001: /*
002: * @(#)RGBImageFilter.java 1.20 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt.image;
029:
030: import java.awt.image.ImageConsumer;
031: import java.awt.image.ColorModel;
032:
033: /**
034: * This class provides an easy way to create an ImageFilter which modifies
035: * the pixels of an image in the default RGB ColorModel. It is meant to
036: * be used in conjunction with a FilteredImageSource object to produce
037: * filtered versions of existing images. It is an abstract class that
038: * provides the calls needed to channel all of the pixel data through a
039: * single method which converts pixels one at a time in the default RGB
040: * ColorModel regardless of the ColorModel being used by the ImageProducer.
041: * The only method which needs to be defined to create a useable image
042: * filter is the filterRGB method. Here is an example of a definition
043: * of a filter which swaps the red and blue components of an image:
044: * <pre>
045: *
046: * class RedBlueSwapFilter extends RGBImageFilter {
047: * public RedBlueSwapFilter() {
048: * // The filter's operation does not depend on the
049: * // pixel's location, so IndexColorModels can be
050: * // filtered directly.
051: * canFilterIndexColorModel = true;
052: * }
053: *
054: * public int filterRGB(int x, int y, int rgb) {
055: * return ((rgb & 0xff00ff00)
056: * | ((rgb & 0xff0000) >> 16)
057: * | ((rgb & 0xff) << 16));
058: * }
059: * }
060: *
061: * </pre>
062: *
063: * @see FilteredImageSource
064: * @see ImageFilter
065: * @see ColorModel#getRGBdefault
066: *
067: * @version 1.16 08/19/02
068: * @author Jim Graham
069: */
070: public abstract class RGBImageFilter extends ImageFilter {
071: protected ColorModel origmodel;
072: protected ColorModel newmodel;
073: /**
074: * This boolean indicates whether or not it is acceptable to apply
075: * the color filtering of the filterRGB method to the color table
076: * entries of an IndexColorModel object in lieu of pixel by pixel
077: * filtering. Subclasses should set this variable to true in their
078: * constructor if their filterRGB method does not depend on the
079: * coordinate of the pixel being filtered.
080: * @see #substituteColorModel
081: * @see #filterRGB
082: * @see IndexColorModel
083: */
084: protected boolean canFilterIndexColorModel;
085:
086: /**
087: * If the ColorModel is an IndexColorModel, and the subclass has
088: * set the canFilterIndexColorModel flag to true, we substitute
089: * a filtered version of the color model here and wherever
090: * that original ColorModel object appears in the setPixels methods. Otherwise
091: * overrides the default ColorModel used by the ImageProducer and
092: * specifies the default RGB ColorModel instead.
093:
094: * @see ImageConsumer
095: * @see ColorModel#getRGBdefault
096: */
097: public void setColorModel(ColorModel model) {
098: if (canFilterIndexColorModel
099: && (model instanceof IndexColorModel)) {
100: ColorModel newcm = filterIndexColorModel((IndexColorModel) model);
101: substituteColorModel(model, newcm);
102: consumer.setColorModel(newcm);
103: } else {
104: consumer.setColorModel(ColorModel.getRGBdefault());
105: }
106: }
107:
108: /**
109: * Registers two ColorModel objects for substitution. If the oldcm
110: * is encountered during any of the setPixels methods, the newcm
111: * is substituted and the pixels passed through
112: * untouched (but with the new ColorModel object).
113: * @param oldcm the ColorModel object to be replaced on the fly
114: * @param newcm the ColorModel object to replace oldcm on the fly
115: */
116: public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
117: origmodel = oldcm;
118: newmodel = newcm;
119: }
120:
121: /**
122: * Filters an IndexColorModel object by running each entry in its
123: * color tables through the filterRGB function that RGBImageFilter
124: * subclasses must provide. Uses coordinates of -1 to indicate that
125: * a color table entry is being filtered rather than an actual
126: * pixel value.
127: * @param icm the IndexColorModel object to be filtered
128: * @return a new IndexColorModel representing the filtered colors
129: */
130: public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
131: int mapsize = icm.getMapSize();
132: byte r[] = new byte[mapsize];
133: byte g[] = new byte[mapsize];
134: byte b[] = new byte[mapsize];
135: byte a[] = new byte[mapsize];
136: icm.getReds(r);
137: icm.getGreens(g);
138: icm.getBlues(b);
139: icm.getAlphas(a);
140: int trans = icm.getTransparentPixel();
141: boolean needalpha = false;
142: for (int i = 0; i < mapsize; i++) {
143: int rgb = filterRGB(-1, -1, icm.getRGB(i));
144: a[i] = (byte) (rgb >> 24);
145: if (a[i] != ((byte) 0xff) && i != trans) {
146: needalpha = true;
147: }
148: r[i] = (byte) (rgb >> 16);
149: g[i] = (byte) (rgb >> 8);
150: b[i] = (byte) (rgb >> 0);
151: }
152: if (needalpha) {
153: return new IndexColorModel(icm.getPixelSize(), mapsize, r,
154: g, b, a);
155: } else {
156: return new IndexColorModel(icm.getPixelSize(), mapsize, r,
157: g, b, trans);
158: }
159: }
160:
161: /**
162: * Filters a buffer of pixels in the default RGB ColorModel by passing
163: * them one by one through the filterRGB method.
164: * @see ColorModel#getRGBdefault
165: * @see #filterRGB
166: */
167: public void filterRGBPixels(int x, int y, int w, int h,
168: int pixels[], int off, int scansize) {
169: int index = off;
170: for (int cy = 0; cy < h; cy++) {
171: for (int cx = 0; cx < w; cx++) {
172: pixels[index] = filterRGB(x + cx, y + cy, pixels[index]);
173: index++;
174: }
175: index += scansize - w;
176: }
177: consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(),
178: pixels, off, scansize);
179: }
180:
181: /**
182: * If the ColorModel object is the same one that has already
183: * been converted, then simply passes the pixels through with the
184: * converted ColorModel. Otherwise converts the buffer of byte
185: * pixels to the default RGB ColorModel and passes the converted
186: * buffer to the filterRGBPixels method to be converted one by one.
187: * @see ColorModel#getRGBdefault
188: * @see #filterRGBPixels
189: */
190: public void setPixels(int x, int y, int w, int h, ColorModel model,
191: byte pixels[], int off, int scansize) {
192: if (model == origmodel) {
193: consumer.setPixels(x, y, w, h, newmodel, pixels, off,
194: scansize);
195: } else {
196: int filteredpixels[] = new int[w];
197: int index = off;
198: for (int cy = 0; cy < h; cy++) {
199: for (int cx = 0; cx < w; cx++) {
200: filteredpixels[cx] = model
201: .getRGB((pixels[index] & 0xff));
202: index++;
203: }
204: index += scansize - w;
205: filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
206: }
207: }
208: }
209:
210: /**
211: * If the ColorModel object is the same one that has already
212: * been converted, then simply passes the pixels through with the
213: * converted ColorModel, otherwise converts the buffer of integer
214: * pixels to the default RGB ColorModel and passes the converted
215: * buffer to the filterRGBPixels method to be converted one by one.
216: * Converts a buffer of integer pixels to the default RGB ColorModel
217: * and passes the converted buffer to the filterRGBPixels method.
218: * @see ColorModel#getRGBdefault
219: * @see #filterRGBPixels
220: */
221: public void setPixels(int x, int y, int w, int h, ColorModel model,
222: int pixels[], int off, int scansize) {
223: if (model == origmodel) {
224: consumer.setPixels(x, y, w, h, newmodel, pixels, off,
225: scansize);
226: } else {
227: int filteredpixels[] = new int[w];
228: int index = off;
229: for (int cy = 0; cy < h; cy++) {
230: for (int cx = 0; cx < w; cx++) {
231: filteredpixels[cx] = model.getRGB(pixels[index]);
232: index++;
233: }
234: index += scansize - w;
235: filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
236: }
237: }
238: }
239:
240: /**
241: * Subclasses must specify a method to convert a single input pixel
242: * in the default RGB ColorModel to a single output pixel.
243: * @see ColorModel#getRGBdefault
244: * @see #filterRGBPixels
245: */
246: public abstract int filterRGB(int x, int y, int rgb);
247: }
|