Home » openjdk-7 » java » awt » image » [javadoc | source]

    1   /*
    2    * Copyright (c) 1995, 2007, 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.awt.image.ImageConsumer;
   29   import java.awt.image.ImageProducer;
   30   import java.awt.image.ColorModel;
   31   import java.util.Hashtable;
   32   import java.util.Vector;
   33   import java.util.Enumeration;
   34   
   35   /**
   36    * This class is an implementation of the ImageProducer interface which
   37    * uses an array to produce pixel values for an Image.  Here is an example
   38    * which calculates a 100x100 image representing a fade from black to blue
   39    * along the X axis and a fade from black to red along the Y axis:
   40    * <pre>
   41    *
   42    *      int w = 100;
   43    *      int h = 100;
   44    *      int pix[] = new int[w * h];
   45    *      int index = 0;
   46    *      for (int y = 0; y < h; y++) {
   47    *          int red = (y * 255) / (h - 1);
   48    *          for (int x = 0; x < w; x++) {
   49    *              int blue = (x * 255) / (w - 1);
   50    *              pix[index++] = (255 << 24) | (red << 16) | blue;
   51    *          }
   52    *      }
   53    *      Image img = createImage(new MemoryImageSource(w, h, pix, 0, w));
   54    *
   55    * </pre>
   56    * The MemoryImageSource is also capable of managing a memory image which
   57    * varies over time to allow animation or custom rendering.  Here is an
   58    * example showing how to set up the animation source and signal changes
   59    * in the data (adapted from the MemoryAnimationSourceDemo by Garth Dickie):
   60    * <pre>
   61    *
   62    *      int pixels[];
   63    *      MemoryImageSource source;
   64    *
   65    *      public void init() {
   66    *          int width = 50;
   67    *          int height = 50;
   68    *          int size = width * height;
   69    *          pixels = new int[size];
   70    *
   71    *          int value = getBackground().getRGB();
   72    *          for (int i = 0; i < size; i++) {
   73    *              pixels[i] = value;
   74    *          }
   75    *
   76    *          source = new MemoryImageSource(width, height, pixels, 0, width);
   77    *          source.setAnimated(true);
   78    *          image = createImage(source);
   79    *      }
   80    *
   81    *      public void run() {
   82    *          Thread me = Thread.currentThread( );
   83    *          me.setPriority(Thread.MIN_PRIORITY);
   84    *
   85    *          while (true) {
   86    *              try {
   87    *                  Thread.sleep(10);
   88    *              } catch( InterruptedException e ) {
   89    *                  return;
   90    *              }
   91    *
   92    *              // Modify the values in the pixels array at (x, y, w, h)
   93    *
   94    *              // Send the new data to the interested ImageConsumers
   95    *              source.newPixels(x, y, w, h);
   96    *          }
   97    *      }
   98    *
   99    * </pre>
  100    *
  101    * @see ImageProducer
  102    *
  103    * @author      Jim Graham
  104    * @author      Animation capabilities inspired by the
  105    *              MemoryAnimationSource class written by Garth Dickie
  106    */
  107   public class MemoryImageSource implements ImageProducer {
  108       int width;
  109       int height;
  110       ColorModel model;
  111       Object pixels;
  112       int pixeloffset;
  113       int pixelscan;
  114       Hashtable properties;
  115       Vector theConsumers = new Vector();
  116       boolean animating;
  117       boolean fullbuffers;
  118   
  119       /**
  120        * Constructs an ImageProducer object which uses an array of bytes
  121        * to produce data for an Image object.
  122        * @param w the width of the rectangle of pixels
  123        * @param h the height of the rectangle of pixels
  124        * @param cm the specified <code>ColorModel</code>
  125        * @param pix an array of pixels
  126        * @param off the offset into the array of where to store the
  127        *        first pixel
  128        * @param scan the distance from one row of pixels to the next in
  129        *        the array
  130        * @see java.awt.Component#createImage
  131        */
  132       public MemoryImageSource(int w, int h, ColorModel cm,
  133                                byte[] pix, int off, int scan) {
  134           initialize(w, h, cm, (Object) pix, off, scan, null);
  135       }
  136   
  137       /**
  138        * Constructs an ImageProducer object which uses an array of bytes
  139        * to produce data for an Image object.
  140        * @param w the width of the rectangle of pixels
  141        * @param h the height of the rectangle of pixels
  142        * @param cm the specified <code>ColorModel</code>
  143        * @param pix an array of pixels
  144        * @param off the offset into the array of where to store the
  145        *        first pixel
  146        * @param scan the distance from one row of pixels to the next in
  147        *        the array
  148        * @param props a list of properties that the <code>ImageProducer</code>
  149        *        uses to process an image
  150        * @see java.awt.Component#createImage
  151        */
  152       public MemoryImageSource(int w, int h, ColorModel cm,
  153                                byte[] pix, int off, int scan,
  154                                Hashtable<?,?> props)
  155       {
  156           initialize(w, h, cm, (Object) pix, off, scan, props);
  157       }
  158   
  159       /**
  160        * Constructs an ImageProducer object which uses an array of integers
  161        * to produce data for an Image object.
  162        * @param w the width of the rectangle of pixels
  163        * @param h the height of the rectangle of pixels
  164        * @param cm the specified <code>ColorModel</code>
  165        * @param pix an array of pixels
  166        * @param off the offset into the array of where to store the
  167        *        first pixel
  168        * @param scan the distance from one row of pixels to the next in
  169        *        the array
  170        * @see java.awt.Component#createImage
  171        */
  172       public MemoryImageSource(int w, int h, ColorModel cm,
  173                                int[] pix, int off, int scan) {
  174           initialize(w, h, cm, (Object) pix, off, scan, null);
  175       }
  176   
  177       /**
  178        * Constructs an ImageProducer object which uses an array of integers
  179        * to produce data for an Image object.
  180        * @param w the width of the rectangle of pixels
  181        * @param h the height of the rectangle of pixels
  182        * @param cm the specified <code>ColorModel</code>
  183        * @param pix an array of pixels
  184        * @param off the offset into the array of where to store the
  185        *        first pixel
  186        * @param scan the distance from one row of pixels to the next in
  187        *        the array
  188        * @param props a list of properties that the <code>ImageProducer</code>
  189        *        uses to process an image
  190        * @see java.awt.Component#createImage
  191        */
  192       public MemoryImageSource(int w, int h, ColorModel cm,
  193                                int[] pix, int off, int scan,
  194                                Hashtable<?,?> props)
  195       {
  196           initialize(w, h, cm, (Object) pix, off, scan, props);
  197       }
  198   
  199       private void initialize(int w, int h, ColorModel cm,
  200                               Object pix, int off, int scan, Hashtable props) {
  201           width = w;
  202           height = h;
  203           model = cm;
  204           pixels = pix;
  205           pixeloffset = off;
  206           pixelscan = scan;
  207           if (props == null) {
  208               props = new Hashtable();
  209           }
  210           properties = props;
  211       }
  212   
  213       /**
  214        * Constructs an ImageProducer object which uses an array of integers
  215        * in the default RGB ColorModel to produce data for an Image object.
  216        * @param w the width of the rectangle of pixels
  217        * @param h the height of the rectangle of pixels
  218        * @param pix an array of pixels
  219        * @param off the offset into the array of where to store the
  220        *        first pixel
  221        * @param scan the distance from one row of pixels to the next in
  222        *        the array
  223        * @see java.awt.Component#createImage
  224        * @see ColorModel#getRGBdefault
  225        */
  226       public MemoryImageSource(int w, int h, int pix[], int off, int scan) {
  227           initialize(w, h, ColorModel.getRGBdefault(),
  228                      (Object) pix, off, scan, null);
  229       }
  230   
  231       /**
  232        * Constructs an ImageProducer object which uses an array of integers
  233        * in the default RGB ColorModel to produce data for an Image object.
  234        * @param w the width of the rectangle of pixels
  235        * @param h the height of the rectangle of pixels
  236        * @param pix an array of pixels
  237        * @param off the offset into the array of where to store the
  238        *        first pixel
  239        * @param scan the distance from one row of pixels to the next in
  240        *        the array
  241        * @param props a list of properties that the <code>ImageProducer</code>
  242        *        uses to process an image
  243        * @see java.awt.Component#createImage
  244        * @see ColorModel#getRGBdefault
  245        */
  246       public MemoryImageSource(int w, int h, int pix[], int off, int scan,
  247                                Hashtable<?,?> props)
  248       {
  249           initialize(w, h, ColorModel.getRGBdefault(),
  250                      (Object) pix, off, scan, props);
  251       }
  252   
  253       /**
  254        * Adds an ImageConsumer to the list of consumers interested in
  255        * data for this image.
  256        * @param ic the specified <code>ImageConsumer</code>
  257        * @throws NullPointerException if the specified
  258        *           <code>ImageConsumer</code> is null
  259        * @see ImageConsumer
  260        */
  261       public synchronized void addConsumer(ImageConsumer ic) {
  262           if (theConsumers.contains(ic)) {
  263               return;
  264           }
  265           theConsumers.addElement(ic);
  266           try {
  267               initConsumer(ic);
  268               sendPixels(ic, 0, 0, width, height);
  269               if (isConsumer(ic)) {
  270                   ic.imageComplete(animating
  271                                    ? ImageConsumer.SINGLEFRAMEDONE
  272                                    : ImageConsumer.STATICIMAGEDONE);
  273                   if (!animating && isConsumer(ic)) {
  274                       ic.imageComplete(ImageConsumer.IMAGEERROR);
  275                       removeConsumer(ic);
  276                   }
  277               }
  278           } catch (Exception e) {
  279               if (isConsumer(ic)) {
  280                   ic.imageComplete(ImageConsumer.IMAGEERROR);
  281               }
  282           }
  283       }
  284   
  285       /**
  286        * Determines if an ImageConsumer is on the list of consumers currently
  287        * interested in data for this image.
  288        * @param ic the specified <code>ImageConsumer</code>
  289        * @return <code>true</code> if the <code>ImageConsumer</code>
  290        * is on the list; <code>false</code> otherwise.
  291        * @see ImageConsumer
  292        */
  293       public synchronized boolean isConsumer(ImageConsumer ic) {
  294           return theConsumers.contains(ic);
  295       }
  296   
  297       /**
  298        * Removes an ImageConsumer from the list of consumers interested in
  299        * data for this image.
  300        * @param ic the specified <code>ImageConsumer</code>
  301        * @see ImageConsumer
  302        */
  303       public synchronized void removeConsumer(ImageConsumer ic) {
  304           theConsumers.removeElement(ic);
  305       }
  306   
  307       /**
  308        * Adds an ImageConsumer to the list of consumers interested in
  309        * data for this image and immediately starts delivery of the
  310        * image data through the ImageConsumer interface.
  311        * @param ic the specified <code>ImageConsumer</code>
  312        * image data through the ImageConsumer interface.
  313        * @see ImageConsumer
  314        */
  315       public void startProduction(ImageConsumer ic) {
  316           addConsumer(ic);
  317       }
  318   
  319       /**
  320        * Requests that a given ImageConsumer have the image data delivered
  321        * one more time in top-down, left-right order.
  322        * @param ic the specified <code>ImageConsumer</code>
  323        * @see ImageConsumer
  324        */
  325       public void requestTopDownLeftRightResend(ImageConsumer ic) {
  326           // Ignored.  The data is either single frame and already in TDLR
  327           // format or it is multi-frame and TDLR resends aren't critical.
  328       }
  329   
  330       /**
  331        * Changes this memory image into a multi-frame animation or a
  332        * single-frame static image depending on the animated parameter.
  333        * <p>This method should be called immediately after the
  334        * MemoryImageSource is constructed and before an image is
  335        * created with it to ensure that all ImageConsumers will
  336        * receive the correct multi-frame data.  If an ImageConsumer
  337        * is added to this ImageProducer before this flag is set then
  338        * that ImageConsumer will see only a snapshot of the pixel
  339        * data that was available when it connected.
  340        * @param animated <code>true</code> if the image is a
  341        *       multi-frame animation
  342        */
  343       public synchronized void setAnimated(boolean animated) {
  344           this.animating = animated;
  345           if (!animating) {
  346               Enumeration enum_ = theConsumers.elements();
  347               while (enum_.hasMoreElements()) {
  348                   ImageConsumer ic = (ImageConsumer) enum_.nextElement();
  349                   ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
  350                   if (isConsumer(ic)) {
  351                       ic.imageComplete(ImageConsumer.IMAGEERROR);
  352                   }
  353               }
  354               theConsumers.removeAllElements();
  355           }
  356       }
  357   
  358       /**
  359        * Specifies whether this animated memory image should always be
  360        * updated by sending the complete buffer of pixels whenever
  361        * there is a change.
  362        * This flag is ignored if the animation flag is not turned on
  363        * through the setAnimated() method.
  364        * <p>This method should be called immediately after the
  365        * MemoryImageSource is constructed and before an image is
  366        * created with it to ensure that all ImageConsumers will
  367        * receive the correct pixel delivery hints.
  368        * @param fullbuffers <code>true</code> if the complete pixel
  369        *             buffer should always
  370        * be sent
  371        * @see #setAnimated
  372        */
  373       public synchronized void setFullBufferUpdates(boolean fullbuffers) {
  374           if (this.fullbuffers == fullbuffers) {
  375               return;
  376           }
  377           this.fullbuffers = fullbuffers;
  378           if (animating) {
  379               Enumeration enum_ = theConsumers.elements();
  380               while (enum_.hasMoreElements()) {
  381                   ImageConsumer ic = (ImageConsumer) enum_.nextElement();
  382                   ic.setHints(fullbuffers
  383                               ? (ImageConsumer.TOPDOWNLEFTRIGHT |
  384                                  ImageConsumer.COMPLETESCANLINES)
  385                               : ImageConsumer.RANDOMPIXELORDER);
  386               }
  387           }
  388       }
  389   
  390       /**
  391        * Sends a whole new buffer of pixels to any ImageConsumers that
  392        * are currently interested in the data for this image and notify
  393        * them that an animation frame is complete.
  394        * This method only has effect if the animation flag has been
  395        * turned on through the setAnimated() method.
  396        * @see #newPixels(int, int, int, int, boolean)
  397        * @see ImageConsumer
  398        * @see #setAnimated
  399        */
  400       public void newPixels() {
  401           newPixels(0, 0, width, height, true);
  402       }
  403   
  404       /**
  405        * Sends a rectangular region of the buffer of pixels to any
  406        * ImageConsumers that are currently interested in the data for
  407        * this image and notify them that an animation frame is complete.
  408        * This method only has effect if the animation flag has been
  409        * turned on through the setAnimated() method.
  410        * If the full buffer update flag was turned on with the
  411        * setFullBufferUpdates() method then the rectangle parameters
  412        * will be ignored and the entire buffer will always be sent.
  413        * @param x the x coordinate of the upper left corner of the rectangle
  414        * of pixels to be sent
  415        * @param y the y coordinate of the upper left corner of the rectangle
  416        * of pixels to be sent
  417        * @param w the width of the rectangle of pixels to be sent
  418        * @param h the height of the rectangle of pixels to be sent
  419        * @see #newPixels(int, int, int, int, boolean)
  420        * @see ImageConsumer
  421        * @see #setAnimated
  422        * @see #setFullBufferUpdates
  423        */
  424       public synchronized void newPixels(int x, int y, int w, int h) {
  425           newPixels(x, y, w, h, true);
  426       }
  427   
  428       /**
  429        * Sends a rectangular region of the buffer of pixels to any
  430        * ImageConsumers that are currently interested in the data for
  431        * this image.
  432        * If the framenotify parameter is true then the consumers are
  433        * also notified that an animation frame is complete.
  434        * This method only has effect if the animation flag has been
  435        * turned on through the setAnimated() method.
  436        * If the full buffer update flag was turned on with the
  437        * setFullBufferUpdates() method then the rectangle parameters
  438        * will be ignored and the entire buffer will always be sent.
  439        * @param x the x coordinate of the upper left corner of the rectangle
  440        * of pixels to be sent
  441        * @param y the y coordinate of the upper left corner of the rectangle
  442        * of pixels to be sent
  443        * @param w the width of the rectangle of pixels to be sent
  444        * @param h the height of the rectangle of pixels to be sent
  445        * @param framenotify <code>true</code> if the consumers should be sent a
  446        * {@link ImageConsumer#SINGLEFRAMEDONE SINGLEFRAMEDONE} notification
  447        * @see ImageConsumer
  448        * @see #setAnimated
  449        * @see #setFullBufferUpdates
  450        */
  451       public synchronized void newPixels(int x, int y, int w, int h,
  452                                          boolean framenotify) {
  453           if (animating) {
  454               if (fullbuffers) {
  455                   x = y = 0;
  456                   w = width;
  457                   h = height;
  458               } else {
  459                   if (x < 0) {
  460                       w += x;
  461                       x = 0;
  462                   }
  463                   if (x + w > width) {
  464                       w = width - x;
  465                   }
  466                   if (y < 0) {
  467                       h += y;
  468                       y = 0;
  469                   }
  470                   if (y + h > height) {
  471                       h = height - y;
  472                   }
  473               }
  474               if ((w <= 0 || h <= 0) && !framenotify) {
  475                   return;
  476               }
  477               Enumeration enum_ = theConsumers.elements();
  478               while (enum_.hasMoreElements()) {
  479                   ImageConsumer ic = (ImageConsumer) enum_.nextElement();
  480                   if (w > 0 && h > 0) {
  481                       sendPixels(ic, x, y, w, h);
  482                   }
  483                   if (framenotify && isConsumer(ic)) {
  484                       ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
  485                   }
  486               }
  487           }
  488       }
  489   
  490       /**
  491        * Changes to a new byte array to hold the pixels for this image.
  492        * If the animation flag has been turned on through the setAnimated()
  493        * method, then the new pixels will be immediately delivered to any
  494        * ImageConsumers that are currently interested in the data for
  495        * this image.
  496        * @param newpix the new pixel array
  497        * @param newmodel the specified <code>ColorModel</code>
  498        * @param offset the offset into the array
  499        * @param scansize the distance from one row of pixels to the next in
  500        * the array
  501        * @see #newPixels(int, int, int, int, boolean)
  502        * @see #setAnimated
  503        */
  504       public synchronized void newPixels(byte[] newpix, ColorModel newmodel,
  505                                          int offset, int scansize) {
  506           this.pixels = newpix;
  507           this.model = newmodel;
  508           this.pixeloffset = offset;
  509           this.pixelscan = scansize;
  510           newPixels();
  511       }
  512   
  513       /**
  514        * Changes to a new int array to hold the pixels for this image.
  515        * If the animation flag has been turned on through the setAnimated()
  516        * method, then the new pixels will be immediately delivered to any
  517        * ImageConsumers that are currently interested in the data for
  518        * this image.
  519        * @param newpix the new pixel array
  520        * @param newmodel the specified <code>ColorModel</code>
  521        * @param offset the offset into the array
  522        * @param scansize the distance from one row of pixels to the next in
  523        * the array
  524        * @see #newPixels(int, int, int, int, boolean)
  525        * @see #setAnimated
  526        */
  527       public synchronized void newPixels(int[] newpix, ColorModel newmodel,
  528                                          int offset, int scansize) {
  529           this.pixels = newpix;
  530           this.model = newmodel;
  531           this.pixeloffset = offset;
  532           this.pixelscan = scansize;
  533           newPixels();
  534       }
  535   
  536       private void initConsumer(ImageConsumer ic) {
  537           if (isConsumer(ic)) {
  538               ic.setDimensions(width, height);
  539           }
  540           if (isConsumer(ic)) {
  541               ic.setProperties(properties);
  542           }
  543           if (isConsumer(ic)) {
  544               ic.setColorModel(model);
  545           }
  546           if (isConsumer(ic)) {
  547               ic.setHints(animating
  548                           ? (fullbuffers
  549                              ? (ImageConsumer.TOPDOWNLEFTRIGHT |
  550                                 ImageConsumer.COMPLETESCANLINES)
  551                              : ImageConsumer.RANDOMPIXELORDER)
  552                           : (ImageConsumer.TOPDOWNLEFTRIGHT |
  553                              ImageConsumer.COMPLETESCANLINES |
  554                              ImageConsumer.SINGLEPASS |
  555                              ImageConsumer.SINGLEFRAME));
  556           }
  557       }
  558   
  559       private void sendPixels(ImageConsumer ic, int x, int y, int w, int h) {
  560           int off = pixeloffset + pixelscan * y + x;
  561           if (isConsumer(ic)) {
  562               if (pixels instanceof byte[]) {
  563                   ic.setPixels(x, y, w, h, model,
  564                                ((byte[]) pixels), off, pixelscan);
  565               } else {
  566                   ic.setPixels(x, y, w, h, model,
  567                                ((int[]) pixels), off, pixelscan);
  568               }
  569           }
  570       }
  571   }

Home » openjdk-7 » java » awt » image » [javadoc | source]