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