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