- 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
Extending the Border
It is often necessary to add borders to images. For example, as we saw in Chapter 8, the convolution operations often cannot fill the last rows and columns of an image. One way to fill them is to add a border. In addition, you may wish to add a decorative border to a displayed image. There are two ways you can add a border:
Using the subclasses of BorderExtender
Using the Border operator
Using the BorderExtender Class
Let's look at the BorderExtender class hierarchy first, as shown in Figure 11.1. BorderExtender, which is at the root of the hierarchy, is an abstract class that allows you to specify the number of pixels to be filled in all sides of the border. BorderExtender has five subclasses, each of which provides a different way to fill the border pixels.
FIGURE 11.1 The borderextender class hierarchy
The subclasses of BorderExtender represent the following five operations:
Zero fill. The border is filled with zeros. The constant BorderExtender.BORDER_ZERO represents this operation.
Constant fill. The pixels in the border are filled by a constant value. If the image has more than one band, each band can have a different constant fill value. The constant values are provided as an array through the constructor of the BorderExtenderConstant class.
Copy. The edge and corner pixels of the source image are copied onto the border area. The constant BorderExtender.BORDER_COPY represents this operation.
Reflection. The pixels on the outer edge of the source image are copied onto the border area. The constant BorderExtender.BORDER_REFLECT represents this operation.
-
Wrap. The image pixels are copied in such a way that the opposite edges of the images appear to be joined (see Figure 11.2). The BorderExtender.BORDER_WRAP constant represents this operation.
FIGURE 11.2 The border wrap operation
The BorderExtender class has the following two methodsone abstract and the other static:
public static BorderExtender createInstance(int extenderType)
public abstract void extend(java.awt.image.WritableRaster raster, PlanarImage im)
This factory method constructs an instance of a BorderExtender object. The BorderExtender class has four constants to represent the extender operations: BORDER_ZERO, BORDER_COPY, BORDER_WRAP, and BORDER_REFLECT. The extenderType parameter can be any of the four constants. Note that no constant is defined for the constant fill operation because constant fill requires an array of constant values.
The subclasses of the BorderExtender class implement this method. As Figure 11.3 shows, the writableRaster parameter contains the border and the image. Depending on the operation, appropriate pixels are copied onto the border area of writableRaster. If the Raster object supplied doesn't cover the image, no pixels are copied.
FIGURE 11.3 An image layout with borders
You can use a BorderExtender object in two ways:
The BorderExtender object can be supplied to an operation as a rendering hint. JAI.KEY_BORDER_EXTENDER is the key value for this rendering hint. The value can be any one of the five BorderExtender constants.
The PlanarImage class has the following methods that take BorderExtender as one of the parameters:
public void copyExtendedData(WritableRaster dest, BorderExtender extender)
public Raster getExtendedData(Rectangle region, BorderExtender extender)
Using the Border Operator
You can also use the Border operator to add the border. This operator takes a rendered image as a source. Table 11.4 lists the parameters of the Border operator.
The example in Listing 11.2 uses the Border operator to add a border to images.
LISTING 11.2 Adding a border to an image
public static RenderedOp setConstantBorder(PlanarImage img, Dimension border, double constVal) { ParameterBlock pb = new ParameterBlock(); pb.addSource(img); pb.add(border.width); pb.add(border.height); pb.add(border.width); pb.add(border.height); pb.add(BorderDescriptor.BORDER_CONST_FILL); int numbands = img.getSampleModel().getNumBands(); double[] fillValue = new double[numbands]; for (int i=0;i<numbands;i++) { fillValue[i] = constVal; } pb.add( fillValue); return JAI.create("border", pb); }
When the border is added, the image dimensions change. The width and height of the image increase, and minX and minY coordinates become negative. Keep this in mind while writing the code for painting the image. To make the image display appear symmetrical, you can either use the Format operator to restructure the image or translate the image by an appropriate amount.
TABLE 11.4 Border Operator Parameters
Operator Name |
Parameter |
Type |
Default Value |
Description |
Border |
leftPad |
int |
0 |
See Figure 11.3 |
rightPad |
int |
0 |
||
topPad |
int |
0 |
||
bottomPad |
int |
0 |
||
type |
int |
BorderDescriptor. BORDER_ZERO_FILL |
One of the BorderDescriptor constants |
|
constants |
double[] |
null |
An array of constants |
|