none
Serializing/Deserializing Bitmap causes the image to change RRS feed

  • Question

  • I have code that serializes/deserializes bitmap objects. For some image files (especially png files) I found out that the size of the file is reduced after deserializing it, and the image quality is reduced. And if I serialize the deserialized image again, the resulting byte array is different compared to what it was before. Has anyone experienced the same problem? If so, how were you able to solve it?

    Here is my code snippet:

        private byte[] GetBytes(Bitmap image)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, image);
                byte[] _bytes = ms.ToArray();
                return _bytes;
            }
        }
    
        private Bitmap GetImage(byte[] _bytes)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(_bytes))
            {
                Bitmap bmp = (Bitmap)formatter.Deserialize(ms);
                return bmp;
            }
        }

    PS: Using an Image object instead of Bitmap seems to solve the problem, but I'd rather not change the object type due to external dependencies.
    Wednesday, February 27, 2019 11:03 AM

All replies

  • Serializing the raw bitmap object isn't the correct way to do this. To serialize a bitmap use the Save method. It accepts the stream to serialize to. To deserializer later use the constructor of Bitmap that takes a stream.

    //Not tested
    private byte[] GetBytes ( Bitmap image )
    {
       using (var output = new MemoryStream())
       {
          image.Save(output, ImageFormat.Bmp);
    
          return output.ToArray();
       };
    }
    
    private Bitmap GetImage ( byte[] data )
    {
       //Do not dispose of the stream!!
       return new Bitmap(new MemoryStream(data));
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, February 27, 2019 3:42 PM
    Moderator
  • Hi Michael,

    Thanks for the reply, but it doesn't change anything. The result is still the same.

    Thursday, February 28, 2019 8:26 AM
  • Hi Cagri

    Thank you for posting here.

    I think CoolDasTx's solution is right, you could try the following complete code.

    Please pay attention to my <g class="gr_ gr_16 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del" data-gr-id="16" id="16">bold</g> code, it is best for you to compare two-byte arrays by using the SequenceEqual method.

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace test4
    {
        class Program
        {
            private static byte[] GetBytes(Bitmap image)
            {
                using (var output = new MemoryStream())
                {
                    image.Save(output, ImageFormat.Bmp);
    
                    return output.ToArray();
                };
            }
    
            private static Bitmap GetImage(byte[] data)
            {
                //Do not dispose of the stream!!
                return new Bitmap(new MemoryStream(data));
            }
            static void Main(string[] args)
            {
                Bitmap bitmap = new Bitmap(@"D:\test.png");
                var b1 = GetBytes(bitmap);
                var m = GetImage(b1);
                var b2 = GetBytes(m);
                var v = b1.SequenceEqual(b2);
                if (v)
                {
                    Console.WriteLine("success");
                }
                else
                {
                    Console.WriteLine("false");
                }
                Console.ReadLine();
    
            }
        }
    }

    Result: 

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Thursday, February 28, 2019 9:41 AM
    Moderator
  • Have you checked if ‘var b = new Bitmap(“myfile.png”); b.Save(“myfile2.png”)’ changes the quality of the image? How did you create the image object?

    Thursday, February 28, 2019 10:26 AM
  • Hi Jack,

    You are right with your example, although it still doesn't work for me. I found out that there is a small difference between your sample code and mine that I forgot to mention (sorry for that). In my case, Bitmap object is created using an Image object, like this:

    //image is an Image object
    Bitmap bmp = new Bitmap(image);
    byte[] _bytes = GetBytes(bmp);

    So if I modify your code, my case looks more like this:

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace test4
    {
        class Program
        {
            private static byte[] GetBytes(Bitmap image)
            {
                using (var output = new MemoryStream())
                {
                    image.Save(output, ImageFormat.Png);
    
                    return output.ToArray();
                };
            }
    
            private static Bitmap GetImage(byte[] data)
            {
                //Do not dispose of the stream!!
                return new Bitmap(new MemoryStream(data));
            }
            static void Main(string[] args)
            {
                Image image = Image.FromFile(@"D:\test.png");
                Bitmap bitmap = new Bitmap(image);
                var b1 = GetBytes(bitmap);
                var m = GetImage(b1);
                var b2 = GetBytes(m);
                var v = b1.SequenceEqual(b2);
                if (v)
                {
                    Console.WriteLine("success");
                }
                else
                {
                    Console.WriteLine("false");
                }
                Console.ReadLine();
    
            }
        }
    }


    Thursday, February 28, 2019 2:36 PM
  • Hi 

    Thanks for the feedback.

    I want to confirm if your keyword 'v' is true. I tested the code you provided, then I found that my test result is still correct. You could refer to the following result picture.


    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Friday, March 1, 2019 3:03 AM
    Moderator
  • Hi Jack,

    'v' is set to false, I double checked it. Unfortunately I can't send you the screenshot because my account is not verified yet therefore I can't use images when I reply.

    I think it depends on the image file you use. I observed that this problem is more likely to occur if the png file has a transparent background. I'll try to post the image I used when my account is verified.


    Friday, March 1, 2019 11:13 AM
  • Hi Cagri

    If you could not send the screenshot here, you could try to share your picture via OneDrive.

    We are waiting for your update.

    Best Regards,

    Jack.


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 4, 2019 6:26 AM
    Moderator
  • Hi again,

    Here is the screenshot:

    And this is the png file I used:

    Monday, March 4, 2019 6:30 AM
  • Hi  Cagri ,

    I have reproduced your problem. You could try the following change.

    Change

     image.Save(output, ImageFormat.Png);

    Into

      image.Save(output, ImageFormat.Bmp);

    Best Regards,

    Jack.


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 4, 2019 7:13 AM
    Moderator
  • Hi Jake,

    But that would change the image format to bmp from png. So, when I deserialize and save the image, it won't be the same image I serialized (i.e. the background will no longer be transparent).

    /Cagri

    Monday, March 4, 2019 9:20 AM
  • Hi Cagri

    I suggest that it is best for you to load the image in one way. so I think the following way is better.

       Bitmap bitmap = new Bitmap(@"D:\test.png");

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Tuesday, March 5, 2019 9:13 AM
    Moderator
  • Hi Jack,

    Thanks for the suggestion. Unfortunately, I cannot change the way the images are loaded, there are external dependencies. And I don't really understand why loading the image using Image class would cause this problem, maybe it is a bug in Bitmap (or Image) serialization code?

    /Cagri

    Tuesday, March 5, 2019 1:18 PM
  • Hi Cagri

    I suggest that it is best for you to load image in one way. so I think the following way is better.

       Bitmap bitmap = new Bitmap(@"D:\test.png");

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Hi Jack,

    I tested it out the way you suggested, just to see if it works. It doesn't work that way either unfortunately.

    Here is my code:

            private static byte[] GetBytes(Bitmap image)
            {
                using (var output = new MemoryStream())
                {
                    image.Save(output, ImageFormat.Png);
    
                    return output.ToArray();
                };
            }
    
            private static Bitmap GetImage(byte[] data)
            {
                //Do not dispose of the stream!!
                return new Bitmap(new MemoryStream(data));
            }
            static void Main(string[] args)
            {
                Bitmap bitmap = new Bitmap(@"TestImage.png");
                var b1 = GetBytes(bitmap);
                var m = GetImage(b1);
                var b2 = GetBytes(m);
                var v = b1.SequenceEqual(b2);
                if (v)
                {
                    Console.WriteLine("success");
                }
                else
                {
                    Console.WriteLine("false");
                }
                Console.ReadLine();
            }

    Here is the screenshot from debug:

    And the image file I used:

    Wednesday, March 6, 2019 9:29 AM
  • Hi  Cagri,

    After checking it, I found it may be an issue.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 11, 2019 1:43 AM
    Moderator
  • Thanks. I faced this problem 3 years ago. Never could figure out what caused it. I just made it into an image compression app. https://github.com/dwakel/Dwindle
    I wish I could know exactly what caused the issue. For research purposes, it could be helpful


    Monday, December 2, 2019 12:24 AM