Search code examples
c#.netimagebitmapsystem.drawing

Why does saving image on C# Bitmap give different file size than original?


I am currently working on a project which modify some images and save it again. However, I have noticed that sometimes the resulted image is drastically different than the original one in terms of file size in bytes. Even if the modifications were very small such as changing colour on a single pixel. So I decided to do this experiment where I load an image and save it again immediately to new file without any changes (using C# Bitmap class). I was expecting to get the same size in both files but unfortunately the actual sizes were not identical. Here is my code:

String originalImagePath = "image.png";
String savedImagePath = "image2.png";
Bitmap image = new Bitmap(originalImagePath);
image.Save(savedImagePath);

Assert.AreEqual(new FileInfo(originalImagePath).Length, new FileInfo(savedImagePath).Length);

Assert.AreEqual failed. 
Expected:<218144>.Actual:<344264>.

Should both files have the same sizes? If no, then what I am missing here?
And how can I generate identical file?
Here is the image that I am using: PNG Image


Solution

  • There really isn't anything strange about this. You're saving a PNG file, which only really defines how the file is supposed to be decoded, but not how to do the actual compression. Different applications can produce vastly different file sizes, just by the virtue of having a different compression tables. There's usually also some tweaking you can do (e.g. limit the palette of the file, or picking between coding/decoding speed and file size).

    This is seen very clearly by using a tool such as PNG Gauntlet, which takes a PNG file on input, and produces a pixel-by-pixel identical image, just with a vastly reduced file size (usually around 30% less space, but I've seen results up to 70% smaller).

    And of course, in the end, even if everything else is equal, a tiny change in the bitmap can result in a significant file increase anyway. Maybe you've broken some pattern that was especially easy to compress. Maybe you can no longer fit in a 8-bit palette. Maybe you've added transparent channels. There's plenty more.