Previous | Next | Trail Map | Creating a GUI with JFC/Swing | Working with Graphics

Improving the Appearance and Performance of Image Animation

You might have noticed two things about the animation on the previous page:

The problem of displaying partial images is easy to fix, using the MediaTracker(in the API reference documentation) class. MediaTracker also can decrease the amount of time that loading images takes. Another way to deal with the problem of slow image loading is to change the image format somehow; this page gives you some suggestions for doing so.


Note: The ImageIcon class (in the Creating a User Interface trail) provided by Swing automatically uses a MediaTracker to download image data as soon as an ImageIcon is created. For more information, see How to Use Icons(in the Creating a User Interface trail). [PENDING: check!]

Using MediaTracker to Download Images and Delay Image Display

The MediaTracker class lets you easily download data for a group of images and find out when the images are fully loaded. Ordinarily, an image's data isn't downloaded until the image is painted for the first time. To request that the data for a group of images be preloaded asynchronously, use one of the following MediaTracker methods: checkID(anInt, true) or checkAll(true). To load data synchronously (waiting for the data to arrive), use the waitForID or waitForAll method. The MediaTracker methods that load data use several background threads to download the data, which can speed up downloading.

To check on the status of image loading, you can use the MediaTracker statusID or statusAll method. To simply check whether any image data remains to be loaded, you can use the checkID or checkAll method.

In MTImageSequenceTimer.java is a modified version of the example applet that uses the MediaTracker waitForAll and checkAll methods. Until every image is fully loaded, this applet simply displays a "Please wait..." message. See the MediaTracker API documentation(in the API reference documentation) for an example that paints a background image immediately, but delays painting the animated images.

Here is a picture of the applet:

Click this figure to run the applet.
This is a picture of the applet's GUI. To run the applet, click the picture. The applet will appear in a new browser window.
Below is the changed code, which uses a MediaTracker to help delay image display. Differences are marked in a bold font.
...//Where instance variables are declared:
MediaTracker tracker;

tracker = new MediaTracker(this);

...//In the init method:
for (int i = 1; i <= 10; i++) {
    images[i-1] = getImage(getCodeBase(), "images/duke/T"+i+".gif");
}

...//In the buildUI method, which is called by init and main, 
   //allowing us to run the sample as an applet or an application:
for (int i = 1; i <= 10; i++) {
    tracker.addImage(images[i-1], 0);
}

...//At the beginning of the actionPerformed method:
try {
    //Start downloading the images. Wait until they're loaded.
    tracker.waitForAll();
} catch (InterruptedException e) {}

...//In the paintComponent method:
//If not all the images are loaded, just clear the background
//and display a status string.
if (!tracker.checkAll()) {
    g.clearRect(0, 0, d.width, d.height);
    g.drawString("Please wait...", 0, d.height/2);
}

//If all images are loaded, paint.
else {
    ...//same code as before...
}

Speeding Up Image Loading

Whether or not you use MediaTracker, loading images using URLs (as applets usually do) usually takes a long time. Most of the time is taken up by initiating HTTP connections. Each image file requires a separate HTTP connection, and each connection can take several seconds to initiate.

The key to avoiding this performance hit is to put the images in a single file. You can do this using a JAR file, as described in Combining an Applet's Files into a Single File(in the Writing Applets trail) and Using JAR Files: The Basics(in the Java Security 1.2 trail).

Another performance strategy that might help is to combine a group of images into a single image file. One simple way to do this is to create an image strip -- a file that contains several images in a row. Here's an example of an image strip:

jack.gif:

To paint an image from the strip, you first set the painting area to the size of one image. Then you paint the image strip, shifted to the left (if necessary) so that only the image you want appears within the painting area. For example:

//imageStrip is the Image object representing the image strip.
//imageWidth is the size of an individual image in the strip.
//imageNumber is the number (from 0 to numImages) of the image to paint.
int stripWidth = imageStrip.getWidth(this);
int stripHeight = imageStrip.getHeight(this);
int imageWidth = stripWidth / numImages;
g.clipRect(0, 0, imageWidth, stripHeight);
g.drawImage(imageStrip, -imageNumber*imageWidth, 0, this);

If you want image loading to be faster still, you should look into image compression schemes, especially ones that perform interframe compression.


Previous | Next | Trail Map | Creating a GUI with JFC/Swing | Working with Graphics