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

Dav*_*lch 17 .net c# png system.drawing libpng

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

Bitmap b = Bitmap.FromStream(new MemoryStream(File.ReadAllBytes(filename))) as Bitmap;
Run Code Online (Sandbox Code Playgroud)

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

b.Save(outputName, ImageFormat.Png);
Run Code Online (Sandbox Code Playgroud)

我已经使用该实用程序成功编写了数千个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
Run Code Online (Sandbox Code Playgroud)

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

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

Swe*_*oij 0

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

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

这会将您的代码更改为:

Bitmap b = new Bitmap(filename);
Run Code Online (Sandbox Code Playgroud)

因为该构造函数使用一些本机 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

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