home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / PixelGrabber.java < prev    next >
Text File  |  1997-05-20  |  18KB  |  575 lines

  1. /*
  2.  * @(#)PixelGrabber.java    1.7 96/11/23
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.awt.image;
  24.  
  25. import java.util.Hashtable;
  26. import java.awt.image.ImageProducer;
  27. import java.awt.image.ImageConsumer;
  28. import java.awt.image.ColorModel;
  29. import java.awt.Image;
  30.  
  31. /**
  32.  * The PixelGrabber class implements an ImageConsumer which can be attached
  33.  * to an Image or ImageProducer object to retrieve a subset of the pixels
  34.  * in that image.  Here is an example:
  35.  * <pre>
  36.  *
  37.  * public void handlesinglepixel(int x, int y, int pixel) {
  38.  *    int alpha = (pixel >> 24) & 0xff;
  39.  *    int red   = (pixel >> 16) & 0xff;
  40.  *    int green = (pixel >>  8) & 0xff;
  41.  *    int blue  = (pixel      ) & 0xff;
  42.  *    // Deal with the pixel as necessary...
  43.  * }
  44.  *
  45.  * public void handlepixels(Image img, int x, int y, int w, int h) {
  46.  *    int[] pixels = new int[w * h];
  47.  *    PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
  48.  *    try {
  49.  *        pg.grabPixels();
  50.  *    } catch (InterruptedException e) {
  51.  *        System.err.println("interrupted waiting for pixels!");
  52.  *        return;
  53.  *    }
  54.  *    if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
  55.  *        System.err.println("image fetch aborted or errored");
  56.  *        return;
  57.  *    }
  58.  *    for (int j = 0; j < h; j++) {
  59.  *        for (int i = 0; i < w; i++) {
  60.  *        handlesinglepixel(x+i, y+j, pixels[j * w + i]);
  61.  *        }
  62.  *    }
  63.  * }
  64.  *
  65.  * </pre>
  66.  *
  67.  * @see ColorModel#getRGBdefault
  68.  *
  69.  * @version     1.7, 11/23/96
  70.  * @author     Jim Graham
  71.  */
  72. public class PixelGrabber implements ImageConsumer {
  73.     ImageProducer producer;
  74.  
  75.     int dstX;
  76.     int dstY;
  77.     int dstW;
  78.     int dstH;
  79.  
  80.     ColorModel imageModel;
  81.     byte[] bytePixels;
  82.     int[] intPixels;
  83.     int dstOff;
  84.     int dstScan;
  85.  
  86.     private boolean grabbing;
  87.     private int flags;
  88.  
  89.     private final int GRABBEDBITS = (ImageObserver.FRAMEBITS
  90.                      | ImageObserver.ALLBITS);
  91.     private final int DONEBITS = (GRABBEDBITS
  92.                   | ImageObserver.ERROR);
  93.  
  94.     /**
  95.      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  96.      * section of pixels from the specified image into the given array.
  97.      * The pixels are stored into the array in the default RGB ColorModel.
  98.      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
  99.      * (x, y, w, h) is stored in the array at
  100.      * <tt>pix[(j - y) * scansize + (i - x) + off]</tt>.
  101.      * @see ColorModel#getRGBdefault
  102.      * @param img the image to retrieve pixels from
  103.      * @param x the x coordinate of the upper left corner of the rectangle
  104.      * of pixels to retrieve from the image, relative to the default
  105.      * (unscaled) size of the image
  106.      * @param y the y coordinate of the upper left corner of the rectangle
  107.      * of pixels to retrieve from the image
  108.      * @param w the width of the rectangle of pixels to retrieve
  109.      * @param h the height of the rectangle of pixels to retrieve
  110.      * @param pix the array of integers which are to be used to hold the
  111.      * RGB pixels retrieved from the image
  112.      * @param off the offset into the array of where to store the first pixel
  113.      * @param scansize the distance from one row of pixels to the next in
  114.      * the array
  115.      */
  116.     public PixelGrabber(Image img, int x, int y, int w, int h,
  117.             int[] pix, int off, int scansize) {
  118.     this(img.getSource(), x, y, w, h, pix, off, scansize);
  119.     }
  120.  
  121.     /**
  122.      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  123.      * section of pixels from the image produced by the specified
  124.      * ImageProducer into the given array.
  125.      * The pixels are stored into the array in the default RGB ColorModel.
  126.      * The RGB data for pixel (i, j) where (i, j) is inside the rectangle
  127.      * (x, y, w, h) is stored in the array at
  128.      * <tt>pix[(j - y) * scansize + (i - x) + off]</tt>.
  129.      * @see ColorModel#getRGBdefault
  130.      * @param img the image to retrieve pixels from
  131.      * @param x the x coordinate of the upper left corner of the rectangle
  132.      * of pixels to retrieve from the image, relative to the default
  133.      * (unscaled) size of the image
  134.      * @param y the y coordinate of the upper left corner of the rectangle
  135.      * of pixels to retrieve from the image
  136.      * @param w the width of the rectangle of pixels to retrieve
  137.      * @param h the height of the rectangle of pixels to retrieve
  138.      * @param pix the array of integers which are to be used to hold the
  139.      * RGB pixels retrieved from the image
  140.      * @param off the offset into the array of where to store the first pixel
  141.      * @param scansize the distance from one row of pixels to the next in
  142.      * the array
  143.      */
  144.     public PixelGrabber(ImageProducer ip, int x, int y, int w, int h,
  145.             int[] pix, int off, int scansize) {
  146.     producer = ip;
  147.     dstX = x;
  148.     dstY = y;
  149.     dstW = w;
  150.     dstH = h;
  151.     dstOff = off;
  152.     dstScan = scansize;
  153.     intPixels = pix;
  154.     imageModel = ColorModel.getRGBdefault();
  155.     }
  156.  
  157.     /**
  158.      * Create a PixelGrabber object to grab the (x, y, w, h) rectangular
  159.      * section of pixels from the specified image.  The pixels are
  160.      * accumulated in the original ColorModel if the same ColorModel
  161.      * is used for every call to setPixels, otherwise the pixels are
  162.      * accumulated in the default RGB ColorModel.  If the forceRGB
  163.      * parameter is true, then the pixels will be accumulated in the
  164.      * default RGB ColorModel anywya.  A buffer is allocated by the
  165.      * PixelGrabber to hold the pixels in either case.  If (w < 0) or
  166.      * (h < 0), then they will default to the remaining width and
  167.      * height of the source data when that information is delivered.
  168.      * @param img the image to retrieve the image data from
  169.      * @param x the x coordinate of the upper left corner of the rectangle
  170.      * of pixels to retrieve from the image, relative to the default
  171.      * (unscaled) size of the image
  172.      * @param y the y coordinate of the upper left corner of the rectangle
  173.      * of pixels to retrieve from the image
  174.      * @param w the width of the rectangle of pixels to retrieve
  175.      * @param h the height of the rectangle of pixels to retrieve
  176.      * @param forceRGB true if the pixels should always be converted to
  177.      * the default RGB ColorModel
  178.      */
  179.     public PixelGrabber(Image img, int x, int y, int w, int h,
  180.             boolean forceRGB)
  181.     {
  182.     producer = img.getSource();
  183.     dstX = x;
  184.     dstY = y;
  185.     dstW = w;
  186.     dstH = h;
  187.     if (forceRGB) {
  188.         imageModel = ColorModel.getRGBdefault();
  189.     }
  190.     }
  191.  
  192.     /**
  193.      * Request the PixelGrabber to start fetching the pixels.
  194.      */
  195.     public synchronized void startGrabbing() {
  196.     if ((flags & DONEBITS) != 0) {
  197.         return;
  198.     }
  199.     if (!grabbing) {
  200.         grabbing = true;
  201.         flags &= ~(ImageObserver.ABORT);
  202.         producer.startProduction(this);
  203.     }
  204.     }
  205.  
  206.     /**
  207.      * Request the PixelGrabber to abort the image fetch.
  208.      */
  209.     public synchronized void abortGrabbing() {
  210.     imageComplete(IMAGEABORTED);
  211.     }
  212.  
  213.     /**
  214.      * Request the Image or ImageProducer to start delivering pixels and
  215.      * wait for all of the pixels in the rectangle of interest to be
  216.      * delivered.
  217.      * @return true if the pixels were successfully grabbed, false on
  218.      * abort, error or timeout
  219.      * @exception InterruptedException 
  220.      *            Another thread has interrupted this thread.
  221.      */
  222.     public boolean grabPixels() throws InterruptedException {
  223.     return grabPixels(0);
  224.     }
  225.  
  226.     /**
  227.      * Request the Image or ImageProducer to start delivering pixels and
  228.      * wait for all of the pixels in the rectangle of interest to be
  229.      * delivered or until the specified timeout has elapsed.
  230.      * @param ms the number of milliseconds to wait for the image pixels
  231.      * to arrive before timing out
  232.      * @return true if the pixels were successfully grabbed, false on
  233.      * abort, error or timeout
  234.      * @exception InterruptedException 
  235.      *            Another thread has interrupted this thread. 
  236.      */
  237.     public synchronized boolean grabPixels(long ms)
  238.     throws InterruptedException
  239.     {
  240.     if ((flags & DONEBITS) != 0) {
  241.         return (flags & GRABBEDBITS) != 0;
  242.     }
  243.     long end = ms + System.currentTimeMillis();
  244.     if (!grabbing) {
  245.         grabbing = true;
  246.         flags &= ~(ImageObserver.ABORT);
  247.         producer.startProduction(this);
  248.     }
  249.     while (grabbing) {
  250.         long timeout;
  251.         if (ms == 0) {
  252.         timeout = 0;
  253.         } else {
  254.         timeout = end - System.currentTimeMillis();
  255.         if (timeout <= 0) {
  256.             break;
  257.         }
  258.         }
  259.         wait(timeout);
  260.     }
  261.     return (flags & GRABBEDBITS) != 0;
  262.     }
  263.  
  264.     /**
  265.      * Return the status of the pixels.  The ImageObserver flags
  266.      * representing the available pixel information are returned.
  267.      * @see ImageObserver
  268.      * @return the bitwise OR of all relevant ImageObserver flags
  269.      */
  270.     public synchronized int getStatus() {
  271.     return flags;
  272.     }
  273.  
  274.     /**
  275.      * Get the width of the pixel buffer (after adjusting for image width).
  276.      * If no width was specified for the rectangle of pixels to grab then
  277.      * then this information will only be available after the image has
  278.      * delivered the dimensions.
  279.      * @return the final width used for the pixel buffer or -1 if the width
  280.      * is not yet known
  281.      * @see #getStatus
  282.      */
  283.     public synchronized int getWidth() {
  284.     return (dstW < 0) ? -1 : dstW;
  285.     }
  286.  
  287.     /**
  288.      * Get the height of the pixel buffer (after adjusting for image height).
  289.      * If no width was specified for the rectangle of pixels to grab then
  290.      * then this information will only be available after the image has
  291.      * delivered the dimensions.
  292.      * @return the final height used for the pixel buffer or -1 if the height
  293.      * is not yet known
  294.      * @see #getStatus
  295.      */
  296.     public synchronized int getHeight() {
  297.     return (dstH < 0) ? -1 : dstH;
  298.     }
  299.  
  300.     /**
  301.      * Get the pixel buffer.  If the PixelGrabber was not constructed
  302.      * with an explicit pixel buffer to hold the pixels then this method
  303.      * will return null until the size and format of the image data is
  304.      * known.
  305.      * Since the PixelGrabber may fall back on accumulating the data
  306.      * in the default RGB ColorModel at any time if the source image
  307.      * uses more than one ColorModel to deliver the data, the array
  308.      * object returned by this method may change over time until the
  309.      * image grab is complete.
  310.      * @return either a byte array or an int array
  311.      * @see #getStatus
  312.      */
  313.     public synchronized Object getPixels() {
  314.     return (bytePixels == null)
  315.         ? ((Object) intPixels)
  316.         : ((Object) bytePixels);
  317.     }
  318.  
  319.     /**
  320.      * Get the ColorModel for the pixels stored in the array.  If the
  321.      * PixelGrabber was constructed with an explicit pixel buffer then
  322.      * this method will always return the default RGB ColorModel,
  323.      * otherwise it may return null until the ColorModel used by the
  324.      * ImageProducer is known.
  325.      * Since the PixelGrabber may fall back on accumulating the data
  326.      * in the default RGB ColorModel at any time if the source image
  327.      * uses more than one ColorModel to deliver the data, the ColorModel
  328.      * object returned by this method may change over time until the
  329.      * image grab is complete.
  330.      * @return the ColorModel object used for storing the pixels
  331.      * @see #getStatus
  332.      * @see ColorModel#getRGBdefault
  333.      */
  334.     public synchronized ColorModel getColorModel() {
  335.     return imageModel;
  336.     }
  337.  
  338.     /**
  339.      * The setDimensions method is part of the ImageConsumer API which
  340.      * this class must implement to retrieve the pixels.
  341.      */
  342.     public void setDimensions(int width, int height) {
  343.     if (dstW < 0) {
  344.         dstW = width - dstX;
  345.     }
  346.     if (dstH < 0) {
  347.         dstH = height - dstY;
  348.     }
  349.     if (dstW <= 0 || dstH <= 0) {
  350.         imageComplete(STATICIMAGEDONE);
  351.     } else if (intPixels == null &&
  352.            imageModel == ColorModel.getRGBdefault()) {
  353.         intPixels = new int[dstW * dstH];
  354.         dstScan = dstW;
  355.         dstOff = 0;
  356.     }
  357.     flags |= (ImageObserver.WIDTH | ImageObserver.HEIGHT);
  358.     }
  359.  
  360.     /**
  361.      * The setHints method is part of the ImageConsumer API which
  362.      * this class must implement to retrieve the pixels.
  363.      */
  364.     public void setHints(int hints) {
  365.     return;
  366.     }
  367.  
  368.     /**
  369.      * The setProperties method is part of the ImageConsumer API which
  370.      * this class must implement to retrieve the pixels.
  371.      */
  372.     public void setProperties(Hashtable props) {
  373.     return;
  374.     }
  375.  
  376.     /**
  377.      * The setColorModel method is part of the ImageConsumer API which
  378.      * this class must implement to retrieve the pixels.
  379.      */
  380.     public void setColorModel(ColorModel model) {
  381.     return;
  382.     }
  383.  
  384.     private void convertToRGB() {
  385.     int size = dstW * dstH;
  386.     int newpixels[] = new int[size];
  387.     if (bytePixels != null) {
  388.         for (int i = 0; i < size; i++) {
  389.         newpixels[i] = imageModel.getRGB(bytePixels[i] & 0xff);
  390.         }
  391.     } else if (intPixels != null) {
  392.         for (int i = 0; i < size; i++) {
  393.         newpixels[i] = imageModel.getRGB(intPixels[i]);
  394.         }
  395.     }
  396.     bytePixels = null;
  397.     intPixels = newpixels;
  398.     dstScan = dstW;
  399.     dstOff = 0;
  400.     imageModel = ColorModel.getRGBdefault();
  401.     }
  402.  
  403.     /**
  404.      * The setPixels method is part of the ImageConsumer API which
  405.      * this class must implement to retrieve the pixels.
  406.      */
  407.     public void setPixels(int srcX, int srcY, int srcW, int srcH,
  408.               ColorModel model,
  409.               byte pixels[], int srcOff, int srcScan) {
  410.     if (srcY < dstY) {
  411.         int diff = dstY - srcY;
  412.         if (diff >= srcH) {
  413.         return;
  414.         }
  415.         srcOff += srcScan * diff;
  416.         srcY += diff;
  417.         srcH -= diff;
  418.     }
  419.     if (srcY + srcH > dstY + dstH) {
  420.         srcH = (dstY + dstH) - srcY;
  421.         if (srcH <= 0) {
  422.         return;
  423.         }
  424.     }
  425.     if (srcX < dstX) {
  426.         int diff = dstX - srcX;
  427.         if (diff >= srcW) {
  428.         return;
  429.         }
  430.         srcOff += diff;
  431.         srcX += diff;
  432.         srcW -= diff;
  433.     }
  434.     if (srcX + srcW > dstX + dstW) {
  435.         srcW = (dstX + dstW) - srcX;
  436.         if (srcW <= 0) {
  437.         return;
  438.         }
  439.     }
  440.     int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
  441.     if (intPixels == null) {
  442.         if (bytePixels == null) {
  443.         bytePixels = new byte[dstW * dstH];
  444.         dstScan = dstW;
  445.         dstOff = 0;
  446.         imageModel = model;
  447.         } else if (imageModel != model) {
  448.         convertToRGB();
  449.         }
  450.         if (bytePixels != null) {
  451.         for (int h = srcH; h > 0; h--) {
  452.             System.arraycopy(pixels, srcOff, bytePixels, dstPtr, srcW);
  453.             srcOff += srcScan;
  454.             dstPtr += dstScan;
  455.         }
  456.         }
  457.     }
  458.     if (intPixels != null) {
  459.         int dstRem = dstScan - srcW;
  460.         int srcRem = srcScan - srcW;
  461.         for (int h = srcH; h > 0; h--) {
  462.         for (int w = srcW; w > 0; w--) {
  463.             intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]&0xff);
  464.         }
  465.         srcOff += srcRem;
  466.         dstPtr += dstRem;
  467.         }
  468.     }
  469.     flags |= ImageObserver.SOMEBITS;
  470.     }
  471.  
  472.     /**
  473.      * The setPixels method is part of the ImageConsumer API which
  474.      * this class must implement to retrieve the pixels.
  475.      */
  476.     public void setPixels(int srcX, int srcY, int srcW, int srcH,
  477.               ColorModel model,
  478.               int pixels[], int srcOff, int srcScan) {
  479.     if (srcY < dstY) {
  480.         int diff = dstY - srcY;
  481.         if (diff >= srcH) {
  482.         return;
  483.         }
  484.         srcOff += srcScan * diff;
  485.         srcY += diff;
  486.         srcH -= diff;
  487.     }
  488.     if (srcY + srcH > dstY + dstH) {
  489.         srcH = (dstY + dstH) - srcY;
  490.         if (srcH <= 0) {
  491.         return;
  492.         }
  493.     }
  494.     if (srcX < dstX) {
  495.         int diff = dstX - srcX;
  496.         if (diff >= srcW) {
  497.         return;
  498.         }
  499.         srcOff += diff;
  500.         srcX += diff;
  501.         srcW -= diff;
  502.     }
  503.     if (srcX + srcW > dstX + dstW) {
  504.         srcW = (dstX + dstW) - srcX;
  505.         if (srcW <= 0) {
  506.         return;
  507.         }
  508.     }
  509.     if (intPixels == null) {
  510.         if (bytePixels == null) {
  511.         intPixels = new int[dstW * dstH];
  512.         dstScan = dstW;
  513.         dstOff = 0;
  514.         imageModel = model;
  515.         } else {
  516.         convertToRGB();
  517.         }
  518.     }
  519.     int dstPtr = dstOff + (srcY - dstY) * dstScan + (srcX - dstX);
  520.     if (imageModel == model) {
  521.         for (int h = srcH; h > 0; h--) {
  522.         System.arraycopy(pixels, srcOff, intPixels, dstPtr, srcW);
  523.         srcOff += srcScan;
  524.         dstPtr += dstScan;
  525.         }
  526.     } else {
  527.         if (imageModel != ColorModel.getRGBdefault()) {
  528.         convertToRGB();
  529.         }
  530.         int dstRem = dstScan - srcW;
  531.         int srcRem = srcScan - srcW;
  532.         for (int h = srcH; h > 0; h--) {
  533.         for (int w = srcW; w > 0; w--) {
  534.             intPixels[dstPtr++] = model.getRGB(pixels[srcOff++]);
  535.         }
  536.         srcOff += srcRem;
  537.         dstPtr += dstRem;
  538.         }
  539.     }
  540.     flags |= ImageObserver.SOMEBITS;
  541.     }
  542.  
  543.     /**
  544.      * The imageComplete method is part of the ImageConsumer API which
  545.      * this class must implement to retrieve the pixels.
  546.      */
  547.     public synchronized void imageComplete(int status) {
  548.     grabbing = false;
  549.     switch (status) {
  550.     default:
  551.     case IMAGEERROR:
  552.         flags |= ImageObserver.ERROR | ImageObserver.ABORT;
  553.         break;
  554.     case IMAGEABORTED:
  555.         flags |= ImageObserver.ABORT;
  556.         break;
  557.     case STATICIMAGEDONE:
  558.         flags |= ImageObserver.ALLBITS;
  559.         break;
  560.     case SINGLEFRAMEDONE:
  561.         flags |= ImageObserver.FRAMEBITS;
  562.         break;
  563.     }
  564.     producer.removeConsumer(this);
  565.     notifyAll();
  566.     }
  567.  
  568.     /**
  569.      * DEPRECATED:  Replaced by getStatus().
  570.      */
  571.     public synchronized int status() {
  572.     return flags;
  573.     }
  574. }
  575.