.NET Image.Save 偶尔会生成一个带有错误 IDAT 块的 PNG
Posted
技术标签:
【中文标题】.NET Image.Save 偶尔会生成一个带有错误 IDAT 块的 PNG【英文标题】:.NET Image.Save occasionally generates a PNG with a bad IDAT chunk 【发布时间】:2013-10-18 13:49:45 【问题描述】:我有一个我编写的 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。但是,我开始认为这是我需要做的。
【问题讨论】:
您的图像大小/行步幅是否不同?如果损坏的图像有一些独特的东西(宽度、高度、步幅、格式),您是否能够缩小范围? 我认为您将不得不更多地隔离问题。如果您使用 C# 立即回读您保存的每个文件,您可以重现错误吗?如果是这样,您需要追踪导致该图像损坏的确切情况并从那里开始。 似乎其他用户偶然发现了same problem。有些代码似乎从问题中恢复,有些则没有(如 libpng)。仍然没有解释额外的块是从哪里来的。 我知道这已经有 4 年历史了,但我现在正在努力解决这个问题。如果您还记得的话,我很好奇您当时使用的是什么操作系统。给定时间范围,假设这是 Windows 7/Server 2012? 我没有您的问题的答案,但在解决完全相同的问题时,我们找到了一种重现它的方法。我们发现生成的 PNG 文件的大小是存在问题的关键指标。如果文件的大小(以字节为单位)为 0x1001C + n * 0x10000,n 为 0、1、2、3、4(可能还有更大的值,但我无法确认),则问题始终存在。我发布了一个问题,其中包含一些代码来重现该问题:***.com/questions/52100703/… 我希望这会有所帮助。 【参考方案1】:老问题。
.NET 在处理图像方面是出了名的差。编解码器是旧的 win32 的,有很多错误。
即使您遵循推荐的 dispose 和/或 using 方法,.NET 也不总是释放读取/写入图像文件时使用的操作系统资源。
【讨论】:
【参考方案2】:这并不是一个完整的答案,因为我无法重现该图像。但是您可以尝试使用另一个 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
可能存在差异,即使问题似乎出在将图像写入磁盘时。
【讨论】:
感谢您的意见。但是,我尝试了其他 Bitmap 构造函数,但没有成功。我特别选择了 FromStream 版本,因为其他人可以让文件句柄打开的时间比我想要的要长。以上是关于.NET Image.Save 偶尔会生成一个带有错误 IDAT 块的 PNG的主要内容,如果未能解决你的问题,请参考以下文章
使用带有子类 UINavigationController 的自定义 iOS 7 过渡偶尔会导致黑屏
带有 tez 的 aws emr 上的 Pig 脚本偶尔会因 OutOfMemoryException 而失败