Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java ImageIO: Exception Weirdness

In my application I was trying to save a BufferedImage to a PNG file using ImageIO. The file is chosen by the user so I need to react to errors that might happend (e.g. user tries to save in a location he has no write permission for). However I am unable to catch the IOException that occurs.

The following code shows the problem. Trying to save to "/foo" should throw an exception for most users on *nix systems, since they do not have write permission in the root directory.

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class IOTest {

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(640, 480,
                BufferedImage.TYPE_INT_RGB);
        try {
            File f = new File("/foo");
            ImageIO.write(img, "png", f);
        } catch (IOException e) {
            System.out.println("Caught IOException!");
        }
    }
}

However, the exception is not caught. Output:

    java.io.FileNotFoundException: /foo (Permission denied)
    at java.io.RandomAccessFile.open(Native Method)
    at java.io.RandomAccessFile.<init>(RandomAccessFile.java:233)
    at javax.imageio.stream.FileImageOutputStream.<init>(FileImageOutputStream.java:69)
    at com.sun.imageio.spi.FileImageOutputStreamSpi.createOutputStreamInstance(FileImageOutputStreamSpi.java:55)
    at javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:419)
    at javax.imageio.ImageIO.write(ImageIO.java:1530)
    at IOTest.main(IOTest.java:16)
Exception in thread "main" java.lang.NullPointerException
    at javax.imageio.ImageIO.write(ImageIO.java:1538)
    at IOTest.main(IOTest.java:16)

Note that FileNotFoundException is a subclass of IOException so it should get caught. A second catch block did not help either:

catch (FileNotFoundException e) {
    System.out.println("Caught FileNotFoundException!");
} catch (IOException e) {
    System.out.println("Caught IOException!");
}

What am I doing wrong?

like image 958
jhenninger Avatar asked Aug 22 '12 14:08

jhenninger


2 Answers

It stems from the details of ImageIO implementation. You will circumvent the problem if you don't pass the File instance to ImageIO.write, but first try to open a FileOutputStream yourself and pass that to write.

This is a more precise analysis of what happens in ImageIO.write. Line 1530:

stream = createImageOutputStream(output);

Line 1538:

stream.close();

And if you take a look at the implementation of createImageOutputStream, you'll see several code paths that return null.

like image 146
Marko Topolnik Avatar answered Nov 02 '22 02:11

Marko Topolnik


It looks like the ImageIO.write method prints the IOException but really doesn't handle it and ends with a NullPointerException. In this specific case of a buggy library, maybe you should catch any RuntimeException...

Of course it will be better to test before if the directory exists and is writable.

like image 43
Denys Séguret Avatar answered Nov 02 '22 04:11

Denys Séguret