001: /*
002: * @(#)IndexColorModel.java 1.30 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt.image;
029:
030: import java.awt.Transparency;
031: import java.awt.color.ColorSpace;
032: import java.math.BigInteger;
033:
034: /**
035: * The <code>IndexColorModel</code> class is a <code>ColorModel</code>
036: * class that works with pixel values consisting of a
037: * single sample that is an index into a fixed colormap in the default
038: * sRGB color space. The colormap specifies red, green, blue, and
039: * optional alpha components corresponding to each index. All components
040: * are represented in the colormap as 8-bit unsigned integral values.
041: * Some constructors allow the caller to specify "holes" in the colormap
042: * by indicating which colormap entries are valid and which represent
043: * unusable colors via the bits set in a <code>BigInteger</code> object.
044: * This color model is similar to an X11 PseudoColor visual.
045: * <p>
046: * Some constructors provide a means to specify an alpha component
047: * for each pixel in the colormap, while others either provide no
048: * such means or, in some cases, a flag to indicate whether the
049: * colormap data contains alpha values. If no alpha is supplied to
050: * the constructor, an opaque alpha component (alpha = 1.0) is
051: * assumed for each entry.
052: * An optional transparent pixel value can be supplied that indicates a
053: * completely transparent pixel, regardless of any alpha component
054: * supplied or assumed for that pixel value.
055: * Note that the color components in the colormap of an
056: * <code>IndexColorModel</code> objects are never pre-multiplied with
057: * the alpha components.
058: * <p>
059: * <a name="transparency">
060: * The transparency of an <code>IndexColorModel</code> object is
061: * determined by examining the alpha components of the colors in the
062: * colormap and choosing the most specific value after considering
063: * the optional alpha values and any transparent index specified.
064: * The transparency value is <code>Transparency.OPAQUE</code>
065: * only if all valid colors in
066: * the colormap are opaque and there is no valid transparent pixel.
067: * If all valid colors
068: * in the colormap are either completely opaque (alpha = 1.0) or
069: * completely transparent (alpha = 0.0), which typically occurs when
070: * a valid transparent pixel is specified,
071: * the value is <code>Transparency.BITMASK</code>.
072: * Otherwise, the value is <code>Transparency.TRANSLUCENT</code>, indicating
073: * that some valid color has an alpha component that is
074: * neither completely transparent nor completely opaque (0.0 < alpha < 1.0).
075: * </a>
076: * <p>
077: * The index represented by a pixel value is stored in the least
078: * significant <em>n</em> bits of the pixel representations passed to the
079: * methods of this class, where <em>n</em> is the pixel size specified to the
080: * constructor for a particular <code>IndexColorModel</code> object;
081: * <em>n</em> must be between 1 and 16, inclusive.
082: * Higher order bits in pixel representations are assumed to be zero.
083: * For those methods that use a primitive array pixel representation of
084: * type <code>transferType</code>, the array length is always one.
085: * The transfer types supported are <code>DataBuffer.TYPE_BYTE</code> and
086: * <code>DataBuffer.TYPE_USHORT</code>. A single int pixel
087: * representation is valid for all objects of this class, since it is
088: * always possible to represent pixel values used with this class in a
089: * single int. Therefore, methods that use this representation do
090: * not throw an <code>IllegalArgumentException</code> due to an invalid
091: * pixel value.
092: * <p>
093: * Many of the methods in this class are final. The reason for
094: * this is that the underlying native graphics code makes assumptions
095: * about the layout and operation of this class and those assumptions
096: * are reflected in the implementations of the methods here that are
097: * marked final. You can subclass this class for other reaons, but
098: * you cannot override or modify the behaviour of those methods.
099: *
100: * @see ColorModel
101: * @see ColorSpace
102: * @see DataBuffer
103: *
104: * @version 10 Feb 1997
105: */
106: public class IndexColorModel extends ColorModel {
107: private int rgb[];
108: private int map_size;
109: private int transparent_index = -1;
110: private boolean allgrayopaque;
111: private BigInteger validBits;
112:
113: private static int[] opaqueBits = { 8, 8, 8 };
114: private static int[] alphaBits = { 8, 8, 8, 8 };
115:
116: /**
117: * Constructs an <code>IndexColorModel</code> from the specified
118: * arrays of red, green, and blue components. Pixels described
119: * by this color model all have alpha components of 255
120: * unnormalized (1.0 normalized), which means they
121: * are fully opaque. All of the arrays specifying the color
122: * components must have at least the specified number of entries.
123: * The <code>ColorSpace</code> is the default sRGB space.
124: * Since there is no alpha information in any of the arguments
125: * to this constructor, the transparency value is always
126: * <code>Transparency.OPAQUE</code>.
127: * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
128: * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
129: * @param bits the number of bits each pixel occupies
130: * @param size the size of the color component arrays
131: * @param r the array of red color components
132: * @param g the array of green color components
133: * @param b the array of blue color components
134: * @throws IllegalArgumentException if <code>bits</code> is less
135: * than 1 or greater than 16
136: * @throws IllegalArgumentException if <code>size</code> is less
137: * than 1
138: */
139: public IndexColorModel(int bits, int size, byte r[], byte g[],
140: byte b[]) {
141: super (bits, opaqueBits, ColorSpace
142: .getInstance(ColorSpace.CS_sRGB), false, false, OPAQUE,
143: ColorModel.getDefaultTransferType(bits));
144: if (bits < 1 || bits > 16) {
145: throw new IllegalArgumentException(
146: "Number of bits must be between" + " 1 and 16.");
147: }
148: setRGBs(size, r, g, b, null);
149: }
150:
151: /**
152: * Constructs an <code>IndexColorModel</code> from the given arrays
153: * of red, green, and blue components. Pixels described by this color
154: * model all have alpha components of 255 unnormalized
155: * (1.0 normalized), which means they are fully opaque, except
156: * for the indicated transparent pixel. All of the arrays
157: * specifying the color components must have at least the specified
158: * number of entries.
159: * The <code>ColorSpace</code> is the default sRGB space.
160: * The transparency value may be <code>Transparency.OPAQUE</code> or
161: * <code>Transparency.BITMASK</code> depending on the arguments, as
162: * specified in the <a href="#transparency">class description</a> above.
163: * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
164: * or <code>DataBuffer.TYPE_USHORT</code> that can hold a
165: * single pixel.
166: * @param bits the number of bits each pixel occupies
167: * @param size the size of the color component arrays
168: * @param r the array of red color components
169: * @param g the array of green color components
170: * @param b the array of blue color components
171: * @param trans the index of the transparent pixel
172: * @throws IllegalArgumentException if <code>bits</code> is less than
173: * 1 or greater than 16
174: * @throws IllegalArgumentException if <code>size</code> is less than
175: * 1
176: */
177: public IndexColorModel(int bits, int size, byte r[], byte g[],
178: byte b[], int trans) {
179: super (bits, opaqueBits, ColorSpace
180: .getInstance(ColorSpace.CS_sRGB), false, false, OPAQUE,
181: ColorModel.getDefaultTransferType(bits));
182: if (bits < 1 || bits > 16) {
183: throw new IllegalArgumentException(
184: "Number of bits must be between" + " 1 and 16.");
185: }
186: setRGBs(size, r, g, b, null);
187: setTransparentPixel(trans);
188: }
189:
190: /**
191: * Constructs an <code>IndexColorModel</code> from the given
192: * arrays of red, green, blue and alpha components. All of the
193: * arrays specifying the components must have at least the specified
194: * number of entries.
195: * The <code>ColorSpace</code> is the default sRGB space.
196: * The transparency value may be any of <code>Transparency.OPAQUE</code>,
197: * <code>Transparency.BITMASK</code>,
198: * or <code>Transparency.TRANSLUCENT</code>
199: * depending on the arguments, as specified
200: * in the <a href="#transparency">class description</a> above.
201: * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
202: * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
203: * @param bits the number of bits each pixel occupies
204: * @param size the size of the color component arrays
205: * @param r the array of red color components
206: * @param g the array of green color components
207: * @param b the array of blue color components
208: * @param a the array of alpha value components
209: * @throws IllegalArgumentException if <code>bits</code> is less
210: * than 1 or greater than 16
211: * @throws IllegalArgumentException if <code>size</code> is less
212: * than 1
213: */
214: public IndexColorModel(int bits, int size, byte r[], byte g[],
215: byte b[], byte a[]) {
216: super (bits, alphaBits, ColorSpace
217: .getInstance(ColorSpace.CS_sRGB), true, false,
218: TRANSLUCENT, ColorModel.getDefaultTransferType(bits));
219: if (bits < 1 || bits > 16) {
220: throw new IllegalArgumentException(
221: "Number of bits must be between" + " 1 and 16.");
222: }
223: setRGBs(size, r, g, b, a);
224: }
225:
226: /**
227: * Constructs an <code>IndexColorModel</code> from a single
228: * array of interleaved red, green, blue and optional alpha
229: * components. The array must have enough values in it to
230: * fill all of the needed component arrays of the specified
231: * size. The <code>ColorSpace</code> is the default sRGB space.
232: * The transparency value may be any of <code>Transparency.OPAQUE</code>,
233: * <code>Transparency.BITMASK</code>,
234: * or <code>Transparency.TRANSLUCENT</code>
235: * depending on the arguments, as specified
236: * in the <a href="#transparency">class description</a> above.
237: * The transfer type is the smallest of
238: * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
239: * that can hold a single pixel.
240: *
241: * @param bits the number of bits each pixel occupies
242: * @param size the size of the color component arrays
243: * @param cmap the array of color components
244: * @param start the starting offset of the first color component
245: * @param hasalpha indicates whether alpha values are contained in
246: * the <code>cmap</code> array
247: * @throws IllegalArgumentException if <code>bits</code> is less
248: * than 1 or greater than 16
249: * @throws IllegalArgumentException if <code>size</code> is less
250: * than 1
251: */
252: public IndexColorModel(int bits, int size, byte cmap[], int start,
253: boolean hasalpha) {
254: this (bits, size, cmap, start, hasalpha, -1);
255: if (bits < 1 || bits > 16) {
256: throw new IllegalArgumentException(
257: "Number of bits must be between" + " 1 and 16.");
258: }
259: }
260:
261: /**
262: * Constructs an <code>IndexColorModel</code> from a single array of
263: * interleaved red, green, blue and optional alpha components. The
264: * specified transparent index represents a pixel that is considered
265: * entirely transparent regardless of any alpha value specified
266: * for it. The array must have enough values in it to fill all
267: * of the needed component arrays of the specified size.
268: * The <code>ColorSpace</code> is the default sRGB space.
269: * The transparency value may be any of <code>Transparency.OPAQUE</code>,
270: * <code>Transparency.BITMASK</code>,
271: * or <code>Transparency.TRANSLUCENT</code>
272: * depending on the arguments, as specified
273: * in the <a href="#transparency">class description</a> above.
274: * The transfer type is the smallest of
275: * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
276: * that can hold a single pixel.
277: * @param bits the number of bits each pixel occupies
278: * @param size the size of the color component arrays
279: * @param cmap the array of color components
280: * @param start the starting offset of the first color component
281: * @param hasalpha indicates whether alpha values are contained in
282: * the <code>cmap</code> array
283: * @param trans the index of the fully transparent pixel
284: * @throws IllegalArgumentException if <code>bits</code> is less than
285: * 1 or greater than 16
286: * @throws IllegalArgumentException if <code>size</code> is less than
287: * 1
288: */
289: public IndexColorModel(int bits, int size, byte cmap[], int start,
290: boolean hasalpha, int trans) {
291: // NOTE: This assumes the ordering: RGB[A]
292: super (bits, opaqueBits, ColorSpace
293: .getInstance(ColorSpace.CS_sRGB), false, false, OPAQUE,
294: ColorModel.getDefaultTransferType(bits));
295:
296: if (bits < 1 || bits > 16) {
297: throw new IllegalArgumentException(
298: "Number of bits must be between" + " 1 and 16.");
299: }
300: if (size < 1) {
301: throw new IllegalArgumentException("Map size (" + size
302: + ") must be >= 1");
303: }
304: map_size = size;
305: rgb = new int[calcRealMapSize(bits, size)];
306: int j = start;
307: int alpha = 0xff;
308: boolean allgray = true;
309: int transparency = OPAQUE;
310: for (int i = 0; i < size; i++) {
311: int r = cmap[j++] & 0xff;
312: int g = cmap[j++] & 0xff;
313: int b = cmap[j++] & 0xff;
314: allgray = allgray && (r == g) && (g == b);
315: if (hasalpha) {
316: alpha = cmap[j++] & 0xff;
317: if (alpha != 0xff) {
318: if (alpha == 0x00) {
319: if (transparency == OPAQUE) {
320: transparency = BITMASK;
321: }
322: if (transparent_index < 0) {
323: transparent_index = i;
324: }
325: } else {
326: transparency = TRANSLUCENT;
327: }
328: allgray = false;
329: }
330: }
331: rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b;
332: }
333: this .allgrayopaque = allgray;
334: setTransparency(transparency);
335: setTransparentPixel(trans);
336: }
337:
338: private void setRGBs(int size, byte r[], byte g[], byte b[],
339: byte a[]) {
340: if (size < 1) {
341: throw new IllegalArgumentException("Map size (" + size
342: + ") must be >= 1");
343: }
344: map_size = size;
345: rgb = new int[calcRealMapSize(pixel_bits, size)];
346: int alpha = 0xff;
347: int transparency = OPAQUE;
348: boolean allgray = true;
349: for (int i = 0; i < size; i++) {
350: int rc = r[i] & 0xff;
351: int gc = g[i] & 0xff;
352: int bc = b[i] & 0xff;
353: allgray = allgray && (rc == gc) && (gc == bc);
354: if (a != null) {
355: alpha = a[i] & 0xff;
356: if (alpha != 0xff) {
357: if (alpha == 0x00) {
358: if (transparency == OPAQUE) {
359: transparency = BITMASK;
360: }
361: if (transparent_index < 0) {
362: transparent_index = i;
363: }
364: } else {
365: transparency = TRANSLUCENT;
366: }
367: allgray = false;
368: }
369: }
370: rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc;
371: }
372: this .allgrayopaque = allgray;
373: setTransparency(transparency);
374: }
375:
376: private void setRGBs(int size, int cmap[], int start,
377: boolean hasalpha) {
378: map_size = size;
379: rgb = new int[calcRealMapSize(pixel_bits, size)];
380: int j = start;
381: int transparency = OPAQUE;
382: boolean allgray = true;
383: BigInteger validBits = this .validBits;
384: for (int i = 0; i < size; i++, j++) {
385: if (validBits != null && !validBits.testBit(i)) {
386: continue;
387: }
388: int cmaprgb = cmap[j];
389: int r = (cmaprgb >> 16) & 0xff;
390: int g = (cmaprgb >> 8) & 0xff;
391: int b = (cmaprgb) & 0xff;
392: allgray = allgray && (r == g) && (g == b);
393: if (hasalpha) {
394: int alpha = cmaprgb >>> 24;
395: if (alpha != 0xff) {
396: if (alpha == 0x00) {
397: if (transparency == OPAQUE) {
398: transparency = BITMASK;
399: }
400: if (transparent_index < 0) {
401: transparent_index = i;
402: }
403: } else {
404: transparency = TRANSLUCENT;
405: }
406: allgray = false;
407: }
408: } else {
409: cmaprgb |= 0xff000000;
410: }
411: rgb[i] = cmaprgb;
412: }
413: this .allgrayopaque = allgray;
414: setTransparency(transparency);
415: }
416:
417: private int calcRealMapSize(int bits, int size) {
418: int newSize = Math.max(1 << bits, size);
419: return Math.max(newSize, 256);
420: }
421:
422: /**
423: * Returns the size of the color/alpha component arrays in this
424: * <code>IndexColorModel</code>.
425: * @return the size of the color and alpha component arrays.
426: */
427: final public int getMapSize() {
428: return map_size;
429: }
430:
431: /**
432: * Returns the index of the transparent pixel in this
433: * <code>IndexColorModel</code> or -1 if there is no transparent pixel.
434: * @return the index of this <code>IndexColorModel</code> object's
435: * transparent pixel, or -1 if there is no such pixel.
436: */
437: final public int getTransparentPixel() {
438: return transparent_index;
439: }
440:
441: /**
442: * Copies the array of red color components into the specified array.
443: * Only the initial entries of the array as specified by
444: * {@link #getMapSize() getMapSize} are written.
445: * @param r the specified array into which the elements of the
446: * array of red color components are copied
447: */
448: final public void getReds(byte r[]) {
449: for (int i = 0; i < map_size; i++) {
450: r[i] = (byte) (rgb[i] >> 16);
451: }
452: }
453:
454: /**
455: * Copies the array of green color components into the specified array.
456: * Only the initial entries of the array as specified by
457: * <code>getMapSize</code> are written.
458: * @param g the specified array into which the elements of the
459: * array of green color components are copied
460: */
461: final public void getGreens(byte g[]) {
462: for (int i = 0; i < map_size; i++) {
463: g[i] = (byte) (rgb[i] >> 8);
464: }
465: }
466:
467: /**
468: * Copies the array of blue color components into the specified array.
469: * Only the initial entries of the array as specified by
470: * <code>getMapSize</code> are written.
471: * @param b the specified array into which the elements of the
472: * array of blue color components are copied
473: */
474: final public void getBlues(byte b[]) {
475: for (int i = 0; i < map_size; i++) {
476: b[i] = (byte) rgb[i];
477: }
478: }
479:
480: /**
481: * Copies the array of alpha transparency components into the
482: * specified array. Only the initial entries of the array as specified
483: * by <code>getMapSize</code> are written.
484: * @param a the specified array into which the elements of the
485: * array of alpha components are copied
486: */
487: final public void getAlphas(byte a[]) {
488: for (int i = 0; i < map_size; i++) {
489: a[i] = (byte) (rgb[i] >> 24);
490: }
491: }
492:
493: /**
494: * Disposes of system resources associated with this
495: * <code>ColorModel</code> once this <code>ColorModel</code> is no
496: * longer referenced.
497: */
498: public void finalize() {
499: }
500:
501: private void setTransparentPixel(int trans) {
502: if (trans >= 0 && trans < map_size) {
503: rgb[trans] &= 0x00ffffff;
504: transparent_index = trans;
505: allgrayopaque = false;
506: if (this .transparency == OPAQUE) {
507: setTransparency(BITMASK);
508: }
509: }
510: }
511:
512: private void setTransparency(int transparency) {
513: if (this .transparency != transparency) {
514: this .transparency = transparency;
515: if (transparency == OPAQUE) {
516: supportsAlpha = false;
517: numComponents = 3;
518: nBits = opaqueBits;
519: } else {
520: supportsAlpha = true;
521: numComponents = 4;
522: nBits = alphaBits;
523: }
524: }
525: }
526:
527: /**
528: * Returns the red color component for the specified pixel, scaled
529: * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
530: * is specified as an int. The returned value is a
531: * non pre-multiplied value.
532: * @param pixel the specified pixel
533: * @return the value of the red color component for the specified pixel
534: */
535: final public int getRed(int pixel) {
536: return (rgb[pixel] >> 16) & 0xff;
537: }
538:
539: /**
540: * Returns the green color component for the specified pixel, scaled
541: * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
542: * is specified as an int. The returned value is a
543: * non pre-multiplied value.
544: * @param pixel the specified pixel
545: * @return the value of the green color component for the specified pixel
546: */
547: final public int getGreen(int pixel) {
548: return (rgb[pixel] >> 8) & 0xff;
549: }
550:
551: /**
552: * Returns the blue color component for the specified pixel, scaled
553: * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
554: * is specified as an int. The returned value is a
555: * non pre-multiplied value.
556: * @param pixel the specified pixel
557: * @return the value of the blue color component for the specified pixel
558: */
559: final public int getBlue(int pixel) {
560: return rgb[pixel] & 0xff;
561: }
562:
563: /**
564: * Returns the alpha component for the specified pixel, scaled
565: * from 0 to 255. The pixel value is specified as an int.
566: * @param pixel the specified pixel
567: * @return the value of the alpha component for the specified pixel
568: */
569: final public int getAlpha(int pixel) {
570: return (rgb[pixel] >> 24) & 0xff;
571: }
572:
573: /**
574: * Returns the color/alpha components of the pixel in the default
575: * RGB color model format. The pixel value is specified as an int.
576: * The returned value is in a non pre-multiplied format.
577: * @param pixel the specified pixel
578: * @return the color and alpha components of the specified pixel
579: * @see ColorModel#getRGBdefault
580: */
581: final public int getRGB(int pixel) {
582: return rgb[pixel];
583: }
584:
585: /**
586: * Returns the <code>String</code> representation of the contents of
587: * this <code>ColorModel</code>object.
588: * @return a <code>String</code> representing the contents of this
589: * <code>ColorModel</code> object.
590: */
591: public String toString() {
592: return new String("IndexColorModel: #pixelBits = " + pixel_bits
593: + " numComponents = " + numComponents
594: + " color space = " + colorSpace + " transparency = "
595: + transparency + " transIndex = " + transparent_index
596: + " has alpha = " + supportsAlpha + " isAlphaPre = "
597: + isAlphaPremultiplied);
598: }
599: }
|