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

C# .NET Image.Save偶尔会生成带有错误IDAT块的PNG,c#,.net,png,system.drawing,libpng,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无法加载

我编写了一个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块之前有一个“rogue”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。然而,我开始认为这是我需要做的。

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

这会将您的代码更改为:

Bitmap b = new Bitmap(filename);
因为该构造函数使用一些本机GDI+函数将图像加载到内存中,而不是读取原始字节:

可能会有不同,即使问题似乎是在将映像写入磁盘时。

旧问题

NET在处理图像方面是出了名的差。编解码器是旧的win32,有很多错误


在读取/写入图像文件时,.NET并不总是释放使用的操作系统资源,即使您遵循建议的处置和/或使用方法。

您的图像大小/行间距是否不同?你是否能够缩小破碎图像的范围(宽度、高度、步幅、格式)?我认为你必须进一步隔离问题。如果您使用C#立即读回保存的每个文件,您可以重新设置错误吗?如果是这样的话,你需要追踪导致图像损坏的确切情况,并从那里着手。似乎其他用户已经无意中发现了这个问题。有些代码似乎可以从问题中恢复,有些则不能(比如libpng)。但仍然不能解释额外的块是从哪里来的。我知道这已经有4年了,但我正在研究导致这一现象的根源。如果你还记得的话,我很好奇你当时在用什么操作系统。考虑到时间范围,假设这是Windows 7/Server 2012?我对您的问题没有答案,但在解决完全相同的问题时,我们找到了一种复制它的方法。我们发现生成的PNG文件的大小是出现问题的一个关键指标。如果文件的大小(以字节为单位)为0x1001C+n*0x10000,其中包含n0、1、2、3、4(可能还有更大的值,但我无法确认),则问题始终存在。我发布了一个带有代码的问题来重现这个问题:我希望这有帮助。谢谢你的输入。但是,我尝试了其他位图构造函数,但没有成功。我特别选择了FromStream版本,因为其他人可以让文件句柄打开的时间比我想要的长。