Home : Course Map : Chapter 11 : Java :
More about Image Loading
JavaTech
Course Map
Chapter 11

Introduction
Image Class
Image Loading
  Demo 1 Demo 2  
Pixels/Transparency
  Demo 3
Pixel Handling
  Demo 4  
Demo 5
Exercises

    Supplements
Java 2D Imaging
BufferedImage
Creating Buf.Image
Pixel Handling
  Demo 1 Demo 2
Filters
  Convolutions
     Demo 3
  AffineTransforms
     Demo 4
  LookupTable
     Demo 5 Demo 6
  Rescale
     Demo 7
  Color Conversion
     Demo 8
  Custom
     Demo 9
Exercises
Java Adv Imaging
AWT Flicker:
  Override Update
     Demo 1  Demo 2
  Clipping
     Demo 3
  Double Buffer
     Demo 4

     About JavaTech
     Codes List
     Exercises
     Feedback
     References
     Resources
     Tips
     Topic Index
     Course Guide
     What's New

We mentioned an Chapter 6 : Java : Images that an image is not actually loaded when getImage()is invoked. Only when an attempt is made to access the image, such as an invocation of drawImage() or getWidth() will the loading of the image begin.

Once the loading begins, it is, of course, not instantaneous. It can in fact take considerable time if the loading takes place over a slow network link. The loading is controlled by an internal thread so that other processing can continue. We look here a three approaches to loading images.

  1. ImageObserver - override the method imageUpdate () and monitor the loading "manually"
  2. MediaTracker - tool to monitor the loading of one or more images
  3. ImageIcon - a useful class to load a single image.

See also the discussion in Chapter 11: Supplements: Creating & Saving Images about using classes in the javax.imageio package for reading/writing instances of BufferedImage.

Monitoring with an ImageObserver

If no other steps are taken, a call to drawImage() will return immediately while the image continues to be periodically updated as more pixels arrive. The last argument to drawImage() is a reference to an object that implements the ImageObserver interface:

  drawImage (Image img, int x, int y, ImageObserver iob)

The image loading thread periodically calls imageUpdate() in the ImageObserver object to provide status reports on the loading:

  public boolean imageUpdate (Image img, int info_flags,
                              int x, int y, int w, int h)

This method receives information via the bit settings in the info_flags argument and from the dimension values. For the situation of multiple images loading, you can identify which image is being updated from the reference value in the first argument.

The method imageUpdate() returns true when the loading is not yet finished. See the ImageObserver class description in the API Specifications and the Constant Field Values for more details about the info_flags values passed in the method's arguments.

You could create an ImageObserver class just for monitoring the image loading but usually you just put "this" in the last argument, as in

   g.drawImage (img, x, y, this)

and rely on the default imageUpdate() of the Applet class, which inherits this method from Component. The Component class implements this interface and provides a default imageUpdate() method..

You can also override imageUpdate() and monitor the loading yourself. The program ImageObsApplet below shows one way to implement imageUpdate(). The applet's start() method starts a thread that will periodically check a flag - fDoneLoadingImage - that indicates whether the image has finished loading.

In the run() method, the invocation of getWidth(ImageObserver) for the image initiates the loading process. The image loading machinery in the AWT will periodically call back to the ImageObserver object passed in the argument to getWidth(). It invokes the imageUpdate() method and passes the image information described above.

As long as info_flags != ALLBITS then the method returns true. When info_flags == ALLBITS then the flag fDoneLoadingImage is set to true, which will cause the loop in the run() method to finish and the thread to die. The imageUpdate() will return false and it will no longer be invoked.

ImageObsApplet.java
Resources: 07-JG-01-pan-A074R1_br2.jpg

import javax.swing.*;
import java.awt.*;

/** Illustrate use of ImageObserver for image loading. **/
public class ImageObsApplet extends JApplet
                       implements Runnable
{
  // Need a reference to the panel for the
  // thread loop.
  DrawingPanel fDrawingPanel;

  Image fImg;
  int fImageNum = 0;
  String fMessage ="Loading...";
  boolean fDoneLoadingImage = false;

  /** Use a ImageObserver to load an image.**/
  public void init () {
    Container content_pane = getContentPane ();

    // Create an instance of DrawingPanel
    fDrawingPanel = new DrawingPanel (this);

    // Add the DrawingPanel to the contentPane.
    content_pane.add (fDrawingPanel);

    // Get image and monitor its loading.
    fImg = getImage (getCodeBase (), "07-JG-01-pan-A074R1_br2.jpg" );

  } // init

  /**
    * Start the thread to monitor the image loading.
   **/
  public void start () {
    Thread thread = new Thread (this);
    thread.start ();
  }

  /** Use a thread to wait for the image to load
    * before painting it.
   **/
  public void run ()  {

    // Checking the image width will initiate the loading.
    int width = fImg.getWidth (this);

    // If the width is not equal to -1 then the file has already
    // been loaded. This can happen if the applet page was loaded
    // once before and then loaded again into the browser.
    if (width >= 0) {
        fDoneLoadingImage = true;
        repaint ();
        return;
    }


    // Wait if the image is not loaded yet
    while (!fDoneLoadingImage) {
      try {
        Thread.sleep (500);
      }
      catch (InterruptedException ie) {
      }
      // Repaint with either the image or the text message
      repaint ();
    }
  } // run

  /** Override the ImageObserver imageUpdate method and monitor
    * the loading of the image. Set a flag when it is loaded.
   **/
  public boolean imageUpdate (Image img, int info_flags,
                             int x, int y, int w, int h) {
    if (info_flags != ALLBITS) {
        // Indicates image has not finished loading
        // Returning true will tell the image loading
        // thread to keep drawing until image fully
        // drawn loaded.
        return true;
    } else {
        fDoneLoadingImage = true;
        return false;
    }
  } // imageUpdate

}// class ImageObsApplet


/** This JPanel subclass draws an image on the panel if
  * the image is loaded. Otherwise, it draws a text message.
**/
class DrawingPanel extends JPanel {
  ImageObsApplet fParent = null;

  DrawingPanel (ImageObsApplet parent) {
    fParent = parent;
  }// ctor

  public void paintComponent (Graphics g) {
    super.paintComponent (g);

    // Add your drawing instructions here
    if (fParent.fDoneLoadingImage)
        g.drawImage (fParent.fImg,10,10,this);
    else
        g.drawString (fParent.fMessage, 10,10);
  } // paintComponent

} // class DrawingPanel

 

MediaTracker

A more powerful and elegant way to monitor image loading is to use the MediaTracker class. Below we see that an instance of the MediaTracker is created and the image added to it. A thread is initiated to load the image. The run() waits for the tracker to signal that the image is loaded and then the paint() switches from drawing a string message to drawing the image.

MediaTracker provides the method

   int status (int ID, boolean load)

which returns a status indicator in an integer value that is an OR of four flags:

  1. ABORTED
  2. COMPLETE
  3. ERRORED
  4. LOADING

The MediaTracker is especially useful when one needs to load many images. The statusAll() returns a similar value as above except that it is an OR of the status of all the images currently loading.

MediaTrackApplet.java
Resources: m20.gif

import javax.swing.*;
import java.awt.*;

/** Illustrate use of MediaTracker for image loading. **/
public class MediaTrackApplet extends JApplet
                       implements Runnable
{
  // Need a reference to the panel for the
  // thread loop.
  DrawingPanel fDrawingPanel;

  // Parameters to track the image
  MediaTracker fTracker;
  Image fImg;
  int fImageNum = 0;
  boolean fShow = false;
  String fMessage ="Loading...";

  /** Use a MediaTracker to load an image.**/
  public void init () {
    Container content_pane = getContentPane ();

    // Create an instance of DrawingPanel
    fDrawingPanel = new DrawingPanel (this);

    // Add the DrawingPanel to the contentPane.
    content_pane.add (fDrawingPanel);

    // Get image and monitor its loading.
    fImg = getImage (getCodeBase (), "m20.gif.jpg" );
    fTracker = new MediaTracker (this);

    // Pass the image reference and an ID number.
    fTracker.addImage (fImg, fImageNum);
  } // init

  /** If the image not yet loaded, run the thread
    * so the run() will monitor the image loading.
   **/
  public void start () {
    if (!fTracker.checkID (fImageNum) ) {
        Thread thread = new Thread (this);
        thread.start ();
    } else
        // Unloading/reloading web page can will leave
        // checkID true but fShow will be false.
        fShow = true;
  } // start

  /** Use a thread to wait for the image to load
    * before painting it.
   **/
  public void run ()  {
    // Paint the loading message
    repaint ();
    // The wait for the image to finish loading
    try {
      fTracker.waitForID (fImageNum );
    } catch (InterruptedException e) {}

    // Check if there was a loading error
    if (fTracker.isErrorID (fImageNum ))
        fMessage= "Error";
    else
        fShow = true;
    // Repaint with the image now if it loaded OK
    repaint ();
  } // run

}// class MediaTrackApplet


/** This JPanel subclass draws an image on the panel if
  * the image is loaded. Otherwise, it draws a text message.
 **/
class DrawingPanel extends JPanel {
  MediaTrackApplet parent = null;

  DrawingPanel (MediaTrackApplet parent) {
    this.parent = parent;
  }// ctor

  public void paintComponent (Graphics g) {
    super.paintComponent (g);

    // Add your drawing instructions here
    if (parent.fShow)
        g.drawImage (parent.fImg,10,10,this);
    else
        g.drawString (parent.fMessage, 10,10);
  } // paintComponent

} // class DrawingPanel

 

See the API Specifications for details of the MediaTracker class.

Using ImageIcon to an Load Image

The ImageIcon class offers a shortcut technque for loading an image. This class, which came with Java 1.2 in the java.swing package, was primarily intended for obtaining small icon images on buttons and other components. However, it can also be used to load any image file, regardless of the size.

ImageIcon uses a MediaTracker internally so it provides a convenient way to load a single image as illustrated by this snippet:.

   ...
   ImageIcon img = new ImageIcon (url);
   Image image = img.getImage ();
   ...

The ImageIcon constructor will block (i.e. not return) until either the image loads or the address is deemed invalid. In the later case an ImageIcon object is still created but it will have zero dimensions. The method getImageLoadStatus() returns an integer with the status flags (see above) from the internal MediaTracker.

References & Web Resources

Latest update: March 8, 2006

              Tech
Fractals
Fractal Drawing
   Demo 1
Fractal Draw Code
Fractal Images
  Demo 2
Image Processing
  Demo 3
Histogram Image
  Demo 4
Exercises

           Physics
Calibration/SysError
SimWithCal/SysErr
  Demo 1
Analysis
  Demo 2
Examples

Exercises

  Part I Part II Part III
Java Core 1  2  3  4  5  6  7  8  9  10  11  12 13 14 15 16 17
18 19 20
21
22 23 24
Supplements

1  2  3  4  5  6  7  8  9  10  11  12

Tech 1  2  3  4  5  6  7  8  9  10  11  12
Physics 1  2  3  4  5  6  7  8  9  10  11  12

Java is a trademark of Sun Microsystems, Inc.