Frames | No Frames |
1: /* BitwiseXORComposite.java -- Composite for emulating old-style XOR. 2: Copyright (C) 2003, 2004 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.java.awt; 40: 41: import java.awt.Color; 42: import java.awt.Composite; 43: import java.awt.CompositeContext; 44: import java.awt.Rectangle; 45: import java.awt.RenderingHints; 46: import java.awt.image.ColorModel; 47: import java.awt.image.DataBuffer; 48: import java.awt.image.Raster; 49: import java.awt.image.WritableRaster; 50: 51: 52: /** 53: * A composite for emulating traditional bitwise XOR of pixel values. 54: * Please note that this composite does <i>not</i> implement the Porter-Duff 55: * XOR operator, but an exclusive or of overlapping subpixel regions. 56: * 57: * <p><img src="doc-files/BitwiseXORComposite-1.png" width="545" 58: * height="138" alt="A screen shot of BitwiseXORComposite in action" 59: * /> 60: * 61: * <p>The above screen shot shows the result of applying six different 62: * BitwiseXORComposites. They were constructed with the colors 63: * white, blue, black, orange, green, and brown, respectively. Each 64: * composite was used to paint a fully white rectangle on top of the 65: * blue bar in the background. 66: * 67: * <p>The purpose of this composite is to support the {@link 68: * Graphics#setXORMode(Color)} method in composite-aware graphics 69: * implementations. Applications typically would use 70: * <code>setXORMode</code> for drawing “highlights” such 71: * as text selections or cursors by inverting colors temporarily and 72: * then inverting them back. 73: * 74: * <p>A concrete <code>Graphics</code> implementation may contain 75: * the following code: 76: * 77: * <p><pre> public void setXORMode(Color xorColor) 78: * { 79: * setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor)); 80: * } 81: * 82: * public void setPaintMode() 83: * { 84: * setComposite(java.awt.AlphaComposite.SrcOver); 85: * }</pre> 86: * 87: * @author Graydon Hoare (graydon@redhat.com) 88: * @author Sascha Brawer (brawer@dandelis.ch) 89: */ 90: public class BitwiseXORComposite 91: implements Composite 92: { 93: /** 94: * The color whose RGB value is xor-ed with the values of each 95: * pixel. 96: */ 97: protected Color xorColor; 98: 99: 100: /** 101: * Constructs a new composite for xor-ing the pixel value. 102: * 103: * @param xorColor the color whose pixel value will be bitwise 104: * xor-ed with the source and destination pixels. 105: */ 106: public BitwiseXORComposite(Color xorColor) 107: { 108: this.xorColor = xorColor; 109: } 110: 111: 112: /** 113: * Creates a context object for performing the compositing 114: * operation. Several contexts may co-exist for one composite; each 115: * context may simultaneously be called from concurrent threads. 116: * 117: * @param srcColorModel the color model of the source. 118: * @param dstColorModel the color model of the destination. 119: * @param hints hints for choosing between rendering alternatives. 120: */ 121: public CompositeContext createContext(ColorModel srcColorModel, 122: ColorModel dstColorModel, 123: RenderingHints hints) 124: { 125: if (IntContext.isSupported(srcColorModel, dstColorModel, hints)) 126: return new IntContext(srcColorModel, xorColor); 127: 128: return new GeneralContext(srcColorModel, dstColorModel, xorColor); 129: } 130: 131: 132: /** 133: * A fallback CompositeContext that performs bitwise XOR of pixel 134: * values with the pixel value of the specified <code>xorColor</code>. 135: * 136: * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of 137: * <code>TYPE_INT_RGB</code> took 611 ms on a lightly loaded 2.4 GHz 138: * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux 139: * 2.4.20. The timing is the average of ten runs on the same 140: * BufferedImage. Since the measurements were taken with {@link 141: * System#currentTimeMillis()}, they are rather inaccurate. 142: * 143: * @author Graydon Hoare (graydon@redhat.com) 144: */ 145: private static class GeneralContext 146: implements CompositeContext 147: { 148: ColorModel srcColorModel; 149: ColorModel dstColorModel; 150: Color xorColor; 151: 152: public GeneralContext(ColorModel srcColorModel, 153: ColorModel dstColorModel, 154: Color xorColor) 155: { 156: this.srcColorModel = srcColorModel; 157: this.dstColorModel = dstColorModel; 158: this.xorColor = xorColor; 159: } 160: 161: 162: public void compose(Raster src, Raster dstIn, WritableRaster dstOut) 163: { 164: Rectangle srcRect = src.getBounds(); 165: Rectangle dstInRect = dstIn.getBounds(); 166: Rectangle dstOutRect = dstOut.getBounds(); 167: 168: int xp = xorColor.getRGB(); 169: int w = Math.min(Math.min(srcRect.width, dstOutRect.width), 170: dstInRect.width); 171: int h = Math.min(Math.min(srcRect.height, dstOutRect.height), 172: dstInRect.height); 173: 174: Object srcPix = null, dstPix = null, rpPix = null; 175: 176: // Re-using the rpPix object saved 1-2% of execution time in 177: // the 1024x1024 pixel benchmark. 178: 179: for (int y = 0; y < h; y++) 180: { 181: for (int x = 0; x < w; x++) 182: { 183: srcPix = src.getDataElements(x + srcRect.x, y + srcRect.y, srcPix); 184: dstPix = dstIn.getDataElements(x + dstInRect.x, y + dstInRect.y, 185: dstPix); 186: int sp = srcColorModel.getRGB(srcPix); 187: int dp = dstColorModel.getRGB(dstPix); 188: int rp = sp ^ xp ^ dp; 189: dstOut.setDataElements(x + dstOutRect.x, y + dstOutRect.y, 190: dstColorModel.getDataElements(rp, rpPix)); 191: } 192: } 193: } 194: 195: 196: /** 197: * Disposes any cached resources. The default implementation does 198: * nothing because no resources are cached. 199: */ 200: public void dispose() 201: { 202: } 203: } 204: 205: 206: /** 207: * An optimized CompositeContext that performs bitwise XOR of 208: * <code>int</code> pixel values with the pixel value of a specified 209: * <code>xorColor</code>. This CompositeContext working only for 210: * rasters whose transfer format is {@link DataBuffer#TYPE_INT}. 211: * 212: * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of 213: * <code>TYPE_INT_RGB</code> took 69 ms on a lightly loaded 2.4 GHz 214: * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux 215: * 2.4.20. The timing is the average of ten runs on the same 216: * BufferedImage. Since the measurements were taken with {@link 217: * System#currentTimeMillis()}, they are rather inaccurate. 218: * 219: * @author Sascha Brawer (brawer@dandelis.ch) 220: */ 221: private static class IntContext 222: extends GeneralContext 223: { 224: public IntContext(ColorModel colorModel, Color xorColor) 225: { 226: super(colorModel, colorModel, xorColor); 227: } 228: 229: 230: public void compose(Raster src, Raster dstIn, 231: WritableRaster dstOut) 232: { 233: int aX, bX, dstX, aY, bY, dstY, width, height; 234: int xorPixel; 235: int[] srcLine, dstLine; 236: 237: aX = src.getMinX(); 238: aY = src.getMinY(); 239: bX = dstIn.getMinX(); 240: bY = dstIn.getMinY(); 241: dstX = dstOut.getMinX(); 242: dstY = dstOut.getMinY(); 243: width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()), 244: dstOut.getWidth()); 245: height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()), 246: dstOut.getHeight()); 247: if ((width < 1) || (height < 1)) 248: return; 249: 250: srcLine = new int[width]; 251: dstLine = new int[width]; 252: 253: /* We need an int[] array with at least one element here; 254: * srcLine is as good as any other. 255: */ 256: srcColorModel.getDataElements(this.xorColor.getRGB(), srcLine); 257: xorPixel = srcLine[0]; 258: 259: for (int y = 0; y < height; y++) 260: { 261: src.getDataElements(aX, y + aY, width, 1, srcLine); 262: dstIn.getDataElements(bX, y + bY, width, 1, dstLine); 263: 264: for (int x = 0; x < width; x++) 265: dstLine[x] ^= srcLine[x] ^ xorPixel; 266: 267: dstOut.setDataElements(dstX, y + dstY, width, 1, dstLine); 268: } 269: } 270: 271: 272: /** 273: * Determines whether an instance of this CompositeContext would 274: * be able to process the specified color models. 275: */ 276: public static boolean isSupported(ColorModel srcColorModel, 277: ColorModel dstColorModel, 278: RenderingHints hints) 279: { 280: // FIXME: It would be good if someone could review these checks. 281: // They probably need to be more restrictive. 282: 283: int transferType; 284: 285: transferType = srcColorModel.getTransferType(); 286: if (transferType != dstColorModel.getTransferType()) 287: return false; 288: 289: if (transferType != DataBuffer.TYPE_INT) 290: return false; 291: 292: return true; 293: } 294: } 295: }