Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / awt / image / IndexColorModel.java
blobe4ccc542903d99ae2901d8d31317fcad722b60b2
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)
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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. */
39 package java.awt.image;
41 import java.awt.color.ColorSpace;
42 import java.math.BigInteger;
44 /**
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
54 * the same index.
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
68 private int map_size;
69 private boolean opaque;
70 private int trans = -1;
71 private int[] rgb;
72 private BigInteger validBits = BigInteger.ZERO;
74 /**
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,
87 byte[] blues)
89 this (bits, size, reds, greens, blues, (byte[]) null);
92 /**
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);
109 this.trans = trans;
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
130 super(bits);
131 map_size = size;
132 opaque = (alphas == null);
134 rgb = new int[size];
135 if (alphas == null)
137 for (int i = 0; i < size; i++)
139 rgb[i] = (0xff000000
140 | ((reds[i] & 0xff) << 16)
141 | ((greens[i] & 0xff) << 8)
142 | (blues[i] & 0xff));
145 else
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,
174 boolean hasAlpha)
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)
194 super (bits);
195 if (bits > 16)
196 throw new IllegalArgumentException("bits > 16");
197 if (size < 1)
198 throw new IllegalArgumentException("size < 1");
199 map_size = size;
200 opaque = !hasAlpha;
201 this.trans = trans;
203 rgb = new int[size];
204 if (hasAlpha)
206 for (int i = 0; i < size; i++)
207 rgb[i] =
208 // alpha
209 ((cmap[4 * i + 3 + start] & 0xff) << 24
210 // red
211 | ((cmap[4 * i + start] & 0xff) << 16)
212 // green
213 | ((cmap[4 * i + 1 + start] & 0xff) << 8)
214 // blue
215 | (cmap[4 * i + 2 + start] & 0xff));
217 else
219 for (int i = 0; i < size; i++)
220 rgb[i] = (0xff000000
221 // red
222 | ((cmap[3 * i + start] & 0xff) << 16)
223 // green
224 | ((cmap[3 * i + 1 + start] & 0xff) << 8)
225 // blue
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
256 true, // has alpha
257 false, // not premultiplied
258 TRANSLUCENT, transferType);
259 if (transferType != DataBuffer.TYPE_BYTE
260 && transferType != DataBuffer.TYPE_USHORT)
261 throw new IllegalArgumentException();
262 if (bits > 16)
263 throw new IllegalArgumentException("bits > 16");
264 if (size < 1)
265 throw new IllegalArgumentException("size < 1");
266 map_size = size;
267 opaque = !hasAlpha;
268 this.trans = trans;
270 rgb = new int[size];
271 if (!hasAlpha)
272 for (int i = 0; i < size; i++)
273 rgb[i] = cmap[i + start] | 0xff000000;
274 else
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
308 true, // has alpha
309 false, // not premultiplied
310 TRANSLUCENT, transferType);
311 if (transferType != DataBuffer.TYPE_BYTE
312 && transferType != DataBuffer.TYPE_USHORT)
313 throw new IllegalArgumentException();
314 if (bits > 16)
315 throw new IllegalArgumentException("bits > 16");
316 if (size < 1)
317 throw new IllegalArgumentException("size < 1");
318 map_size = size;
319 opaque = false;
320 this.trans = -1;
321 this.validBits = validBits;
323 rgb = new int[size];
324 if (!hasAlpha)
325 for (int i = 0; i < size; i++)
326 rgb[i] = cmap[i + start] | 0xff000000;
327 else
328 System.arraycopy(cmap, start, rgb, 0, size);
331 public final int getMapSize ()
333 return map_size;
337 * Get the index of the transparent color in this color model
339 public final int getTransparentPixel ()
341 return trans;
345 * <br>
347 public final void getReds (byte[] r)
349 getComponents (r, 2);
353 * <br>
355 public final void getGreens (byte[] g)
357 getComponents (g, 1);
361 * <br>
363 public final void getBlues (byte[] b)
365 getComponents (b, 0);
369 * <br>
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));
391 return 0;
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));
402 return 0;
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]);
413 return 0;
417 * Get the alpha component of the given pixel.
419 public final int getAlpha (int pixel)
421 if (opaque || pixel >= map_size)
422 return 255;
424 return (int) ((generateMask (3) & rgb[pixel]) >> (3 * pixel_bits));
428 * Get the RGB color value of the given pixel using the default
429 * RGB color model.
431 * @param pixel a pixel value
433 public final int getRGB (int pixel)
435 if (pixel < map_size)
436 return rgb[pixel];
438 return 0;
442 * Get the RGB color values of all pixels in the map using the default
443 * RGB color model.
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);
474 /**
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()
480 return validBits;
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
507 // handling here.
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)]);
513 return im;