Question

Heres the error:

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

and heres the code causing it:

        bimg = ImageIO.read(icons[i]);

icons is an array of files. The strange thing is that my computer can read the images just fine in any image viewer. Googling the error gave me no results. I have a ton of images I need to read, so is their an alternate way to get the dimensions of an image aside from turning it into a BufferedImage? Will that fix the problem? Is there a way to fix these images? I got them from collecting icons of apps from iOS devices. Tests from my own devices produced no errors, though ones that had previously been sent as part of a zip file, though gathered the same way, produced this error regularly. Everything I know about compression tells me this shouldn't happen. I am not sure where to begin looking, and really need a fix. Here is an example of a failed image.

I should note, for this part of my program, all I need are the image dimensions. I believe this can be obtained through reading metadata, but I also cannot find specifics on this with java.

Was it helpful?

Solution

According to the PNG specifiaction:

4.1.1. IHDR Image header

The IHDR chunk must appear FIRST.

Your example image contains a custom critical chunk CgBI as the first chunk, and does not conform to this spec. This is why you get the exception.

Actually, it seems your image is an "iOS optimized PNG".

From http://fileformats.archiveteam.org/wiki/CgBI:

It is not compatible with PNG. Standard PNG decoders that don't support it will fail gracefully, due to an unknown "critical chunk".

Now, what probably should be considered a bug in the com.sun.imageio.plugins.png.PNGImageReader is that it doesn't check that the first chunk is actually a IHDRchunk, before claiming it can read the input.

You can fix the images, by reading them in one of the viewers/apps you say can read them fine, then writing them back as normal PNGs. I tested using Preview on OS X, and it worked fine. Give it a try.

If on OS X (with dev tools), you should also be able to use Apple's modified pngcrush with the following command line:

xcrun -sdk iphoneos pngcrush -revert-iphone-optimizations infile.png outfile.png

If you just want to get the width/height of the images, you don't need to read full BufferedImages, just get an ImageReader and use its getWidth(0) and getHeight(0) methods (there are plenty examples on SO for this already, no need to repeat).

You could probably also create a quick PNG structure parser, that skips the CgBI chunk, and parses the IHDR directly, to get width/height.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top