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, 0, 0} and 230 * {255, 255, 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, 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, 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, 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, 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}, {@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 }