Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / java / awt / image / IndexColorModel.java
blob299b4dc0d86be8fa21301dca68fb4471401220ae
1 /* IndexColorModel.java -- Java class for interpreting Pixel objects
2 Copyright (C) 1999, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package java.awt.image;
40 import gnu.java.awt.Buffers;
42 import java.awt.color.ColorSpace;
43 import java.math.BigInteger;
45 /**
46 * Color model similar to pseudo visual in X11.
47 * <br><br>
48 * This color model maps linear pixel values to actual RGB and alpha colors.
49 * Thus, pixel values are indexes into the color map. Each color component is
50 * an 8-bit unsigned value.
51 * <br><br>
52 * The <code>IndexColorModel</code> supports a map of valid pixels, allowing
53 * the representation of holes in the the color map. The valid map is
54 * represented as a {@link BigInteger} where each bit indicates the validity
55 * of the map entry with the same index.
56 * <br><br>
57 * Colors can have alpha components for transparency support. If alpha
58 * component values aren't given, color values are opaque. The model also
59 * supports a reserved pixel value to represent completely transparent colors,
60 * no matter what the actual color component values are.
61 * <br><br>
62 * <code>IndexColorModel</code> supports anywhere from 1 to 16 bit index
63 * values. The allowed transfer types are {@link DataBuffer#TYPE_BYTE} and
64 * {@link DataBuffer#TYPE_USHORT}.
66 * @author C. Brian Jones (cbj@gnu.org)
68 public class IndexColorModel extends ColorModel
70 private int map_size;
71 private boolean opaque; // no alpha, but doesn't account for trans
72 private int trans = -1;
73 private int[] rgb;
74 private BigInteger validBits = BigInteger.ZERO;
76 /**
77 * Creates a new indexed color model for <code>size</code> color elements
78 * with no alpha component. Each array must contain at least
79 * <code>size</code> elements. For each array, the i-th color is described
80 * by reds[i], greens[i] and blues[i].
82 * @param bits the number of bits needed to represent <code>size</code>
83 * colors.
84 * @param size the number of colors in the color map.
85 * @param reds the red component of all colors.
86 * @param greens the green component of all colors.
87 * @param blues the blue component of all colors.
89 * @throws IllegalArgumentException if <code>bits</code> &lt; 1 or
90 * <code>bits</code> &gt; 16.
91 * @throws NullPointerException if any of the arrays is <code>null</code>.
92 * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater
93 * than the length of the component arrays.
95 public IndexColorModel(int bits, int size, byte[] reds, byte[] greens,
96 byte[] blues)
98 this(bits, size, reds, greens, blues, (byte[]) null);
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.
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).
116 * @throws IllegalArgumentException if <code>bits</code> &lt; 1 or
117 * <code>bits</code> &gt; 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.
122 public IndexColorModel(int bits, int size, byte[] reds, byte[] greens,
123 byte[] blues, int trans)
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 if (0 <= trans && trans < size) {
138 this.trans = trans;
139 transparency = BITMASK;
141 rgb = new int[size];
142 for (int i = 0; i < size; i++)
144 rgb[i] = (0xff000000
145 | ((reds[i] & 0xff) << 16)
146 | ((greens[i] & 0xff) << 8)
147 | (blues[i] & 0xff));
149 // Generate a bigint with 1's for every pixel
150 validBits = validBits.setBit(size).subtract(BigInteger.ONE);
154 * Creates a new indexed color model for <code>size</code> color elements
155 * including alpha. Each array must contain at least <code>size</code>
156 * elements. For each array, the i-th color is described
157 * by reds[i], greens[i], blues[i] and alphas[i].
159 * @param bits the number of bits needed to represent <code>size</code>
160 * colors.
161 * @param size the number of colors in the color map.
162 * @param reds the red component of all colors.
163 * @param greens the green component of all colors.
164 * @param blues the blue component of all colors.
165 * @param alphas the alpha component of all colors (<code>null</code>
166 * permitted).
168 * @throws IllegalArgumentException if <code>bits</code> &lt; 1 or
169 * <code>bits</code> &gt; 16.
170 * @throws NullPointerException if <code>reds</code>, <code>greens</code> or
171 * <code>blues</code> is <code>null</code>.
172 * @throws ArrayIndexOutOfBoundsException if <code>size</code> is greater
173 * than the length of the component arrays.
175 public IndexColorModel(int bits, int size, byte[] reds, byte[] greens,
176 byte[] blues, byte[] alphas)
178 super(bits, nArray(8, (alphas == null ? 3 : 4)),
179 ColorSpace.getInstance(ColorSpace.CS_sRGB),
180 (alphas != null), false, TRANSLUCENT,
181 Buffers.smallestAppropriateTransferType(bits));
182 if (bits < 1)
183 throw new IllegalArgumentException("bits < 1");
184 if (bits > 16)
185 throw new IllegalArgumentException("bits > 16");
186 if (size < 1)
187 throw new IllegalArgumentException("size < 1");
188 map_size = size;
189 opaque = (alphas == null);
191 rgb = new int[size];
192 if (alphas == null)
194 for (int i = 0; i < size; i++)
196 rgb[i] = (0xff000000
197 | ((reds[i] & 0xff) << 16)
198 | ((greens[i] & 0xff) << 8)
199 | (blues[i] & 0xff));
201 transparency = OPAQUE;
203 else
205 byte alphaZero = (byte) 0x00;
206 byte alphaOne = (byte) 0xFF;
207 for (int i = 0; i < size; i++)
209 alphaZero = (byte) (alphaZero | alphas[i]);
210 alphaOne = (byte) (alphaOne & alphas[i]);
211 rgb[i] = ((alphas[i] & 0xff) << 24
212 | ((reds[i] & 0xff) << 16)
213 | ((greens[i] & 0xff) << 8)
214 | (blues[i] & 0xff));
216 if ((alphaZero == (byte) 0x00) || (alphaOne == (byte) 0xFF))
217 transparency = BITMASK;
218 else
219 transparency = TRANSLUCENT;
222 // Generate a bigint with 1's for every pixel
223 validBits = validBits.setBit(size).subtract(BigInteger.ONE);
227 * Creates a new indexed color model using the color components in
228 * <code>cmap</code>. If <code>hasAlpha</code> is <code>true</code> then
229 * <code>cmap</code> contains an alpha component after each of the red, green
230 * and blue components.
232 * @param bits the number of bits needed to represent <code>size</code>
233 * colors
234 * @param size the number of colors in the color map
235 * @param cmap packed color components
236 * @param start the offset of the first color component in <code>cmap</code>
237 * @param hasAlpha <code>cmap</code> has alpha values
238 * @throws IllegalArgumentException if bits &lt; 1, bits &gt; 16, or size
239 * &lt; 1.
240 * @throws NullPointerException if <code>cmap</code> is <code>null</code>.
242 public IndexColorModel(int bits, int size, byte[] cmap, int start,
243 boolean hasAlpha)
245 this(bits, size, cmap, start, hasAlpha, -1);
249 * Construct an IndexColorModel from an array of red, green, blue, and
250 * optional alpha components. The component values are interleaved as RGB(A).
252 * @param bits the number of bits needed to represent <code>size</code>
253 * colors
254 * @param size the number of colors in the color map
255 * @param cmap interleaved color components
256 * @param start the offset of the first color component in <code>cmap</code>
257 * @param hasAlpha <code>cmap</code> has alpha values
258 * @param trans the index of the transparent color
259 * @throws IllegalArgumentException if bits &lt; 1, bits &gt; 16, or size
260 * &lt; 1.
261 * @throws NullPointerException if <code>cmap</code> is <code>null</code>.
263 public IndexColorModel(int bits, int size, byte[] cmap, int start,
264 boolean hasAlpha, int trans)
266 super(bits, nArray(8, hasAlpha || (0 <= trans && trans < size) ? 4 : 3),
267 ColorSpace.getInstance(ColorSpace.CS_sRGB),
268 hasAlpha || (0 <= trans && trans < size), false, OPAQUE,
269 Buffers.smallestAppropriateTransferType(bits));
270 if (bits < 1)
271 throw new IllegalArgumentException("bits < 1");
272 if (bits > 16)
273 throw new IllegalArgumentException("bits > 16");
274 if (size < 1)
275 throw new IllegalArgumentException("size < 1");
276 map_size = size;
277 opaque = !hasAlpha;
278 if (0 <= trans && trans < size)
279 this.trans = trans;
281 rgb = new int[size];
282 if (hasAlpha)
284 int alpha;
285 int alphaZero = 0x00; // use to detect all zeros
286 int alphaOne = 0xff; // use to detect all ones
287 for (int i = 0; i < size; i++) {
288 alpha = cmap[4 * i + 3 + start] & 0xff;
289 alphaZero = alphaZero | alpha;
290 alphaOne = alphaOne & alpha;
291 rgb[i] =
292 ( alpha << 24
293 // red
294 | ((cmap[4 * i + start] & 0xff) << 16)
295 // green
296 | ((cmap[4 * i + 1 + start] & 0xff) << 8)
297 // blue
298 | (cmap[4 * i + 2 + start] & 0xff));
300 if (alphaZero == 0)
301 transparency = BITMASK;
302 else if (alphaOne == 255)
303 transparency = (trans != -1 ? BITMASK : OPAQUE);
304 else
305 transparency = TRANSLUCENT;
307 else
309 for (int i = 0; i < size; i++)
310 rgb[i] = (0xff000000
311 // red
312 | ((cmap[3 * i + start] & 0xff) << 16)
313 // green
314 | ((cmap[3 * i + 1 + start] & 0xff) << 8)
315 // blue
316 | (cmap[3 * i + 2 + start] & 0xff));
317 if (trans != -1)
318 transparency = BITMASK;
321 // Generate a bigint with 1's for every pixel
322 validBits = validBits.setBit(size).subtract(BigInteger.ONE);
326 * Construct an IndexColorModel from an array of <code>size</code> packed
327 * colors. Each int element contains 8-bit red, green, blue, and optional
328 * alpha values packed in order. If hasAlpha is false, then all the colors
329 * are opaque except for the transparent color.
331 * @param bits the number of bits needed to represent <code>size</code>
332 * colors
333 * @param size the number of colors in the color map
334 * @param cmap packed color components
335 * @param start the offset of the first color component in <code>cmap</code>
336 * @param hasAlpha <code>cmap</code> has alpha values
337 * @param trans the index of the transparent color
338 * @param transferType {@link DataBuffer#TYPE_BYTE} or
339 {@link DataBuffer#TYPE_USHORT}.
340 * @throws IllegalArgumentException if bits &lt; 1, bits &gt; 16, or size
341 * &lt; 1.
342 * @throws IllegalArgumentException if <code>transferType</code> is something
343 * other than {@link DataBuffer#TYPE_BYTE} or
344 * {@link DataBuffer#TYPE_USHORT}.
346 public IndexColorModel(int bits, int size, int[] cmap, int start,
347 boolean hasAlpha, int trans, int transferType)
349 super(bits,
350 nArray(8, 4), // bits for each channel
351 ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB
352 true, // has alpha
353 false, // not premultiplied
354 TRANSLUCENT, transferType);
355 if (transferType != DataBuffer.TYPE_BYTE
356 && transferType != DataBuffer.TYPE_USHORT)
357 throw new IllegalArgumentException();
358 if (bits > 16)
359 throw new IllegalArgumentException("bits > 16");
360 if (size < 1)
361 throw new IllegalArgumentException("size < 1");
362 map_size = size;
363 opaque = !hasAlpha;
364 if (0 <= trans && trans < size)
365 this.trans = trans;
367 rgb = new int[size];
368 if (!hasAlpha)
369 for (int i = 0; i < size; i++)
370 rgb[i] = cmap[i + start] | 0xff000000;
371 else
372 System.arraycopy(cmap, start, rgb, 0, size);
374 // Generate a bigint with 1's for every pixel
375 validBits = validBits.setBit(size).subtract(BigInteger.ONE);
379 * Construct an IndexColorModel using a colormap with holes.
380 * <br><br>
381 * The IndexColorModel is built from the array of ints defining the
382 * colormap. Each element contains red, green, blue, and alpha
383 * components. The ColorSpace is sRGB. The transparency value is
384 * automatically determined.
385 * <br><br>
386 * This constructor permits indicating which colormap entries are valid,
387 * using the validBits argument. Each entry in cmap is valid if the
388 * corresponding bit in validBits is set.
390 * @param bits the number of bits needed to represent <code>size</code>
391 * colors.
392 * @param size the number of colors in the color map.
393 * @param cmap packed color components.
394 * @param start the offset of the first color component in <code>cmap</code>.
395 * @param transferType {@link DataBuffer#TYPE_BYTE} or
396 * {@link DataBuffer#TYPE_USHORT}.
397 * @param validBits a map of the valid entries in <code>cmap</code>.
398 * @throws IllegalArgumentException if bits &lt; 1, bits &gt; 16, or size
399 * &lt; 1.
400 * @throws IllegalArgumentException if transferType is something other than
401 * {@link DataBuffer#TYPE_BYTE} or {@link DataBuffer#TYPE_USHORT}.
403 public IndexColorModel(int bits, int size, int[] cmap, int start,
404 int transferType, BigInteger validBits)
406 super(bits, // total bits, sRGB, four channels
407 nArray(8, 4), // bits for each channel
408 ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB
409 true, // has alpha
410 false, // not premultiplied
411 TRANSLUCENT, transferType);
412 if (transferType != DataBuffer.TYPE_BYTE
413 && transferType != DataBuffer.TYPE_USHORT)
414 throw new IllegalArgumentException();
415 if (bits > 16)
416 throw new IllegalArgumentException("bits > 16");
417 if (size < 1)
418 throw new IllegalArgumentException("size < 1");
419 map_size = size;
420 opaque = false;
421 this.trans = -1;
422 this.validBits = validBits;
424 rgb = new int[size];
425 if (!hasAlpha)
426 for (int i = 0; i < size; i++)
427 rgb[i] = cmap[i + start] | 0xff000000;
428 else
429 System.arraycopy(cmap, start, rgb, 0, size);
433 * Returns the size of the color lookup table.
435 * @return The size of the color lookup table.
437 public final int getMapSize()
439 return map_size;
443 * Get the index of the transparent color in this color model.
445 * @return The index of the color that is considered transparent, or -1 if
446 * there is no transparent color.
448 public final int getTransparentPixel()
450 return trans;
454 * Fills the supplied array with the red component of each color in the
455 * lookup table.
457 * @param r an array that is at least as large as {@link #getMapSize()}.
458 * @throws NullPointerException if <code>r</code> is <code>null</code>.
459 * @throws ArrayIndexOutOfBoundsException if <code>r</code> has less
460 * than {@link #getMapSize()} elements.
462 public final void getReds(byte[] r)
464 int i;
465 for (i = 0; i < map_size; i++)
466 r[i] = (byte) ((0x00FF0000 & rgb[i]) >> 16);
470 * Fills the supplied array with the green component of each color in the
471 * lookup table.
473 * @param g an array that is at least as large as {@link #getMapSize()}.
474 * @throws NullPointerException if <code>g</code> is <code>null</code>.
475 * @throws ArrayIndexOutOfBoundsException if <code>g</code> has less
476 * than {@link #getMapSize()} elements.
478 public final void getGreens(byte[] g)
480 int i;
481 for (i = 0; i < map_size; i++)
482 g[i] = (byte) ((0x0000FF00 & rgb[i]) >> 8);
486 * Fills the supplied array with the blue component of each color in the
487 * lookup table.
489 * @param b an array that is at least as large as {@link #getMapSize()}.
490 * @throws NullPointerException if <code>b</code> is <code>null</code>.
491 * @throws ArrayIndexOutOfBoundsException if <code>b</code> has less
492 * than {@link #getMapSize()} elements.
494 public final void getBlues(byte[] b)
496 int i;
497 for (i = 0; i < map_size; i++)
498 b[i] = (byte) (0x000000FF & rgb[i]);
502 * Fills the supplied array with the alpha component of each color in the
503 * lookup table. If the model has a transparent pixel specified, the alpha
504 * for that pixel will be 0.
506 * @param a an array that is at least as large as {@link #getMapSize()}.
507 * @throws NullPointerException if <code>a</code> is <code>null</code>.
508 * @throws ArrayIndexOutOfBoundsException if <code>a</code> has less
509 * than {@link #getMapSize()} elements.
511 public final void getAlphas(byte[] a)
513 int i;
514 for (i = 0; i < map_size; i++)
515 if (i == trans)
516 a[i] = (byte) 0;
517 else
518 a[i] = (byte) ((0xFF000000 & rgb[i]) >> 24);
522 * Returns the red component of the color in the lookup table for the
523 * given pixel value.
525 * @param pixel the pixel lookup value.
527 * @return The red component of the color in the lookup table.
528 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative.
530 public final int getRed(int pixel)
532 if (pixel < map_size)
533 return (0x00FF0000 & rgb[pixel]) >> 16;
535 return 0;
539 * Returns the green component of the color in the lookup table for the
540 * given pixel value.
542 * @param pixel the pixel lookup value.
544 * @return The green component of the color in the lookup table.
545 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative.
547 public final int getGreen(int pixel)
549 if (pixel < map_size)
550 return (0x0000FF00 & rgb[pixel]) >> 8;
552 return 0;
556 * Returns the blue component of the color in the lookup table for the
557 * given pixel value.
559 * @param pixel the pixel lookup value.
561 * @return The blue component of the color in the lookup table.
562 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative.
564 public final int getBlue(int pixel)
566 if (pixel < map_size)
567 return 0x000000FF & rgb[pixel];
569 return 0;
573 * Returns the alpha component of the color in the lookup table for the
574 * given pixel value. If no alpha channel was specified when the color model
575 * was created, then 255 is returned for all pixels except the transparent
576 * pixel (if one is defined - see {@link #getTransparentPixel()}) which
577 * returns an alpha of 0.
579 * @param pixel the pixel lookup value.
581 * @return The alpha component of the color in the lookup table (in the
582 * range 0 to 255).
583 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative.
585 public final int getAlpha(int pixel)
587 if (opaque && pixel != trans)
588 return 255;
589 if ((pixel == trans && trans != -1) || pixel >= map_size)
590 return 0;
592 return (0xFF000000 & rgb[pixel]) >> 24;
596 * Get the RGB color value of the given pixel using the default
597 * RGB color model.
599 * @param pixel the pixel lookup value.
600 * @return The RGB color value.
601 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code> is negative.
603 public final int getRGB(int pixel)
605 if (pixel >= 0 && pixel < map_size)
606 return rgb[pixel];
608 return 0;
612 * Get the RGB color values of all pixels in the map using the default
613 * RGB color model.
615 * @param rgb The destination array.
617 public final void getRGBs(int[] rgb)
619 System.arraycopy(this.rgb, 0, rgb, 0, map_size);
622 /**
623 * Return <code>true</code> if the lookup table contains valid data for
624 * <code>pixel</code>, and <code>false</code> otherwise.
626 * @param pixel the pixel value used to index the color lookup table.
627 * @return <code>true</code> if <code>pixel</code> is valid,
628 * <code>false</code> otherwise.
630 public boolean isValid(int pixel)
632 if (pixel >= 0)
633 return validBits.testBit(pixel);
634 return false;
637 /**
638 * Return <code>true</code> if all pixels are valid, <code>false</code>
639 * otherwise.
641 * @return <code>true</code> if all pixels are valid, <code>false</code>
642 * otherwise.
644 public boolean isValid()
646 // Generate a bigint with 1's for every pixel
647 BigInteger allbits = new BigInteger("0");
648 allbits = allbits.setBit(map_size);
649 allbits = allbits.subtract(new BigInteger("1"));
650 return allbits.equals(validBits);
653 /**
654 * Returns a binary value ({@link BigInteger}) where each bit represents an
655 * entry in the color lookup table. If the bit is on, the entry is valid.
657 * @return The binary value.
659 public BigInteger getValidPixels()
661 return validBits;
665 * Construct a {@link BufferedImage} with rgb pixel values from a
666 * {@link Raster}.
668 * Constructs a new BufferedImage in which each pixel is an RGBA int from
669 * a Raster with index-valued pixels. If this model has no alpha component
670 * or transparent pixel, the type of the new BufferedImage is TYPE_INT_RGB.
671 * Otherwise the type is TYPE_INT_ARGB. If forceARGB is true, the type is
672 * forced to be TYPE_INT_ARGB no matter what.
674 * @param raster The source of pixel values.
675 * @param forceARGB True if type must be TYPE_INT_ARGB.
676 * @return New BufferedImage with RBGA int pixel values.
678 public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB)
680 int type = forceARGB ? BufferedImage.TYPE_INT_ARGB
681 : ((opaque && trans == -1) ? BufferedImage.TYPE_INT_RGB :
682 BufferedImage.TYPE_INT_ARGB);
684 // FIXME: assuming that raster has only 1 band since pixels are supposed
685 // to be int indexes.
686 // FIXME: it would likely be more efficient to fetch a complete array,
687 // but it would take much more memory.
688 // FIXME: I'm not sure if transparent pixels or alpha values need special
689 // handling here.
690 BufferedImage im = new BufferedImage(raster.width, raster.height, type);
691 for (int x = raster.minX; x < raster.width + raster.minX; x++)
692 for (int y = raster.minY; y < raster.height + raster.minY; y++)
693 im.setRGB(x, y, rgb[raster.getSample(x, y, 0)]);
695 return im;