Frames | No Frames |
1: /* LookupOp.java -- Filter that converts each pixel using a lookup table. 2: Copyright (C) 2004 Free Software Foundation 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 java.awt.image; 40: 41: import java.awt.Graphics2D; 42: import java.awt.RenderingHints; 43: import java.awt.geom.Point2D; 44: import java.awt.geom.Rectangle2D; 45: 46: /** 47: * LookupOp is a filter that converts each pixel using a lookup table. 48: * 49: * For filtering Rasters, the lookup table must have either one component 50: * that is applied to all bands, or one component for every band in the 51: * Rasters. 52: * 53: * For BufferedImages, the lookup table may apply to both color and alpha 54: * components. If the lookup table contains one component, or if there are 55: * the same number of components as color components in the source, the table 56: * applies to all color components. Otherwise the table applies to all 57: * components including alpha. Alpha premultiplication is ignored during the 58: * lookup filtering. 59: * 60: * After filtering, if color conversion is necessary, the conversion happens, 61: * taking alpha premultiplication into account. 62: * 63: * @author jlquinn 64: */ 65: public class LookupOp implements BufferedImageOp, RasterOp 66: { 67: private LookupTable lut; 68: private RenderingHints hints; 69: 70: /** Construct a new LookupOp. 71: * 72: * @param lookup LookupTable to use. 73: * @param hints Rendering hints (can be null). 74: */ 75: public LookupOp(LookupTable lookup, RenderingHints hints) 76: { 77: lut = lookup; 78: this.hints = hints; 79: } 80: 81: /* (non-Javadoc) 82: * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage) 83: */ 84: public final BufferedImage filter(BufferedImage src, BufferedImage dst) 85: { 86: if (src.getColorModel() instanceof IndexColorModel) 87: throw new IllegalArgumentException("LookupOp.filter: IndexColorModel " 88: + "not allowed"); 89: if (dst == null) 90: dst = createCompatibleDestImage(src, src.getColorModel()); 91: 92: // Set up for potential colormodel mismatch 93: BufferedImage tgt; 94: if (dst.getColorModel().equals(src.getColorModel())) 95: tgt = dst; 96: else 97: tgt = createCompatibleDestImage(src, src.getColorModel()); 98: 99: Raster sr = src.getRaster(); 100: WritableRaster dr = tgt.getRaster(); 101: 102: if (src.getColorModel().hasAlpha() && 103: (lut.getNumComponents() == 1 || 104: lut.getNumComponents() == src.getColorModel().getNumColorComponents())) 105: { 106: // Need to ignore alpha for lookup 107: int[] dbuf = new int[src.getColorModel().getNumComponents()]; 108: int tmpBands = src.getColorModel().getNumColorComponents(); 109: int[] tmp = new int[tmpBands]; 110: 111: // Filter the pixels 112: for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) 113: for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) 114: { 115: // Filter only color components, but also copy alpha 116: sr.getPixel(x, y, dbuf); 117: System.arraycopy(dbuf, 0, tmp, 0, tmpBands); 118: dr.setPixel(x, y, lut.lookupPixel(tmp, dbuf)); 119: } 120: } 121: else if (lut.getNumComponents() != 1 122: && 123: lut.getNumComponents() != src.getColorModel().getNumComponents()) 124: throw new IllegalArgumentException("LookupOp.filter: " 125: + "Incompatible lookup " 126: + "table and source image"); 127: 128: // No alpha to ignore 129: int[] dbuf = new int[src.getColorModel().getNumComponents()]; 130: 131: // Filter the pixels 132: for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) 133: for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) 134: dr.setPixel(x, y, lut.lookupPixel(sr.getPixel(x, y, dbuf), dbuf)); 135: 136: if (tgt != dst) 137: { 138: // Convert between color models. 139: // TODO Check that premultiplied alpha is handled correctly here. 140: Graphics2D gg = dst.createGraphics(); 141: gg.setRenderingHints(hints); 142: gg.drawImage(tgt, 0, 0, null); 143: gg.dispose(); 144: } 145: 146: return dst; 147: } 148: 149: /* (non-Javadoc) 150: * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) 151: */ 152: public final Rectangle2D getBounds2D(BufferedImage src) 153: { 154: return src.getRaster().getBounds(); 155: } 156: 157: /* (non-Javadoc) 158: * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel) 159: */ 160: public BufferedImage createCompatibleDestImage(BufferedImage src, 161: ColorModel dstCM) 162: { 163: // FIXME: set properties to those in src 164: return new BufferedImage(dstCM, 165: src.getRaster().createCompatibleWritableRaster(), 166: src.isPremultiplied, null); 167: } 168: 169: /** Return corresponding destination point for source point. 170: * 171: * LookupOp will return the value of src unchanged. 172: * @param src The source point. 173: * @param dst The destination point. 174: * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) 175: */ 176: public final Point2D getPoint2D(Point2D src, Point2D dst) 177: { 178: if (dst == null) 179: return (Point2D) src.clone(); 180: 181: dst.setLocation(src); 182: return dst; 183: } 184: 185: /** Return the LookupTable for this op. */ 186: public final LookupTable getTable() 187: { 188: return lut; 189: } 190: 191: /* (non-Javadoc) 192: * @see java.awt.image.RasterOp#getRenderingHints() 193: */ 194: public final RenderingHints getRenderingHints() 195: { 196: return hints; 197: } 198: 199: /** Filter a raster through a lookup table. 200: * 201: * Applies the lookup table for this Rasterop to each pixel of src and 202: * puts the results in dest. If dest is null, a new Raster is created and 203: * returned. 204: * 205: * @param src The source raster. 206: * @param dest The destination raster. 207: * @return The WritableRaster with the filtered pixels. 208: * @throws IllegalArgumentException if lookup table has more than one 209: * component but not the same as src and dest. 210: * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) 211: */ 212: public final WritableRaster filter(Raster src, WritableRaster dest) 213: { 214: if (dest == null) 215: // Allocate a raster if needed 216: dest = createCompatibleDestRaster(src); 217: else 218: if (src.getNumBands() != dest.getNumBands()) 219: throw new IllegalArgumentException(); 220: 221: if (lut.getNumComponents() != 1 222: && lut.getNumComponents() != src.getNumBands()) 223: throw new IllegalArgumentException(); 224: 225: 226: // Allocate pixel storage. 227: int[] tmp = new int[src.getNumBands()]; 228: 229: // Filter the pixels 230: for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) 231: for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) 232: dest.setPixel(x, y, lut.lookupPixel(src.getPixel(x, y, tmp), tmp)); 233: return dest; 234: } 235: 236: /* (non-Javadoc) 237: * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) 238: */ 239: public final Rectangle2D getBounds2D(Raster src) 240: { 241: return src.getBounds(); 242: } 243: 244: /* (non-Javadoc) 245: * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster) 246: */ 247: public WritableRaster createCompatibleDestRaster(Raster src) 248: { 249: return src.createCompatibleWritableRaster(); 250: } 251: 252: }