Create embedded-5_0-branch branch for development on ARM embedded cores.
[official-gcc.git] / embedded-5_0-branch / libjava / classpath / java / awt / image / PixelGrabber.java
blobb83fab5711dd5c9d14724b546a96a9d24e898b50
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 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. This can
116 * be null.
117 * @param x the x coordinate of the grab rectangle's top-left pixel,
118 * specified relative to the top-left corner of the image produced
119 * by <code>ip</code>
120 * @param y the y coordinate of the grab rectangle's top-left pixel,
121 * specified relative to the top-left corner of the image produced
122 * by <code>ip</code>
123 * @param w the width of the grab rectangle, in pixels
124 * @param h the height of the grab rectangle, in pixels
125 * @param pix the array in which to store grabbed RGB pixel data
126 * @param off the offset into the <code>pix</code> array at which to
127 * start storing RGB data
128 * @param scansize a set of <code>scansize</code> consecutive
129 * elements in the <code>pix</code> array represents one row of
130 * pixels in the grab rectangle
132 public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
133 int pix[], int off, int scansize)
135 this.ip = ip;
136 this.x = x;
137 this.y = y;
138 this.width = w;
139 this.height = h;
140 this.offset = off;
141 this.scansize = scansize;
143 int_pixel_buffer = pix;
144 // Initialize the byte array in case ip sends us byte-formatted
145 // pixel data.
146 byte_pixel_buffer = new byte[pix.length * 4];
150 * Construct a PixelGrabber that will retrieve data from a given
151 * Image.
153 * The RGB data will be retrieved from a rectangular region
154 * <code>(x, y, w, h)</code> within the image. The data will be
155 * stored in an internal array which can be accessed by calling
156 * <code>getPixels</code>. The data for a pixel (m, n) in the grab
157 * rectangle will be stored in the returned array at index
158 * <code>(n - y) * scansize + (m - x) + off</code>.
159 * If forceRGB is false, then the returned data will be not be
160 * converted to RGB from its format in <code>img</code>.
162 * If <code>w</code> is negative, the width of the grab region will
163 * be from x to the right edge of the image. Likewise, if
164 * <code>h</code> is negative, the height of the grab region will be
165 * from y to the bottom edge of the image.
167 * @param img the Image from which to grab pixels
168 * @param x the x coordinate, relative to <code>img</code>'s
169 * top-left corner, of the grab rectangle's top-left pixel
170 * @param y the y coordinate, relative to <code>img</code>'s
171 * top-left corner, of the grab rectangle's top-left pixel
172 * @param w the width of the grab rectangle, in pixels
173 * @param h the height of the grab rectangle, in pixels
174 * @param forceRGB true to force conversion of the rectangular
175 * region's pixel data to RGB
177 public PixelGrabber(Image img,
178 int x, int y,
179 int w, int h,
180 boolean forceRGB)
182 this.ip = img.getSource();
184 if (this.ip == null)
185 throw new NullPointerException("The ImageProducer must not be null.");
187 this.x = x;
188 this.y = y;
189 width = w;
190 height = h;
191 // If width or height is negative, postpone pixel buffer
192 // initialization until setDimensions is called back by ip.
193 if (width >= 0 && height >= 0)
195 int_pixel_buffer = new int[width * height];
196 byte_pixel_buffer = new byte[width * height];
198 this.forceRGB = forceRGB;
202 * Start grabbing pixels.
204 * Spawns an image production thread that calls back to this
205 * PixelGrabber's ImageConsumer methods.
207 public synchronized void startGrabbing()
209 // Make sure we're not already grabbing.
210 if (grabbing == false)
212 grabbing = true;
213 grabberThread = new Thread ()
215 public void run ()
219 ip.startProduction (PixelGrabber.this);
221 catch (Exception ex)
223 imageComplete(ImageConsumer.IMAGEABORTED);
227 grabberThread.start ();
232 * Abort pixel grabbing.
234 public synchronized void abortGrabbing()
236 if (grabbing)
238 // Interrupt the grabbing thread.
239 Thread moribund = grabberThread;
240 grabberThread = null;
241 moribund.interrupt();
243 imageComplete (ImageConsumer.IMAGEABORTED);
248 * Have our Image or ImageProducer start sending us pixels via our
249 * ImageConsumer methods and wait for all pixels in the grab
250 * rectangle to be delivered.
252 * @return true if successful, false on abort or error
254 * @throws InterruptedException if interrupted by another thread.
256 public synchronized boolean grabPixels() throws InterruptedException
258 return grabPixels(0);
262 * grabPixels's behavior depends on the value of <code>ms</code>.
264 * If ms < 0, return true if all pixels from the source image have
265 * been delivered, false otherwise. Do not wait.
267 * If ms >= 0 then we request that our Image or ImageProducer start
268 * delivering pixels to us via our ImageConsumer methods.
270 * If ms > 0, wait at most <code>ms</code> milliseconds for
271 * delivery of all pixels within the grab rectangle.
273 * If ms == 0, wait until all pixels have been delivered.
275 * @return true if all pixels from the source image have been
276 * delivered, false otherwise
278 * @throws InterruptedException if this thread is interrupted while
279 * we are waiting for pixels to be delivered
281 public synchronized boolean grabPixels(long ms) throws InterruptedException
283 if (ms < 0)
284 return ((observerStatus & (ImageObserver.FRAMEBITS
285 | ImageObserver.ALLBITS)) != 0);
287 // Spawn a new ImageProducer thread to send us the image data via
288 // our ImageConsumer methods.
289 startGrabbing();
291 if (ms > 0)
293 long stop_time = System.currentTimeMillis() + ms;
294 long time_remaining;
295 while (grabbing)
297 time_remaining = stop_time - System.currentTimeMillis();
298 if (time_remaining <= 0)
299 break;
300 wait (time_remaining);
302 abortGrabbing ();
304 else
305 wait ();
307 // If consumerStatus is non-zero then the image is done loading or
308 // an error has occurred.
309 if (consumerStatus != 0)
310 return setObserverStatus ();
312 return ((observerStatus & (ImageObserver.FRAMEBITS
313 | ImageObserver.ALLBITS)) != 0);
316 // Set observer status flags based on the current consumer status
317 // flags. Return true if the consumer flags indicate that the
318 // image was loaded successfully, or false otherwise.
319 private synchronized boolean setObserverStatus ()
321 boolean retval = false;
323 if ((consumerStatus & IMAGEERROR) != 0)
324 observerStatus |= ImageObserver.ERROR;
326 if ((consumerStatus & IMAGEABORTED) != 0)
327 observerStatus |= ImageObserver.ABORT;
329 if ((consumerStatus & STATICIMAGEDONE) != 0)
331 observerStatus |= ImageObserver.ALLBITS;
332 retval = true;
335 if ((consumerStatus & SINGLEFRAMEDONE) != 0)
337 observerStatus |= ImageObserver.FRAMEBITS;
338 retval = true;
341 return retval;
345 * @return the status of the pixel grabbing thread, represented by a
346 * bitwise OR of ImageObserver flags
348 public synchronized int getStatus()
350 return observerStatus;
354 * @return the width of the grab rectangle in pixels, or a negative
355 * number if the ImageProducer has not yet called our setDimensions
356 * method
358 public synchronized int getWidth()
360 return width;
364 * @return the height of the grab rectangle in pixels, or a negative
365 * number if the ImageProducer has not yet called our setDimensions
366 * method
368 public synchronized int getHeight()
370 return height;
374 * @return a byte array of pixel data if ImageProducer delivered
375 * pixel data using the byte[] variant of setPixels, or an int array
376 * otherwise
378 public synchronized Object getPixels()
380 if (ints_delivered)
381 return int_pixel_buffer;
382 else if (bytes_delivered)
383 return byte_pixel_buffer;
384 else
385 return null;
389 * @return the ColorModel currently being used for the majority of
390 * pixel data conversions
392 public synchronized ColorModel getColorModel()
394 return model;
398 * Our <code>ImageProducer</code> calls this method to indicate the
399 * size of the image being produced.
401 * setDimensions is an ImageConsumer method. None of PixelGrabber's
402 * ImageConsumer methods should be called by code that instantiates
403 * a PixelGrabber. They are only made public so they can be called
404 * by the PixelGrabber's ImageProducer.
406 * @param width the width of the image
407 * @param height the height of the image
409 public synchronized void setDimensions(int width, int height)
411 // Our width wasn't set when we were constructed. Set our width
412 // so that the grab region includes all pixels from x to the right
413 // edge of the source image.
414 if (this.width < 0)
415 this.width = width - x;
417 // Our height wasn't set when we were constructed. Set our height
418 // so that the grab region includes all pixels from y to the
419 // bottom edge of the source image.
420 if (this.height < 0)
421 this.height = height - y;
423 if (scansize < 0)
424 scansize = this.width;
426 if (int_pixel_buffer == null)
427 int_pixel_buffer = new int[this.width * this.height];
429 if (byte_pixel_buffer == null)
430 byte_pixel_buffer = new byte[this.width * this.height];
434 * Our <code>ImageProducer</code> may call this method to send us a
435 * list of its image's properties.
437 * setProperties is an ImageConsumer method. None of PixelGrabber's
438 * ImageConsumer methods should be called by code that instantiates
439 * a PixelGrabber. They are only made public so they can be called
440 * by the PixelGrabber's ImageProducer.
442 * @param props a list of properties associated with the image being
443 * produced
445 public synchronized void setProperties(Hashtable<?,?> props)
447 this.props = props;
451 * Our ImageProducer will call <code>setColorModel</code> to
452 * indicate the model used by the majority of calls to
453 * <code>setPixels</code>. Each call to <code>setPixels</code>
454 * could however indicate a different <code>ColorModel</code>.
456 * setColorModel is an ImageConsumer method. None of PixelGrabber's
457 * ImageConsumer methods should be called by code that instantiates
458 * a PixelGrabber. They are only made public so they can be called
459 * by the PixelGrabber's ImageProducer.
461 * @param model the color model to be used most often by setPixels
463 * @see ColorModel
465 public synchronized void setColorModel(ColorModel model)
467 this.model = model;
471 * Our <code>ImageProducer</code> may call this method with a
472 * bit mask of hints from any of <code>RANDOMPIXELORDER</code>,
473 * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>,
474 * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code>.
476 * setHints is an ImageConsumer method. None of PixelGrabber's
477 * ImageConsumer methods should be called by code that instantiates
478 * a PixelGrabber. They are only made public so they can be called
479 * by the PixelGrabber's ImageProducer.
481 * @param flags a bit mask of hints
483 public synchronized void setHints(int flags)
485 hints = flags;
489 * Our ImageProducer calls setPixels to deliver a subset of its
490 * pixels.
492 * Each element of the pixels array represents one pixel. The
493 * pixel data is formatted according to the color model model.
494 * The x and y parameters are the coordinates of the rectangular
495 * region of pixels being delivered to this ImageConsumer,
496 * specified relative to the top left corner of the image being
497 * produced. Likewise, w and h are the pixel region's dimensions.
499 * @param x x coordinate of pixel block
500 * @param y y coordinate of pixel block
501 * @param w width of pixel block
502 * @param h height of pixel block
503 * @param model color model used to interpret pixel data
504 * @param pixels pixel block data
505 * @param offset offset into pixels array
506 * @param scansize width of one row in the pixel block
508 public synchronized void setPixels(int x, int y, int w, int h,
509 ColorModel model, byte[] pixels,
510 int offset, int scansize)
512 ColorModel currentModel;
513 if (model != null)
514 currentModel = model;
515 else
516 currentModel = this.model;
518 for(int yp = y; yp < (y + h); yp++)
520 for(int xp = x; xp < (x + w); xp++)
522 // Check if the coordinates (xp, yp) are within the
523 // pixel block that we are grabbing.
524 if(xp >= this.x
525 && yp >= this.y
526 && xp < (this.x + this.width)
527 && yp < (this.y + this.height))
529 int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset;
530 int p = (yp - y) * scansize + (xp - x) + offset;
531 if (forceRGB)
533 ints_delivered = true;
535 int_pixel_buffer[i] = currentModel.getRGB (pixels[p] & 0xFF);
537 else
539 bytes_delivered = true;
541 byte_pixel_buffer[i] = pixels[p];
549 * Our ImageProducer calls setPixels to deliver a subset of its
550 * pixels.
552 * Each element of the pixels array represents one pixel. The
553 * pixel data is formatted according to the color model model.
554 * The x and y parameters are the coordinates of the rectangular
555 * region of pixels being delivered to this ImageConsumer,
556 * specified relative to the top left corner of the image being
557 * produced. Likewise, w and h are the pixel region's dimensions.
559 * @param x x coordinate of pixel block
560 * @param y y coordinate of pixel block
561 * @param w width of pixel block
562 * @param h height of pixel block
563 * @param model color model used to interpret pixel data
564 * @param pixels pixel block data
565 * @param offset offset into pixels array
566 * @param scansize width of one row in the pixel block
568 public synchronized void setPixels(int x, int y, int w, int h,
569 ColorModel model, int[] pixels,
570 int offset, int scansize)
572 ColorModel currentModel;
573 if (model != null)
574 currentModel = model;
575 else
576 currentModel = this.model;
578 ints_delivered = true;
580 for(int yp = y; yp < (y + h); yp++)
582 for(int xp = x; xp < (x + w); xp++)
584 // Check if the coordinates (xp, yp) are within the
585 // pixel block that we are grabbing.
586 if(xp >= this.x
587 && yp >= this.y
588 && xp < (this.x + this.width)
589 && yp < (this.y + this.height))
591 int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset;
592 int p = (yp - y) * scansize + (xp - x) + offset;
593 if (forceRGB)
594 int_pixel_buffer[i] = currentModel.getRGB (pixels[p]);
595 else
596 int_pixel_buffer[i] = pixels[p];
603 * Our <code>ImageProducer</code> calls this method to inform us
604 * that a single frame or the entire image is complete. The method
605 * is also used to inform us of an error in loading or producing the
606 * image.
608 * @param status the status of image production, represented by a
609 * bitwise OR of ImageConsumer flags
611 public synchronized void imageComplete(int status)
613 consumerStatus = status;
614 setObserverStatus ();
615 grabbing = false;
616 if (ip != null)
617 ip.removeConsumer (this);
619 notifyAll ();
623 * @return the return value of getStatus
625 * @specnote The newer getStatus should be used in place of status.
627 public synchronized int status()
629 return getStatus();