奇怪的PNG错误:IHDR块的长度不正确

use*_*716 2 java png bufferedimage javax.imageio

继承人错误:

Exception in thread "main" javax.imageio.IIOException: I/O error reading PNG header!
    at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:307)
    at com.sun.imageio.plugins.png.PNGImageReader.readMetadata(PNGImageReader.java:637)
    at com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1212)
    at com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1560)
    at javax.imageio.ImageIO.read(ImageIO.java:1422)
    at javax.imageio.ImageIO.read(ImageIO.java:1282)
    at Bundle.iconExists(Bundle.java:139)
    at Bundle.dPhIconExists(Bundle.java:158)
    at BundleAnalyzer.supports6(BundleAnalyzer.java:14)
    at TheifReader.<init>(TheifReader.java:14)
    at TheifReader.main(TheifReader.java:63)
Caused by: javax.imageio.IIOException: Bad length for IHDR chunk!
    at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:239)
    ... 10 more
Run Code Online (Sandbox Code Playgroud)

以及导致它的代码:

        bimg = ImageIO.read(icons[i]);
Run Code Online (Sandbox Code Playgroud)

icons是一个文件数组.奇怪的是,我的电脑可以在任何图像浏览器中读取图像.谷歌搜索错误给了我没有结果.我需要阅读大量图像,除了将图像转换为BufferedImage之外,还有另一种获取图像尺寸的方法吗?这会解决问题吗?有没有办法修复这些图像?我通过从iOS设备收集应用程序图标来获取它们.来自我自己的设备的测试没有产生任何错误,尽管之前作为zip文件的一部分发送的测试虽然以相同的方式收集,但是会定期产生此错误.我所知道的关于压缩的一切都告诉我这不应该发生.我不知道从哪里开始寻找,真的需要修复. 以下是失败图像的示例.

我应该注意,对于我的程序的这一部分,我需要的只是图像尺寸.我相信这可以通过阅读元数据来获得,但我也找不到与java相关的细节.

har*_*ldK 5

根据PNG的规定:

4.1.1.IHDR图像标题

IHDR块必须首先出现.

您的示例图像包含自定义关键块CgBI作为第一个块,并且不符合此规范.这就是你得到例外的原因.

实际上,您的图像似乎是"iOS优化的PNG".

来自http://fileformats.archiveteam.org/wiki/CgBI:

它与PNG不兼容.由于未知的"关键块",不支持它的标准PNG解码器将会正常失败.

现在,在声称它可以读取输入之前,可能应该被认为是错误的com.sun.imageio.plugins.png.PNGImageReader是它没有检查第一个块实际上是一个IHDR块.

您可以通过在其中一个您认为可以正常读取它们的查看器/应用程序中读取它们来修复图像,然后将它们作为普通PNG写回.我在OS X上使用Preview进行了测试,它运行良好.试试看.

如果在OS X上(使用开发工具),您还应该能够使用以下命令行使用Apple的修改后的pngcrush:

xcrun -sdk iphoneos pngcrush -revert-iphone-optimizations infile.png outfile.png
Run Code Online (Sandbox Code Playgroud)

如果你只想获得图像的宽度/高度,你不需要阅读完整BufferedImages,只需获取ImageReader并使用它getWidth(0)getHeight(0)方法(SO已经有很多例子,不需要重复).

您可能还可以创建一个快速PNG结构解析器,跳过CgBI块,并IHDR直接解析,以获得宽度/高度.