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