Introduction

To begin, let's look at a simple program written using the Java Advanced Imaging (JAI) package. This program (shown in Listing 6.1) takes as parameters an image filename and a scale factor. It loads the image, scales its dimensions, and displays the results.

Listing 6.1 Intro.java
package ch6;

import java.awt.*;
import javax.swing.*;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;

/**
   Intro.java -- objects of this class perform the following steps:
   1.  reads an image file
   2.  scales the image dimensions using provided scale factor
   3.  displays the result
*/
public class Intro extends JFrame {

    public Intro(String filename, String scaleFactor) {
        ParameterBlock pb;

        /*
          create new ParameterBlock,
          add filename parameter,
          create RenderedOp
        */
        pb = new ParameterBlock();
        pb.add(filename);
        RenderedOp inputRO = JAI.create("fileload", pb);

        /*
          create new ParameterBlock,
          add a source and add a scale parameter,
          create RenderedOp
        */
        pb = new ParameterBlock();
        pb.addSource(inputRO);
        float scale = Float.parseFloat(scaleFactor);
        pb.add(scale); // x dimension scale factor
        pb.add(scale); // y dimension scale factor
        RenderedOp scaledRO = JAI.create("scale", pb);

        // display result
        getContentPane().add(new ch6Display(scaledRO));
        pack();
        show();
    }

    public static void main(String[] args) {
        if (args.length != 2)
            System.err.println("Usage:  filename scaleFactor");
        else
            new Intro(args[0], args[1]);
    }
}

By examining Listing 6.1, you will notice the pattern that is underlying much of JAI's functionality. That pattern follows these steps:

1.
Set up a ParameterBlock with the necessary sources and parameters according to the corresponding operation.

2.
Call the JAI class's static method create with the operation name and the ParameterBlock.

3.
Use the result of this operation as a source for subsequent operations.

Note that this listing and most listings in this chapter make use of the ch6Display class defined in Listing 6.2 for displaying images.

Listing 6.2 ch6Display.java
package ch6;

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

/**
   Very simple class for displaying RenderedImages
 */
public class ch6Display extends JPanel {
    public ch6Display(RenderedImage image) {
        super();
        source = image;
        setPreferredSize(new Dimension(source.getWidth(),
                                       source.getHeight()));
    }

    public synchronized void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;

        // account for borders and source image offsets
        Insets insets = getInsets();
        int tx = insets.left - source.getMinX();
        int ty = insets.top  - source.getMinY();

        AffineTransform af;
        af = AffineTransform.getTranslateInstance(tx, ty);

        // Translation moves the entire image within the container
        g2d.drawRenderedImage(source, af);
    }
    protected RenderedImage source = null;
}

As you will see in the remainder of this chapter, not only is the Java Advanced Imaging package simple to use, but it also has many useful features not illustrated in this example, such as the ability to

  • Go easily back and forth between Java 2D classes and JAI classes.

  • Provide resolution independent operations.

  • Work on remote images.

  • Add your own image processing operators.

  • Use float and double data types for pixel values.

  • Use native code to increase speed of image processing operations.

In this chapter, we will start off describing underlying concepts such as imaging models. We will then look at some important JAI classes. Then we will look into the different JAI operators that are provided and how they are to be used. Finally, we will look at some more advanced topics such as remote image processing, renderable images, and creating your own image processing operators.

Imaging Models

In the original AWT package, the main class used for image processing is the java.awt.Image class. This class doesn't store image data, but it contains methods and resources to allow this data to be displayed and manipulated. The image data is obtained through an ImageConsumer, which registers itself with an ImageProducer. This ImageConsumer instructs the ImageProducer to start producing data. It is important to note that the ImageConsumer never requests data for a particular pixel location. It just asks that the image production begin, and then processes data as it arrives. This behavior specifies a push imaging model, as illustrated in Figure 6.1.

Figure 6.1. Java's push imaging model.


In this figure, a request from the final ImageConsumer causes the initial ImageProducer to begin image production. As the image data is produced it passes through the ImageConsumer/ImageProducer pipeline until it is received by the final ImageConsumer. In this model, the final ImageConsumer might be processing or displaying image data it has received while the initial ImageProducer is still producing the rest of the image data. Note that for the ImageConsumer/ImageProducer pairs, the ImageConsumers are usually java.awt.image.ImageFilters and the ImageProducers are usually java.awt.image.FilteredImageSources.

In the Java2D package, the main class used for image processing is the java.awt.image.BufferedImage class. Unlike the Image class, BufferedImage objects provide storage for image data. Whenever a new BufferedImage is created, its image pixels are immediately calculated and made available to any object that requests them. This behavior specifies an immediate mode imaging model.

As illustrated in Figure 6.2, the requesting objects are usually BufferedImageOps. When a BufferedImageOp's filter method is called, it creates a new BufferedImage whose data can be used by the next BufferedImageOp. Note that Figure 6.2 is just one example of the Java immediate mode imaging model. An analogous interface called RasterOp performs the same function for Rasters that BufferedImageOps performs for BufferedImages. Thus, this figure could have also been diagrammed using RasterOps and WritableRasters.

Figure 6.2. Java's immediate mode imaging model.


In the JAI package, the main class used for image processing is the javax.media.jai.PlanarImage class. PlanarImage objects don't make their data immediately available, but wait until an object requests it; at which time, all its pixel data is calculated before being passed on. This behavior specifies a new Java imaging model referred to as the pull imaging model, as illustrated in Figure 6.3.

Figure 6.3. Java's pull imaging model.


In this figure, when the final RenderedImage is requested, its corresponding RenderedOp attempts to create it. To do so, it requests the data from its source RenderedOps, which must then create their RenderedImages. These requests work their way to the original RenderedOp, which will have no image sources and will be able to create its RenderedImage without making any further requests. In each case, only after all its image data is created will a RenderedOp object provide its RenderedImage to the requesting object.

BufferedImage Revisited

In Chapter 4, “The Immediate Mode Imaging Model,” the BufferedImage class was described as having a Raster for holding and accessing pixel data and a ColorModel for pixel data interpretation. Further understanding of a BufferedImage's behavior can be obtained by examining the two interfaces it implements: the java.awt.image.RenderedImage and java.awt.image.WritableRenderedImage interfaces. The RenderedImage interface describes the functionality required to provide tiled, read only images in the form of a Raster. The WritableRenderedImage interface describes the additional functionality required to provide tiled, writable images in the form of a WritableRaster, which is a Raster subclass. Thus, a BufferedImage can provide its image data as either a Raster or a WritableRaster.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset