Saving Image object in java on OS X

I have an app I am working on that stores an image an ImageIcon object. I want to save this image to disk. So I start with:

Image image = imageIcon.getImage();

This creates an Image object which is a super class of the BufferedImage. Did a bit of reading and it seemed it should really be a BufferedImage, so all that was really necessary was to call:

ImageIO.write((BufferedImage)image, "png", file);

casting the Image to a BufferedImage. However the system balked at this irresponsible and apparently ill advised abuse of the typing system and delivered me a swift rebuke, in the form of a class cast exception. Well I guess I was asking for it, but what exactly was the problem? was it a volatile image perhaps? The other documented sub class of Image? No such luck, this was the telling off I got: java.lang.ClassCastException: apple.awt.OSXImage cannot be cast to java.awt.image.BufferedImage. Turns out on the mac (oh how I love you and hate you apple), they have their own pretty much undocumented image class OSXImage. So how to deal with this. I did a little googling and came across this. To summarise the advice was essentially:

  • Get the Image’s consumer with Image.getSource().
  • Use a PixelGrabber to read the image data from the consumer into some
    pixel array
  • Create a DataBufferInt from the pixel data
  • Create a WritableRaster using the DataBufferInt
  • Create a BufferedImage using the WritableRaster
  • curse, wait, curse, wait, curse, curse, curse

More than a little daunting, still I hadn’t found any thing else of any use so I gave it a crack. Documentation on this stuff was painfully thin on the ground but I got something that created an image – just not the right image. I had real trouble with understanding the bitmasks required for decoding pixels packed into ints offsets and all sorts of other things I will have to get to grips with at some point. But thankfully not now. After hours of cursing and waiting as advised in the approach quoted, I went back to google. After a while I stumbled across this, thank you dan!

Dan is the man! He out thought the problem and came up with a beautifully simple solution!

Image image = imgIcon.getImage();
int width = imgIcon.getIconWidth();
int height = imgIcon.getIconHeight();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = bi.getGraphics();
graphics.drawImage(image, 0, 0, this);
graphics.dispose();

Basically get the Image out of the icon, create a new BufferedImage. Get its graphics object and just draw our image into it! Now we have a buffered image, with our image in it. This seems like it should be a nice solution that will ensure that this image saving malarkey doesn’t fail on crazy java VM implementations where the image class is unexpectedly extended. Best of all no more, seat of the pants casting!

Thanks Dan!


About this entry