Hello,

This patch completes the PixelGrabber implementation, updates its
javadocs and includes a mauve test case.

OK to commit?

Tom

2003-11-24  Thomas Fitzsimmons  <[EMAIL PROTECTED]>

        * gnu/java/awt/peer/gtk/GtkImage.java (setDimensions,
        setProperties): Check that io is not null before calling
        io.imageUpdate.
        * java/awt/image/ImageConsumer.java (setPixels, imageComplete):
        Update javadocs.
        * java/awt/image/PixelGrabber.java: Fix implementation and
        update javadocs.

Index: gnu/java/awt/peer/gtk/GtkImage.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkImage.java,v
retrieving revision 1.3
diff -u -r1.3 GtkImage.java
--- gnu/java/awt/peer/gtk/GtkImage.java	12 Nov 2003 00:37:33 -0000	1.3
+++ gnu/java/awt/peer/gtk/GtkImage.java	25 Nov 2003 03:59:01 -0000
@@ -1,5 +1,5 @@
 /* GtkImage.java
-   Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -168,13 +168,15 @@
     for (int i = 0; i < widthObservers.size (); i++)
       {
 	ImageObserver io = (ImageObserver) widthObservers.elementAt (i);
-	io.imageUpdate (this, ImageObserver.WIDTH, -1, -1, width, height);
+	if (io != null)
+	  io.imageUpdate (this, ImageObserver.WIDTH, -1, -1, width, height);
       }
 
     for (int i = 0; i < heightObservers.size (); i++)
       {
 	ImageObserver io = (ImageObserver) heightObservers.elementAt (i);
-	io.imageUpdate (this, ImageObserver.HEIGHT, -1, -1, width, height);
+	if (io != null)
+	  io.imageUpdate (this, ImageObserver.HEIGHT, -1, -1, width, height);
       }
 
     if (observer != null)
@@ -192,7 +194,8 @@
     for (int i = 0; i < propertyObservers.size (); i++)
       {
 	ImageObserver io = (ImageObserver) propertyObservers.elementAt (i);
-	io.imageUpdate (this, ImageObserver.PROPERTIES, -1, -1, width, height);
+	if (io != null)
+	  io.imageUpdate (this, ImageObserver.PROPERTIES, -1, -1, width, height);
       }
   }
 
Index: java/awt/image/ImageConsumer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/image/ImageConsumer.java,v
retrieving revision 1.6
diff -u -r1.6 ImageConsumer.java
--- java/awt/image/ImageConsumer.java	11 Oct 2003 17:19:46 -0000	1.6
+++ java/awt/image/ImageConsumer.java	25 Nov 2003 03:59:01 -0000
@@ -1,5 +1,5 @@
 /* ImageConsumer.java -- Java interface for image consumption
-   Copyright (C) 1999 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -160,17 +160,45 @@
     void setHints(int flags);
 
     /**
-     * This function delivers a rectangle of pixels where any
-     * pixel(m,n) is stored in the array as a <code>byte</code> at
-     * index (n * scansize + m + offset).  
+     * Deliver a subset of an ImageProducer's pixels to this ImageConsumer.
+     *
+     * Each element of the pixels array represents one pixel.  The
+     * pixel data is formatted according to the color model model.
+     * The x and y parameters are the coordinates of the block of
+     * pixels being delivered to this ImageConsumer.  They are
+     * specified relative to the top left corner of the image being
+     * produced.  Likewise, w and h are the pixel block's dimensions.
+     *
+     * @param x x coordinate of pixel block
+     * @param y y coordinate of pixel block
+     * @param w width of pixel block
+     * @param h height of pixel block
+     * @param model color model used to interpret pixel data
+     * @param pixels pixel block data
+     * @param offset offset into pixels array
+     * @param scansize width of one row in the pixel block
      */
     void setPixels(int x, int y, int w, int h, 
 	   ColorModel model, byte[] pixels, int offset, int scansize);
 
     /**
-     * This function delivers a rectangle of pixels where any
-     * pixel(m,n) is stored in the array as an <code>int</code> at
-     * index (n * scansize + m + offset).  
+     * Deliver a subset of an ImageProducer's pixels to this ImageConsumer.
+     *
+     * Each element of the pixels array represents one pixel.  The
+     * pixel data is formatted according to the color model model.
+     * The x and y parameters are the coordinates of the rectangular
+     * region of pixels being delivered to this ImageConsumer,
+     * specified relative to the top left corner of the image being
+     * produced.  Likewise, w and h are the pixel region's dimensions.
+     *
+     * @param x x coordinate of pixel block
+     * @param y y coordinate of pixel block
+     * @param w width of pixel block
+     * @param h height of pixel block
+     * @param model color model used to interpret pixel data
+     * @param pixels pixel block data
+     * @param offset offset into pixels array
+     * @param scansize width of one row in the pixel block
      */
     void setPixels(int x, int y, int w, int h, 
            ColorModel model, int[] pixels, int offset, int scansize);
@@ -180,7 +208,9 @@
      * single frame or the entire image is complete.  The method is
      * also used to indicate an error in loading or producing the
      * image.  
+     *
+     * @param status the status of image production, represented by a
+     * bitwise OR of ImageConsumer flags
      */
     void imageComplete(int status);
 }
-
Index: java/awt/image/PixelGrabber.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/image/PixelGrabber.java,v
retrieving revision 1.4
diff -u -r1.4 PixelGrabber.java
--- java/awt/image/PixelGrabber.java	27 Jun 2003 20:53:01 -0000	1.4
+++ java/awt/image/PixelGrabber.java	25 Nov 2003 03:59:01 -0000
@@ -1,39 +1,39 @@
-/* PixelGrabber.java -- Java class for providing image data 
-   Copyright (C) 1999 Free Software Foundation, Inc.
+/* PixelGrabber.java -- retrieve a subset of an image's data
+   Copyright (C) 1999, 2003 Free Software Foundation, Inc.
 
-This file is part of GNU Classpath.
+   This file is part of GNU Classpath.
 
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING.  If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library.  Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module.  An independent module is a module which is not derived from
-or based on this library.  If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so.  If you do not wish to do so, delete this
-exception statement from your version. */
+   GNU Classpath is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Classpath is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Classpath; see the file COPYING.  If not, write to the
+   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.
+
+   Linking this library statically or dynamically with other modules is
+   making a combined work based on this library.  Thus, the terms and
+   conditions of the GNU General Public License cover the whole
+   combination.
+
+   As a special exception, the copyright holders of this library give you
+   permission to link this library with independent modules to produce an
+   executable, regardless of the license terms of these independent
+   modules, and to copy and distribute the resulting executable under
+   terms of your choice, provided that you also meet, for each linked
+   independent module, the terms and conditions of the license of that
+   module.  An independent module is a module which is not derived from
+   or based on this library.  If you modify this library, you may extend
+   this exception to your version of the library, but you are not
+   obligated to do so.  If you do not wish to do so, delete this
+   exception statement from your version. */
 
 
 package java.awt.image;
@@ -42,309 +42,583 @@
 import java.util.Hashtable;
 
 /**
-   PixelGrabber is an ImageConsumer designed to extract a rectangular region of pixels
-   from an Image
+ * PixelGrabber is an ImageConsumer that extracts a rectangular region
+ * of pixels from an Image.
  */
-public class PixelGrabber implements ImageConsumer 
+public class PixelGrabber implements ImageConsumer
 {
-    int x, y, width, height, status, scansize, offset;
-    ColorModel model = ColorModel.getRGBdefault();
-    //int hints;
-    //Hashtable props;
-    int pixel_bufferi[];
-    byte pixel_bufferb[];
-    boolean grabbing;
-    ImageProducer ip;
-
-    /**
-     * Create a PixelGrabber used to grab pixels from the specified Image 
-     * in the specified rectangle
-     *
-     * @param img the Image to grab pixels from
-     * @param x the x coordinate of the rectangle
-     * @param y the y coordinate of the rectangle
-     * @param w the width of the rectangle
-     * @param h the height of the rectangle
-     * @param pixels the array of pixel values
-     * @param offset the index of the first pixels in the <code>pixels</code> array
-     * @param scansize the width to use in extracting pixels from the <code>pixels</code> array
-     */
-    public PixelGrabber(Image img, int x, int y, int w, int h,
-			int pix[], int off, int scansize)
-    {
-	this( img.getSource(), x, y, w, h, pix, off, scansize );
-    }
-
-    /**
-     * Create a PixelGrabber used to grab pixels from the specified ImageProducer
-     * in the specified rectangle
-     *
-     * @param ip the ImageProducer to grab pixels from
-     * @param x the x coordinate of the rectangle
-     * @param y the y coordinate of the rectangle
-     * @param w the width of the rectangle
-     * @param h the height of the rectangle
-     * @param pixels the array of pixel values
-     * @param offset the index of the first pixels in the <code>pixels</code> array
-     * @param scansize the width to use in extracting pixels from the <code>pixels</code> array
-     */
-    public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
-			int pix[], int off, int scansize)
-    {
-	this.ip = ip;
-	this.x = x;
-	this.y = y;
-	this.width = w;
-	this.height = h;
-	this.pixel_bufferi = pix;
-	this.offset = off;
-	this.scansize = scansize;
-	pixel_bufferb = new byte[pix.length * 4];
-    }
-
-
-    /**
-     * Create a PixelGrabber used to grab pixels from the specified Image 
-     * in the specified rectangle
-     *
-     * @param img the Image to grab pixels from
-     * @param x the x coordinate of the rectangle
-     * @param y the y coordinate of the rectangle
-     * @param w the width of the rectangle
-     * @param h the height of the rectangle
-     * @param forceRGB true to force conversion to RGB
-     */
-    public PixelGrabber(Image img,
-			int x, int y,
-			int w, int h,
-			boolean forceRGB)
-    {
-	//FIXME
-    }
-
-    /**
-       Start Grabbing Pixels
-     */
-    public synchronized void startGrabbing()
-    {
-	if ( grabbing == false )
+  int x, y, offset;
+  int width = -1;
+  int height = -1;
+  int scansize = -1;
+  boolean forceRGB = true;
+
+  ColorModel model = ColorModel.getRGBdefault();
+  int hints;
+  Hashtable props;
+
+  int int_pixel_buffer[];
+  boolean ints_delivered = false;
+  byte byte_pixel_buffer[];
+  boolean bytes_delivered = false;
+
+  ImageProducer ip;
+  int observerStatus;
+  int consumerStatus;
+
+  private Thread grabberThread;
+  boolean grabbing = false;
+
+  /**
+   * Construct a PixelGrabber that will retrieve RGB data from a given
+   * Image.
+   *
+   * The RGB data will be retrieved from a rectangular region
+   * <code>(x, y, w, h)</code> within the image.  The data will be
+   * stored in the provided <code>pix</code> array, which must have
+   * been initialized to a size of at least <code>w * h</code>.  The
+   * data for a pixel (m, n) in the grab rectangle will be stored at
+   * <code>pix[(n - y) * scansize + (m - x) + off]</code>.
+   *
+   * @param img the Image from which to grab pixels
+   * @param x the x coordinate, relative to <code>img</code>'s
+   * top-left corner, of the grab rectangle's top-left pixel
+   * @param y the y coordinate, relative to <code>img</code>'s
+   * top-left corner, of the grab rectangle's top-left pixel
+   * @param w the width of the grab rectangle, in pixels
+   * @param h the height of the grab rectangle, in pixels
+   * @param pix the array in which to store grabbed RGB pixel data
+   * @param off the offset into the <code>pix</code> array at which to
+   * start storing RGB data
+   * @param scansize a set of <code>scansize</code> consecutive
+   * elements in the <code>pix</code> array represents one row of
+   * pixels in the grab rectangle
+   */
+  public PixelGrabber(Image img, int x, int y, int w, int h,
+		      int pix[], int off, int scansize)
+  {
+    this (img.getSource(), x, y, w, h, pix, off, scansize);
+  }
+
+  /**
+   * Construct a PixelGrabber that will retrieve RGB data from a given
+   * ImageProducer.
+   *
+   * The RGB data will be retrieved from a rectangular region
+   * <code>(x, y, w, h)</code> within the image produced by
+   * <code>ip</code>.  The data will be stored in the provided
+   * <code>pix</code> array, which must have been initialized to a
+   * size of at least <code>w * h</code>.  The data for a pixel (m, n)
+   * in the grab rectangle will be stored at
+   * <code>pix[(n - y) * scansize + (m - x) + off]</code>.
+   *
+   * @param ip the ImageProducer from which to grab pixels
+   * @param x the x coordinate of the grab rectangle's top-left pixel,
+   * specified relative to the top-left corner of the image produced
+   * by <code>ip</code>
+   * @param y the y coordinate of the grab rectangle's top-left pixel,
+   * specified relative to the top-left corner of the image produced
+   * by <code>ip</code>
+   * @param w the width of the grab rectangle, in pixels
+   * @param h the height of the grab rectangle, in pixels
+   * @param pix the array in which to store grabbed RGB pixel data
+   * @param off the offset into the <code>pix</code> array at which to
+   * start storing RGB data
+   * @param scansize a set of <code>scansize</code> consecutive
+   * elements in the <code>pix</code> array represents one row of
+   * pixels in the grab rectangle
+   */
+  public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
+		      int pix[], int off, int scansize)
+  {
+    this.ip = ip;
+    this.x = x;
+    this.y = y;
+    this.width = w;
+    this.height = h;
+    this.offset = off;
+    this.scansize = scansize;
+
+    int_pixel_buffer = pix;
+    // Initialize the byte array in case ip sends us byte-formatted
+    // pixel data.
+    byte_pixel_buffer = new byte[pix.length * 4];
+  }
+
+  /**
+   * Construct a PixelGrabber that will retrieve data from a given
+   * Image.
+   *
+   * The RGB data will be retrieved from a rectangular region
+   * <code>(x, y, w, h)</code> within the image.  The data will be
+   * stored in an internal array which can be accessed by calling
+   * <code>getPixels</code>.  The data for a pixel (m, n) in the grab
+   * rectangle will be stored in the returned array at index
+   * <code>(n - y) * scansize + (m - x) + off</code>.
+   * If forceRGB is false, then the returned data will be not be
+   * converted to RGB from its format in <code>img</code>.
+   *
+   * If <code>w</code> is negative, the width of the grab region will
+   * be from x to the right edge of the image.  Likewise, if
+   * <code>h</code> is negative, the height of the grab region will be
+   * from y to the bottom edge of the image.
+   *
+   * @param img the Image from which to grab pixels
+   * @param x the x coordinate, relative to <code>img</code>'s
+   * top-left corner, of the grab rectangle's top-left pixel
+   * @param y the y coordinate, relative to <code>img</code>'s
+   * top-left corner, of the grab rectangle's top-left pixel
+   * @param w the width of the grab rectangle, in pixels
+   * @param h the height of the grab rectangle, in pixels
+   * @param forceRGB true to force conversion of the rectangular
+   * region's pixel data to RGB
+   */
+  public PixelGrabber(Image img,
+		      int x, int y,
+		      int w, int h,
+		      boolean forceRGB)
+  {
+    this.ip = img.getSource();
+    this.x = x;
+    this.y = y;
+    width = w;
+    height = h;
+    // If width or height is negative, postpone pixel buffer
+    // initialization until setDimensions is called back by ip.
+    if (width >= 0 && height >= 0)
+      {
+	int_pixel_buffer = new int[width * height];
+	byte_pixel_buffer = new byte[width * height];
+      }
+    this.forceRGB = forceRGB;
+  }
+
+  /**
+   * Start grabbing pixels.
+   *
+   * Spawns an image production thread that calls back to this
+   * PixelGrabber's ImageConsumer methods.
+   */
+  public synchronized void startGrabbing()
+  {
+    // Make sure we're not already grabbing.
+    if (grabbing == false)
+      {
+	grabbing = true;
+	grabberThread = new Thread ()
+	  {
+	    public void run ()
 	    {
-		grabbing = true;
-		ip.startProduction( this );
+	      ip.startProduction (PixelGrabber.this);
 	    }
-    }
-
-    /**
-       Abort the grabbing of pixels
-     */
-    public synchronized void abortGrabbing()
-    {
-	if ( grabbing == true )
-	    {
-		grabbing = false;
-		ip.removeConsumer( this );
-	    }
-    }
-
-    /**
-       Grab the Pixels.
-
-       @return true if successful
-
-       @throws InterruptedException if interrupted by another thread.
-     */
-    public boolean grabPixels() throws InterruptedException
-    {
-      return grabPixels(0);
-    }
-
-    /**
-       Grab the Pixels and abort if it takes too long
-
-       @return true if successful
-
-       @throws InterruptedException if interrupted by another thread.
-               or time runs out
-     */
-    public synchronized boolean grabPixels(long ms) throws InterruptedException
-    {
-	startGrabbing();
-	
-	if (ms < 0)
-	  return (status == ImageObserver.ALLBITS);
-	
-	wait(ms);
-	
-	if (status == ImageObserver.ALLBITS)
-	    return true;
-	else
-	    return false;
-    }
-
-    /**
-       Get the status of the pixel grabbing representing by ImageObserver flags
-
-       @return the status
-    */
-    public synchronized int getStatus()
-    {
-	return status;
-    }
-
-    /**
-       Return width of pixel region
-
-       @return width of region
-    */
-    public synchronized int getWidth()
-    {
-	return width;
-    }
-
-    /**
-       Return height of pixel region
-       
-       @return height of region
-    */
-    public synchronized int getHeight()
-    {
-	return height;
-    }
-
-    /**
-       Returns the grabbed pixel buffer 
-
-       @return a byte or int array
-    */
-    public synchronized Object getPixels()
-    {
-	if( pixel_bufferi != null )
-	    return pixel_bufferi;
-	return pixel_bufferb;
-    }
-
-    /**
-       Get the ColorModel of the image
-       
-       @return the ColorModel
-    */
-    public synchronized ColorModel getColorModel()
-    {
-	return model;
-    }
-
-    /**
-     * An <code>ImageProducer</code> indicates the size of the image
-     * being produced using this method.
-     * 
-     * @param width the width of the image
-     * @param height the height of the image 
-     */
-    public  void setDimensions(int width, int height)
-    {
-    }
-
-    /**
-     * An <code>ImageProducer</code> can set a list of properties
-     * associated with this image by using this method.
-     *
-     * @param props the list of properties associated with this image 
-     */
-    public  void setProperties(Hashtable props)
-    {
-	//this.props = props; //FIXME - DO WE NEED THIS
-    }
-
-    /**
-     * This <code>ColorModel</code> should indicate the model used by
-     * the majority of calls to <code>setPixels</code>.  Each call to
-     * <code>setPixels</code> could however indicate a different
-     * <code>ColorModel</code>.
-     *
-     * @param model the color model to be used most often by setPixels
-     * @see ColorModel 
-     */
-    public  void setColorModel(ColorModel model)
-    {
-	this.model = model;
-    }
-
-    /**
-     * The <code>ImageProducer</code> should call this method with a
-     * bit mask of hints from any of <code>RANDOMPIXELORDER</code>,
-     * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>,
-     * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code>.
-     * 
-     * @param flags a bit mask of hints
-     */
-    public  void setHints(int flags)
-    {
-	//hints = flags; // FIXME - DO NOT KNOW WHAT TO DO WITH THE HINTS
-    }
-
-    /**
-     * This function delivers a rectangle of pixels where any
-     * pixel(m,n) is stored in the array as a <code>byte</code> at
-     * index (n * scansize + m + offset).  
-     */
-    public  void setPixels(int x, int y, int w, int h, 
-			   ColorModel model, byte[] pixels, int offset, int scansize)
-    {
-	//FIXME - I hate bytes
-	int xp, yp;
-	for( xp = x; xp < ( x + w); xp++ )
-	    for( yp = y; yp < (y + h); yp++ )
-		if( xp >= this.x && 
-		    yp >= this.y && 
-		    xp <= ( this.x + this.width ) && 
-		    yp <= ( this.y + this.height ) ) {
-		    pixel_bufferb[(yp - this.y) * this.scansize + (xp - this.x) + this.offset] =
-			pixels[ offset + yp * scansize + xp ];
-		}
-
-    }
-
-    /**
-     * This function delivers a rectangle of pixels where any
-     * pixel(m,n) is stored in the array as an <code>int</code> at
-     * index (n * scansize + m + offset).  
-     */
-    public  void setPixels(int x, int y, int w, int h, 
-			   ColorModel model, int[] pixels, int offset, int scansize)
-    {
-	int xp, yp;
-	for( xp = x; xp < ( x + w); xp++ )
-	    for( yp = y; yp < (y + h); yp++ )
-		if( xp >= this.x && 
-		    yp >= this.y && 
-		    xp <= ( this.x + this.width ) && 
-		    yp <= ( this.y + this.height ) ) {
-		    pixel_bufferi[(yp - this.y) * this.scansize + (xp - this.x) + this.offset] =
-			pixels[ offset + yp * scansize + xp ];
-		}
-    }
-
-    /**
-     * The <code>ImageProducer</code> calls this method to indicate a
-     * single frame or the entire image is complete.  The method is
-     * also used to indicate an error in loading or producing the
-     * image.  
-     */
-    public synchronized void imageComplete(int status)
-    {
-	this.status = status;
-    }
-
-    /**
-       Get the status of the pixel grabbing representing by ImageObserver flags
-
-       @return the status
-       
-       @specnote This method is not deprecated but getStatus is preferred to use
-     */
-    public synchronized int status()
-    {
-	return getStatus();
-    }
-
+	  };
+	grabberThread.start ();
+      }
+  }
+
+  /**
+   * Abort pixel grabbing.
+   */
+  public synchronized void abortGrabbing()
+  {
+    if (grabbing)
+      {
+	// Interrupt the grabbing thread.
+        Thread moribund = grabberThread;
+        grabberThread = null;
+        moribund.interrupt();
+
+	imageComplete (ImageConsumer.IMAGEABORTED);
+      }
+  }
+
+  /**
+   * Have our Image or ImageProducer start sending us pixels via our
+   * ImageConsumer methods and wait for all pixels in the grab
+   * rectangle to be delivered.
+   *
+   * @return true if successful, false on abort or error
+   *
+   * @throws InterruptedException if interrupted by another thread.
+   */
+  public synchronized boolean grabPixels() throws InterruptedException
+  {
+    return grabPixels(0);
+  }
+
+  /**
+   * grabPixels's behavior depends on the value of <code>ms</code>.
+   *
+   * If ms < 0, return true if all pixels from the source image have
+   * been delivered, false otherwise.  Do not wait.
+   *
+   * If ms >= 0 then we request that our Image or ImageProducer start
+   * delivering pixels to us via our ImageConsumer methods.
+   *
+   * If ms > 0, wait at most <code>ms</code> milliseconds for
+   * delivery of all pixels within the grab rectangle.
+   *
+   * If ms == 0, wait until all pixels have been delivered.
+   *
+   * @return true if all pixels from the source image have been
+   * delivered, false otherwise
+   *
+   * @throws InterruptedException if this thread is interrupted while
+   * we are waiting for pixels to be delivered
+   */
+  public synchronized boolean grabPixels(long ms) throws InterruptedException
+  {
+    if (ms < 0)
+      return ((observerStatus & (ImageObserver.FRAMEBITS
+				 | ImageObserver.ALLBITS)) != 0);
+
+    // Spawn a new ImageProducer thread to send us the image data via
+    // our ImageConsumer methods.
+    startGrabbing();
+
+    if (ms > 0)
+      {
+	long stop_time = System.currentTimeMillis() + ms;
+	long time_remaining;
+	while (grabbing)
+	  {
+	    time_remaining = stop_time - System.currentTimeMillis();
+	    if (time_remaining <= 0)
+	      break;
+	    wait (time_remaining);
+	  }
+	abortGrabbing ();
+      }
+    else
+      wait ();
+
+    // If consumerStatus is non-zero then the image is done loading or
+    // an error has occurred.
+    if (consumerStatus != 0)
+      return setObserverStatus ();
+
+    return ((observerStatus & (ImageObserver.FRAMEBITS
+			       | ImageObserver.ALLBITS)) != 0);
+  }
+
+  // Set observer status flags based on the current consumer status
+  // flags.  Return true if the consumer flags indicate that the
+  // image was loaded successfully, or false otherwise.
+  private synchronized boolean setObserverStatus ()
+  {
+    boolean retval = false;
+
+    if ((consumerStatus & IMAGEERROR) != 0)
+      observerStatus |= ImageObserver.ERROR;
+
+    if ((consumerStatus & IMAGEABORTED) != 0)
+      observerStatus |= ImageObserver.ABORT;
+
+    if ((consumerStatus & STATICIMAGEDONE) != 0)
+      {
+	observerStatus |= ImageObserver.ALLBITS;
+	retval = true;
+      }
+
+    if ((consumerStatus & SINGLEFRAMEDONE) != 0)
+      {
+	observerStatus |= ImageObserver.FRAMEBITS;
+	retval = true;
+      }
+
+    return retval;
+  }
+
+  /**
+   * @return the status of the pixel grabbing thread, represented by a
+   * bitwise OR of ImageObserver flags
+   */
+  public synchronized int getStatus()
+  {
+    return observerStatus;
+  }
+
+  /**
+   * @return the width of the grab rectangle in pixels, or a negative
+   * number if the ImageProducer has not yet called our setDimensions
+   * method
+   */
+  public synchronized int getWidth()
+  {
+    return width;
+  }
+
+  /**
+   * @return the height of the grab rectangle in pixels, or a negative
+   * number if the ImageProducer has not yet called our setDimensions
+   * method
+   */
+  public synchronized int getHeight()
+  {
+    return height;
+  }
+
+  /**
+   * @return a byte array of pixel data if ImageProducer delivered
+   * pixel data using the byte[] variant of setPixels, or an int array
+   * otherwise
+   */
+  public synchronized Object getPixels()
+  {
+    if (ints_delivered)
+      return int_pixel_buffer;
+    else if (bytes_delivered)
+      return byte_pixel_buffer;
+    else
+      return null;
+  }
+
+  /**
+   * @return the ColorModel currently being used for the majority of
+   * pixel data conversions
+   */
+  public synchronized ColorModel getColorModel()
+  {
+    return model;
+  }
+
+  /**
+   * Our <code>ImageProducer</code> calls this method to indicate the
+   * size of the image being produced.
+   *
+   * setDimensions is an ImageConsumer method.  None of PixelGrabber's
+   * ImageConsumer methods should be called by code that instantiates
+   * a PixelGrabber.  They are only made public so they can be called
+   * by the PixelGrabber's ImageProducer.
+   * 
+   * @param width the width of the image
+   * @param height the height of the image
+   */
+  public synchronized void setDimensions(int width, int height)
+  {
+    // Our width wasn't set when we were constructed.  Set our width
+    // so that the grab region includes all pixels from x to the right
+    // edge of the source image.
+    if (this.width < 0)
+      this.width = width - x;
+
+    // Our height wasn't set when we were constructed.  Set our height
+    // so that the grab region includes all pixels from y to the
+    // bottom edge of the source image.
+    if (this.height < 0)
+      this.height = height - y;
+
+    if (scansize < 0)
+      scansize = this.width;
+
+    if (int_pixel_buffer == null)
+      int_pixel_buffer = new int[this.width * this.height];
+
+    if (byte_pixel_buffer == null)
+      byte_pixel_buffer = new byte[this.width * this.height];
+  }
+
+  /**
+   * Our <code>ImageProducer</code> may call this method to send us a
+   * list of its image's properties.
+   *
+   * setProperties is an ImageConsumer method.  None of PixelGrabber's
+   * ImageConsumer methods should be called by code that instantiates
+   * a PixelGrabber.  They are only made public so they can be called
+   * by the PixelGrabber's ImageProducer.
+   *
+   * @param props a list of properties associated with the image being
+   * produced
+   */
+  public synchronized void setProperties(Hashtable props)
+  {
+    this.props = props;
+  }
+
+  /**
+   * Our ImageProducer will call <code>setColorModel</code> to
+   * indicate the model used by the majority of calls to
+   * <code>setPixels</code>.  Each call to <code>setPixels</code>
+   * could however indicate a different <code>ColorModel</code>.
+   *
+   * setColorModel is an ImageConsumer method.  None of PixelGrabber's
+   * ImageConsumer methods should be called by code that instantiates
+   * a PixelGrabber.  They are only made public so they can be called
+   * by the PixelGrabber's ImageProducer.
+   *
+   * @param model the color model to be used most often by setPixels
+   *
+   * @see ColorModel
+   */
+  public synchronized void setColorModel(ColorModel model)
+  {
+    this.model = model;
+  }
+
+  /**
+   * Our <code>ImageProducer</code> may call this method with a
+   * bit mask of hints from any of <code>RANDOMPIXELORDER</code>,
+   * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>,
+   * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code>.
+   * 
+   * setHints is an ImageConsumer method.  None of PixelGrabber's
+   * ImageConsumer methods should be called by code that instantiates
+   * a PixelGrabber.  They are only made public so they can be called
+   * by the PixelGrabber's ImageProducer.
+   *
+   * @param flags a bit mask of hints
+   */
+  public synchronized void setHints(int flags)
+  {
+    hints = flags;
+  }
+
+  /**
+   * Our ImageProducer calls setPixels to deliver a subset of its
+   * pixels.
+   *
+   * Each element of the pixels array represents one pixel.  The
+   * pixel data is formatted according to the color model model.
+   * The x and y parameters are the coordinates of the rectangular
+   * region of pixels being delivered to this ImageConsumer,
+   * specified relative to the top left corner of the image being
+   * produced.  Likewise, w and h are the pixel region's dimensions.
+   *
+   * @param x x coordinate of pixel block
+   * @param y y coordinate of pixel block
+   * @param w width of pixel block
+   * @param h height of pixel block
+   * @param model color model used to interpret pixel data
+   * @param pixels pixel block data
+   * @param offset offset into pixels array
+   * @param scansize width of one row in the pixel block
+   */
+  public synchronized void setPixels(int x, int y, int w, int h, 
+				     ColorModel model, byte[] pixels,
+				     int offset, int scansize)
+  {
+    ColorModel currentModel;
+    if (model != null)
+      currentModel = model;
+    else
+      currentModel = this.model;
+
+    for(int yp = y; yp < (y + h); yp++)
+      {
+	for(int xp = x; xp < (x + w); xp++)
+	  {
+	    // Check if the coordinates (xp, yp) are within the
+	    // pixel block that we are grabbing.
+	    if(xp >= this.x
+	       && yp >= this.y
+	       && xp < (this.x + this.width)
+	       && yp < (this.y + this.height))
+	      {
+		int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset;
+		int p = (yp - y) * scansize + (xp - x) + offset;
+		if (forceRGB)
+		  {
+		    ints_delivered = true;
+
+		    assert (i >= 0 && i < int_pixel_buffer.length);
+		    assert (p >= 0 && p < pixels.length);
+		    int_pixel_buffer[i] = currentModel.getRGB (pixels[p]);
+		  }
+		else
+		  {
+		    bytes_delivered = true;
+
+		    assert (i >= 0 && i < byte_pixel_buffer.length);
+		    assert (p >= 0 && p < pixels.length);
+		    byte_pixel_buffer[i] = pixels[p];
+		  }
+	      }
+	  }
+      }
+  }
+
+  /**
+   * Our ImageProducer calls setPixels to deliver a subset of its
+   * pixels.
+   *
+   * Each element of the pixels array represents one pixel.  The
+   * pixel data is formatted according to the color model model.
+   * The x and y parameters are the coordinates of the rectangular
+   * region of pixels being delivered to this ImageConsumer,
+   * specified relative to the top left corner of the image being
+   * produced.  Likewise, w and h are the pixel region's dimensions.
+   *
+   * @param x x coordinate of pixel block
+   * @param y y coordinate of pixel block
+   * @param w width of pixel block
+   * @param h height of pixel block
+   * @param model color model used to interpret pixel data
+   * @param pixels pixel block data
+   * @param offset offset into pixels array
+   * @param scansize width of one row in the pixel block
+   */
+  public synchronized void setPixels(int x, int y, int w, int h, 
+				     ColorModel model, int[] pixels,
+				     int offset, int scansize)
+  {
+    ColorModel currentModel;
+    if (model != null)
+      currentModel = model;
+    else
+      currentModel = this.model;
+
+    ints_delivered = true;
+
+    for(int yp = y; yp < (y + h); yp++)
+      {
+	for(int xp = x; xp < (x + w); xp++)
+	  {
+	    // Check if the coordinates (xp, yp) are within the
+	    // pixel block that we are grabbing.
+	    if(xp >= this.x
+	       && yp >= this.y
+	       && xp < (this.x + this.width)
+	       && yp < (this.y + this.height))
+	      {
+		int i = (yp - this.y) * this.scansize + (xp - this.x) + this.offset;
+		int p = (yp - y) * scansize + (xp - x) + offset;
+		assert (i >= 0 && i < int_pixel_buffer.length);
+		assert (p >= 0 && p < pixels.length);
+		if (forceRGB)
+		  int_pixel_buffer[i] = currentModel.getRGB (pixels[p]);
+		else
+		  int_pixel_buffer[i] = pixels[p];
+	      }
+	  }
+      }
+  }
+
+  /**
+   * Our <code>ImageProducer</code> calls this method to inform us
+   * that a single frame or the entire image is complete.  The method
+   * is also used to inform us of an error in loading or producing the
+   * image.
+   *
+   * @param status the status of image production, represented by a
+   * bitwise OR of ImageConsumer flags
+   */
+  public synchronized void imageComplete(int status)
+  {
+    consumerStatus = status;
+    setObserverStatus ();
+    grabbing = false;
+    ip.removeConsumer (this);
+
+    notifyAll ();
+  }
+
+  /**
+   * @return the return value of getStatus
+   *
+   * @specnote The newer getStatus should be used in place of status.
+   */
+  public synchronized int status()
+  {
+    return getStatus();
+  }
 }
// Tags: JDK1.0

/* SimpleGrabber.java
   Copyright (C) 2003 Red Hat, Inc.

   This file is part of Mauve.

   Mauve is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.
 
   Mauve is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with Mauve; see the file COPYING.  If not, write to the Free
   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA. */

package gnu.testlet.java.awt.image.PixelGrabber;

import gnu.testlet.Testlet;
import gnu.testlet.TestHarness;

import java.awt.*;
import java.awt.image.*;

public class SimpleGrabber implements Testlet
{
  TestHarness harness;

  public void test (TestHarness harness)
  {
    this.harness = harness;

    Image i = null;

    try
      {
	String f = "gnu#testlet#java#awt#image#PixelGrabber#lena1.jpg";
	i = Toolkit.getDefaultToolkit().getImage (harness.getResourceFile (f).getAbsolutePath ());
      }
    catch (Exception e)
      {
	harness.fail ("lena1.jpg not found.");
      }

    String str = getPixels (i, 0, 0, 6, 12);

    harness.check (str,
		  "Pixel (0, 0)\n"
		  + "   R: 98 G: 31 B: 82\n"
		  + "Pixel (1, 0)\n"
		  + "   R: 79 G: 12 B: 63\n"
		  + "Pixel (2, 0)\n"
		  + "   R: 76 G: 9 B: 60\n"
		  + "Pixel (3, 0)\n"
		  + "   R: 152 G: 85 B: 136\n"
		  + "Pixel (4, 0)\n"
		  + "   R: 132 G: 66 B: 114\n"
		  + "Pixel (5, 0)\n"
		  + "   R: 95 G: 29 B: 77\n"
		  + "Pixel (0, 1)\n"
		  + "   R: 86 G: 19 B: 70\n"
		  + "Pixel (1, 1)\n"
		  + "   R: 75 G: 8 B: 59\n"
		  + "Pixel (2, 1)\n"
		  + "   R: 81 G: 14 B: 65\n"
		  + "Pixel (3, 1)\n"
		  + "   R: 150 G: 83 B: 134\n"
		  + "Pixel (4, 1)\n"
		  + "   R: 121 G: 55 B: 103\n"
		  + "Pixel (5, 1)\n"
		  + "   R: 85 G: 19 B: 67\n"
		  + "Pixel (0, 2)\n"
		  + "   R: 75 G: 11 B: 61\n"
		  + "Pixel (1, 2)\n"
		  + "   R: 79 G: 15 B: 65\n"
		  + "Pixel (2, 2)\n"
		  + "   R: 100 G: 36 B: 86\n"
		  + "Pixel (3, 2)\n"
		  + "   R: 155 G: 91 B: 141\n"
		  + "Pixel (4, 2)\n"
		  + "   R: 115 G: 52 B: 99\n"
		  + "Pixel (5, 2)\n"
		  + "   R: 76 G: 13 B: 60\n"
		  + "Pixel (0, 3)\n"
		  + "   R: 70 G: 8 B: 57\n"
		  + "Pixel (1, 3)\n"
		  + "   R: 91 G: 29 B: 78\n"
		  + "Pixel (2, 3)\n"
		  + "   R: 122 G: 60 B: 109\n"
		  + "Pixel (3, 3)\n"
		  + "   R: 162 G: 100 B: 149\n"
		  + "Pixel (4, 3)\n"
		  + "   R: 116 G: 53 B: 100\n"
		  + "Pixel (5, 3)\n"
		  + "   R: 69 G: 6 B: 53\n"
		  + "Pixel (0, 4)\n"
		  + "   R: 72 G: 13 B: 61\n"
		  + "Pixel (1, 4)\n"
		  + "   R: 102 G: 43 B: 91\n"
		  + "Pixel (2, 4)\n"
		  + "   R: 128 G: 69 B: 117\n"
		  + "Pixel (3, 4)\n"
		  + "   R: 154 G: 95 B: 143\n"
		  + "Pixel (4, 4)\n"
		  + "   R: 120 G: 58 B: 105\n"
		  + "Pixel (5, 4)\n"
		  + "   R: 64 G: 2 B: 49\n"
		  + "Pixel (0, 5)\n"
		  + "   R: 95 G: 36 B: 84\n"
		  + "Pixel (1, 5)\n"
		  + "   R: 117 G: 58 B: 106\n"
		  + "Pixel (2, 5)\n"
		  + "   R: 119 G: 60 B: 108\n"
		  + "Pixel (3, 5)\n"
		  + "   R: 136 G: 77 B: 125\n"
		  + "Pixel (4, 5)\n"
		  + "   R: 133 G: 74 B: 120\n"
		  + "Pixel (5, 5)\n"
		  + "   R: 73 G: 14 B: 60\n"
		  + "Pixel (0, 6)\n"
		  + "   R: 123 G: 65 B: 113\n"
		  + "Pixel (1, 6)\n"
		  + "   R: 125 G: 67 B: 115\n"
		  + "Pixel (2, 6)\n"
		  + "   R: 93 G: 35 B: 83\n"
		  + "Pixel (3, 6)\n"
		  + "   R: 106 G: 48 B: 96\n"
		  + "Pixel (4, 6)\n"
		  + "   R: 146 G: 89 B: 134\n"
		  + "Pixel (5, 6)\n"
		  + "   R: 88 G: 31 B: 76\n"
		  + "Pixel (0, 7)\n"
		  + "   R: 137 G: 79 B: 127\n"
		  + "Pixel (1, 7)\n"
		  + "   R: 123 G: 65 B: 113\n"
		  + "Pixel (2, 7)\n"
		  + "   R: 65 G: 7 B: 55\n"
		  + "Pixel (3, 7)\n"
		  + "   R: 78 G: 20 B: 68\n"
		  + "Pixel (4, 7)\n"
		  + "   R: 149 G: 92 B: 137\n"
		  + "Pixel (5, 7)\n"
		  + "   R: 95 G: 38 B: 83\n"
		  + "Pixel (0, 8)\n"
		  + "   R: 138 G: 80 B: 128\n"
		  + "Pixel (1, 8)\n"
		  + "   R: 96 G: 38 B: 86\n"
		  + "Pixel (2, 8)\n"
		  + "   R: 78 G: 20 B: 68\n"
		  + "Pixel (3, 8)\n"
		  + "   R: 76 G: 18 B: 66\n"
		  + "Pixel (4, 8)\n"
		  + "   R: 106 G: 49 B: 94\n"
		  + "Pixel (5, 8)\n"
		  + "   R: 122 G: 65 B: 110\n"
		  + "Pixel (0, 9)\n"
		  + "   R: 155 G: 97 B: 145\n"
		  + "Pixel (1, 9)\n"
		  + "   R: 99 G: 41 B: 89\n"
		  + "Pixel (2, 9)\n"
		  + "   R: 73 G: 15 B: 63\n"
		  + "Pixel (3, 9)\n"
		  + "   R: 80 G: 22 B: 70\n"
		  + "Pixel (4, 9)\n"
		  + "   R: 115 G: 58 B: 103\n"
		  + "Pixel (5, 9)\n"
		  + "   R: 107 G: 50 B: 95\n"
		  + "Pixel (0, 10)\n"
		  + "   R: 165 G: 106 B: 154\n"
		  + "Pixel (1, 10)\n"
		  + "   R: 99 G: 40 B: 88\n"
		  + "Pixel (2, 10)\n"
		  + "   R: 68 G: 9 B: 57\n"
		  + "Pixel (3, 10)\n"
		  + "   R: 83 G: 24 B: 72\n"
		  + "Pixel (4, 10)\n"
		  + "   R: 123 G: 64 B: 110\n"
		  + "Pixel (5, 10)\n"
		  + "   R: 88 G: 29 B: 75\n"
		  + "Pixel (0, 11)\n"
		  + "   R: 151 G: 92 B: 140\n"
		  + "Pixel (1, 11)\n"
		  + "   R: 93 G: 34 B: 82\n"
		  + "Pixel (2, 11)\n"
		  + "   R: 68 G: 9 B: 57\n"
		  + "Pixel (3, 11)\n"
		  + "   R: 81 G: 22 B: 70\n"
		  + "Pixel (4, 11)\n"
		  + "   R: 120 G: 58 B: 105\n"
		  + "Pixel (5, 11)\n"
		  + "   R: 74 G: 12 B: 59\n");
  }

  // Test eight-parameter constructor.
  public String getPixels(Image img, int x, int y, int w, int h)
  {
    int[] pix = new int[w * h];

    PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pix, 0, w);
    try
      {
	pg.grabPixels(5000);
      }
    catch (InterruptedException e)
      {
	harness.fail ("image production interrupted.");
	return "";
      }

    if ((pg.getStatus() & ImageObserver.ABORT) != 0)
      {
	harness.fail ("image production aborted.");
	return "";
      }

    String result = "";
    for (int j = 0; j < h; j++)
      {
	for (int i = 0; i < w; i++)
	  {
	    int p = j * w + i;
	    result = result + getPixel (x + i, y + j, pix[p]);
	  }
      }
    return result;
  }

  public String getPixel (int x, int y, int pixel)
  {
    ColorModel model = ColorModel.getRGBdefault();

    return "Pixel (" + x + ", " + y + ")\n  "
      + " R: " + model.getRed (pixel)
      + " G: " + model.getGreen (pixel)
      + " B: " + model.getBlue (pixel) + "\n";
  }
}
_______________________________________________
Classpath mailing list
[EMAIL PROTECTED]
http://mail.gnu.org/mailman/listinfo/classpath

Reply via email to