从磁盘读取 png 文件并将其保存回来后文件大小增加

File size increases after reading png file from disk and saving it back

我目前正在开发一个小程序来从磁盘读取 png 文件,进行一些修改并将其保存回来。一切都很顺利运行 除了一个小问题,我把文件存回磁盘后,它的大小总是增加,例如一个27.1MB的文件会变成33.3MB。

经过一些调试,我终于将范围缩小到阅读和保存代码。这是我目前使用的代码:

Bitmap img = new Bitmap(<path to file>);
//omitted
img.Save(<path to new file>, ImageFormat.Png);

我已经验证过无论我是否做任何修改,简单地读取和保存图像都会导致它的大小发生变化。此外,如果我用画图打开保存的文件并从那里保存,文件会缩小回原来的大小。

如何在不改变大小的情况下读取和保存图像?

我认为您缺少 压缩 部分。
像这样添加到您的代码中 -

Bitmap img = new Bitmap(<path to file>);

这是你错过的 -

ImageCodecInfo myImageCodecInfo = GetEncoderInfo("image/jpeg");
EncoderParameter myEncoderParameter = new EncoderParameter(Encoder.Quality, 25L);
EncoderParameters myEncoderParameters.Param[0] = myEncoderParameter;

然后像这样保存 -

img.Save(<path to file>, myImageCodecInfo, myEncoderParameters);

这里是MSDNlink。希望对你有帮助。

您尝试过 Endoder.ColorDepth 字段吗? PNG 还支持透明度,并且可能会保存一些图像不需要的信息。

ImageCodecInfo pngCodec = ImageCodecInfo.GetImageEncoders().Where(codec => codec.FormatID.Equals(ImageFormat.Png.Guid)).FirstOrDefault();
if (pngCodec != null)
{
    EncoderParameters parameters = new EncoderParameters();
    parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 24); //8, 16, 24, 32 (base on your format)
    image.Save(stream, pngCodec, parameters);
}

此处的附加信息:https://msdn.microsoft.com/en-us/library/system.drawing.imaging.encoder.colordepth(v=vs.110).aspx

除了颜色深度和使用的通道数(w/o alpha)之外,保存的 PNG 文件大小主要取决于两个因素:

  • 如何对图像线进行预处理(称为过滤)。
  • deflate 算法的压缩级别 (0-9)。

这两个因素会极大地影响输出图像文件的大小。过滤是经验性的,您可以对所有图像行使用四分之一的过滤算法,或者对不同的行使用不同的算法,甚至可以自适应地在各个行上尝试不同的算法并选择最大的压缩率。对于大多数图像作者来说,自适应方式是最耗时且不切实际的。

过滤后,图像数据被deflate压缩。 deflate 算法的压缩级别通常为 0-9,从最低压缩率到最高压缩率。压缩率越高,压缩过程越慢。通常 4 是大多数图像的最佳选择。

过滤过程在 PNG 压缩过程中扮演着非常重要的角色。不同的过滤算法可能导致保存的图像大小差异较大。另一方面,图像大小对压缩级别不太敏感。

您可以使用 TweakPNG 等工具来检查图像包含的颜色深度和通道数。如果原始图像和重新保存的图像具有相同的颜色深度和通道,那么过滤和压缩级别很可能是文件大小增加的罪魁祸首。

事实是,如果编码器没有优化,文件大小往往会增加。但是,如果您不介意 post 处理生成的图像,那么有很多 PNG 优化软件。