KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > image > PixelGrabber


1 /*
2  * @(#)PixelGrabber.java 1.25 04/07/16
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.image;
9
10 import java.util.Hashtable JavaDoc;
11 import java.awt.image.ImageProducer JavaDoc;
12 import java.awt.image.ImageConsumer JavaDoc;
13 import java.awt.image.ColorModel JavaDoc;
14 import java.awt.Image JavaDoc;
15
16 /**
17  * The PixelGrabber class implements an ImageConsumer which can be attached
18  * to an Image or ImageProducer object to retrieve a subset of the pixels
19  * in that image. Here is an example:
20  * <pre>
21  *
22  * public void handlesinglepixel(int x, int y, int pixel) {
23  * int alpha = (pixel >> 24) & 0xff;
24  * int red = (pixel >> 16) & 0xff;
25  * int green = (pixel >> 8) & 0xff;
26  * int blue = (pixel ) & 0xff;
27  * // Deal with the pixel as necessary...
28  * }
29  *
30  * public void handlepixels(Image img, int x, int y, int w, int h) {
31  * int[] pixels = new int[w * h];
32  * PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
33  * try {
34  * pg.grabPixels();
35  * } catch (InterruptedException e) {
36  * System.err.println("interrupted waiting for pixels!");
37  * return;
38  * }
39  * if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
40  * System.err.println("image fetch aborted or errored");
41  * return;
42  * }
43  * for (int j = 0; j < h; j++) {
44  * for (int i = 0; i < w; i++) {
45  * handlesinglepixel(x+i, y+j, pixels[j * w + i]);
46  * }
47  * }
48  * }
49  *
50  * </pre>
51  *
52  * @see ColorModel#getRGBdefault
53  *
54  * @version 1.25, 07/16/04
55  * @author Jim Graham
56  */

57 public class PixelGrabber implements ImageConsumer JavaDoc {
58     ImageProducer JavaDoc producer;
59
60     int dstX;
61     int dstY;
62     int dstW;
63     int dstH;
64
65     ColorModel JavaDoc imageModel;
66     byte[] bytePixels;
67     int[] intPixels;
68     int dstOff;
69     int dstScan;
70
71     private boolean grabbing;
72     private int flags;
73
74     private static final int GRABBEDBITS = (ImageObserver.FRAMEBITS
75                         | ImageObserver.ALLBITS);
76     private static final int DONEBITS = (GRABBEDBITS
77                      | ImageObserver.ERROR);
78
79     /**
80      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
81      * section of pixels from the specified image into the given array.
82      * The pixels are stored into the array in the default RGB ColorModel.
83      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
84      * (x, y, w, h) is stored in the array at
85      * <tt>pix[(j - y) * scansize + (i - x) + off]</tt>.
86      * @see ColorModel#getRGBdefault
87      * @param img the image to retrieve pixels from
88      * @param x the x coordinate of the upper left corner of the rectangle
89      * of pixels to retrieve from the image, relative to the default
90      * (unscaled) size of the image
91      * @param y the y coordinate of the upper left corner of the rectangle
92      * of pixels to retrieve from the image
93      * @param w the width of the rectangle of pixels to retrieve
94      * @param h the height of the rectangle of pixels to retrieve
95      * @param pix the array of integers which are to be used to hold the
96      * RGB pixels retrieved from the image
97      * @param off the offset into the array of where to store the first pixel
98      * @param scansize the distance from one row of pixels to the next in
99      * the array
100      */

101     public PixelGrabber(Image JavaDoc img, int x, int y, int w, int h,
102             int[] pix, int off, int scansize) {
103     this(img.getSource(), x, y, w, h, pix, off, scansize);
104     }
105
106     /**
107      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
108      * section of pixels from the image produced by the specified
109      * ImageProducer into the given array.
110      * The pixels are stored into the array in the default RGB ColorModel.
111      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
112      * (x, y, w, h) is stored in the array at
113      * <tt>pix[(j - y) * scansize + (i - x) + off]</tt>.
114      * @param ip the <code>ImageProducer</code> that produces the
115      * image from which to retrieve pixels
116      * @param x the x coordinate of the upper left corner of the rectangle
117      * of pixels to retrieve from the image, relative to the default
118      * (unscaled) size of the image
119      * @param y the y coordinate of the upper left corner of the rectangle
120      * of pixels to retrieve from the image
121      * @param w the width of the rectangle of pixels to retrieve
122      * @param h the height of the rectangle of pixels to retrieve
123      * @param pix the array of integers which are to be used to hold the
124      * RGB pixels retrieved from the image
125      * @param off the offset into the array of where to store the first pixel
126      * @param scansize the distance from one row of pixels to the next in
127      * the array
128      * @see ColorModel#getRGBdefault
129      */

130     public PixelGrabber(ImageProducer JavaDoc ip, int x, int y, int w, int h,
131             int[] pix, int off, int scansize) {
132     producer = ip;
133     dstX = x;
134     dstY = y;
135     dstW = w;
136     dstH = h;
137     dstOff = off;
138     dstScan = scansize;
139     intPixels = pix;
140     imageModel = ColorModel.getRGBdefault();
141     }
142
143     /**
144      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
145      * section of pixels from the specified image. The pixels are
146      * accumulated in the original ColorModel if the same ColorModel
147      * is used for every call to setPixels, otherwise the pixels are
148      * accumulated in the default RGB ColorModel. If the forceRGB
149      * parameter is true, then the pixels will be accumulated in the
150      * default RGB ColorModel anyway. A buffer is allocated by the
151      * PixelGrabber to hold the pixels in either case. If (w < 0) or
152      * (h < 0), then they will default to the remaining width and
153      * height of the source data when that information is delivered.
154      * @param img the image to retrieve the image data from
155      * @param x the x coordinate of the upper left corner of the rectangle
156      * of pixels to retrieve from the image, relative to the default
157      * (unscaled) size of the image
158      * @param y the y coordinate of the upper left corner of the rectangle
159      * of pixels to retrieve from the image
160      * @param w the width of the rectangle of pixels to retrieve
161      * @param h the height of the rectangle of pixels to retrieve
162      * @param forceRGB true if the pixels should always be converted to
163      * the default RGB ColorModel
164      */

165     public PixelGrabber(Image JavaDoc img, int x, int y, int w, int h,
166             boolean forceRGB)
167     {
168     producer = img.getSource();
169     dstX = x;
170     dstY = y;
171     dstW = w;
172     dstH = h;
173     if (forceRGB) {
174         imageModel = ColorModel.getRGBdefault();
175     }
176     }
177
178     /**
179      * Request the PixelGrabber to start fetching the pixels.
180      */

181     public synchronized void startGrabbing() {
182     if ((flags & DONEBITS) != 0) {
183         return;
184     }
185     if (!grabbing) {
186         grabbing = true;
187         flags &= ~(ImageObserver.ABORT);
188         producer.startProduction(this);
189     }
190     }
191
192     /**
193      * Request the PixelGrabber to abort the image fetch.
194      */

195     public synchronized void abortGrabbing() {
196     imageComplete(IMAGEABORTED);
197     }
198
199     /**
200      * Request the Image or ImageProducer to start delivering pixels and
201      * wait for all of the pixels in the rectangle of interest to be
202      * delivered.
203      * @return true if the pixels were successfully grabbed, false on
204      * abort, error or timeout
205      * @exception InterruptedException
206      * Another thread has interrupted this thread.
207      */

208     public boolean grabPixels() throws InterruptedException JavaDoc {
209     return grabPixels(0);
210     }
211
212     /**
213      * Request the Image or ImageProducer to start delivering pixels and
214      * wait for all of the pixels in the rectangle of interest to be
215      * delivered or until the specified timeout has elapsed. This method
216      * behaves in the following ways, depending on the value of
217      * <code>ms</code>:
218      * <ul>
219      * <li> If <code>ms</code> == 0, waits until all pixels are delivered
220      * <li> If <code>ms</code> > 0, waits until all pixels are delivered
221      * as timeout expires.
222      * <li> If <code>ms</code> < 0, returns <code>true</code> if all pixels
223      * are grabbed, <code>false</code> otherwise and does not wait.
224      * </ul>
225      * @param ms the number of milliseconds to wait for the image pixels
226      * to arrive before timing out
227      * @return true if the pixels were successfully grabbed, false on
228      * abort, error or timeout
229      * @exception InterruptedException
230      * Another thread has interrupted this thread.
231      */

232     public synchronized boolean grabPixels(long ms)
233     throws InterruptedException JavaDoc
234     {
235     if ((flags & DONEBITS) != 0) {
236         return (flags & GRABBEDBITS) != 0;
237     }
238     long end = ms + System.currentTimeMillis();
239     if (!grabbing) {
240         grabbing = true;
241         flags &= ~(ImageObserver.ABORT);
242         producer.startProduction(this);
243     }
244     while (grabbing) {
245         long timeout;
246         if (ms == 0) {
247         timeout = 0;
248         } else {
249         timeout = end - System.currentTimeMillis();
250         if (timeout <= 0) {
251             break;
252         }
253         }
254         wait(timeout);
255     }
256     return (flags & GRABBEDBITS) != 0;
257     }
258
259     /**
260      * Return the status of the pixels. The ImageObserver flags
261      * representing the available pixel information are returned.
262      * @return the bitwise OR of all relevant ImageObserver flags
263      * @see ImageObserver
264      */

265     public synchronized int getStatus() {
266     return flags;
267     }
268
269     /**
270      * Get the width of the pixel buffer (after adjusting for image width).
271      * If no width was specified for the rectangle of pixels to grab then
272      * then this information will only be available after the image has
273      * delivered the dimensions.
274      * @return the final width used for the pixel buffer or -1 if the width
275      * is not yet known
276      * @see #getStatus
277      */

278     public synchronized int getWidth() {
279     return (dstW < 0) ? -1 : dstW;
280     }
281
282     /**
283      * Get the height of the pixel buffer (after adjusting for image height).
284      * If no width was specified for the rectangle of pixels to grab then
285      * then this information will only be available after the image has
286      * delivered the dimensions.
287      * @return the final height used for the pixel buffer or -1 if the height
288      * is not yet known
289      * @see #getStatus
290      */

291     public synchronized int getHeight() {
292     return (dstH < 0) ? -1 : dstH;
293     }
294
295     /**
296      * Get the pixel buffer. If the PixelGrabber was not constructed
297      * with an explicit pixel buffer to hold the pixels then this method
298      * will return null until the size and format of the image data is
299      * known.
300      * Since the PixelGrabber may fall back on accumulating the data
301      * in the default RGB ColorModel at any time if the source image
302      * uses more than one ColorModel to deliver the data, the array
303      * object returned by this method may change over time until the
304      * image grab is complete.
305      * @return either a byte array or an int array
306      * @see #getStatus
307      * @see #setPixels(int, int, int, int, ColorModel, byte[], int, int)
308      * @see #setPixels(int, int, int, int, ColorModel, int[], int, int)
309      */

310     public synchronized Object JavaDoc getPixels() {
311     return (bytePixels == null)
312         ? ((Object JavaDoc) intPixels)
313         : ((Object JavaDoc) bytePixels);
314     }
315
316     /**
317      * Get the ColorModel for the pixels stored in the array. If the
318      * PixelGrabber was constructed with an explicit pixel buffer then
319      * this method will always return the default RGB ColorModel,
320      * otherwise it may return null until the ColorModel used by the
321      * ImageProducer is known.
322      * Since the PixelGrabber may fall back on accumulating the data
323      * in the default RGB ColorModel at any time if the source image
324      * uses more than one ColorModel to deliver the data, the ColorModel
325      * object returned by this method may change over time until the
326      * image grab is complete and may not reflect any of the ColorModel
327      * objects that was used by the ImageProducer to deliver the pixels.
328      * @return the ColorModel object used for storing the pixels
329      * @see #getStatus
330      * @see ColorModel#getRGBdefault
331      * @see #setColorModel(ColorModel)
332      */

333     public synchronized ColorModel JavaDoc getColorModel() {
334     return imageModel;
335     }
336
337     /**
338      * The setDimensions method is part of the ImageConsumer API which
339      * this class must implement to retrieve the pixels.
340      * <p>
341      * Note: This method is intended to be called by the ImageProducer
342      * of the Image whose pixels are being grabbed. Developers using
343      * this class to retrieve pixels from an image should avoid calling
344      * this method directly since that operation could result in problems
345      * with retrieving the requested pixels.
346      * @param width the width of the dimension
347      * @param height the height of the dimension
348      */

349     public void setDimensions(int width, int height) {
350     if (dstW < 0) {
351         dstW = width - dstX;
352     }
353     if (dstH < 0) {
354         dstH = height - dstY;
355     }
356     if (dstW <= 0 || dstH <= 0) {
357         imageComplete(STATICIMAGEDONE);
358     } else if (intPixels == null &&
359            imageModel == ColorModel.getRGBdefault()) {
360         intPixels = new int[dstW * dstH];
361         dstScan = dstW;
362         dstOff = 0;
363     }
364     flags |= (ImageObserver.WIDTH | ImageObserver.HEIGHT);
365     }
366
367     /**
368      * The setHints method is part of the ImageConsumer API which
369      * this class must implement to retrieve the pixels.
370      * <p>
371      * Note: This method is intended to be called by the ImageProducer
372      * of the Image whose pixels are being grabbed. Developers using
373      * this class to retrieve pixels from an image should avoid calling
374      * this method directly since that operation could result in problems
375      * with retrieving the requested pixels.
376      * @param hints a set of hints used to process the pixels
377      */

378     public void setHints(int hints) {
379     return;
380     }
381
382     /**
383      * The setProperties method is part of the ImageConsumer API which
384      * this class must implement to retrieve the pixels.
385      * <p>
386      * Note: This method is intended to be called by the ImageProducer
387      * of the Image whose pixels are being grabbed. Developers using
388      * this class to retrieve pixels from an image should avoid calling
389      * this method directly since that operation could result in problems
390      * with retrieving the requested pixels.
391      * @param props the list of properties
392      */

393     public void setProperties(Hashtable JavaDoc<?,?> props) {
394     return;
395     }
396
397     /**
398      * The setColorModel method is part of the ImageConsumer API which
399      * this class must implement to retrieve the pixels.
400      * <p>
401      * Note: This method is intended to be called by the ImageProducer
402      * of the Image whose pixels are being grabbed. Developers using
403      * this class to retrieve pixels from an image should avoid calling
404      * this method directly since that operation could result in problems
405      * with retrieving the requested pixels.
406      * @param model the specified <code>ColorModel</code>
407      * @see #getColorModel
408      */

409     public void setColorModel(ColorModel JavaDoc model) {
410     return;
411     }
412
413     private void convertToRGB() {
414     int size = dstW * dstH;
415     int newpixels[] = new int[size];
416     if (bytePixels != null) {
417         for (int i = 0; i < size; i++) {
418         newpixels[i] = imageModel.getRGB(bytePixels[i] & 0xff);
419         }
420     } else if (intPixels != null) {
421         for (int i = 0; i < size; i++) {
422         newpixels[i] = imageModel.getRGB(intPixels[i]);
423         }
424     }
425     bytePixels = null;
426     intPixels = newpixels;
427     dstScan = dstW;
428     dstOff = 0;
429     imageModel = ColorModel.getRGBdefault();
430     }
431
432     /**
433      * The setPixels method is part of the ImageConsumer API which
434      * this class must implement to retrieve the pixels.
435      * <p>
436      * Note: This method is intended to be called by the ImageProducer
437      * of the Image whose pixels are being grabbed. Developers using
438      * this class to retrieve pixels from an image should avoid calling
439      * this method directly since that operation could result in problems
440      * with retrieving the requested pixels.
441      * @param srcX,&nbsp;srcY the coordinates of the upper-left corner
442      * of the area of pixels to be set
443      * @param srcW the width of the area of pixels
444      * @param srcH the height of the area of pixels
445      * @param model the specified <code>ColorModel</code>
446      * @param pixels the array of pixels
447      * @param srcOff the offset into the pixels array
448      * @param srcScan the distance from one row of pixels to the next
449      * in the pixels array
450      * @see #getPixels
451      */

452     public void setPixels(int srcX, int srcY, int srcW, int srcH,
453               ColorModel JavaDoc model,
454               byte pixels[], int srcOff, int srcScan) {
455     if (srcY < dstY) {
456         int diff = dstY - srcY;
457         if (diff >= srcH) {
458         return;
459         }
460         srcOff += srcScan * diff;
461         srcY += diff;
462         srcH -= diff;
463     }
464     if (srcY + srcH > dstY + dstH) {
465         srcH = (dstY + dstH) - srcY;
466         if (srcH <= 0) {
467         return;
468         }
469     }
470     if (srcX < dstX) {
471         int diff = dstX - srcX;
472         if (diff >= srcW) {
473         return;
474         }
475         srcOff += diff;
476         srcX += diff;
477         srcW -= diff;
478     }
479     if (srcX + srcW > dstX + dstW) {
480         srcW = (dstX + dstW) - srcX;
481         if (srcW <= 0) {
482         return;
483         }
484     }
485     int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
486     if (intPixels == null) {
487         if (bytePixels == null) {
488         bytePixels = new byte[dstW * dstH];
489         dstScan = dstW;
490         dstOff = 0;
491         imageModel = model;
492         } else if (imageModel != model) {
493         convertToRGB();
494         }
495         if (bytePixels != null) {
496         for (int h = srcH; h > 0; h--) {
497             System.arraycopy(pixels, srcOff, bytePixels, dstPtr, srcW);
498             srcOff += srcScan;
499             dstPtr += dstScan;
500         }
501         }
502     }
503     if (intPixels != null) {
504         int dstRem = dstScan - srcW;
505         int srcRem = srcScan - srcW;
506         for (int h = srcH; h > 0; h--) {
507         for (int w = srcW; w > 0; w--) {
508             intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]&0xff);
509         }
510         srcOff += srcRem;
511         dstPtr += dstRem;
512         }
513     }
514     flags |= ImageObserver.SOMEBITS;
515     }
516
517     /**
518      * The setPixels method is part of the ImageConsumer API which
519      * this class must implement to retrieve the pixels.
520      * <p>
521      * Note: This method is intended to be called by the ImageProducer
522      * of the Image whose pixels are being grabbed. Developers using
523      * this class to retrieve pixels from an image should avoid calling
524      * this method directly since that operation could result in problems
525      * with retrieving the requested pixels.
526      * @param srcX,&nbsp;srcY the coordinates of the upper-left corner
527      * of the area of pixels to be set
528      * @param srcW the width of the area of pixels
529      * @param srcH the height of the area of pixels
530      * @param model the specified <code>ColorModel</code>
531      * @param pixels the array of pixels
532      * @param srcOff the offset into the pixels array
533      * @param srcScan the distance from one row of pixels to the next
534      * in the pixels array
535      * @see #getPixels
536      */

537     public void setPixels(int srcX, int srcY, int srcW, int srcH,
538               ColorModel JavaDoc model,
539               int pixels[], int srcOff, int srcScan) {
540     if (srcY < dstY) {
541         int diff = dstY - srcY;
542         if (diff >= srcH) {
543         return;
544         }
545         srcOff += srcScan * diff;
546         srcY += diff;
547         srcH -= diff;
548     }
549     if (srcY + srcH > dstY + dstH) {
550         srcH = (dstY + dstH) - srcY;
551         if (srcH <= 0) {
552         return;
553         }
554     }
555     if (srcX < dstX) {
556         int diff = dstX - srcX;
557         if (diff >= srcW) {
558         return;
559         }
560         srcOff += diff;
561         srcX += diff;
562         srcW -= diff;
563     }
564     if (srcX + srcW > dstX + dstW) {
565         srcW = (dstX + dstW) - srcX;
566         if (srcW <= 0) {
567         return;
568         }
569     }
570     if (intPixels == null) {
571         if (bytePixels == null) {
572         intPixels = new int[dstW * dstH];
573         dstScan = dstW;
574         dstOff = 0;
575         imageModel = model;
576         } else {
577         convertToRGB();
578         }
579     }
580     int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
581     if (imageModel == model) {
582         for (int h = srcH; h > 0; h--) {
583         System.arraycopy(pixels, srcOff, intPixels, dstPtr, srcW);
584         srcOff += srcScan;
585         dstPtr += dstScan;
586         }
587     } else {
588         if (imageModel != ColorModel.getRGBdefault()) {
589         convertToRGB();
590         }
591         int dstRem = dstScan - srcW;
592         int srcRem = srcScan - srcW;
593         for (int h = srcH; h > 0; h--) {
594         for (int w = srcW; w > 0; w--) {
595             intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]);
596         }
597         srcOff += srcRem;
598         dstPtr += dstRem;
599         }
600     }
601     flags |= ImageObserver.SOMEBITS;
602     }
603
604     /**
605      * The imageComplete method is part of the ImageConsumer API which
606      * this class must implement to retrieve the pixels.
607      * <p>
608      * Note: This method is intended to be called by the ImageProducer
609      * of the Image whose pixels are being grabbed. Developers using
610      * this class to retrieve pixels from an image should avoid calling
611      * this method directly since that operation could result in problems
612      * with retrieving the requested pixels.
613      * @param status the status of image loading
614      */

615     public synchronized void imageComplete(int status) {
616     grabbing = false;
617     switch (status) {
618     default:
619     case IMAGEERROR:
620         flags |= ImageObserver.ERROR | ImageObserver.ABORT;
621         break;
622     case IMAGEABORTED:
623         flags |= ImageObserver.ABORT;
624         break;
625     case STATICIMAGEDONE:
626         flags |= ImageObserver.ALLBITS;
627         break;
628     case SINGLEFRAMEDONE:
629         flags |= ImageObserver.FRAMEBITS;
630         break;
631     }
632     producer.removeConsumer(this);
633     notifyAll();
634     }
635
636     /**
637      * Returns the status of the pixels. The ImageObserver flags
638      * representing the available pixel information are returned.
639      * This method and {@link #getStatus() getStatus} have the
640      * same implementation, but <code>getStatus</code> is the
641      * preferred method because it conforms to the convention of
642      * naming information-retrieval methods with the form
643      * "getXXX".
644      * @return the bitwise OR of all relevant ImageObserver flags
645      * @see ImageObserver
646      * @see #getStatus()
647      */

648     public synchronized int status() {
649     return flags;
650     }
651 }
652
Popular Tags