You can implement the BufferedImageOp
interface to create your own custom filters. In addition to the
filter() method, there are four other
methods in the interface that must be implemented. The following
RotateOp example illustrates the basics
of creating a filter.
The filter() method offers the option
of using an existing BufferedImage
object, passed via the second argument, to receive the output of
the filter. If this reference is null, a BufferedImage
must be created and it must possess the same dimensions as the source
image, similar raster and color model.
The createCompatibleDestImage() method
does the job of making a suitable destination image. For the BufferedImage
constructor it uses a color model either passed as an argument or
from the source. It also gets a raster suitable for this color model
and it checks to see if the alpha transparency factor pre-multiplies
the color components.
The getBound2Ds() method returns the
bounds object obtained from the source image. The getPoint2D()
method, which asks for the point in the destination image that corresponds
to the given point in the source image, just returns the same point
as in the source image since in this filter the dimensions are unchanged.
There are no RenderingHints
provided for displaying the filter output image.
The RotateColorsApplet program shown
below uses the custom filter called RotateOp,
which shifts the RGB color components each time the image is repainted
on the RotateImagePanel,
a subclass of JPanel.
RotateColorsApplet
+ RotateImagePanel
+ RotateOp
Resources: liftoff.jpg
|
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
/**
* Demonstration of the RotateOp filter. Most of
the work is done on the
* RotateImagePanel, which is displayed on this applet.
The applet is
* Runnable and periodically signals to the RotateImagePanel
to repaint
* itself with the image filtered for a different color.
**/
public class RotateColorsApplet extends JApplet
implements Runnable
{
// Will use thread reference as a flag
Thread fThread;
int fDeltaT = 1000; //msecs of sleep time
// Need a reference to the panel for the
// thread loop.
RotateImagePanel fRotateImagePanel;
public void init () {
Container content_pane = getContentPane
();
// Create an instance of DrawingPanel
fRotateImagePanel = new RotateImagePanel
();
// Add the DrawingPanel to the contentPane.
content_pane.add (fRotateImagePanel);
} // init
/** Create the image on the panel and
then start the thread.**/
public void start () {
// Tell the panel to create the image
source.
fRotateImagePanel.init (this);
if (fThread == null) {
fThread =
new Thread (this);
fThread.start
();
}
} // start
/** Stop the thread web page unloaded by setting
loop flag in run().**/
public void stop () {
fThread = null;
}
/** Loop the image display so that it rotates
the image each frame.**/
public void run () {
while (fThread != null) {
try {
Thread.sleep
(fDeltaT);
} catch (InterruptedException
e) { }
// Repaint filtered image.
repaint ();
}
} // run
} // class RotateColorsApplet
|
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
/** Load an image, apply the rotate filter to it, and then
display it. **/
class RotateImagePanel extends JPanel
{
BufferedImage fBufferedImage;
int fWidth, fHeight;
RotateOp fRotate;
void init (JApplet applet) {
// Get the image
Image img = applet.getImage (applet.getCodeBase(),
"liftoff.jpg");
// and use a MediaTracker to load
it before converting it to
// a BufferedImage.
try {
MediaTracker tracker
= new MediaTracker (this);
tracker.addImage (img,0);
tracker.waitForID ( 0
);
} catch ( InterruptedException e)
{ }
int fWidth = img.getWidth (this);
int fHeight= img.getHeight (this);
fBufferedImage =
new BufferedImage (fWidth,
fHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = fBufferedImage.createGraphics
();
g2.drawImage (img,0 ,0, null);
// Create the color rotation filter
object.
fRotate = new RotateOp ();
} // init
/** Before drawing the image, apply the filter.**/
public void paintComponent (Graphics g) {
fRotate.filter (fBufferedImage, fBufferedImage);
g.drawImage (fBufferedImage, 0, 0,
this );
}
} // RotateImagePanel
|
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
/** Demonstrate a custom filter by shift the color components.
**/
public class RotateOp implements BufferedImageOp
{
public final BufferedImage filter (BufferedImage
source_img,
BufferedImage dest_img) {
// If no destination image provided,
make one of same form as source
if (dest_img == null)
dest_img = createCompatibleDestImage
(source_img, null);
int width = source_img.getWidth
();
int height= source_img.getHeight
();
for (int y=0; y < height; y++) {
for (int
x=0; x < width; x++) {
int
pixel = source_img.getRGB (x,y);
//
Get the component colors
int
red = (pixel >> 16) & 0xff;
int
green = (pixel >> 8) & 0xff;
int
blue = pixel &
0xff;
//
Rotate the values
int
tmp = blue;
blue
= green;
green
= red;
red
= tmp;
//
Put new value into corresponding pixel of destination image;
pixel
= (255 << 24) | (red << 16) | (green
<< 8) | blue;
dest_img.setRGB
(x,y,pixel);
}
}
return dest_img;
} // filter
/**
* Create a destination image
if needed. Must be same width as source
* and will by default use
the same color model. Otherwise, it will use
* the one passed to it.
**/
public BufferedImage createCompatibleDestImage
(BufferedImage source_img,
ColorModel dest_color_model) {
// If no color model passed, use
the same as in source
if (dest_color_model == null)
dest_color_model
= source_img.getColorModel ();
int width = source_img.getWidth
();
int height= source_img.getHeight
();
// Create a new image with this
color model & raster. Check if the
// color components already multiplied
by the alpha factor.
return new BufferedImage (
dest_color_model,
dest_color_model.createCompatibleWritableRaster
(width,height),
dest_color_model.isAlphaPremultiplied
(),
null);
} // createCompatibleDestImage
/** Use the source image for the destination
bounds size. **/
public final Rectangle2D getBounds2D (BufferedImage
source_img) {
return source_img.getRaster ().getBounds
();
} // getBounds2D
/** The point in the source corresponds to same
point
* in the destination.
**/
public final Point2D getPoint2D (Point2D source_point,
Point2D dest_point) {
if (dest_point == null) dest_point
= new Point2D.Float ();
dest_point.setLocation (source_point.getX
(), source_point.getY ());
return dest_point;
} // getPoint2D
/** This filter doesn't provide any rendering
hints. **/
public final RenderingHints getRenderingHints
() {
return null;
}
}// class RotateOp
|
See Knudsen (1999) and the other references for more details about
creating custom filters.
References & Web Resources
Latest update: March 8, 2006
|