【问题标题】:What influences the C# PNG lossless compression ratio?什么影响 C# PNG 无损压缩率?
【发布时间】:2013-10-18 17:47:04
【问题描述】:
Bitmap clip = new Bitmap((int)(8.5 * 72), (int)(11 * 72));
MemoryStream stream = new MemoryStream();
clip.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
byte[] bytes = stream.ToArray();

我在我的机器上运行它,bytes.Length8587,在我其他开发人员的机器上它是 2009。据说在.NET 中没有办法影响PNG 压缩的质量(或者更确切地说是这种情况下的比率)。这个特定的图像是空白的,我有其他测试可以处理带有内容的图像,它们确认压缩是无损的(我遇到了一些争论,这是一个问题)。

但即使压缩是无损的,在压缩算法运行时间 + CPU 利用率与压缩率/质量之间也存在权衡。我想知道System.Drawing.Imaging 如何确定质量,因为上述案例清楚地表明可能存在差异。我如何确定在客户端的机器上它不会选择 100% 的质量(这将产生 1.457.337 大小的文件)?

相关资料:

附加信息:

  • 检查了另一个开发者的机器,和我其他同事的结果一致,所以我的机器是异常值。
  • 每台机器上都安装了 Win 7 Prof 64 位,特定测试是 NUnit,我们使用的是 .NET 4
  • 我安装的任何软件都可以在这方面覆盖 .NET 的行为吗?例如,我安装了 IrfanView,它可以替换任何系统范围的“过滤器”或使用的 dll 吗? (顺便说一句,我在 Modules 调试视图中检查了,我没有看到任何异常的 dll 加载)
  • 它会受到某些 Windows 操作系统桌面质量设置或其他因素的影响吗?

【问题讨论】:

  • 您说您保存了 PNG,但您的代码使用的是 BMP...
  • @TrevorElliott 我复制了错误的测试代码,已更正。
  • 如果您切换到无损压缩,那么在任何东西和质量之间进行权衡是什么意思?无损压缩的全部意义在于压缩前和解压缩后的图像是逐位相同的。没有质量损失,除非算法被破坏或者你故意丢弃它。
  • @cHao 好吧,通常质量和压缩比是相同的设置(它们相互影响)。人们经常提到质量,在我们的例子中,我们更应该谈论压缩比。即使在无损压缩的情况下,编解码器的编码器算法的工作也是努力在整个过程中找到最佳参数。我会更正这个问题。

标签: c# png image-compression image-quality


【解决方案1】:

您可能安装了不同的 .NET 框架更新。

按照这个检查:http://msdn.microsoft.com/en-us/library/hh925567.aspx

您可能还拥有不同的 .NET Framework 4“发行版”

  • 客户资料
  • 扩展
  • 多目标包

你可以用同样的方法检查它。

【讨论】:

  • 我还安装了Microsoft Windows SDK for Windows 7Debugging Tools for Windows (x64) 和一大堆符号,而我认为我的同事没有。希望我们能尽快检查版本。
  • 我收集了一些版本信息,但不一致。具体来说,我调试了软件,设置了断点,在 Modules 窗口中你可以看到所有 dll 的确切版本(包括内部版本号)。 System.Drawing 对于所有三台机器都是相同的。其他开发人员之一的构建几乎与我相同,而另一个则不同。我需要进一步调查,即使版本是指标,问题是为什么或如何?
【解决方案2】:

我一直在追查这个问题,并在我的两台机器上得到与你完全相同的结果。我相信我已经将它追踪到两台机器上不同版本的 System.IO.Compression.DeflateStream - png 使用 deflate 作为其压缩方法,并且似乎使用这个类。

当我运行以下命令时:

byte[] blank = new byte[1000000];
MemoryStream uncstream = new MemoryStream(blank);
MemoryStream compstream = new MemoryStream();
DeflateStream defstream = new DeflateStream(compstream, CompressionMode.Compress);
uncstream.CopyTo(defstream);
defstream.Close();
byte[] bytes = compstream.ToArray();
System.Console.WriteLine(bytes.Length);

我在一台机器上得到 985 字节,在另一台机器上得到 8806 字节。

如果我将构造函数更改为:

DeflateStream defstream = new DeflateStream(compstream, CompressionLevel.Optimal);

我在第一台机器上得到了相同的结果,在第二台机器上得到了一个未实现的异常,表明它使用的是早期版本的压缩库。当我在第二台机器上搜索 System.IO.Compression.dll 时,我根本找不到它,即使应该安装了 .Net 4。我猜它隐藏在.Net 2.0中的某个地方。我知道 MS 声称在 .Net 版本 2 和 4 之间改进了 DeflateStream - 请参阅此处进行讨论:

http://www.virtualdub.org/blog/pivot/entry.php?id=335

我还看到它说单独的压缩 dll 在 .Net 4.5 中开始使用,尽管我不知道这是否正确。我的下一步是在第二台机器上安装 .Net 4.5,看看它是否会有所不同,但这必须等到我 1 月份回到办公室。

【讨论】:

  • 感谢您对此事的深入追踪。我没有时间。我会尝试仔细检查您的发现,但我相信您的答案是正确的。从我的角度来看,您的发现是好的,因为这意味着即使使用“旧”方法的默认压缩也不会恶化到令人惊讶的大尺寸(我相信)。
  • 另请注意,.NET 4.5 是开始提供 ZipArchive 类的版本。所以很有可能在压缩区域的引擎盖下有发展,这可能会影响到这一点。我现在没有时间验证这一点,但我会将你的答案标记为正确。
  • .Net 4.5(最终)开始使用 zLib 进行压缩/放气,从而获得更好的压缩率。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 2014-09-28
  • 2014-05-18
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
相关资源
最近更新 更多