How can I save an Image object using serialization?

Tim Rohaly

java.awt.Image does not implement Serializable, so if you need to send it to a stream using serialization you must access the underlying data representation and write that representation out explicitly.

Fortunately, there's an easy way to do this. Swing provides the javax.swing.ImageIcon class, which can be used as a serializable replacement for Image. ImageIcon has a constructor which accepts an Image, then stores a reference to that Image in a transient instance variable. ImageIcon defines writeObject() and readObject() methods which use the PixelGrabber class to convert the image to an array of integers for writing to the stream and the MemoryImageSource class to restore the image from the stream. An excerpt from the ImageIcon source is shown below.

ImageIcon provides a getImage() method for you to recover the stored Image object, so you may either use it directly or you may mimic the technique displayed in the source below to serialize images in your own code.

/**
 * Excerpted from the javax.swing.ImageIcon source code
 */
public class ImageIcon implements Icon, Serializable {

    transient Image image;

/*

body of class has been removed...
     
*/

    private void writeObject(ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();

        int w = getIconWidth();
        int h = getIconHeight();
        int[] pixels = image != null? new int[w * h] : null;

        if (image != null) {
            try {
                PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
                pg.grabPixels();
                if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
                    throw new IOException("failed to load image contents");
                }
            }
            catch (InterruptedException e) {
                throw new IOException("image load interrupted");
            }
        }
        s.writeInt(w);
        s.writeInt(h);
        s.writeObject(pixels);
    }

    private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
        s.defaultReadObject();

        int w = s.readInt();
        int h = s.readInt();
        int[] pixels = (int[])(s.readObject());

        if (pixels != null) {
            Toolkit tk = Toolkit.getDefaultToolkit();
            ColorModel cm = ColorModel.getRGBdefault();
            image = tk.createImage(new MemoryImageSource(w, h, cm, pixels, 0, w));
        }
    }
}

Note that using an integer for each pixel is an extremely inefficient way to save an image. GIF or JPEG encoded images can easily be 10 times more compact. If size is a concern, you might want to investigate other image formats. For example, at http://www.acme.com/ you can find classes that let you write an image out in GIF format. Alternatively, you can compress your array of integers before writing it to the stream.

0 Comments  (click to add your comment)
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

About | Sitemap | Contact