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