- Applying Rendering Hints
- Managing Memory
- Scheduling Tiles
- Reformatting an Image
- Extending the Border
- A Rendering Example
- A Closer Look at the PlanarImage Class
- Using the RenderedOp Class
- Working with Tiles
- A Tiled-Image Viewer
- Writing to Pixels
- Creating an Aggregate Image
- A JAI Image Browser
- The Renderable Layer
- Conclusion
A Closer Look at the PlanarImage Class
The PlanarImage class is at the heart of image rendering in JAI. It is the base class for representing an image. Figure 10.3 showed the PlanarImage class hierarchy. Whether it is a rendered or renderable chain, the image is normally converted to a planar image for actual rendering because the planar image represents the actual physical image.
Although we have used PlanarImage in many examples, we have not described it in detail. So in this section we'll look more closely at its methods.
The PlanarImage class has just one constructor, which takes no arguments. A PlanarImage object is typically constructed by an image reader or an image operator, so you may not need to use this constructor at all.
Even when an image reader returns a RenderedImage object, as in the case of the Image I/O API, it can be converted to a PlanarImage object by the Rendered ImageAdapter class.
RenderedImage renderedImage = javax.imageio.ImageIO.read (new File("myImage.jpg")); RenderedImageAdapter planarImage = new RenderedImageAdapter(renderedImage);
Note that RenderedImageAdapter is a subclass of PlanarImage.
As mentioned earlier, the RenderedImage interface, which the PlanarImage class implements, has set and get methods for RenderedImage attributes, which are listed in Tables 10.1 and 10.2. In addition, the PlanarImage class has methods that are needed for rendering a JAI image. The tasks accomplished by these methods include converting the image to a buffered image or a snapshot image. The PlanarImage class also has some static utility methods that are often used in rendering. The sections that follow review the specific methods of PlanarImage.
Converting to a Buffered Image
The PlanarImage class has two methods that can convert a JAI image to a buffered image:
public BufferedImage getAsBufferedImage()
public BufferedImage getAsBufferedImage(Rectangle rect, ColorModel colorModel)
The first method converts the entire image into a buffered image. If the image is huge, you may not want to use this method because BufferedImage keeps all the image data in memory.
The second method converts a specified rectangular area into a buffered image. The color model must be compatible with the source image. If not, this method will throw an exception: IllegalArgumentException. If the value of the colorModel parameter is null, the source color model is used for constructing the buffered image.
These methods are handy when you need to construct a buffered image for the purpose of rendering or saving images. For example, a bean or application that is written with the Java 2D API may use only BufferedImage inputs. In that case you can use JAI for loading an image, convert it to a buffered image, and then pass it to the Java 2D bean or application. Along the same lines, a codec might have been developed with only Java 2D in mind. To save a planar image using that codec, you can use these methods to convert the image to a buffered image.
Remember that the RenderedImage interface is an API in Java 2D and part of J2SE. So if a method in a bean or application written with the Java 2D API takes a RenderedImage input, the PlanarImage object can be passed to it. The new Image I/O API takes this approach. In this API, methods to write an image take RenderedImage as an input. With this API, then, there is no need to convert PlanarImage to BufferedImage before saving.
Creating a Snapshot Image
As the name suggests, the SnapshotImage class represents a snapshot of the image contents at a given time. The PlanarImage class has the following method for creating such a snapshot:
public PlanarImage createSnapshot()
This method creates an immutable image with a copy of the source image's current contents. Multiple calls to this method don't create multiple copies of snapshot images. Instead, they create multiple references to a single SnapshotImage object. This means that at any given time there is one SnapshotImage object per PlanarImage instance.
Converting to a Planar Image
The following factory method in the PlanarImage class constructs a PlanarImage object from a RenderedImage object:
public static PlanarImage wrapRenderedImage(java.awt.image. RenderedImage im)
This method adds various properties to the input image, such as source and sink vectors and the ability to produce snapshots to create a PlanarImage object. If the image is already a planar image, it is simply returned unchanged. If the input image implements the RenderedImage interface, this method constructs a RenderedImage Adapter object. If the input implements the WritableRenderedImage interface, the method constructs a WritableRenderedImageAdapter object. RenderedImageAdapter is a subclass of PlanarImage, and WritableRenderedImageAdapter is a subclass of RenderedImageAdapter.
The wrapRenderedImage() method is a very convenient method that converts RenderedImage to the JAI-specific PlanarImage. For instance, a BufferedImage object that implements the RenderedImage interface can be converted to a PlanarImage object with this method. To convert images read by the Java 2D JPEG codec and the new Image I/O API, you can use this method as shown in the following example:
BufferedImage renderedImage = javax.imageio.ImageIO.read(new File("myImage")); PlanarImage planarImage = PlanarImage.wrapRenderedImage(renderedImage)
Converting Image Coordinates to Tile Index and Vice Versa
As we'll see later in this chapter, it is often necessary to compute the tile index when a coordinate in the image is given. For example, when an image is scrolled, the application needs to compute the ULHC of the image that is visible on the viewport. So the rendering program needs to compute tiles for the visible portion of the image. The following methods of the PlanarImage class do this:
public int XToTileX(int x)
public int YToTileY(int y)
public static int XToTileX(int x, int tileGridXOffset, int tileWidth)
public static int YToTileY(int y, int tileGridYOffset, int tileHeight)
The following methods do the reverse: convert a tile index to image coordinates:
public static int tileXToX(int tx, int tileGridXOffset, int tileWidth)
public static int tileYToY(int ty, int tileGridYOffset, int tileHeight)
public int tileXToX(int tx)
public int tileYToY(int ty)
Obtaining Sources and Sinks
When a PlanarImage object is part of a rendering chain, it is often necessary to obtain the list of sources and sinks. Here are the methods that do this:
public java.util.Vector getSinks()
public java.util.Vector getSources()
public int getNumSources()