.NET Image.Save偶尔会生成一个带有错误IDAT块的PNG

时间:2013-10-10 17:02:21

标签: c# .net png system.drawing libpng

我有一个C#/ .NET实用程序我写的从磁盘加载PNG图像

Bitmap b = Bitmap.FromStream(new MemoryStream(File.ReadAllBytes(filename))) as Bitmap;

对它们执行多次转换(旋转,缩放,alpha),然后根据应用的转换将生成的PNG图像保存回具有不同文件名的磁盘

b.Save(outputName, ImageFormat.Png);

我使用该实用程序成功编写了数千个PNG。但是,偶尔有一个PNG无法加载到使用libpng的单独程序中。在该程序中,libpng给出错误“找到太多IDAT”

查看PNG文件会在IEND块之前的文件末尾显示“流氓”IDAT块。一个这样的IDAT块(以及下面的IEND块)在十六进制编辑器中看起来像这样。这些是文件中的最后24个字节。

IDAT: 0x00 0x00 0xFF 0xF4 0x49 0x44 0x41 0x54 0x35 0xAF 0x06 0x1E    
IEND: 0x00 0x00 0x00 0x00 0x49 0x45 0x4e 0x44 0xAE 0x42 0x60 0x82

IDAT块长度显示为0xFFF4。但是,很明显,IDAT块中没有那么多字节(甚至文件也没有。)

还有其他人遇到过这个问题吗?我可以用以下几种方法之一解决问题。我可以手动编辑PNG文件以删除最后一个IDAT块(或将其大小设置为0.)我可以运行修复损坏的PNG的辅助程序。但是,我想要一个C#/ .NET解决方案,我可以轻松地将其添加到我的原始程序中。理想情况下,我想要一个不需要我重新打开PNG作为二进制文件的解决方案;检查IDAT坏块;并重写PNG。但是,我开始认为这就是我需要做的事情。

2 个答案:

答案 0 :(得分:1)

老问题。

.NET众所周知在处理图像方面很差。编解码器是较旧的win32编解码器,其中包含许多错误。

即使您遵循建议的处理方式和/或使用方法,.NET也不总是释放读取/写入图像文件时使用的OS资源。

答案 1 :(得分:0)

这不是一个完整的答案,因为我无法重现图像。但您可以尝试使用Bitmap构造函数中的另一个加载图像:

http://msdn.microsoft.com/en-us/library/0cbhe98f.aspx

哪会将您的代码更改为:

Bitmap b = new Bitmap(filename);

因为该构造函数使用一些本机GDI +函​​数将图像加载到内存中,而不是读取原始字节:

http://dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/CommonUI/System/Drawing/Bitmap@cs/1305376/Bitmap@cs

可能存在差异,即使问题似乎是在将图像写入磁盘时。