Index: java/awt/image/IndexColorModel.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/awt/image/IndexColorModel.java,v retrieving revision 1.13 diff -u -r1.13 IndexColorModel.java --- java/awt/image/IndexColorModel.java 1 Apr 2005 16:29:30 -0000 1.13 +++ java/awt/image/IndexColorModel.java 14 Apr 2005 20:57:12 -0000 @@ -1,5 +1,5 @@ /* IndexColorModel.java -- Java class for interpreting Pixel objects - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,99 +35,156 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package java.awt.image; +import gnu.java.awt.Buffers; + import java.awt.color.ColorSpace; import java.math.BigInteger; /** * Color model similar to pseudo visual in X11. - * + *

* This color model maps linear pixel values to actual RGB and alpha colors. * Thus, pixel values are indexes into the color map. Each color component is * an 8-bit unsigned value. - * - * The IndexColorModel supports a map of valid pixels, allowing the - * representation of holes in the the color map. The valid map is represented - * as a BigInteger where each bit indicates the validity of the map entry with - * the same index. - * + *

+ * The IndexColorModel supports a map of valid pixels, allowing + * the representation of holes in the the color map. The valid map is + * represented as a address@hidden BigInteger} where each bit indicates the validity + * of the map entry with the same index. + *

* Colors can have alpha components for transparency support. If alpha * component values aren't given, color values are opaque. The model also * supports a reserved pixel value to represent completely transparent colors, * no matter what the actual color component values are. - * - * IndexColorModel supports anywhere from 1 to 16 bit index values. The - * allowed transfer types are DataBuffer.TYPE_BYTE and DataBuffer.TYPE_USHORT. + *

+ * IndexColorModel supports anywhere from 1 to 16 bit index + * values. The allowed transfer types are address@hidden DataBuffer#TYPE_BYTE} and + * address@hidden DataBuffer#TYPE_USHORT}. * * @author C. Brian Jones (address@hidden) */ public class IndexColorModel extends ColorModel { private int map_size; - private boolean opaque; + private boolean opaque; // no alpha, but doesn't account for trans private int trans = -1; private int[] rgb; private BigInteger validBits = BigInteger.ZERO; /** - * Each array much contain size elements. For each - * array, the i-th color is described by reds[i], greens[i], - * blues[i], alphas[i], unless alphas is not specified, then all the - * colors are opaque except for the transparent color. + * Creates a new indexed color model for size color elements + * with no alpha component. Each array must contain at least + * size elements. For each array, the i-th color is described + * by reds[i], greens[i] and blues[i]. * - * @param bits the number of bits needed to represent size colors - * @param size the number of colors in the color map - * @param reds the red component of all colors - * @param greens the green component of all colors - * @param blues the blue component of all colors + * @param bits the number of bits needed to represent size + * colors. + * @param size the number of colors in the color map. + * @param reds the red component of all colors. + * @param greens the green component of all colors. + * @param blues the blue component of all colors. + * + * @throws IllegalArgumentException if bits < 1 or + * bits > 16. + * @throws NullPointerException if any of the arrays is null. + * @throws ArrayIndexOutOfBoundsException if size is greater + * than the length of the component arrays. */ public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, byte[] blues) { - this (bits, size, reds, greens, blues, (byte[]) null); + this(bits, size, reds, greens, blues, (byte[]) null); } /** - * Each array much contain size elements. For each - * array, the i-th color is described by reds[i], greens[i], - * blues[i], alphas[i], unless alphas is not specified, then all the - * colors are opaque except for the transparent color. + * Creates a new indexed color model for size color elements. + * Each array must contain at least size elements. For each + * array, the i-th color is described by reds[i], greens[i] and blues[i]. + * All the colors are opaque except for the transparent color. * - * @param bits the number of bits needed to represent size colors + * @param bits the number of bits needed to represent size + * colors * @param size the number of colors in the color map * @param reds the red component of all colors * @param greens the green component of all colors * @param blues the blue component of all colors - * @param trans the index of the transparent color + * @param trans the index of the transparent color (use -1 for no + * transparent color). + * + * @throws IllegalArgumentException if bits < 1 or + * bits > 16. + * @throws NullPointerException if any of the arrays is null. + * @throws ArrayIndexOutOfBoundsException if size is greater + * than the length of the component arrays. */ public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, byte[] blues, int trans) { - this (bits, size, reds, greens, blues, (byte[]) null); - this.trans = trans; + super(bits, nArray(8, (0 <= trans && trans < size) ? 4 : 3), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (0 <= trans && trans < size), // hasAlpha + false, OPAQUE, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); + map_size = size; + if (0 <= trans && trans < size) { + this.trans = trans; + transparency = BITMASK; + } + rgb = new int[size]; + for (int i = 0; i < size; i++) + { + rgb[i] = (0xff000000 + | ((reds[i] & 0xff) << 16) + | ((greens[i] & 0xff) << 8) + | (blues[i] & 0xff)); + } + // Generate a bigint with 1's for every pixel + validBits = validBits.setBit(size).subtract(BigInteger.ONE); } /** - * Each array much contain size elements. For each - * array, the i-th color is described by reds[i], greens[i], - * blues[i], alphas[i], unless alphas is not specified, then all the - * colors are opaque except for the transparent color. + * Creates a new indexed color model for size color elements + * including alpha. Each array must contain at least size + * elements. For each array, the i-th color is described + * by reds[i], greens[i], blues[i] and alphas[i]. * - * @param bits the number of bits needed to represent size colors - * @param size the number of colors in the color map - * @param reds the red component of all colors - * @param greens the green component of all colors - * @param blues the blue component of all colors - * @param alphas the alpha component of all colors + * @param bits the number of bits needed to represent size + * colors. + * @param size the number of colors in the color map. + * @param reds the red component of all colors. + * @param greens the green component of all colors. + * @param blues the blue component of all colors. + * @param alphas the alpha component of all colors (null + * permitted). + * + * @throws IllegalArgumentException if bits < 1 or + * bits > 16. + * @throws NullPointerException if reds, greens or + * blues is null. + * @throws ArrayIndexOutOfBoundsException if size is greater + * than the length of the component arrays. */ public IndexColorModel(int bits, int size, byte[] reds, byte[] greens, byte[] blues, byte[] alphas) { - // FIXME: This super() constructor should not be used since it can give - // the wrong value for hasAlpha() which is final and cannot be overloaded - super(bits); + super(bits, nArray(8, (alphas == null ? 3 : 4)), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + (alphas != null), false, TRANSLUCENT, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); + if (bits > 16) + throw new IllegalArgumentException("bits > 16"); + if (size < 1) + throw new IllegalArgumentException("size < 1"); map_size = size; opaque = (alphas == null); @@ -141,16 +198,25 @@ | ((greens[i] & 0xff) << 8) | (blues[i] & 0xff)); } + transparency = OPAQUE; } else { + byte alphaZero = (byte) 0x00; + byte alphaOne = (byte) 0xFF; for (int i = 0; i < size; i++) { + alphaZero = (byte) (alphaZero | alphas[i]); + alphaOne = (byte) (alphaOne & alphas[i]); rgb[i] = ((alphas[i] & 0xff) << 24 | ((reds[i] & 0xff) << 16) | ((greens[i] & 0xff) << 8) | (blues[i] & 0xff)); } + if ((alphaZero == (byte) 0x00) || (alphaOne == (byte) 0xFF)) + transparency = BITMASK; + else + transparency = TRANSLUCENT; } // Generate a bigint with 1's for every pixel @@ -158,61 +224,85 @@ } /** - * Each array much contain size elements. For each - * array, the i-th color is described by reds[i], greens[i], - * blues[i], alphas[i], unless alphas is not specified, then all the - * colors are opaque except for the transparent color. + * Creates a new indexed color model using the color components in + * cmap. If hasAlpha is true then + * cmap contains an alpha component after each of the red, green + * and blue components. * - * @param bits the number of bits needed to represent size colors + * @param bits the number of bits needed to represent size + * colors * @param size the number of colors in the color map * @param cmap packed color components * @param start the offset of the first color component in cmap * @param hasAlpha cmap has alpha values - * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws NullPointerException if cmap is null. */ - public IndexColorModel (int bits, int size, byte[] cmap, int start, - boolean hasAlpha) + public IndexColorModel(int bits, int size, byte[] cmap, int start, + boolean hasAlpha) { - this (bits, size, cmap, start, hasAlpha, -1); + this(bits, size, cmap, start, hasAlpha, -1); } /** * Construct an IndexColorModel from an array of red, green, blue, and - * optional alpha components. The component values are interleaved as RGB(A). + * optional alpha components. The component values are interleaved as RGB(A). * - * @param bits the number of bits needed to represent size colors + * @param bits the number of bits needed to represent size + * colors * @param size the number of colors in the color map * @param cmap interleaved color components * @param start the offset of the first color component in cmap * @param hasAlpha cmap has alpha values * @param trans the index of the transparent color - * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1. - */ - public IndexColorModel (int bits, int size, byte[] cmap, int start, - boolean hasAlpha, int trans) - { - super (bits); + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws NullPointerException if cmap is null. + */ + public IndexColorModel(int bits, int size, byte[] cmap, int start, + boolean hasAlpha, int trans) + { + super(bits, nArray(8, hasAlpha || (0 <= trans && trans < size) ? 4 : 3), + ColorSpace.getInstance(ColorSpace.CS_sRGB), + hasAlpha || (0 <= trans && trans < size), false, OPAQUE, + Buffers.smallestAppropriateTransferType(bits)); + if (bits < 1) + throw new IllegalArgumentException("bits < 1"); if (bits > 16) throw new IllegalArgumentException("bits > 16"); if (size < 1) throw new IllegalArgumentException("size < 1"); map_size = size; opaque = !hasAlpha; - this.trans = trans; + if (0 <= trans && trans < size) + this.trans = trans; rgb = new int[size]; if (hasAlpha) { - for (int i = 0; i < size; i++) + int alpha; + int alphaZero = 0x00; // use to detect all zeros + int alphaOne = 0xff; // use to detect all ones + for (int i = 0; i < size; i++) { + alpha = cmap[4 * i + 3 + start] & 0xff; + alphaZero = alphaZero | alpha; + alphaOne = alphaOne & alpha; rgb[i] = - // alpha - ((cmap[4 * i + 3 + start] & 0xff) << 24 + ( alpha << 24 // red | ((cmap[4 * i + start] & 0xff) << 16) // green | ((cmap[4 * i + 1 + start] & 0xff) << 8) // blue | (cmap[4 * i + 2 + start] & 0xff)); + } + if (alphaZero == 0) + transparency = BITMASK; + else if (alphaOne == 255) + transparency = (trans != -1 ? BITMASK : OPAQUE); + else + transparency = TRANSLUCENT; } else { @@ -224,6 +314,8 @@ | ((cmap[3 * i + 1 + start] & 0xff) << 8) // blue | (cmap[3 * i + 2 + start] & 0xff)); + if (trans != -1) + transparency = BITMASK; } // Generate a bigint with 1's for every pixel @@ -236,22 +328,26 @@ * alpha values packed in order. If hasAlpha is false, then all the colors * are opaque except for the transparent color. * - * @param bits the number of bits needed to represent size colors + * @param bits the number of bits needed to represent size + * colors * @param size the number of colors in the color map * @param cmap packed color components * @param start the offset of the first color component in cmap * @param hasAlpha cmap has alpha values * @param trans the index of the transparent color - * @param transferType DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT - * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1. - * @throws IllegalArgumentException if transferType is something other than - * TYPE_BYTE or TYPE_USHORT. + * @param transferType address@hidden DataBuffer#TYPE_BYTE} or + address@hidden DataBuffer#TYPE_USHORT}. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. + * @throws IllegalArgumentException if transferType is something + * other than address@hidden DataBuffer#TYPE_BYTE} or + * address@hidden DataBuffer#TYPE_USHORT}. */ - public IndexColorModel (int bits, int size, int[] cmap, int start, - boolean hasAlpha, int trans, int transferType) + public IndexColorModel(int bits, int size, int[] cmap, int start, + boolean hasAlpha, int trans, int transferType) { - super(bits * 4, // total bits, sRGB, four channels - nArray(bits, 4), // bits for each channel + super(bits, + nArray(8, 4), // bits for each channel ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB true, // has alpha false, // not premultiplied @@ -265,7 +361,8 @@ throw new IllegalArgumentException("size < 1"); map_size = size; opaque = !hasAlpha; - this.trans = trans; + if (0 <= trans && trans < size) + this.trans = trans; rgb = new int[size]; if (!hasAlpha) @@ -280,30 +377,34 @@ /** * Construct an IndexColorModel using a colormap with holes. - * + *

* The IndexColorModel is built from the array of ints defining the * colormap. Each element contains red, green, blue, and alpha * components. The ColorSpace is sRGB. The transparency value is * automatically determined. - * + *

* This constructor permits indicating which colormap entries are valid, * using the validBits argument. Each entry in cmap is valid if the * corresponding bit in validBits is set. * - * @param bits the number of bits needed to represent size colors - * @param size the number of colors in the color map - * @param cmap packed color components - * @param start the offset of the first color component in cmap - * @param transferType DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT - * @throws IllegalArgumentException if bits < 1, bits > 16, or size < 1. + * @param bits the number of bits needed to represent size + * colors. + * @param size the number of colors in the color map. + * @param cmap packed color components. + * @param start the offset of the first color component in cmap. + * @param transferType address@hidden DataBuffer#TYPE_BYTE} or + * address@hidden DataBuffer#TYPE_USHORT}. + * @param validBits a map of the valid entries in cmap. + * @throws IllegalArgumentException if bits < 1, bits > 16, or size + * < 1. * @throws IllegalArgumentException if transferType is something other than - * TYPE_BYTE or TYPE_USHORT. + * address@hidden DataBuffer#TYPE_BYTE} or address@hidden DataBuffer#TYPE_USHORT}. */ - public IndexColorModel (int bits, int size, int[] cmap, int start, - int transferType, BigInteger validBits) + public IndexColorModel(int bits, int size, int[] cmap, int start, + int transferType, BigInteger validBits) { - super(bits * 4, // total bits, sRGB, four channels - nArray(bits, 4), // bits for each channel + super(bits, // total bits, sRGB, four channels + nArray(8, 4), // bits for each channel ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB true, // has alpha false, // not premultiplied @@ -328,112 +429,181 @@ System.arraycopy(cmap, start, rgb, 0, size); } - public final int getMapSize () + /** + * Returns the size of the color lookup table. + * + * @return The size of the color lookup table. + */ + public final int getMapSize() { return map_size; } /** - * Get the index of the transparent color in this color model + * Get the index of the transparent color in this color model. + * + * @return The index of the color that is considered transparent, or -1 if + * there is no transparent color. */ - public final int getTransparentPixel () + public final int getTransparentPixel() { return trans; } /** - *
+ * Fills the supplied array with the red component of each color in the + * lookup table. + * + * @param r an array that is at least as large as address@hidden #getMapSize()}. + * @throws NullPointerException if r is null. + * @throws ArrayIndexOutOfBoundsException if r has less + * than address@hidden #getMapSize()} elements. */ - public final void getReds (byte[] r) + public final void getReds(byte[] r) { - getComponents (r, 2); + int i; + for (i = 0; i < map_size; i++) + r[i] = (byte) ((0x00FF0000 & rgb[i]) >> 16); } /** - *
+ * Fills the supplied array with the green component of each color in the + * lookup table. + * + * @param g an array that is at least as large as address@hidden #getMapSize()}. + * @throws NullPointerException if g is null. + * @throws ArrayIndexOutOfBoundsException if g has less + * than address@hidden #getMapSize()} elements. */ - public final void getGreens (byte[] g) + public final void getGreens(byte[] g) { - getComponents (g, 1); + int i; + for (i = 0; i < map_size; i++) + g[i] = (byte) ((0x0000FF00 & rgb[i]) >> 8); } /** - *
+ * Fills the supplied array with the blue component of each color in the + * lookup table. + * + * @param b an array that is at least as large as address@hidden #getMapSize()}. + * @throws NullPointerException if b is null. + * @throws ArrayIndexOutOfBoundsException if b has less + * than address@hidden #getMapSize()} elements. */ - public final void getBlues (byte[] b) + public final void getBlues(byte[] b) { - getComponents (b, 0); + int i; + for (i = 0; i < map_size; i++) + b[i] = (byte) (0x000000FF & rgb[i]); } /** - *
+ * Fills the supplied array with the alpha component of each color in the + * lookup table. If the model has a transparent pixel specified, the alpha + * for that pixel will be 0. + * + * @param a an array that is at least as large as address@hidden #getMapSize()}. + * @throws NullPointerException if a is null. + * @throws ArrayIndexOutOfBoundsException if a has less + * than address@hidden #getMapSize()} elements. */ - public final void getAlphas (byte[] a) + public final void getAlphas(byte[] a) { - getComponents (a, 3); + int i; + for (i = 0; i < map_size; i++) + if (i == trans) + a[i] = (byte) 0; + else + a[i] = (byte) ((0xFF000000 & rgb[i]) >> 24); } - private void getComponents (byte[] c, int ci) - { - int i, max = (map_size < c.length) ? map_size : c.length; - for (i = 0; i < max; i++) - c[i] = (byte) ((generateMask (ci) & rgb[i]) >> (ci * pixel_bits)); - } - /** - * Get the red component of the given pixel. + * Returns the red component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The red component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. */ - public final int getRed (int pixel) + public final int getRed(int pixel) { if (pixel < map_size) - return (int) ((generateMask (2) & rgb[pixel]) >> (2 * pixel_bits)); + return (0x00FF0000 & rgb[pixel]) >> 16; return 0; } /** - * Get the green component of the given pixel. + * Returns the green component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The green component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. */ - public final int getGreen (int pixel) + public final int getGreen(int pixel) { if (pixel < map_size) - return (int) ((generateMask (1) & rgb[pixel]) >> (1 * pixel_bits)); + return (0x0000FF00 & rgb[pixel]) >> 8; return 0; } /** - * Get the blue component of the given pixel. + * Returns the blue component of the color in the lookup table for the + * given pixel value. + * + * @param pixel the pixel lookup value. + * + * @return The blue component of the color in the lookup table. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. */ - public final int getBlue (int pixel) + public final int getBlue(int pixel) { - if (pixel < map_size) - return (int) (generateMask (0) & rgb[pixel]); + if (pixel < map_size) + return 0x000000FF & rgb[pixel]; return 0; } /** - * Get the alpha component of the given pixel. + * Returns the alpha component of the color in the lookup table for the + * given pixel value. If no alpha channel was specified when the color model + * was created, then 255 is returned for all pixels except the transparent + * pixel (if one is defined - see address@hidden #getTransparentPixel()}) which + * returns an alpha of 0. + * + * @param pixel the pixel lookup value. + * + * @return The alpha component of the color in the lookup table (in the + * range 0 to 255). + * @throws ArrayIndexOutOfBoundsException if pixel is negative. */ - public final int getAlpha (int pixel) + public final int getAlpha(int pixel) { - if (opaque || pixel >= map_size) + if (opaque && pixel != trans) return 255; + if ((pixel == trans && trans != -1) || pixel >= map_size) + return 0; - return (int) ((generateMask (3) & rgb[pixel]) >> (3 * pixel_bits)); + return (0xFF000000 & rgb[pixel]) >> 24; } /** * Get the RGB color value of the given pixel using the default * RGB color model. * - * @param pixel a pixel value + * @param pixel the pixel lookup value. + * @return The RGB color value. + * @throws ArrayIndexOutOfBoundsException if pixel is negative. */ - public final int getRGB (int pixel) + public final int getRGB(int pixel) { if (pixel >= 0 && pixel < map_size) - return rgb[pixel]; + return rgb[pixel]; return 0; } @@ -444,36 +614,47 @@ * * @param rgb The destination array. */ - public final void getRGBs (int[] rgb) + public final void getRGBs(int[] rgb) { System.arraycopy(this.rgb, 0, rgb, 0, map_size); } - //pixel_bits is number of bits to be in generated mask - private int generateMask (int offset) - { - return (((2 << pixel_bits ) - 1) << (pixel_bits * offset)); - } - - /** Return true if pixel is valid, false otherwise. */ + /** + * Return true if the lookup table contains valid data for + * pixel, and false otherwise. + * + * @param pixel the pixel value used to index the color lookup table. + * @return true if pixel is valid, + * false otherwise. + */ public boolean isValid(int pixel) { - return validBits.testBit(pixel); + if (pixel >= 0) + return validBits.testBit(pixel); + return false; } - /** Return true if all pixels are valid, false otherwise. */ + /** + * Return true if all pixels are valid, false + * otherwise. + * + * @return true if all pixels are valid, false + * otherwise. + */ public boolean isValid() { // Generate a bigint with 1's for every pixel BigInteger allbits = new BigInteger("0"); - allbits.setBit(map_size); - allbits.subtract(new BigInteger("1")); + allbits = allbits.setBit(map_size); + allbits = allbits.subtract(new BigInteger("1")); return allbits.equals(validBits); } /** - * Returns a BigInteger where each bit represents an entry in the color - * model. If the bit is on, the entry is valid. + * Returns a binary value (address@hidden BigInteger}) where each bit represents an + * entry in the color lookup table. If the bit is on, the entry is valid. + * + * @return The binary value. */ public BigInteger getValidPixels() { @@ -481,7 +662,8 @@ } /** - * Construct a BufferedImage with rgb pixel values from a Raster. + * Construct a address@hidden BufferedImage} with rgb pixel values from a + * address@hidden Raster}. * * Constructs a new BufferedImage in which each pixel is an RGBA int from * a Raster with index-valued pixels. If this model has no alpha component @@ -513,4 +695,3 @@ return im; } } -