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