Working with Graphics |
All image filters must be subclasses of the ImageFilter class. If your image filter will modify the colors or transparency of an image, then instead of creating a direct subclass of ImageFilter, you should probably create a subclass of RGBImageFilter.Before writing an image filter, you first should find others, studying any that are similar to what you plan to write. You should also study the ImageProducer and ImageConsumer interfaces, becoming thoroughly familiar with them.
Finding Examples
You can find examples of RGBImageFilter subclasses in the applets mentioned on the previous page (Dynamically Generated Color Bullets, Live Feedback ImageMap, and Image Test).Later in this page, you'll see an example of a direct ImageFilter subclass, RotateFilter.
Creating an ImageFilter Subclass
As we mentioned before, image filters implement the ImageConsumer interface. This lets them intercept data intended for the image consumer. ImageConsumer defines the following methods:The ImageFilter class implements all the above methods so that they forward the method data to the filter's consumer. For example, ImageFilter implements thevoid setDimensions(int width, int height); void setProperties(Hashtable props); void setColorModel(ColorModel model); void setHints(int hintflags); void setPixels(int x, int y, int w, int h, ColorModel model, byte pixels[], int off, int scansize); void setPixels(int x, int y, int w, int h, ColorModel model, int pixels[], int off, int scansize); void imageComplete(int status);setDimensions()
method as follows:Thanks to these ImageFilter methods, your subclass probably doesn't need to implement every ImageConsumer method. You need to implement only the methods that transmit data you want to change.public void setDimensions(int width, int height) { consumer.setDimensions(width, height); }For example, the CropImageFilter class implements four of the ImageConsumer methods:
setDimensions()
,setProperties()
, and both varieties ofsetPixels()
. It also implements a constructor with arguments that specify the rectangle to be cropped. As another example, the RGBImageFilter class implements some helper methods, defines an abstract helper method to perform the actual color modifications of each pixel, and implements the following ImageConsumer methods:setColorModel()
and both varieties ofsetPixels()
.Most, if not all, filters implement the
setPixels()
methods. These methods determine exactly what image data is used to construct the Image. One or both of thesetPixels()
methods may be called multiple times during the construction of a single image. Each call gives the ImageConsumer information about a rectangle of pixels within the image. When the ImageConsumer'simageComplete()
method is called with any status except SINGLEFRAMEDONE (which implies that data for more frames will appear), then the ImageConsumer can assume that it will receive no furthersetPixels()
calls. AnimageComplete()
status of STATICIMAGEDONE specifies that not only is the image data complete, but that no errors have been detected.The following illustration and table describe the arguments to the
setPixels()
methods.
x
,y
- Specify the location within the image, relative to its upper left corner, at which this rectangle begins.
w
,h
- Specify the width and height, in pixels, of this rectangle.
model
- Specifies the color model used by the data in the pixels array.
pixels[]
- Specifies an array of pixels. The rectangle of image data is contained in this array, but the array might contain more than
w
*h
entries, depending on the values ofoffset
andscansize
. Here's the formula for determining what entry in thepixels
array contains the data for the pixel at (x
+i,y
+j), where (0 <= i <w
) and (0 <= j <h
):The above formula assumes that (m,n) is in the rectangle thisoffset + (j * scansize) + isetPixels()
call specifies, and that (m,n) is relative to the image origin. Below is an illustration of thepixels
array to make this clearer. It shows how a specific pixel (for example, (x,y)) maps to an entry in thepixels
array.offset
- Specifies the index (in the
pixels
array) of the first pixel in the rectangle.scansize
- Specifies the width of each row in the
pixels
array. Due to efficiency considerations, this might be greater thanw
.The RotateFilter Image Filter
The RotateFilter class rotates an image by the specified angle. It relies on the following graphics formulas to calculate the new position of each pixel:RotateFilter implements the following ImageConsumer methods:newX = oldX*cos(angle) - oldY*sin(angle) newY = oldX*sin(angle) + oldY*cos(angle)
setDimensions()
- Records the unfiltered image's width and height for use in the
setPixels()
andimageComplete()
methods. Calculates the filtered image's final width and height, records it for use in itsimageComplete()
method, creates a buffer to store the image data as it comes in, and calls the consumer'ssetDimensions()
method to set the new width and height.setColorModel()
- Tells the consumer to expect pixels in the default RGB color model.
setHints()
- Tells the consumer to expect the image data in top-down-left-right order (the order in which you're reading this page), in complete scan lines, and with every pixel sent exactly once.
setPixels()
(both varieties of this method)- Converts the pixels to the default RGB model (if necessary) and copies the pixels into a storage buffer. Most image filters would simply modify the pixel data and forward it to the consumer, but because the sides of a rotated rectangle are no longer horizontal and vertical (for most angles), this filter can not efficiently forward pixels from its
setPixels()
method. Instead, RotateFilter stores all the pixel data until it receives animageComplete()
message.imageComplete()
- Rotates the image and then invokes
consumer.setPixels()
repeatedly to send each line of the image to the consumer. After sending the whole image, this method invokesconsumer.imageComplete()
.
Working with Graphics |