Bugs in javax.imageio.ImageReader

H

Harold Yarmouth

I did some testing of ImageIO robustness and found some disturbing problems.



Bug #1: com.sun.media.imageioimpl.plugins.raw.RawImageReader does not
accept ImageInputStream in setInput.



java.lang.ClassCastException: javax.imageio.stream.FileImageInputStream
cannot be cast to com.sun.media.imageio.stream.RawImageInputStream
at
com.sun.media.imageioimpl.plugins.raw.RawImageReader.setInput(RawImageReader.java:121)
at javax.imageio.ImageReader.setInput(ImageReader.java:363)

Got this calling imageReader.setInput(new ImageInputStream(someFile));

Obviously, this should not be, given the Javadocs:




setInput

public void setInput(Object input)

Sets the input source to use to the given ImageInputStream or other
Object. The input source must be set before any of the query or read
methods are used. If input is null, any currently set input source will
be removed. In any case, the value of minIndex will be initialized to 0.

This method is equivalent to setInput(input, false, false).

Parameters:
input - the ImageInputStream or other Object to use for future
decoding.
Throws:
IllegalArgumentException - if input is not an instance of one
of the classes returned by the originating service provider's
getInputTypes method, or is not an ImageInputStream.
See Also:
getInput()




This makes it quite clear that ImageReader implementations are supposed
to accept ImageInputStreams, and furthermore are supposed to throw
IllegalArgumentException, not ClassCastException, if passed an object
that is not accepted.



Workaround: Catch ClassCastException and try another ImageReader on that
input stream.



Bug #2: com.sun.media.imageioimpl.plugins.pnm.PNMImageReader throws
RuntimeException instead of IOException when the file format is unfamiliar.


java.lang.RuntimeException: What in the stream isn't a PNM image.
at
com.sun.media.imageioimpl.plugins.pnm.PNMImageReader.readHeader(PNMImageReader.java:187)
at
com.sun.media.imageioimpl.plugins.pnm.PNMImageReader.getWidth(PNMImageReader.java:153)

calling getWidth on a PNMImageReader invoked on a jpeg. This time the
error message isn't even quite grammatical...


The correct behavior when the image format is not the expected one is to
throw an IOException, of course. Throwing a RuntimeException is bad.
Throwing an unsubtyped RuntimeException is worse, because client code
has to catch all RuntimeExceptions and treat them as IOExceptions, which
may mask real RuntimeExceptions.



Workaround: Catch RuntimeException, test with getClass() whether it is
exactly RuntimeException, if not rethrow, and if yes treat as if
IOException.
 
H

Harold Yarmouth

Bug #1 appears to result from calling
ImageIO.getImageReadersByMIMEType(""); this returns an iterator that
returns a com.sun.media.imageioimpl.plugins.raw.RawImageReader which
does not like an ImageInputStream source.

And, of course, ImageIO.getReaderMIMETypes() returns a collection that
includes the empty string...




Bug #3:
com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib
throws ArithmeticException (division by zero) instead of IOException
when fed a jpeg that is not a jpeg2000 jpeg.




java.lang.ArithmeticException: / by zero
at
com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.<init>(J2KRenderedImageCodecLib.java:224)
at
com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.readHeader(J2KImageReaderCodecLib.java:422)
at
com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.getWidth(J2KImageReaderCodecLib.java:182)




Bug #4:
com.sun.media.imageioimpl.plugins.bmp.BMPImageReader throws
IllegalArgumentException instead of IOException when fed a jpeg.




java.lang.IllegalArgumentException: Invalid magic value for BMP file.
at
com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.readHeader(BMPImageReader.java:248)
at
com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.getWidth(BMPImageReader.java:212)
 
H

Harold Yarmouth

Bug #5: com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader sometimes
throws an IllegalArgumentException ultimately out of a private method
saying "Empty region!" when faced with a file that is corrupt or of the
wrong type, instead of throwing an IOException.
 
D

Daniel Pitts

Harold said:
Bug #1 appears to result from calling
ImageIO.getImageReadersByMIMEType(""); this returns an iterator that
returns a com.sun.media.imageioimpl.plugins.raw.RawImageReader which
does not like an ImageInputStream source.

And, of course, ImageIO.getReaderMIMETypes() returns a collection that
includes the empty string...




Bug #3:
com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib
throws ArithmeticException (division by zero) instead of IOException
when fed a jpeg that is not a jpeg2000 jpeg.




java.lang.ArithmeticException: / by zero
at
com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.<init>(J2KRenderedImageCodecLib.java:224)

at
com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.readHeader(J2KImageReaderCodecLib.java:422)

at
com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.getWidth(J2KImageReaderCodecLib.java:182)





Bug #4:
com.sun.media.imageioimpl.plugins.bmp.BMPImageReader throws
IllegalArgumentException instead of IOException when fed a jpeg.




java.lang.IllegalArgumentException: Invalid magic value for BMP file.
at
com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.readHeader(BMPImageReader.java:248)

at
com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.getWidth(BMPImageReader.java:212)
Generally, you use ImageIO.createImageInputStream(Object) to create the
ImageInputStream. Does that work better for you? (Since you haven't
provided an SSCCE, or files, I can't test for you).
 
H

Harold Yarmouth

Daniel said:
Generally, you use ImageIO.createImageInputStream(Object) to create the
ImageInputStream. Does that work better for you?

That's what I have already been doing. I was just stress-testing ImageIO
and found places where it behaves inappropriately if the data it slurps
off the disk is not in the expected format. Random RuntimeExceptions
instead of a well-defined checked exception on parse error is Bad Design
with a capital BD.

Only one case involves setInput itself failing -- that "blank mime
type"-produced RawImageReader that apparently does not like
setInput(createImageInputStream(File)) being called on it.

That was clearly contrary to the javadoc-embodied specifications.

As for the various exceptions from read, getWidth, etc. when the on-disk
file is of an unexpected type, those should all be IOException or
perhaps some sort of ParseException or IIOException or something. Or at
least they should be documented somewhere. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,076
Latest member
OrderKetoBeez

Latest Threads

Top