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