--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/awt/image/IndexColorModel.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1533 @@
+/*
+ * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.math.BigInteger;
+
+/**
+ * The <code>IndexColorModel</code> class is a <code>ColorModel</code>
+ * class that works with pixel values consisting of a
+ * single sample that is an index into a fixed colormap in the default
+ * sRGB color space. The colormap specifies red, green, blue, and
+ * optional alpha components corresponding to each index. All components
+ * are represented in the colormap as 8-bit unsigned integral values.
+ * Some constructors allow the caller to specify "holes" in the colormap
+ * by indicating which colormap entries are valid and which represent
+ * unusable colors via the bits set in a <code>BigInteger</code> object.
+ * This color model is similar to an X11 PseudoColor visual.
+ * <p>
+ * Some constructors provide a means to specify an alpha component
+ * for each pixel in the colormap, while others either provide no
+ * such means or, in some cases, a flag to indicate whether the
+ * colormap data contains alpha values. If no alpha is supplied to
+ * the constructor, an opaque alpha component (alpha = 1.0) is
+ * assumed for each entry.
+ * An optional transparent pixel value can be supplied that indicates a
+ * pixel to be made completely transparent, regardless of any alpha
+ * component supplied or assumed for that pixel value.
+ * Note that the color components in the colormap of an
+ * <code>IndexColorModel</code> objects are never pre-multiplied with
+ * the alpha components.
+ * <p>
+ * <a name="transparency">
+ * The transparency of an <code>IndexColorModel</code> object is
+ * determined by examining the alpha components of the colors in the
+ * colormap and choosing the most specific value after considering
+ * the optional alpha values and any transparent index specified.
+ * The transparency value is <code>Transparency.OPAQUE</code>
+ * only if all valid colors in
+ * the colormap are opaque and there is no valid transparent pixel.
+ * If all valid colors
+ * in the colormap are either completely opaque (alpha = 1.0) or
+ * completely transparent (alpha = 0.0), which typically occurs when
+ * a valid transparent pixel is specified,
+ * the value is <code>Transparency.BITMASK</code>.
+ * Otherwise, the value is <code>Transparency.TRANSLUCENT</code>, indicating
+ * that some valid color has an alpha component that is
+ * neither completely transparent nor completely opaque
+ * (0.0 < alpha < 1.0).
+ * </a>
+ *
+ * <p>
+ * If an <code>IndexColorModel</code> object has
+ * a transparency value of <code>Transparency.OPAQUE</code>,
+ * then the <code>hasAlpha</code>
+ * and <code>getNumComponents</code> methods
+ * (both inherited from <code>ColorModel</code>)
+ * return false and 3, respectively.
+ * For any other transparency value,
+ * <code>hasAlpha</code> returns true
+ * and <code>getNumComponents</code> returns 4.
+ *
+ * <p>
+ * <a name="index_values">
+ * The values used to index into the colormap are taken from the least
+ * significant <em>n</em> bits of pixel representations where
+ * <em>n</em> is based on the pixel size specified in the constructor.
+ * For pixel sizes smaller than 8 bits, <em>n</em> is rounded up to a
+ * power of two (3 becomes 4 and 5,6,7 become 8).
+ * For pixel sizes between 8 and 16 bits, <em>n</em> is equal to the
+ * pixel size.
+ * Pixel sizes larger than 16 bits are not supported by this class.
+ * Higher order bits beyond <em>n</em> are ignored in pixel representations.
+ * Index values greater than or equal to the map size, but less than
+ * 2<sup><em>n</em></sup>, are undefined and return 0 for all color and
+ * alpha components.
+ * <p>
+ * For those methods that use a primitive array pixel representation of
+ * type <code>transferType</code>, the array length is always one.
+ * The transfer types supported are <code>DataBuffer.TYPE_BYTE</code> and
+ * <code>DataBuffer.TYPE_USHORT</code>. A single int pixel
+ * representation is valid for all objects of this class, since it is
+ * always possible to represent pixel values used with this class in a
+ * single int. Therefore, methods that use this representation do
+ * not throw an <code>IllegalArgumentException</code> due to an invalid
+ * pixel value.
+ * <p>
+ * Many of the methods in this class are final. The reason for
+ * this is that the underlying native graphics code makes assumptions
+ * about the layout and operation of this class and those assumptions
+ * are reflected in the implementations of the methods here that are
+ * marked final. You can subclass this class for other reasons, but
+ * you cannot override or modify the behaviour of those methods.
+ *
+ * @see ColorModel
+ * @see ColorSpace
+ * @see DataBuffer
+ *
+ */
+public class IndexColorModel extends ColorModel {
+ private int rgb[];
+ private int map_size;
+ private int pixel_mask;
+ private int transparent_index = -1;
+ private boolean allgrayopaque;
+ private BigInteger validBits;
+
+ private static int[] opaqueBits = {8, 8, 8};
+ private static int[] alphaBits = {8, 8, 8, 8};
+
+ static private native void initIDs();
+ static {
+ ColorModel.loadLibraries();
+ initIDs();
+ }
+ /**
+ * Constructs an <code>IndexColorModel</code> from the specified
+ * arrays of red, green, and blue components. Pixels described
+ * by this color model all have alpha components of 255
+ * unnormalized (1.0 normalized), which means they
+ * are fully opaque. All of the arrays specifying the color
+ * components must have at least the specified number of entries.
+ * The <code>ColorSpace</code> is the default sRGB space.
+ * Since there is no alpha information in any of the arguments
+ * to this constructor, the transparency value is always
+ * <code>Transparency.OPAQUE</code>.
+ * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
+ * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component arrays
+ * @param r the array of red color components
+ * @param g the array of green color components
+ * @param b the array of blue color components
+ * @throws IllegalArgumentException if <code>bits</code> is less
+ * than 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less
+ * than 1
+ */
+ public IndexColorModel(int bits, int size,
+ byte r[], byte g[], byte b[]) {
+ super(bits, opaqueBits,
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ false, false, OPAQUE,
+ ColorModel.getDefaultTransferType(bits));
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ setRGBs(size, r, g, b, null);
+ calculatePixelMask();
+ }
+
+ /**
+ * Constructs an <code>IndexColorModel</code> from the given arrays
+ * of red, green, and blue components. Pixels described by this color
+ * model all have alpha components of 255 unnormalized
+ * (1.0 normalized), which means they are fully opaque, except
+ * for the indicated pixel to be made transparent. All of the arrays
+ * specifying the color components must have at least the specified
+ * number of entries.
+ * The <code>ColorSpace</code> is the default sRGB space.
+ * The transparency value may be <code>Transparency.OPAQUE</code> or
+ * <code>Transparency.BITMASK</code> depending on the arguments, as
+ * specified in the <a href="#transparency">class description</a> above.
+ * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
+ * or <code>DataBuffer.TYPE_USHORT</code> that can hold a
+ * single pixel.
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component arrays
+ * @param r the array of red color components
+ * @param g the array of green color components
+ * @param b the array of blue color components
+ * @param trans the index of the transparent pixel
+ * @throws IllegalArgumentException if <code>bits</code> is less than
+ * 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less than
+ * 1
+ */
+ public IndexColorModel(int bits, int size,
+ byte r[], byte g[], byte b[], int trans) {
+ super(bits, opaqueBits,
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ false, false, OPAQUE,
+ ColorModel.getDefaultTransferType(bits));
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ setRGBs(size, r, g, b, null);
+ setTransparentPixel(trans);
+ calculatePixelMask();
+ }
+
+ /**
+ * Constructs an <code>IndexColorModel</code> from the given
+ * arrays of red, green, blue and alpha components. All of the
+ * arrays specifying the components must have at least the specified
+ * number of entries.
+ * The <code>ColorSpace</code> is the default sRGB space.
+ * The transparency value may be any of <code>Transparency.OPAQUE</code>,
+ * <code>Transparency.BITMASK</code>,
+ * or <code>Transparency.TRANSLUCENT</code>
+ * depending on the arguments, as specified
+ * in the <a href="#transparency">class description</a> above.
+ * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
+ * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component arrays
+ * @param r the array of red color components
+ * @param g the array of green color components
+ * @param b the array of blue color components
+ * @param a the array of alpha value components
+ * @throws IllegalArgumentException if <code>bits</code> is less
+ * than 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less
+ * than 1
+ */
+ public IndexColorModel(int bits, int size,
+ byte r[], byte g[], byte b[], byte a[]) {
+ super (bits, alphaBits,
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ true, false, TRANSLUCENT,
+ ColorModel.getDefaultTransferType(bits));
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ setRGBs (size, r, g, b, a);
+ calculatePixelMask();
+ }
+
+ /**
+ * Constructs an <code>IndexColorModel</code> from a single
+ * array of interleaved red, green, blue and optional alpha
+ * components. The array must have enough values in it to
+ * fill all of the needed component arrays of the specified
+ * size. The <code>ColorSpace</code> is the default sRGB space.
+ * The transparency value may be any of <code>Transparency.OPAQUE</code>,
+ * <code>Transparency.BITMASK</code>,
+ * or <code>Transparency.TRANSLUCENT</code>
+ * depending on the arguments, as specified
+ * in the <a href="#transparency">class description</a> above.
+ * The transfer type is the smallest of
+ * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
+ * that can hold a single pixel.
+ *
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component arrays
+ * @param cmap the array of color components
+ * @param start the starting offset of the first color component
+ * @param hasalpha indicates whether alpha values are contained in
+ * the <code>cmap</code> array
+ * @throws IllegalArgumentException if <code>bits</code> is less
+ * than 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less
+ * than 1
+ */
+ public IndexColorModel(int bits, int size, byte cmap[], int start,
+ boolean hasalpha) {
+ this(bits, size, cmap, start, hasalpha, -1);
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ }
+
+ /**
+ * Constructs an <code>IndexColorModel</code> from a single array of
+ * interleaved red, green, blue and optional alpha components. The
+ * specified transparent index represents a pixel that is made
+ * entirely transparent regardless of any alpha value specified
+ * for it. The array must have enough values in it to fill all
+ * of the needed component arrays of the specified size.
+ * The <code>ColorSpace</code> is the default sRGB space.
+ * The transparency value may be any of <code>Transparency.OPAQUE</code>,
+ * <code>Transparency.BITMASK</code>,
+ * or <code>Transparency.TRANSLUCENT</code>
+ * depending on the arguments, as specified
+ * in the <a href="#transparency">class description</a> above.
+ * The transfer type is the smallest of
+ * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
+ * that can hold a single pixel.
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component arrays
+ * @param cmap the array of color components
+ * @param start the starting offset of the first color component
+ * @param hasalpha indicates whether alpha values are contained in
+ * the <code>cmap</code> array
+ * @param trans the index of the fully transparent pixel
+ * @throws IllegalArgumentException if <code>bits</code> is less than
+ * 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less than
+ * 1
+ */
+ public IndexColorModel(int bits, int size, byte cmap[], int start,
+ boolean hasalpha, int trans) {
+ // REMIND: This assumes the ordering: RGB[A]
+ super(bits, opaqueBits,
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ false, false, OPAQUE,
+ ColorModel.getDefaultTransferType(bits));
+
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ if (size < 1) {
+ throw new IllegalArgumentException("Map size ("+size+
+ ") must be >= 1");
+ }
+ map_size = size;
+ rgb = new int[calcRealMapSize(bits, size)];
+ int j = start;
+ int alpha = 0xff;
+ boolean allgray = true;
+ int transparency = OPAQUE;
+ for (int i = 0; i < size; i++) {
+ int r = cmap[j++] & 0xff;
+ int g = cmap[j++] & 0xff;
+ int b = cmap[j++] & 0xff;
+ allgray = allgray && (r == g) && (g == b);
+ if (hasalpha) {
+ alpha = cmap[j++] & 0xff;
+ if (alpha != 0xff) {
+ if (alpha == 0x00) {
+ if (transparency == OPAQUE) {
+ transparency = BITMASK;
+ }
+ if (transparent_index < 0) {
+ transparent_index = i;
+ }
+ } else {
+ transparency = TRANSLUCENT;
+ }
+ allgray = false;
+ }
+ }
+ rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b;
+ }
+ this.allgrayopaque = allgray;
+ setTransparency(transparency);
+ setTransparentPixel(trans);
+ calculatePixelMask();
+ }
+
+ /**
+ * Constructs an <code>IndexColorModel</code> from an array of
+ * ints where each int is comprised of red, green, blue, and
+ * optional alpha components in the default RGB color model format.
+ * The specified transparent index represents a pixel that is made
+ * entirely transparent regardless of any alpha value specified
+ * for it. The array must have enough values in it to fill all
+ * of the needed component arrays of the specified size.
+ * The <code>ColorSpace</code> is the default sRGB space.
+ * The transparency value may be any of <code>Transparency.OPAQUE</code>,
+ * <code>Transparency.BITMASK</code>,
+ * or <code>Transparency.TRANSLUCENT</code>
+ * depending on the arguments, as specified
+ * in the <a href="#transparency">class description</a> above.
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component arrays
+ * @param cmap the array of color components
+ * @param start the starting offset of the first color component
+ * @param hasalpha indicates whether alpha values are contained in
+ * the <code>cmap</code> array
+ * @param trans the index of the fully transparent pixel
+ * @param transferType the data type of the array used to represent
+ * pixel values. The data type must be either
+ * <code>DataBuffer.TYPE_BYTE</code> or
+ * <code>DataBuffer.TYPE_USHORT</code>.
+ * @throws IllegalArgumentException if <code>bits</code> is less
+ * than 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less
+ * than 1
+ * @throws IllegalArgumentException if <code>transferType</code> is not
+ * one of <code>DataBuffer.TYPE_BYTE</code> or
+ * <code>DataBuffer.TYPE_USHORT</code>
+ */
+ public IndexColorModel(int bits, int size,
+ int cmap[], int start,
+ boolean hasalpha, int trans, int transferType) {
+ // REMIND: This assumes the ordering: RGB[A]
+ super(bits, opaqueBits,
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ false, false, OPAQUE,
+ transferType);
+
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ if (size < 1) {
+ throw new IllegalArgumentException("Map size ("+size+
+ ") must be >= 1");
+ }
+ if ((transferType != DataBuffer.TYPE_BYTE) &&
+ (transferType != DataBuffer.TYPE_USHORT)) {
+ throw new IllegalArgumentException("transferType must be either" +
+ "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT");
+ }
+
+ setRGBs(size, cmap, start, hasalpha);
+ setTransparentPixel(trans);
+ calculatePixelMask();
+ }
+
+ /**
+ * Constructs an <code>IndexColorModel</code> from an
+ * <code>int</code> array where each <code>int</code> is
+ * comprised of red, green, blue, and alpha
+ * components in the default RGB color model format.
+ * The array must have enough values in it to fill all
+ * of the needed component arrays of the specified size.
+ * The <code>ColorSpace</code> is the default sRGB space.
+ * The transparency value may be any of <code>Transparency.OPAQUE</code>,
+ * <code>Transparency.BITMASK</code>,
+ * or <code>Transparency.TRANSLUCENT</code>
+ * depending on the arguments, as specified
+ * in the <a href="#transparency">class description</a> above.
+ * The transfer type must be one of <code>DataBuffer.TYPE_BYTE</code>
+ * <code>DataBuffer.TYPE_USHORT</code>.
+ * The <code>BigInteger</code> object specifies the valid/invalid pixels
+ * in the <code>cmap</code> array. A pixel is valid if the
+ * <code>BigInteger</code> value at that index is set, and is invalid
+ * if the <code>BigInteger</code> bit at that index is not set.
+ * @param bits the number of bits each pixel occupies
+ * @param size the size of the color component array
+ * @param cmap the array of color components
+ * @param start the starting offset of the first color component
+ * @param transferType the specified data type
+ * @param validBits a <code>BigInteger</code> object. If a bit is
+ * set in the BigInteger, the pixel at that index is valid.
+ * If a bit is not set, the pixel at that index
+ * is considered invalid. If null, all pixels are valid.
+ * Only bits from 0 to the map size are considered.
+ * @throws IllegalArgumentException if <code>bits</code> is less
+ * than 1 or greater than 16
+ * @throws IllegalArgumentException if <code>size</code> is less
+ * than 1
+ * @throws IllegalArgumentException if <code>transferType</code> is not
+ * one of <code>DataBuffer.TYPE_BYTE</code> or
+ * <code>DataBuffer.TYPE_USHORT</code>
+ *
+ * @since 1.3
+ */
+ public IndexColorModel(int bits, int size, int cmap[], int start,
+ int transferType, BigInteger validBits) {
+ super (bits, alphaBits,
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ true, false, TRANSLUCENT,
+ transferType);
+
+ if (bits < 1 || bits > 16) {
+ throw new IllegalArgumentException("Number of bits must be between"
+ +" 1 and 16.");
+ }
+ if (size < 1) {
+ throw new IllegalArgumentException("Map size ("+size+
+ ") must be >= 1");
+ }
+ if ((transferType != DataBuffer.TYPE_BYTE) &&
+ (transferType != DataBuffer.TYPE_USHORT)) {
+ throw new IllegalArgumentException("transferType must be either" +
+ "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT");
+ }
+
+ if (validBits != null) {
+ // Check to see if it is all valid
+ for (int i=0; i < size; i++) {
+ if (!validBits.testBit(i)) {
+ this.validBits = validBits;
+ break;
+ }
+ }
+ }
+
+ setRGBs(size, cmap, start, true);
+ calculatePixelMask();
+ }
+
+ private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) {
+ if (size < 1) {
+ throw new IllegalArgumentException("Map size ("+size+
+ ") must be >= 1");
+ }
+ map_size = size;
+ rgb = new int[calcRealMapSize(pixel_bits, size)];
+ int alpha = 0xff;
+ int transparency = OPAQUE;
+ boolean allgray = true;
+ for (int i = 0; i < size; i++) {
+ int rc = r[i] & 0xff;
+ int gc = g[i] & 0xff;
+ int bc = b[i] & 0xff;
+ allgray = allgray && (rc == gc) && (gc == bc);
+ if (a != null) {
+ alpha = a[i] & 0xff;
+ if (alpha != 0xff) {
+ if (alpha == 0x00) {
+ if (transparency == OPAQUE) {
+ transparency = BITMASK;
+ }
+ if (transparent_index < 0) {
+ transparent_index = i;
+ }
+ } else {
+ transparency = TRANSLUCENT;
+ }
+ allgray = false;
+ }
+ }
+ rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc;
+ }
+ this.allgrayopaque = allgray;
+ setTransparency(transparency);
+ }
+
+ private void setRGBs(int size, int cmap[], int start, boolean hasalpha) {
+ map_size = size;
+ rgb = new int[calcRealMapSize(pixel_bits, size)];
+ int j = start;
+ int transparency = OPAQUE;
+ boolean allgray = true;
+ BigInteger validBits = this.validBits;
+ for (int i = 0; i < size; i++, j++) {
+ if (validBits != null && !validBits.testBit(i)) {
+ continue;
+ }
+ int cmaprgb = cmap[j];
+ int r = (cmaprgb >> 16) & 0xff;
+ int g = (cmaprgb >> 8) & 0xff;
+ int b = (cmaprgb ) & 0xff;
+ allgray = allgray && (r == g) && (g == b);
+ if (hasalpha) {
+ int alpha = cmaprgb >>> 24;
+ if (alpha != 0xff) {
+ if (alpha == 0x00) {
+ if (transparency == OPAQUE) {
+ transparency = BITMASK;
+ }
+ if (transparent_index < 0) {
+ transparent_index = i;
+ }
+ } else {
+ transparency = TRANSLUCENT;
+ }
+ allgray = false;
+ }
+ } else {
+ cmaprgb |= 0xff000000;
+ }
+ rgb[i] = cmaprgb;
+ }
+ this.allgrayopaque = allgray;
+ setTransparency(transparency);
+ }
+
+ private int calcRealMapSize(int bits, int size) {
+ int newSize = Math.max(1 << bits, size);
+ return Math.max(newSize, 256);
+ }
+
+ private BigInteger getAllValid() {
+ int numbytes = (map_size+7)/8;
+ byte[] valid = new byte[numbytes];
+ java.util.Arrays.fill(valid, (byte)0xff);
+ valid[0] = (byte)(0xff >>> (numbytes*8 - map_size));
+
+ return new BigInteger(1, valid);
+ }
+
+ /**
+ * Returns the transparency. Returns either OPAQUE, BITMASK,
+ * or TRANSLUCENT
+ * @return the transparency of this <code>IndexColorModel</code>
+ * @see Transparency#OPAQUE
+ * @see Transparency#BITMASK
+ * @see Transparency#TRANSLUCENT
+ */
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Returns an array of the number of bits for each color/alpha component.
+ * The array contains the color components in the order red, green,
+ * blue, followed by the alpha component, if present.
+ * @return an array containing the number of bits of each color
+ * and alpha component of this <code>IndexColorModel</code>
+ */
+ public int[] getComponentSize() {
+ if (nBits == null) {
+ if (supportsAlpha) {
+ nBits = new int[4];
+ nBits[3] = 8;
+ }
+ else {
+ nBits = new int[3];
+ }
+ nBits[0] = nBits[1] = nBits[2] = 8;
+ }
+ return nBits;
+ }
+
+ /**
+ * Returns the size of the color/alpha component arrays in this
+ * <code>IndexColorModel</code>.
+ * @return the size of the color and alpha component arrays.
+ */
+ final public int getMapSize() {
+ return map_size;
+ }
+
+ /**
+ * Returns the index of a transparent pixel in this
+ * <code>IndexColorModel</code> or -1 if there is no pixel
+ * with an alpha value of 0. If a transparent pixel was
+ * explicitly specified in one of the constructors by its
+ * index, then that index will be preferred, otherwise,
+ * the index of any pixel which happens to be fully transparent
+ * may be returned.
+ * @return the index of a transparent pixel in this
+ * <code>IndexColorModel</code> object, or -1 if there
+ * is no such pixel
+ */
+ final public int getTransparentPixel() {
+ return transparent_index;
+ }
+
+ /**
+ * Copies the array of red color components into the specified array.
+ * Only the initial entries of the array as specified by
+ * {@link #getMapSize() getMapSize} are written.
+ * @param r the specified array into which the elements of the
+ * array of red color components are copied
+ */
+ final public void getReds(byte r[]) {
+ for (int i = 0; i < map_size; i++) {
+ r[i] = (byte) (rgb[i] >> 16);
+ }
+ }
+
+ /**
+ * Copies the array of green color components into the specified array.
+ * Only the initial entries of the array as specified by
+ * <code>getMapSize</code> are written.
+ * @param g the specified array into which the elements of the
+ * array of green color components are copied
+ */
+ final public void getGreens(byte g[]) {
+ for (int i = 0; i < map_size; i++) {
+ g[i] = (byte) (rgb[i] >> 8);
+ }
+ }
+
+ /**
+ * Copies the array of blue color components into the specified array.
+ * Only the initial entries of the array as specified by
+ * <code>getMapSize</code> are written.
+ * @param b the specified array into which the elements of the
+ * array of blue color components are copied
+ */
+ final public void getBlues(byte b[]) {
+ for (int i = 0; i < map_size; i++) {
+ b[i] = (byte) rgb[i];
+ }
+ }
+
+ /**
+ * Copies the array of alpha transparency components into the
+ * specified array. Only the initial entries of the array as specified
+ * by <code>getMapSize</code> are written.
+ * @param a the specified array into which the elements of the
+ * array of alpha components are copied
+ */
+ final public void getAlphas(byte a[]) {
+ for (int i = 0; i < map_size; i++) {
+ a[i] = (byte) (rgb[i] >> 24);
+ }
+ }
+
+ /**
+ * Converts data for each index from the color and alpha component
+ * arrays to an int in the default RGB ColorModel format and copies
+ * the resulting 32-bit ARGB values into the specified array. Only
+ * the initial entries of the array as specified by
+ * <code>getMapSize</code> are
+ * written.
+ * @param rgb the specified array into which the converted ARGB
+ * values from this array of color and alpha components
+ * are copied.
+ */
+ final public void getRGBs(int rgb[]) {
+ System.arraycopy(this.rgb, 0, rgb, 0, map_size);
+ }
+
+ private void setTransparentPixel(int trans) {
+ if (trans >= 0 && trans < map_size) {
+ rgb[trans] &= 0x00ffffff;
+ transparent_index = trans;
+ allgrayopaque = false;
+ if (this.transparency == OPAQUE) {
+ setTransparency(BITMASK);
+ }
+ }
+ }
+
+ private void setTransparency(int transparency) {
+ if (this.transparency != transparency) {
+ this.transparency = transparency;
+ if (transparency == OPAQUE) {
+ supportsAlpha = false;
+ numComponents = 3;
+ nBits = opaqueBits;
+ } else {
+ supportsAlpha = true;
+ numComponents = 4;
+ nBits = alphaBits;
+ }
+ }
+ }
+
+ /**
+ * This method is called from the constructors to set the pixel_mask
+ * value, which is based on the value of pixel_bits. The pixel_mask
+ * value is used to mask off the pixel parameters for methods such
+ * as getRed(), getGreen(), getBlue(), getAlpha(), and getRGB().
+ */
+ private final void calculatePixelMask() {
+ // Note that we adjust the mask so that our masking behavior here
+ // is consistent with that of our native rendering loops.
+ int maskbits = pixel_bits;
+ if (maskbits == 3) {
+ maskbits = 4;
+ } else if (maskbits > 4 && maskbits < 8) {
+ maskbits = 8;
+ }
+ pixel_mask = (1 << maskbits) - 1;
+ }
+
+ /**
+ * Returns the red color component for the specified pixel, scaled
+ * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
+ * is specified as an int.
+ * Only the lower <em>n</em> bits of the pixel value, as specified in the
+ * <a href="#index_values">class description</a> above, are used to
+ * calculate the returned value.
+ * The returned value is a non pre-multiplied value.
+ * @param pixel the specified pixel
+ * @return the value of the red color component for the specified pixel
+ */
+ final public int getRed(int pixel) {
+ return (rgb[pixel & pixel_mask] >> 16) & 0xff;
+ }
+
+ /**
+ * Returns the green color component for the specified pixel, scaled
+ * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
+ * is specified as an int.
+ * Only the lower <em>n</em> bits of the pixel value, as specified in the
+ * <a href="#index_values">class description</a> above, are used to
+ * calculate the returned value.
+ * The returned value is a non pre-multiplied value.
+ * @param pixel the specified pixel
+ * @return the value of the green color component for the specified pixel
+ */
+ final public int getGreen(int pixel) {
+ return (rgb[pixel & pixel_mask] >> 8) & 0xff;
+ }
+
+ /**
+ * Returns the blue color component for the specified pixel, scaled
+ * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
+ * is specified as an int.
+ * Only the lower <em>n</em> bits of the pixel value, as specified in the
+ * <a href="#index_values">class description</a> above, are used to
+ * calculate the returned value.
+ * The returned value is a non pre-multiplied value.
+ * @param pixel the specified pixel
+ * @return the value of the blue color component for the specified pixel
+ */
+ final public int getBlue(int pixel) {
+ return rgb[pixel & pixel_mask] & 0xff;
+ }
+
+ /**
+ * Returns the alpha component for the specified pixel, scaled
+ * from 0 to 255. The pixel value is specified as an int.
+ * Only the lower <em>n</em> bits of the pixel value, as specified in the
+ * <a href="#index_values">class description</a> above, are used to
+ * calculate the returned value.
+ * @param pixel the specified pixel
+ * @return the value of the alpha component for the specified pixel
+ */
+ final public int getAlpha(int pixel) {
+ return (rgb[pixel & pixel_mask] >> 24) & 0xff;
+ }
+
+ /**
+ * Returns the color/alpha components of the pixel in the default
+ * RGB color model format. The pixel value is specified as an int.
+ * Only the lower <em>n</em> bits of the pixel value, as specified in the
+ * <a href="#index_values">class description</a> above, are used to
+ * calculate the returned value.
+ * The returned value is in a non pre-multiplied format.
+ * @param pixel the specified pixel
+ * @return the color and alpha components of the specified pixel
+ * @see ColorModel#getRGBdefault
+ */
+ final public int getRGB(int pixel) {
+ return rgb[pixel & pixel_mask];
+ }
+
+ private static final int CACHESIZE = 40;
+ private int lookupcache[] = new int[CACHESIZE];
+
+ /**
+ * Returns a data element array representation of a pixel in this
+ * ColorModel, given an integer pixel representation in the
+ * default RGB color model. This array can then be passed to the
+ * {@link WritableRaster#setDataElements(int, int, java.lang.Object) setDataElements}
+ * method of a {@link WritableRaster} object. If the pixel variable is
+ * <code>null</code>, a new array is allocated. If <code>pixel</code>
+ * is not <code>null</code>, it must be
+ * a primitive array of type <code>transferType</code>; otherwise, a
+ * <code>ClassCastException</code> is thrown. An
+ * <code>ArrayIndexOutOfBoundsException</code> is
+ * thrown if <code>pixel</code> is not large enough to hold a pixel
+ * value for this <code>ColorModel</code>. The pixel array is returned.
+ * <p>
+ * Since <code>IndexColorModel</code> can be subclassed, subclasses
+ * inherit the implementation of this method and if they don't
+ * override it then they throw an exception if they use an
+ * unsupported <code>transferType</code>.
+ *
+ * @param rgb the integer pixel representation in the default RGB
+ * color model
+ * @param pixel the specified pixel
+ * @return an array representation of the specified pixel in this
+ * <code>IndexColorModel</code>.
+ * @throws ClassCastException if <code>pixel</code>
+ * is not a primitive array of type <code>transferType</code>
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>pixel</code> is not large enough to hold a pixel value
+ * for this <code>ColorModel</code>
+ * @throws UnsupportedOperationException if <code>transferType</code>
+ * is invalid
+ * @see WritableRaster#setDataElements
+ * @see SampleModel#setDataElements
+ */
+ public synchronized Object getDataElements(int rgb, Object pixel) {
+ int red = (rgb>>16) & 0xff;
+ int green = (rgb>>8) & 0xff;
+ int blue = rgb & 0xff;
+ int alpha = (rgb>>>24);
+ int pix = 0;
+
+ // Note that pixels are stored at lookupcache[2*i]
+ // and the rgb that was searched is stored at
+ // lookupcache[2*i+1]. Also, the pixel is first
+ // inverted using the unary complement operator
+ // before storing in the cache so it can never be 0.
+ for (int i = CACHESIZE - 2; i >= 0; i -= 2) {
+ if ((pix = lookupcache[i]) == 0) {
+ break;
+ }
+ if (rgb == lookupcache[i+1]) {
+ return installpixel(pixel, ~pix);
+ }
+ }
+
+ if (allgrayopaque) {
+ // IndexColorModel objects are all tagged as
+ // non-premultiplied so ignore the alpha value
+ // of the incoming color, convert the
+ // non-premultiplied color components to a
+ // grayscale value and search for the closest
+ // gray value in the palette. Since all colors
+ // in the palette are gray, we only need compare
+ // to one of the color components for a match
+ // using a simple linear distance formula.
+
+ int minDist = 256;
+ int d;
+ int gray = (int) (red*77 + green*150 + blue*29 + 128)/256;
+
+ for (int i = 0; i < map_size; i++) {
+ if (this.rgb[i] == 0x0) {
+ // For allgrayopaque colormaps, entries are 0
+ // iff they are an invalid color and should be
+ // ignored during color searches.
+ continue;
+ }
+ d = (this.rgb[i] & 0xff) - gray;
+ if (d < 0) d = -d;
+ if (d < minDist) {
+ pix = i;
+ if (d == 0) {
+ break;
+ }
+ minDist = d;
+ }
+ }
+ } else if (transparency == OPAQUE) {
+ // IndexColorModel objects are all tagged as
+ // non-premultiplied so ignore the alpha value
+ // of the incoming color and search for closest
+ // color match independently using a 3 component
+ // Euclidean distance formula.
+ // For opaque colormaps, palette entries are 0
+ // iff they are an invalid color and should be
+ // ignored during color searches.
+ // As an optimization, exact color searches are
+ // likely to be fairly common in opaque colormaps
+ // so first we will do a quick search for an
+ // exact match.
+
+ int smallestError = Integer.MAX_VALUE;
+ int lut[] = this.rgb;
+ int lutrgb;
+ for (int i=0; i < map_size; i++) {
+ lutrgb = lut[i];
+ if (lutrgb == rgb && lutrgb != 0) {
+ pix = i;
+ smallestError = 0;
+ break;
+ }
+ }
+
+ if (smallestError != 0) {
+ for (int i=0; i < map_size; i++) {
+ lutrgb = lut[i];
+ if (lutrgb == 0) {
+ continue;
+ }
+
+ int tmp = ((lutrgb >> 16) & 0xff) - red;
+ int currentError = tmp*tmp;
+ if (currentError < smallestError) {
+ tmp = ((lutrgb >> 8) & 0xff) - green;
+ currentError += tmp * tmp;
+ if (currentError < smallestError) {
+ tmp = (lutrgb & 0xff) - blue;
+ currentError += tmp * tmp;
+ if (currentError < smallestError) {
+ pix = i;
+ smallestError = currentError;
+ }
+ }
+ }
+ }
+ }
+ } else if (alpha == 0 && transparent_index >= 0) {
+ // Special case - transparent color maps to the
+ // specified transparent pixel, if there is one
+
+ pix = transparent_index;
+ } else {
+ // IndexColorModel objects are all tagged as
+ // non-premultiplied so use non-premultiplied
+ // color components in the distance calculations.
+ // Look for closest match using a 4 component
+ // Euclidean distance formula.
+
+ int smallestError = Integer.MAX_VALUE;
+ int lut[] = this.rgb;
+ for (int i=0; i < map_size; i++) {
+ int lutrgb = lut[i];
+ if (lutrgb == rgb) {
+ if (validBits != null && !validBits.testBit(i)) {
+ continue;
+ }
+ pix = i;
+ break;
+ }
+
+ int tmp = ((lutrgb >> 16) & 0xff) - red;
+ int currentError = tmp*tmp;
+ if (currentError < smallestError) {
+ tmp = ((lutrgb >> 8) & 0xff) - green;
+ currentError += tmp * tmp;
+ if (currentError < smallestError) {
+ tmp = (lutrgb & 0xff) - blue;
+ currentError += tmp * tmp;
+ if (currentError < smallestError) {
+ tmp = (lutrgb >>> 24) - alpha;
+ currentError += tmp * tmp;
+ if (currentError < smallestError &&
+ (validBits == null || validBits.testBit(i)))
+ {
+ pix = i;
+ smallestError = currentError;
+ }
+ }
+ }
+ }
+ }
+ }
+ System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2);
+ lookupcache[CACHESIZE - 1] = rgb;
+ lookupcache[CACHESIZE - 2] = ~pix;
+ return installpixel(pixel, pix);
+ }
+
+ private Object installpixel(Object pixel, int pix) {
+ switch (transferType) {
+ case DataBuffer.TYPE_INT:
+ int[] intObj;
+ if (pixel == null) {
+ pixel = intObj = new int[1];
+ } else {
+ intObj = (int[]) pixel;
+ }
+ intObj[0] = pix;
+ break;
+ case DataBuffer.TYPE_BYTE:
+ byte[] byteObj;
+ if (pixel == null) {
+ pixel = byteObj = new byte[1];
+ } else {
+ byteObj = (byte[]) pixel;
+ }
+ byteObj[0] = (byte) pix;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short[] shortObj;
+ if (pixel == null) {
+ pixel = shortObj = new short[1];
+ } else {
+ shortObj = (short[]) pixel;
+ }
+ shortObj[0] = (short) pix;
+ break;
+ default:
+ throw new UnsupportedOperationException("This method has not been "+
+ "implemented for transferType " + transferType);
+ }
+ return pixel;
+ }
+
+ /**
+ * Returns an array of unnormalized color/alpha components for a
+ * specified pixel in this <code>ColorModel</code>. The pixel value
+ * is specified as an int. If the <code>components</code> array is <code>null</code>,
+ * a new array is allocated that contains
+ * <code>offset + getNumComponents()</code> elements.
+ * The <code>components</code> array is returned,
+ * with the alpha component included
+ * only if <code>hasAlpha</code> returns true.
+ * Color/alpha components are stored in the <code>components</code> array starting
+ * at <code>offset</code> even if the array is allocated by this method.
+ * An <code>ArrayIndexOutOfBoundsException</code>
+ * is thrown if the <code>components</code> array is not <code>null</code> and is
+ * not large enough to hold all the color and alpha components
+ * starting at <code>offset</code>.
+ * @param pixel the specified pixel
+ * @param components the array to receive the color and alpha
+ * components of the specified pixel
+ * @param offset the offset into the <code>components</code> array at
+ * which to start storing the color and alpha components
+ * @return an array containing the color and alpha components of the
+ * specified pixel starting at the specified offset.
+ * @see ColorModel#hasAlpha
+ * @see ColorModel#getNumComponents
+ */
+ public int[] getComponents(int pixel, int[] components, int offset) {
+ if (components == null) {
+ components = new int[offset+numComponents];
+ }
+
+ // REMIND: Needs to change if different color space
+ components[offset+0] = getRed(pixel);
+ components[offset+1] = getGreen(pixel);
+ components[offset+2] = getBlue(pixel);
+ if (supportsAlpha && (components.length-offset) > 3) {
+ components[offset+3] = getAlpha(pixel);
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns an array of unnormalized color/alpha components for
+ * a specified pixel in this <code>ColorModel</code>. The pixel
+ * value is specified by an array of data elements of type
+ * <code>transferType</code> passed in as an object reference.
+ * If <code>pixel</code> is not a primitive array of type
+ * <code>transferType</code>, a <code>ClassCastException</code>
+ * is thrown. An <code>ArrayIndexOutOfBoundsException</code>
+ * is thrown if <code>pixel</code> is not large enough to hold
+ * a pixel value for this <code>ColorModel</code>. If the
+ * <code>components</code> array is <code>null</code>, a new array
+ * is allocated that contains
+ * <code>offset + getNumComponents()</code> elements.
+ * The <code>components</code> array is returned,
+ * with the alpha component included
+ * only if <code>hasAlpha</code> returns true.
+ * Color/alpha components are stored in the <code>components</code>
+ * array starting at <code>offset</code> even if the array is
+ * allocated by this method. An
+ * <code>ArrayIndexOutOfBoundsException</code> is also
+ * thrown if the <code>components</code> array is not
+ * <code>null</code> and is not large enough to hold all the color
+ * and alpha components starting at <code>offset</code>.
+ * <p>
+ * Since <code>IndexColorModel</code> can be subclassed, subclasses
+ * inherit the implementation of this method and if they don't
+ * override it then they throw an exception if they use an
+ * unsupported <code>transferType</code>.
+ *
+ * @param pixel the specified pixel
+ * @param components an array that receives the color and alpha
+ * components of the specified pixel
+ * @param offset the index into the <code>components</code> array at
+ * which to begin storing the color and alpha components of the
+ * specified pixel
+ * @return an array containing the color and alpha components of the
+ * specified pixel starting at the specified offset.
+ * @throws ArrayIndexOutOfBoundsException if <code>pixel</code>
+ * is not large enough to hold a pixel value for this
+ * <code>ColorModel</code> or if the
+ * <code>components</code> array is not <code>null</code>
+ * and is not large enough to hold all the color
+ * and alpha components starting at <code>offset</code>
+ * @throws ClassCastException if <code>pixel</code> is not a
+ * primitive array of type <code>transferType</code>
+ * @throws UnsupportedOperationException if <code>transferType</code>
+ * is not one of the supported transer types
+ * @see ColorModel#hasAlpha
+ * @see ColorModel#getNumComponents
+ */
+ public int[] getComponents(Object pixel, int[] components, int offset) {
+ int intpixel;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[] = (byte[])pixel;
+ intpixel = bdata[0] & 0xff;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sdata[] = (short[])pixel;
+ intpixel = sdata[0] & 0xffff;
+ break;
+ case DataBuffer.TYPE_INT:
+ int idata[] = (int[])pixel;
+ intpixel = idata[0];
+ break;
+ default:
+ throw new UnsupportedOperationException("This method has not been "+
+ "implemented for transferType " + transferType);
+ }
+ return getComponents(intpixel, components, offset);
+ }
+
+ /**
+ * Returns a pixel value represented as an int in this
+ * <code>ColorModel</code> given an array of unnormalized
+ * color/alpha components. An
+ * <code>ArrayIndexOutOfBoundsException</code>
+ * is thrown if the <code>components</code> array is not large
+ * enough to hold all of the color and alpha components starting
+ * at <code>offset</code>. Since
+ * <code>ColorModel</code> can be subclassed, subclasses inherit the
+ * implementation of this method and if they don't override it then
+ * they throw an exception if they use an unsupported transferType.
+ * @param components an array of unnormalized color and alpha
+ * components
+ * @param offset the index into <code>components</code> at which to
+ * begin retrieving the color and alpha components
+ * @return an <code>int</code> pixel value in this
+ * <code>ColorModel</code> corresponding to the specified components.
+ * @throws ArrayIndexOutOfBoundsException if
+ * the <code>components</code> array is not large enough to
+ * hold all of the color and alpha components starting at
+ * <code>offset</code>
+ * @throws UnsupportedOperationException if <code>transferType</code>
+ * is invalid
+ */
+ public int getDataElement(int[] components, int offset) {
+ int rgb = (components[offset+0]<<16)
+ | (components[offset+1]<<8) | (components[offset+2]);
+ if (supportsAlpha) {
+ rgb |= (components[offset+3]<<24);
+ }
+ else {
+ rgb |= 0xff000000;
+ }
+ Object inData = getDataElements(rgb, null);
+ int pixel;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[] = (byte[])inData;
+ pixel = bdata[0] & 0xff;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sdata[] = (short[])inData;
+ pixel = sdata[0];
+ break;
+ case DataBuffer.TYPE_INT:
+ int idata[] = (int[])inData;
+ pixel = idata[0];
+ break;
+ default:
+ throw new UnsupportedOperationException("This method has not been "+
+ "implemented for transferType " + transferType);
+ }
+ return pixel;
+ }
+
+ /**
+ * Returns a data element array representation of a pixel in this
+ * <code>ColorModel</code> given an array of unnormalized color/alpha
+ * components. This array can then be passed to the
+ * <code>setDataElements</code> method of a <code>WritableRaster</code>
+ * object. An <code>ArrayIndexOutOfBoundsException</code> is
+ * thrown if the
+ * <code>components</code> array is not large enough to hold all of the
+ * color and alpha components starting at <code>offset</code>.
+ * If the pixel variable is <code>null</code>, a new array
+ * is allocated. If <code>pixel</code> is not <code>null</code>,
+ * it must be a primitive array of type <code>transferType</code>;
+ * otherwise, a <code>ClassCastException</code> is thrown.
+ * An <code>ArrayIndexOutOfBoundsException</code> is thrown if pixel
+ * is not large enough to hold a pixel value for this
+ * <code>ColorModel</code>.
+ * <p>
+ * Since <code>IndexColorModel</code> can be subclassed, subclasses
+ * inherit the implementation of this method and if they don't
+ * override it then they throw an exception if they use an
+ * unsupported <code>transferType</code>
+ *
+ * @param components an array of unnormalized color and alpha
+ * components
+ * @param offset the index into <code>components</code> at which to
+ * begin retrieving color and alpha components
+ * @param pixel the <code>Object</code> representing an array of color
+ * and alpha components
+ * @return an <code>Object</code> representing an array of color and
+ * alpha components.
+ * @throws ClassCastException if <code>pixel</code>
+ * is not a primitive array of type <code>transferType</code>
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>pixel</code> is not large enough to hold a pixel value
+ * for this <code>ColorModel</code> or the <code>components</code>
+ * array is not large enough to hold all of the color and alpha
+ * components starting at <code>offset</code>
+ * @throws UnsupportedOperationException if <code>transferType</code>
+ * is not one of the supported transer types
+ * @see WritableRaster#setDataElements
+ * @see SampleModel#setDataElements
+ */
+ public Object getDataElements(int[] components, int offset, Object pixel) {
+ int rgb = (components[offset+0]<<16) | (components[offset+1]<<8)
+ | (components[offset+2]);
+ if (supportsAlpha) {
+ rgb |= (components[offset+3]<<24);
+ }
+ else {
+ rgb &= 0xff000000;
+ }
+ return getDataElements(rgb, pixel);
+ }
+
+ /**
+ * Creates a <code>WritableRaster</code> with the specified width
+ * and height that has a data layout (<code>SampleModel</code>)
+ * compatible with this <code>ColorModel</code>. This method
+ * only works for color models with 16 or fewer bits per pixel.
+ * <p>
+ * Since <code>IndexColorModel</code> can be subclassed, any
+ * subclass that supports greater than 16 bits per pixel must
+ * override this method.
+ *
+ * @param w the width to apply to the new <code>WritableRaster</code>
+ * @param h the height to apply to the new <code>WritableRaster</code>
+ * @return a <code>WritableRaster</code> object with the specified
+ * width and height.
+ * @throws UnsupportedOperationException if the number of bits in a
+ * pixel is greater than 16
+ * @see WritableRaster
+ * @see SampleModel
+ */
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ WritableRaster raster;
+
+ if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+ // TYPE_BINARY
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
+ w, h, 1, pixel_bits, null);
+ }
+ else if (pixel_bits <= 8) {
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ w,h,1,null);
+ }
+ else if (pixel_bits <= 16) {
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT,
+ w,h,1,null);
+ }
+ else {
+ throw new
+ UnsupportedOperationException("This method is not supported "+
+ " for pixel bits > 16.");
+ }
+ return raster;
+ }
+
+ /**
+ * Returns <code>true</code> if <code>raster</code> is compatible
+ * with this <code>ColorModel</code> or <code>false</code> if it
+ * is not compatible with this <code>ColorModel</code>.
+ * @param raster the {@link Raster} object to test for compatibility
+ * @return <code>true</code> if <code>raster</code> is compatible
+ * with this <code>ColorModel</code>; <code>false</code> otherwise.
+ *
+ */
+ public boolean isCompatibleRaster(Raster raster) {
+
+ int size = raster.getSampleModel().getSampleSize(0);
+ return ((raster.getTransferType() == transferType) &&
+ (raster.getNumBands() == 1) && ((1 << size) >= map_size));
+ }
+
+ /**
+ * Creates a <code>SampleModel</code> with the specified
+ * width and height that has a data layout compatible with
+ * this <code>ColorModel</code>.
+ * @param w the width to apply to the new <code>SampleModel</code>
+ * @param h the height to apply to the new <code>SampleModel</code>
+ * @return a <code>SampleModel</code> object with the specified
+ * width and height.
+ * @throws IllegalArgumentException if <code>w</code> or
+ * <code>h</code> is not greater than 0
+ * @see SampleModel
+ */
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ int[] off = new int[1];
+ off[0] = 0;
+ if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+ return new MultiPixelPackedSampleModel(transferType, w, h,
+ pixel_bits);
+ }
+ else {
+ return new ComponentSampleModel(transferType, w, h, 1, w,
+ off);
+ }
+ }
+
+ /**
+ * Checks if the specified <code>SampleModel</code> is compatible
+ * with this <code>ColorModel</code>. If <code>sm</code> is
+ * <code>null</code>, this method returns <code>false</code>.
+ * @param sm the specified <code>SampleModel</code>,
+ * or <code>null</code>
+ * @return <code>true</code> if the specified <code>SampleModel</code>
+ * is compatible with this <code>ColorModel</code>; <code>false</code>
+ * otherwise.
+ * @see SampleModel
+ */
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ // fix 4238629
+ if (! (sm instanceof ComponentSampleModel) &&
+ ! (sm instanceof MultiPixelPackedSampleModel) ) {
+ return false;
+ }
+
+ // Transfer type must be the same
+ if (sm.getTransferType() != transferType) {
+ return false;
+ }
+
+ if (sm.getNumBands() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns a new <code>BufferedImage</code> of TYPE_INT_ARGB or
+ * TYPE_INT_RGB that has a <code>Raster</code> with pixel data
+ * computed by expanding the indices in the source <code>Raster</code>
+ * using the color/alpha component arrays of this <code>ColorModel</code>.
+ * Only the lower <em>n</em> bits of each index value in the source
+ * <code>Raster</code>, as specified in the
+ * <a href="#index_values">class description</a> above, are used to
+ * compute the color/alpha values in the returned image.
+ * If <code>forceARGB</code> is <code>true</code>, a TYPE_INT_ARGB image is
+ * returned regardless of whether or not this <code>ColorModel</code>
+ * has an alpha component array or a transparent pixel.
+ * @param raster the specified <code>Raster</code>
+ * @param forceARGB if <code>true</code>, the returned
+ * <code>BufferedImage</code> is TYPE_INT_ARGB; otherwise it is
+ * TYPE_INT_RGB
+ * @return a <code>BufferedImage</code> created with the specified
+ * <code>Raster</code>
+ * @throws IllegalArgumentException if the raster argument is not
+ * compatible with this IndexColorModel
+ */
+ public BufferedImage convertToIntDiscrete(Raster raster,
+ boolean forceARGB) {
+ ColorModel cm;
+
+ if (!isCompatibleRaster(raster)) {
+ throw new IllegalArgumentException("This raster is not compatible" +
+ "with this IndexColorModel.");
+ }
+ if (forceARGB || transparency == TRANSLUCENT) {
+ cm = ColorModel.getRGBdefault();
+ }
+ else if (transparency == BITMASK) {
+ cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff,
+ 0x1000000);
+ }
+ else {
+ cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff);
+ }
+
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+ WritableRaster discreteRaster =
+ cm.createCompatibleWritableRaster(w, h);
+ Object obj = null;
+ int[] data = null;
+
+ int rX = raster.getMinX();
+ int rY = raster.getMinY();
+
+ for (int y=0; y < h; y++, rY++) {
+ obj = raster.getDataElements(rX, rY, w, 1, obj);
+ if (obj instanceof int[]) {
+ data = (int[])obj;
+ } else {
+ data = DataBuffer.toIntArray(obj);
+ }
+ for (int x=0; x < w; x++) {
+ data[x] = rgb[data[x] & pixel_mask];
+ }
+ discreteRaster.setDataElements(0, y, w, 1, data);
+ }
+
+ return new BufferedImage(cm, discreteRaster, false, null);
+ }
+
+ /**
+ * Returns whether or not the pixel is valid.
+ * @param pixel the specified pixel value
+ * @return <code>true</code> if <code>pixel</code>
+ * is valid; <code>false</code> otherwise.
+ * @since 1.3
+ */
+ public boolean isValid(int pixel) {
+ return ((pixel >= 0 && pixel < map_size) &&
+ (validBits == null || validBits.testBit(pixel)));
+ }
+
+ /**
+ * Returns whether or not all of the pixels are valid.
+ * @return <code>true</code> if all pixels are valid;
+ * <code>false</code> otherwise.
+ * @since 1.3
+ */
+ public boolean isValid() {
+ return (validBits == null);
+ }
+
+ /**
+ * Returns a <code>BigInteger</code> that indicates the valid/invalid
+ * pixels in the colormap. A bit is valid if the
+ * <code>BigInteger</code> value at that index is set, and is invalid
+ * if the <code>BigInteger</code> value at that index is not set.
+ * The only valid ranges to query in the <code>BigInteger</code> are
+ * between 0 and the map size.
+ * @return a <code>BigInteger</code> indicating the valid/invalid pixels.
+ * @since 1.3
+ */
+ public BigInteger getValidPixels() {
+ if (validBits == null) {
+ return getAllValid();
+ }
+ else {
+ return validBits;
+ }
+ }
+
+ /**
+ * Disposes of system resources associated with this
+ * <code>ColorModel</code> once this <code>ColorModel</code> is no
+ * longer referenced.
+ */
+ public void finalize() {
+ sun.awt.image.BufImgSurfaceData.freeNativeICMData(this);
+ }
+
+ /**
+ * Returns the <code>String</code> representation of the contents of
+ * this <code>ColorModel</code>object.
+ * @return a <code>String</code> representing the contents of this
+ * <code>ColorModel</code> object.
+ */
+ public String toString() {
+ return new String("IndexColorModel: #pixelBits = "+pixel_bits
+ + " numComponents = "+numComponents
+ + " color space = "+colorSpace
+ + " transparency = "+transparency
+ + " transIndex = "+transparent_index
+ + " has alpha = "+supportsAlpha
+ + " isAlphaPre = "+isAlphaPremultiplied
+ );
+ }
+}