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

    1   /*
    2    * Copyright (c) 1997, 2008, 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.Transparency;
   29   import java.awt.color.ColorSpace;
   30   import java.awt.Graphics2D;
   31   import java.awt.GraphicsConfiguration;
   32   import java.awt.GraphicsEnvironment;
   33   import java.awt.ImageCapabilities;
   34   import java.awt.geom.Rectangle2D;
   35   import java.awt.geom.Point2D;
   36   import java.awt.Point;
   37   import java.awt.Rectangle;
   38   import java.util.Hashtable;
   39   import java.util.Vector;
   40   
   41   import sun.awt.image.BytePackedRaster;
   42   import sun.awt.image.ShortComponentRaster;
   43   import sun.awt.image.ByteComponentRaster;
   44   import sun.awt.image.IntegerComponentRaster;
   45   import sun.awt.image.OffScreenImageSource;
   46   
   47   /**
   48    *
   49    * The <code>BufferedImage</code> subclass describes an {@link
   50    * java.awt.Image Image} with an accessible buffer of image data.
   51    * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a
   52    * {@link Raster} of image data.
   53    * The number and types of bands in the {@link SampleModel} of the
   54    * <code>Raster</code> must match the number and types required by the
   55    * <code>ColorModel</code> to represent its color and alpha components.
   56    * All <code>BufferedImage</code> objects have an upper left corner
   57    * coordinate of (0,&nbsp;0).  Any <code>Raster</code> used to construct a
   58    * <code>BufferedImage</code> must therefore have minX=0 and minY=0.
   59    *
   60    * <p>
   61    * This class relies on the data fetching and setting methods
   62    * of <code>Raster</code>,
   63    * and on the color characterization methods of <code>ColorModel</code>.
   64    *
   65    * @see ColorModel
   66    * @see Raster
   67    * @see WritableRaster
   68    */
   69   
   70   public class BufferedImage extends java.awt.Image
   71                              implements WritableRenderedImage, Transparency
   72   {
   73       int        imageType = TYPE_CUSTOM;
   74       ColorModel colorModel;
   75       WritableRaster raster;
   76       OffScreenImageSource osis;
   77       Hashtable properties;
   78   
   79       boolean    isAlphaPremultiplied;// If true, alpha has been premultiplied in
   80       // color channels
   81   
   82       /**
   83        * Image Type Constants
   84        */
   85   
   86       /**
   87        * Image type is not recognized so it must be a customized
   88        * image.  This type is only used as a return value for the getType()
   89        * method.
   90        */
   91       public static final int TYPE_CUSTOM = 0;
   92   
   93       /**
   94        * Represents an image with 8-bit RGB color components packed into
   95        * integer pixels.  The image has a {@link DirectColorModel} without
   96        * alpha.
   97        * When data with non-opaque alpha is stored
   98        * in an image of this type,
   99        * the color data must be adjusted to a non-premultiplied form
  100        * and the alpha discarded,
  101        * as described in the
  102        * {@link java.awt.AlphaComposite} documentation.
  103        */
  104       public static final int TYPE_INT_RGB = 1;
  105   
  106       /**
  107        * Represents an image with 8-bit RGBA color components packed into
  108        * integer pixels.  The image has a <code>DirectColorModel</code>
  109        * with alpha. The color data in this image is considered not to be
  110        * premultiplied with alpha.  When this type is used as the
  111        * <code>imageType</code> argument to a <code>BufferedImage</code>
  112        * constructor, the created image is consistent with images
  113        * created in the JDK1.1 and earlier releases.
  114        */
  115       public static final int TYPE_INT_ARGB = 2;
  116   
  117       /**
  118        * Represents an image with 8-bit RGBA color components packed into
  119        * integer pixels.  The image has a <code>DirectColorModel</code>
  120        * with alpha.  The color data in this image is considered to be
  121        * premultiplied with alpha.
  122        */
  123       public static final int TYPE_INT_ARGB_PRE = 3;
  124   
  125       /**
  126        * Represents an image with 8-bit RGB color components, corresponding
  127        * to a Windows- or Solaris- style BGR color model, with the colors
  128        * Blue, Green, and Red packed into integer pixels.  There is no alpha.
  129        * The image has a {@link DirectColorModel}.
  130        * When data with non-opaque alpha is stored
  131        * in an image of this type,
  132        * the color data must be adjusted to a non-premultiplied form
  133        * and the alpha discarded,
  134        * as described in the
  135        * {@link java.awt.AlphaComposite} documentation.
  136        */
  137       public static final int TYPE_INT_BGR = 4;
  138   
  139       /**
  140        * Represents an image with 8-bit RGB color components, corresponding
  141        * to a Windows-style BGR color model) with the colors Blue, Green,
  142        * and Red stored in 3 bytes.  There is no alpha.  The image has a
  143        * <code>ComponentColorModel</code>.
  144        * When data with non-opaque alpha is stored
  145        * in an image of this type,
  146        * the color data must be adjusted to a non-premultiplied form
  147        * and the alpha discarded,
  148        * as described in the
  149        * {@link java.awt.AlphaComposite} documentation.
  150        */
  151       public static final int TYPE_3BYTE_BGR = 5;
  152   
  153       /**
  154        * Represents an image with 8-bit RGBA color components with the colors
  155        * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha.  The
  156        * image has a <code>ComponentColorModel</code> with alpha.  The
  157        * color data in this image is considered not to be premultiplied with
  158        * alpha.  The byte data is interleaved in a single
  159        * byte array in the order A, B, G, R
  160        * from lower to higher byte addresses within each pixel.
  161        */
  162       public static final int TYPE_4BYTE_ABGR = 6;
  163   
  164       /**
  165        * Represents an image with 8-bit RGBA color components with the colors
  166        * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha.  The
  167        * image has a <code>ComponentColorModel</code> with alpha. The color
  168        * data in this image is considered to be premultiplied with alpha.
  169        * The byte data is interleaved in a single byte array in the order
  170        * A, B, G, R from lower to higher byte addresses within each pixel.
  171        */
  172       public static final int TYPE_4BYTE_ABGR_PRE = 7;
  173   
  174       /**
  175        * Represents an image with 5-6-5 RGB color components (5-bits red,
  176        * 6-bits green, 5-bits blue) with no alpha.  This image has
  177        * a <code>DirectColorModel</code>.
  178        * When data with non-opaque alpha is stored
  179        * in an image of this type,
  180        * the color data must be adjusted to a non-premultiplied form
  181        * and the alpha discarded,
  182        * as described in the
  183        * {@link java.awt.AlphaComposite} documentation.
  184        */
  185       public static final int TYPE_USHORT_565_RGB = 8;
  186   
  187       /**
  188        * Represents an image with 5-5-5 RGB color components (5-bits red,
  189        * 5-bits green, 5-bits blue) with no alpha.  This image has
  190        * a <code>DirectColorModel</code>.
  191        * When data with non-opaque alpha is stored
  192        * in an image of this type,
  193        * the color data must be adjusted to a non-premultiplied form
  194        * and the alpha discarded,
  195        * as described in the
  196        * {@link java.awt.AlphaComposite} documentation.
  197        */
  198       public static final int TYPE_USHORT_555_RGB = 9;
  199   
  200       /**
  201        * Represents a unsigned byte grayscale image, non-indexed.  This
  202        * image has a <code>ComponentColorModel</code> with a CS_GRAY
  203        * {@link ColorSpace}.
  204        * When data with non-opaque alpha is stored
  205        * in an image of this type,
  206        * the color data must be adjusted to a non-premultiplied form
  207        * and the alpha discarded,
  208        * as described in the
  209        * {@link java.awt.AlphaComposite} documentation.
  210        */
  211       public static final int TYPE_BYTE_GRAY = 10;
  212   
  213       /**
  214        * Represents an unsigned short grayscale image, non-indexed).  This
  215        * image has a <code>ComponentColorModel</code> with a CS_GRAY
  216        * <code>ColorSpace</code>.
  217        * When data with non-opaque alpha is stored
  218        * in an image of this type,
  219        * the color data must be adjusted to a non-premultiplied form
  220        * and the alpha discarded,
  221        * as described in the
  222        * {@link java.awt.AlphaComposite} documentation.
  223        */
  224       public static final int TYPE_USHORT_GRAY = 11;
  225   
  226       /**
  227        * Represents an opaque byte-packed 1, 2, or 4 bit image.  The
  228        * image has an {@link IndexColorModel} without alpha.  When this
  229        * type is used as the <code>imageType</code> argument to the
  230        * <code>BufferedImage</code> constructor that takes an
  231        * <code>imageType</code> argument but no <code>ColorModel</code>
  232        * argument, a 1-bit image is created with an
  233        * <code>IndexColorModel</code> with two colors in the default
  234        * sRGB <code>ColorSpace</code>: {0,&nbsp;0,&nbsp;0} and
  235        * {255,&nbsp;255,&nbsp;255}.
  236        *
  237        * <p> Images with 2 or 4 bits per pixel may be constructed via
  238        * the <code>BufferedImage</code> constructor that takes a
  239        * <code>ColorModel</code> argument by supplying a
  240        * <code>ColorModel</code> with an appropriate map size.
  241        *
  242        * <p> Images with 8 bits per pixel should use the image types
  243        * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code>
  244        * depending on their <code>ColorModel</code>.
  245   
  246        * <p> When color data is stored in an image of this type,
  247        * the closest color in the colormap is determined
  248        * by the <code>IndexColorModel</code> and the resulting index is stored.
  249        * Approximation and loss of alpha or color components
  250        * can result, depending on the colors in the
  251        * <code>IndexColorModel</code> colormap.
  252        */
  253       public static final int TYPE_BYTE_BINARY = 12;
  254   
  255       /**
  256        * Represents an indexed byte image.  When this type is used as the
  257        * <code>imageType</code> argument to the <code>BufferedImage</code>
  258        * constructor that takes an <code>imageType</code> argument
  259        * but no <code>ColorModel</code> argument, an
  260        * <code>IndexColorModel</code> is created with
  261        * a 256-color 6/6/6 color cube palette with the rest of the colors
  262        * from 216-255 populated by grayscale values in the
  263        * default sRGB ColorSpace.
  264        *
  265        * <p> When color data is stored in an image of this type,
  266        * the closest color in the colormap is determined
  267        * by the <code>IndexColorModel</code> and the resulting index is stored.
  268        * Approximation and loss of alpha or color components
  269        * can result, depending on the colors in the
  270        * <code>IndexColorModel</code> colormap.
  271        */
  272       public static final int TYPE_BYTE_INDEXED = 13;
  273   
  274       private static final int DCM_RED_MASK   = 0x00ff0000;
  275       private static final int DCM_GREEN_MASK = 0x0000ff00;
  276       private static final int DCM_BLUE_MASK  = 0x000000ff;
  277       private static final int DCM_ALPHA_MASK = 0xff000000;
  278       private static final int DCM_565_RED_MASK = 0xf800;
  279       private static final int DCM_565_GRN_MASK = 0x07E0;
  280       private static final int DCM_565_BLU_MASK = 0x001F;
  281       private static final int DCM_555_RED_MASK = 0x7C00;
  282       private static final int DCM_555_GRN_MASK = 0x03E0;
  283       private static final int DCM_555_BLU_MASK = 0x001F;
  284       private static final int DCM_BGR_RED_MASK = 0x0000ff;
  285       private static final int DCM_BGR_GRN_MASK = 0x00ff00;
  286       private static final int DCM_BGR_BLU_MASK = 0xff0000;
  287   
  288   
  289       static private native void initIDs();
  290       static {
  291           ColorModel.loadLibraries();
  292           initIDs();
  293       }
  294   
  295       /**
  296        * Constructs a <code>BufferedImage</code> of one of the predefined
  297        * image types.  The <code>ColorSpace</code> for the image is the
  298        * default sRGB space.
  299        * @param width     width of the created image
  300        * @param height    height of the created image
  301        * @param imageType type of the created image
  302        * @see ColorSpace
  303        * @see #TYPE_INT_RGB
  304        * @see #TYPE_INT_ARGB
  305        * @see #TYPE_INT_ARGB_PRE
  306        * @see #TYPE_INT_BGR
  307        * @see #TYPE_3BYTE_BGR
  308        * @see #TYPE_4BYTE_ABGR
  309        * @see #TYPE_4BYTE_ABGR_PRE
  310        * @see #TYPE_BYTE_GRAY
  311        * @see #TYPE_USHORT_GRAY
  312        * @see #TYPE_BYTE_BINARY
  313        * @see #TYPE_BYTE_INDEXED
  314        * @see #TYPE_USHORT_565_RGB
  315        * @see #TYPE_USHORT_555_RGB
  316        */
  317       public BufferedImage(int width,
  318                            int height,
  319                            int imageType) {
  320           switch (imageType) {
  321           case TYPE_INT_RGB:
  322               {
  323                   colorModel = new DirectColorModel(24,
  324                                                     0x00ff0000,   // Red
  325                                                     0x0000ff00,   // Green
  326                                                     0x000000ff,   // Blue
  327                                                     0x0           // Alpha
  328                                                     );
  329                     raster = colorModel.createCompatibleWritableRaster(width,
  330                                                                         height);
  331               }
  332           break;
  333   
  334           case TYPE_INT_ARGB:
  335               {
  336                   colorModel = ColorModel.getRGBdefault();
  337   
  338                   raster = colorModel.createCompatibleWritableRaster(width,
  339                                                                      height);
  340               }
  341           break;
  342   
  343           case TYPE_INT_ARGB_PRE:
  344               {
  345                   colorModel = new
  346                       DirectColorModel(
  347                                        ColorSpace.getInstance(ColorSpace.CS_sRGB),
  348                                        32,
  349                                        0x00ff0000,// Red
  350                                        0x0000ff00,// Green
  351                                        0x000000ff,// Blue
  352                                        0xff000000,// Alpha
  353                                        true,       // Alpha Premultiplied
  354                                        DataBuffer.TYPE_INT
  355                                        );
  356   
  357                     raster = colorModel.createCompatibleWritableRaster(width,
  358                                                                         height);
  359               }
  360           break;
  361   
  362           case TYPE_INT_BGR:
  363               {
  364                   colorModel = new DirectColorModel(24,
  365                                                     0x000000ff,   // Red
  366                                                     0x0000ff00,   // Green
  367                                                     0x00ff0000    // Blue
  368                                                     );
  369                     raster = colorModel.createCompatibleWritableRaster(width,
  370                                                                         height);
  371               }
  372           break;
  373   
  374           case TYPE_3BYTE_BGR:
  375               {
  376                   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  377                   int[] nBits = {8, 8, 8};
  378                   int[] bOffs = {2, 1, 0};
  379                   colorModel = new ComponentColorModel(cs, nBits, false, false,
  380                                                        Transparency.OPAQUE,
  381                                                        DataBuffer.TYPE_BYTE);
  382                   raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  383                                                           width, height,
  384                                                           width*3, 3,
  385                                                           bOffs, null);
  386               }
  387           break;
  388   
  389           case TYPE_4BYTE_ABGR:
  390               {
  391                   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  392                   int[] nBits = {8, 8, 8, 8};
  393                   int[] bOffs = {3, 2, 1, 0};
  394                   colorModel = new ComponentColorModel(cs, nBits, true, false,
  395                                                        Transparency.TRANSLUCENT,
  396                                                        DataBuffer.TYPE_BYTE);
  397                   raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  398                                                           width, height,
  399                                                           width*4, 4,
  400                                                           bOffs, null);
  401               }
  402           break;
  403   
  404           case TYPE_4BYTE_ABGR_PRE:
  405               {
  406                   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  407                   int[] nBits = {8, 8, 8, 8};
  408                   int[] bOffs = {3, 2, 1, 0};
  409                   colorModel = new ComponentColorModel(cs, nBits, true, true,
  410                                                        Transparency.TRANSLUCENT,
  411                                                        DataBuffer.TYPE_BYTE);
  412                   raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  413                                                           width, height,
  414                                                           width*4, 4,
  415                                                           bOffs, null);
  416               }
  417           break;
  418   
  419           case TYPE_BYTE_GRAY:
  420               {
  421                   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
  422                   int[] nBits = {8};
  423                   colorModel = new ComponentColorModel(cs, nBits, false, true,
  424                                                        Transparency.OPAQUE,
  425                                                        DataBuffer.TYPE_BYTE);
  426                   raster = colorModel.createCompatibleWritableRaster(width,
  427                                                                      height);
  428               }
  429           break;
  430   
  431           case TYPE_USHORT_GRAY:
  432               {
  433                   ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
  434                   int[] nBits = {16};
  435                   colorModel = new ComponentColorModel(cs, nBits, false, true,
  436                                                        Transparency.OPAQUE,
  437                                                        DataBuffer.TYPE_USHORT);
  438                   raster = colorModel.createCompatibleWritableRaster(width,
  439                                                                      height);
  440               }
  441           break;
  442   
  443           case TYPE_BYTE_BINARY:
  444               {
  445                   byte[] arr = {(byte)0, (byte)0xff};
  446   
  447                   colorModel = new IndexColorModel(1, 2, arr, arr, arr);
  448                   raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
  449                                                      width, height, 1, 1, null);
  450               }
  451           break;
  452   
  453           case TYPE_BYTE_INDEXED:
  454               {
  455                   // Create a 6x6x6 color cube
  456                   int[] cmap = new int[256];
  457                   int i=0;
  458                   for (int r=0; r < 256; r += 51) {
  459                       for (int g=0; g < 256; g += 51) {
  460                           for (int b=0; b < 256; b += 51) {
  461                               cmap[i++] = (r<<16)|(g<<8)|b;
  462                           }
  463                       }
  464                   }
  465                   // And populate the rest of the cmap with gray values
  466                   int grayIncr = 256/(256-i);
  467   
  468                   // The gray ramp will be between 18 and 252
  469                   int gray = grayIncr*3;
  470                   for (; i < 256; i++) {
  471                       cmap[i] = (gray<<16)|(gray<<8)|gray;
  472                       gray += grayIncr;
  473                   }
  474   
  475                   colorModel = new IndexColorModel(8, 256, cmap, 0, false, -1,
  476                                                    DataBuffer.TYPE_BYTE);
  477                   raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  478                                                         width, height, 1, null);
  479               }
  480           break;
  481   
  482           case TYPE_USHORT_565_RGB:
  483               {
  484                   colorModel = new DirectColorModel(16,
  485                                                     DCM_565_RED_MASK,
  486                                                     DCM_565_GRN_MASK,
  487                                                     DCM_565_BLU_MASK
  488                                                     );
  489                   raster = colorModel.createCompatibleWritableRaster(width,
  490                                                                      height);
  491               }
  492               break;
  493   
  494           case TYPE_USHORT_555_RGB:
  495               {
  496                   colorModel = new DirectColorModel(15,
  497                                                     DCM_555_RED_MASK,
  498                                                     DCM_555_GRN_MASK,
  499                                                     DCM_555_BLU_MASK
  500                                                     );
  501                   raster = colorModel.createCompatibleWritableRaster(width,
  502                                                                      height);
  503               }
  504               break;
  505   
  506           default:
  507               throw new IllegalArgumentException ("Unknown image type " +
  508                                                   imageType);
  509           }
  510   
  511           this.imageType = imageType;
  512       }
  513   
  514       /**
  515        * Constructs a <code>BufferedImage</code> of one of the predefined
  516        * image types:
  517        * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED.
  518        *
  519        * <p> If the image type is TYPE_BYTE_BINARY, the number of
  520        * entries in the color model is used to determine whether the
  521        * image should have 1, 2, or 4 bits per pixel.  If the color model
  522        * has 1 or 2 entries, the image will have 1 bit per pixel.  If it
  523        * has 3 or 4 entries, the image with have 2 bits per pixel.  If
  524        * it has between 5 and 16 entries, the image will have 4 bits per
  525        * pixel.  Otherwise, an IllegalArgumentException will be thrown.
  526        *
  527        * @param width     width of the created image
  528        * @param height    height of the created image
  529        * @param imageType type of the created image
  530        * @param cm        <code>IndexColorModel</code> of the created image
  531        * @throws IllegalArgumentException   if the imageType is not
  532        * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is
  533        * TYPE_BYTE_BINARY and the color map has more than 16 entries.
  534        * @see #TYPE_BYTE_BINARY
  535        * @see #TYPE_BYTE_INDEXED
  536        */
  537       public BufferedImage (int width,
  538                             int height,
  539                             int imageType,
  540                             IndexColorModel cm) {
  541           if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
  542               throw new IllegalArgumentException("This image types do not have "+
  543                                                  "premultiplied alpha.");
  544           }
  545   
  546           switch(imageType) {
  547           case TYPE_BYTE_BINARY:
  548               int bits; // Will be set below
  549               int mapSize = cm.getMapSize();
  550               if (mapSize <= 2) {
  551                   bits = 1;
  552               } else if (mapSize <= 4) {
  553                   bits = 2;
  554               } else if (mapSize <= 16) {
  555                   bits = 4;
  556               } else {
  557                   throw new IllegalArgumentException
  558                       ("Color map for TYPE_BYTE_BINARY " +
  559                        "must have no more than 16 entries");
  560               }
  561               raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
  562                                                   width, height, 1, bits, null);
  563               break;
  564   
  565           case TYPE_BYTE_INDEXED:
  566               raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  567                                                       width, height, 1, null);
  568               break;
  569           default:
  570               throw new IllegalArgumentException("Invalid image type (" +
  571                                                  imageType+").  Image type must"+
  572                                                  " be either TYPE_BYTE_BINARY or "+
  573                                                  " TYPE_BYTE_INDEXED");
  574           }
  575   
  576           if (!cm.isCompatibleRaster(raster)) {
  577               throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
  578           }
  579   
  580           colorModel = cm;
  581           this.imageType = imageType;
  582       }
  583   
  584       /**
  585        * Constructs a new <code>BufferedImage</code> with a specified
  586        * <code>ColorModel</code> and <code>Raster</code>.  If the number and
  587        * types of bands in the <code>SampleModel</code> of the
  588        * <code>Raster</code> do not match the number and types required by
  589        * the <code>ColorModel</code> to represent its color and alpha
  590        * components, a {@link RasterFormatException} is thrown.  This
  591        * method can multiply or divide the color <code>Raster</code> data by
  592        * alpha to match the <code>alphaPremultiplied</code> state
  593        * in the <code>ColorModel</code>.  Properties for this
  594        * <code>BufferedImage</code> can be established by passing
  595        * in a {@link Hashtable} of <code>String</code>/<code>Object</code>
  596        * pairs.
  597        * @param cm <code>ColorModel</code> for the new image
  598        * @param raster     <code>Raster</code> for the image data
  599        * @param isRasterPremultiplied   if <code>true</code>, the data in
  600        *                  the raster has been premultiplied with alpha.
  601        * @param properties <code>Hashtable</code> of
  602        *                  <code>String</code>/<code>Object</code> pairs.
  603        * @exception <code>RasterFormatException</code> if the number and
  604        * types of bands in the <code>SampleModel</code> of the
  605        * <code>Raster</code> do not match the number and types required by
  606        * the <code>ColorModel</code> to represent its color and alpha
  607        * components.
  608        * @exception <code>IllegalArgumentException</code> if
  609        *          <code>raster</code> is incompatible with <code>cm</code>
  610        * @see ColorModel
  611        * @see Raster
  612        * @see WritableRaster
  613        */
  614   
  615   
  616   /*
  617    *
  618    *  FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
  619    *  SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
  620    *
  621    */
  622       public BufferedImage (ColorModel cm,
  623                             WritableRaster raster,
  624                             boolean isRasterPremultiplied,
  625                             Hashtable<?,?> properties) {
  626   
  627           if (!cm.isCompatibleRaster(raster)) {
  628               throw new
  629                   IllegalArgumentException("Raster "+raster+
  630                                            " is incompatible with ColorModel "+
  631                                            cm);
  632           }
  633   
  634           if ((raster.minX != 0) || (raster.minY != 0)) {
  635               throw new
  636                   IllegalArgumentException("Raster "+raster+
  637                                            " has minX or minY not equal to zero: "
  638                                            + raster.minX + " " + raster.minY);
  639           }
  640   
  641           colorModel = cm;
  642           this.raster  = raster;
  643           this.properties = properties;
  644           int numBands = raster.getNumBands();
  645           boolean isAlphaPre = cm.isAlphaPremultiplied();
  646           ColorSpace cs;
  647   
  648           // Force the raster data alpha state to match the premultiplied
  649           // state in the color model
  650           coerceData(isRasterPremultiplied);
  651   
  652           SampleModel sm = raster.getSampleModel();
  653           cs = cm.getColorSpace();
  654           int csType = cs.getType();
  655           if (csType != ColorSpace.TYPE_RGB) {
  656               if (csType == ColorSpace.TYPE_GRAY
  657                   && cm instanceof ComponentColorModel) {
  658                   // Check if this might be a child raster (fix for bug 4240596)
  659                   if (sm instanceof ComponentSampleModel &&
  660                       ((ComponentSampleModel)sm).getPixelStride() != numBands) {
  661                       imageType = TYPE_CUSTOM;
  662                   } else if (raster instanceof ByteComponentRaster &&
  663                          raster.getNumBands() == 1 &&
  664                          cm.getComponentSize(0) == 8 &&
  665                          ((ByteComponentRaster)raster).getPixelStride() == 1) {
  666                       imageType = TYPE_BYTE_GRAY;
  667                   } else if (raster instanceof ShortComponentRaster &&
  668                          raster.getNumBands() == 1 &&
  669                          cm.getComponentSize(0) == 16 &&
  670                          ((ShortComponentRaster)raster).getPixelStride() == 1) {
  671                       imageType = TYPE_USHORT_GRAY;
  672                   }
  673               } else {
  674                   imageType = TYPE_CUSTOM;
  675               }
  676               return;
  677           }
  678   
  679           if ((raster instanceof IntegerComponentRaster) &&
  680               (numBands == 3 || numBands == 4)) {
  681               IntegerComponentRaster iraster =
  682                   (IntegerComponentRaster) raster;
  683               // Check if the raster params and the color model
  684               // are correct
  685               int pixSize = cm.getPixelSize();
  686               if (iraster.getPixelStride() == 1 &&
  687                   cm instanceof DirectColorModel  &&
  688                   (pixSize == 32 || pixSize == 24))
  689               {
  690                   // Now check on the DirectColorModel params
  691                   DirectColorModel dcm = (DirectColorModel) cm;
  692                   int rmask = dcm.getRedMask();
  693                   int gmask = dcm.getGreenMask();
  694                   int bmask = dcm.getBlueMask();
  695                   if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK &&
  696                       bmask == DCM_BLUE_MASK)
  697                   {
  698                       if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
  699                           imageType = (isAlphaPre
  700                                        ? TYPE_INT_ARGB_PRE
  701                                        : TYPE_INT_ARGB);
  702                       }
  703                       else {
  704                           // No Alpha
  705                           if (!dcm.hasAlpha()) {
  706                               imageType = TYPE_INT_RGB;
  707                           }
  708                       }
  709                   }   // if (dcm.getRedMask() == DCM_RED_MASK &&
  710                   else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK
  711                            && bmask == DCM_BGR_BLU_MASK) {
  712                       if (!dcm.hasAlpha()) {
  713                           imageType = TYPE_INT_BGR;
  714                       }
  715                   }  // if (rmask == DCM_BGR_RED_MASK &&
  716               }   // if (iraster.getPixelStride() == 1
  717           }   // ((raster instanceof IntegerComponentRaster) &&
  718           else if ((cm instanceof IndexColorModel) && (numBands == 1) &&
  719                    (!cm.hasAlpha() || !isAlphaPre))
  720           {
  721               IndexColorModel icm = (IndexColorModel) cm;
  722               int pixSize = icm.getPixelSize();
  723   
  724               if (raster instanceof BytePackedRaster) {
  725                   imageType = TYPE_BYTE_BINARY;
  726               }   // if (raster instanceof BytePackedRaster)
  727               else if (raster instanceof ByteComponentRaster) {
  728                   ByteComponentRaster braster = (ByteComponentRaster) raster;
  729                   if (braster.getPixelStride() == 1 && pixSize <= 8) {
  730                       imageType = TYPE_BYTE_INDEXED;
  731                   }
  732               }
  733           }   // else if (cm instanceof IndexColorModel) && (numBands == 1))
  734           else if ((raster instanceof ShortComponentRaster)
  735                    && (cm instanceof DirectColorModel)
  736                    && (numBands == 3)
  737                    && !cm.hasAlpha())
  738           {
  739               DirectColorModel dcm = (DirectColorModel) cm;
  740               if (dcm.getRedMask() == DCM_565_RED_MASK) {
  741                   if (dcm.getGreenMask() == DCM_565_GRN_MASK &&
  742                       dcm.getBlueMask()  == DCM_565_BLU_MASK) {
  743                       imageType = TYPE_USHORT_565_RGB;
  744                   }
  745               }
  746               else if (dcm.getRedMask() == DCM_555_RED_MASK) {
  747                   if (dcm.getGreenMask() == DCM_555_GRN_MASK &&
  748                       dcm.getBlueMask() == DCM_555_BLU_MASK) {
  749                       imageType = TYPE_USHORT_555_RGB;
  750                   }
  751               }
  752           }   // else if ((cm instanceof IndexColorModel) && (numBands == 1))
  753           else if ((raster instanceof ByteComponentRaster)
  754                    && (cm instanceof ComponentColorModel)
  755                    && (raster.getSampleModel() instanceof PixelInterleavedSampleModel)
  756                    && (numBands == 3 || numBands == 4))
  757           {
  758               ComponentColorModel ccm = (ComponentColorModel) cm;
  759               PixelInterleavedSampleModel csm =
  760                   (PixelInterleavedSampleModel)raster.getSampleModel();
  761               ByteComponentRaster braster = (ByteComponentRaster) raster;
  762               int[] offs = csm.getBandOffsets();
  763               if (ccm.getNumComponents() != numBands) {
  764                   throw new RasterFormatException("Number of components in "+
  765                                                   "ColorModel ("+
  766                                                   ccm.getNumComponents()+
  767                                                   ") does not match # in "+
  768                                                   " Raster ("+numBands+")");
  769               }
  770               int[] nBits = ccm.getComponentSize();
  771               boolean is8bit = true;
  772               for (int i=0; i < numBands; i++) {
  773                   if (nBits[i] != 8) {
  774                       is8bit = false;
  775                       break;
  776                   }
  777               }
  778               if (is8bit &&
  779                   offs[0] == numBands-1 &&
  780                   offs[1] == numBands-2 &&
  781                   offs[2] == numBands-3)
  782               {
  783                   if (numBands == 3) {
  784                       imageType = TYPE_3BYTE_BGR;
  785                   }
  786                   else if (offs[3] == 0) {
  787                       imageType = (isAlphaPre
  788                                    ? TYPE_4BYTE_ABGR_PRE
  789                                    : TYPE_4BYTE_ABGR);
  790                   }
  791               }
  792           }   // else if ((raster instanceof ByteComponentRaster) &&
  793       }
  794   
  795       /**
  796        * Returns the image type.  If it is not one of the known types,
  797        * TYPE_CUSTOM is returned.
  798        * @return the image type of this <code>BufferedImage</code>.
  799        * @see #TYPE_INT_RGB
  800        * @see #TYPE_INT_ARGB
  801        * @see #TYPE_INT_ARGB_PRE
  802        * @see #TYPE_INT_BGR
  803        * @see #TYPE_3BYTE_BGR
  804        * @see #TYPE_4BYTE_ABGR
  805        * @see #TYPE_4BYTE_ABGR_PRE
  806        * @see #TYPE_BYTE_GRAY
  807        * @see #TYPE_BYTE_BINARY
  808        * @see #TYPE_BYTE_INDEXED
  809        * @see #TYPE_USHORT_GRAY
  810        * @see #TYPE_USHORT_565_RGB
  811        * @see #TYPE_USHORT_555_RGB
  812        * @see #TYPE_CUSTOM
  813        */
  814       public int getType() {
  815           return imageType;
  816       }
  817   
  818       /**
  819        * Returns the <code>ColorModel</code>.
  820        * @return the <code>ColorModel</code> of this
  821        *  <code>BufferedImage</code>.
  822        */
  823       public ColorModel getColorModel() {
  824           return colorModel;
  825       }
  826   
  827       /**
  828        * Returns the {@link WritableRaster}.
  829        * @return the <code>WriteableRaster</code> of this
  830        *  <code>BufferedImage</code>.
  831        */
  832       public WritableRaster getRaster() {
  833           return raster;
  834       }
  835   
  836   
  837       /**
  838        * Returns a <code>WritableRaster</code> representing the alpha
  839        * channel for <code>BufferedImage</code> objects
  840        * with <code>ColorModel</code> objects that support a separate
  841        * spatial alpha channel, such as <code>ComponentColorModel</code> and
  842        * <code>DirectColorModel</code>.  Returns <code>null</code> if there
  843        * is no alpha channel associated with the <code>ColorModel</code> in
  844        * this image.  This method assumes that for all
  845        * <code>ColorModel</code> objects other than
  846        * <code>IndexColorModel</code>, if the <code>ColorModel</code>
  847        * supports alpha, there is a separate alpha channel
  848        * which is stored as the last band of image data.
  849        * If the image uses an <code>IndexColorModel</code> that
  850        * has alpha in the lookup table, this method returns
  851        * <code>null</code> since there is no spatially discrete alpha
  852        * channel.  This method creates a new
  853        * <code>WritableRaster</code>, but shares the data array.
  854        * @return a <code>WritableRaster</code> or <code>null</code> if this
  855        *          <code>BufferedImage</code> has no alpha channel associated
  856        *          with its <code>ColorModel</code>.
  857        */
  858       public WritableRaster getAlphaRaster() {
  859           return colorModel.getAlphaRaster(raster);
  860       }
  861   
  862       /**
  863        * Returns an integer pixel in the default RGB color model
  864        * (TYPE_INT_ARGB) and default sRGB colorspace.  Color
  865        * conversion takes place if this default model does not match
  866        * the image <code>ColorModel</code>.  There are only 8-bits of
  867        * precision for each color component in the returned data when using
  868        * this method.
  869        *
  870        * <p>
  871        *
  872        * An <code>ArrayOutOfBoundsException</code> may be thrown
  873        * if the coordinates are not in bounds.
  874        * However, explicit bounds checking is not guaranteed.
  875        *
  876        * @param x the X coordinate of the pixel from which to get
  877        *          the pixel in the default RGB color model and sRGB
  878        *          color space
  879        * @param y the Y coordinate of the pixel from which to get
  880        *          the pixel in the default RGB color model and sRGB
  881        *          color space
  882        * @return an integer pixel in the default RGB color model and
  883        *          default sRGB colorspace.
  884        * @see #setRGB(int, int, int)
  885        * @see #setRGB(int, int, int, int, int[], int, int)
  886        */
  887       public int getRGB(int x, int y) {
  888           return colorModel.getRGB(raster.getDataElements(x, y, null));
  889       }
  890   
  891       /**
  892        * Returns an array of integer pixels in the default RGB color model
  893        * (TYPE_INT_ARGB) and default sRGB color space,
  894        * from a portion of the image data.  Color conversion takes
  895        * place if the default model does not match the image
  896        * <code>ColorModel</code>.  There are only 8-bits of precision for
  897        * each color component in the returned data when
  898        * using this method.  With a specified coordinate (x,&nbsp;y) in the
  899        * image, the ARGB pixel can be accessed in this way:
  900        * </p>
  901        *
  902        * <pre>
  903        *    pixel   = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre>
  904        *
  905        * <p>
  906        *
  907        * An <code>ArrayOutOfBoundsException</code> may be thrown
  908        * if the region is not in bounds.
  909        * However, explicit bounds checking is not guaranteed.
  910        *
  911        * @param startX      the starting X coordinate
  912        * @param startY      the starting Y coordinate
  913        * @param w           width of region
  914        * @param h           height of region
  915        * @param rgbArray    if not <code>null</code>, the rgb pixels are
  916        *          written here
  917        * @param offset      offset into the <code>rgbArray</code>
  918        * @param scansize    scanline stride for the <code>rgbArray</code>
  919        * @return            array of RGB pixels.
  920        * @see #setRGB(int, int, int)
  921        * @see #setRGB(int, int, int, int, int[], int, int)
  922        */
  923       public int[] getRGB(int startX, int startY, int w, int h,
  924                           int[] rgbArray, int offset, int scansize) {
  925           int yoff  = offset;
  926           int off;
  927           Object data;
  928           int nbands = raster.getNumBands();
  929           int dataType = raster.getDataBuffer().getDataType();
  930           switch (dataType) {
  931           case DataBuffer.TYPE_BYTE:
  932               data = new byte[nbands];
  933               break;
  934           case DataBuffer.TYPE_USHORT:
  935               data = new short[nbands];
  936               break;
  937           case DataBuffer.TYPE_INT:
  938               data = new int[nbands];
  939               break;
  940           case DataBuffer.TYPE_FLOAT:
  941               data = new float[nbands];
  942               break;
  943           case DataBuffer.TYPE_DOUBLE:
  944               data = new double[nbands];
  945               break;
  946           default:
  947               throw new IllegalArgumentException("Unknown data buffer type: "+
  948                                                  dataType);
  949           }
  950   
  951           if (rgbArray == null) {
  952               rgbArray = new int[offset+h*scansize];
  953           }
  954   
  955           for (int y = startY; y < startY+h; y++, yoff+=scansize) {
  956               off = yoff;
  957               for (int x = startX; x < startX+w; x++) {
  958                   rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x,
  959                                                                           y,
  960                                                                           data));
  961               }
  962           }
  963   
  964           return rgbArray;
  965       }
  966   
  967   
  968       /**
  969        * Sets a pixel in this <code>BufferedImage</code> to the specified
  970        * RGB value. The pixel is assumed to be in the default RGB color
  971        * model, TYPE_INT_ARGB, and default sRGB color space.  For images
  972        * with an <code>IndexColorModel</code>, the index with the nearest
  973        * color is chosen.
  974        *
  975        * <p>
  976        *
  977        * An <code>ArrayOutOfBoundsException</code> may be thrown
  978        * if the coordinates are not in bounds.
  979        * However, explicit bounds checking is not guaranteed.
  980        *
  981        * @param x the X coordinate of the pixel to set
  982        * @param y the Y coordinate of the pixel to set
  983        * @param rgb the RGB value
  984        * @see #getRGB(int, int)
  985        * @see #getRGB(int, int, int, int, int[], int, int)
  986        */
  987       public synchronized void setRGB(int x, int y, int rgb) {
  988           raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
  989       }
  990   
  991       /**
  992        * Sets an array of integer pixels in the default RGB color model
  993        * (TYPE_INT_ARGB) and default sRGB color space,
  994        * into a portion of the image data.  Color conversion takes place
  995        * if the default model does not match the image
  996        * <code>ColorModel</code>.  There are only 8-bits of precision for
  997        * each color component in the returned data when
  998        * using this method.  With a specified coordinate (x,&nbsp;y) in the
  999        * this image, the ARGB pixel can be accessed in this way:
 1000        * <pre>
 1001        *    pixel   = rgbArray[offset + (y-startY)*scansize + (x-startX)];
 1002        * </pre>
 1003        * WARNING: No dithering takes place.
 1004        *
 1005        * <p>
 1006        *
 1007        * An <code>ArrayOutOfBoundsException</code> may be thrown
 1008        * if the region is not in bounds.
 1009        * However, explicit bounds checking is not guaranteed.
 1010        *
 1011        * @param startX      the starting X coordinate
 1012        * @param startY      the starting Y coordinate
 1013        * @param w           width of the region
 1014        * @param h           height of the region
 1015        * @param rgbArray    the rgb pixels
 1016        * @param offset      offset into the <code>rgbArray</code>
 1017        * @param scansize    scanline stride for the <code>rgbArray</code>
 1018        * @see #getRGB(int, int)
 1019        * @see #getRGB(int, int, int, int, int[], int, int)
 1020        */
 1021       public void setRGB(int startX, int startY, int w, int h,
 1022                           int[] rgbArray, int offset, int scansize) {
 1023           int yoff  = offset;
 1024           int off;
 1025           Object pixel = null;
 1026   
 1027           for (int y = startY; y < startY+h; y++, yoff+=scansize) {
 1028               off = yoff;
 1029               for (int x = startX; x < startX+w; x++) {
 1030                   pixel = colorModel.getDataElements(rgbArray[off++], pixel);
 1031                   raster.setDataElements(x, y, pixel);
 1032               }
 1033           }
 1034       }
 1035   
 1036   
 1037       /**
 1038        * Returns the width of the <code>BufferedImage</code>.
 1039        * @return the width of this <code>BufferedImage</code>
 1040        */
 1041       public int getWidth() {
 1042           return raster.getWidth();
 1043       }
 1044   
 1045       /**
 1046        * Returns the height of the <code>BufferedImage</code>.
 1047        * @return the height of this <code>BufferedImage</code>
 1048        */
 1049       public int getHeight() {
 1050           return raster.getHeight();
 1051       }
 1052   
 1053       /**
 1054        * Returns the width of the <code>BufferedImage</code>.
 1055        * @param observer ignored
 1056        * @return the width of this <code>BufferedImage</code>
 1057        */
 1058       public int getWidth(ImageObserver observer) {
 1059           return raster.getWidth();
 1060       }
 1061   
 1062       /**
 1063        * Returns the height of the <code>BufferedImage</code>.
 1064        * @param observer ignored
 1065        * @return the height of this <code>BufferedImage</code>
 1066        */
 1067       public int getHeight(ImageObserver observer) {
 1068           return raster.getHeight();
 1069       }
 1070   
 1071       /**
 1072        * Returns the object that produces the pixels for the image.
 1073        * @return the {@link ImageProducer} that is used to produce the
 1074        * pixels for this image.
 1075        * @see ImageProducer
 1076        */
 1077       public ImageProducer getSource() {
 1078           if (osis == null) {
 1079               if (properties == null) {
 1080                   properties = new Hashtable();
 1081               }
 1082               osis = new OffScreenImageSource(this, properties);
 1083           }
 1084           return osis;
 1085       }
 1086   
 1087   
 1088       /**
 1089        * Returns a property of the image by name.  Individual property names
 1090        * are defined by the various image formats.  If a property is not
 1091        * defined for a particular image, this method returns the
 1092        * <code>UndefinedProperty</code> field.  If the properties
 1093        * for this image are not yet known, then this method returns
 1094        * <code>null</code> and the <code>ImageObserver</code> object is
 1095        * notified later.  The property name "comment" should be used to
 1096        * store an optional comment that can be presented to the user as a
 1097        * description of the image, its source, or its author.
 1098        * @param name the property name
 1099        * @param observer the <code>ImageObserver</code> that receives
 1100        *  notification regarding image information
 1101        * @return an {@link Object} that is the property referred to by the
 1102        *          specified <code>name</code> or <code>null</code> if the
 1103        *          properties of this image are not yet known.
 1104        * @throws <code>NullPointerException</code> if the property name is null.
 1105        * @see ImageObserver
 1106        * @see java.awt.Image#UndefinedProperty
 1107        */
 1108       public Object getProperty(String name, ImageObserver observer) {
 1109           return getProperty(name);
 1110       }
 1111   
 1112       /**
 1113        * Returns a property of the image by name.
 1114        * @param name the property name
 1115        * @return an <code>Object</code> that is the property referred to by
 1116        *          the specified <code>name</code>.
 1117        * @throws <code>NullPointerException</code> if the property name is null.
 1118        */
 1119       public Object getProperty(String name) {
 1120           if (name == null) {
 1121               throw new NullPointerException("null property name is not allowed");
 1122           }
 1123           if (properties == null) {
 1124               return java.awt.Image.UndefinedProperty;
 1125           }
 1126           Object o = properties.get(name);
 1127           if (o == null) {
 1128               o = java.awt.Image.UndefinedProperty;
 1129           }
 1130           return o;
 1131       }
 1132   
 1133       /**
 1134        * This method returns a {@link Graphics2D}, but is here
 1135        * for backwards compatibility.  {@link #createGraphics() createGraphics} is more
 1136        * convenient, since it is declared to return a
 1137        * <code>Graphics2D</code>.
 1138        * @return a <code>Graphics2D</code>, which can be used to draw into
 1139        *          this image.
 1140        */
 1141       public java.awt.Graphics getGraphics() {
 1142           return createGraphics();
 1143       }
 1144   
 1145       /**
 1146        * Creates a <code>Graphics2D</code>, which can be used to draw into
 1147        * this <code>BufferedImage</code>.
 1148        * @return a <code>Graphics2D</code>, used for drawing into this
 1149        *          image.
 1150        */
 1151       public Graphics2D createGraphics() {
 1152           GraphicsEnvironment env =
 1153               GraphicsEnvironment.getLocalGraphicsEnvironment();
 1154           return env.createGraphics(this);
 1155       }
 1156   
 1157       /**
 1158        * Returns a subimage defined by a specified rectangular region.
 1159        * The returned <code>BufferedImage</code> shares the same
 1160        * data array as the original image.
 1161        * @param x the X coordinate of the upper-left corner of the
 1162        *          specified rectangular region
 1163        * @param y the Y coordinate of the upper-left corner of the
 1164        *          specified rectangular region
 1165        * @param w the width of the specified rectangular region
 1166        * @param h the height of the specified rectangular region
 1167        * @return a <code>BufferedImage</code> that is the subimage of this
 1168        *          <code>BufferedImage</code>.
 1169        * @exception <code>RasterFormatException</code> if the specified
 1170        * area is not contained within this <code>BufferedImage</code>.
 1171        */
 1172       public BufferedImage getSubimage (int x, int y, int w, int h) {
 1173           return new BufferedImage (colorModel,
 1174                                     raster.createWritableChild(x, y, w, h,
 1175                                                                0, 0, null),
 1176                                     colorModel.isAlphaPremultiplied(),
 1177                                     properties);
 1178       }
 1179   
 1180       /**
 1181        * Returns whether or not the alpha has been premultiplied.  It
 1182        * returns <code>false</code> if there is no alpha.
 1183        * @return <code>true</code> if the alpha has been premultiplied;
 1184        *          <code>false</code> otherwise.
 1185        */
 1186       public boolean isAlphaPremultiplied() {
 1187           return colorModel.isAlphaPremultiplied();
 1188       }
 1189   
 1190       /**
 1191        * Forces the data to match the state specified in the
 1192        * <code>isAlphaPremultiplied</code> variable.  It may multiply or
 1193        * divide the color raster data by alpha, or do nothing if the data is
 1194        * in the correct state.
 1195        * @param isAlphaPremultiplied <code>true</code> if the alpha has been
 1196        *          premultiplied; <code>false</code> otherwise.
 1197        */
 1198       public void coerceData (boolean isAlphaPremultiplied) {
 1199           if (colorModel.hasAlpha() &&
 1200               colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
 1201               // Make the color model do the conversion
 1202               colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
 1203           }
 1204       }
 1205   
 1206       /**
 1207        * Returns a <code>String</code> representation of this
 1208        * <code>BufferedImage</code> object and its values.
 1209        * @return a <code>String</code> representing this
 1210        *          <code>BufferedImage</code>.
 1211        */
 1212       public String toString() {
 1213           return "BufferedImage@"+Integer.toHexString(hashCode())
 1214               +": type = "+imageType
 1215               +" "+colorModel+" "+raster;
 1216       }
 1217   
 1218       /**
 1219        * Returns a {@link Vector} of {@link RenderedImage} objects that are
 1220        * the immediate sources, not the sources of these immediate sources,
 1221        * of image data for this <code>BufferedImage</code>.  This
 1222        * method returns <code>null</code> if the <code>BufferedImage</code>
 1223        * has no information about its immediate sources.  It returns an
 1224        * empty <code>Vector</code> if the <code>BufferedImage</code> has no
 1225        * immediate sources.
 1226        * @return a <code>Vector</code> containing immediate sources of
 1227        *          this <code>BufferedImage</code> object's image date, or
 1228        *          <code>null</code> if this <code>BufferedImage</code> has
 1229        *          no information about its immediate sources, or an empty
 1230        *          <code>Vector</code> if this <code>BufferedImage</code>
 1231        *          has no immediate sources.
 1232        */
 1233       public Vector<RenderedImage> getSources() {
 1234           return null;
 1235       }
 1236   
 1237       /**
 1238        * Returns an array of names recognized by
 1239        * {@link #getProperty(String) getProperty(String)}
 1240        * or <code>null</code>, if no property names are recognized.
 1241        * @return a <code>String</code> array containing all of the property
 1242        *          names that <code>getProperty(String)</code> recognizes;
 1243        *          or <code>null</code> if no property names are recognized.
 1244        */
 1245       public String[] getPropertyNames() {
 1246            return null;
 1247       }
 1248   
 1249       /**
 1250        * Returns the minimum x coordinate of this
 1251        * <code>BufferedImage</code>.  This is always zero.
 1252        * @return the minimum x coordinate of this
 1253        *          <code>BufferedImage</code>.
 1254        */
 1255       public int getMinX() {
 1256           return raster.getMinX();
 1257       }
 1258   
 1259       /**
 1260        * Returns the minimum y coordinate of this
 1261        * <code>BufferedImage</code>.  This is always zero.
 1262        * @return the minimum y coordinate of this
 1263        *          <code>BufferedImage</code>.
 1264        */
 1265       public int getMinY() {
 1266           return raster.getMinY();
 1267       }
 1268   
 1269       /**
 1270        * Returns the <code>SampleModel</code> associated with this
 1271        * <code>BufferedImage</code>.
 1272        * @return the <code>SampleModel</code> of this
 1273        *          <code>BufferedImage</code>.
 1274        */
 1275       public SampleModel getSampleModel() {
 1276           return raster.getSampleModel();
 1277       }
 1278   
 1279       /**
 1280        * Returns the number of tiles in the x direction.
 1281        * This is always one.
 1282        * @return the number of tiles in the x direction.
 1283        */
 1284       public int getNumXTiles() {
 1285           return 1;
 1286       }
 1287   
 1288       /**
 1289        * Returns the number of tiles in the y direction.
 1290        * This is always one.
 1291        * @return the number of tiles in the y direction.
 1292        */
 1293       public int getNumYTiles() {
 1294           return 1;
 1295       }
 1296   
 1297       /**
 1298        * Returns the minimum tile index in the x direction.
 1299        * This is always zero.
 1300        * @return the minimum tile index in the x direction.
 1301        */
 1302       public int getMinTileX() {
 1303           return 0;
 1304       }
 1305   
 1306       /**
 1307        * Returns the minimum tile index in the y direction.
 1308        * This is always zero.
 1309        * @return the mininum tile index in the y direction.
 1310        */
 1311       public int getMinTileY() {
 1312           return 0;
 1313       }
 1314   
 1315       /**
 1316        * Returns the tile width in pixels.
 1317        * @return the tile width in pixels.
 1318        */
 1319       public int getTileWidth() {
 1320          return raster.getWidth();
 1321       }
 1322   
 1323       /**
 1324        * Returns the tile height in pixels.
 1325        * @return the tile height in pixels.
 1326        */
 1327       public int getTileHeight() {
 1328          return raster.getHeight();
 1329       }
 1330   
 1331       /**
 1332        * Returns the x offset of the tile grid relative to the origin,
 1333        * For example, the x coordinate of the location of tile
 1334        * (0,&nbsp;0).  This is always zero.
 1335        * @return the x offset of the tile grid.
 1336        */
 1337       public int getTileGridXOffset() {
 1338           return raster.getSampleModelTranslateX();
 1339       }
 1340   
 1341       /**
 1342        * Returns the y offset of the tile grid relative to the origin,
 1343        * For example, the y coordinate of the location of tile
 1344        * (0,&nbsp;0).  This is always zero.
 1345        * @return the y offset of the tile grid.
 1346        */
 1347       public int getTileGridYOffset() {
 1348           return raster.getSampleModelTranslateY();
 1349       }
 1350   
 1351       /**
 1352        * Returns tile (<code>tileX</code>,&nbsp;<code>tileY</code>).  Note
 1353        * that <code>tileX</code> and <code>tileY</code> are indices
 1354        * into the tile array, not pixel locations.  The <code>Raster</code>
 1355        * that is returned is live, which means that it is updated if the
 1356        * image is changed.
 1357        * @param tileX the x index of the requested tile in the tile array
 1358        * @param tileY the y index of the requested tile in the tile array
 1359        * @return a <code>Raster</code> that is the tile defined by the
 1360        *          arguments <code>tileX</code> and <code>tileY</code>.
 1361        * @exception <code>ArrayIndexOutOfBoundsException</code> if both
 1362        *          <code>tileX</code> and <code>tileY</code> are not
 1363        *          equal to 0
 1364        */
 1365       public Raster getTile(int tileX, int tileY) {
 1366           if (tileX == 0 && tileY == 0) {
 1367               return raster;
 1368           }
 1369           throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
 1370                " one tile with index 0,0");
 1371       }
 1372   
 1373       /**
 1374        * Returns the image as one large tile.  The <code>Raster</code>
 1375        * returned is a copy of the image data is not updated if the
 1376        * image is changed.
 1377        * @return a <code>Raster</code> that is a copy of the image data.
 1378        * @see #setData(Raster)
 1379        */
 1380       public Raster getData() {
 1381   
 1382           // REMIND : this allocates a whole new tile if raster is a
 1383           // subtile.  (It only copies in the requested area)
 1384           // We should do something smarter.
 1385           int width = raster.getWidth();
 1386           int height = raster.getHeight();
 1387           int startX = raster.getMinX();
 1388           int startY = raster.getMinY();
 1389           WritableRaster wr =
 1390              Raster.createWritableRaster(raster.getSampleModel(),
 1391                            new Point(raster.getSampleModelTranslateX(),
 1392                                      raster.getSampleModelTranslateY()));
 1393   
 1394           Object tdata = null;
 1395   
 1396           for (int i = startY; i < startY+height; i++)  {
 1397               tdata = raster.getDataElements(startX,i,width,1,tdata);
 1398               wr.setDataElements(startX,i,width,1, tdata);
 1399           }
 1400           return wr;
 1401       }
 1402   
 1403       /**
 1404        * Computes and returns an arbitrary region of the
 1405        * <code>BufferedImage</code>.  The <code>Raster</code> returned is a
 1406        * copy of the image data and is not updated if the image is
 1407        * changed.
 1408        * @param rect the region of the <code>BufferedImage</code> to be
 1409        * returned.
 1410        * @return a <code>Raster</code> that is a copy of the image data of
 1411        *          the specified region of the <code>BufferedImage</code>
 1412        * @see #setData(Raster)
 1413        */
 1414       public Raster getData(Rectangle rect) {
 1415           SampleModel sm = raster.getSampleModel();
 1416           SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
 1417                                                            rect.height);
 1418           WritableRaster wr = Raster.createWritableRaster(nsm,
 1419                                                     rect.getLocation());
 1420           int width = rect.width;
 1421           int height = rect.height;
 1422           int startX = rect.x;
 1423           int startY = rect.y;
 1424   
 1425           Object tdata = null;
 1426   
 1427           for (int i = startY; i < startY+height; i++)  {
 1428               tdata = raster.getDataElements(startX,i,width,1,tdata);
 1429               wr.setDataElements(startX,i,width,1, tdata);
 1430           }
 1431           return wr;
 1432       }
 1433   
 1434       /**
 1435        * Computes an arbitrary rectangular region of the
 1436        * <code>BufferedImage</code> and copies it into a specified
 1437        * <code>WritableRaster</code>.  The region to be computed is
 1438        * determined from the bounds of the specified
 1439        * <code>WritableRaster</code>.  The specified
 1440        * <code>WritableRaster</code> must have a
 1441        * <code>SampleModel</code> that is compatible with this image.  If
 1442        * <code>outRaster</code> is <code>null</code>,
 1443        * an appropriate <code>WritableRaster</code> is created.
 1444        * @param outRaster a <code>WritableRaster</code> to hold the returned
 1445        *          part of the image, or <code>null</code>
 1446        * @return a reference to the supplied or created
 1447        *          <code>WritableRaster</code>.
 1448        */
 1449       public WritableRaster copyData(WritableRaster outRaster) {
 1450           if (outRaster == null) {
 1451               return (WritableRaster) getData();
 1452           }
 1453           int width = outRaster.getWidth();
 1454           int height = outRaster.getHeight();
 1455           int startX = outRaster.getMinX();
 1456           int startY = outRaster.getMinY();
 1457   
 1458           Object tdata = null;
 1459   
 1460           for (int i = startY; i < startY+height; i++)  {
 1461               tdata = raster.getDataElements(startX,i,width,1,tdata);
 1462               outRaster.setDataElements(startX,i,width,1, tdata);
 1463           }
 1464   
 1465           return outRaster;
 1466       }
 1467   
 1468     /**
 1469        * Sets a rectangular region of the image to the contents of the
 1470        * specified <code>Raster</code> <code>r</code>, which is
 1471        * assumed to be in the same coordinate space as the
 1472        * <code>BufferedImage</code>. The operation is clipped to the bounds
 1473        * of the <code>BufferedImage</code>.
 1474        * @param r the specified <code>Raster</code>
 1475        * @see #getData
 1476        * @see #getData(Rectangle)
 1477       */
 1478       public void setData(Raster r) {
 1479           int width = r.getWidth();
 1480           int height = r.getHeight();
 1481           int startX = r.getMinX();
 1482           int startY = r.getMinY();
 1483   
 1484           int[] tdata = null;
 1485   
 1486           // Clip to the current Raster
 1487           Rectangle rclip = new Rectangle(startX, startY, width, height);
 1488           Rectangle bclip = new Rectangle(0, 0, raster.width, raster.height);
 1489           Rectangle intersect = rclip.intersection(bclip);
 1490           if (intersect.isEmpty()) {
 1491               return;
 1492           }
 1493           width = intersect.width;
 1494           height = intersect.height;
 1495           startX = intersect.x;
 1496           startY = intersect.y;
 1497   
 1498           // remind use get/setDataElements for speed if Rasters are
 1499           // compatible
 1500           for (int i = startY; i < startY+height; i++)  {
 1501               tdata = r.getPixels(startX,i,width,1,tdata);
 1502               raster.setPixels(startX,i,width,1, tdata);
 1503           }
 1504       }
 1505   
 1506   
 1507     /**
 1508      * Adds a tile observer.  If the observer is already present,
 1509      * it receives multiple notifications.
 1510      * @param to the specified {@link TileObserver}
 1511      */
 1512       public void addTileObserver (TileObserver to) {
 1513       }
 1514   
 1515     /**
 1516      * Removes a tile observer.  If the observer was not registered,
 1517      * nothing happens.  If the observer was registered for multiple
 1518      * notifications, it is now registered for one fewer notification.
 1519      * @param to the specified <code>TileObserver</code>.
 1520      */
 1521       public void removeTileObserver (TileObserver to) {
 1522       }
 1523   
 1524       /**
 1525        * Returns whether or not a tile is currently checked out for writing.
 1526        * @param tileX the x index of the tile.
 1527        * @param tileY the y index of the tile.
 1528        * @return <code>true</code> if the tile specified by the specified
 1529        *          indices is checked out for writing; <code>false</code>
 1530        *          otherwise.
 1531        * @exception <code>ArrayIndexOutOfBoundsException</code> if both
 1532        *          <code>tileX</code> and <code>tileY</code> are not equal
 1533        *          to 0
 1534        */
 1535       public boolean isTileWritable (int tileX, int tileY) {
 1536           if (tileX == 0 && tileY == 0) {
 1537               return true;
 1538           }
 1539           throw new IllegalArgumentException("Only 1 tile in image");
 1540       }
 1541   
 1542       /**
 1543        * Returns an array of {@link Point} objects indicating which tiles
 1544        * are checked out for writing.  Returns <code>null</code> if none are
 1545        * checked out.
 1546        * @return a <code>Point</code> array that indicates the tiles that
 1547        *          are checked out for writing, or <code>null</code> if no
 1548        *          tiles are checked out for writing.
 1549        */
 1550       public Point[] getWritableTileIndices() {
 1551           Point[] p = new Point[1];
 1552           p[0] = new Point(0, 0);
 1553   
 1554           return p;
 1555       }
 1556   
 1557       /**
 1558        * Returns whether or not any tile is checked out for writing.
 1559        * Semantically equivalent to
 1560        * <pre>
 1561        * (getWritableTileIndices() != null).
 1562        * </pre>
 1563        * @return <code>true</code> if any tile is checked out for writing;
 1564        *          <code>false</code> otherwise.
 1565        */
 1566       public boolean hasTileWriters () {
 1567           return true;
 1568       }
 1569   
 1570     /**
 1571      * Checks out a tile for writing.  All registered
 1572      * <code>TileObservers</code> are notified when a tile goes from having
 1573      * no writers to having one writer.
 1574      * @param tileX the x index of the tile
 1575      * @param tileY the y index of the tile
 1576      * @return a <code>WritableRaster</code> that is the tile, indicated by
 1577      *            the specified indices, to be checked out for writing.
 1578      */
 1579       public WritableRaster getWritableTile (int tileX, int tileY) {
 1580           return raster;
 1581       }
 1582   
 1583     /**
 1584      * Relinquishes permission to write to a tile.  If the caller
 1585      * continues to write to the tile, the results are undefined.
 1586      * Calls to this method should only appear in matching pairs
 1587      * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}.  Any other leads
 1588      * to undefined results.  All registered <code>TileObservers</code>
 1589      * are notified when a tile goes from having one writer to having no
 1590      * writers.
 1591      * @param tileX the x index of the tile
 1592      * @param tileY the y index of the tile
 1593      */
 1594       public void releaseWritableTile (int tileX, int tileY) {
 1595       }
 1596   
 1597       /**
 1598        * Returns the transparency.  Returns either OPAQUE, BITMASK,
 1599        * or TRANSLUCENT.
 1600        * @return the transparency of this <code>BufferedImage</code>.
 1601        * @see Transparency#OPAQUE
 1602        * @see Transparency#BITMASK
 1603        * @see Transparency#TRANSLUCENT
 1604        * @since 1.5
 1605        */
 1606       public int getTransparency() {
 1607           return colorModel.getTransparency();
 1608       }
 1609   }

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