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