1 /* 2 * Copyright (c) 1995, 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.Transparency; 29 import java.awt.color.ColorSpace; 30 import java.math.BigInteger; 31 import java.util.Arrays; 32 import java.util.Objects; 33 34 /** 35 * The {@code IndexColorModel} class is a {@code ColorModel} 36 * class that works with pixel values consisting of a 37 * single sample that is an index into a fixed colormap in the default 38 * sRGB color space. The colormap specifies red, green, blue, and 39 * optional alpha components corresponding to each index. All components 40 * are represented in the colormap as 8-bit unsigned integral values. 41 * Some constructors allow the caller to specify "holes" in the colormap 42 * by indicating which colormap entries are valid and which represent 43 * unusable colors via the bits set in a {@code BigInteger} object. 44 * This color model is similar to an X11 PseudoColor visual. 45 * <p> 46 * Some constructors provide a means to specify an alpha component 47 * for each pixel in the colormap, while others either provide no 48 * such means or, in some cases, a flag to indicate whether the 49 * colormap data contains alpha values. If no alpha is supplied to 50 * the constructor, an opaque alpha component (alpha = 1.0) is 51 * assumed for each entry. 52 * An optional transparent pixel value can be supplied that indicates a 53 * pixel to be made completely transparent, regardless of any alpha 54 * component supplied or assumed for that pixel value. 55 * Note that the color components in the colormap of an 56 * {@code IndexColorModel} objects are never pre-multiplied with 57 * the alpha components. 58 * <p> 59 * <a name="transparency"> 60 * The transparency of an {@code IndexColorModel} object is 61 * determined by examining the alpha components of the colors in the 62 * colormap and choosing the most specific value after considering 63 * the optional alpha values and any transparent index specified. 64 * The transparency value is {@code Transparency.OPAQUE} 65 * only if all valid colors in 66 * the colormap are opaque and there is no valid transparent pixel. 67 * If all valid colors 68 * in the colormap are either completely opaque (alpha = 1.0) or 69 * completely transparent (alpha = 0.0), which typically occurs when 70 * a valid transparent pixel is specified, 71 * the value is {@code Transparency.BITMASK}. 72 * Otherwise, the value is {@code Transparency.TRANSLUCENT}, indicating 73 * that some valid color has an alpha component that is 74 * neither completely transparent nor completely opaque 75 * (0.0 < alpha < 1.0). 76 * </a> 77 * 78 * <p> 79 * If an {@code IndexColorModel} object has 80 * a transparency value of {@code Transparency.OPAQUE}, 81 * then the {@code hasAlpha} 82 * and {@code getNumComponents} methods 83 * (both inherited from {@code ColorModel}) 84 * return false and 3, respectively. 85 * For any other transparency value, 86 * {@code hasAlpha} returns true 87 * and {@code getNumComponents} returns 4. 88 * 89 * <p> 90 * <a name="index_values"> 91 * The values used to index into the colormap are taken from the least 92 * significant <em>n</em> bits of pixel representations where 93 * <em>n</em> is based on the pixel size specified in the constructor. 94 * For pixel sizes smaller than 8 bits, <em>n</em> is rounded up to a 95 * power of two (3 becomes 4 and 5,6,7 become 8). 96 * For pixel sizes between 8 and 16 bits, <em>n</em> is equal to the 97 * pixel size. 98 * Pixel sizes larger than 16 bits are not supported by this class. 99 * Higher order bits beyond <em>n</em> are ignored in pixel representations. 100 * Index values greater than or equal to the map size, but less than 101 * 2<sup><em>n</em></sup>, are undefined and return 0 for all color and 102 * alpha components. 103 * </a> 104 * <p> 105 * For those methods that use a primitive array pixel representation of 106 * type {@code transferType}, the array length is always one. 107 * The transfer types supported are {@code DataBuffer.TYPE_BYTE} and 108 * {@code DataBuffer.TYPE_USHORT}. A single int pixel 109 * representation is valid for all objects of this class, since it is 110 * always possible to represent pixel values used with this class in a 111 * single int. Therefore, methods that use this representation do 112 * not throw an {@code IllegalArgumentException} due to an invalid 113 * pixel value. 114 * <p> 115 * Many of the methods in this class are final. The reason for 116 * this is that the underlying native graphics code makes assumptions 117 * about the layout and operation of this class and those assumptions 118 * are reflected in the implementations of the methods here that are 119 * marked final. You can subclass this class for other reasons, but 120 * you cannot override or modify the behaviour of those methods. 121 * 122 * @see ColorModel 123 * @see ColorSpace 124 * @see DataBuffer 125 * 126 */ 127 public class IndexColorModel extends ColorModel { 128 private int rgb[]; 129 private int map_size; 130 private int pixel_mask; 131 private int transparent_index = -1; 132 private boolean allgrayopaque; 133 private BigInteger validBits; 134 private volatile int hashCode; 135 136 private sun.awt.image.BufImgSurfaceData.ICMColorData colorData = null; 137 138 private static int[] opaqueBits = {8, 8, 8}; 139 private static int[] alphaBits = {8, 8, 8, 8}; 140 141 private static native void initIDs(); 142 static { 143 ColorModel.loadLibraries(); 144 initIDs(); 145 } 146 /** 147 * Constructs an {@code IndexColorModel} from the specified 148 * arrays of red, green, and blue components. Pixels described 149 * by this color model all have alpha components of 255 150 * unnormalized (1.0 normalized), which means they 151 * are fully opaque. All of the arrays specifying the color 152 * components must have at least the specified number of entries. 153 * The {@code ColorSpace} is the default sRGB space. 154 * Since there is no alpha information in any of the arguments 155 * to this constructor, the transparency value is always 156 * {@code Transparency.OPAQUE}. 157 * The transfer type is the smallest of {@code DataBuffer.TYPE_BYTE} 158 * or {@code DataBuffer.TYPE_USHORT} that can hold a single pixel. 159 * @param bits the number of bits each pixel occupies 160 * @param size the size of the color component arrays 161 * @param r the array of red color components 162 * @param g the array of green color components 163 * @param b the array of blue color components 164 * @throws IllegalArgumentException if {@code bits} is less 165 * than 1 or greater than 16 166 * @throws IllegalArgumentException if {@code size} is less 167 * than 1 168 */ 169 public IndexColorModel(int bits, int size, 170 byte r[], byte g[], byte b[]) { 171 super(bits, opaqueBits, 172 ColorSpace.getInstance(ColorSpace.CS_sRGB), 173 false, false, OPAQUE, 174 ColorModel.getDefaultTransferType(bits)); 175 if (bits < 1 || bits > 16) { 176 throw new IllegalArgumentException("Number of bits must be between" 177 +" 1 and 16."); 178 } 179 setRGBs(size, r, g, b, null); 180 calculatePixelMask(); 181 } 182 183 /** 184 * Constructs an {@code IndexColorModel} from the given arrays 185 * of red, green, and blue components. Pixels described by this color 186 * model all have alpha components of 255 unnormalized 187 * (1.0 normalized), which means they are fully opaque, except 188 * for the indicated pixel to be made transparent. All of the arrays 189 * specifying the color components must have at least the specified 190 * number of entries. 191 * The {@code ColorSpace} is the default sRGB space. 192 * The transparency value may be {@code Transparency.OPAQUE} or 193 * {@code Transparency.BITMASK} depending on the arguments, as 194 * specified in the <a href="#transparency">class description</a> above. 195 * The transfer type is the smallest of {@code DataBuffer.TYPE_BYTE} 196 * or {@code DataBuffer.TYPE_USHORT} that can hold a 197 * single pixel. 198 * @param bits the number of bits each pixel occupies 199 * @param size the size of the color component arrays 200 * @param r the array of red color components 201 * @param g the array of green color components 202 * @param b the array of blue color components 203 * @param trans the index of the transparent pixel 204 * @throws IllegalArgumentException if {@code bits} is less than 205 * 1 or greater than 16 206 * @throws IllegalArgumentException if {@code size} is less than 207 * 1 208 */ 209 public IndexColorModel(int bits, int size, 210 byte r[], byte g[], byte b[], int trans) { 211 super(bits, opaqueBits, 212 ColorSpace.getInstance(ColorSpace.CS_sRGB), 213 false, false, OPAQUE, 214 ColorModel.getDefaultTransferType(bits)); 215 if (bits < 1 || bits > 16) { 216 throw new IllegalArgumentException("Number of bits must be between" 217 +" 1 and 16."); 218 } 219 setRGBs(size, r, g, b, null); 220 setTransparentPixel(trans); 221 calculatePixelMask(); 222 } 223 224 /** 225 * Constructs an {@code IndexColorModel} from the given 226 * arrays of red, green, blue and alpha components. All of the 227 * arrays specifying the components must have at least the specified 228 * number of entries. 229 * The {@code ColorSpace} is the default sRGB space. 230 * The transparency value may be any of {@code Transparency.OPAQUE}, 231 * {@code Transparency.BITMASK}, 232 * or {@code Transparency.TRANSLUCENT} 233 * depending on the arguments, as specified 234 * in the <a href="#transparency">class description</a> above. 235 * The transfer type is the smallest of {@code DataBuffer.TYPE_BYTE} 236 * or {@code DataBuffer.TYPE_USHORT} that can hold a single pixel. 237 * @param bits the number of bits each pixel occupies 238 * @param size the size of the color component arrays 239 * @param r the array of red color components 240 * @param g the array of green color components 241 * @param b the array of blue color components 242 * @param a the array of alpha value components 243 * @throws IllegalArgumentException if {@code bits} is less 244 * than 1 or greater than 16 245 * @throws IllegalArgumentException if {@code size} is less 246 * than 1 247 */ 248 public IndexColorModel(int bits, int size, 249 byte r[], byte g[], byte b[], byte a[]) { 250 super (bits, alphaBits, 251 ColorSpace.getInstance(ColorSpace.CS_sRGB), 252 true, false, TRANSLUCENT, 253 ColorModel.getDefaultTransferType(bits)); 254 if (bits < 1 || bits > 16) { 255 throw new IllegalArgumentException("Number of bits must be between" 256 +" 1 and 16."); 257 } 258 setRGBs (size, r, g, b, a); 259 calculatePixelMask(); 260 } 261 262 /** 263 * Constructs an {@code IndexColorModel} from a single 264 * array of interleaved red, green, blue and optional alpha 265 * components. The array must have enough values in it to 266 * fill all of the needed component arrays of the specified 267 * size. The {@code ColorSpace} is the default sRGB space. 268 * The transparency value may be any of {@code Transparency.OPAQUE}, 269 * {@code Transparency.BITMASK}, 270 * or {@code Transparency.TRANSLUCENT} 271 * depending on the arguments, as specified 272 * in the <a href="#transparency">class description</a> above. 273 * The transfer type is the smallest of 274 * {@code DataBuffer.TYPE_BYTE} or {@code DataBuffer.TYPE_USHORT} 275 * that can hold a single pixel. 276 * 277 * @param bits the number of bits each pixel occupies 278 * @param size the size of the color component arrays 279 * @param cmap the array of color components 280 * @param start the starting offset of the first color component 281 * @param hasalpha indicates whether alpha values are contained in 282 * the {@code cmap} array 283 * @throws IllegalArgumentException if {@code bits} is less 284 * than 1 or greater than 16 285 * @throws IllegalArgumentException if {@code size} is less 286 * than 1 287 */ 288 public IndexColorModel(int bits, int size, byte cmap[], int start, 289 boolean hasalpha) { 290 this(bits, size, cmap, start, hasalpha, -1); 291 if (bits < 1 || bits > 16) { 292 throw new IllegalArgumentException("Number of bits must be between" 293 +" 1 and 16."); 294 } 295 } 296 297 /** 298 * Constructs an {@code IndexColorModel} from a single array of 299 * interleaved red, green, blue and optional alpha components. The 300 * specified transparent index represents a pixel that is made 301 * entirely transparent regardless of any alpha value specified 302 * for it. The array must have enough values in it to fill all 303 * of the needed component arrays of the specified size. 304 * The {@code ColorSpace} is the default sRGB space. 305 * The transparency value may be any of {@code Transparency.OPAQUE}, 306 * {@code Transparency.BITMASK}, 307 * or {@code Transparency.TRANSLUCENT} 308 * depending on the arguments, as specified 309 * in the <a href="#transparency">class description</a> above. 310 * The transfer type is the smallest of 311 * {@code DataBuffer.TYPE_BYTE} or {@code DataBuffer.TYPE_USHORT} 312 * that can hold a single pixel. 313 * @param bits the number of bits each pixel occupies 314 * @param size the size of the color component arrays 315 * @param cmap the array of color components 316 * @param start the starting offset of the first color component 317 * @param hasalpha indicates whether alpha values are contained in 318 * the {@code cmap} array 319 * @param trans the index of the fully transparent pixel 320 * @throws IllegalArgumentException if {@code bits} is less than 321 * 1 or greater than 16 322 * @throws IllegalArgumentException if {@code size} is less than 323 * 1 324 */ 325 public IndexColorModel(int bits, int size, byte cmap[], int start, 326 boolean hasalpha, int trans) { 327 // REMIND: This assumes the ordering: RGB[A] 328 super(bits, opaqueBits, 329 ColorSpace.getInstance(ColorSpace.CS_sRGB), 330 false, false, OPAQUE, 331 ColorModel.getDefaultTransferType(bits)); 332 333 if (bits < 1 || bits > 16) { 334 throw new IllegalArgumentException("Number of bits must be between" 335 +" 1 and 16."); 336 } 337 if (size < 1) { 338 throw new IllegalArgumentException("Map size ("+size+ 339 ") must be >= 1"); 340 } 341 map_size = size; 342 rgb = new int[calcRealMapSize(bits, size)]; 343 int j = start; 344 int alpha = 0xff; 345 boolean allgray = true; 346 int transparency = OPAQUE; 347 for (int i = 0; i < size; i++) { 348 int r = cmap[j++] & 0xff; 349 int g = cmap[j++] & 0xff; 350 int b = cmap[j++] & 0xff; 351 allgray = allgray && (r == g) && (g == b); 352 if (hasalpha) { 353 alpha = cmap[j++] & 0xff; 354 if (alpha != 0xff) { 355 if (alpha == 0x00) { 356 if (transparency == OPAQUE) { 357 transparency = BITMASK; 358 } 359 if (transparent_index < 0) { 360 transparent_index = i; 361 } 362 } else { 363 transparency = TRANSLUCENT; 364 } 365 allgray = false; 366 } 367 } 368 rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b; 369 } 370 this.allgrayopaque = allgray; 371 setTransparency(transparency); 372 setTransparentPixel(trans); 373 calculatePixelMask(); 374 } 375 376 /** 377 * Constructs an {@code IndexColorModel} from an array of 378 * ints where each int is comprised of red, green, blue, and 379 * optional alpha components in the default RGB color model format. 380 * The specified transparent index represents a pixel that is made 381 * entirely transparent regardless of any alpha value specified 382 * for it. The array must have enough values in it to fill all 383 * of the needed component arrays of the specified size. 384 * The {@code ColorSpace} is the default sRGB space. 385 * The transparency value may be any of {@code Transparency.OPAQUE}, 386 * {@code Transparency.BITMASK}, 387 * or {@code Transparency.TRANSLUCENT} 388 * depending on the arguments, as specified 389 * in the <a href="#transparency">class description</a> above. 390 * @param bits the number of bits each pixel occupies 391 * @param size the size of the color component arrays 392 * @param cmap the array of color components 393 * @param start the starting offset of the first color component 394 * @param hasalpha indicates whether alpha values are contained in 395 * the {@code cmap} array 396 * @param trans the index of the fully transparent pixel 397 * @param transferType the data type of the array used to represent 398 * pixel values. The data type must be either 399 * {@code DataBuffer.TYPE_BYTE} or 400 * {@code DataBuffer.TYPE_USHORT}. 401 * @throws IllegalArgumentException if {@code bits} is less 402 * than 1 or greater than 16 403 * @throws IllegalArgumentException if {@code size} is less 404 * than 1 405 * @throws IllegalArgumentException if {@code transferType} is not 406 * one of {@code DataBuffer.TYPE_BYTE} or 407 * {@code DataBuffer.TYPE_USHORT} 408 */ 409 public IndexColorModel(int bits, int size, 410 int cmap[], int start, 411 boolean hasalpha, int trans, int transferType) { 412 // REMIND: This assumes the ordering: RGB[A] 413 super(bits, opaqueBits, 414 ColorSpace.getInstance(ColorSpace.CS_sRGB), 415 false, false, OPAQUE, 416 transferType); 417 418 if (bits < 1 || bits > 16) { 419 throw new IllegalArgumentException("Number of bits must be between" 420 +" 1 and 16."); 421 } 422 if (size < 1) { 423 throw new IllegalArgumentException("Map size ("+size+ 424 ") must be >= 1"); 425 } 426 if ((transferType != DataBuffer.TYPE_BYTE) && 427 (transferType != DataBuffer.TYPE_USHORT)) { 428 throw new IllegalArgumentException("transferType must be either" + 429 "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); 430 } 431 432 setRGBs(size, cmap, start, hasalpha); 433 setTransparentPixel(trans); 434 calculatePixelMask(); 435 } 436 437 /** 438 * Constructs an {@code IndexColorModel} from an 439 * {@code int} array where each {@code int} is 440 * comprised of red, green, blue, and alpha 441 * components in the default RGB color model format. 442 * The array must have enough values in it to fill all 443 * of the needed component arrays of the specified size. 444 * The {@code ColorSpace} is the default sRGB space. 445 * The transparency value may be any of {@code Transparency.OPAQUE}, 446 * {@code Transparency.BITMASK}, 447 * or {@code Transparency.TRANSLUCENT} 448 * depending on the arguments, as specified 449 * in the <a href="#transparency">class description</a> above. 450 * The transfer type must be one of {@code DataBuffer.TYPE_BYTE} 451 * {@code DataBuffer.TYPE_USHORT}. 452 * The {@code BigInteger} object specifies the valid/invalid pixels 453 * in the {@code cmap} array. A pixel is valid if the 454 * {@code BigInteger} value at that index is set, and is invalid 455 * if the {@code BigInteger} bit at that index is not set. 456 * @param bits the number of bits each pixel occupies 457 * @param size the size of the color component array 458 * @param cmap the array of color components 459 * @param start the starting offset of the first color component 460 * @param transferType the specified data type 461 * @param validBits a {@code BigInteger} object. If a bit is 462 * set in the BigInteger, the pixel at that index is valid. 463 * If a bit is not set, the pixel at that index 464 * is considered invalid. If null, all pixels are valid. 465 * Only bits from 0 to the map size are considered. 466 * @throws IllegalArgumentException if {@code bits} is less 467 * than 1 or greater than 16 468 * @throws IllegalArgumentException if {@code size} is less 469 * than 1 470 * @throws IllegalArgumentException if {@code transferType} is not 471 * one of {@code DataBuffer.TYPE_BYTE} or 472 * {@code DataBuffer.TYPE_USHORT} 473 * 474 * @since 1.3 475 */ 476 public IndexColorModel(int bits, int size, int cmap[], int start, 477 int transferType, BigInteger validBits) { 478 super (bits, alphaBits, 479 ColorSpace.getInstance(ColorSpace.CS_sRGB), 480 true, false, TRANSLUCENT, 481 transferType); 482 483 if (bits < 1 || bits > 16) { 484 throw new IllegalArgumentException("Number of bits must be between" 485 +" 1 and 16."); 486 } 487 if (size < 1) { 488 throw new IllegalArgumentException("Map size ("+size+ 489 ") must be >= 1"); 490 } 491 if ((transferType != DataBuffer.TYPE_BYTE) && 492 (transferType != DataBuffer.TYPE_USHORT)) { 493 throw new IllegalArgumentException("transferType must be either" + 494 "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); 495 } 496 497 if (validBits != null) { 498 // Check to see if it is all valid 499 for (int i=0; i < size; i++) { 500 if (!validBits.testBit(i)) { 501 this.validBits = validBits; 502 break; 503 } 504 } 505 } 506 507 setRGBs(size, cmap, start, true); 508 calculatePixelMask(); 509 } 510 511 private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) { 512 if (size < 1) { 513 throw new IllegalArgumentException("Map size ("+size+ 514 ") must be >= 1"); 515 } 516 map_size = size; 517 rgb = new int[calcRealMapSize(pixel_bits, size)]; 518 int alpha = 0xff; 519 int transparency = OPAQUE; 520 boolean allgray = true; 521 for (int i = 0; i < size; i++) { 522 int rc = r[i] & 0xff; 523 int gc = g[i] & 0xff; 524 int bc = b[i] & 0xff; 525 allgray = allgray && (rc == gc) && (gc == bc); 526 if (a != null) { 527 alpha = a[i] & 0xff; 528 if (alpha != 0xff) { 529 if (alpha == 0x00) { 530 if (transparency == OPAQUE) { 531 transparency = BITMASK; 532 } 533 if (transparent_index < 0) { 534 transparent_index = i; 535 } 536 } else { 537 transparency = TRANSLUCENT; 538 } 539 allgray = false; 540 } 541 } 542 rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc; 543 } 544 this.allgrayopaque = allgray; 545 setTransparency(transparency); 546 } 547 548 private void setRGBs(int size, int cmap[], int start, boolean hasalpha) { 549 map_size = size; 550 rgb = new int[calcRealMapSize(pixel_bits, size)]; 551 int j = start; 552 int transparency = OPAQUE; 553 boolean allgray = true; 554 BigInteger validBits = this.validBits; 555 for (int i = 0; i < size; i++, j++) { 556 if (validBits != null && !validBits.testBit(i)) { 557 continue; 558 } 559 int cmaprgb = cmap[j]; 560 int r = (cmaprgb >> 16) & 0xff; 561 int g = (cmaprgb >> 8) & 0xff; 562 int b = (cmaprgb ) & 0xff; 563 allgray = allgray && (r == g) && (g == b); 564 if (hasalpha) { 565 int alpha = cmaprgb >>> 24; 566 if (alpha != 0xff) { 567 if (alpha == 0x00) { 568 if (transparency == OPAQUE) { 569 transparency = BITMASK; 570 } 571 if (transparent_index < 0) { 572 transparent_index = i; 573 } 574 } else { 575 transparency = TRANSLUCENT; 576 } 577 allgray = false; 578 } 579 } else { 580 cmaprgb |= 0xff000000; 581 } 582 rgb[i] = cmaprgb; 583 } 584 this.allgrayopaque = allgray; 585 setTransparency(transparency); 586 } 587 588 private int calcRealMapSize(int bits, int size) { 589 int newSize = Math.max(1 << bits, size); 590 return Math.max(newSize, 256); 591 } 592 593 private BigInteger getAllValid() { 594 int numbytes = (map_size+7)/8; 595 byte[] valid = new byte[numbytes]; 596 java.util.Arrays.fill(valid, (byte)0xff); 597 valid[0] = (byte)(0xff >>> (numbytes*8 - map_size)); 598 599 return new BigInteger(1, valid); 600 } 601 602 /** 603 * Returns the transparency. Returns either OPAQUE, BITMASK, 604 * or TRANSLUCENT 605 * @return the transparency of this {@code IndexColorModel} 606 * @see Transparency#OPAQUE 607 * @see Transparency#BITMASK 608 * @see Transparency#TRANSLUCENT 609 */ 610 public int getTransparency() { 611 return transparency; 612 } 613 614 /** 615 * Returns an array of the number of bits for each color/alpha component. 616 * The array contains the color components in the order red, green, 617 * blue, followed by the alpha component, if present. 618 * @return an array containing the number of bits of each color 619 * and alpha component of this {@code IndexColorModel} 620 */ 621 public int[] getComponentSize() { 622 if (nBits == null) { 623 if (supportsAlpha) { 624 nBits = new int[4]; 625 nBits[3] = 8; 626 } 627 else { 628 nBits = new int[3]; 629 } 630 nBits[0] = nBits[1] = nBits[2] = 8; 631 } 632 return nBits.clone(); 633 } 634 635 /** 636 * Returns the size of the color/alpha component arrays in this 637 * {@code IndexColorModel}. 638 * @return the size of the color and alpha component arrays. 639 */ 640 public final int getMapSize() { 641 return map_size; 642 } 643 644 /** 645 * Returns the index of a transparent pixel in this 646 * {@code IndexColorModel} or -1 if there is no pixel 647 * with an alpha value of 0. If a transparent pixel was 648 * explicitly specified in one of the constructors by its 649 * index, then that index will be preferred, otherwise, 650 * the index of any pixel which happens to be fully transparent 651 * may be returned. 652 * @return the index of a transparent pixel in this 653 * {@code IndexColorModel} object, or -1 if there 654 * is no such pixel 655 */ 656 public final int getTransparentPixel() { 657 return transparent_index; 658 } 659 660 /** 661 * Copies the array of red color components into the specified array. 662 * Only the initial entries of the array as specified by 663 * {@link #getMapSize() getMapSize} are written. 664 * @param r the specified array into which the elements of the 665 * array of red color components are copied 666 */ 667 public final void getReds(byte r[]) { 668 for (int i = 0; i < map_size; i++) { 669 r[i] = (byte) (rgb[i] >> 16); 670 } 671 } 672 673 /** 674 * Copies the array of green color components into the specified array. 675 * Only the initial entries of the array as specified by 676 * {@code getMapSize} are written. 677 * @param g the specified array into which the elements of the 678 * array of green color components are copied 679 */ 680 public final void getGreens(byte g[]) { 681 for (int i = 0; i < map_size; i++) { 682 g[i] = (byte) (rgb[i] >> 8); 683 } 684 } 685 686 /** 687 * Copies the array of blue color components into the specified array. 688 * Only the initial entries of the array as specified by 689 * {@code getMapSize} are written. 690 * @param b the specified array into which the elements of the 691 * array of blue color components are copied 692 */ 693 public final void getBlues(byte b[]) { 694 for (int i = 0; i < map_size; i++) { 695 b[i] = (byte) rgb[i]; 696 } 697 } 698 699 /** 700 * Copies the array of alpha transparency components into the 701 * specified array. Only the initial entries of the array as specified 702 * by {@code getMapSize} are written. 703 * @param a the specified array into which the elements of the 704 * array of alpha components are copied 705 */ 706 public final void getAlphas(byte a[]) { 707 for (int i = 0; i < map_size; i++) { 708 a[i] = (byte) (rgb[i] >> 24); 709 } 710 } 711 712 /** 713 * Converts data for each index from the color and alpha component 714 * arrays to an int in the default RGB ColorModel format and copies 715 * the resulting 32-bit ARGB values into the specified array. Only 716 * the initial entries of the array as specified by 717 * {@code getMapSize} are 718 * written. 719 * @param rgb the specified array into which the converted ARGB 720 * values from this array of color and alpha components 721 * are copied. 722 */ 723 public final void getRGBs(int rgb[]) { 724 System.arraycopy(this.rgb, 0, rgb, 0, map_size); 725 } 726 727 private void setTransparentPixel(int trans) { 728 if (trans >= 0 && trans < map_size) { 729 rgb[trans] &= 0x00ffffff; 730 transparent_index = trans; 731 allgrayopaque = false; 732 if (this.transparency == OPAQUE) { 733 setTransparency(BITMASK); 734 } 735 } 736 } 737 738 private void setTransparency(int transparency) { 739 if (this.transparency != transparency) { 740 this.transparency = transparency; 741 if (transparency == OPAQUE) { 742 supportsAlpha = false; 743 numComponents = 3; 744 nBits = opaqueBits; 745 } else { 746 supportsAlpha = true; 747 numComponents = 4; 748 nBits = alphaBits; 749 } 750 } 751 } 752 753 /** 754 * This method is called from the constructors to set the pixel_mask 755 * value, which is based on the value of pixel_bits. The pixel_mask 756 * value is used to mask off the pixel parameters for methods such 757 * as getRed(), getGreen(), getBlue(), getAlpha(), and getRGB(). 758 */ 759 private final void calculatePixelMask() { 760 // Note that we adjust the mask so that our masking behavior here 761 // is consistent with that of our native rendering loops. 762 int maskbits = pixel_bits; 763 if (maskbits == 3) { 764 maskbits = 4; 765 } else if (maskbits > 4 && maskbits < 8) { 766 maskbits = 8; 767 } 768 pixel_mask = (1 << maskbits) - 1; 769 } 770 771 /** 772 * Returns the red color component for the specified pixel, scaled 773 * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value 774 * is specified as an int. 775 * Only the lower <em>n</em> bits of the pixel value, as specified in the 776 * <a href="#index_values">class description</a> above, are used to 777 * calculate the returned value. 778 * The returned value is a non pre-multiplied value. 779 * @param pixel the specified pixel 780 * @return the value of the red color component for the specified pixel 781 */ 782 public final int getRed(int pixel) { 783 return (rgb[pixel & pixel_mask] >> 16) & 0xff; 784 } 785 786 /** 787 * Returns the green color component for the specified pixel, scaled 788 * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value 789 * is specified as an int. 790 * Only the lower <em>n</em> bits of the pixel value, as specified in the 791 * <a href="#index_values">class description</a> above, are used to 792 * calculate the returned value. 793 * The returned value is a non pre-multiplied value. 794 * @param pixel the specified pixel 795 * @return the value of the green color component for the specified pixel 796 */ 797 public final int getGreen(int pixel) { 798 return (rgb[pixel & pixel_mask] >> 8) & 0xff; 799 } 800 801 /** 802 * Returns the blue color component for the specified pixel, scaled 803 * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value 804 * is specified as an int. 805 * Only the lower <em>n</em> bits of the pixel value, as specified in the 806 * <a href="#index_values">class description</a> above, are used to 807 * calculate the returned value. 808 * The returned value is a non pre-multiplied value. 809 * @param pixel the specified pixel 810 * @return the value of the blue color component for the specified pixel 811 */ 812 public final int getBlue(int pixel) { 813 return rgb[pixel & pixel_mask] & 0xff; 814 } 815 816 /** 817 * Returns the alpha component for the specified pixel, scaled 818 * from 0 to 255. The pixel value is specified as an int. 819 * Only the lower <em>n</em> bits of the pixel value, as specified in the 820 * <a href="#index_values">class description</a> above, are used to 821 * calculate the returned value. 822 * @param pixel the specified pixel 823 * @return the value of the alpha component for the specified pixel 824 */ 825 public final int getAlpha(int pixel) { 826 return (rgb[pixel & pixel_mask] >> 24) & 0xff; 827 } 828 829 /** 830 * Returns the color/alpha components of the pixel in the default 831 * RGB color model format. The pixel value is specified as an int. 832 * Only the lower <em>n</em> bits of the pixel value, as specified in the 833 * <a href="#index_values">class description</a> above, are used to 834 * calculate the returned value. 835 * The returned value is in a non pre-multiplied format. 836 * @param pixel the specified pixel 837 * @return the color and alpha components of the specified pixel 838 * @see ColorModel#getRGBdefault 839 */ 840 public final int getRGB(int pixel) { 841 return rgb[pixel & pixel_mask]; 842 } 843 844 private static final int CACHESIZE = 40; 845 private int lookupcache[] = new int[CACHESIZE]; 846 847 /** 848 * Returns a data element array representation of a pixel in this 849 * ColorModel, given an integer pixel representation in the 850 * default RGB color model. This array can then be passed to the 851 * {@link WritableRaster#setDataElements(int, int, java.lang.Object) setDataElements} 852 * method of a {@link WritableRaster} object. If the pixel variable is 853 * {@code null}, a new array is allocated. If {@code pixel} 854 * is not {@code null}, it must be 855 * a primitive array of type {@code transferType}; otherwise, a 856 * {@code ClassCastException} is thrown. An 857 * {@code ArrayIndexOutOfBoundsException} is 858 * thrown if {@code pixel} is not large enough to hold a pixel 859 * value for this {@code ColorModel}. The pixel array is returned. 860 * <p> 861 * Since {@code IndexColorModel} can be subclassed, subclasses 862 * inherit the implementation of this method and if they don't 863 * override it then they throw an exception if they use an 864 * unsupported {@code transferType}. 865 * 866 * @param rgb the integer pixel representation in the default RGB 867 * color model 868 * @param pixel the specified pixel 869 * @return an array representation of the specified pixel in this 870 * {@code IndexColorModel}. 871 * @throws ClassCastException if {@code pixel} 872 * is not a primitive array of type {@code transferType} 873 * @throws ArrayIndexOutOfBoundsException if 874 * {@code pixel} is not large enough to hold a pixel value 875 * for this {@code ColorModel} 876 * @throws UnsupportedOperationException if {@code transferType} 877 * is invalid 878 * @see WritableRaster#setDataElements 879 * @see SampleModel#setDataElements 880 */ 881 public synchronized Object getDataElements(int rgb, Object pixel) { 882 int red = (rgb>>16) & 0xff; 883 int green = (rgb>>8) & 0xff; 884 int blue = rgb & 0xff; 885 int alpha = (rgb>>>24); 886 int pix = 0; 887 888 // Note that pixels are stored at lookupcache[2*i] 889 // and the rgb that was searched is stored at 890 // lookupcache[2*i+1]. Also, the pixel is first 891 // inverted using the unary complement operator 892 // before storing in the cache so it can never be 0. 893 for (int i = CACHESIZE - 2; i >= 0; i -= 2) { 894 if ((pix = lookupcache[i]) == 0) { 895 break; 896 } 897 if (rgb == lookupcache[i+1]) { 898 return installpixel(pixel, ~pix); 899 } 900 } 901 902 if (allgrayopaque) { 903 // IndexColorModel objects are all tagged as 904 // non-premultiplied so ignore the alpha value 905 // of the incoming color, convert the 906 // non-premultiplied color components to a 907 // grayscale value and search for the closest 908 // gray value in the palette. Since all colors 909 // in the palette are gray, we only need compare 910 // to one of the color components for a match 911 // using a simple linear distance formula. 912 913 int minDist = 256; 914 int d; 915 int gray = (red*77 + green*150 + blue*29 + 128)/256; 916 917 for (int i = 0; i < map_size; i++) { 918 if (this.rgb[i] == 0x0) { 919 // For allgrayopaque colormaps, entries are 0 920 // iff they are an invalid color and should be 921 // ignored during color searches. 922 continue; 923 } 924 d = (this.rgb[i] & 0xff) - gray; 925 if (d < 0) d = -d; 926 if (d < minDist) { 927 pix = i; 928 if (d == 0) { 929 break; 930 } 931 minDist = d; 932 } 933 } 934 } else if (transparency == OPAQUE) { 935 // IndexColorModel objects are all tagged as 936 // non-premultiplied so ignore the alpha value 937 // of the incoming color and search for closest 938 // color match independently using a 3 component 939 // Euclidean distance formula. 940 // For opaque colormaps, palette entries are 0 941 // iff they are an invalid color and should be 942 // ignored during color searches. 943 // As an optimization, exact color searches are 944 // likely to be fairly common in opaque colormaps 945 // so first we will do a quick search for an 946 // exact match. 947 948 int smallestError = Integer.MAX_VALUE; 949 int lut[] = this.rgb; 950 int lutrgb; 951 for (int i=0; i < map_size; i++) { 952 lutrgb = lut[i]; 953 if (lutrgb == rgb && lutrgb != 0) { 954 pix = i; 955 smallestError = 0; 956 break; 957 } 958 } 959 960 if (smallestError != 0) { 961 for (int i=0; i < map_size; i++) { 962 lutrgb = lut[i]; 963 if (lutrgb == 0) { 964 continue; 965 } 966 967 int tmp = ((lutrgb >> 16) & 0xff) - red; 968 int currentError = tmp*tmp; 969 if (currentError < smallestError) { 970 tmp = ((lutrgb >> 8) & 0xff) - green; 971 currentError += tmp * tmp; 972 if (currentError < smallestError) { 973 tmp = (lutrgb & 0xff) - blue; 974 currentError += tmp * tmp; 975 if (currentError < smallestError) { 976 pix = i; 977 smallestError = currentError; 978 } 979 } 980 } 981 } 982 } 983 } else if (alpha == 0 && transparent_index >= 0) { 984 // Special case - transparent color maps to the 985 // specified transparent pixel, if there is one 986 987 pix = transparent_index; 988 } else { 989 // IndexColorModel objects are all tagged as 990 // non-premultiplied so use non-premultiplied 991 // color components in the distance calculations. 992 // Look for closest match using a 4 component 993 // Euclidean distance formula. 994 995 int smallestError = Integer.MAX_VALUE; 996 int lut[] = this.rgb; 997 for (int i=0; i < map_size; i++) { 998 int lutrgb = lut[i]; 999 if (lutrgb == rgb) { 1000 if (validBits != null && !validBits.testBit(i)) { 1001 continue; 1002 } 1003 pix = i; 1004 break; 1005 } 1006 1007 int tmp = ((lutrgb >> 16) & 0xff) - red; 1008 int currentError = tmp*tmp; 1009 if (currentError < smallestError) { 1010 tmp = ((lutrgb >> 8) & 0xff) - green; 1011 currentError += tmp * tmp; 1012 if (currentError < smallestError) { 1013 tmp = (lutrgb & 0xff) - blue; 1014 currentError += tmp * tmp; 1015 if (currentError < smallestError) { 1016 tmp = (lutrgb >>> 24) - alpha; 1017 currentError += tmp * tmp; 1018 if (currentError < smallestError && 1019 (validBits == null || validBits.testBit(i))) 1020 { 1021 pix = i; 1022 smallestError = currentError; 1023 } 1024 } 1025 } 1026 } 1027 } 1028 } 1029 System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2); 1030 lookupcache[CACHESIZE - 1] = rgb; 1031 lookupcache[CACHESIZE - 2] = ~pix; 1032 return installpixel(pixel, pix); 1033 } 1034 1035 private Object installpixel(Object pixel, int pix) { 1036 switch (transferType) { 1037 case DataBuffer.TYPE_INT: 1038 int[] intObj; 1039 if (pixel == null) { 1040 pixel = intObj = new int[1]; 1041 } else { 1042 intObj = (int[]) pixel; 1043 } 1044 intObj[0] = pix; 1045 break; 1046 case DataBuffer.TYPE_BYTE: 1047 byte[] byteObj; 1048 if (pixel == null) { 1049 pixel = byteObj = new byte[1]; 1050 } else { 1051 byteObj = (byte[]) pixel; 1052 } 1053 byteObj[0] = (byte) pix; 1054 break; 1055 case DataBuffer.TYPE_USHORT: 1056 short[] shortObj; 1057 if (pixel == null) { 1058 pixel = shortObj = new short[1]; 1059 } else { 1060 shortObj = (short[]) pixel; 1061 } 1062 shortObj[0] = (short) pix; 1063 break; 1064 default: 1065 throw new UnsupportedOperationException("This method has not been "+ 1066 "implemented for transferType " + transferType); 1067 } 1068 return pixel; 1069 } 1070 1071 /** 1072 * Returns an array of unnormalized color/alpha components for a 1073 * specified pixel in this {@code ColorModel}. The pixel value 1074 * is specified as an int. If the {@code components} array is {@code null}, 1075 * a new array is allocated that contains 1076 * {@code offset + getNumComponents()} elements. 1077 * The {@code components} array is returned, 1078 * with the alpha component included 1079 * only if {@code hasAlpha} returns true. 1080 * Color/alpha components are stored in the {@code components} array starting 1081 * at {@code offset} even if the array is allocated by this method. 1082 * An {@code ArrayIndexOutOfBoundsException} 1083 * is thrown if the {@code components} array is not {@code null} and is 1084 * not large enough to hold all the color and alpha components 1085 * starting at {@code offset}. 1086 * @param pixel the specified pixel 1087 * @param components the array to receive the color and alpha 1088 * components of the specified pixel 1089 * @param offset the offset into the {@code components} array at 1090 * which to start storing the color and alpha components 1091 * @return an array containing the color and alpha components of the 1092 * specified pixel starting at the specified offset. 1093 * @see ColorModel#hasAlpha 1094 * @see ColorModel#getNumComponents 1095 */ 1096 public int[] getComponents(int pixel, int[] components, int offset) { 1097 if (components == null) { 1098 components = new int[offset+numComponents]; 1099 } 1100 1101 // REMIND: Needs to change if different color space 1102 components[offset+0] = getRed(pixel); 1103 components[offset+1] = getGreen(pixel); 1104 components[offset+2] = getBlue(pixel); 1105 if (supportsAlpha && (components.length-offset) > 3) { 1106 components[offset+3] = getAlpha(pixel); 1107 } 1108 1109 return components; 1110 } 1111 1112 /** 1113 * Returns an array of unnormalized color/alpha components for 1114 * a specified pixel in this {@code ColorModel}. The pixel 1115 * value is specified by an array of data elements of type 1116 * {@code transferType} passed in as an object reference. 1117 * If {@code pixel} is not a primitive array of type 1118 * {@code transferType}, a {@code ClassCastException} 1119 * is thrown. An {@code ArrayIndexOutOfBoundsException} 1120 * is thrown if {@code pixel} is not large enough to hold 1121 * a pixel value for this {@code ColorModel}. If the 1122 * {@code components} array is {@code null}, a new array 1123 * is allocated that contains 1124 * {@code offset + getNumComponents()} elements. 1125 * The {@code components} array is returned, 1126 * with the alpha component included 1127 * only if {@code hasAlpha} returns true. 1128 * Color/alpha components are stored in the {@code components} 1129 * array starting at {@code offset} even if the array is 1130 * allocated by this method. An 1131 * {@code ArrayIndexOutOfBoundsException} is also 1132 * thrown if the {@code components} array is not 1133 * {@code null} and is not large enough to hold all the color 1134 * and alpha components starting at {@code offset}. 1135 * <p> 1136 * Since {@code IndexColorModel} can be subclassed, subclasses 1137 * inherit the implementation of this method and if they don't 1138 * override it then they throw an exception if they use an 1139 * unsupported {@code transferType}. 1140 * 1141 * @param pixel the specified pixel 1142 * @param components an array that receives the color and alpha 1143 * components of the specified pixel 1144 * @param offset the index into the {@code components} array at 1145 * which to begin storing the color and alpha components of the 1146 * specified pixel 1147 * @return an array containing the color and alpha components of the 1148 * specified pixel starting at the specified offset. 1149 * @throws ArrayIndexOutOfBoundsException if {@code pixel} 1150 * is not large enough to hold a pixel value for this 1151 * {@code ColorModel} or if the 1152 * {@code components} array is not {@code null} 1153 * and is not large enough to hold all the color 1154 * and alpha components starting at {@code offset} 1155 * @throws ClassCastException if {@code pixel} is not a 1156 * primitive array of type {@code transferType} 1157 * @throws UnsupportedOperationException if {@code transferType} 1158 * is not one of the supported transfer types 1159 * @see ColorModel#hasAlpha 1160 * @see ColorModel#getNumComponents 1161 */ 1162 public int[] getComponents(Object pixel, int[] components, int offset) { 1163 int intpixel; 1164 switch (transferType) { 1165 case DataBuffer.TYPE_BYTE: 1166 byte bdata[] = (byte[])pixel; 1167 intpixel = bdata[0] & 0xff; 1168 break; 1169 case DataBuffer.TYPE_USHORT: 1170 short sdata[] = (short[])pixel; 1171 intpixel = sdata[0] & 0xffff; 1172 break; 1173 case DataBuffer.TYPE_INT: 1174 int idata[] = (int[])pixel; 1175 intpixel = idata[0]; 1176 break; 1177 default: 1178 throw new UnsupportedOperationException("This method has not been "+ 1179 "implemented for transferType " + transferType); 1180 } 1181 return getComponents(intpixel, components, offset); 1182 } 1183 1184 /** 1185 * Returns a pixel value represented as an int in this 1186 * {@code ColorModel} given an array of unnormalized 1187 * color/alpha components. An 1188 * {@code ArrayIndexOutOfBoundsException} 1189 * is thrown if the {@code components} array is not large 1190 * enough to hold all of the color and alpha components starting 1191 * at {@code offset}. Since 1192 * {@code ColorModel} can be subclassed, subclasses inherit the 1193 * implementation of this method and if they don't override it then 1194 * they throw an exception if they use an unsupported transferType. 1195 * @param components an array of unnormalized color and alpha 1196 * components 1197 * @param offset the index into {@code components} at which to 1198 * begin retrieving the color and alpha components 1199 * @return an {@code int} pixel value in this 1200 * {@code ColorModel} corresponding to the specified components. 1201 * @throws ArrayIndexOutOfBoundsException if 1202 * the {@code components} array is not large enough to 1203 * hold all of the color and alpha components starting at 1204 * {@code offset} 1205 * @throws UnsupportedOperationException if {@code transferType} 1206 * is invalid 1207 */ 1208 public int getDataElement(int[] components, int offset) { 1209 int rgb = (components[offset+0]<<16) 1210 | (components[offset+1]<<8) | (components[offset+2]); 1211 if (supportsAlpha) { 1212 rgb |= (components[offset+3]<<24); 1213 } 1214 else { 1215 rgb |= 0xff000000; 1216 } 1217 Object inData = getDataElements(rgb, null); 1218 int pixel; 1219 switch (transferType) { 1220 case DataBuffer.TYPE_BYTE: 1221 byte bdata[] = (byte[])inData; 1222 pixel = bdata[0] & 0xff; 1223 break; 1224 case DataBuffer.TYPE_USHORT: 1225 short sdata[] = (short[])inData; 1226 pixel = sdata[0]; 1227 break; 1228 case DataBuffer.TYPE_INT: 1229 int idata[] = (int[])inData; 1230 pixel = idata[0]; 1231 break; 1232 default: 1233 throw new UnsupportedOperationException("This method has not been "+ 1234 "implemented for transferType " + transferType); 1235 } 1236 return pixel; 1237 } 1238 1239 /** 1240 * Returns a data element array representation of a pixel in this 1241 * {@code ColorModel} given an array of unnormalized color/alpha 1242 * components. This array can then be passed to the 1243 * {@code setDataElements} method of a {@code WritableRaster} 1244 * object. An {@code ArrayIndexOutOfBoundsException} is 1245 * thrown if the 1246 * {@code components} array is not large enough to hold all of the 1247 * color and alpha components starting at {@code offset}. 1248 * If the pixel variable is {@code null}, a new array 1249 * is allocated. If {@code pixel} is not {@code null}, 1250 * it must be a primitive array of type {@code transferType}; 1251 * otherwise, a {@code ClassCastException} is thrown. 1252 * An {@code ArrayIndexOutOfBoundsException} is thrown if pixel 1253 * is not large enough to hold a pixel value for this 1254 * {@code ColorModel}. 1255 * <p> 1256 * Since {@code IndexColorModel} can be subclassed, subclasses 1257 * inherit the implementation of this method and if they don't 1258 * override it then they throw an exception if they use an 1259 * unsupported {@code transferType} 1260 * 1261 * @param components an array of unnormalized color and alpha 1262 * components 1263 * @param offset the index into {@code components} at which to 1264 * begin retrieving color and alpha components 1265 * @param pixel the {@code Object} representing an array of color 1266 * and alpha components 1267 * @return an {@code Object} representing an array of color and 1268 * alpha components. 1269 * @throws ClassCastException if {@code pixel} 1270 * is not a primitive array of type {@code transferType} 1271 * @throws ArrayIndexOutOfBoundsException if 1272 * {@code pixel} is not large enough to hold a pixel value 1273 * for this {@code ColorModel} or the {@code components} 1274 * array is not large enough to hold all of the color and alpha 1275 * components starting at {@code offset} 1276 * @throws UnsupportedOperationException if {@code transferType} 1277 * is not one of the supported transfer types 1278 * @see WritableRaster#setDataElements 1279 * @see SampleModel#setDataElements 1280 */ 1281 public Object getDataElements(int[] components, int offset, Object pixel) { 1282 int rgb = (components[offset+0]<<16) | (components[offset+1]<<8) 1283 | (components[offset+2]); 1284 if (supportsAlpha) { 1285 rgb |= (components[offset+3]<<24); 1286 } 1287 else { 1288 rgb &= 0xff000000; 1289 } 1290 return getDataElements(rgb, pixel); 1291 } 1292 1293 /** 1294 * Creates a {@code WritableRaster} with the specified width 1295 * and height that has a data layout ({@code SampleModel}) 1296 * compatible with this {@code ColorModel}. This method 1297 * only works for color models with 16 or fewer bits per pixel. 1298 * <p> 1299 * Since {@code IndexColorModel} can be subclassed, any 1300 * subclass that supports greater than 16 bits per pixel must 1301 * override this method. 1302 * 1303 * @param w the width to apply to the new {@code WritableRaster} 1304 * @param h the height to apply to the new {@code WritableRaster} 1305 * @return a {@code WritableRaster} object with the specified 1306 * width and height. 1307 * @throws UnsupportedOperationException if the number of bits in a 1308 * pixel is greater than 16 1309 * @see WritableRaster 1310 * @see SampleModel 1311 */ 1312 public WritableRaster createCompatibleWritableRaster(int w, int h) { 1313 WritableRaster raster; 1314 1315 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { 1316 // TYPE_BINARY 1317 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, 1318 w, h, 1, pixel_bits, null); 1319 } 1320 else if (pixel_bits <= 8) { 1321 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1322 w,h,1,null); 1323 } 1324 else if (pixel_bits <= 16) { 1325 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, 1326 w,h,1,null); 1327 } 1328 else { 1329 throw new 1330 UnsupportedOperationException("This method is not supported "+ 1331 " for pixel bits > 16."); 1332 } 1333 return raster; 1334 } 1335 1336 /** 1337 * Returns {@code true} if {@code raster} is compatible 1338 * with this {@code ColorModel} or {@code false} if it 1339 * is not compatible with this {@code ColorModel}. 1340 * @param raster the {@link Raster} object to test for compatibility 1341 * @return {@code true} if {@code raster} is compatible 1342 * with this {@code ColorModel}; {@code false} otherwise. 1343 * 1344 */ 1345 public boolean isCompatibleRaster(Raster raster) { 1346 1347 int size = raster.getSampleModel().getSampleSize(0); 1348 return ((raster.getTransferType() == transferType) && 1349 (raster.getNumBands() == 1) && ((1 << size) >= map_size)); 1350 } 1351 1352 /** 1353 * Creates a {@code SampleModel} with the specified 1354 * width and height that has a data layout compatible with 1355 * this {@code ColorModel}. 1356 * @param w the width to apply to the new {@code SampleModel} 1357 * @param h the height to apply to the new {@code SampleModel} 1358 * @return a {@code SampleModel} object with the specified 1359 * width and height. 1360 * @throws IllegalArgumentException if {@code w} or 1361 * {@code h} is not greater than 0 1362 * @see SampleModel 1363 */ 1364 public SampleModel createCompatibleSampleModel(int w, int h) { 1365 int[] off = new int[1]; 1366 off[0] = 0; 1367 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { 1368 return new MultiPixelPackedSampleModel(transferType, w, h, 1369 pixel_bits); 1370 } 1371 else { 1372 return new ComponentSampleModel(transferType, w, h, 1, w, 1373 off); 1374 } 1375 } 1376 1377 /** 1378 * Checks if the specified {@code SampleModel} is compatible 1379 * with this {@code ColorModel}. If {@code sm} is 1380 * {@code null}, this method returns {@code false}. 1381 * @param sm the specified {@code SampleModel}, 1382 * or {@code null} 1383 * @return {@code true} if the specified {@code SampleModel} 1384 * is compatible with this {@code ColorModel}; {@code false} 1385 * otherwise. 1386 * @see SampleModel 1387 */ 1388 public boolean isCompatibleSampleModel(SampleModel sm) { 1389 // fix 4238629 1390 if (! (sm instanceof ComponentSampleModel) && 1391 ! (sm instanceof MultiPixelPackedSampleModel) ) { 1392 return false; 1393 } 1394 1395 // Transfer type must be the same 1396 if (sm.getTransferType() != transferType) { 1397 return false; 1398 } 1399 1400 if (sm.getNumBands() != 1) { 1401 return false; 1402 } 1403 1404 return true; 1405 } 1406 1407 /** 1408 * Returns a new {@code BufferedImage} of TYPE_INT_ARGB or 1409 * TYPE_INT_RGB that has a {@code Raster} with pixel data 1410 * computed by expanding the indices in the source {@code Raster} 1411 * using the color/alpha component arrays of this {@code ColorModel}. 1412 * Only the lower <em>n</em> bits of each index value in the source 1413 * {@code Raster}, as specified in the 1414 * <a href="#index_values">class description</a> above, are used to 1415 * compute the color/alpha values in the returned image. 1416 * If {@code forceARGB} is {@code true}, a TYPE_INT_ARGB image is 1417 * returned regardless of whether or not this {@code ColorModel} 1418 * has an alpha component array or a transparent pixel. 1419 * @param raster the specified {@code Raster} 1420 * @param forceARGB if {@code true}, the returned 1421 * {@code BufferedImage} is TYPE_INT_ARGB; otherwise it is 1422 * TYPE_INT_RGB 1423 * @return a {@code BufferedImage} created with the specified 1424 * {@code Raster} 1425 * @throws IllegalArgumentException if the raster argument is not 1426 * compatible with this IndexColorModel 1427 */ 1428 public BufferedImage convertToIntDiscrete(Raster raster, 1429 boolean forceARGB) { 1430 ColorModel cm; 1431 1432 if (!isCompatibleRaster(raster)) { 1433 throw new IllegalArgumentException("This raster is not compatible" + 1434 "with this IndexColorModel."); 1435 } 1436 if (forceARGB || transparency == TRANSLUCENT) { 1437 cm = ColorModel.getRGBdefault(); 1438 } 1439 else if (transparency == BITMASK) { 1440 cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff, 1441 0x1000000); 1442 } 1443 else { 1444 cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff); 1445 } 1446 1447 int w = raster.getWidth(); 1448 int h = raster.getHeight(); 1449 WritableRaster discreteRaster = 1450 cm.createCompatibleWritableRaster(w, h); 1451 Object obj = null; 1452 int[] data = null; 1453 1454 int rX = raster.getMinX(); 1455 int rY = raster.getMinY(); 1456 1457 for (int y=0; y < h; y++, rY++) { 1458 obj = raster.getDataElements(rX, rY, w, 1, obj); 1459 if (obj instanceof int[]) { 1460 data = (int[])obj; 1461 } else { 1462 data = DataBuffer.toIntArray(obj); 1463 } 1464 for (int x=0; x < w; x++) { 1465 data[x] = rgb[data[x] & pixel_mask]; 1466 } 1467 discreteRaster.setDataElements(0, y, w, 1, data); 1468 } 1469 1470 return new BufferedImage(cm, discreteRaster, false, null); 1471 } 1472 1473 /** 1474 * Returns whether or not the pixel is valid. 1475 * @param pixel the specified pixel value 1476 * @return {@code true} if {@code pixel} 1477 * is valid; {@code false} otherwise. 1478 * @since 1.3 1479 */ 1480 public boolean isValid(int pixel) { 1481 return ((pixel >= 0 && pixel < map_size) && 1482 (validBits == null || validBits.testBit(pixel))); 1483 } 1484 1485 /** 1486 * Returns whether or not all of the pixels are valid. 1487 * @return {@code true} if all pixels are valid; 1488 * {@code false} otherwise. 1489 * @since 1.3 1490 */ 1491 public boolean isValid() { 1492 return (validBits == null); 1493 } 1494 1495 /** 1496 * Returns a {@code BigInteger} that indicates the valid/invalid 1497 * pixels in the colormap. A bit is valid if the 1498 * {@code BigInteger} value at that index is set, and is invalid 1499 * if the {@code BigInteger} value at that index is not set. 1500 * The only valid ranges to query in the {@code BigInteger} are 1501 * between 0 and the map size. 1502 * @return a {@code BigInteger} indicating the valid/invalid pixels. 1503 * @since 1.3 1504 */ 1505 public BigInteger getValidPixels() { 1506 if (validBits == null) { 1507 return getAllValid(); 1508 } 1509 else { 1510 return validBits; 1511 } 1512 } 1513 1514 /** 1515 * Disposes of system resources associated with this 1516 * {@code ColorModel} once this {@code ColorModel} is no 1517 * longer referenced. 1518 */ 1519 public void finalize() { 1520 } 1521 1522 /** 1523 * Returns the {@code String} representation of the contents of 1524 * this {@code ColorModel} object. 1525 * @return a {@code String} representing the contents of this 1526 * {@code ColorModel} object. 1527 */ 1528 public String toString() { 1529 return new String("IndexColorModel: #pixelBits = "+pixel_bits 1530 + " numComponents = "+numComponents 1531 + " color space = "+colorSpace 1532 + " transparency = "+transparency 1533 + " transIndex = "+transparent_index 1534 + " has alpha = "+supportsAlpha 1535 + " isAlphaPre = "+isAlphaPremultiplied 1536 ); 1537 } 1538 1539 /** 1540 * Tests if the specified {@code Object} is an 1541 * instance of {@code IndexColorModel} 1542 * and if it equals this {@code IndexColorModel} 1543 * @param obj the {@code Object} to test for equality 1544 * @return {@code true} if the specified {@code Object} 1545 * equals this {@code IndexColorModel}; {@code false} otherwise. 1546 */ 1547 @Override 1548 public boolean equals(Object obj) { 1549 1550 if (!(obj instanceof IndexColorModel)) { 1551 return false; 1552 } 1553 1554 IndexColorModel cm = (IndexColorModel) obj; 1555 if (supportsAlpha != cm.hasAlpha() || 1556 isAlphaPremultiplied != cm.isAlphaPremultiplied() || 1557 pixel_bits != cm.getPixelSize() || 1558 transparency != cm.getTransparency() || 1559 numComponents != cm.getNumComponents() || 1560 (!(colorSpace.equals(cm.colorSpace))) || 1561 transferType != cm.transferType || 1562 map_size != cm.map_size || 1563 transparent_index != cm.transparent_index) 1564 { 1565 return false; 1566 } 1567 1568 int[] nb = cm.getComponentSize(); 1569 1570 if ((nBits != null) && (nb != null)) { 1571 for (int i = 0; i < numComponents; i++) { 1572 if (nBits[i] != nb[i]) { 1573 return false; 1574 } 1575 } 1576 } else { 1577 return ((nBits == null) && (nb == null)); 1578 } 1579 1580 // verify whether we have to check equality of all bits in validBits 1581 boolean testValidBits; 1582 if (validBits == cm.validBits) { 1583 testValidBits = false; 1584 } else if (validBits == null || cm.validBits == null) { 1585 return false; 1586 } else if (validBits.equals(cm.validBits)) { 1587 testValidBits = false; 1588 } else { 1589 testValidBits = true; 1590 } 1591 1592 if (testValidBits) { 1593 for (int i = 0; i < map_size; i++) { 1594 if (rgb[i] != cm.rgb[i] || 1595 validBits.testBit(i) != cm.validBits.testBit(i)) 1596 { 1597 return false; 1598 } 1599 } 1600 } else { 1601 for (int i = 0; i < map_size; i++) { 1602 if (rgb[i] != cm.rgb[i]) { 1603 return false; 1604 } 1605 } 1606 } 1607 return true; 1608 } 1609 1610 /** 1611 * Returns the hash code for IndexColorModel. 1612 * 1613 * @return a hash code for IndexColorModel 1614 */ 1615 @Override 1616 public int hashCode() { 1617 int result = hashCode; 1618 if (result == 0) { 1619 result = 7; 1620 result = 89 * result + this.pixel_bits; 1621 result = 89 * result + Arrays.hashCode(this.nBits); 1622 result = 89 * result + this.transparency; 1623 result = 89 * result + (this.supportsAlpha ? 1 : 0); 1624 result = 89 * result + (this.isAlphaPremultiplied ? 1 : 0); 1625 result = 89 * result + this.numComponents; 1626 result = 89 * result + Objects.hashCode(this.colorSpace); 1627 result = 89 * result + this.transferType; 1628 result = 89 * result + Arrays.hashCode(this.rgb); 1629 result = 89 * result + this.map_size; 1630 result = 89 * result + this.transparent_index; 1631 hashCode = result; 1632 } 1633 return result; 1634 } 1635 } --- EOF ---