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