Полезная информация

Exploring Java

Previous: 17.1 Image ProcessingChapter 17
Working with Images
Next: 17.3 Using a MediaTracker
 

17.2 Implementing an ImageObserver

To be an image observer, you have to implement the single method, imageUpdate(), defined by the java.awt.image.ImageObserver interface:

public boolean imageUpdate(Image image, int flags, int x, int y, 
                           int width, int height)

imageUpdate() is called by the consumer, as needed, to pass the observer information about the construction of its view of the image. Essentially, any time the image changes, the consumer tells the observer so that the observer can perform any necessary actions, like repainting. image holds a reference to the Image object the consumer is processing. flags is an integer whose bits specify what information about the image is now available. The values of the flags are defined as static identifiers in the ImageObserver interface, as shown in Table 17.1.

Table 17.1: ImageObserver Information Flags
FlagDescription
HEIGHT

The height of the image is ready.

WIDTH

The width of the image is ready.

FRAMEBITS

A frame is complete.

SOMEBITS

An arbitrary number of pixels have arrived.

ALLBITS

The image is complete.

ABORT

The image loading has been aborted.

ERROR

An error occurred during image processing; attempts to display the image will fail.

The flags determine which of the other parameters, x, y, width, and height, hold valid data and what that data means. To test whether a particular flag in the flags integer is set, we have to resort to some binary shenanigans. The following class, MyObserver, implements the ImageObserver interface and prints its information as it's called:

import java.awt.*; 
import java.awt.image.*; 
 
class MyObserver implements ImageObserver { 
 
    public boolean imageUpdate( Image image, int flags, int x, int y, 
                                int width, int height) { 
 
        if ( (flags & HEIGHT) !=0 ) 
            System.out.println("Image height = " + height ); 
 
        if ( (flags & WIDTH ) !=0 ) 
            System.out.println("Image width = " + width ); 
         
        if ( (flags & FRAMEBITS) != 0 ) 
            System.out.println("Another frame finished."); 
 
        if ( (flags & SOMEBITS) != 0 ) 
            System.out.println("Image section :" 
                         + new Rectangle( x, y, width, height ) ); 
 
        if ( (flags & ALLBITS) != 0 ) { 
            System.out.println("Image finished!"); 
            return false;  
        } 
 
        if ( (flags & ABORT) != 0 )  { 
            System.out.println("Image load aborted..."); 
            return false;  
        }
            return true;  
    } 
} 

The imageUpdate() method of MyObserver is called by the consumer periodically, and prints simple status messages about the construction of the image. Notice that width and height play a dual role. If SOMEBITS is set, they represent the size of the chunk of the image that has just been delivered. If HEIGHT or WIDTH is set, however, they represent the overall image dimensions. Just for amusement, we have used the java.awt.Rectangle class to help us print the bounds of a rectangular region.

imageUpdate() returns a boolean value indicating whether or not it's interested in future updates. If the image is finished or aborted, imageUpdate() returns false to indicate it isn't interested in further updates. Otherwise, it returns true.

The following example uses MyObserver to print information about an image as AWT loads it:

import java.awt.*; 
 
public class ObserveImage extends java.applet.Applet {  
    Image img; 
    public void init() { 
        img = getImage( getClass().getResource(getParameter("img")) ); 
        MyObserver mo = new MyObserver(); 
        img.getWidth( mo ); 
        img.getHeight( mo ); 
        prepareImage( img, mo ); 
    } 
} 

After requesting the Image object with getImage(), we perform three operations on it to kick-start the loading process. getWidth() and getHeight() ask for the image's width and height. If the image hasn't been loaded yet, or its size can't be determined until loading is finished, our observer will be called when the data is ready. prepareImage() asks that the image be readied for display on the component. It's a general mechanism for getting AWT started loading, converting, and possibly scaling the image. If the image hasn't been otherwise prepared or displayed, this happens asynchronously, and our image observer will be notified as the data is constructed.

You may be wondering where the image consumer is, since we never see a call to imageUpdate(). That's a good question, but for now I'd like you to take it on faith that the consumer exists. As you'll see later, image consumers are rather mysterious objects that tend to hide beneath the surface of image-processing applications. In this case, the consumer is hiding deep inside the implementation of Applet.

You should be able to see how we could implement all sorts of sophisticated image loading and tracking schemes. The two most obvious strategies, however, are to draw an image progressively, as it's constructed, or to wait until it's complete and draw it in its entirety. We have already seen that the Component class implements the first scheme. Another class, java.awt.MediaTracker, is a general utility that tracks the loading of a number of images or other media types for us. We'll look at it next.


Previous: 17.1 Image ProcessingExploring JavaNext: 17.3 Using a MediaTracker
17.1 Image ProcessingBook Index17.3 Using a MediaTracker

Other Books in this LibraryJava in a NutshellJava Language ReferenceJava AWTJava Fundamental ClassesExploring Java