001 /* IndexColorModel.java -- Java class for interpreting Pixel objects
002 Copyright (C) 1999, 2005 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038 package java.awt.image;
039
040 import gnu.java.awt.Buffers;
041
042 import java.awt.color.ColorSpace;
043 import 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 */
068 public 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 }