Applying Affine Transformation to Images
In Chapter 4 you may have noticed that the AffineTransform class does not explicitly provide a way to apply the affine transformation to an image. However, we can do this by using the Graphics2D class or the AffineTransformOp class, as described in the sections that follow.
Using the Graphics2D Class
The Graphics2D class has a flavor of the drawImage() method that takes an AffineTransform object as an input parameter. This method applies the transformation to the image before rendering. Listing 7.1 gives an example.
LISTING 7.1 The applyTransform() method
protected BufferedImage applyTransform(BufferedImage bi, AffineTransform atx, int interpolationType){ Dimension d = getSize(); BufferedImage displayImage = new BufferedImage(d.width, d.height, interpolationType); Graphics2D dispGc = displayImage.createGraphics(); dispGc.drawImage(bi, atx, this); return displayImage; }
The drawImage() method used in Listing 7.1 applies the transformation parameter atx to the BufferedImage object before it draws onto the dispGc graphical context that belongs to displayImage. So in effect, one buffered image is transformed and drawn onto another buffered image. If displayImage is drawn on a context obtained through paint() or paintComponent(), you can see the transformed image.
As mentioned in Chapter 5, the Graphics2D object maintains a transform attribute. This attribute is applied after the transformation from the input parameter is applied.
Using the AffineTransformOp Class
Here's a quick introduction to the AffineTransformOp class. The class has two constructors:
public AffineTransformOp(AffineTransform xform, int interpolationType)
public AffineTransformOp(AffineTransform xform, RenderingHints hints)
The interpolationType parameter in the first constructor should be one of TYPE_BILINEAR and TYPE_NEAREST_NEIGHBOR, which are defined in the Affine TransformOp class itself. If you use the second constructor, you may have more choices of interpolation techniques, depending on your platform.
The AffineTransformOp class implements two interfaces: BufferedImageOp and RasterOp. It applies the affine transformation to the source image and creates a transformed destination image. While transforming the image, AffineTransformOp applies the interpolation technique provided through its constructor. It has two filter methods:
public final BufferedImage filter(BufferedImage src, BufferedImage dst)
public final WritableRaster filter(Raster src, WritableRaster dst)
In this chapter only the first filter method is of interest. We'll explore the second one in Chapter 8.
Listing 7.2 shows a sample implementation of the applyTransform() method using the AffineTransformOp class.
LISTING 7.2 The applyTransform() method using AffineTransformOp
protected BufferedImage applyTransform(BufferedImage bi, AffineTransform atx, int interpolationType){ Dimension d = getSize(); BufferedImage displayImage = new BufferedImage(d.width, d.height, interpolationType); Graphics2D dispGc = displayImage.createGraphics(); AffineTransformOp atop = new AffineTransformOp(atx, interpolationType); return atop.filter(bi, displayImage); }
In Listing 7.2 an AffineTransformOp object is created with AffineTransform and interpolationType parameters. The filter() method in the AffineTransformOp class is invoked next. This method takes two arguments: source and destination BufferedImage object. It applies the transformation to the source buffered image and puts the resulting image in the destination buffered image.
With both Graphics2D and AffineTransformOp, the transformation is applied to a BufferedImage object. The resulting BufferedImage object is then rendered to a Graphics2D context in the paint methods.
Although we didn't mention it explicitly in Chapter 6, there was some image manipulation in the ImageCanvas class, which was achieved through the drawImage() methods. For instance, setting up display modes and flip modes involved some image manipulation. These operations can now be performed with the AffineTransform class.