Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / awt / image / PixelGrabber.java
blobbcfa050f3df70be7801b7e70e6aba3ee4dd99aec
1 /* PixelGrabber.java -- retrieve a subset of an image's data
2 Copyright (C) 1999, 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
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.
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. */
39 package java.awt.image;
41 import java.awt.Image;
42 import java.util.Hashtable;
44 /**
45 * PixelGrabber is an ImageConsumer that extracts a rectangular region
46 * of pixels from an Image.
48 public class PixelGrabber implements ImageConsumer
50 int x, y, offset;
51 int width = -1;
52 int height = -1;
53 int scansize = -1;
54 boolean forceRGB = true;
56 ColorModel model = ColorModel.getRGBdefault();
57 int hints;
58 Hashtable props;
60 int int_pixel_buffer[];
61 boolean ints_delivered = false;
62 byte byte_pixel_buffer[];
63 boolean bytes_delivered = false;
65 ImageProducer ip;
66 int observerStatus;
67 int consumerStatus;
69 private Thread grabberThread;
70 boolean grabbing = false;
72 /**
73 * Construct a PixelGrabber that will retrieve RGB data from a given
74 * Image.
76 * The RGB data will be retrieved from a rectangular region
77 * <code>(x, y, w, h)</code> within the image. The data will be
78 * stored in the provided <code>pix</code> array, which must have
79 * been initialized to a size of at least <code>w * h</code>. The
80 * data for a pixel (m, n) in the grab rectangle will be stored at
81 * <code>pix[(n - y) * scansize + (m - x) + off]</code>.
83 * @param img the Image from which to grab pixels
84 * @param x the x coordinate, relative to <code>img</code>'s
85 * top-left corner, of the grab rectangle's top-left pixel
86 * @param y the y coordinate, relative to <code>img</code>'s
87 * top-left corner, of the grab rectangle's top-left pixel
88 * @param w the width of the grab rectangle, in pixels
89 * @param h the height of the grab rectangle, in pixels
90 * @param pix the array in which to store grabbed RGB pixel data
91 * @param off the offset into the <code>pix</code> array at which to
92 * start storing RGB data
93 * @param scansize a set of <code>scansize</code> consecutive
94 * elements in the <code>pix</code> array represents one row of
95 * pixels in the grab rectangle
97 public PixelGrabber(Image img, int x, int y, int w, int h,
98 int pix[], int off, int scansize)
100 this (img.getSource(), x, y, w, h, pix, off, scansize);
104 * Construct a PixelGrabber that will retrieve RGB data from a given
105 * ImageProducer.
107 * The RGB data will be retrieved from a rectangular region
108 * <code>(x, y, w, h)</code> within the image produced by
109 * <code>ip</code>. The data will be stored in the provided
110 * <code>pix</code> array, which must have been initialized to a
111 * size of at least <code>w * h</code>. The data for a pixel (m, n)
112 * in the grab rectangle will be stored at
113 * <code>pix[(n - y) * scansize + (m - x) + off]</code>.
115 * @param ip the ImageProducer from which to grab pixels
116 * @param x the x coordinate of the grab rectangle's top-left pixel,
117 * specified relative to the top-left corner of the image produced
118 * by <code>ip</code>
119 * @param y the y coordinate of the grab rectangle's top-left pixel,
120 * specified relative to the top-left corner of the image produced
121 * by <code>ip</code>
122 * @param w the width of the grab rectangle, in pixels
123 * @param h the height of the grab rectangle, in pixels
124 * @param pix the array in which to store grabbed RGB pixel data
125 * @param off the offset into the <code>pix</code> array at which to
126 * start storing RGB data
127 * @param scansize a set of <code>scansize</code> consecutive
128 * elements in the <code>pix</code> array represents one row of
129 * pixels in the grab rectangle
131 public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
132 int pix[], int off, int scansize)
134 this.ip = ip;
135 this.x = x;
136 this.y = y;
137 this.width = w;
138 this.height = h;
139 this.offset = off;
140 this.scansize = scansize;
142 int_pixel_buffer = pix;
143 // Initialize the byte array in case ip sends us byte-formatted
144 // pixel data.
145 byte_pixel_buffer = new byte[pix.length * 4];
149 * Construct a PixelGrabber that will retrieve data from a given
150 * Image.
152 * The RGB data will be retrieved from a rectangular region
153 * <code>(x, y, w, h)</code> within the image. The data will be
154 * stored in an internal array which can be accessed by calling
155 * <code>getPixels</code>. The data for a pixel (m, n) in the grab
156 * rectangle will be stored in the returned array at index
157 * <code>(n - y) * scansize + (m - x) + off</code>.
158 * If forceRGB is false, then the returned data will be not be
159 * converted to RGB from its format in <code>img</code>.
161 * If <code>w</code> is negative, the width of the grab region will
162 * be from x to the right edge of the image. Likewise, if
163 * <code>h</code> is negative, the height of the grab region will be
164 * from y to the bottom edge of the image.
166 * @param img the Image from which to grab pixels
167 * @param x the x coordinate, relative to <code>img</code>'s
168 * top-left corner, of the grab rectangle's top-left pixel
169 * @param y the y coordinate, relative to <code>img</code>'s
170 * top-left corner, of the grab rectangle's top-left pixel
171 * @param w the width of the grab rectangle, in pixels
172 * @param h the height of the grab rectangle, in pixels
173 * @param forceRGB true to force conversion of the rectangular
174 * region's pixel data to RGB
176 public PixelGrabber(Image img,
177 int x, int y,
178 int w, int h,
179 boolean forceRGB)
181 this.ip = img.getSource();
182 this.x = x;
183 this.y = y;
184 width = w;
185 height = h;
186 // If width or height is negative, postpone pixel buffer
187 // initialization until setDimensions is called back by ip.
188 if (width >= 0 && height >= 0)
190 int_pixel_buffer = new int[width * height];
191 byte_pixel_buffer = new byte[width * height];
193 this.forceRGB = forceRGB;
197 * Start grabbing pixels.
199 * Spawns an image production thread that calls back to this
200 * PixelGrabber's ImageConsumer methods.
202 public synchronized void startGrabbing()
204 // Make sure we're not already grabbing.
205 if (grabbing == false)
207 grabbing = true;
208 grabberThread = new Thread ()
210 public void run ()
212 ip.startProduction (PixelGrabber.this);
215 grabberThread.start ();
220 * Abort pixel grabbing.
222 public synchronized void abortGrabbing()
224 if (grabbing)
226 // Interrupt the grabbing thread.
227 Thread moribund = grabberThread;
228 grabberThread = null;
229 moribund.interrupt();
231 imageComplete (ImageConsumer.IMAGEABORTED);
236 * Have our Image or ImageProducer start sending us pixels via our
237 * ImageConsumer methods and wait for all pixels in the grab
238 * rectangle to be delivered.
240 * @return true if successful, false on abort or error
242 * @throws InterruptedException if interrupted by another thread.
244 public synchronized boolean grabPixels() throws InterruptedException
246 return grabPixels(0);
250 * grabPixels's behavior depends on the value of <code>ms</code>.
252 * If ms < 0, return true if all pixels from the source image have
253 * been delivered, false otherwise. Do not wait.
255 * If ms >= 0 then we request that our Image or ImageProducer start
256 * delivering pixels to us via our ImageConsumer methods.
258 * If ms > 0, wait at most <code>ms</code> milliseconds for
259 * delivery of all pixels within the grab rectangle.
261 * If ms == 0, wait until all pixels have been delivered.
263 * @return true if all pixels from the source image have been
264 * delivered, false otherwise
266 * @throws InterruptedException if this thread is interrupted while
267 * we are waiting for pixels to be delivered
269 public synchronized boolean grabPixels(long ms) throws InterruptedException
271 if (ms < 0)
272 return ((observerStatus & (ImageObserver.FRAMEBITS
273 | ImageObserver.ALLBITS)) != 0);
275 // Spawn a new ImageProducer thread to send us the image data via
276 // our ImageConsumer methods.
277 startGrabbing();
279 if (ms > 0)
281 long stop_time = System.currentTimeMillis() + ms;
282 long time_remaining;
283 while (grabbing)
285 time_remaining = stop_time - System.currentTimeMillis();
286 if (time_remaining <= 0)
287 break;
288 wait (time_remaining);
290 abortGrabbing ();
292 else
293 wait ();
295 // If consumerStatus is non-zero then the image is done loading or
296 // an error has occurred.
297 if (consumerStatus != 0)
298 return setObserverStatus ();
300 return ((observerStatus & (ImageObserver.FRAMEBITS
301 | ImageObserver.ALLBITS)) != 0);
304 // Set observer status flags based on the current consumer status
305 // flags. Return true if the consumer flags indicate that the
306 // image was loaded successfully, or false otherwise.
307 private synchronized boolean setObserverStatus ()
309 boolean retval = false;
311 if ((consumerStatus & IMAGEERROR) != 0)
312 observerStatus |= ImageObserver.ERROR;
314 if ((consumerStatus & IMAGEABORTED) != 0)
315 observerStatus |= ImageObserver.ABORT;
317 if ((consumerStatus & STATICIMAGEDONE) != 0)
319 observerStatus |= ImageObserver.ALLBITS;
320 retval = true;
323 if ((consumerStatus & SINGLEFRAMEDONE) != 0)
325 observerStatus |= ImageObserver.FRAMEBITS;
326 retval = true;
329 return retval;
333 * @return the status of the pixel grabbing thread, represented by a
334 * bitwise OR of ImageObserver flags
336 public synchronized int getStatus()
338 return observerStatus;
342 * @return the width of the grab rectangle in pixels, or a negative
343 * number if the ImageProducer has not yet called our setDimensions
344 * method
346 public synchronized int getWidth()
348 return width;
352 * @return the height of the grab rectangle in pixels, or a negative
353 * number if the ImageProducer has not yet called our setDimensions
354 * method
356 public synchronized int getHeight()
358 return height;
362 * @return a byte array of pixel data if ImageProducer delivered
363 * pixel data using the byte[] variant of setPixels, or an int array
364 * otherwise
366 public synchronized Object getPixels()
368 if (ints_delivered)
369 return int_pixel_buffer;
370 else if (bytes_delivered)
371 return byte_pixel_buffer;
372 else
373 return null;
377 * @return the ColorModel currently being used for the majority of
378 * pixel data conversions
380 public synchronized ColorModel getColorModel()
382 return model;
386 * Our <code>ImageProducer</code> calls this method to indicate the
387 * size of the image being produced.
389 * setDimensions is an ImageConsumer method. None of PixelGrabber's
390 * ImageConsumer methods should be called by code that instantiates
391 * a PixelGrabber. They are only made public so they can be called
392 * by the PixelGrabber's ImageProducer.
394 * @param width the width of the image
395 * @param height the height of the image
397 public synchronized void setDimensions(int width, int height)
399 // Our width wasn't set when we were constructed. Set our width
400 // so that the grab region includes all pixels from x to the right
401 // edge of the source image.
402 if (this.width < 0)
403 this.width = width - x;
405 // Our height wasn't set when we were constructed. Set our height
406 // so that the grab region includes all pixels from y to the
407 // bottom edge of the source image.
408 if (this.height < 0)
409 this.height = height - y;
411 if (scansize < 0)
412 scansize = this.width;
414 if (int_pixel_buffer == null)
415 int_pixel_buffer = new int[this.width * this.height];
417 if (byte_pixel_buffer == null)
418 byte_pixel_buffer = new byte[this.width * this.height];
422 * Our <code>ImageProducer</code> may call this method to send us a
423 * list of its image's properties.
425 * setProperties is an ImageConsumer method. None of PixelGrabber's
426 * ImageConsumer methods should be called by code that instantiates
427 * a PixelGrabber. They are only made public so they can be called
428 * by the PixelGrabber's ImageProducer.
430 * @param props a list of properties associated with the image being
431 * produced
433 public synchronized void setProperties(Hashtable props)
435 this.props = props;
439 * Our ImageProducer will call <code>setColorModel</code> to
440 * indicate the model used by the majority of calls to
441 * <code>setPixels</code>. Each call to <code>setPixels</code>
442 * could however indicate a different <code>ColorModel</code>.
444 * setColorModel is an ImageConsumer method. None of PixelGrabber's
445 * ImageConsumer methods should be called by code that instantiates
446 * a PixelGrabber. They are only made public so they can be called
447 * by the PixelGrabber's ImageProducer.
449 * @param model the color model to be used most often by setPixels
451 * @see ColorModel
453 public synchronized void setColorModel(ColorModel model)
455 this.model = model;
459 * Our <code>ImageProducer</code> may call this method with a
460 * bit mask of hints from any of <code>RANDOMPIXELORDER</code>,
461 * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>,
462 * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code>.
464 * setHints is an ImageConsumer method. None of PixelGrabber's
465 * ImageConsumer methods should be called by code that instantiates
466 * a PixelGrabber. They are only made public so they can be called
467 * by the PixelGrabber's ImageProducer.
469 * @param flags a bit mask of hints
471 public synchronized void setHints(int flags)
473 hints = flags;
477 * Our ImageProducer calls setPixels to deliver a subset of its
478 * pixels.
480 * Each element of the pixels array represents one pixel. The
481 * pixel data is formatted according to the color model model.
482 * The x and y parameters are the coordinates of the rectangular
483 * region of pixels being delivered to this ImageConsumer,
484 * specified relative to the top left corner of the image being
485 * produced. Likewise, w and h are the pixel region's dimensions.
487 * @param x x coordinate of pixel block
488 * @param y y coordinate of pixel block
489 * @param w width of pixel block
490 * @param h height of pixel block
491 * @param model color model used to interpret pixel data
492 * @param pixels pixel block data
493 * @param offset offset into pixels array
494 * @param scansize width of one row in the pixel block
496 public synchronized void setPixels(int x, int y, int w, int h,
497 ColorModel model, byte[] pixels,
498 int offset, int scansize)
500 ColorModel currentModel;
501 if (model != null)
502 currentModel = model;
503 else
504 currentModel = this.model;
506 for(int yp = y; yp < (y + h); yp++)
508 for(int xp = x; xp < (x + w); xp++)
510 // Check if the coordinates (xp, yp) are within the
511 // pixel block that we are grabbing.
512 if(xp >= this.x
513 && yp >= this.y
514 && xp < (this.x + this.width)
515 && yp < (this.y + this.height))
517 int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset;
518 int p = (yp - y) * scansize + (xp - x) + offset;
519 if (forceRGB)
521 ints_delivered = true;
523 assert (i >= 0 && i < int_pixel_buffer.length);
524 assert (p >= 0 && p < pixels.length);
525 int_pixel_buffer[i] = currentModel.getRGB (pixels[p]);
527 else
529 bytes_delivered = true;
531 assert (i >= 0 && i < byte_pixel_buffer.length);
532 assert (p >= 0 && p < pixels.length);
533 byte_pixel_buffer[i] = pixels[p];
541 * Our ImageProducer calls setPixels to deliver a subset of its
542 * pixels.
544 * Each element of the pixels array represents one pixel. The
545 * pixel data is formatted according to the color model model.
546 * The x and y parameters are the coordinates of the rectangular
547 * region of pixels being delivered to this ImageConsumer,
548 * specified relative to the top left corner of the image being
549 * produced. Likewise, w and h are the pixel region's dimensions.
551 * @param x x coordinate of pixel block
552 * @param y y coordinate of pixel block
553 * @param w width of pixel block
554 * @param h height of pixel block
555 * @param model color model used to interpret pixel data
556 * @param pixels pixel block data
557 * @param offset offset into pixels array
558 * @param scansize width of one row in the pixel block
560 public synchronized void setPixels(int x, int y, int w, int h,
561 ColorModel model, int[] pixels,
562 int offset, int scansize)
564 ColorModel currentModel;
565 if (model != null)
566 currentModel = model;
567 else
568 currentModel = this.model;
570 ints_delivered = true;
572 for(int yp = y; yp < (y + h); yp++)
574 for(int xp = x; xp < (x + w); xp++)
576 // Check if the coordinates (xp, yp) are within the
577 // pixel block that we are grabbing.
578 if(xp >= this.x
579 && yp >= this.y
580 && xp < (this.x + this.width)
581 && yp < (this.y + this.height))
583 int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset;
584 int p = (yp - y) * scansize + (xp - x) + offset;
585 assert (i >= 0 && i < int_pixel_buffer.length);
586 assert (p >= 0 && p < pixels.length);
587 if (forceRGB)
588 int_pixel_buffer[i] = currentModel.getRGB (pixels[p]);
589 else
590 int_pixel_buffer[i] = pixels[p];
597 * Our <code>ImageProducer</code> calls this method to inform us
598 * that a single frame or the entire image is complete. The method
599 * is also used to inform us of an error in loading or producing the
600 * image.
602 * @param status the status of image production, represented by a
603 * bitwise OR of ImageConsumer flags
605 public synchronized void imageComplete(int status)
607 consumerStatus = status;
608 setObserverStatus ();
609 grabbing = false;
610 ip.removeConsumer (this);
612 notifyAll ();
616 * @return the return value of getStatus
618 * @specnote The newer getStatus should be used in place of status.
620 public synchronized int status()
622 return getStatus();