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 &lt; alpha &lt; 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&nbsp;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               falsefalse, 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&nbsp;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               falsefalse, 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                truefalse, 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               falsefalse, 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               falsefalse, 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                truefalse, 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(intint, 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 trueif {@code raster} is compatible
1337       * with this {@code ColorModel} or {@code falseif it
1338       * is not compatible with this {@code ColorModel}.
1339       * @param raster the {@link Raster} object to test for compatibility
1340       * @return {@code trueif {@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 trueif 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, falsenull);
1470     }
1471
1472     /**
1473      * Returns whether or not the pixel is valid.
1474      * @param pixel the specified pixel value
1475      * @return {@code trueif {@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 trueif 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 trueif 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