【问题标题】:File size increases after reading png file from disk and saving it back从磁盘读取 png 文件并将其保存回来后文件大小增加
【发布时间】:2015-10-02 11:21:30
【问题描述】:

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

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

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

我已经验证,无论我是否进行任何修改,只需读取并保存图像就会导致其大小发生变化。此外,如果我用 Paint 打开保存的文件并从那里保存,文件将缩小到原始大小。

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

【问题讨论】:

  • 如果您使用 C# 程序重新读取相同的 PNG,是否也会发生这种情况?如果不是,则可能与 PNG 压缩级别有关(您使用的代码压缩较少,Paint 压缩较多)。
  • 如果我重新读取同一个保存的 PNG,那么它的大小就不会再增加了。

标签: c# image-processing png


【解决方案1】:

除了颜色深度和使用多少通道(不带 alpha)外,保存的 PNG 文件大小主要取决于两个因素:

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

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

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

过滤过程在PNG压缩过程中起着非常重要的有时至关重要的作用。不同的过滤算法可能会导致保存的图像大小有很大差异。另一方面,图像大小对压缩级别不太敏感。

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

事实上,如果编码器没有经过优化,文件大小通常会增加。但是,如果您不介意对生成的图像进行后期处理,那么有很多 PNG 优化软件。

【讨论】:

  • 第三个因素是文件是否使用不适当的颜色类型写入,例如将灰度图像写入真彩色或即使对于不透明图像也写入 Alpha 通道,浪费文件大小。许多应用程序都会这样做。
【解决方案2】:

您是否尝试过使用 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

【讨论】:

  • 确实透明是原因。我已使用此链接中的代码social.msdn.microsoft.com/Forums/vstudio/en-US/…,但将“红色”替换为“透明”,我的问题似乎已解决。
  • 感谢 @gzup 及时向我们发布适合您的解决方案。
  • 对我来说不是这样;我制作的代码专门用于删除 png 图像上的 alpha 通道。相同的 paste-on-white-background-and-resave-without-alpha-channel 操作在 Gimp 中给了我一个 117k png 文件,在 c# 中给了我一个 145k png 文件。
  • .NET 中的 .PNG 编码器不支持任何 EncoderParameters - 或者改变了吗??
【解决方案3】:

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

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);

这是MSDN 链接。希望有帮助。

【讨论】:

  • 此解决方案将图像从 png 转换为 jpeg,而我需要 png 格式的文件。如果我将 EncoderInfo 更改为“image/png”然后设置压缩不起作用,我仍然得到一个略微臃肿的图像。
猜你喜欢
  • 1970-01-01
  • 2010-10-26
  • 1970-01-01
  • 2017-09-08
  • 2018-10-16
  • 2020-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多