1 /*
2 * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.awt.image;
27
28 import java.awt.Transparency;
29 import java.awt.color.ColorSpace;
30 import java.math.BigInteger;
31
32 /**
33 * The <code>IndexColorModel</code> class is a <code>ColorModel</code>
34 * class that works with pixel values consisting of a
35 * single sample that is an index into a fixed colormap in the default
36 * sRGB color space. The colormap specifies red, green, blue, and
37 * optional alpha components corresponding to each index. All components
38 * are represented in the colormap as 8-bit unsigned integral values.
39 * Some constructors allow the caller to specify "holes" in the colormap
40 * by indicating which colormap entries are valid and which represent
41 * unusable colors via the bits set in a <code>BigInteger</code> object.
42 * This color model is similar to an X11 PseudoColor visual.
43 * <p>
44 * Some constructors provide a means to specify an alpha component
45 * for each pixel in the colormap, while others either provide no
46 * such means or, in some cases, a flag to indicate whether the
47 * colormap data contains alpha values. If no alpha is supplied to
48 * the constructor, an opaque alpha component (alpha = 1.0) is
49 * assumed for each entry.
50 * An optional transparent pixel value can be supplied that indicates a
51 * pixel to be made completely transparent, regardless of any alpha
52 * component supplied or assumed for that pixel value.
53 * Note that the color components in the colormap of an
54 * <code>IndexColorModel</code> objects are never pre-multiplied with
55 * the alpha components.
56 * <p>
57 * <a name="transparency">
58 * The transparency of an <code>IndexColorModel</code> object is
59 * determined by examining the alpha components of the colors in the
60 * colormap and choosing the most specific value after considering
61 * the optional alpha values and any transparent index specified.
62 * The transparency value is <code>Transparency.OPAQUE</code>
63 * only if all valid colors in
64 * the colormap are opaque and there is no valid transparent pixel.
65 * If all valid colors
66 * in the colormap are either completely opaque (alpha = 1.0) or
67 * completely transparent (alpha = 0.0), which typically occurs when
68 * a valid transparent pixel is specified,
69 * the value is <code>Transparency.BITMASK</code>.
70 * Otherwise, the value is <code>Transparency.TRANSLUCENT</code>, indicating
71 * that some valid color has an alpha component that is
72 * neither completely transparent nor completely opaque
73 * (0.0 < alpha < 1.0).
74 * </a>
75 *
76 * <p>
77 * If an <code>IndexColorModel</code> object has
78 * a transparency value of <code>Transparency.OPAQUE</code>,
79 * then the <code>hasAlpha</code>
80 * and <code>getNumComponents</code> methods
81 * (both inherited from <code>ColorModel</code>)
82 * return false and 3, respectively.
83 * For any other transparency value,
84 * <code>hasAlpha</code> returns true
85 * and <code>getNumComponents</code> returns 4.
86 *
87 * <p>
88 * <a name="index_values">
89 * The values used to index into the colormap are taken from the least
90 * significant <em>n</em> bits of pixel representations where
91 * <em>n</em> is based on the pixel size specified in the constructor.
92 * For pixel sizes smaller than 8 bits, <em>n</em> is rounded up to a
93 * power of two (3 becomes 4 and 5,6,7 become 8).
94 * For pixel sizes between 8 and 16 bits, <em>n</em> is equal to the
95 * pixel size.
96 * Pixel sizes larger than 16 bits are not supported by this class.
97 * Higher order bits beyond <em>n</em> are ignored in pixel representations.
98 * Index values greater than or equal to the map size, but less than
99 * 2<sup><em>n</em></sup>, are undefined and return 0 for all color and
100 * alpha components.
101 * <p>
102 * For those methods that use a primitive array pixel representation of
103 * type <code>transferType</code>, the array length is always one.
104 * The transfer types supported are <code>DataBuffer.TYPE_BYTE</code> and
105 * <code>DataBuffer.TYPE_USHORT</code>. A single int pixel
106 * representation is valid for all objects of this class, since it is
107 * always possible to represent pixel values used with this class in a
108 * single int. Therefore, methods that use this representation do
109 * not throw an <code>IllegalArgumentException</code> due to an invalid
110 * pixel value.
111 * <p>
112 * Many of the methods in this class are final. The reason for
113 * this is that the underlying native graphics code makes assumptions
114 * about the layout and operation of this class and those assumptions
115 * are reflected in the implementations of the methods here that are
116 * marked final. You can subclass this class for other reasons, but
117 * you cannot override or modify the behaviour of those methods.
118 *
119 * @see ColorModel
120 * @see ColorSpace
121 * @see DataBuffer
122 *
123 */
124 public class IndexColorModel extends ColorModel {
125 private int rgb[];
126 private int map_size;
127 private int pixel_mask;
128 private int transparent_index = -1;
129 private boolean allgrayopaque;
130 private BigInteger validBits;
131
132 private static int[] opaqueBits = {8, 8, 8};
133 private static int[] alphaBits = {8, 8, 8, 8};
134
135 static private native void initIDs();
136 static {
137 ColorModel.loadLibraries();
138 initIDs();
139 }
140 /**
141 * Constructs an <code>IndexColorModel</code> from the specified
142 * arrays of red, green, and blue components. Pixels described
143 * by this color model all have alpha components of 255
144 * unnormalized (1.0 normalized), which means they
145 * are fully opaque. All of the arrays specifying the color
146 * components must have at least the specified number of entries.
147 * The <code>ColorSpace</code> is the default sRGB space.
148 * Since there is no alpha information in any of the arguments
149 * to this constructor, the transparency value is always
150 * <code>Transparency.OPAQUE</code>.
151 * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
152 * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
153 * @param bits the number of bits each pixel occupies
154 * @param size the size of the color component arrays
155 * @param r the array of red color components
156 * @param g the array of green color components
157 * @param b the array of blue color components
158 * @throws IllegalArgumentException if <code>bits</code> is less
159 * than 1 or greater than 16
160 * @throws IllegalArgumentException if <code>size</code> is less
161 * than 1
162 */
163 public IndexColorModel(int bits, int size,
164 byte r[], byte g[], byte b[]) {
165 super(bits, opaqueBits,
166 ColorSpace.getInstance(ColorSpace.CS_sRGB),
167 false, false, OPAQUE,
168 ColorModel.getDefaultTransferType(bits));
169 if (bits < 1 || bits > 16) {
170 throw new IllegalArgumentException("Number of bits must be between"
171 +" 1 and 16.");
172 }
173 setRGBs(size, r, g, b, null);
174 calculatePixelMask();
175 }
176
177 /**
178 * Constructs an <code>IndexColorModel</code> from the given arrays
179 * of red, green, and blue components. Pixels described by this color
180 * model all have alpha components of 255 unnormalized
181 * (1.0 normalized), which means they are fully opaque, except
182 * for the indicated pixel to be made transparent. All of the arrays
183 * specifying the color components must have at least the specified
184 * number of entries.
185 * The <code>ColorSpace</code> is the default sRGB space.
186 * The transparency value may be <code>Transparency.OPAQUE</code> or
187 * <code>Transparency.BITMASK</code> depending on the arguments, as
188 * specified in the <a href="#transparency">class description</a> above.
189 * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
190 * or <code>DataBuffer.TYPE_USHORT</code> that can hold a
191 * single pixel.
192 * @param bits the number of bits each pixel occupies
193 * @param size the size of the color component arrays
194 * @param r the array of red color components
195 * @param g the array of green color components
196 * @param b the array of blue color components
197 * @param trans the index of the transparent pixel
198 * @throws IllegalArgumentException if <code>bits</code> is less than
199 * 1 or greater than 16
200 * @throws IllegalArgumentException if <code>size</code> is less than
201 * 1
202 */
203 public IndexColorModel(int bits, int size,
204 byte r[], byte g[], byte b[], int trans) {
205 super(bits, opaqueBits,
206 ColorSpace.getInstance(ColorSpace.CS_sRGB),
207 false, false, OPAQUE,
208 ColorModel.getDefaultTransferType(bits));
209 if (bits < 1 || bits > 16) {
210 throw new IllegalArgumentException("Number of bits must be between"
211 +" 1 and 16.");
212 }
213 setRGBs(size, r, g, b, null);
214 setTransparentPixel(trans);
215 calculatePixelMask();
216 }
217
218 /**
219 * Constructs an <code>IndexColorModel</code> from the given
220 * arrays of red, green, blue and alpha components. All of the
221 * arrays specifying the components must have at least the specified
222 * number of entries.
223 * The <code>ColorSpace</code> is the default sRGB space.
224 * The transparency value may be any of <code>Transparency.OPAQUE</code>,
225 * <code>Transparency.BITMASK</code>,
226 * or <code>Transparency.TRANSLUCENT</code>
227 * depending on the arguments, as specified
228 * in the <a href="#transparency">class description</a> above.
229 * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
230 * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
231 * @param bits the number of bits each pixel occupies
232 * @param size the size of the color component arrays
233 * @param r the array of red color components
234 * @param g the array of green color components
235 * @param b the array of blue color components
236 * @param a the array of alpha value components
237 * @throws IllegalArgumentException if <code>bits</code> is less
238 * than 1 or greater than 16
239 * @throws IllegalArgumentException if <code>size</code> is less
240 * than 1
241 */
242 public IndexColorModel(int bits, int size,
243 byte r[], byte g[], byte b[], byte a[]) {
244 super (bits, alphaBits,
245 ColorSpace.getInstance(ColorSpace.CS_sRGB),
246 true, false, TRANSLUCENT,
247 ColorModel.getDefaultTransferType(bits));
248 if (bits < 1 || bits > 16) {
249 throw new IllegalArgumentException("Number of bits must be between"
250 +" 1 and 16.");
251 }
252 setRGBs (size, r, g, b, a);
253 calculatePixelMask();
254 }
255
256 /**
257 * Constructs an <code>IndexColorModel</code> from a single
258 * array of interleaved red, green, blue and optional alpha
259 * components. The array must have enough values in it to
260 * fill all of the needed component arrays of the specified
261 * size. The <code>ColorSpace</code> is the default sRGB space.
262 * The transparency value may be any of <code>Transparency.OPAQUE</code>,
263 * <code>Transparency.BITMASK</code>,
264 * or <code>Transparency.TRANSLUCENT</code>
265 * depending on the arguments, as specified
266 * in the <a href="#transparency">class description</a> above.
267 * The transfer type is the smallest of
268 * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
269 * that can hold a single pixel.
270 *
271 * @param bits the number of bits each pixel occupies
272 * @param size the size of the color component arrays
273 * @param cmap the array of color components
274 * @param start the starting offset of the first color component
275 * @param hasalpha indicates whether alpha values are contained in
276 * the <code>cmap</code> array
277 * @throws IllegalArgumentException if <code>bits</code> is less
278 * than 1 or greater than 16
279 * @throws IllegalArgumentException if <code>size</code> is less
280 * than 1
281 */
282 public IndexColorModel(int bits, int size, byte cmap[], int start,
283 boolean hasalpha) {
284 this(bits, size, cmap, start, hasalpha, -1);
285 if (bits < 1 || bits > 16) {
286 throw new IllegalArgumentException("Number of bits must be between"
287 +" 1 and 16.");
288 }
289 }
290
291 /**
292 * Constructs an <code>IndexColorModel</code> from a single array of
293 * interleaved red, green, blue and optional alpha components. The
294 * specified transparent index represents a pixel that is made
295 * entirely transparent regardless of any alpha value specified
296 * for it. The array must have enough values in it to fill all
297 * of the needed component arrays of the specified size.
298 * The <code>ColorSpace</code> is the default sRGB space.
299 * The transparency value may be any of <code>Transparency.OPAQUE</code>,
300 * <code>Transparency.BITMASK</code>,
301 * or <code>Transparency.TRANSLUCENT</code>
302 * depending on the arguments, as specified
303 * in the <a href="#transparency">class description</a> above.
304 * The transfer type is the smallest of
305 * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
306 * that can hold a single pixel.
307 * @param bits the number of bits each pixel occupies
308 * @param size the size of the color component arrays
309 * @param cmap the array of color components
310 * @param start the starting offset of the first color component
311 * @param hasalpha indicates whether alpha values are contained in
312 * the <code>cmap</code> array
313 * @param trans the index of the fully transparent pixel
314 * @throws IllegalArgumentException if <code>bits</code> is less than
315 * 1 or greater than 16
316 * @throws IllegalArgumentException if <code>size</code> is less than
317 * 1
318 */
319 public IndexColorModel(int bits, int size, byte cmap[], int start,
320 boolean hasalpha, int trans) {
321 // REMIND: This assumes the ordering: RGB[A]
322 super(bits, opaqueBits,
323 ColorSpace.getInstance(ColorSpace.CS_sRGB),
324 false, false, OPAQUE,
325 ColorModel.getDefaultTransferType(bits));
326
327 if (bits < 1 || bits > 16) {
328 throw new IllegalArgumentException("Number of bits must be between"
329 +" 1 and 16.");
330 }
331 if (size < 1) {
332 throw new IllegalArgumentException("Map size ("+size+
333 ") must be >= 1");
334 }
335 map_size = size;
336 rgb = new int[calcRealMapSize(bits, size)];
337 int j = start;
338 int alpha = 0xff;
339 boolean allgray = true;
340 int transparency = OPAQUE;
341 for (int i = 0; i < size; i++) {
342 int r = cmap[j++] & 0xff;
343 int g = cmap[j++] & 0xff;
344 int b = cmap[j++] & 0xff;
345 allgray = allgray && (r == g) && (g == b);
346 if (hasalpha) {
347 alpha = cmap[j++] & 0xff;
348 if (alpha != 0xff) {
349 if (alpha == 0x00) {
350 if (transparency == OPAQUE) {
351 transparency = BITMASK;
352 }
353 if (transparent_index < 0) {
354 transparent_index = i;
355 }
356 } else {
357 transparency = TRANSLUCENT;
358 }
359 allgray = false;
360 }
361 }
362 rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b;
363 }
364 this.allgrayopaque = allgray;
365 setTransparency(transparency);
366 setTransparentPixel(trans);
367 calculatePixelMask();
368 }
369
370 /**
371 * Constructs an <code>IndexColorModel</code> from an array of
372 * ints where each int is comprised of red, green, blue, and
373 * optional alpha components in the default RGB color model format.
374 * The specified transparent index represents a pixel that is made
375 * entirely transparent regardless of any alpha value specified
376 * for it. The array must have enough values in it to fill all
377 * of the needed component arrays of the specified size.
378 * The <code>ColorSpace</code> is the default sRGB space.
379 * The transparency value may be any of <code>Transparency.OPAQUE</code>,
380 * <code>Transparency.BITMASK</code>,
381 * or <code>Transparency.TRANSLUCENT</code>
382 * depending on the arguments, as specified
383 * in the <a href="#transparency">class description</a> above.
384 * @param bits the number of bits each pixel occupies
385 * @param size the size of the color component arrays
386 * @param cmap the array of color components
387 * @param start the starting offset of the first color component
388 * @param hasalpha indicates whether alpha values are contained in
389 * the <code>cmap</code> array
390 * @param trans the index of the fully transparent pixel
391 * @param transferType the data type of the array used to represent
392 * pixel values. The data type must be either
393 * <code>DataBuffer.TYPE_BYTE</code> or
394 * <code>DataBuffer.TYPE_USHORT</code>.
395 * @throws IllegalArgumentException if <code>bits</code> is less
396 * than 1 or greater than 16
397 * @throws IllegalArgumentException if <code>size</code> is less
398 * than 1
399 * @throws IllegalArgumentException if <code>transferType</code> is not
400 * one of <code>DataBuffer.TYPE_BYTE</code> or
401 * <code>DataBuffer.TYPE_USHORT</code>
402 */
403 public IndexColorModel(int bits, int size,
404 int cmap[], int start,
405 boolean hasalpha, int trans, int transferType) {
406 // REMIND: This assumes the ordering: RGB[A]
407 super(bits, opaqueBits,
408 ColorSpace.getInstance(ColorSpace.CS_sRGB),
409 false, false, OPAQUE,
410 transferType);
411
412 if (bits < 1 || bits > 16) {
413 throw new IllegalArgumentException("Number of bits must be between"
414 +" 1 and 16.");
415 }
416 if (size < 1) {
417 throw new IllegalArgumentException("Map size ("+size+
418 ") must be >= 1");
419 }
420 if ((transferType != DataBuffer.TYPE_BYTE) &&
421 (transferType != DataBuffer.TYPE_USHORT)) {
422 throw new IllegalArgumentException("transferType must be either" +
423 "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT");
424 }
425
426 setRGBs(size, cmap, start, hasalpha);
427 setTransparentPixel(trans);
428 calculatePixelMask();
429 }
430
431 /**
432 * Constructs an <code>IndexColorModel</code> from an
433 * <code>int</code> array where each <code>int</code> is
434 * comprised of red, green, blue, and alpha
435 * components in the default RGB color model format.
436 * The array must have enough values in it to fill all
437 * of the needed component arrays of the specified size.
438 * The <code>ColorSpace</code> is the default sRGB space.
439 * The transparency value may be any of <code>Transparency.OPAQUE</code>,
440 * <code>Transparency.BITMASK</code>,
441 * or <code>Transparency.TRANSLUCENT</code>
442 * depending on the arguments, as specified
443 * in the <a href="#transparency">class description</a> above.
444 * The transfer type must be one of <code>DataBuffer.TYPE_BYTE</code>
445 * <code>DataBuffer.TYPE_USHORT</code>.
446 * The <code>BigInteger</code> object specifies the valid/invalid pixels
447 * in the <code>cmap</code> array. A pixel is valid if the
448 * <code>BigInteger</code> value at that index is set, and is invalid
449 * if the <code>BigInteger</code> bit at that index is not set.
450 * @param bits the number of bits each pixel occupies
451 * @param size the size of the color component array
452 * @param cmap the array of color components
453 * @param start the starting offset of the first color component
454 * @param transferType the specified data type
455 * @param validBits a <code>BigInteger</code> object. If a bit is
456 * set in the BigInteger, the pixel at that index is valid.
457 * If a bit is not set, the pixel at that index
458 * is considered invalid. If null, all pixels are valid.
459 * Only bits from 0 to the map size are considered.
460 * @throws IllegalArgumentException if <code>bits</code> is less
461 * than 1 or greater than 16
462 * @throws IllegalArgumentException if <code>size</code> is less
463 * than 1
464 * @throws IllegalArgumentException if <code>transferType</code> is not
465 * one of <code>DataBuffer.TYPE_BYTE</code> or
466 * <code>DataBuffer.TYPE_USHORT</code>
467 *
468 * @since 1.3
469 */
470 public IndexColorModel(int bits, int size, int cmap[], int start,
471 int transferType, BigInteger validBits) {
472 super (bits, alphaBits,
473 ColorSpace.getInstance(ColorSpace.CS_sRGB),
474 true, false, TRANSLUCENT,
475 transferType);
476
477 if (bits < 1 || bits > 16) {
478 throw new IllegalArgumentException("Number of bits must be between"
479 +" 1 and 16.");
480 }
481 if (size < 1) {
482 throw new IllegalArgumentException("Map size ("+size+
483 ") must be >= 1");
484 }
485 if ((transferType != DataBuffer.TYPE_BYTE) &&
486 (transferType != DataBuffer.TYPE_USHORT)) {
487 throw new IllegalArgumentException("transferType must be either" +
488 "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT");
489 }
490
491 if (validBits != null) {
492 // Check to see if it is all valid
493 for (int i=0; i < size; i++) {
494 if (!validBits.testBit(i)) {
495 this.validBits = validBits;
496 break;
497 }
498 }
499 }
500
501 setRGBs(size, cmap, start, true);
502 calculatePixelMask();
503 }
504
505 private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) {
506 if (size < 1) {
507 throw new IllegalArgumentException("Map size ("+size+
508 ") must be >= 1");
509 }
510 map_size = size;
511 rgb = new int[calcRealMapSize(pixel_bits, size)];
512 int alpha = 0xff;
513 int transparency = OPAQUE;
514 boolean allgray = true;
515 for (int i = 0; i < size; i++) {
516 int rc = r[i] & 0xff;
517 int gc = g[i] & 0xff;
518 int bc = b[i] & 0xff;
519 allgray = allgray && (rc == gc) && (gc == bc);
520 if (a != null) {
521 alpha = a[i] & 0xff;
522 if (alpha != 0xff) {
523 if (alpha == 0x00) {
524 if (transparency == OPAQUE) {
525 transparency = BITMASK;
526 }
527 if (transparent_index < 0) {
528 transparent_index = i;
529 }
530 } else {
531 transparency = TRANSLUCENT;
532 }
533 allgray = false;
534 }
535 }
536 rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc;
537 }
538 this.allgrayopaque = allgray;
539 setTransparency(transparency);
540 }
541
542 private void setRGBs(int size, int cmap[], int start, boolean hasalpha) {
543 map_size = size;
544 rgb = new int[calcRealMapSize(pixel_bits, size)];
545 int j = start;
546 int transparency = OPAQUE;
547 boolean allgray = true;
548 BigInteger validBits = this.validBits;
549 for (int i = 0; i < size; i++, j++) {
550 if (validBits != null && !validBits.testBit(i)) {
551 continue;
552 }
553 int cmaprgb = cmap[j];
554 int r = (cmaprgb >> 16) & 0xff;
555 int g = (cmaprgb >> 8) & 0xff;
556 int b = (cmaprgb ) & 0xff;
557 allgray = allgray && (r == g) && (g == b);
558 if (hasalpha) {
559 int alpha = cmaprgb >>> 24;
560 if (alpha != 0xff) {
561 if (alpha == 0x00) {
562 if (transparency == OPAQUE) {
563 transparency = BITMASK;
564 }
565 if (transparent_index < 0) {
566 transparent_index = i;
567 }
568 } else {
569 transparency = TRANSLUCENT;
570 }
571 allgray = false;
572 }
573 } else {
574 cmaprgb |= 0xff000000;
575 }
576 rgb[i] = cmaprgb;
577 }
578 this.allgrayopaque = allgray;
579 setTransparency(transparency);
580 }
581
582 private int calcRealMapSize(int bits, int size) {
583 int newSize = Math.max(1 << bits, size);
584 return Math.max(newSize, 256);
585 }
586
587 private BigInteger getAllValid() {
588 int numbytes = (map_size+7)/8;
589 byte[] valid = new byte[numbytes];
590 java.util.Arrays.fill(valid, (byte)0xff);
591 valid[0] = (byte)(0xff >>> (numbytes*8 - map_size));
592
593 return new BigInteger(1, valid);
594 }
595
596 /**
597 * Returns the transparency. Returns either OPAQUE, BITMASK,
598 * or TRANSLUCENT
599 * @return the transparency of this <code>IndexColorModel</code>
600 * @see Transparency#OPAQUE
601 * @see Transparency#BITMASK
602 * @see Transparency#TRANSLUCENT
603 */
604 public int getTransparency() {
605 return transparency;
606 }
607
608 /**
609 * Returns an array of the number of bits for each color/alpha component.
610 * The array contains the color components in the order red, green,
611 * blue, followed by the alpha component, if present.
612 * @return an array containing the number of bits of each color
613 * and alpha component of this <code>IndexColorModel</code>
614 */
615 public int[] getComponentSize() {
616 if (nBits == null) {
617 if (supportsAlpha) {
618 nBits = new int[4];
619 nBits[3] = 8;
620 }
621 else {
622 nBits = new int[3];
623 }
624 nBits[0] = nBits[1] = nBits[2] = 8;
625 }
626 return nBits;
627 }
628
629 /**
630 * Returns the size of the color/alpha component arrays in this
631 * <code>IndexColorModel</code>.
632 * @return the size of the color and alpha component arrays.
633 */
634 final public int getMapSize() {
635 return map_size;
636 }
637
638 /**
639 * Returns the index of a transparent pixel in this
640 * <code>IndexColorModel</code> or -1 if there is no pixel
641 * with an alpha value of 0. If a transparent pixel was
642 * explicitly specified in one of the constructors by its
643 * index, then that index will be preferred, otherwise,
644 * the index of any pixel which happens to be fully transparent
645 * may be returned.
646 * @return the index of a transparent pixel in this
647 * <code>IndexColorModel</code> object, or -1 if there
648 * is no such pixel
649 */
650 final public int getTransparentPixel() {
651 return transparent_index;
652 }
653
654 /**
655 * Copies the array of red color components into the specified array.
656 * Only the initial entries of the array as specified by
657 * {@link #getMapSize() getMapSize} are written.
658 * @param r the specified array into which the elements of the
659 * array of red color components are copied
660 */
661 final public void getReds(byte r[]) {
662 for (int i = 0; i < map_size; i++) {
663 r[i] = (byte) (rgb[i] >> 16);
664 }
665 }
666
667 /**
668 * Copies the array of green color components into the specified array.
669 * Only the initial entries of the array as specified by
670 * <code>getMapSize</code> are written.
671 * @param g the specified array into which the elements of the
672 * array of green color components are copied
673 */
674 final public void getGreens(byte g[]) {
675 for (int i = 0; i < map_size; i++) {
676 g[i] = (byte) (rgb[i] >> 8);
677 }
678 }
679
680 /**
681 * Copies the array of blue color components into the specified array.
682 * Only the initial entries of the array as specified by
683 * <code>getMapSize</code> are written.
684 * @param b the specified array into which the elements of the
685 * array of blue color components are copied
686 */
687 final public void getBlues(byte b[]) {
688 for (int i = 0; i < map_size; i++) {
689 b[i] = (byte) rgb[i];
690 }
691 }
692
693 /**
694 * Copies the array of alpha transparency components into the
695 * specified array. Only the initial entries of the array as specified
696 * by <code>getMapSize</code> are written.
697 * @param a the specified array into which the elements of the
698 * array of alpha components are copied
699 */
700 final public void getAlphas(byte a[]) {
701 for (int i = 0; i < map_size; i++) {
702 a[i] = (byte) (rgb[i] >> 24);
703 }
704 }
705
706 /**
707 * Converts data for each index from the color and alpha component
708 * arrays to an int in the default RGB ColorModel format and copies
709 * the resulting 32-bit ARGB values into the specified array. Only
710 * the initial entries of the array as specified by
711 * <code>getMapSize</code> are
712 * written.
713 * @param rgb the specified array into which the converted ARGB
714 * values from this array of color and alpha components
715 * are copied.
716 */
717 final public void getRGBs(int rgb[]) {
718 System.arraycopy(this.rgb, 0, rgb, 0, map_size);
719 }
720
721 private void setTransparentPixel(int trans) {
722 if (trans >= 0 && trans < map_size) {
723 rgb[trans] &= 0x00ffffff;
724 transparent_index = trans;
725 allgrayopaque = false;
726 if (this.transparency == OPAQUE) {
727 setTransparency(BITMASK);
728 }
729 }
730 }
731
732 private void setTransparency(int transparency) {
733 if (this.transparency != transparency) {
734 this.transparency = transparency;
735 if (transparency == OPAQUE) {
736 supportsAlpha = false;
737 numComponents = 3;
738 nBits = opaqueBits;
739 } else {
740 supportsAlpha = true;
741 numComponents = 4;
742 nBits = alphaBits;
743 }
744 }
745 }
746
747 /**
748 * This method is called from the constructors to set the pixel_mask
749 * value, which is based on the value of pixel_bits. The pixel_mask
750 * value is used to mask off the pixel parameters for methods such
751 * as getRed(), getGreen(), getBlue(), getAlpha(), and getRGB().
752 */
753 private final void calculatePixelMask() {
754 // Note that we adjust the mask so that our masking behavior here
755 // is consistent with that of our native rendering loops.
756 int maskbits = pixel_bits;
757 if (maskbits == 3) {
758 maskbits = 4;
759 } else if (maskbits > 4 && maskbits < 8) {
760 maskbits = 8;
761 }
762 pixel_mask = (1 << maskbits) - 1;
763 }
764
765 /**
766 * Returns the red color component for the specified pixel, scaled
767 * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
768 * is specified as an int.
769 * Only the lower <em>n</em> bits of the pixel value, as specified in the
770 * <a href="#index_values">class description</a> above, are used to
771 * calculate the returned value.
772 * The returned value is a non pre-multiplied value.
773 * @param pixel the specified pixel
774 * @return the value of the red color component for the specified pixel
775 */
776 final public int getRed(int pixel) {
777 return (rgb[pixel & pixel_mask] >> 16) & 0xff;
778 }
779
780 /**
781 * Returns the green color component for the specified pixel, scaled
782 * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
783 * is specified as an int.
784 * Only the lower <em>n</em> bits of the pixel value, as specified in the
785 * <a href="#index_values">class description</a> above, are used to
786 * calculate the returned value.
787 * The returned value is a non pre-multiplied value.
788 * @param pixel the specified pixel
789 * @return the value of the green color component for the specified pixel
790 */
791 final public int getGreen(int pixel) {
792 return (rgb[pixel & pixel_mask] >> 8) & 0xff;
793 }
794
795 /**
796 * Returns the blue color component for the specified pixel, scaled
797 * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
798 * is specified as an int.
799 * Only the lower <em>n</em> bits of the pixel value, as specified in the
800 * <a href="#index_values">class description</a> above, are used to
801 * calculate the returned value.
802 * The returned value is a non pre-multiplied value.
803 * @param pixel the specified pixel
804 * @return the value of the blue color component for the specified pixel
805 */
806 final public int getBlue(int pixel) {
807 return rgb[pixel & pixel_mask] & 0xff;
808 }
809
810 /**
811 * Returns the alpha component for the specified pixel, scaled
812 * from 0 to 255. The pixel value is specified as an int.
813 * Only the lower <em>n</em> bits of the pixel value, as specified in the
814 * <a href="#index_values">class description</a> above, are used to
815 * calculate the returned value.
816 * @param pixel the specified pixel
817 * @return the value of the alpha component for the specified pixel
818 */
819 final public int getAlpha(int pixel) {
820 return (rgb[pixel & pixel_mask] >> 24) & 0xff;
821 }
822
823 /**
824 * Returns the color/alpha components of the pixel in the default
825 * RGB color model format. The pixel value is specified as an int.
826 * Only the lower <em>n</em> bits of the pixel value, as specified in the
827 * <a href="#index_values">class description</a> above, are used to
828 * calculate the returned value.
829 * The returned value is in a non pre-multiplied format.
830 * @param pixel the specified pixel
831 * @return the color and alpha components of the specified pixel
832 * @see ColorModel#getRGBdefault
833 */
834 final public int getRGB(int pixel) {
835 return rgb[pixel & pixel_mask];
836 }
837
838 private static final int CACHESIZE = 40;
839 private int lookupcache[] = new int[CACHESIZE];
840
841 /**
842 * Returns a data element array representation of a pixel in this
843 * ColorModel, given an integer pixel representation in the
844 * default RGB color model. This array can then be passed to the
845 * {@link WritableRaster#setDataElements(int, int, java.lang.Object) setDataElements}
846 * method of a {@link WritableRaster} object. If the pixel variable is
847 * <code>null</code>, a new array is allocated. If <code>pixel</code>
848 * is not <code>null</code>, it must be
849 * a primitive array of type <code>transferType</code>; otherwise, a
850 * <code>ClassCastException</code> is thrown. An
851 * <code>ArrayIndexOutOfBoundsException</code> is
852 * thrown if <code>pixel</code> is not large enough to hold a pixel
853 * value for this <code>ColorModel</code>. The pixel array is returned.
854 * <p>
855 * Since <code>IndexColorModel</code> can be subclassed, subclasses
856 * inherit the implementation of this method and if they don't
857 * override it then they throw an exception if they use an
858 * unsupported <code>transferType</code>.
859 *
860 * @param rgb the integer pixel representation in the default RGB
861 * color model
862 * @param pixel the specified pixel
863 * @return an array representation of the specified pixel in this
864 * <code>IndexColorModel</code>.
865 * @throws ClassCastException if <code>pixel</code>
866 * is not a primitive array of type <code>transferType</code>
867 * @throws ArrayIndexOutOfBoundsException if
868 * <code>pixel</code> is not large enough to hold a pixel value
869 * for this <code>ColorModel</code>
870 * @throws UnsupportedOperationException if <code>transferType</code>
871 * is invalid
872 * @see WritableRaster#setDataElements
873 * @see SampleModel#setDataElements
874 */
875 public synchronized Object getDataElements(int rgb, Object pixel) {
876 int red = (rgb>>16) & 0xff;
877 int green = (rgb>>8) & 0xff;
878 int blue = rgb & 0xff;
879 int alpha = (rgb>>>24);
880 int pix = 0;
881
882 // Note that pixels are stored at lookupcache[2*i]
883 // and the rgb that was searched is stored at
884 // lookupcache[2*i+1]. Also, the pixel is first
885 // inverted using the unary complement operator
886 // before storing in the cache so it can never be 0.
887 for (int i = CACHESIZE - 2; i >= 0; i -= 2) {
888 if ((pix = lookupcache[i]) == 0) {
889 break;
890 }
891 if (rgb == lookupcache[i+1]) {
892 return installpixel(pixel, ~pix);
893 }
894 }
895
896 if (allgrayopaque) {
897 // IndexColorModel objects are all tagged as
898 // non-premultiplied so ignore the alpha value
899 // of the incoming color, convert the
900 // non-premultiplied color components to a
901 // grayscale value and search for the closest
902 // gray value in the palette. Since all colors
903 // in the palette are gray, we only need compare
904 // to one of the color components for a match
905 // using a simple linear distance formula.
906
907 int minDist = 256;
908 int d;
909 int gray = (int) (red*77 + green*150 + blue*29 + 128)/256;
910
911 for (int i = 0; i < map_size; i++) {
912 if (this.rgb[i] == 0x0) {
913 // For allgrayopaque colormaps, entries are 0
914 // iff they are an invalid color and should be
915 // ignored during color searches.
916 continue;
917 }
918 d = (this.rgb[i] & 0xff) - gray;
919 if (d < 0) d = -d;
920 if (d < minDist) {
921 pix = i;
922 if (d == 0) {
923 break;
924 }
925 minDist = d;
926 }
927 }
928 } else if (transparency == OPAQUE) {
929 // IndexColorModel objects are all tagged as
930 // non-premultiplied so ignore the alpha value
931 // of the incoming color and search for closest
932 // color match independently using a 3 component
933 // Euclidean distance formula.
934 // For opaque colormaps, palette entries are 0
935 // iff they are an invalid color and should be
936 // ignored during color searches.
937 // As an optimization, exact color searches are
938 // likely to be fairly common in opaque colormaps
939 // so first we will do a quick search for an
940 // exact match.
941
942 int smallestError = Integer.MAX_VALUE;
943 int lut[] = this.rgb;
944 int lutrgb;
945 for (int i=0; i < map_size; i++) {
946 lutrgb = lut[i];
947 if (lutrgb == rgb && lutrgb != 0) {
948 pix = i;
949 smallestError = 0;
950 break;
951 }
952 }
953
954 if (smallestError != 0) {
955 for (int i=0; i < map_size; i++) {
956 lutrgb = lut[i];
957 if (lutrgb == 0) {
958 continue;
959 }
960
961 int tmp = ((lutrgb >> 16) & 0xff) - red;
962 int currentError = tmp*tmp;
963 if (currentError < smallestError) {
964 tmp = ((lutrgb >> 8) & 0xff) - green;
965 currentError += tmp * tmp;
966 if (currentError < smallestError) {
967 tmp = (lutrgb & 0xff) - blue;
968 currentError += tmp * tmp;
969 if (currentError < smallestError) {
970 pix = i;
971 smallestError = currentError;
972 }
973 }
974 }
975 }
976 }
977 } else if (alpha == 0 && transparent_index >= 0) {
978 // Special case - transparent color maps to the
979 // specified transparent pixel, if there is one
980
981 pix = transparent_index;
982 } else {
983 // IndexColorModel objects are all tagged as
984 // non-premultiplied so use non-premultiplied
985 // color components in the distance calculations.
986 // Look for closest match using a 4 component
987 // Euclidean distance formula.
988
989 int smallestError = Integer.MAX_VALUE;
990 int lut[] = this.rgb;
991 for (int i=0; i < map_size; i++) {
992 int lutrgb = lut[i];
993 if (lutrgb == rgb) {
994 if (validBits != null && !validBits.testBit(i)) {
995 continue;
996 }
997 pix = i;
998 break;
999 }
1000
1001 int tmp = ((lutrgb >> 16) & 0xff) - red;
1002 int currentError = tmp*tmp;
1003 if (currentError < smallestError) {
1004 tmp = ((lutrgb >> 8) & 0xff) - green;
1005 currentError += tmp * tmp;
1006 if (currentError < smallestError) {
1007 tmp = (lutrgb & 0xff) - blue;
1008 currentError += tmp * tmp;
1009 if (currentError < smallestError) {
1010 tmp = (lutrgb >>> 24) - alpha;
1011 currentError += tmp * tmp;
1012 if (currentError < smallestError &&
1013 (validBits == null || validBits.testBit(i)))
1014 {
1015 pix = i;
1016 smallestError = currentError;
1017 }
1018 }
1019 }
1020 }
1021 }
1022 }
1023 System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2);
1024 lookupcache[CACHESIZE - 1] = rgb;
1025 lookupcache[CACHESIZE - 2] = ~pix;
1026 return installpixel(pixel, pix);
1027 }
1028
1029 private Object installpixel(Object pixel, int pix) {
1030 switch (transferType) {
1031 case DataBuffer.TYPE_INT:
1032 int[] intObj;
1033 if (pixel == null) {
1034 pixel = intObj = new int[1];
1035 } else {
1036 intObj = (int[]) pixel;
1037 }
1038 intObj[0] = pix;
1039 break;
1040 case DataBuffer.TYPE_BYTE:
1041 byte[] byteObj;
1042 if (pixel == null) {
1043 pixel = byteObj = new byte[1];
1044 } else {
1045 byteObj = (byte[]) pixel;
1046 }
1047 byteObj[0] = (byte) pix;
1048 break;
1049 case DataBuffer.TYPE_USHORT:
1050 short[] shortObj;
1051 if (pixel == null) {
1052 pixel = shortObj = new short[1];
1053 } else {
1054 shortObj = (short[]) pixel;
1055 }
1056 shortObj[0] = (short) pix;
1057 break;
1058 default:
1059 throw new UnsupportedOperationException("This method has not been "+
1060 "implemented for transferType " + transferType);
1061 }
1062 return pixel;
1063 }
1064
1065 /**
1066 * Returns an array of unnormalized color/alpha components for a
1067 * specified pixel in this <code>ColorModel</code>. The pixel value
1068 * is specified as an int. If the <code>components</code> array is <code>null</code>,
1069 * a new array is allocated that contains
1070 * <code>offset + getNumComponents()</code> elements.
1071 * The <code>components</code> array is returned,
1072 * with the alpha component included
1073 * only if <code>hasAlpha</code> returns true.
1074 * Color/alpha components are stored in the <code>components</code> array starting
1075 * at <code>offset</code> even if the array is allocated by this method.
1076 * An <code>ArrayIndexOutOfBoundsException</code>
1077 * is thrown if the <code>components</code> array is not <code>null</code> and is
1078 * not large enough to hold all the color and alpha components
1079 * starting at <code>offset</code>.
1080 * @param pixel the specified pixel
1081 * @param components the array to receive the color and alpha
1082 * components of the specified pixel
1083 * @param offset the offset into the <code>components</code> array at
1084 * which to start storing the color and alpha components
1085 * @return an array containing the color and alpha components of the
1086 * specified pixel starting at the specified offset.
1087 * @see ColorModel#hasAlpha
1088 * @see ColorModel#getNumComponents
1089 */
1090 public int[] getComponents(int pixel, int[] components, int offset) {
1091 if (components == null) {
1092 components = new int[offset+numComponents];
1093 }
1094
1095 // REMIND: Needs to change if different color space
1096 components[offset+0] = getRed(pixel);
1097 components[offset+1] = getGreen(pixel);
1098 components[offset+2] = getBlue(pixel);
1099 if (supportsAlpha && (components.length-offset) > 3) {
1100 components[offset+3] = getAlpha(pixel);
1101 }
1102
1103 return components;
1104 }
1105
1106 /**
1107 * Returns an array of unnormalized color/alpha components for
1108 * a specified pixel in this <code>ColorModel</code>. The pixel
1109 * value is specified by an array of data elements of type
1110 * <code>transferType</code> passed in as an object reference.
1111 * If <code>pixel</code> is not a primitive array of type
1112 * <code>transferType</code>, a <code>ClassCastException</code>
1113 * is thrown. An <code>ArrayIndexOutOfBoundsException</code>
1114 * is thrown if <code>pixel</code> is not large enough to hold
1115 * a pixel value for this <code>ColorModel</code>. If the
1116 * <code>components</code> array is <code>null</code>, a new array
1117 * is allocated that contains
1118 * <code>offset + getNumComponents()</code> elements.
1119 * The <code>components</code> array is returned,
1120 * with the alpha component included
1121 * only if <code>hasAlpha</code> returns true.
1122 * Color/alpha components are stored in the <code>components</code>
1123 * array starting at <code>offset</code> even if the array is
1124 * allocated by this method. An
1125 * <code>ArrayIndexOutOfBoundsException</code> is also
1126 * thrown if the <code>components</code> array is not
1127 * <code>null</code> and is not large enough to hold all the color
1128 * and alpha components starting at <code>offset</code>.
1129 * <p>
1130 * Since <code>IndexColorModel</code> can be subclassed, subclasses
1131 * inherit the implementation of this method and if they don't
1132 * override it then they throw an exception if they use an
1133 * unsupported <code>transferType</code>.
1134 *
1135 * @param pixel the specified pixel
1136 * @param components an array that receives the color and alpha
1137 * components of the specified pixel
1138 * @param offset the index into the <code>components</code> array at
1139 * which to begin storing the color and alpha components of the
1140 * specified pixel
1141 * @return an array containing the color and alpha components of the
1142 * specified pixel starting at the specified offset.
1143 * @throws ArrayIndexOutOfBoundsException if <code>pixel</code>
1144 * is not large enough to hold a pixel value for this
1145 * <code>ColorModel</code> or if the
1146 * <code>components</code> array is not <code>null</code>
1147 * and is not large enough to hold all the color
1148 * and alpha components starting at <code>offset</code>
1149 * @throws ClassCastException if <code>pixel</code> is not a
1150 * primitive array of type <code>transferType</code>
1151 * @throws UnsupportedOperationException if <code>transferType</code>
1152 * is not one of the supported transer types
1153 * @see ColorModel#hasAlpha
1154 * @see ColorModel#getNumComponents
1155 */
1156 public int[] getComponents(Object pixel, int[] components, int offset) {
1157 int intpixel;
1158 switch (transferType) {
1159 case DataBuffer.TYPE_BYTE:
1160 byte bdata[] = (byte[])pixel;
1161 intpixel = bdata[0] & 0xff;
1162 break;
1163 case DataBuffer.TYPE_USHORT:
1164 short sdata[] = (short[])pixel;
1165 intpixel = sdata[0] & 0xffff;
1166 break;
1167 case DataBuffer.TYPE_INT:
1168 int idata[] = (int[])pixel;
1169 intpixel = idata[0];
1170 break;
1171 default:
1172 throw new UnsupportedOperationException("This method has not been "+
1173 "implemented for transferType " + transferType);
1174 }
1175 return getComponents(intpixel, components, offset);
1176 }
1177
1178 /**
1179 * Returns a pixel value represented as an int in this
1180 * <code>ColorModel</code> given an array of unnormalized
1181 * color/alpha components. An
1182 * <code>ArrayIndexOutOfBoundsException</code>
1183 * is thrown if the <code>components</code> array is not large
1184 * enough to hold all of the color and alpha components starting
1185 * at <code>offset</code>. Since
1186 * <code>ColorModel</code> can be subclassed, subclasses inherit the
1187 * implementation of this method and if they don't override it then
1188 * they throw an exception if they use an unsupported transferType.
1189 * @param components an array of unnormalized color and alpha
1190 * components
1191 * @param offset the index into <code>components</code> at which to
1192 * begin retrieving the color and alpha components
1193 * @return an <code>int</code> pixel value in this
1194 * <code>ColorModel</code> corresponding to the specified components.
1195 * @throws ArrayIndexOutOfBoundsException if
1196 * the <code>components</code> array is not large enough to
1197 * hold all of the color and alpha components starting at
1198 * <code>offset</code>
1199 * @throws UnsupportedOperationException if <code>transferType</code>
1200 * is invalid
1201 */
1202 public int getDataElement(int[] components, int offset) {
1203 int rgb = (components[offset+0]<<16)
1204 | (components[offset+1]<<8) | (components[offset+2]);
1205 if (supportsAlpha) {
1206 rgb |= (components[offset+3]<<24);
1207 }
1208 else {
1209 rgb |= 0xff000000;
1210 }
1211 Object inData = getDataElements(rgb, null);
1212 int pixel;
1213 switch (transferType) {
1214 case DataBuffer.TYPE_BYTE:
1215 byte bdata[] = (byte[])inData;
1216 pixel = bdata[0] & 0xff;
1217 break;
1218 case DataBuffer.TYPE_USHORT:
1219 short sdata[] = (short[])inData;
1220 pixel = sdata[0];
1221 break;
1222 case DataBuffer.TYPE_INT:
1223 int idata[] = (int[])inData;
1224 pixel = idata[0];
1225 break;
1226 default:
1227 throw new UnsupportedOperationException("This method has not been "+
1228 "implemented for transferType " + transferType);
1229 }
1230 return pixel;
1231 }
1232
1233 /**
1234 * Returns a data element array representation of a pixel in this
1235 * <code>ColorModel</code> given an array of unnormalized color/alpha
1236 * components. This array can then be passed to the
1237 * <code>setDataElements</code> method of a <code>WritableRaster</code>
1238 * object. An <code>ArrayIndexOutOfBoundsException</code> is
1239 * thrown if the
1240 * <code>components</code> array is not large enough to hold all of the
1241 * color and alpha components starting at <code>offset</code>.
1242 * If the pixel variable is <code>null</code>, a new array
1243 * is allocated. If <code>pixel</code> is not <code>null</code>,
1244 * it must be a primitive array of type <code>transferType</code>;
1245 * otherwise, a <code>ClassCastException</code> is thrown.
1246 * An <code>ArrayIndexOutOfBoundsException</code> is thrown if pixel
1247 * is not large enough to hold a pixel value for this
1248 * <code>ColorModel</code>.
1249 * <p>
1250 * Since <code>IndexColorModel</code> can be subclassed, subclasses
1251 * inherit the implementation of this method and if they don't
1252 * override it then they throw an exception if they use an
1253 * unsupported <code>transferType</code>
1254 *
1255 * @param components an array of unnormalized color and alpha
1256 * components
1257 * @param offset the index into <code>components</code> at which to
1258 * begin retrieving color and alpha components
1259 * @param pixel the <code>Object</code> representing an array of color
1260 * and alpha components
1261 * @return an <code>Object</code> representing an array of color and
1262 * alpha components.
1263 * @throws ClassCastException if <code>pixel</code>
1264 * is not a primitive array of type <code>transferType</code>
1265 * @throws ArrayIndexOutOfBoundsException if
1266 * <code>pixel</code> is not large enough to hold a pixel value
1267 * for this <code>ColorModel</code> or the <code>components</code>
1268 * array is not large enough to hold all of the color and alpha
1269 * components starting at <code>offset</code>
1270 * @throws UnsupportedOperationException if <code>transferType</code>
1271 * is not one of the supported transer types
1272 * @see WritableRaster#setDataElements
1273 * @see SampleModel#setDataElements
1274 */
1275 public Object getDataElements(int[] components, int offset, Object pixel) {
1276 int rgb = (components[offset+0]<<16) | (components[offset+1]<<8)
1277 | (components[offset+2]);
1278 if (supportsAlpha) {
1279 rgb |= (components[offset+3]<<24);
1280 }
1281 else {
1282 rgb &= 0xff000000;
1283 }
1284 return getDataElements(rgb, pixel);
1285 }
1286
1287 /**
1288 * Creates a <code>WritableRaster</code> with the specified width
1289 * and height that has a data layout (<code>SampleModel</code>)
1290 * compatible with this <code>ColorModel</code>. This method
1291 * only works for color models with 16 or fewer bits per pixel.
1292 * <p>
1293 * Since <code>IndexColorModel</code> can be subclassed, any
1294 * subclass that supports greater than 16 bits per pixel must
1295 * override this method.
1296 *
1297 * @param w the width to apply to the new <code>WritableRaster</code>
1298 * @param h the height to apply to the new <code>WritableRaster</code>
1299 * @return a <code>WritableRaster</code> object with the specified
1300 * width and height.
1301 * @throws UnsupportedOperationException if the number of bits in a
1302 * pixel is greater than 16
1303 * @see WritableRaster
1304 * @see SampleModel
1305 */
1306 public WritableRaster createCompatibleWritableRaster(int w, int h) {
1307 WritableRaster raster;
1308
1309 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
1310 // TYPE_BINARY
1311 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
1312 w, h, 1, pixel_bits, null);
1313 }
1314 else if (pixel_bits <= 8) {
1315 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
1316 w,h,1,null);
1317 }
1318 else if (pixel_bits <= 16) {
1319 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT,
1320 w,h,1,null);
1321 }
1322 else {
1323 throw new
1324 UnsupportedOperationException("This method is not supported "+
1325 " for pixel bits > 16.");
1326 }
1327 return raster;
1328 }
1329
1330 /**
1331 * Returns <code>true</code> if <code>raster</code> is compatible
1332 * with this <code>ColorModel</code> or <code>false</code> if it
1333 * is not compatible with this <code>ColorModel</code>.
1334 * @param raster the {@link Raster} object to test for compatibility
1335 * @return <code>true</code> if <code>raster</code> is compatible
1336 * with this <code>ColorModel</code>; <code>false</code> otherwise.
1337 *
1338 */
1339 public boolean isCompatibleRaster(Raster raster) {
1340
1341 int size = raster.getSampleModel().getSampleSize(0);
1342 return ((raster.getTransferType() == transferType) &&
1343 (raster.getNumBands() == 1) && ((1 << size) >= map_size));
1344 }
1345
1346 /**
1347 * Creates a <code>SampleModel</code> with the specified
1348 * width and height that has a data layout compatible with
1349 * this <code>ColorModel</code>.
1350 * @param w the width to apply to the new <code>SampleModel</code>
1351 * @param h the height to apply to the new <code>SampleModel</code>
1352 * @return a <code>SampleModel</code> object with the specified
1353 * width and height.
1354 * @throws IllegalArgumentException if <code>w</code> or
1355 * <code>h</code> is not greater than 0
1356 * @see SampleModel
1357 */
1358 public SampleModel createCompatibleSampleModel(int w, int h) {
1359 int[] off = new int[1];
1360 off[0] = 0;
1361 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
1362 return new MultiPixelPackedSampleModel(transferType, w, h,
1363 pixel_bits);
1364 }
1365 else {
1366 return new ComponentSampleModel(transferType, w, h, 1, w,
1367 off);
1368 }
1369 }
1370
1371 /**
1372 * Checks if the specified <code>SampleModel</code> is compatible
1373 * with this <code>ColorModel</code>. If <code>sm</code> is
1374 * <code>null</code>, this method returns <code>false</code>.
1375 * @param sm the specified <code>SampleModel</code>,
1376 * or <code>null</code>
1377 * @return <code>true</code> if the specified <code>SampleModel</code>
1378 * is compatible with this <code>ColorModel</code>; <code>false</code>
1379 * otherwise.
1380 * @see SampleModel
1381 */
1382 public boolean isCompatibleSampleModel(SampleModel sm) {
1383 // fix 4238629
1384 if (! (sm instanceof ComponentSampleModel) &&
1385 ! (sm instanceof MultiPixelPackedSampleModel) ) {
1386 return false;
1387 }
1388
1389 // Transfer type must be the same
1390 if (sm.getTransferType() != transferType) {
1391 return false;
1392 }
1393
1394 if (sm.getNumBands() != 1) {
1395 return false;
1396 }
1397
1398 return true;
1399 }
1400
1401 /**
1402 * Returns a new <code>BufferedImage</code> of TYPE_INT_ARGB or
1403 * TYPE_INT_RGB that has a <code>Raster</code> with pixel data
1404 * computed by expanding the indices in the source <code>Raster</code>
1405 * using the color/alpha component arrays of this <code>ColorModel</code>.
1406 * Only the lower <em>n</em> bits of each index value in the source
1407 * <code>Raster</code>, as specified in the
1408 * <a href="#index_values">class description</a> above, are used to
1409 * compute the color/alpha values in the returned image.
1410 * If <code>forceARGB</code> is <code>true</code>, a TYPE_INT_ARGB image is
1411 * returned regardless of whether or not this <code>ColorModel</code>
1412 * has an alpha component array or a transparent pixel.
1413 * @param raster the specified <code>Raster</code>
1414 * @param forceARGB if <code>true</code>, the returned
1415 * <code>BufferedImage</code> is TYPE_INT_ARGB; otherwise it is
1416 * TYPE_INT_RGB
1417 * @return a <code>BufferedImage</code> created with the specified
1418 * <code>Raster</code>
1419 * @throws IllegalArgumentException if the raster argument is not
1420 * compatible with this IndexColorModel
1421 */
1422 public BufferedImage convertToIntDiscrete(Raster raster,
1423 boolean forceARGB) {
1424 ColorModel cm;
1425
1426 if (!isCompatibleRaster(raster)) {
1427 throw new IllegalArgumentException("This raster is not compatible" +
1428 "with this IndexColorModel.");
1429 }
1430 if (forceARGB || transparency == TRANSLUCENT) {
1431 cm = ColorModel.getRGBdefault();
1432 }
1433 else if (transparency == BITMASK) {
1434 cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff,
1435 0x1000000);
1436 }
1437 else {
1438 cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff);
1439 }
1440
1441 int w = raster.getWidth();
1442 int h = raster.getHeight();
1443 WritableRaster discreteRaster =
1444 cm.createCompatibleWritableRaster(w, h);
1445 Object obj = null;
1446 int[] data = null;
1447
1448 int rX = raster.getMinX();
1449 int rY = raster.getMinY();
1450
1451 for (int y=0; y < h; y++, rY++) {
1452 obj = raster.getDataElements(rX, rY, w, 1, obj);
1453 if (obj instanceof int[]) {
1454 data = (int[])obj;
1455 } else {
1456 data = DataBuffer.toIntArray(obj);
1457 }
1458 for (int x=0; x < w; x++) {
1459 data[x] = rgb[data[x] & pixel_mask];
1460 }
1461 discreteRaster.setDataElements(0, y, w, 1, data);
1462 }
1463
1464 return new BufferedImage(cm, discreteRaster, false, null);
1465 }
1466
1467 /**
1468 * Returns whether or not the pixel is valid.
1469 * @param pixel the specified pixel value
1470 * @return <code>true</code> if <code>pixel</code>
1471 * is valid; <code>false</code> otherwise.
1472 * @since 1.3
1473 */
1474 public boolean isValid(int pixel) {
1475 return ((pixel >= 0 && pixel < map_size) &&
1476 (validBits == null || validBits.testBit(pixel)));
1477 }
1478
1479 /**
1480 * Returns whether or not all of the pixels are valid.
1481 * @return <code>true</code> if all pixels are valid;
1482 * <code>false</code> otherwise.
1483 * @since 1.3
1484 */
1485 public boolean isValid() {
1486 return (validBits == null);
1487 }
1488
1489 /**
1490 * Returns a <code>BigInteger</code> that indicates the valid/invalid
1491 * pixels in the colormap. A bit is valid if the
1492 * <code>BigInteger</code> value at that index is set, and is invalid
1493 * if the <code>BigInteger</code> value at that index is not set.
1494 * The only valid ranges to query in the <code>BigInteger</code> are
1495 * between 0 and the map size.
1496 * @return a <code>BigInteger</code> indicating the valid/invalid pixels.
1497 * @since 1.3
1498 */
1499 public BigInteger getValidPixels() {
1500 if (validBits == null) {
1501 return getAllValid();
1502 }
1503 else {
1504 return validBits;
1505 }
1506 }
1507
1508 /**
1509 * Disposes of system resources associated with this
1510 * <code>ColorModel</code> once this <code>ColorModel</code> is no
1511 * longer referenced.
1512 */
1513 public void finalize() {
1514 sun.awt.image.BufImgSurfaceData.freeNativeICMData(this);
1515 }
1516
1517 /**
1518 * Returns the <code>String</code> representation of the contents of
1519 * this <code>ColorModel</code>object.
1520 * @return a <code>String</code> representing the contents of this
1521 * <code>ColorModel</code> object.
1522 */
1523 public String toString() {
1524 return new String("IndexColorModel: #pixelBits = "+pixel_bits
1525 + " numComponents = "+numComponents
1526 + " color space = "+colorSpace
1527 + " transparency = "+transparency
1528 + " transIndex = "+transparent_index
1529 + " has alpha = "+supportsAlpha
1530 + " isAlphaPre = "+isAlphaPremultiplied
1531 );
1532 }
1533 }