001 /*
002 * Copyright 1997-2000 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.util.Hashtable;
029 import java.awt.image.ImageConsumer;
030 import java.awt.image.ImageFilter;
031
032 /**
033 * The <code>BufferedImageFilter</code> class subclasses an
034 * <code>ImageFilter</code> to provide a simple means of
035 * using a single-source/single-destination image operator
036 * ({@link BufferedImageOp}) to filter a <code>BufferedImage</code>
037 * in the Image Producer/Consumer/Observer
038 * paradigm. Examples of these image operators are: {@link ConvolveOp},
039 * {@link AffineTransformOp} and {@link LookupOp}.
040 *
041 * @see ImageFilter
042 * @see BufferedImage
043 * @see BufferedImageOp
044 * @version 10 Feb 1997
045 */
046
047 public class BufferedImageFilter extends ImageFilter implements
048 Cloneable {
049 BufferedImageOp bufferedImageOp;
050 ColorModel model;
051 int width;
052 int height;
053 byte[] bytePixels;
054 int[] intPixels;
055
056 /**
057 * Constructs a <code>BufferedImageFilter</code> with the
058 * specified single-source/single-destination operator.
059 * @param op the specified <code>BufferedImageOp</code> to
060 * use to filter a <code>BufferedImage</code>
061 * @throws NullPointerException if op is null
062 */
063 public BufferedImageFilter(BufferedImageOp op) {
064 super ();
065 if (op == null) {
066 throw new NullPointerException("Operation cannot be null");
067 }
068 bufferedImageOp = op;
069 }
070
071 /**
072 * Returns the <code>BufferedImageOp</code>.
073 * @return the operator of this <code>BufferedImageFilter</code>.
074 */
075 public BufferedImageOp getBufferedImageOp() {
076 return bufferedImageOp;
077 }
078
079 /**
080 * Filters the information provided in the
081 * {@link ImageConsumer#setDimensions(int, int) setDimensions } method
082 * of the {@link ImageConsumer} interface.
083 * <p>
084 * Note: This method is intended to be called by the
085 * {@link ImageProducer} of the <code>Image</code> whose pixels are
086 * being filtered. Developers using this class to retrieve pixels from
087 * an image should avoid calling this method directly since that
088 * operation could result in problems with retrieving the requested
089 * pixels.
090 * <p>
091 * @param width the width to which to set the width of this
092 * <code>BufferedImageFilter</code>
093 * @param height the height to which to set the height of this
094 * <code>BufferedImageFilter</code>
095 * @see ImageConsumer#setDimensions
096 */
097 public void setDimensions(int width, int height) {
098 if (width <= 0 || height <= 0) {
099 imageComplete(STATICIMAGEDONE);
100 return;
101 }
102 this .width = width;
103 this .height = height;
104 }
105
106 /**
107 * Filters the information provided in the
108 * {@link ImageConsumer#setColorModel(ColorModel) setColorModel} method
109 * of the <code>ImageConsumer</code> interface.
110 * <p>
111 * If <code>model</code> is <code>null</code>, this
112 * method clears the current <code>ColorModel</code> of this
113 * <code>BufferedImageFilter</code>.
114 * <p>
115 * Note: This method is intended to be called by the
116 * <code>ImageProducer</code> of the <code>Image</code>
117 * whose pixels are being filtered. Developers using this
118 * class to retrieve pixels from an image
119 * should avoid calling this method directly since that
120 * operation could result in problems with retrieving the
121 * requested pixels.
122 * @param model the {@link ColorModel} to which to set the
123 * <code>ColorModel</code> of this <code>BufferedImageFilter</code>
124 * @see ImageConsumer#setColorModel
125 */
126 public void setColorModel(ColorModel model) {
127 this .model = model;
128 }
129
130 private void convertToRGB() {
131 int size = width * height;
132 int newpixels[] = new int[size];
133 if (bytePixels != null) {
134 for (int i = 0; i < size; i++) {
135 newpixels[i] = this .model.getRGB(bytePixels[i] & 0xff);
136 }
137 } else if (intPixels != null) {
138 for (int i = 0; i < size; i++) {
139 newpixels[i] = this .model.getRGB(intPixels[i]);
140 }
141 }
142 bytePixels = null;
143 intPixels = newpixels;
144 this .model = ColorModel.getRGBdefault();
145 }
146
147 /**
148 * Filters the information provided in the <code>setPixels</code>
149 * method of the <code>ImageConsumer</code> interface which takes
150 * an array of bytes.
151 * <p>
152 * Note: This method is intended to be called by the
153 * <code>ImageProducer</code> of the <code>Image</code> whose pixels
154 * are being filtered. Developers using
155 * this class to retrieve pixels from an image should avoid calling
156 * this method directly since that operation could result in problems
157 * with retrieving the requested pixels.
158 * @throws IllegalArgumentException if width or height are less than
159 * zero.
160 * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, byte[],
161 int, int)
162 */
163 public void setPixels(int x, int y, int w, int h, ColorModel model,
164 byte pixels[], int off, int scansize) {
165 // Fix 4184230
166 if (w < 0 || h < 0) {
167 throw new IllegalArgumentException("Width (" + w
168 + ") and height (" + h + ") must be > 0");
169 }
170 // Nothing to do
171 if (w == 0 || h == 0) {
172 return;
173 }
174 if (y < 0) {
175 int diff = -y;
176 if (diff >= h) {
177 return;
178 }
179 off += scansize * diff;
180 y += diff;
181 h -= diff;
182 }
183 if (y + h > height) {
184 h = height - y;
185 if (h <= 0) {
186 return;
187 }
188 }
189 if (x < 0) {
190 int diff = -x;
191 if (diff >= w) {
192 return;
193 }
194 off += diff;
195 x += diff;
196 w -= diff;
197 }
198 if (x + w > width) {
199 w = width - x;
200 if (w <= 0) {
201 return;
202 }
203 }
204 int dstPtr = y * width + x;
205 if (intPixels == null) {
206 if (bytePixels == null) {
207 bytePixels = new byte[width * height];
208 this .model = model;
209 } else if (this .model != model) {
210 convertToRGB();
211 }
212 if (bytePixels != null) {
213 for (int sh = h; sh > 0; sh--) {
214 System
215 .arraycopy(pixels, off, bytePixels, dstPtr,
216 w);
217 off += scansize;
218 dstPtr += width;
219 }
220 }
221 }
222 if (intPixels != null) {
223 int dstRem = width - w;
224 int srcRem = scansize - w;
225 for (int sh = h; sh > 0; sh--) {
226 for (int sw = w; sw > 0; sw--) {
227 intPixels[dstPtr++] = model
228 .getRGB(pixels[off++] & 0xff);
229 }
230 off += srcRem;
231 dstPtr += dstRem;
232 }
233 }
234 }
235
236 /**
237 * Filters the information provided in the <code>setPixels</code>
238 * method of the <code>ImageConsumer</code> interface which takes
239 * an array of integers.
240 * <p>
241 * Note: This method is intended to be called by the
242 * <code>ImageProducer</code> of the <code>Image</code> whose
243 * pixels are being filtered. Developers using this class to
244 * retrieve pixels from an image should avoid calling this method
245 * directly since that operation could result in problems
246 * with retrieving the requested pixels.
247 * @throws IllegalArgumentException if width or height are less than
248 * zero.
249 * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, int[],
250 int, int)
251 */
252 public void setPixels(int x, int y, int w, int h, ColorModel model,
253 int pixels[], int off, int scansize) {
254 // Fix 4184230
255 if (w < 0 || h < 0) {
256 throw new IllegalArgumentException("Width (" + w
257 + ") and height (" + h + ") must be > 0");
258 }
259 // Nothing to do
260 if (w == 0 || h == 0) {
261 return;
262 }
263 if (y < 0) {
264 int diff = -y;
265 if (diff >= h) {
266 return;
267 }
268 off += scansize * diff;
269 y += diff;
270 h -= diff;
271 }
272 if (y + h > height) {
273 h = height - y;
274 if (h <= 0) {
275 return;
276 }
277 }
278 if (x < 0) {
279 int diff = -x;
280 if (diff >= w) {
281 return;
282 }
283 off += diff;
284 x += diff;
285 w -= diff;
286 }
287 if (x + w > width) {
288 w = width - x;
289 if (w <= 0) {
290 return;
291 }
292 }
293
294 if (intPixels == null) {
295 if (bytePixels == null) {
296 intPixels = new int[width * height];
297 this .model = model;
298 } else {
299 convertToRGB();
300 }
301 }
302 int dstPtr = y * width + x;
303 if (this .model == model) {
304 for (int sh = h; sh > 0; sh--) {
305 System.arraycopy(pixels, off, intPixels, dstPtr, w);
306 off += scansize;
307 dstPtr += width;
308 }
309 } else {
310 if (this .model != ColorModel.getRGBdefault()) {
311 convertToRGB();
312 }
313 int dstRem = width - w;
314 int srcRem = scansize - w;
315 for (int sh = h; sh > 0; sh--) {
316 for (int sw = w; sw > 0; sw--) {
317 intPixels[dstPtr++] = model.getRGB(pixels[off++]);
318 }
319 off += srcRem;
320 dstPtr += dstRem;
321 }
322 }
323 }
324
325 /**
326 * Filters the information provided in the <code>imageComplete</code>
327 * method of the <code>ImageConsumer</code> interface.
328 * <p>
329 * Note: This method is intended to be called by the
330 * <code>ImageProducer</code> of the <code>Image</code> whose pixels
331 * are being filtered. Developers using
332 * this class to retrieve pixels from an image should avoid calling
333 * this method directly since that operation could result in problems
334 * with retrieving the requested pixels.
335 * @param status the status of image loading
336 * @throws ImagingOpException if there was a problem calling the filter
337 * method of the <code>BufferedImageOp</code> associated with this
338 * instance.
339 * @see ImageConsumer#imageComplete
340 */
341 public void imageComplete(int status) {
342 WritableRaster wr;
343 switch (status) {
344 case IMAGEERROR:
345 case IMAGEABORTED:
346 // reinitialize the params
347 model = null;
348 width = -1;
349 height = -1;
350 intPixels = null;
351 bytePixels = null;
352 break;
353
354 case SINGLEFRAMEDONE:
355 case STATICIMAGEDONE:
356 if (width <= 0 || height <= 0)
357 break;
358 if (model instanceof DirectColorModel) {
359 if (intPixels == null)
360 break;
361 wr = createDCMraster();
362 } else if (model instanceof IndexColorModel) {
363 int[] bandOffsets = { 0 };
364 if (bytePixels == null)
365 break;
366 DataBufferByte db = new DataBufferByte(bytePixels,
367 width * height);
368 wr = Raster.createInterleavedRaster(db, width, height,
369 width, 1, bandOffsets, null);
370 } else {
371 convertToRGB();
372 if (intPixels == null)
373 break;
374 wr = createDCMraster();
375 }
376 BufferedImage bi = new BufferedImage(model, wr, model
377 .isAlphaPremultiplied(), null);
378 bi = bufferedImageOp.filter(bi, null);
379 WritableRaster r = bi.getRaster();
380 ColorModel cm = bi.getColorModel();
381 int w = r.getWidth();
382 int h = r.getHeight();
383 consumer.setDimensions(w, h);
384 consumer.setColorModel(cm);
385 if (cm instanceof DirectColorModel) {
386 DataBufferInt db = (DataBufferInt) r.getDataBuffer();
387 consumer.setPixels(0, 0, w, h, cm, db.getData(), 0, w);
388 } else if (cm instanceof IndexColorModel) {
389 DataBufferByte db = (DataBufferByte) r.getDataBuffer();
390 consumer.setPixels(0, 0, w, h, cm, db.getData(), 0, w);
391 } else {
392 throw new InternalError("Unknown color model " + cm);
393 }
394 break;
395 }
396 consumer.imageComplete(status);
397 }
398
399 private final WritableRaster createDCMraster() {
400 WritableRaster wr;
401 DirectColorModel dcm = (DirectColorModel) model;
402 boolean hasAlpha = model.hasAlpha();
403 int[] bandMasks = new int[3 + (hasAlpha ? 1 : 0)];
404 bandMasks[0] = dcm.getRedMask();
405 bandMasks[1] = dcm.getGreenMask();
406 bandMasks[2] = dcm.getBlueMask();
407 if (hasAlpha) {
408 bandMasks[3] = dcm.getAlphaMask();
409 }
410 DataBufferInt db = new DataBufferInt(intPixels, width * height);
411 wr = Raster.createPackedRaster(db, width, height, width,
412 bandMasks, null);
413 return wr;
414 }
415
416 }
|