Previous | Next | Trail Map | Creating a User Interface (with Swing) | Working with Graphics

How to Use an Image Filter

The following applet uses a filter to rotate an image. The filter is a custom one named RotateFilter that you'll see discussed on the next page. All you need to know about the filter to use it is that its constructor takes a single double argument: the rotation angle in radians. The applet converts the number the user enters from degrees into radians, so that the applet can construct a RotateFilter.

Here's the source code that uses the filter. (Here's the whole program.)

public class ImageRotator extends Applet {
    . . .
    RotatorCanvas rotator;
    double radiansPerDegree = Math.PI / 180;

    public void init() {
        //Load the image.
        Image image = getImage(getCodeBase(), "../images/rocketship.gif");

        ...//Create the component that uses the image filter:
        rotator = new RotatorCanvas(image);
        . . .
        add(rotator);
        . . .
    }

    public boolean action(Event evt, Object arg) {
        int degrees;

        ...//Get the number of degrees to rotate the image by.

        //Convert to radians.
        rotator.rotateImage((double)degrees * radiansPerDegree);

        return true;
    }
}

class RotatorCanvas extends Canvas {
    Image sourceImage;
    Image resultImage;

    public RotatorCanvas(Image image) {
        sourceImage = image;
        resultImage = sourceImage;
    }

    public void rotateImage(double angle) {
        ImageFilter filter = new RotateFilter(angle);
        ImageProducer producer = new FilteredImageSource(
                                        sourceImage.getSource(),
                                        filter);
        resultImage = createImage(producer);
        repaint();
    }

    public void paint(Graphics g) {
        Dimension d = size();
        int x = (d.width - resultImage.getWidth(this)) / 2;
        int y = (d.height - resultImage.getHeight(this)) / 2;

        g.drawImage(resultImage, x, y, this); 
    }
}

How the Code Works

To use an image filter, a program goes through the following steps:
  1. Get an Image object (usually done with a getImage() method).
  2. Using the getSource() method, get the data source (an ImageProducer) for the Image object,
  3. Create an instance of the image filter, initializing the filter as necessary.
  4. Create a FilteredImageSource object, passing the constructor the image source and filter objects.
  5. With the Component Code>createImage() method, create a new Image object that has the FilteredImageSource as its image producer.

This might sound complex, but it's actually easy for you to implement. The real complexity is behind the scenes, as we'll explain a bit later. First, we'll explain the code in the example applet that uses the image filter.

In the example applet, the RotatorCanvas rotateImage() method performs most of the tasks associated with using the image filter. The one exception is the first step, getting the original Image object, which is performed by the applet's init() method. This Image object is passed to the RotatorCanvas, which refers to it as sourceImage.

The rotateImage() method instantiates the image filter by calling the filter's constructor. The single argument to the constructor is the angle, in radians, to rotate the image by.

ImageFilter filter = new RotateFilter(angle);
Next, the rotateImage() method creates a FilteredImageSource instance. The first argument to the FilteredImageSource constructor is the image source, obtained with the getSource() method. The second argument is the filter object.
ImageProducer producer = new FilteredImageSource(
                                sourceImage.getSource(),
                                filter);
Finally, the code creates a second Image, resultImage, by invoking the Component createImage() method. The lone argument to createImage() is the FilteredImageSource created in the above step.
resultImage = createImage(producer);

What Happens Behind the Scenes

This section explains how image filtering works, behind the scenes. If you don't care about these implementation details, feel free to skip ahead to Where to Find Image Filters.

The first thing you need to know is that the AWT uses ImageConsumers behind the scenes, in response to drawImage() requests. So the Component that displays the image isn't the image consumer -- some object deep in the AWT is the image consumer.

The createImage() call above sets up an Image (resultImage) that expects to get image data from its producer, the FilteredImageSource instance. Here's what the path for the image data looks like, from the perspective of resultImage:

The dotted line indicates that the image consumer never actually gets data from the FilteredImageSource. Instead, when the image consumer requests image data (in response to g.drawImage(resultImage,...)), the FilteredImageSource performs some sleight of hand and then steps out of the way. Here's the magic that FilteredImageSource performs:

Here is the result:

Where to Find Image Filters

So where can you find existing image filters? The java.awt.image package includes one ready-to-use filter, CropImageFilter(in the API reference documentation), which produces an image consisting of a rectangular region of the original image. You can also find several image filters used by applets at our website. All of the following pages include links to the source code for each applet and image filter:


Previous | Next | Trail Map | Creating a User Interface (with Swing) | Working with Graphics