1 /* IndexColorModel.java -- Java class for interpreting Pixel objects
2 Copyright (C) 1999 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)
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., 59 Temple Place, Suite 330, Boston, MA
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
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. */
39 package java
.awt
.image
;
41 import java
.awt
.color
.ColorSpace
;
42 import java
.math
.BigInteger
;
45 * Color model similar to pseudo visual in X11.
47 * This color model maps linear pixel values to actual RGB and alpha colors.
48 * Thus, pixel values are indexes into the color map. Each color component is
49 * an 8-bit unsigned value.
51 * The IndexColorModel supports a map of valid pixels, allowing the
52 * representation of holes in the the color map. The valid map is represented
53 * as a BigInteger where each bit indicates the validity of the map entry with
56 * Colors can have alpha components for transparency support. If alpha
57 * component values aren't given, color values are opaque. The model also
58 * supports a reserved pixel value to represent completely transparent colors,
59 * no matter what the actual color component values are.
61 * IndexColorModel supports anywhere from 1 to 16 bit index values. The
62 * allowed transfer types are DataBuffer.TYPE_BYTE and DataBuffer.TYPE_USHORT.
64 * @author C. Brian Jones (cbj@gnu.org)
66 public class IndexColorModel
extends ColorModel
69 private boolean opaque
;
70 private int trans
= -1;
72 private BigInteger validBits
= BigInteger
.ZERO
;
75 * Each array much contain <code>size</code> elements. For each
76 * array, the i-th color is described by reds[i], greens[i],
77 * blues[i], alphas[i], unless alphas is not specified, then all the
78 * colors are opaque except for the transparent color.
80 * @param bits the number of bits needed to represent <code>size</code> colors
81 * @param size the number of colors in the color map
82 * @param reds the red component of all colors
83 * @param greens the green component of all colors
84 * @param blues the blue component of all colors
86 public IndexColorModel(int bits
, int size
, byte[] reds
, byte[] greens
,
89 this (bits
, size
, reds
, greens
, blues
, (byte[]) null);
93 * Each array much contain <code>size</code> elements. For each
94 * array, the i-th color is described by reds[i], greens[i],
95 * blues[i], alphas[i], unless alphas is not specified, then all the
96 * colors are opaque except for the transparent color.
98 * @param bits the number of bits needed to represent <code>size</code> colors
99 * @param size the number of colors in the color map
100 * @param reds the red component of all colors
101 * @param greens the green component of all colors
102 * @param blues the blue component of all colors
103 * @param trans the index of the transparent color
105 public IndexColorModel(int bits
, int size
, byte[] reds
, byte[] greens
,
106 byte[] blues
, int trans
)
108 this (bits
, size
, reds
, greens
, blues
, (byte[]) null);
113 * Each array much contain <code>size</code> elements. For each
114 * array, the i-th color is described by reds[i], greens[i],
115 * blues[i], alphas[i], unless alphas is not specified, then all the
116 * colors are opaque except for the transparent color.
118 * @param bits the number of bits needed to represent <code>size</code> colors
119 * @param size the number of colors in the color map
120 * @param reds the red component of all colors
121 * @param greens the green component of all colors
122 * @param blues the blue component of all colors
123 * @param alphas the alpha component of all colors
125 public IndexColorModel(int bits
, int size
, byte[] reds
, byte[] greens
,
126 byte[] blues
, byte[] alphas
)
128 // FIXME: This super() constructor should not be used since it can give
129 // the wrong value for hasAlpha() which is final and cannot be overloaded
132 opaque
= (alphas
== null);
137 for (int i
= 0; i
< size
; i
++)
140 | ((reds
[i
] & 0xff) << 16)
141 | ((greens
[i
] & 0xff) << 8)
142 | (blues
[i
] & 0xff));
147 for (int i
= 0; i
< size
; i
++)
149 rgb
[i
] = ((alphas
[i
] & 0xff) << 24
150 | ((reds
[i
] & 0xff) << 16)
151 | ((greens
[i
] & 0xff) << 8)
152 | (blues
[i
] & 0xff));
156 // Generate a bigint with 1's for every pixel
157 validBits
= validBits
.setBit(size
).subtract(BigInteger
.ONE
);
161 * Each array much contain <code>size</code> elements. For each
162 * array, the i-th color is described by reds[i], greens[i],
163 * blues[i], alphas[i], unless alphas is not specified, then all the
164 * colors are opaque except for the transparent color.
166 * @param bits the number of bits needed to represent <code>size</code> colors
167 * @param size the number of colors in the color map
168 * @param cmap packed color components
169 * @param start the offset of the first color component in <code>cmap</code>
170 * @param hasAlpha <code>cmap</code> has alpha values
171 * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1.
173 public IndexColorModel (int bits
, int size
, byte[] cmap
, int start
,
176 this (bits
, size
, cmap
, start
, hasAlpha
, -1);
180 * Construct an IndexColorModel from an array of red, green, blue, and
181 * optional alpha components. The component values are interleaved as RGB(A).
183 * @param bits the number of bits needed to represent <code>size</code> colors
184 * @param size the number of colors in the color map
185 * @param cmap interleaved color components
186 * @param start the offset of the first color component in <code>cmap</code>
187 * @param hasAlpha <code>cmap</code> has alpha values
188 * @param trans the index of the transparent color
189 * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1.
191 public IndexColorModel (int bits
, int size
, byte[] cmap
, int start
,
192 boolean hasAlpha
, int trans
)
196 throw new IllegalArgumentException("bits > 16");
198 throw new IllegalArgumentException("size < 1");
206 for (int i
= 0; i
< size
; i
++)
209 ((cmap
[4 * i
+ 3 + start
] & 0xff) << 24
211 | ((cmap
[4 * i
+ start
] & 0xff) << 16)
213 | ((cmap
[4 * i
+ 1 + start
] & 0xff) << 8)
215 | (cmap
[4 * i
+ 2 + start
] & 0xff));
219 for (int i
= 0; i
< size
; i
++)
222 | ((cmap
[3 * i
+ start
] & 0xff) << 16)
224 | ((cmap
[3 * i
+ 1 + start
] & 0xff) << 8)
226 | (cmap
[3 * i
+ 2 + start
] & 0xff));
229 // Generate a bigint with 1's for every pixel
230 validBits
= validBits
.setBit(size
).subtract(BigInteger
.ONE
);
234 * Construct an IndexColorModel from an array of <code>size</code> packed
235 * colors. Each int element contains 8-bit red, green, blue, and optional
236 * alpha values packed in order. If hasAlpha is false, then all the colors
237 * are opaque except for the transparent color.
239 * @param bits the number of bits needed to represent <code>size</code> colors
240 * @param size the number of colors in the color map
241 * @param cmap packed color components
242 * @param start the offset of the first color component in <code>cmap</code>
243 * @param hasAlpha <code>cmap</code> has alpha values
244 * @param trans the index of the transparent color
245 * @param transferType DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
246 * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1.
247 * @throws IllegalArgumentException if transferType is something other than
248 * TYPE_BYTE or TYPE_USHORT.
250 public IndexColorModel (int bits
, int size
, int[] cmap
, int start
,
251 boolean hasAlpha
, int trans
, int transferType
)
253 super(bits
* 4, // total bits, sRGB, four channels
254 nArray(bits
, 4), // bits for each channel
255 ColorSpace
.getInstance(ColorSpace
.CS_sRGB
), // sRGB
257 false, // not premultiplied
258 TRANSLUCENT
, transferType
);
259 if (transferType
!= DataBuffer
.TYPE_BYTE
260 && transferType
!= DataBuffer
.TYPE_USHORT
)
261 throw new IllegalArgumentException();
263 throw new IllegalArgumentException("bits > 16");
265 throw new IllegalArgumentException("size < 1");
272 for (int i
= 0; i
< size
; i
++)
273 rgb
[i
] = cmap
[i
+ start
] | 0xff000000;
275 System
.arraycopy(cmap
, start
, rgb
, 0, size
);
277 // Generate a bigint with 1's for every pixel
278 validBits
= validBits
.setBit(size
).subtract(BigInteger
.ONE
);
282 * Construct an IndexColorModel using a colormap with holes.
284 * The IndexColorModel is built from the array of ints defining the
285 * colormap. Each element contains red, green, blue, and alpha
286 * components. The ColorSpace is sRGB. The transparency value is
287 * automatically determined.
289 * This constructor permits indicating which colormap entries are valid,
290 * using the validBits argument. Each entry in cmap is valid if the
291 * corresponding bit in validBits is set.
293 * @param bits the number of bits needed to represent <code>size</code> colors
294 * @param size the number of colors in the color map
295 * @param cmap packed color components
296 * @param start the offset of the first color component in <code>cmap</code>
297 * @param transferType DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
298 * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1.
299 * @throws IllegalArgumentException if transferType is something other than
300 * TYPE_BYTE or TYPE_USHORT.
302 public IndexColorModel (int bits
, int size
, int[] cmap
, int start
,
303 int transferType
, BigInteger validBits
)
305 super(bits
* 4, // total bits, sRGB, four channels
306 nArray(bits
, 4), // bits for each channel
307 ColorSpace
.getInstance(ColorSpace
.CS_sRGB
), // sRGB
309 false, // not premultiplied
310 TRANSLUCENT
, transferType
);
311 if (transferType
!= DataBuffer
.TYPE_BYTE
312 && transferType
!= DataBuffer
.TYPE_USHORT
)
313 throw new IllegalArgumentException();
315 throw new IllegalArgumentException("bits > 16");
317 throw new IllegalArgumentException("size < 1");
321 this.validBits
= validBits
;
325 for (int i
= 0; i
< size
; i
++)
326 rgb
[i
] = cmap
[i
+ start
] | 0xff000000;
328 System
.arraycopy(cmap
, start
, rgb
, 0, size
);
331 public final int getMapSize ()
337 * Get the index of the transparent color in this color model
339 public final int getTransparentPixel ()
347 public final void getReds (byte[] r
)
349 getComponents (r
, 2);
355 public final void getGreens (byte[] g
)
357 getComponents (g
, 1);
363 public final void getBlues (byte[] b
)
365 getComponents (b
, 0);
371 public final void getAlphas (byte[] a
)
373 getComponents (a
, 3);
376 private void getComponents (byte[] c
, int ci
)
378 int i
, max
= (map_size
< c
.length
) ? map_size
: c
.length
;
379 for (i
= 0; i
< max
; i
++)
380 c
[i
] = (byte) ((generateMask (ci
) & rgb
[i
]) >> (ci
* pixel_bits
));
384 * Get the red component of the given pixel.
386 public final int getRed (int pixel
)
388 if (pixel
< map_size
)
389 return (int) ((generateMask (2) & rgb
[pixel
]) >> (2 * pixel_bits
));
395 * Get the green component of the given pixel.
397 public final int getGreen (int pixel
)
399 if (pixel
< map_size
)
400 return (int) ((generateMask (1) & rgb
[pixel
]) >> (1 * pixel_bits
));
406 * Get the blue component of the given pixel.
408 public final int getBlue (int pixel
)
410 if (pixel
< map_size
)
411 return (int) (generateMask (0) & rgb
[pixel
]);
417 * Get the alpha component of the given pixel.
419 public final int getAlpha (int pixel
)
421 if (opaque
|| pixel
>= map_size
)
424 return (int) ((generateMask (3) & rgb
[pixel
]) >> (3 * pixel_bits
));
428 * Get the RGB color value of the given pixel using the default
431 * @param pixel a pixel value
433 public final int getRGB (int pixel
)
435 if (pixel
< map_size
)
442 * Get the RGB color values of all pixels in the map using the default
445 * @param rgb The destination array.
447 public final void getRGBs (int[] rgb
)
449 System
.arraycopy(this.rgb
, 0, rgb
, 0, map_size
);
452 //pixel_bits is number of bits to be in generated mask
453 private int generateMask (int offset
)
455 return (((2 << pixel_bits
) - 1) << (pixel_bits
* offset
));
458 /** Return true if pixel is valid, false otherwise. */
459 public boolean isValid(int pixel
)
461 return validBits
.testBit(pixel
);
464 /** Return true if all pixels are valid, false otherwise. */
465 public boolean isValid()
467 // Generate a bigint with 1's for every pixel
468 BigInteger allbits
= new BigInteger("0");
469 allbits
.setBit(map_size
);
470 allbits
.subtract(new BigInteger("1"));
471 return allbits
.equals(validBits
);
475 * Returns a BigInteger where each bit represents an entry in the color
476 * model. If the bit is on, the entry is valid.
478 public BigInteger
getValidPixels()
484 * Construct a BufferedImage with rgb pixel values from a Raster.
486 * Constructs a new BufferedImage in which each pixel is an RGBA int from
487 * a Raster with index-valued pixels. If this model has no alpha component
488 * or transparent pixel, the type of the new BufferedImage is TYPE_INT_RGB.
489 * Otherwise the type is TYPE_INT_ARGB. If forceARGB is true, the type is
490 * forced to be TYPE_INT_ARGB no matter what.
492 * @param raster The source of pixel values.
493 * @param forceARGB True if type must be TYPE_INT_ARGB.
494 * @return New BufferedImage with RBGA int pixel values.
496 public BufferedImage
convertToIntDiscrete(Raster raster
, boolean forceARGB
)
498 int type
= forceARGB ? BufferedImage
.TYPE_INT_ARGB
499 : ((opaque
&& trans
== -1) ? BufferedImage
.TYPE_INT_RGB
:
500 BufferedImage
.TYPE_INT_ARGB
);
502 // FIXME: assuming that raster has only 1 band since pixels are supposed
503 // to be int indexes.
504 // FIXME: it would likely be more efficient to fetch a complete array,
505 // but it would take much more memory.
506 // FIXME: I'm not sure if transparent pixels or alpha values need special
508 BufferedImage im
= new BufferedImage(raster
.width
, raster
.height
, type
);
509 for (int x
= raster
.minX
; x
< raster
.width
+ raster
.minX
; x
++)
510 for (int y
= raster
.minY
; y
< raster
.height
+ raster
.minY
; y
++)
511 im
.setRGB(x
, y
, rgb
[raster
.getSample(x
, y
, 0)]);