001/* IndexColorModel.java -- Java class for interpreting Pixel objects 002 Copyright (C) 1999, 2005 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038package java.awt.image; 039 040import gnu.java.awt.Buffers; 041 042import java.awt.color.ColorSpace; 043import java.math.BigInteger; 044 045/** 046 * Color model similar to pseudo visual in X11. 047 * <br><br> 048 * This color model maps linear pixel values to actual RGB and alpha colors. 049 * Thus, pixel values are indexes into the color map. Each color component is 050 * an 8-bit unsigned value. 051 * <br><br> 052 * The <code>IndexColorModel</code> supports a map of valid pixels, allowing 053 * the representation of holes in the the color map. The valid map is 054 * represented as a {@link BigInteger} where each bit indicates the validity 055 * of the map entry with the same index. 056 * <br><br> 057 * Colors can have alpha components for transparency support. If alpha 058 * component values aren't given, color values are opaque. The model also 059 * supports a reserved pixel value to represent completely transparent colors, 060 * no matter what the actual color component values are. 061 * <br><br> 062 * <code>IndexColorModel</code> supports anywhere from 1 to 16 bit index 063 * values. The allowed transfer types are {@link DataBuffer#TYPE_BYTE} and 064 * {@link DataBuffer#TYPE_USHORT}. 065 * 066 * @author C. Brian Jones (cbj@gnu.org) 067 */ 068public class IndexColorModel extends ColorModel 069{ 070 private int map_size; 071 private boolean opaque; // no alpha, but doesn't account for trans 072 private int trans = -1; 073 private int[] rgb; 074 private BigInteger validBits = BigInteger.ZERO; 075 076 /** 077 * Creates a new indexed color model for <code>size</code> color elements 078 * with no alpha component. Each array must contain at least 079 * <code>size</code> elements. For each array, the i-th color is described 080 * by reds[i], greens[i] and blues[i]. 081 * 082 * @param bits the number of bits needed to represent <code>size</code> 083 * colors. 084 * @param size the number of colors in the color map. 085 * @param reds the red component of all colors. 086 * @param greens the green component of all colors. 087 * @param blues the blue component of all colors. 088 * 089 * @throws IllegalArgumentException if <code>bits</code> < 1 or 090 * <code>bits</code> > 16. 091 * @throws NullPointerException if any of the arrays is <code>null</code>. 092 * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater 093 * than the length of the component arrays. 094 */ 095 public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, 096 byte[] blues) 097 { 098 this(bits, size, reds, greens, blues, (byte[]) null); 099 } 100 101 /** 102 * Creates a new indexed color model for <code>size</code> color elements. 103 * Each array must contain at least <code>size</code> elements. For each 104 * array, the i-th color is described by reds[i], greens[i] and blues[i]. 105 * All the colors are opaque except for the transparent color. 106 * 107 * @param bits the number of bits needed to represent <code>size</code> 108 * colors 109 * @param size the number of colors in the color map 110 * @param reds the red component of all colors 111 * @param greens the green component of all colors 112 * @param blues the blue component of all colors 113 * @param trans the index of the transparent color (use -1 for no 114 * transparent color). 115 * 116 * @throws IllegalArgumentException if <code>bits</code> < 1 or 117 * <code>bits</code> > 16. 118 * @throws NullPointerException if any of the arrays is <code>null</code>. 119 * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater 120 * than the length of the component arrays. 121 */ 122 public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, 123 byte[] blues, int trans) 124 { 125 super(bits, nArray(8, (0 <= trans && trans < size) ? 4 : 3), 126 ColorSpace.getInstance(ColorSpace.CS_sRGB), 127 (0 <= trans && trans < size), // hasAlpha 128 false, OPAQUE, 129 Buffers.smallestAppropriateTransferType(bits)); 130 if (bits < 1) 131 throw new IllegalArgumentException("bits < 1"); 132 if (bits > 16) 133 throw new IllegalArgumentException("bits > 16"); 134 if (size < 1) 135 throw new IllegalArgumentException("size < 1"); 136 map_size = size; 137 rgb = createColorMap(bits, size); 138 for (int i = 0; i < size; i++) 139 { 140 rgb[i] = (0xff000000 141 | ((reds[i] & 0xff) << 16) 142 | ((greens[i] & 0xff) << 8) 143 | (blues[i] & 0xff)); 144 } 145 146 setTransparentPixel(trans); 147 148 // Generate a bigint with 1's for every pixel 149 validBits = validBits.setBit(size).subtract(BigInteger.ONE); 150 } 151 152 /** 153 * Creates a new indexed color model for <code>size</code> color elements 154 * including alpha. Each array must contain at least <code>size</code> 155 * elements. For each array, the i-th color is described 156 * by reds[i], greens[i], blues[i] and alphas[i]. 157 * 158 * @param bits the number of bits needed to represent <code>size</code> 159 * colors. 160 * @param size the number of colors in the color map. 161 * @param reds the red component of all colors. 162 * @param greens the green component of all colors. 163 * @param blues the blue component of all colors. 164 * @param alphas the alpha component of all colors (<code>null</code> 165 * permitted). 166 * 167 * @throws IllegalArgumentException if <code>bits</code> < 1 or 168 * <code>bits</code> > 16. 169 * @throws NullPointerException if <code>reds</code>, <code>greens</code> or 170 * <code>blues</code> is <code>null</code>. 171 * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater 172 * than the length of the component arrays. 173 */ 174 public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, 175 byte[] blues, byte[] alphas) 176 { 177 super(bits, nArray(8, (alphas == null ? 3 : 4)), 178 ColorSpace.getInstance(ColorSpace.CS_sRGB), 179 (alphas != null), false, TRANSLUCENT, 180 Buffers.smallestAppropriateTransferType(bits)); 181 if (bits < 1) 182 throw new IllegalArgumentException("bits < 1"); 183 if (bits > 16) 184 throw new IllegalArgumentException("bits > 16"); 185 if (size < 1) 186 throw new IllegalArgumentException("size < 1"); 187 map_size = size; 188 opaque = (alphas == null); 189 190 rgb = createColorMap(bits, size); 191 if (alphas == null) 192 { 193 for (int i = 0; i < size; i++) 194 { 195 rgb[i] = (0xff000000 196 | ((reds[i] & 0xff) << 16) 197 | ((greens[i] & 0xff) << 8) 198 | (blues[i] & 0xff)); 199 } 200 transparency = OPAQUE; 201 } 202 else 203 { 204 byte alphaZero = (byte) 0x00; 205 byte alphaOne = (byte) 0xFF; 206 for (int i = 0; i < size; i++) 207 { 208 alphaZero = (byte) (alphaZero | alphas[i]); 209 alphaOne = (byte) (alphaOne & alphas[i]); 210 rgb[i] = ((alphas[i] & 0xff) << 24 211 | ((reds[i] & 0xff) << 16) 212 | ((greens[i] & 0xff) << 8) 213 | (blues[i] & 0xff)); 214 } 215 if ((alphaZero == (byte) 0x00) || (alphaOne == (byte) 0xFF)) 216 transparency = BITMASK; 217 else 218 transparency = TRANSLUCENT; 219 } 220 221 // Generate a bigint with 1's for every pixel 222 validBits = validBits.setBit(size).subtract(BigInteger.ONE); 223 } 224 225 /** 226 * Creates a new indexed color model using the color components in 227 * <code>cmap</code>. If <code>hasAlpha</code> is <code>true</code> then 228 * <code>cmap</code> contains an alpha component after each of the red, green 229 * and blue components. 230 * 231 * @param bits the number of bits needed to represent <code>size</code> 232 * colors 233 * @param size the number of colors in the color map 234 * @param cmap packed color components 235 * @param start the offset of the first color component in <code>cmap</code> 236 * @param hasAlpha <code>cmap</code> has alpha values 237 * @throws IllegalArgumentException if bits < 1, bits > 16, or size 238 * < 1. 239 * @throws NullPointerException if <code>cmap</code> is <code>null</code>. 240 */ 241 public IndexColorModel(int bits, int size, byte[] cmap, int start, 242 boolean hasAlpha) 243 { 244 this(bits, size, cmap, start, hasAlpha, -1); 245 } 246 247 /** 248 * Construct an IndexColorModel from an array of red, green, blue, and 249 * optional alpha components. The component values are interleaved as RGB(A). 250 * 251 * @param bits the number of bits needed to represent <code>size</code> 252 * colors 253 * @param size the number of colors in the color map 254 * @param cmap interleaved color components 255 * @param start the offset of the first color component in <code>cmap</code> 256 * @param hasAlpha <code>cmap</code> has alpha values 257 * @param trans the index of the transparent color 258 * @throws IllegalArgumentException if bits < 1, bits > 16, or size 259 * < 1. 260 * @throws NullPointerException if <code>cmap</code> is <code>null</code>. 261 */ 262 public IndexColorModel(int bits, int size, byte[] cmap, int start, 263 boolean hasAlpha, int trans) 264 { 265 super(bits, nArray(8, hasAlpha || (0 <= trans && trans < size) ? 4 : 3), 266 ColorSpace.getInstance(ColorSpace.CS_sRGB), 267 hasAlpha || (0 <= trans && trans < size), false, OPAQUE, 268 Buffers.smallestAppropriateTransferType(bits)); 269 if (bits < 1) 270 throw new IllegalArgumentException("bits < 1"); 271 if (bits > 16) 272 throw new IllegalArgumentException("bits > 16"); 273 if (size < 1) 274 throw new IllegalArgumentException("size < 1"); 275 map_size = size; 276 opaque = !hasAlpha; 277 278 rgb = createColorMap(bits, size); 279 if (hasAlpha) 280 { 281 int alpha; 282 int alphaZero = 0x00; // use to detect all zeros 283 int alphaOne = 0xff; // use to detect all ones 284 for (int i = 0; i < size; i++) { 285 alpha = cmap[4 * i + 3 + start] & 0xff; 286 alphaZero = alphaZero | alpha; 287 alphaOne = alphaOne & alpha; 288 rgb[i] = 289 ( alpha << 24 290 // red 291 | ((cmap[4 * i + start] & 0xff) << 16) 292 // green 293 | ((cmap[4 * i + 1 + start] & 0xff) << 8) 294 // blue 295 | (cmap[4 * i + 2 + start] & 0xff)); 296 } 297 if (alphaZero == 0) 298 transparency = BITMASK; 299 else if (alphaOne == 255) 300 transparency = (trans != -1 ? BITMASK : OPAQUE); 301 else 302 transparency = TRANSLUCENT; 303 } 304 else 305 { 306 for (int i = 0; i < size; i++) 307 rgb[i] = (0xff000000 308 // red 309 | ((cmap[3 * i + start] & 0xff) << 16) 310 // green 311 | ((cmap[3 * i + 1 + start] & 0xff) << 8) 312 // blue 313 | (cmap[3 * i + 2 + start] & 0xff)); 314 if (trans != -1) 315 transparency = BITMASK; 316 } 317 318 setTransparentPixel(trans); 319 320 // Generate a bigint with 1's for every pixel 321 validBits = validBits.setBit(size).subtract(BigInteger.ONE); 322 } 323 324 /** 325 * Construct an IndexColorModel from an array of <code>size</code> packed 326 * colors. Each int element contains 8-bit red, green, blue, and optional 327 * alpha values packed in order. If hasAlpha is false, then all the colors 328 * are opaque except for the transparent color. 329 * 330 * @param bits the number of bits needed to represent <code>size</code> 331 * colors 332 * @param size the number of colors in the color map 333 * @param cmap packed color components 334 * @param start the offset of the first color component in <code>cmap</code> 335 * @param hasAlpha <code>cmap</code> has alpha values 336 * @param trans the index of the transparent color 337 * @param transferType {@link DataBuffer#TYPE_BYTE} or 338 {@link DataBuffer#TYPE_USHORT}. 339 * @throws IllegalArgumentException if bits < 1, bits > 16, or size 340 * < 1. 341 * @throws IllegalArgumentException if <code>transferType</code> is something 342 * other than {@link DataBuffer#TYPE_BYTE} or 343 * {@link DataBuffer#TYPE_USHORT}. 344 */ 345 public IndexColorModel(int bits, int size, int[] cmap, int start, 346 boolean hasAlpha, int trans, int transferType) 347 { 348 super(bits, 349 nArray(8, 4), // bits for each channel 350 ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB 351 true, // has alpha 352 false, // not premultiplied 353 TRANSLUCENT, transferType); 354 if (transferType != DataBuffer.TYPE_BYTE 355 && transferType != DataBuffer.TYPE_USHORT) 356 throw new IllegalArgumentException(); 357 if (bits > 16) 358 throw new IllegalArgumentException("bits > 16"); 359 if (size < 1) 360 throw new IllegalArgumentException("size < 1"); 361 map_size = size; 362 opaque = !hasAlpha; 363 rgb = createColorMap(bits, size); 364 if (!hasAlpha) 365 for (int i = 0; i < size; i++) 366 rgb[i] = cmap[i + start] | 0xff000000; 367 else 368 System.arraycopy(cmap, start, rgb, 0, size); 369 370 setTransparentPixel(trans); 371 372 // Generate a bigint with 1's for every pixel 373 validBits = validBits.setBit(size).subtract(BigInteger.ONE); 374 } 375 376 /** 377 * Construct an IndexColorModel using a colormap with holes. 378 * <br><br> 379 * The IndexColorModel is built from the array of ints defining the 380 * colormap. Each element contains red, green, blue, and alpha 381 * components. The ColorSpace is sRGB. The transparency value is 382 * automatically determined. 383 * <br><br> 384 * This constructor permits indicating which colormap entries are valid, 385 * using the validBits argument. Each entry in cmap is valid if the 386 * corresponding bit in validBits is set. 387 * 388 * @param bits the number of bits needed to represent <code>size</code> 389 * colors. 390 * @param size the number of colors in the color map. 391 * @param cmap packed color components. 392 * @param start the offset of the first color component in <code>cmap</code>. 393 * @param transferType {@link DataBuffer#TYPE_BYTE} or 394 * {@link DataBuffer#TYPE_USHORT}. 395 * @param validBits a map of the valid entries in <code>cmap</code>. 396 * @throws IllegalArgumentException if bits < 1, bits > 16, or size 397 * < 1. 398 * @throws IllegalArgumentException if transferType is something other than 399 * {@link DataBuffer#TYPE_BYTE} or {@link DataBuffer#TYPE_USHORT}. 400 */ 401 public IndexColorModel(int bits, int size, int[] cmap, int start, 402 int transferType, BigInteger validBits) 403 { 404 super(bits, // total bits, sRGB, four channels 405 nArray(8, 4), // bits for each channel 406 ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB 407 true, // has alpha 408 false, // not premultiplied 409 TRANSLUCENT, transferType); 410 if (transferType != DataBuffer.TYPE_BYTE 411 && transferType != DataBuffer.TYPE_USHORT) 412 throw new IllegalArgumentException(); 413 if (bits > 16) 414 throw new IllegalArgumentException("bits > 16"); 415 if (size < 1) 416 throw new IllegalArgumentException("size < 1"); 417 map_size = size; 418 opaque = false; 419 this.trans = -1; 420 this.validBits = validBits; 421 422 rgb = createColorMap(bits, size); 423 if (!hasAlpha) 424 for (int i = 0; i < size; i++) 425 rgb[i] = cmap[i + start] | 0xff000000; 426 else 427 System.arraycopy(cmap, start, rgb, 0, size); 428 } 429 430 /** 431 * Returns the size of the color lookup table. 432 * 433 * @return The size of the color lookup table. 434 */ 435 public final int getMapSize() 436 { 437 return map_size; 438 } 439 440 /** 441 * Get the index of the transparent color in this color model. 442 * 443 * @return The index of the color that is considered transparent, or -1 if 444 * there is no transparent color. 445 */ 446 public final int getTransparentPixel() 447 { 448 return trans; 449 } 450 451 /** 452 * Fills the supplied array with the red component of each color in the 453 * lookup table. 454 * 455 * @param r an array that is at least as large as {@link #getMapSize()}. 456 * @throws NullPointerException if <code>r</code> is <code>null</code>. 457 * @throws ArrayIndexOutOfBoundsException if <code>r</code> has less 458 * than {@link #getMapSize()} elements. 459 */ 460 public final void getReds(byte[] r) 461 { 462 int i; 463 for (i = 0; i < map_size; i++) 464 r[i] = (byte) ((0x00FF0000 & rgb[i]) >> 16); 465 } 466 467 /** 468 * Fills the supplied array with the green component of each color in the 469 * lookup table. 470 * 471 * @param g an array that is at least as large as {@link #getMapSize()}. 472 * @throws NullPointerException if <code>g</code> is <code>null</code>. 473 * @throws ArrayIndexOutOfBoundsException if <code>g</code> has less 474 * than {@link #getMapSize()} elements. 475 */ 476 public final void getGreens(byte[] g) 477 { 478 int i; 479 for (i = 0; i < map_size; i++) 480 g[i] = (byte) ((0x0000FF00 & rgb[i]) >> 8); 481 } 482 483 /** 484 * Fills the supplied array with the blue component of each color in the 485 * lookup table. 486 * 487 * @param b an array that is at least as large as {@link #getMapSize()}. 488 * @throws NullPointerException if <code>b</code> is <code>null</code>. 489 * @throws ArrayIndexOutOfBoundsException if <code>b</code> has less 490 * than {@link #getMapSize()} elements. 491 */ 492 public final void getBlues(byte[] b) 493 { 494 int i; 495 for (i = 0; i < map_size; i++) 496 b[i] = (byte) (0x000000FF & rgb[i]); 497 } 498 499 /** 500 * Fills the supplied array with the alpha component of each color in the 501 * lookup table. If the model has a transparent pixel specified, the alpha 502 * for that pixel will be 0. 503 * 504 * @param a an array that is at least as large as {@link #getMapSize()}. 505 * @throws NullPointerException if <code>a</code> is <code>null</code>. 506 * @throws ArrayIndexOutOfBoundsException if <code>a</code> has less 507 * than {@link #getMapSize()} elements. 508 */ 509 public final void getAlphas(byte[] a) 510 { 511 int i; 512 for (i = 0; i < map_size; i++) 513 if (i == trans) 514 a[i] = (byte) 0; 515 else 516 a[i] = (byte) ((0xFF000000 & rgb[i]) >> 24); 517 } 518 519 /** 520 * Returns the red component of the color in the lookup table for the 521 * given pixel value. 522 * 523 * @param pixel the pixel lookup value. 524 * 525 * @return The red component of the color in the lookup table. 526 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. 527 */ 528 public final int getRed(int pixel) 529 { 530 if (pixel < map_size) 531 return (0x00FF0000 & rgb[pixel]) >> 16; 532 533 return 0; 534 } 535 536 /** 537 * Returns the green component of the color in the lookup table for the 538 * given pixel value. 539 * 540 * @param pixel the pixel lookup value. 541 * 542 * @return The green component of the color in the lookup table. 543 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. 544 */ 545 public final int getGreen(int pixel) 546 { 547 if (pixel < map_size) 548 return (0x0000FF00 & rgb[pixel]) >> 8; 549 550 return 0; 551 } 552 553 /** 554 * Returns the blue component of the color in the lookup table for the 555 * given pixel value. 556 * 557 * @param pixel the pixel lookup value. 558 * 559 * @return The blue component of the color in the lookup table. 560 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. 561 */ 562 public final int getBlue(int pixel) 563 { 564 if (pixel < map_size) 565 return 0x000000FF & rgb[pixel]; 566 567 return 0; 568 } 569 570 /** 571 * Returns the alpha component of the color in the lookup table for the 572 * given pixel value. If no alpha channel was specified when the color model 573 * was created, then 255 is returned for all pixels except the transparent 574 * pixel (if one is defined - see {@link #getTransparentPixel()}) which 575 * returns an alpha of 0. 576 * 577 * @param pixel the pixel lookup value. 578 * 579 * @return The alpha component of the color in the lookup table (in the 580 * range 0 to 255). 581 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. 582 */ 583 public final int getAlpha(int pixel) 584 { 585 return (rgb[pixel] >> 24) & 0xFF; 586 } 587 588 /** 589 * Get the RGB color value of the given pixel using the default 590 * RGB color model. 591 * 592 * @param pixel the pixel lookup value. 593 * @return The RGB color value. 594 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative. 595 */ 596 public final int getRGB(int pixel) 597 { 598 if (pixel >= 0 && pixel < map_size) 599 return rgb[pixel]; 600 601 return 0; 602 } 603 604 /** 605 * Get the RGB color values of all pixels in the map using the default 606 * RGB color model. 607 * 608 * @param rgb The destination array. 609 */ 610 public final void getRGBs(int[] rgb) 611 { 612 System.arraycopy(this.rgb, 0, rgb, 0, map_size); 613 } 614 615 /** 616 * Return <code>true</code> if the lookup table contains valid data for 617 * <code>pixel</code>, and <code>false</code> otherwise. 618 * 619 * @param pixel the pixel value used to index the color lookup table. 620 * @return <code>true</code> if <code>pixel</code> is valid, 621 * <code>false</code> otherwise. 622 */ 623 public boolean isValid(int pixel) 624 { 625 if (pixel >= 0) 626 return validBits.testBit(pixel); 627 return false; 628 } 629 630 /** 631 * Return <code>true</code> if all pixels are valid, <code>false</code> 632 * otherwise. 633 * 634 * @return <code>true</code> if all pixels are valid, <code>false</code> 635 * otherwise. 636 */ 637 public boolean isValid() 638 { 639 // Generate a bigint with 1's for every pixel 640 BigInteger allbits = new BigInteger("0"); 641 allbits = allbits.setBit(map_size); 642 allbits = allbits.subtract(new BigInteger("1")); 643 return allbits.equals(validBits); 644 } 645 646 /** 647 * Returns a binary value ({@link BigInteger}) where each bit represents an 648 * entry in the color lookup table. If the bit is on, the entry is valid. 649 * 650 * @return The binary value. 651 */ 652 public BigInteger getValidPixels() 653 { 654 return validBits; 655 } 656 657 /** 658 * Construct a {@link BufferedImage} with rgb pixel values from a 659 * {@link Raster}. 660 * 661 * Constructs a new BufferedImage in which each pixel is an RGBA int from 662 * a Raster with index-valued pixels. If this model has no alpha component 663 * or transparent pixel, the type of the new BufferedImage is TYPE_INT_RGB. 664 * Otherwise the type is TYPE_INT_ARGB. If forceARGB is true, the type is 665 * forced to be TYPE_INT_ARGB no matter what. 666 * 667 * @param raster The source of pixel values. 668 * @param forceARGB True if type must be TYPE_INT_ARGB. 669 * @return New BufferedImage with RBGA int pixel values. 670 */ 671 public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) 672 { 673 int type = forceARGB ? BufferedImage.TYPE_INT_ARGB 674 : ((opaque && trans == -1) ? BufferedImage.TYPE_INT_RGB : 675 BufferedImage.TYPE_INT_ARGB); 676 677 // FIXME: assuming that raster has only 1 band since pixels are supposed 678 // to be int indexes. 679 // FIXME: it would likely be more efficient to fetch a complete array, 680 // but it would take much more memory. 681 // FIXME: I'm not sure if transparent pixels or alpha values need special 682 // handling here. 683 BufferedImage im = new BufferedImage(raster.width, raster.height, type); 684 for (int x = raster.minX; x < raster.width + raster.minX; x++) 685 for (int y = raster.minY; y < raster.height + raster.minY; y++) 686 im.setRGB(x, y, rgb[raster.getSample(x, y, 0)]); 687 688 return im; 689 } 690 691 /** 692 * Creates a {@link SampleModel} that is compatible to this color model. 693 * This will be a {@link MultiPixelPackedSampleModel} for bits/pixel of 694 * 1, 2 or 4, or a {@link ComponentColorModel} for the other cases. 695 * 696 * @param w the width of the sample model to create 697 * @param h the height of the sample model to create 698 * 699 * @return a compatible sample model 700 */ 701 public SampleModel createCompatibleSampleModel(int w, int h) 702 { 703 SampleModel sm; 704 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) 705 sm = new MultiPixelPackedSampleModel(transferType, w, h, pixel_bits); 706 else 707 sm = new ComponentSampleModel(transferType, w, h, 1, w, new int[]{0}); 708 return sm; 709 } 710 711 /** 712 * Sets the transparent pixel. This is called by the various constructors. 713 * 714 * @param t the transparent pixel 715 */ 716 private void setTransparentPixel(int t) 717 { 718 if (t >= 0 && t < map_size) 719 { 720 rgb[t] &= 0xffffff; // Make the value transparent. 721 trans = t; 722 if (transparency == OPAQUE) 723 { 724 transparency = BITMASK; 725 hasAlpha = true; 726 } 727 } 728 } 729 730 private int[] createColorMap(int bits, int size) 731 { 732 // According to a Mauve test, the RI allocates at least 256 entries here. 733 int realSize = Math.max(256, Math.max(1 << bits, size)); 734 return new int[realSize]; 735 } 736}