1 /*
   2  * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.image;
  27 
  28 import java.util.Hashtable;
  29 import java.awt.image.ImageProducer;
  30 import java.awt.image.ImageConsumer;
  31 import java.awt.image.ColorModel;
  32 import java.awt.Image;
  33 
  34 /**
  35  * The PixelGrabber class implements an ImageConsumer which can be attached
  36  * to an Image or ImageProducer object to retrieve a subset of the pixels
  37  * in that image.  Here is an example:
  38  * <pre>{@code
  39  *
  40  * public void handlesinglepixel(int x, int y, int pixel) {
  41  *      int alpha = (pixel >> 24) & 0xff;
  42  *      int red   = (pixel >> 16) & 0xff;
  43  *      int green = (pixel >>  8) & 0xff;
  44  *      int blue  = (pixel      ) & 0xff;
  45  *      // Deal with the pixel as necessary...
  46  * }
  47  *
  48  * public void handlepixels(Image img, int x, int y, int w, int h) {
  49  *      int[] pixels = new int[w * h];
  50  *      PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
  51  *      try {
  52  *          pg.grabPixels();
  53  *      } catch (InterruptedException e) {
  54  *          System.err.println("interrupted waiting for pixels!");
  55  *          return;
  56  *      }
  57  *      if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
  58  *          System.err.println("image fetch aborted or errored");
  59  *          return;
  60  *      }
  61  *      for (int j = 0; j < h; j++) {
  62  *          for (int i = 0; i < w; i++) {
  63  *              handlesinglepixel(x+i, y+j, pixels[j * w + i]);
  64  *          }
  65  *      }
  66  * }
  67  *
  68  * }</pre>
  69  *
  70  * @see ColorModel#getRGBdefault
  71  *
  72  * @author      Jim Graham
  73  */
  74 public class PixelGrabber implements ImageConsumer {
  75     ImageProducer producer;
  76 
  77     int dstX;
  78     int dstY;
  79     int dstW;
  80     int dstH;
  81 
  82     ColorModel imageModel;
  83     byte[] bytePixels;
  84     int[] intPixels;
  85     int dstOff;
  86     int dstScan;
  87 
  88     private boolean grabbing;
  89     private int flags;
  90 
  91     private static final int GRABBEDBITS = (ImageObserver.FRAMEBITS
  92                                             | ImageObserver.ALLBITS);
  93     private static final int DONEBITS = (GRABBEDBITS
  94                                          | ImageObserver.ERROR);
  95 
  96     /**
  97      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  98      * section of pixels from the specified image into the given array.
  99      * The pixels are stored into the array in the default RGB ColorModel.
 100      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
 101      * (x, y, w, h) is stored in the array at
 102      * {@code pix[(j - y) * scansize + (i - x) + off]}.
 103      * @see ColorModel#getRGBdefault
 104      * @param img the image to retrieve pixels from
 105      * @param x the x coordinate of the upper left corner of the rectangle
 106      * of pixels to retrieve from the image, relative to the default
 107      * (unscaled) size of the image
 108      * @param y the y coordinate of the upper left corner of the rectangle
 109      * of pixels to retrieve from the image
 110      * @param w the width of the rectangle of pixels to retrieve
 111      * @param h the height of the rectangle of pixels to retrieve
 112      * @param pix the array of integers which are to be used to hold the
 113      * RGB pixels retrieved from the image
 114      * @param off the offset into the array of where to store the first pixel
 115      * @param scansize the distance from one row of pixels to the next in
 116      * the array
 117      */
 118     public PixelGrabber(Image img, int x, int y, int w, int h,
 119                         int[] pix, int off, int scansize) {
 120         this(img.getSource(), x, y, w, h, pix, off, scansize);
 121     }
 122 
 123     /**
 124      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
 125      * section of pixels from the image produced by the specified
 126      * ImageProducer into the given array.
 127      * The pixels are stored into the array in the default RGB ColorModel.
 128      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
 129      * (x, y, w, h) is stored in the array at
 130      * {@code pix[(j - y) * scansize + (i - x) + off]}.
 131      * @param ip the {@code ImageProducer} that produces the
 132      * image from which to retrieve pixels
 133      * @param x the x coordinate of the upper left corner of the rectangle
 134      * of pixels to retrieve from the image, relative to the default
 135      * (unscaled) size of the image
 136      * @param y the y coordinate of the upper left corner of the rectangle
 137      * of pixels to retrieve from the image
 138      * @param w the width of the rectangle of pixels to retrieve
 139      * @param h the height of the rectangle of pixels to retrieve
 140      * @param pix the array of integers which are to be used to hold the
 141      * RGB pixels retrieved from the image
 142      * @param off the offset into the array of where to store the first pixel
 143      * @param scansize the distance from one row of pixels to the next in
 144      * the array
 145      * @see ColorModel#getRGBdefault
 146      */
 147     public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
 148                         int[] pix, int off, int scansize) {
 149         producer = ip;
 150         dstX = x;
 151         dstY = y;
 152         dstW = w;
 153         dstH = h;
 154         dstOff = off;
 155         dstScan = scansize;
 156         intPixels = pix;
 157         imageModel = ColorModel.getRGBdefault();
 158     }
 159 
 160     /**
 161      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
 162      * section of pixels from the specified image.  The pixels are
 163      * accumulated in the original ColorModel if the same ColorModel
 164      * is used for every call to setPixels, otherwise the pixels are
 165      * accumulated in the default RGB ColorModel.  If the forceRGB
 166      * parameter is true, then the pixels will be accumulated in the
 167      * default RGB ColorModel anyway.  A buffer is allocated by the
 168      * PixelGrabber to hold the pixels in either case.  If {@code (w < 0)} or
 169      * {@code (h < 0)}, then they will default to the remaining width and
 170      * height of the source data when that information is delivered.
 171      * @param img the image to retrieve the image data from
 172      * @param x the x coordinate of the upper left corner of the rectangle
 173      * of pixels to retrieve from the image, relative to the default
 174      * (unscaled) size of the image
 175      * @param y the y coordinate of the upper left corner of the rectangle
 176      * of pixels to retrieve from the image
 177      * @param w the width of the rectangle of pixels to retrieve
 178      * @param h the height of the rectangle of pixels to retrieve
 179      * @param forceRGB true if the pixels should always be converted to
 180      * the default RGB ColorModel
 181      */
 182     public PixelGrabber(Image img, int x, int y, int w, int h,
 183                         boolean forceRGB)
 184     {
 185         producer = img.getSource();
 186         dstX = x;
 187         dstY = y;
 188         dstW = w;
 189         dstH = h;
 190         if (forceRGB) {
 191             imageModel = ColorModel.getRGBdefault();
 192         }
 193     }
 194 
 195     /**
 196      * Request the PixelGrabber to start fetching the pixels.
 197      */
 198     public synchronized void startGrabbing() {
 199         if ((flags & DONEBITS) != 0) {
 200             return;
 201         }
 202         if (!grabbing) {
 203             grabbing = true;
 204             flags &= ~(ImageObserver.ABORT);
 205             producer.startProduction(this);
 206         }
 207     }
 208 
 209     /**
 210      * Request the PixelGrabber to abort the image fetch.
 211      */
 212     public synchronized void abortGrabbing() {
 213         imageComplete(IMAGEABORTED);
 214     }
 215 
 216     /**
 217      * Request the Image or ImageProducer to start delivering pixels and
 218      * wait for all of the pixels in the rectangle of interest to be
 219      * delivered.
 220      * @return true if the pixels were successfully grabbed, false on
 221      * abort, error or timeout
 222      * @exception InterruptedException
 223      *            Another thread has interrupted this thread.
 224      */
 225     public boolean grabPixels() throws InterruptedException {
 226         return grabPixels(0);
 227     }
 228 
 229     /**
 230      * Request the Image or ImageProducer to start delivering pixels and
 231      * wait for all of the pixels in the rectangle of interest to be
 232      * delivered or until the specified timeout has elapsed.  This method
 233      * behaves in the following ways, depending on the value of
 234      * {@code ms}:
 235      * <ul>
 236      * <li> If {@code ms == 0}, waits until all pixels are delivered
 237      * <li> If {@code ms > 0}, waits until all pixels are delivered
 238      * as timeout expires.
 239      * <li> If {@code ms < 0}, returns {@code true} if all pixels
 240      * are grabbed, {@code false} otherwise and does not wait.
 241      * </ul>
 242      * @param ms the number of milliseconds to wait for the image pixels
 243      * to arrive before timing out
 244      * @return true if the pixels were successfully grabbed, false on
 245      * abort, error or timeout
 246      * @exception InterruptedException
 247      *            Another thread has interrupted this thread.
 248      */
 249     public synchronized boolean grabPixels(long ms)
 250         throws InterruptedException
 251     {
 252         if ((flags & DONEBITS) != 0) {
 253             return (flags & GRABBEDBITS) != 0;
 254         }
 255         long end = ms + System.currentTimeMillis();
 256         if (!grabbing) {
 257             grabbing = true;
 258             flags &= ~(ImageObserver.ABORT);
 259             producer.startProduction(this);
 260         }
 261         while (grabbing) {
 262             long timeout;
 263             if (ms == 0) {
 264                 timeout = 0;
 265             } else {
 266                 timeout = end - System.currentTimeMillis();
 267                 if (timeout <= 0) {
 268                     break;
 269                 }
 270             }
 271             wait(timeout);
 272         }
 273         return (flags & GRABBEDBITS) != 0;
 274     }
 275 
 276     /**
 277      * Return the status of the pixels.  The ImageObserver flags
 278      * representing the available pixel information are returned.
 279      * @return the bitwise OR of all relevant ImageObserver flags
 280      * @see ImageObserver
 281      */
 282     public synchronized int getStatus() {
 283         return flags;
 284     }
 285 
 286     /**
 287      * Get the width of the pixel buffer (after adjusting for image width).
 288      * If no width was specified for the rectangle of pixels to grab then
 289      * then this information will only be available after the image has
 290      * delivered the dimensions.
 291      * @return the final width used for the pixel buffer or -1 if the width
 292      * is not yet known
 293      * @see #getStatus
 294      */
 295     public synchronized int getWidth() {
 296         return (dstW < 0) ? -1 : dstW;
 297     }
 298 
 299     /**
 300      * Get the height of the pixel buffer (after adjusting for image height).
 301      * If no width was specified for the rectangle of pixels to grab then
 302      * then this information will only be available after the image has
 303      * delivered the dimensions.
 304      * @return the final height used for the pixel buffer or -1 if the height
 305      * is not yet known
 306      * @see #getStatus
 307      */
 308     public synchronized int getHeight() {
 309         return (dstH < 0) ? -1 : dstH;
 310     }
 311 
 312     /**
 313      * Get the pixel buffer.  If the PixelGrabber was not constructed
 314      * with an explicit pixel buffer to hold the pixels then this method
 315      * will return null until the size and format of the image data is
 316      * known.
 317      * Since the PixelGrabber may fall back on accumulating the data
 318      * in the default RGB ColorModel at any time if the source image
 319      * uses more than one ColorModel to deliver the data, the array
 320      * object returned by this method may change over time until the
 321      * image grab is complete.
 322      * @return either a byte array or an int array
 323      * @see #getStatus
 324      * @see #setPixels(int, int, int, int, ColorModel, byte[], int, int)
 325      * @see #setPixels(int, int, int, int, ColorModel, int[], int, int)
 326      */
 327     public synchronized Object getPixels() {
 328         return (bytePixels == null)
 329             ? ((Object) intPixels)
 330             : ((Object) bytePixels);
 331     }
 332 
 333     /**
 334      * Get the ColorModel for the pixels stored in the array.  If the
 335      * PixelGrabber was constructed with an explicit pixel buffer then
 336      * this method will always return the default RGB ColorModel,
 337      * otherwise it may return null until the ColorModel used by the
 338      * ImageProducer is known.
 339      * Since the PixelGrabber may fall back on accumulating the data
 340      * in the default RGB ColorModel at any time if the source image
 341      * uses more than one ColorModel to deliver the data, the ColorModel
 342      * object returned by this method may change over time until the
 343      * image grab is complete and may not reflect any of the ColorModel
 344      * objects that was used by the ImageProducer to deliver the pixels.
 345      * @return the ColorModel object used for storing the pixels
 346      * @see #getStatus
 347      * @see ColorModel#getRGBdefault
 348      * @see #setColorModel(ColorModel)
 349      */
 350     public synchronized ColorModel getColorModel() {
 351         return imageModel;
 352     }
 353 
 354     /**
 355      * The setDimensions method is part of the ImageConsumer API which
 356      * this class must implement to retrieve the pixels.
 357      * <p>
 358      * Note: This method is intended to be called by the ImageProducer
 359      * of the Image whose pixels are being grabbed.  Developers using
 360      * this class to retrieve pixels from an image should avoid calling
 361      * this method directly since that operation could result in problems
 362      * with retrieving the requested pixels.
 363      * @param width the width of the dimension
 364      * @param height the height of the dimension
 365      */
 366     public void setDimensions(int width, int height) {
 367         if (dstW < 0) {
 368             dstW = width - dstX;
 369         }
 370         if (dstH < 0) {
 371             dstH = height - dstY;
 372         }
 373         if (dstW <= 0 || dstH <= 0) {
 374             imageComplete(STATICIMAGEDONE);
 375         } else if (intPixels == null &&
 376                    imageModel == ColorModel.getRGBdefault()) {
 377             intPixels = new int[dstW * dstH];
 378             dstScan = dstW;
 379             dstOff = 0;
 380         }
 381         flags |= (ImageObserver.WIDTH | ImageObserver.HEIGHT);
 382     }
 383 
 384     /**
 385      * The setHints method is part of the ImageConsumer API which
 386      * this class must implement to retrieve the pixels.
 387      * <p>
 388      * Note: This method is intended to be called by the ImageProducer
 389      * of the Image whose pixels are being grabbed.  Developers using
 390      * this class to retrieve pixels from an image should avoid calling
 391      * this method directly since that operation could result in problems
 392      * with retrieving the requested pixels.
 393      * @param hints a set of hints used to process the pixels
 394      */
 395     public void setHints(int hints) {
 396         return;
 397     }
 398 
 399     /**
 400      * The setProperties method is part of the ImageConsumer API which
 401      * this class must implement to retrieve the pixels.
 402      * <p>
 403      * Note: This method is intended to be called by the ImageProducer
 404      * of the Image whose pixels are being grabbed.  Developers using
 405      * this class to retrieve pixels from an image should avoid calling
 406      * this method directly since that operation could result in problems
 407      * with retrieving the requested pixels.
 408      * @param props the list of properties
 409      */
 410     public void setProperties(Hashtable<?,?> props) {
 411         return;
 412     }
 413 
 414     /**
 415      * The setColorModel method is part of the ImageConsumer API which
 416      * this class must implement to retrieve the pixels.
 417      * <p>
 418      * Note: This method is intended to be called by the ImageProducer
 419      * of the Image whose pixels are being grabbed.  Developers using
 420      * this class to retrieve pixels from an image should avoid calling
 421      * this method directly since that operation could result in problems
 422      * with retrieving the requested pixels.
 423      * @param model the specified {@code ColorModel}
 424      * @see #getColorModel
 425      */
 426     public void setColorModel(ColorModel model) {
 427         return;
 428     }
 429 
 430     private void convertToRGB() {
 431         int size = dstW * dstH;
 432         int[] newpixels = new int[size];
 433         if (bytePixels != null) {
 434             for (int i = 0; i < size; i++) {
 435                 newpixels[i] = imageModel.getRGB(bytePixels[i] & 0xff);
 436             }
 437         } else if (intPixels != null) {
 438             for (int i = 0; i < size; i++) {
 439                 newpixels[i] = imageModel.getRGB(intPixels[i]);
 440             }
 441         }
 442         bytePixels = null;
 443         intPixels = newpixels;
 444         dstScan = dstW;
 445         dstOff = 0;
 446         imageModel = ColorModel.getRGBdefault();
 447     }
 448 
 449     /**
 450      * The setPixels method is part of the ImageConsumer API which
 451      * this class must implement to retrieve the pixels.
 452      * <p>
 453      * Note: This method is intended to be called by the ImageProducer
 454      * of the Image whose pixels are being grabbed.  Developers using
 455      * this class to retrieve pixels from an image should avoid calling
 456      * this method directly since that operation could result in problems
 457      * with retrieving the requested pixels.
 458      * @param srcX the X coordinate of the upper-left corner
 459      *        of the area of pixels to be set
 460      * @param srcY the Y coordinate of the upper-left corner
 461      *        of the area of pixels to be set
 462      * @param srcW the width of the area of pixels
 463      * @param srcH the height of the area of pixels
 464      * @param model the specified {@code ColorModel}
 465      * @param pixels the array of pixels
 466      * @param srcOff the offset into the pixels array
 467      * @param srcScan the distance from one row of pixels to the next
 468      *        in the pixels array
 469      * @see #getPixels
 470      */
 471     public void setPixels(int srcX, int srcY, int srcW, int srcH,
 472                           ColorModel model,
 473                           byte[] pixels, int srcOff, int srcScan) {
 474         if (srcY < dstY) {
 475             int diff = dstY - srcY;
 476             if (diff >= srcH) {
 477                 return;
 478             }
 479             srcOff += srcScan * diff;
 480             srcY += diff;
 481             srcH -= diff;
 482         }
 483         if (srcY + srcH > dstY + dstH) {
 484             srcH = (dstY + dstH) - srcY;
 485             if (srcH <= 0) {
 486                 return;
 487             }
 488         }
 489         if (srcX < dstX) {
 490             int diff = dstX - srcX;
 491             if (diff >= srcW) {
 492                 return;
 493             }
 494             srcOff += diff;
 495             srcX += diff;
 496             srcW -= diff;
 497         }
 498         if (srcX + srcW > dstX + dstW) {
 499             srcW = (dstX + dstW) - srcX;
 500             if (srcW <= 0) {
 501                 return;
 502             }
 503         }
 504         int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
 505         if (intPixels == null) {
 506             if (bytePixels == null) {
 507                 bytePixels = new byte[dstW * dstH];
 508                 dstScan = dstW;
 509                 dstOff = 0;
 510                 imageModel = model;
 511             } else if (imageModel != model) {
 512                 convertToRGB();
 513             }
 514             if (bytePixels != null) {
 515                 for (int h = srcH; h > 0; h--) {
 516                     System.arraycopy(pixels, srcOff, bytePixels, dstPtr, srcW);
 517                     srcOff += srcScan;
 518                     dstPtr += dstScan;
 519                 }
 520             }
 521         }
 522         if (intPixels != null) {
 523             int dstRem = dstScan - srcW;
 524             int srcRem = srcScan - srcW;
 525             for (int h = srcH; h > 0; h--) {
 526                 for (int w = srcW; w > 0; w--) {
 527                     intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]&0xff);
 528                 }
 529                 srcOff += srcRem;
 530                 dstPtr += dstRem;
 531             }
 532         }
 533         flags |= ImageObserver.SOMEBITS;
 534     }
 535 
 536     /**
 537      * The setPixels method is part of the ImageConsumer API which
 538      * this class must implement to retrieve the pixels.
 539      * <p>
 540      * Note: This method is intended to be called by the ImageProducer
 541      * of the Image whose pixels are being grabbed.  Developers using
 542      * this class to retrieve pixels from an image should avoid calling
 543      * this method directly since that operation could result in problems
 544      * with retrieving the requested pixels.
 545      * @param srcX the X coordinate of the upper-left corner
 546      *        of the area of pixels to be set
 547      * @param srcY the Y coordinate of the upper-left corner
 548      *        of the area of pixels to be set
 549      * @param srcW the width of the area of pixels
 550      * @param srcH the height of the area of pixels
 551      * @param model the specified {@code ColorModel}
 552      * @param pixels the array of pixels
 553      * @param srcOff the offset into the pixels array
 554      * @param srcScan the distance from one row of pixels to the next
 555      *        in the pixels array
 556      * @see #getPixels
 557      */
 558     public void setPixels(int srcX, int srcY, int srcW, int srcH,
 559                           ColorModel model,
 560                           int[] pixels, int srcOff, int srcScan) {
 561         if (srcY < dstY) {
 562             int diff = dstY - srcY;
 563             if (diff >= srcH) {
 564                 return;
 565             }
 566             srcOff += srcScan * diff;
 567             srcY += diff;
 568             srcH -= diff;
 569         }
 570         if (srcY + srcH > dstY + dstH) {
 571             srcH = (dstY + dstH) - srcY;
 572             if (srcH <= 0) {
 573                 return;
 574             }
 575         }
 576         if (srcX < dstX) {
 577             int diff = dstX - srcX;
 578             if (diff >= srcW) {
 579                 return;
 580             }
 581             srcOff += diff;
 582             srcX += diff;
 583             srcW -= diff;
 584         }
 585         if (srcX + srcW > dstX + dstW) {
 586             srcW = (dstX + dstW) - srcX;
 587             if (srcW <= 0) {
 588                 return;
 589             }
 590         }
 591         if (intPixels == null) {
 592             if (bytePixels == null) {
 593                 intPixels = new int[dstW * dstH];
 594                 dstScan = dstW;
 595                 dstOff = 0;
 596                 imageModel = model;
 597             } else {
 598                 convertToRGB();
 599             }
 600         }
 601         int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
 602         if (imageModel == model) {
 603             for (int h = srcH; h > 0; h--) {
 604                 System.arraycopy(pixels, srcOff, intPixels, dstPtr, srcW);
 605                 srcOff += srcScan;
 606                 dstPtr += dstScan;
 607             }
 608         } else {
 609             if (imageModel != ColorModel.getRGBdefault()) {
 610                 convertToRGB();
 611             }
 612             int dstRem = dstScan - srcW;
 613             int srcRem = srcScan - srcW;
 614             for (int h = srcH; h > 0; h--) {
 615                 for (int w = srcW; w > 0; w--) {
 616                     intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]);
 617                 }
 618                 srcOff += srcRem;
 619                 dstPtr += dstRem;
 620             }
 621         }
 622         flags |= ImageObserver.SOMEBITS;
 623     }
 624 
 625     /**
 626      * The imageComplete method is part of the ImageConsumer API which
 627      * this class must implement to retrieve the pixels.
 628      * <p>
 629      * Note: This method is intended to be called by the ImageProducer
 630      * of the Image whose pixels are being grabbed.  Developers using
 631      * this class to retrieve pixels from an image should avoid calling
 632      * this method directly since that operation could result in problems
 633      * with retrieving the requested pixels.
 634      * @param status the status of image loading
 635      */
 636     public synchronized void imageComplete(int status) {
 637         grabbing = false;
 638         switch (status) {
 639         default:
 640         case IMAGEERROR:
 641             flags |= ImageObserver.ERROR | ImageObserver.ABORT;
 642             break;
 643         case IMAGEABORTED:
 644             flags |= ImageObserver.ABORT;
 645             break;
 646         case STATICIMAGEDONE:
 647             flags |= ImageObserver.ALLBITS;
 648             break;
 649         case SINGLEFRAMEDONE:
 650             flags |= ImageObserver.FRAMEBITS;
 651             break;
 652         }
 653         producer.removeConsumer(this);
 654         notifyAll();
 655     }
 656 
 657     /**
 658      * Returns the status of the pixels.  The ImageObserver flags
 659      * representing the available pixel information are returned.
 660      * This method and {@link #getStatus() getStatus} have the
 661      * same implementation, but {@code getStatus} is the
 662      * preferred method because it conforms to the convention of
 663      * naming information-retrieval methods with the form
 664      * "getXXX".
 665      * @return the bitwise OR of all relevant ImageObserver flags
 666      * @see ImageObserver
 667      * @see #getStatus()
 668      */
 669     public synchronized int status() {
 670         return flags;
 671     }
 672 }