Both Java 1.0 and 1.1 included a complex API for filtering images on the fly as they were downloaded over a network connection. Although this API is still available in later versions of Java, it is not commonly used, nor is it demonstrated in this book. Java 2D defines a simpler API based on the BufferedImageOp interface of the java.awt.image package. This package also includes several versatile implementations of the interface that can generate the image-processing effects illustrated in Figure 12-11. Example 12-13 shows the code used to produce Figure 12-11. The code is straightforward: to process a BufferedImage, simply pass it to the filter( ) method of a BufferedImageOp. Figure 12-11. Image processing with BufferedImageOpExample 12-13. ImageOps.javapackage je3.graphics; import java.awt.*; import java.awt.geom.*; import java.awt.image.*; import java.awt.color.*; /** A demonstration of various image processing filters */ public class ImageOps implements GraphicsExample { static final int WIDTH = 600, HEIGHT = 675; // Size of our example public String getName( ) {return "Image Processing";}// From GraphicsExample public int getWidth( ) { return WIDTH; } // From GraphicsExample public int getHeight( ) { return HEIGHT; } // From GraphicsExample Image image; /** This constructor loads the image we will manipulate */ public ImageOps( ) { java.net.URL imageurl = this.getClass( ).getResource("cover.gif"); image = new javax.swing.ImageIcon(imageurl).getImage( ); } // These arrays of bytes are used by the LookupImageOp image filters below static byte[ ] brightenTable = new byte[256]; static byte[ ] thresholdTable = new byte[256]; static { // Initialize the arrays for(int i = 0; i < 256; i++) { brightenTable[i] = (byte)(Math.sqrt(i/255.0)*255); thresholdTable[i] = (byte)((i < 225)?0:i); } } // This AffineTransform is used by one of the image filters below static AffineTransform mirrorTransform; static { // Create and initialize the AffineTransform mirrorTransform = AffineTransform.getTranslateInstance(127, 0); mirrorTransform.scale(-1.0, 1.0); // flip horizontally } // These are the labels we'll display for each of the filtered images static String[ ] filterNames = new String[ ] { "Original", "Gray Scale", "Negative", "Brighten (linear)", "Brighten (sqrt)", "Threshold", "Blur", "Sharpen", "Edge Detect", "Mirror", "Rotate (center)", "Rotate (lower left)" }; // The following BufferedImageOp image filter objects perform // different types of image processing operations. static BufferedImageOp[ ] filters = new BufferedImageOp[ ] { // 1) No filter here. We'll display the original image null, // 2) Convert to Grayscale color space new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null), // 3) Image negative. Multiply each color value by -1.0 and add 255 new RescaleOp(-1.0f, 255f, null), // 4) Brighten using a linear formula that increases all color values new RescaleOp(1.25f, 0, null), // 5) Brighten using the lookup table defined above new LookupOp(new ByteLookupTable(0, brightenTable), null), // 6) Threshold using the lookup table defined above new LookupOp(new ByteLookupTable(0, thresholdTable), null), // 7) Blur by "convolving" the image with a matrix new ConvolveOp(new Kernel(3, 3, new float[ ] { .1111f,.1111f,.1111f, .1111f,.1111f,.1111f, .1111f,.1111f,.1111f,})), // 8) Sharpen by using a different matrix new ConvolveOp(new Kernel(3, 3, new float[ ] { 0.0f, -0.75f, 0.0f, -0.75f, 4.0f, -0.75f, 0.0f, -0.75f, 0.0f})), // 9) Edge detect using yet another matrix new ConvolveOp(new Kernel(3, 3, new float[ ] { 0.0f, -0.75f, 0.0f, -0.75f, 3.0f, -0.75f, 0.0f, -0.75f, 0.0f})), // 10) Compute a mirror image using the transform defined above new AffineTransformOp(mirrorTransform,AffineTransformOp.TYPE_BILINEAR), // 11) Rotate the image 180 degrees about its center point new AffineTransformOp(AffineTransform.getRotateInstance(Math.PI,64,95), AffineTransformOp.TYPE_NEAREST_NEIGHBOR), // 12) Rotate the image 15 degrees about the bottom left new AffineTransformOp(AffineTransform.getRotateInstance(Math.PI/12, 0, 190), AffineTransformOp.TYPE_NEAREST_NEIGHBOR), }; /** Draw the example */ public void draw(Graphics2D g, Component c) { // Create a BufferedImage big enough to hold the Image loaded // in the constructor. Then copy that image into the new // BufferedImage object so that we can process it. BufferedImage bimage = new BufferedImage(image.getWidth(c), image.getHeight(c), BufferedImage.TYPE_INT_RGB); Graphics2D ig = bimage.createGraphics( ); ig.drawImage(image, 0, 0, c); // copy the image // Set some default graphics attributes g.setFont(new Font("SansSerif", Font.BOLD, 12)); // 12pt bold text g.setColor(Color.green); // Draw in green g.translate(10, 10); // Set some margins // Loop through the filters for(int i = 0; i < filters.length; i++) { // If the filter is null, draw the original image; otherwise, // draw the image as processed by the filter if (filters[i] == null) g.drawImage(bimage, 0, 0, c); else g.drawImage(filters[i].filter(bimage, null), 0, 0, c); g.drawString(filterNames[i], 0, 205); // Label the image g.translate(137, 0); // Move over if (i % 4 == 3) g.translate(-137*4, 215); // Move down after 4 } } } |