Transferring an Image over the network

Serialization won’t work here because the actual contents of the image (the colors of the pixels) is kept in native code and Serialization only works on Java objects.

The solution is to obtain pixel values and write them into a socket. On the other side, the pixel values must be read and converted into an Image again. Here’s a method that takes an Image and writes its pixel color values into the given OutputStream:

/**
 * Grabs the pixels of the given Image object and returns the array of those
 * pixels. Note that the Image needs to be preloaded in order for this
 * method to work correctly.
 * 
 * @param Image img: The image whose pixels to grab.
 * 
 * @return The values of the pixels encoded in 4 bytes each
 * in aRGB format.
 */

public static int [] grabPixels(Image img){
  int width = img.getWidth(null);
  int height = img.getHeight(null);
  int [] pixels = new int[width*height];
  PixelGrabber grabber = new PixelGrabber(img,0,0,width,height,pixels,0,width);
  try{
    if (!grabber.grabPixels())
      return null;
  } catch (InterruptedException e){
      return null;
    }
  return pixels;
}
 
public static void writeImage(Image img, OutputStream out) throws IOException{
  int [] pixelValues = grabPixels(img);
  ObjectOutputStream objectOut = new ObjectOutputStream(out);  
  objectOut.writeObject(pixelValues); // Arrays are Serializable
}

And here is code that reads the pixel values from the given InputStream, creates and returns an Image object representing the image:

/**
 * Creates an Image object from the given array of pixels.
 * Note that the returned Image is created using an ImageProducer
 * (MemoryImageSource), and such Images are painted much slower than
 * offscreen Images created via Component.createImage(int,int) and you can't
 * draw on these Images as their getGraphics() method will return null. If
 * you need an Image that will be drawn fast and/or you need to paint
 * additional things on the Image, create an offscreen Image using
 * Component.createImage(int,int) and paint the Image returned by this method
 * on that Image.
 * Parameters:
 *   int [] pixels: The pixels array.
 *   int width: The width of the Image.
 *   int height: The height of the Image.
 */
 
public static Image createImage(int [] pixels, int width, int height){
  MemoryImageSource imageSource = new MemoryImageSource(width,height,pixels,
                                                        0,width);
  return Toolkit.getDefaultToolkit().createImage(imageSource);
}
 
 
public static Image readImage(InputStream in) throws IOException{
  ObjectInputStream objectIn = new ObjectInputStream(in);
  try{
    int [] pixelValues = (int [])objectIn.readObject();
  } catch (ClassNotFoundException e){} // This can't happen
    // since the class for (int []) must be present on every JVM
}