From 8a200829f09dc9a8d1c8bf1c8670bf639e5db06c Mon Sep 17 00:00:00 2001 From: smallsql Date: Wed, 7 Jan 2009 15:27:43 +0000 Subject: [PATCH] Replace Classpath ColorModels with the Sun ColorModels; fix some bugs in BufferedImage --- openjdk/allsources.lst | 13 +- openjdk/java/awt/image/BufferedImage.java | 35 +- openjdk/java/awt/image/ColorConvertOp.java | 2 +- openjdk/java/awt/image/ColorModel.java | 1921 +++++++++++ .../java/awt/image/ComponentColorModel.java | 2862 +++++++++++++++++ openjdk/java/awt/image/IndexColorModel.java | 1519 +++++++++ openjdk/response.txt | 1 + 7 files changed, 6336 insertions(+), 17 deletions(-) create mode 100644 openjdk/java/awt/image/ColorModel.java create mode 100644 openjdk/java/awt/image/ComponentColorModel.java create mode 100644 openjdk/java/awt/image/IndexColorModel.java diff --git a/openjdk/allsources.lst b/openjdk/allsources.lst index 4e25f480..622822de 100644 --- a/openjdk/allsources.lst +++ b/openjdk/allsources.lst @@ -350,24 +350,19 @@ ../../classpath-0.95/java/awt/image/BufferedImageOp.java ../../classpath-0.95/java/awt/image/BufferStrategy.java ../../classpath-0.95/java/awt/image/ByteLookupTable.java -../../classpath-0.95/java/awt/image/ColorModel.java -../../classpath-0.95/java/awt/image/ComponentColorModel.java ../../classpath-0.95/java/awt/image/ConvolveOp.java ../../classpath-0.95/java/awt/image/CropImageFilter.java -../../classpath-0.95/java/awt/image/DirectColorModel.java ../../classpath-0.95/java/awt/image/FilteredImageSource.java ../../classpath-0.95/java/awt/image/ImageConsumer.java ../../classpath-0.95/java/awt/image/ImageFilter.java ../../classpath-0.95/java/awt/image/ImageObserver.java ../../classpath-0.95/java/awt/image/ImageProducer.java ../../classpath-0.95/java/awt/image/ImagingOpException.java -../../classpath-0.95/java/awt/image/IndexColorModel.java ../../classpath-0.95/java/awt/image/Kernel.java ../../classpath-0.95/java/awt/image/LookupOp.java ../../classpath-0.95/java/awt/image/LookupTable.java ../../classpath-0.95/java/awt/image/MemoryImageSource.java ../../classpath-0.95/java/awt/image/MultiPixelPackedSampleModel.java -../../classpath-0.95/java/awt/image/PackedColorModel.java ../../classpath-0.95/java/awt/image/PixelGrabber.java ../../classpath-0.95/java/awt/image/RasterFormatException.java ../../classpath-0.95/java/awt/image/RasterOp.java @@ -1037,7 +1032,10 @@ ikvm/internal/AnnotationAttributeBase.java ikvm/internal/FieldReflectorBase.java java/awt/image/BufferedImage.java java/awt/image/ColorConvertOp.java +java/awt/image/ColorModel.java +java/awt/image/ComponentColorModel.java java/awt/image/ComponentSampleModel.java +java/awt/image/IndexColorModel.java java/awt/image/Raster.java java/awt/image/SampleModel.java java/io/DeleteOnExitHook.java @@ -7428,6 +7426,8 @@ SystemProperties.java ../../openjdk6-b12/jdk/src/share/classes/java/awt/image/DataBufferInt.java ../../openjdk6-b12/jdk/src/share/classes/java/awt/image/DataBufferShort.java ../../openjdk6-b12/jdk/src/share/classes/java/awt/image/DataBufferUShort.java +../../openjdk6-b12/jdk/src/share/classes/java/awt/image/DirectColorModel.java +../../openjdk6-b12/jdk/src/share/classes/java/awt/image/PackedColorModel.java ../../openjdk6-b12/jdk/src/share/classes/java/awt/image/PixelInterleavedSampleModel.java ../../openjdk6-b12/jdk/src/share/classes/java/beans/AppletInitializer.java ../../openjdk6-b12/jdk/src/share/classes/java/beans/BeanDescriptor.java @@ -9582,6 +9582,9 @@ SystemProperties.java ../../openjdk6-b12/jdk/src/share/classes/sun/io/Converters.java ../../openjdk6-b12/jdk/src/share/classes/sun/io/MalformedInputException.java ../../openjdk6-b12/jdk/src/share/classes/sun/io/UnknownCharacterException.java +../../openjdk6-b12/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java +../../openjdk6-b12/jdk/src/share/classes/sun/java2d/cmm/ColorTransform.java +../../openjdk6-b12/jdk/src/share/classes/sun/java2d/cmm/PCMM.java ../../openjdk6-b12/jdk/src/share/classes/sun/java2d/DefaultDisposerRecord.java ../../openjdk6-b12/jdk/src/share/classes/sun/java2d/Disposer.java ../../openjdk6-b12/jdk/src/share/classes/sun/java2d/DisposerRecord.java diff --git a/openjdk/java/awt/image/BufferedImage.java b/openjdk/java/awt/image/BufferedImage.java index 7f48d462..f365c79d 100644 --- a/openjdk/java/awt/image/BufferedImage.java +++ b/openjdk/java/awt/image/BufferedImage.java @@ -651,7 +651,7 @@ public class BufferedImage extends java.awt.Image bitmap = new cli.System.Drawing.Bitmap(width, height, PixelFormat.wrap( PixelFormat.Format32bppArgb )); for( int y = 0; yColorModel abstract class encapsulates the + * methods for translating a pixel value to color components + * (for example, red, green, and blue) and an alpha component. + * In order to render an image to the screen, a printer, or another + * image, pixel values must be converted to color and alpha components. + * As arguments to or return values from methods of this class, + * pixels are represented as 32-bit ints or as arrays of primitive types. + * The number, order, and interpretation of color components for a + * ColorModel is specified by its ColorSpace. + * A ColorModel used with pixel data that does not include + * alpha information treats all pixels as opaque, which is an alpha + * value of 1.0. + *

+ * This ColorModel class supports two representations of + * pixel values. A pixel value can be a single 32-bit int or an + * array of primitive types. The Java(tm) Platform 1.0 and 1.1 APIs + * represented pixels as single byte or single + * int values. For purposes of the ColorModel + * class, pixel value arguments were passed as ints. The Java(tm) 2 + * Platform API introduced additional classes for representing images. + * With {@link BufferedImage} or {@link RenderedImage} + * objects, based on {@link Raster} and {@link SampleModel} classes, pixel + * values might not be conveniently representable as a single int. + * Consequently, ColorModel now has methods that accept + * pixel values represented as arrays of primitive types. The primitive + * type used by a particular ColorModel object is called its + * transfer type. + *

+ * ColorModel objects used with images for which pixel values + * are not conveniently representable as a single int throw an + * {@link IllegalArgumentException} when methods taking a single int pixel + * argument are called. Subclasses of ColorModel must + * specify the conditions under which this occurs. This does not + * occur with {@link DirectColorModel} or {@link IndexColorModel} objects. + *

+ * Currently, the transfer types supported by the Java 2D(tm) API are + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, and DataBuffer.TYPE_DOUBLE. + * Most rendering operations will perform much faster when using ColorModels + * and images based on the first three of these types. In addition, some + * image filtering operations are not supported for ColorModels and + * images based on the latter three types. + * The transfer type for a particular ColorModel object is + * specified when the object is created, either explicitly or by default. + * All subclasses of ColorModel must specify what the + * possible transfer types are and how the number of elements in the + * primitive arrays representing pixels is determined. + *

+ * For BufferedImages, the transfer type of its + * Raster and of the Raster object's + * SampleModel (available from the + * getTransferType methods of these classes) must match that + * of the ColorModel. The number of elements in an array + * representing a pixel for the Raster and + * SampleModel (available from the + * getNumDataElements methods of these classes) must match + * that of the ColorModel. + *

+ * The algorithm used to convert from pixel values to color and alpha + * components varies by subclass. For example, there is not necessarily + * a one-to-one correspondence between samples obtained from the + * SampleModel of a BufferedImage object's + * Raster and color/alpha components. Even when + * there is such a correspondence, the number of bits in a sample is not + * necessarily the same as the number of bits in the corresponding color/alpha + * component. Each subclass must specify how the translation from + * pixel values to color/alpha components is done. + *

+ * Methods in the ColorModel class use two different + * representations of color and alpha components - a normalized form + * and an unnormalized form. In the normalized form, each component is a + * float value between some minimum and maximum values. For + * the alpha component, the minimum is 0.0 and the maximum is 1.0. For + * color components the minimum and maximum values for each component can + * be obtained from the ColorSpace object. These values + * will often be 0.0 and 1.0 (e.g. normalized component values for the + * default sRGB color space range from 0.0 to 1.0), but some color spaces + * have component values with different upper and lower limits. These + * limits can be obtained using the getMinValue and + * getMaxValue methods of the ColorSpace + * class. Normalized color component values are not premultiplied. + * All ColorModels must support the normalized form. + *

+ * In the unnormalized + * form, each component is an unsigned integral value between 0 and + * 2n - 1, where n is the number of significant bits for a + * particular component. If pixel values for a particular + * ColorModel represent color samples premultiplied by + * the alpha sample, unnormalized color component values are + * also premultiplied. The unnormalized form is used only with instances + * of ColorModel whose ColorSpace has minimum + * component values of 0.0 for all components and maximum values of + * 1.0 for all components. + * The unnormalized form for color and alpha components can be a convenient + * representation for ColorModels whose normalized component + * values all lie + * between 0.0 and 1.0. In such cases the integral value 0 maps to 0.0 and + * the value 2n - 1 maps to 1.0. In other cases, such as + * when the normalized component values can be either negative or positive, + * the unnormalized form is not convenient. Such ColorModel + * objects throw an {@link IllegalArgumentException} when methods involving + * an unnormalized argument are called. Subclasses of ColorModel + * must specify the conditions under which this occurs. + * + * @see IndexColorModel + * @see ComponentColorModel + * @see PackedColorModel + * @see DirectColorModel + * @see java.awt.Image + * @see BufferedImage + * @see RenderedImage + * @see java.awt.color.ColorSpace + * @see SampleModel + * @see Raster + * @see DataBuffer + */ +public abstract class ColorModel implements Transparency{ + private long pData; // Placeholder for data for native functions + + /** + * The total number of bits in the pixel. + */ + protected int pixel_bits; + int nBits[]; + int transparency = Transparency.TRANSLUCENT; + boolean supportsAlpha = true; + boolean isAlphaPremultiplied = false; + int numComponents = -1; + int numColorComponents = -1; + ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int colorSpaceType = ColorSpace.TYPE_RGB; + int maxBits; + boolean is_sRGB = true; + + /** + * Data type of the array used to represent pixel values. + */ + protected int transferType; + + private static ColorModel RGBdefault; + + /** + * Returns a DirectColorModel that describes the default + * format for integer RGB values used in many of the methods in the + * AWT image interfaces for the convenience of the programmer. + * The color space is the default {@link ColorSpace}, sRGB. + * The format for the RGB values is an integer with 8 bits + * each of alpha, red, green, and blue color components ordered + * correspondingly from the most significant byte to the least + * significant byte, as in: 0xAARRGGBB. Color components are + * not premultiplied by the alpha component. This format does not + * necessarily represent the native or the most efficient + * ColorModel for a particular device or for all images. + * It is merely used as a common color model format. + * @return a DirectColorModelobject describing default + * RGB values. + */ + public static ColorModel getRGBdefault() { + if (RGBdefault == null) { + RGBdefault = new DirectColorModel(32, + 0x00ff0000, // Red + 0x0000ff00, // Green + 0x000000ff, // Blue + 0xff000000 // Alpha + ); + } + return RGBdefault; + } + + /** + * Constructs a ColorModel that translates pixels of the + * specified number of bits to color/alpha components. The color + * space is the default RGB ColorSpace, which is sRGB. + * Pixel values are assumed to include alpha information. If color + * and alpha information are represented in the pixel value as + * separate spatial bands, the color bands are assumed not to be + * premultiplied with the alpha value. The transparency type is + * java.awt.Transparency.TRANSLUCENT. The transfer type will be the + * smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * or DataBuffer.TYPE_INT that can hold a single pixel + * (or DataBuffer.TYPE_UNDEFINED if bits is greater + * than 32). Since this constructor has no information about the + * number of bits per color and alpha component, any subclass calling + * this constructor should override any method that requires this + * information. + * @param bits the number of bits of a pixel + * @throws IllegalArgumentException if the number + * of bits in bits is less than 1 + */ + public ColorModel(int bits) { + pixel_bits = bits; + if (bits < 1) { + throw new IllegalArgumentException("Number of bits must be > 0"); + } + numComponents = 4; + numColorComponents = 3; + maxBits = bits; + // REMIND: make sure transferType is set correctly + transferType = ColorModel.getDefaultTransferType(bits); + } + + /** + * Constructs a ColorModel that translates pixel values + * to color/alpha components. Color components will be in the + * specified ColorSpace. pixel_bits is the + * number of bits in the pixel values. The bits array + * specifies the number of significant bits per color and alpha component. + * Its length should be the number of components in the + * ColorSpace if there is no alpha information in the + * pixel values, or one more than this number if there is alpha + * information. hasAlpha indicates whether or not alpha + * information is present. The boolean + * isAlphaPremultiplied specifies how to interpret pixel + * values in which color and alpha information are represented as + * separate spatial bands. If the boolean + * is true, color samples are assumed to have been + * multiplied by the alpha sample. The transparency + * specifies what alpha values can be represented by this color model. + * The transfer type is the type of primitive array used to represent + * pixel values. Note that the bits array contains the number of + * significant bits per color/alpha component after the translation + * from pixel values. For example, for an + * IndexColorModel with pixel_bits equal to + * 16, the bits array might have four elements with each element set + * to 8. + * @param pixel_bits the number of bits in the pixel values + * @param bits array that specifies the number of significant bits + * per color and alpha component + * @param cspace the specified ColorSpace + * @param hasAlpha true if alpha information is present; + * false otherwise + * @param isAlphaPremultiplied true if color samples are + * assumed to be premultiplied by the alpha samples; + * false otherwise + * @param transparency what alpha values can be represented by this + * color model + * @param transferType the type of the array used to represent pixel + * values + * @throws IllegalArgumentException if the length of + * the bit array is less than the number of color or alpha + * components in this ColorModel, or if the + * transparency is not a valid value. + * @throws IllegalArgumentException if the sum of the number + * of bits in bits is less than 1 or if + * any of the elements in bits is less than 0. + * @see java.awt.Transparency + */ + protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, + boolean hasAlpha, + boolean isAlphaPremultiplied, + int transparency, + int transferType) { + colorSpace = cspace; + colorSpaceType = cspace.getType(); + numColorComponents = cspace.getNumComponents(); + numComponents = numColorComponents + (hasAlpha ? 1 : 0); + supportsAlpha = hasAlpha; + if (bits.length < numComponents) { + throw new IllegalArgumentException("Number of color/alpha "+ + "components should be "+ + numComponents+ + " but length of bits array is "+ + bits.length); + } + + // 4186669 + if (transparency < Transparency.OPAQUE || + transparency > Transparency.TRANSLUCENT) + { + throw new IllegalArgumentException("Unknown transparency: "+ + transparency); + } + + if (supportsAlpha == false) { + this.isAlphaPremultiplied = false; + this.transparency = Transparency.OPAQUE; + } + else { + this.isAlphaPremultiplied = isAlphaPremultiplied; + this.transparency = transparency; + } + + nBits = (int[]) bits.clone(); + this.pixel_bits = pixel_bits; + if (pixel_bits <= 0) { + throw new IllegalArgumentException("Number of pixel bits must "+ + "be > 0"); + } + // Check for bits < 0 + maxBits = 0; + for (int i=0; i < bits.length; i++) { + // bug 4304697 + if (bits[i] < 0) { + throw new + IllegalArgumentException("Number of bits must be >= 0"); + } + if (maxBits < bits[i]) { + maxBits = bits[i]; + } + } + + // Make sure that we don't have all 0-bit components + if (maxBits == 0) { + throw new IllegalArgumentException("There must be at least "+ + "one component with > 0 "+ + "pixel bits."); + } + + // Save this since we always need to check if it is the default CS + if (cspace != ColorSpace.getInstance(ColorSpace.CS_sRGB)) { + is_sRGB = false; + } + + // Save the transfer type + this.transferType = transferType; + } + + /** + * Returns whether or not alpha is supported in this + * ColorModel. + * @return true if alpha is supported in this + * ColorModel; false otherwise. + */ + final public boolean hasAlpha() { + return supportsAlpha; + } + + /** + * Returns whether or not the alpha has been premultiplied in the + * pixel values to be translated by this ColorModel. + * If the boolean is true, this ColorModel + * is to be used to interpret pixel values in which color and alpha + * information are represented as separate spatial bands, and color + * samples are assumed to have been multiplied by the + * alpha sample. + * @return true if the alpha values are premultiplied + * in the pixel values to be translated by this + * ColorModel; false otherwise. + */ + final public boolean isAlphaPremultiplied() { + return isAlphaPremultiplied; + } + + /** + * Returns the transfer type of this ColorModel. + * The transfer type is the type of primitive array used to represent + * pixel values as arrays. + * @return the transfer type. + * @since 1.3 + */ + final public int getTransferType() { + return transferType; + } + + /** + * Returns the number of bits per pixel described by this + * ColorModel. + * @return the number of bits per pixel. + */ + public int getPixelSize() { + return pixel_bits; + } + + /** + * Returns the number of bits for the specified color/alpha component. + * Color components are indexed in the order specified by the + * ColorSpace. Typically, this order reflects the name + * of the color space type. For example, for TYPE_RGB, index 0 + * corresponds to red, index 1 to green, and index 2 + * to blue. If this ColorModel supports alpha, the alpha + * component corresponds to the index following the last color + * component. + * @param componentIdx the index of the color/alpha component + * @return the number of bits for the color/alpha component at the + * specified index. + * @throws ArrayIndexOutOfBoundsException if componentIdx + * is greater than the number of components or + * less than zero + * @throws NullPointerException if the number of bits array is + * null + */ + public int getComponentSize(int componentIdx) { + // REMIND: + if (nBits == null) { + throw new NullPointerException("Number of bits array is null."); + } + + return nBits[componentIdx]; + } + + /** + * Returns an array of the number of bits per color/alpha component. + * The array contains the color components in the order specified by the + * ColorSpace, followed by the alpha component, if + * present. + * @return an array of the number of bits per color/alpha component + */ + public int[] getComponentSize() { + if (nBits != null) { + return (int[]) nBits.clone(); + } + + return null; + } + + /** + * Returns the transparency. Returns either OPAQUE, BITMASK, + * or TRANSLUCENT. + * @return the transparency of this ColorModel. + * @see Transparency#OPAQUE + * @see Transparency#BITMASK + * @see Transparency#TRANSLUCENT + */ + public int getTransparency() { + return transparency; + } + + /** + * Returns the number of components, including alpha, in this + * ColorModel. This is equal to the number of color + * components, optionally plus one, if there is an alpha component. + * @return the number of components in this ColorModel + */ + public int getNumComponents() { + return numComponents; + } + + /** + * Returns the number of color components in this + * ColorModel. + * This is the number of components returned by + * {@link ColorSpace#getNumComponents}. + * @return the number of color components in this + * ColorModel. + * @see ColorSpace#getNumComponents + */ + public int getNumColorComponents() { + return numColorComponents; + } + + /** + * Returns the red color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion + * is done if necessary. The pixel value is specified as an int. + * An IllegalArgumentException is thrown if pixel + * values for this ColorModel are not conveniently + * representable as a single int. The returned value is not a + * pre-multiplied value. For example, if the + * alpha is premultiplied, this method divides it out before returning + * the value. If the alpha value is 0, the red value is 0. + * @param pixel a specified pixel + * @return the value of the red component of the specified pixel. + */ + public abstract int getRed(int pixel); + + /** + * Returns the green color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion + * is done if necessary. The pixel value is specified as an int. + * An IllegalArgumentException is thrown if pixel + * values for this ColorModel are not conveniently + * representable as a single int. The returned value is a non + * pre-multiplied value. For example, if the alpha is premultiplied, + * this method divides it out before returning + * the value. If the alpha value is 0, the green value is 0. + * @param pixel the specified pixel + * @return the value of the green component of the specified pixel. + */ + public abstract int getGreen(int pixel); + + /** + * Returns the blue color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion + * is done if necessary. The pixel value is specified as an int. + * An IllegalArgumentException is thrown if pixel values + * for this ColorModel are not conveniently representable + * as a single int. The returned value is a non pre-multiplied + * value, for example, if the alpha is premultiplied, this method + * divides it out before returning the value. If the alpha value is + * 0, the blue value is 0. + * @param pixel the specified pixel + * @return the value of the blue component of the specified pixel. + */ + public abstract int getBlue(int pixel); + + /** + * Returns the alpha component for the specified pixel, scaled + * from 0 to 255. The pixel value is specified as an int. + * An IllegalArgumentException is thrown if pixel + * values for this ColorModel are not conveniently + * representable as a single int. + * @param pixel the specified pixel + * @return the value of alpha component of the specified pixel. + */ + public abstract int getAlpha(int pixel); + + /** + * Returns the color/alpha components of the pixel in the default + * RGB color model format. A color conversion is done if necessary. + * The pixel value is specified as an int. + * An IllegalArgumentException thrown if pixel values + * for this ColorModel are not conveniently representable + * as a single int. The returned value is in a non + * pre-multiplied format. For example, if the alpha is premultiplied, + * this method divides it out of the color components. If the alpha + * value is 0, the color values are 0. + * @param pixel the specified pixel + * @return the RGB value of the color/alpha components of the + * specified pixel. + * @see ColorModel#getRGBdefault + */ + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24) + | (getRed(pixel) << 16) + | (getGreen(pixel) << 8) + | (getBlue(pixel) << 0); + } + + /** + * Returns the red color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A + * color conversion is done if necessary. The pixel value is + * specified by an array of data elements of type transferType passed + * in as an object reference. The returned value is a non + * pre-multiplied value. For example, if alpha is premultiplied, + * this method divides it out before returning + * the value. If the alpha value is 0, the red value is 0. + * If inData is not a primitive array of type + * transferType, a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * inData is not large enough to hold a pixel value for + * this ColorModel. + * If this transferType is not supported, a + * UnsupportedOperationException will be + * thrown. Since + * ColorModel is an abstract class, any instance + * must be an instance of a subclass. Subclasses inherit the + * implementation of this method and if they don't override it, this + * method throws an exception if the subclass uses a + * transferType other than + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT. + * @param inData an array of pixel values + * @return the value of the red component of the specified pixel. + * @throws ClassCastException if inData + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * inData is not large enough to hold a pixel value + * for this ColorModel + * @throws UnsupportedOperationException if this + * tranferType is not supported by this + * ColorModel + */ + public int getRed(Object inData) { + int pixel=0,length=0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])inData; + pixel = bdata[0] & 0xff; + length = bdata.length; + break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + length = sdata.length; + break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])inData; + pixel = idata[0]; + length = idata.length; + break; + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + transferType); + } + if (length == 1) { + return getRed(pixel); + } + else { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + } + + /** + * Returns the green color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A + * color conversion is done if necessary. The pixel value is + * specified by an array of data elements of type transferType passed + * in as an object reference. The returned value will be a non + * pre-multiplied value. For example, if the alpha is premultiplied, + * this method divides it out before returning the value. If the + * alpha value is 0, the green value is 0. If inData is + * not a primitive array of type transferType, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * inData is not large enough to hold a pixel value for + * this ColorModel. + * If this transferType is not supported, a + * UnsupportedOperationException will be + * thrown. Since + * ColorModel is an abstract class, any instance + * must be an instance of a subclass. Subclasses inherit the + * implementation of this method and if they don't override it, this + * method throws an exception if the subclass uses a + * transferType other than + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT. + * @param inData an array of pixel values + * @return the value of the green component of the specified pixel. + * @throws ClassCastException if inData + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * inData is not large enough to hold a pixel value + * for this ColorModel + * @throws UnsupportedOperationException if this + * tranferType is not supported by this + * ColorModel + */ + public int getGreen(Object inData) { + int pixel=0,length=0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])inData; + pixel = bdata[0] & 0xff; + length = bdata.length; + break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + length = sdata.length; + break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])inData; + pixel = idata[0]; + length = idata.length; + break; + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + transferType); + } + if (length == 1) { + return getGreen(pixel); + } + else { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + } + + /** + * Returns the blue color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A + * color conversion is done if necessary. The pixel value is + * specified by an array of data elements of type transferType passed + * in as an object reference. The returned value is a non + * pre-multiplied value. For example, if the alpha is premultiplied, + * this method divides it out before returning the value. If the + * alpha value is 0, the blue value will be 0. If + * inData is not a primitive array of type transferType, + * a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is + * thrown if inData is not large enough to hold a pixel + * value for this ColorModel. + * If this transferType is not supported, a + * UnsupportedOperationException will be + * thrown. Since + * ColorModel is an abstract class, any instance + * must be an instance of a subclass. Subclasses inherit the + * implementation of this method and if they don't override it, this + * method throws an exception if the subclass uses a + * transferType other than + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT. + * @param inData an array of pixel values + * @return the value of the blue component of the specified pixel. + * @throws ClassCastException if inData + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * inData is not large enough to hold a pixel value + * for this ColorModel + * @throws UnsupportedOperationException if this + * tranferType is not supported by this + * ColorModel + */ + public int getBlue(Object inData) { + int pixel=0,length=0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])inData; + pixel = bdata[0] & 0xff; + length = bdata.length; + break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + length = sdata.length; + break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])inData; + pixel = idata[0]; + length = idata.length; + break; + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + transferType); + } + if (length == 1) { + return getBlue(pixel); + } + else { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + } + + /** + * Returns the alpha component for the specified pixel, scaled + * from 0 to 255. The pixel value is specified by an array of data + * elements of type transferType passed in as an object reference. + * If inData is not a primitive array of type transferType, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * inData is not large enough to hold a pixel value for + * this ColorModel. + * If this transferType is not supported, a + * UnsupportedOperationException will be + * thrown. Since + * ColorModel is an abstract class, any instance + * must be an instance of a subclass. Subclasses inherit the + * implementation of this method and if they don't override it, this + * method throws an exception if the subclass uses a + * transferType other than + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT. + * @param inData the specified pixel + * @return the alpha component of the specified pixel, scaled from + * 0 to 255. + * @throws ClassCastException if inData + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * inData is not large enough to hold a pixel value + * for this ColorModel + * @throws UnsupportedOperationException if this + * tranferType is not supported by this + * ColorModel + */ + public int getAlpha(Object inData) { + int pixel=0,length=0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])inData; + pixel = bdata[0] & 0xff; + length = bdata.length; + break; + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])inData; + pixel = sdata[0] & 0xffff; + length = sdata.length; + break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])inData; + pixel = idata[0]; + length = idata.length; + break; + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + transferType); + } + if (length == 1) { + return getAlpha(pixel); + } + else { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + } + + /** + * Returns the color/alpha components for the specified pixel in the + * default RGB color model format. A color conversion is done if + * necessary. The pixel value is specified by an array of data + * elements of type transferType passed in as an object reference. + * If inData is not a primitive array of type transferType, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is + * thrown if inData is not large enough to hold a pixel + * value for this ColorModel. + * The returned value will be in a non pre-multiplied format, i.e. if + * the alpha is premultiplied, this method will divide it out of the + * color components (if the alpha value is 0, the color values will be 0). + * @param inData the specified pixel + * @return the color and alpha components of the specified pixel. + * @see ColorModel#getRGBdefault + */ + public int getRGB(Object inData) { + return (getAlpha(inData) << 24) + | (getRed(inData) << 16) + | (getGreen(inData) << 8) + | (getBlue(inData) << 0); + } + + /** + * 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} method of + * a {@link WritableRaster} object. If the pixel variable is + * null, a new array will be allocated. If + * pixel is not + * null, it must be a primitive array of type + * transferType; otherwise, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * pixel is + * not large enough to hold a pixel value for this + * ColorModel. The pixel array is returned. + * If this transferType is not supported, a + * UnsupportedOperationException will be + * thrown. Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @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 + * ColorModel. + * @throws ClassCastException if pixel + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * pixel is not large enough to hold a pixel value + * for this ColorModel + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + * @see WritableRaster#setDataElements + * @see SampleModel#setDataElements + */ + public Object getDataElements(int rgb, Object pixel) { + throw new UnsupportedOperationException + ("This method is not supported by this color model."); + } + + /** + * Returns an array of unnormalized color/alpha components given a pixel + * in this ColorModel. The pixel value is specified as + * an int. An IllegalArgumentException + * will be thrown if pixel values for this ColorModel are + * not conveniently representable as a single int or if + * color component values for this ColorModel are not + * conveniently representable in the unnormalized form. + * For example, this method can be used to retrieve the + * components for a specific pixel value in a + * DirectColorModel. If the components array is + * null, a new array will be allocated. The + * components array will be returned. Color/alpha components are + * stored in the components array starting at offset + * (even if the array is allocated by this method). An + * ArrayIndexOutOfBoundsException is thrown if the + * components array is not null and is not large + * enough to hold all the color and alpha components (starting at offset). + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @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 components 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. + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + */ + public int[] getComponents(int pixel, int[] components, int offset) { + throw new UnsupportedOperationException + ("This method is not supported by this color model."); + } + + /** + * Returns an array of unnormalized color/alpha components given a pixel + * in this ColorModel. The pixel value is specified by + * an array of data elements of type transferType passed in as an + * object reference. If pixel is not a primitive array + * of type transferType, a ClassCastException is thrown. + * An IllegalArgumentException will be thrown if color + * component values for this ColorModel are not + * conveniently representable in the unnormalized form. + * An ArrayIndexOutOfBoundsException is + * thrown if pixel is not large enough to hold a pixel + * value for this ColorModel. + * This method can be used to retrieve the components for a specific + * pixel value in any ColorModel. If the components + * array is null, a new array will be allocated. The + * components array will be returned. Color/alpha components are + * stored in the components array starting at + * offset (even if the array is allocated by this + * method). An ArrayIndexOutOfBoundsException + * is thrown if the components array is not null and is + * not large enough to hold all the color and alpha components + * (starting at offset). + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @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 components 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 UnsupportedOperationException if this + * method is not supported by this ColorModel + */ + public int[] getComponents(Object pixel, int[] components, int offset) { + throw new UnsupportedOperationException + ("This method is not supported by this color model."); + } + + /** + * Returns an array of all of the color/alpha components in unnormalized + * form, given a normalized component array. Unnormalized components + * are unsigned integral values between 0 and 2n - 1, where + * n is the number of bits for a particular component. Normalized + * components are float values between a per component minimum and + * maximum specified by the ColorSpace object for this + * ColorModel. An IllegalArgumentException + * will be thrown if color component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. If the + * components array is null, a new array + * will be allocated. The components array will + * be returned. Color/alpha components are stored in the + * components array starting at offset (even + * if the array is allocated by this method). An + * ArrayIndexOutOfBoundsException is thrown if the + * components array is not null and is not + * large enough to hold all the color and alpha + * components (starting at offset). An + * IllegalArgumentException is thrown if the + * normComponents array is not large enough to hold + * all the color and alpha components starting at + * normOffset. + * @param normComponents an array containing normalized components + * @param normOffset the offset into the normComponents + * array at which to start retrieving normalized components + * @param components an array that receives the components from + * normComponents + * @param offset the index into components at which to + * begin storing normalized components from + * normComponents + * @return an array containing unnormalized color and alpha + * components. + * @throws IllegalArgumentException If the component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. + * @throws IllegalArgumentException if the length of + * normComponents minus normOffset + * is less than numComponents + * @throws UnsupportedOperationException if the + * constructor of this ColorModel called the + * super(bits) constructor, but did not + * override this method. See the constructor, + * {@link #ColorModel(int)}. + */ + public int[] getUnnormalizedComponents(float[] normComponents, + int normOffset, + int[] components, int offset) { + // Make sure that someone isn't using a custom color model + // that called the super(bits) constructor. + if (colorSpace == null) { + throw new UnsupportedOperationException("This method is not supported "+ + "by this color model."); + } + + if (nBits == null) { + throw new UnsupportedOperationException ("This method is not supported. "+ + "Unable to determine #bits per "+ + "component."); + } + if ((normComponents.length - normOffset) < numComponents) { + throw new + IllegalArgumentException( + "Incorrect number of components. Expecting "+ + numComponents); + } + + if (components == null) { + components = new int[offset+numComponents]; + } + + if (supportsAlpha && isAlphaPremultiplied) { + float normAlpha = normComponents[normOffset+numColorComponents]; + for (int i=0; i < numColorComponents; i++) { + components[offset+i] = (int) (normComponents[normOffset+i] + * ((1<n - 1, where + * n is the number of bits for a particular component. Normalized + * components are float values between a per component minimum and + * maximum specified by the ColorSpace object for this + * ColorModel. An IllegalArgumentException + * will be thrown if color component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. If the + * normComponents array is null, a new array + * will be allocated. The normComponents array + * will be returned. Color/alpha components are stored in the + * normComponents array starting at + * normOffset (even if the array is allocated by this + * method). An ArrayIndexOutOfBoundsException is thrown + * if the normComponents array is not null + * and is not large enough to hold all the color and alpha components + * (starting at normOffset). An + * IllegalArgumentException is thrown if the + * components array is not large enough to hold all the + * color and alpha components starting at offset. + *

+ * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. The default implementation + * of this method in this abstract class assumes that component values + * for this class are conveniently representable in the unnormalized + * form. Therefore, subclasses which may + * have instances which do not support the unnormalized form must + * override this method. + * @param components an array containing unnormalized components + * @param offset the offset into the components array at + * which to start retrieving unnormalized components + * @param normComponents an array that receives the normalized components + * @param normOffset the index into normComponents at + * which to begin storing normalized components + * @return an array containing normalized color and alpha + * components. + * @throws IllegalArgumentException If the component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. + * @throws UnsupportedOperationException if the + * constructor of this ColorModel called the + * super(bits) constructor, but did not + * override this method. See the constructor, + * {@link #ColorModel(int)}. + * @throws UnsupportedOperationException if this method is unable + * to determine the number of bits per component + */ + public float[] getNormalizedComponents(int[] components, int offset, + float[] normComponents, + int normOffset) { + // Make sure that someone isn't using a custom color model + // that called the super(bits) constructor. + if (colorSpace == null) { + throw new UnsupportedOperationException("This method is not supported by "+ + "this color model."); + } + if (nBits == null) { + throw new UnsupportedOperationException ("This method is not supported. "+ + "Unable to determine #bits per "+ + "component."); + } + + if ((components.length - offset) < numComponents) { + throw new + IllegalArgumentException( + "Incorrect number of components. Expecting "+ + numComponents); + } + + if (normComponents == null) { + normComponents = new float[numComponents+normOffset]; + } + + if (supportsAlpha && isAlphaPremultiplied) { + // Normalized coordinates are non premultiplied + float normAlpha = (float)components[offset+numColorComponents]; + normAlpha /= (float) ((1<int in this + * ColorModel, given an array of unnormalized color/alpha + * components. This method will throw an + * IllegalArgumentException if component values for this + * ColorModel are not conveniently representable as a + * single int or if color component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. An + * ArrayIndexOutOfBoundsException is thrown if the + * components array is not large enough to hold all the + * color and alpha components (starting at offset). + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param components an array of unnormalized color and alpha + * components + * @param offset the index into components at which to + * begin retrieving the color and alpha components + * @return an int pixel value in this + * ColorModel corresponding to the specified components. + * @throws IllegalArgumentException if + * pixel values for this ColorModel are not + * conveniently representable as a single int + * @throws IllegalArgumentException if + * component values for this ColorModel are not + * conveniently representable in the unnormalized form + * @throws ArrayIndexOutOfBoundsException if + * the components array is not large enough to + * hold all of the color and alpha components starting at + * offset + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + */ + public int getDataElement(int[] components, int offset) { + throw new UnsupportedOperationException("This method is not supported "+ + "by this color model."); + } + + /** + * Returns a data element array representation of a pixel in this + * ColorModel, given an array of unnormalized color/alpha + * components. This array can then be passed to the + * setDataElements method of a WritableRaster + * object. This method will throw an IllegalArgumentException + * if color component values for this ColorModel are not + * conveniently representable in the unnormalized form. + * An ArrayIndexOutOfBoundsException is thrown + * if the components array is not large enough to hold + * all the color and alpha components (starting at + * offset). If the obj variable is + * null, a new array will be allocated. If + * obj is not null, it must be a primitive + * array of type transferType; otherwise, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * obj is not large enough to hold a pixel value for this + * ColorModel. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param components an array of unnormalized color and alpha + * components + * @param offset the index into components at which to + * begin retrieving color and alpha components + * @param obj the Object representing an array of color + * and alpha components + * @return an Object representing an array of color and + * alpha components. + * @throws ClassCastException if obj + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * obj is not large enough to hold a pixel value + * for this ColorModel or the components + * array is not large enough to hold all of the color and alpha + * components starting at offset + * @throws IllegalArgumentException if + * component values for this ColorModel are not + * conveniently representable in the unnormalized form + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + * @see WritableRaster#setDataElements + * @see SampleModel#setDataElements + */ + public Object getDataElements(int[] components, int offset, Object obj) { + throw new UnsupportedOperationException("This method has not been implemented "+ + "for this color model."); + } + + /** + * Returns a pixel value represented as an int in this + * ColorModel, given an array of normalized color/alpha + * components. This method will throw an + * IllegalArgumentException if pixel values for this + * ColorModel are not conveniently representable as a + * single int. An + * ArrayIndexOutOfBoundsException is thrown if the + * normComponents array is not large enough to hold all the + * color and alpha components (starting at normOffset). + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. The default implementation + * of this method in this abstract class first converts from the + * normalized form to the unnormalized form and then calls + * getDataElement(int[], int). Subclasses which may + * have instances which do not support the unnormalized form must + * override this method. + * @param normComponents an array of normalized color and alpha + * components + * @param normOffset the index into normComponents at which to + * begin retrieving the color and alpha components + * @return an int pixel value in this + * ColorModel corresponding to the specified components. + * @throws IllegalArgumentException if + * pixel values for this ColorModel are not + * conveniently representable as a single int + * @throws ArrayIndexOutOfBoundsException if + * the normComponents array is not large enough to + * hold all of the color and alpha components starting at + * normOffset + * @since 1.4 + */ + public int getDataElement(float[] normComponents, int normOffset) { + int components[] = getUnnormalizedComponents(normComponents, + normOffset, null, 0); + return getDataElement(components, 0); + } + + /** + * Returns a data element array representation of a pixel in this + * ColorModel, given an array of normalized color/alpha + * components. This array can then be passed to the + * setDataElements method of a WritableRaster + * object. An ArrayIndexOutOfBoundsException is thrown + * if the normComponents array is not large enough to hold + * all the color and alpha components (starting at + * normOffset). If the obj variable is + * null, a new array will be allocated. If + * obj is not null, it must be a primitive + * array of type transferType; otherwise, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * obj is not large enough to hold a pixel value for this + * ColorModel. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. The default implementation + * of this method in this abstract class first converts from the + * normalized form to the unnormalized form and then calls + * getDataElement(int[], int, Object). Subclasses which may + * have instances which do not support the unnormalized form must + * override this method. + * @param normComponents an array of normalized color and alpha + * components + * @param normOffset the index into normComponents at which to + * begin retrieving color and alpha components + * @param obj a primitive data array to hold the returned pixel + * @return an Object which is a primitive data array + * representation of a pixel + * @throws ClassCastException if obj + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * obj is not large enough to hold a pixel value + * for this ColorModel or the normComponents + * array is not large enough to hold all of the color and alpha + * components starting at normOffset + * @see WritableRaster#setDataElements + * @see SampleModel#setDataElements + * @since 1.4 + */ + public Object getDataElements(float[] normComponents, int normOffset, + Object obj) { + int components[] = getUnnormalizedComponents(normComponents, + normOffset, null, 0); + return getDataElements(components, 0, obj); + } + + /** + * Returns an array of all of the color/alpha components in normalized + * form, given a pixel in this ColorModel. The pixel + * value is specified by an array of data elements of type transferType + * passed in as an object reference. If pixel is not a primitive array + * of type transferType, a ClassCastException is thrown. + * An ArrayIndexOutOfBoundsException is thrown if + * pixel is not large enough to hold a pixel value for this + * ColorModel. + * Normalized components are float values between a per component minimum + * and maximum specified by the ColorSpace object for this + * ColorModel. If the + * normComponents array is null, a new array + * will be allocated. The normComponents array + * will be returned. Color/alpha components are stored in the + * normComponents array starting at + * normOffset (even if the array is allocated by this + * method). An ArrayIndexOutOfBoundsException is thrown + * if the normComponents array is not null + * and is not large enough to hold all the color and alpha components + * (starting at normOffset). + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. The default implementation + * of this method in this abstract class first retrieves color and alpha + * components in the unnormalized form using + * getComponents(Object, int[], int) and then calls + * getNormalizedComponents(int[], int, float[], int). + * Subclasses which may + * have instances which do not support the unnormalized form must + * override this method. + * @param pixel the specified pixel + * @param normComponents an array to receive the normalized components + * @param normOffset the offset into the normComponents + * array at which to start storing normalized components + * @return an array containing normalized color and alpha + * components. + * @throws ClassCastException if pixel is not a primitive + * array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * normComponents is not large enough to hold all + * color and alpha components starting at normOffset + * @throws ArrayIndexOutOfBoundsException if + * pixel is not large enough to hold a pixel + * value for this ColorModel. + * @throws UnsupportedOperationException if the + * constructor of this ColorModel called the + * super(bits) constructor, but did not + * override this method. See the constructor, + * {@link #ColorModel(int)}. + * @throws UnsupportedOperationException if this method is unable + * to determine the number of bits per component + * @since 1.4 + */ + public float[] getNormalizedComponents(Object pixel, + float[] normComponents, + int normOffset) { + int components[] = getComponents(pixel, null, 0); + return getNormalizedComponents(components, 0, + normComponents, normOffset); + } + + /** + * Tests if the specified Object is an instance of + * ColorModel and if it equals this + * ColorModel. + * @param obj the Object to test for equality + * @return true if the specified Object + * is an instance of ColorModel and equals this + * ColorModel; false otherwise. + */ + public boolean equals(Object obj) { + if (!(obj instanceof ColorModel)) { + return false; + } + ColorModel cm = (ColorModel) obj; + + if (this == cm) { + return true; + } + if (supportsAlpha != cm.hasAlpha() || + isAlphaPremultiplied != cm.isAlphaPremultiplied() || + pixel_bits != cm.getPixelSize() || + transparency != cm.getTransparency() || + numComponents != cm.getNumComponents()) + { + return false; + } + + int[] nb = cm.getComponentSize(); + + if ((nBits != null) && (nb != null)) { + for (int i = 0; i < numComponents; i++) { + if (nBits[i] != nb[i]) { + return false; + } + } + } else { + return ((nBits == null) && (nb == null)); + } + + return true; + } + + /** + * Returns the hash code for this ColorModel. + * + * @return a hash code for this ColorModel. + */ + public int hashCode() { + + int result = 0; + + result = (supportsAlpha ? 2 : 3) + + (isAlphaPremultiplied ? 4 : 5) + + pixel_bits * 6 + + transparency * 7 + + numComponents * 8; + + if (nBits != null) { + for (int i = 0; i < numComponents; i++) { + result = result + nBits[i] * (i + 9); + } + } + + return result; + } + + /** + * Returns the ColorSpace associated with this + * ColorModel. + * @return the ColorSpace of this + * ColorModel. + */ + final public ColorSpace getColorSpace() { + return colorSpace; + } + + /** + * Forces the raster data to match the state specified in the + * isAlphaPremultiplied variable, assuming the data is + * currently correctly described by this ColorModel. It + * may multiply or divide the color raster data by alpha, or do + * nothing if the data is in the correct state. If the data needs to + * be coerced, this method will also return an instance of this + * ColorModel with the isAlphaPremultiplied + * flag set appropriately. This method will throw a + * UnsupportedOperationException if it is not supported + * by this ColorModel. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param raster the WritableRaster data + * @param isAlphaPremultiplied true if the alpha is + * premultiplied; false otherwise + * @return a ColorModel object that represents the + * coerced data. + */ + public ColorModel coerceData (WritableRaster raster, + boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + + /** + * Returns true if raster is compatible + * with this ColorModel and false if it is + * not. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param raster the {@link Raster} object to test for compatibility + * @return true if raster is compatible + * with this ColorModel. + * @throws UnsupportedOperationException if this + * method has not been implemented for this + * ColorModel + */ + public boolean isCompatibleRaster(Raster raster) { + throw new UnsupportedOperationException( + "This method has not been implemented for this ColorModel."); + } + + /** + * Creates a WritableRaster with the specified width and + * height that has a data layout (SampleModel) compatible + * with this ColorModel. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param w the width to apply to the new WritableRaster + * @param h the height to apply to the new WritableRaster + * @return a WritableRaster object with the specified + * width and height. + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + * @see WritableRaster + * @see SampleModel + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + + /** + * Creates a SampleModel with the specified width and + * height that has a data layout compatible with this + * ColorModel. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param w the width to apply to the new SampleModel + * @param h the height to apply to the new SampleModel + * @return a SampleModel object with the specified + * width and height. + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + * @see SampleModel + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + + /** Checks if the SampleModel is compatible with this + * ColorModel. + * Since ColorModel is an abstract class, + * any instance is an instance of a subclass. Subclasses must + * override this method since the implementation in this abstract + * class throws an UnsupportedOperationException. + * @param sm the specified SampleModel + * @return true if the specified SampleModel + * is compatible with this ColorModel; false + * otherwise. + * @throws UnsupportedOperationException if this + * method is not supported by this ColorModel + * @see SampleModel + */ + public boolean isCompatibleSampleModel(SampleModel sm) { + throw new UnsupportedOperationException + ("This method is not supported by this color model"); + } + + /** + * Disposes of system resources associated with this + * ColorModel once this ColorModel is no + * longer referenced. + */ + public void finalize() { + } + + + /** + * Returns a Raster representing the alpha channel of an + * image, extracted from the input Raster, provided that + * pixel values of this ColorModel represent color and + * alpha information as separate spatial bands (e.g. + * {@link ComponentColorModel} and DirectColorModel). + * This method assumes that Raster objects associated + * with such a ColorModel store the alpha band, if + * present, as the last band of image data. Returns null + * if there is no separate spatial alpha channel associated with this + * ColorModel. If this is an + * IndexColorModel which has alpha in the lookup table, + * this method will return null since + * there is no spatially discrete alpha channel. + * This method will create a new Raster (but will share + * the data array). + * Since ColorModel is an abstract class, any instance + * is an instance of a subclass. Subclasses must override this + * method to get any behavior other than returning null + * because the implementation in this abstract class returns + * null. + * @param raster the specified Raster + * @return a Raster representing the alpha channel of + * an image, obtained from the specified Raster. + */ + public WritableRaster getAlphaRaster(WritableRaster raster) { + return null; + } + + /** + * Returns the String representation of the contents of + * this ColorModelobject. + * @return a String representing the contents of this + * ColorModel object. + */ + public String toString() { + return new String("ColorModel: #pixelBits = "+pixel_bits + + " numComponents = "+numComponents + + " color space = "+colorSpace + + " transparency = "+transparency + + " has alpha = "+supportsAlpha + + " isAlphaPre = "+isAlphaPremultiplied + ); + } + + static int getDefaultTransferType(int pixel_bits) { + if (pixel_bits <= 8) { + return DataBuffer.TYPE_BYTE; + } else if (pixel_bits <= 16) { + return DataBuffer.TYPE_USHORT; + } else if (pixel_bits <= 32) { + return DataBuffer.TYPE_INT; + } else { + return DataBuffer.TYPE_UNDEFINED; + } + } + + static byte[] l8Tos8 = null; // 8-bit linear to 8-bit non-linear sRGB LUT + static byte[] s8Tol8 = null; // 8-bit non-linear sRGB to 8-bit linear LUT + static byte[] l16Tos8 = null; // 16-bit linear to 8-bit non-linear sRGB LUT + static short[] s8Tol16 = null; // 8-bit non-linear sRGB to 16-bit linear LUT + + // Maps to hold LUTs for grayscale conversions + static Map g8Tos8Map = null; // 8-bit gray values to 8-bit sRGB values + static Map lg16Toog8Map = null; // 16-bit linear to 8-bit "other" gray + static Map g16Tos8Map = null; // 16-bit gray values to 8-bit sRGB values + static Map lg16Toog16Map = null; // 16-bit linear to 16-bit "other" gray + + static boolean isLinearRGBspace(ColorSpace cs) { + // Note: CMM.LINEAR_RGBspace will be null if the linear + // RGB space has not been created yet. + return (cs == CMSManager.LINEAR_RGBspace); + } + + static boolean isLinearGRAYspace(ColorSpace cs) { + // Note: CMM.GRAYspace will be null if the linear + // gray space has not been created yet. + return (cs == CMSManager.GRAYspace); + } + + static byte[] getLinearRGB8TosRGB8LUT() { + if (l8Tos8 == null) { + l8Tos8 = new byte[256]; + float input, output; + // algorithm for linear RGB to nonlinear sRGB conversion + // is from the IEC 61966-2-1 International Standard, + // Colour Management - Default RGB colour space - sRGB, + // First Edition, 1999-10, + // avaiable for order at http://www.iec.ch + for (int i = 0; i <= 255; i++) { + input = ((float) i) / 255.0f; + if (input <= 0.0031308f) { + output = input * 12.92f; + } else { + output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) + - 0.055f; + } + l8Tos8[i] = (byte) Math.round(output * 255.0f); + } + } + return l8Tos8; + } + + static byte[] getsRGB8ToLinearRGB8LUT() { + if (s8Tol8 == null) { + s8Tol8 = new byte[256]; + float input, output; + // algorithm from IEC 61966-2-1 International Standard + for (int i = 0; i <= 255; i++) { + input = ((float) i) / 255.0f; + if (input <= 0.04045f) { + output = input / 12.92f; + } else { + output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); + } + s8Tol8[i] = (byte) Math.round(output * 255.0f); + } + } + return s8Tol8; + } + + static byte[] getLinearRGB16TosRGB8LUT() { + if (l16Tos8 == null) { + l16Tos8 = new byte[65536]; + float input, output; + // algorithm from IEC 61966-2-1 International Standard + for (int i = 0; i <= 65535; i++) { + input = ((float) i) / 65535.0f; + if (input <= 0.0031308f) { + output = input * 12.92f; + } else { + output = 1.055f * ((float) Math.pow(input, (1.0 / 2.4))) + - 0.055f; + } + l16Tos8[i] = (byte) Math.round(output * 255.0f); + } + } + return l16Tos8; + } + + static short[] getsRGB8ToLinearRGB16LUT() { + if (s8Tol16 == null) { + s8Tol16 = new short[256]; + float input, output; + // algorithm from IEC 61966-2-1 International Standard + for (int i = 0; i <= 255; i++) { + input = ((float) i) / 255.0f; + if (input <= 0.04045f) { + output = input / 12.92f; + } else { + output = (float) Math.pow((input + 0.055f) / 1.055f, 2.4); + } + s8Tol16[i] = (short) Math.round(output * 65535.0f); + } + } + return s8Tol16; + } + + /* + * Return a byte LUT that converts 8-bit gray values in the grayCS + * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut + * is the byte array returned by this method and sval = lut[gval], + * then the sRGB triple (sval,sval,sval) is the best match to gval. + * Cache references to any computed LUT in a Map. + */ + static byte[] getGray8TosRGB8LUT(ICC_ColorSpace grayCS) { + if (isLinearGRAYspace(grayCS)) { + return getLinearRGB8TosRGB8LUT(); + } + if (g8Tos8Map != null) { + byte[] g8Tos8LUT = (byte []) g8Tos8Map.get(grayCS); + if (g8Tos8LUT != null) { + return g8Tos8LUT; + } + } + byte[] g8Tos8LUT = new byte[256]; + for (int i = 0; i <= 255; i++) { + g8Tos8LUT[i] = (byte) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace srgbCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); + transformList[0] = mdl.createTransform( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform( + srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform(transformList); + byte[] tmp = t.colorConvert(g8Tos8LUT, null); + for (int i = 0, j= 2; i <= 255; i++, j += 3) { + // All three components of tmp should be equal, since + // the input color space to colorConvert is a gray scale + // space. However, there are slight anomalies in the results. + // Copy tmp starting at index 2, since colorConvert seems + // to be slightly more accurate for the third component! + g8Tos8LUT[i] = tmp[j]; + } + if (g8Tos8Map == null) { + g8Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + g8Tos8Map.put(grayCS, g8Tos8LUT); + return g8Tos8LUT; + } + + /* + * Return a byte LUT that converts 16-bit gray values in the CS_GRAY + * linear gray ColorSpace to the appropriate 8-bit value in the + * grayCS ColorSpace. Cache references to any computed LUT in a Map. + */ + static byte[] getLinearGray16ToOtherGray8LUT(ICC_ColorSpace grayCS) { + if (lg16Toog8Map != null) { + byte[] lg16Toog8LUT = (byte []) lg16Toog8Map.get(grayCS); + if (lg16Toog8LUT != null) { + return lg16Toog8LUT; + } + } + short[] tmp = new short[65536]; + for (int i = 0; i <= 65535; i++) { + tmp[i] = (short) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace lgCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); + transformList[0] = mdl.createTransform ( + lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform ( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform(transformList); + tmp = t.colorConvert(tmp, null); + byte[] lg16Toog8LUT = new byte[65536]; + for (int i = 0; i <= 65535; i++) { + // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) + lg16Toog8LUT[i] = + (byte) (((float) (tmp[i] & 0xffff)) * (1.0f /257.0f) + 0.5f); + } + if (lg16Toog8Map == null) { + lg16Toog8Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + lg16Toog8Map.put(grayCS, lg16Toog8LUT); + return lg16Toog8LUT; + } + + /* + * Return a byte LUT that converts 16-bit gray values in the grayCS + * ColorSpace to the appropriate 8-bit sRGB value. I.e., if lut + * is the byte array returned by this method and sval = lut[gval], + * then the sRGB triple (sval,sval,sval) is the best match to gval. + * Cache references to any computed LUT in a Map. + */ + static byte[] getGray16TosRGB8LUT(ICC_ColorSpace grayCS) { + if (isLinearGRAYspace(grayCS)) { + return getLinearRGB16TosRGB8LUT(); + } + if (g16Tos8Map != null) { + byte[] g16Tos8LUT = (byte []) g16Tos8Map.get(grayCS); + if (g16Tos8LUT != null) { + return g16Tos8LUT; + } + } + short[] tmp = new short[65536]; + for (int i = 0; i <= 65535; i++) { + tmp[i] = (short) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace srgbCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_sRGB); + transformList[0] = mdl.createTransform ( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform ( + srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform(transformList); + tmp = t.colorConvert(tmp, null); + byte[] g16Tos8LUT = new byte[65536]; + for (int i = 0, j= 2; i <= 65535; i++, j += 3) { + // All three components of tmp should be equal, since + // the input color space to colorConvert is a gray scale + // space. However, there are slight anomalies in the results. + // Copy tmp starting at index 2, since colorConvert seems + // to be slightly more accurate for the third component! + + // scale unsigned short (0 - 65535) to unsigned byte (0 - 255) + g16Tos8LUT[i] = + (byte) (((float) (tmp[j] & 0xffff)) * (1.0f /257.0f) + 0.5f); + } + if (g16Tos8Map == null) { + g16Tos8Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + g16Tos8Map.put(grayCS, g16Tos8LUT); + return g16Tos8LUT; + } + + /* + * Return a short LUT that converts 16-bit gray values in the CS_GRAY + * linear gray ColorSpace to the appropriate 16-bit value in the + * grayCS ColorSpace. Cache references to any computed LUT in a Map. + */ + static short[] getLinearGray16ToOtherGray16LUT(ICC_ColorSpace grayCS) { + if (lg16Toog16Map != null) { + short[] lg16Toog16LUT = (short []) lg16Toog16Map.get(grayCS); + if (lg16Toog16LUT != null) { + return lg16Toog16LUT; + } + } + short[] tmp = new short[65536]; + for (int i = 0; i <= 65535; i++) { + tmp[i] = (short) i; + } + ColorTransform[] transformList = new ColorTransform[2]; + PCMM mdl = CMSManager.getModule(); + ICC_ColorSpace lgCS = + (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_GRAY); + transformList[0] = mdl.createTransform ( + lgCS.getProfile(), ColorTransform.Any, ColorTransform.In); + transformList[1] = mdl.createTransform( + grayCS.getProfile(), ColorTransform.Any, ColorTransform.Out); + ColorTransform t = mdl.createTransform( + transformList); + short[] lg16Toog16LUT = t.colorConvert(tmp, null); + if (lg16Toog16Map == null) { + lg16Toog16Map = Collections.synchronizedMap(new WeakHashMap(2)); + } + lg16Toog16Map.put(grayCS, lg16Toog16LUT); + return lg16Toog16LUT; + } + +} diff --git a/openjdk/java/awt/image/ComponentColorModel.java b/openjdk/java/awt/image/ComponentColorModel.java new file mode 100644 index 00000000..9b934a97 --- /dev/null +++ b/openjdk/java/awt/image/ComponentColorModel.java @@ -0,0 +1,2862 @@ +/* + * Copyright 1997-2003 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.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; + +/** + * A ColorModel class that works with pixel values that + * represent color and alpha information as separate samples and that + * store each sample in a separate data element. This class can be + * used with an arbitrary ColorSpace. The number of + * color samples in the pixel values must be same as the number of + * color components in the ColorSpace. There may be a + * single alpha sample. + *

+ * For those methods that use + * a primitive array pixel representation of type transferType, + * the array length is the same as the number of color and alpha samples. + * Color samples are stored first in the array followed by the alpha + * sample, if present. The order of the color samples is specified + * by the ColorSpace. Typically, this order reflects the + * name of the color space type. For example, for TYPE_RGB, + * index 0 corresponds to red, index 1 to green, and index 2 to blue. + *

+ * The translation from pixel sample values to color/alpha components for + * display or processing purposes is based on a one-to-one correspondence of + * samples to components. + * Depending on the transfer type used to create an instance of + * ComponentColorModel, the pixel sample values + * represented by that instance may be signed or unsigned and may + * be of integral type or float or double (see below for details). + * The translation from sample values to normalized color/alpha components + * must follow certain rules. For float and double samples, the translation + * is an identity, i.e. normalized component values are equal to the + * corresponding sample values. For integral samples, the translation + * should be only a simple scale and offset, where the scale and offset + * constants may be different for each component. The result of + * applying the scale and offset constants is a set of color/alpha + * component values, which are guaranteed to fall within a certain + * range. Typically, the range for a color component will be the range + * defined by the getMinValue and getMaxValue + * methods of the ColorSpace class. The range for an + * alpha component should be 0.0 to 1.0. + *

+ * Instances of ComponentColorModel created with transfer types + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * and DataBuffer.TYPE_INT have pixel sample values which + * are treated as unsigned integral values. + * The number of bits in a color or alpha sample of a pixel value might not + * be the same as the number of bits for the corresponding color or alpha + * sample passed to the + * ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int) + * constructor. In + * that case, this class assumes that the least significant n bits of a sample + * value hold the component value, where n is the number of significant bits + * for the component passed to the constructor. It also assumes that + * any higher-order bits in a sample value are zero. Thus, sample values + * range from 0 to 2n - 1. This class maps these sample values + * to normalized color component values such that 0 maps to the value + * obtained from the ColorSpace's getMinValue + * method for each component and 2n - 1 maps to the value + * obtained from getMaxValue. To create a + * ComponentColorModel with a different color sample mapping + * requires subclassing this class and overriding the + * getNormalizedComponents(Object, float[], int) method. + * The mapping for an alpha sample always maps 0 to 0.0 and + * 2n - 1 to 1.0. + *

+ * For instances with unsigned sample values, + * the unnormalized color/alpha component representation is only + * supported if two conditions hold. First, sample value value 0 must + * map to normalized component value 0.0 and sample value 2n - 1 + * to 1.0. Second the min/max range of all color components of the + * ColorSpace must be 0.0 to 1.0. In this case, the + * component representation is the n least + * significant bits of the corresponding sample. Thus each component is + * an unsigned integral value between 0 and 2n - 1, where + * n is the number of significant bits for a particular component. + * If these conditions are not met, any method taking an unnormalized + * component argument will throw an IllegalArgumentException. + *

+ * Instances of ComponentColorModel created with transfer types + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, and + * DataBuffer.TYPE_DOUBLE have pixel sample values which + * are treated as signed short, float, or double values. + * Such instances do not support the unnormalized color/alpha component + * representation, so any methods taking such a representation as an argument + * will throw an IllegalArgumentException when called on one + * of these instances. The normalized component values of instances + * of this class have a range which depends on the transfer + * type as follows: for float samples, the full range of the float data + * type; for double samples, the full range of the float data type + * (resulting from casting double to float); for short samples, + * from approximately -maxVal to +maxVal, where maxVal is the per + * component maximum value for the ColorSpace + * (-32767 maps to -maxVal, 0 maps to 0.0, and 32767 maps + * to +maxVal). A subclass may override the scaling for short sample + * values to normalized component values by overriding the + * getNormalizedComponents(Object, float[], int) method. + * For float and double samples, the normalized component values are + * taken to be equal to the corresponding sample values, and subclasses + * should not attempt to add any non-identity scaling for these transfer + * types. + *

+ * Instances of ComponentColorModel created with transfer types + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, and + * DataBuffer.TYPE_DOUBLE + * use all the bits of all sample values. Thus all color/alpha components + * have 16 bits when using DataBuffer.TYPE_SHORT, 32 bits when + * using DataBuffer.TYPE_FLOAT, and 64 bits when using + * DataBuffer.TYPE_DOUBLE. When the + * ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int) + * form of constructor is used with one of these transfer types, the + * bits array argument is ignored. + *

+ * It is possible to have color/alpha sample values + * which cannot be reasonably interpreted as component values for rendering. + * This can happen when ComponentColorModel is subclassed to + * override the mapping of unsigned sample values to normalized color + * component values or when signed sample values outside a certain range + * are used. (As an example, specifying an alpha component as a signed + * short value outside the range 0 to 32767, normalized range 0.0 to 1.0, can + * lead to unexpected results.) It is the + * responsibility of applications to appropriately scale pixel data before + * rendering such that color components fall within the normalized range + * of the ColorSpace (obtained using the getMinValue + * and getMaxValue methods of the ColorSpace class) + * and the alpha component is between 0.0 and 1.0. If color or alpha + * component values fall outside these ranges, rendering results are + * indeterminate. + *

+ * Methods that use a single int pixel representation throw + * an IllegalArgumentException, unless the number of components + * for the ComponentColorModel is one and the component + * value is unsigned -- in other words, a single color component using + * a transfer type of DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + * and no alpha. + *

+ * A ComponentColorModel can be used in conjunction with a + * ComponentSampleModel, a BandedSampleModel, + * or a PixelInterleavedSampleModel to construct a + * BufferedImage. + * + * @see ColorModel + * @see ColorSpace + * @see ComponentSampleModel + * @see BandedSampleModel + * @see PixelInterleavedSampleModel + * @see BufferedImage + * + */ +public class ComponentColorModel extends ColorModel { + + /** + * signed is true for short, + * float, and double transfer types; it + * is false for byte, ushort, + * and int transfer types. + */ + private boolean signed; // true for transfer types short, float, double + // false for byte, ushort, int + private boolean is_sRGB_stdScale; + private boolean is_LinearRGB_stdScale; + private boolean is_LinearGray_stdScale; + private boolean is_ICCGray_stdScale; + private byte[] tosRGB8LUT; + private byte[] fromsRGB8LUT8; + private short[] fromsRGB8LUT16; + private byte[] fromLinearGray16ToOtherGray8LUT; + private short[] fromLinearGray16ToOtherGray16LUT; + private boolean needScaleInit; + private boolean noUnnorm; + private boolean nonStdScale; + private float[] min; + private float[] diffMinMax; + private float[] compOffset; + private float[] compScale; + + /** + * Constructs a ComponentColorModel from the specified + * parameters. Color components will be in the specified + * ColorSpace. The supported transfer types are + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * and DataBuffer.TYPE_DOUBLE. + * If not null, the bits array specifies the + * number of significant bits per color and alpha component and its + * length should be at least the number of components in the + * ColorSpace if there is no alpha + * information in the pixel values, or one more than this number if + * there is alpha information. When the transferType is + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE the bits array + * argument is ignored. hasAlpha indicates whether alpha + * information is present. If hasAlpha is true, then + * the boolean isAlphaPremultiplied + * specifies how to interpret color and alpha samples in pixel values. + * If the boolean is true, color samples are assumed to have been + * multiplied by the alpha sample. The transparency + * specifies what alpha values can be represented by this color model. + * The acceptable transparency values are + * OPAQUE, BITMASK or TRANSLUCENT. + * The transferType is the type of primitive array used + * to represent pixel values. + * + * @param colorSpace The ColorSpace associated + * with this color model. + * @param bits The number of significant bits per component. + * May be null, in which case all bits of all + * component samples will be significant. + * Ignored if transferType is one of + * DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE, + * in which case all bits of all component + * samples will be significant. + * @param hasAlpha If true, this color model supports alpha. + * @param isAlphaPremultiplied If true, alpha is premultiplied. + * @param transparency Specifies what alpha values can be represented + * by this color model. + * @param transferType Specifies the type of primitive array used to + * represent pixel values. + * + * @throws IllegalArgumentException If the bits array + * argument is not null, its length is less than the number of + * color and alpha components, and transferType is one of + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT. + * @throws IllegalArgumentException If transferType is not one of + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @see ColorSpace + * @see java.awt.Transparency + */ + public ComponentColorModel (ColorSpace colorSpace, + int[] bits, + boolean hasAlpha, + boolean isAlphaPremultiplied, + int transparency, + int transferType) { + super (bitsHelper(transferType, colorSpace, hasAlpha), + bitsArrayHelper(bits, transferType, colorSpace, hasAlpha), + colorSpace, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + switch(transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + signed = false; + needScaleInit = true; + break; + case DataBuffer.TYPE_SHORT: + signed = true; + needScaleInit = true; + break; + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + signed = true; + needScaleInit = false; + noUnnorm = true; + nonStdScale = false; + break; + default: + throw new IllegalArgumentException("This constructor is not "+ + "compatible with transferType " + transferType); + } + } + + /** + * Constructs a ComponentColorModel from the specified + * parameters. Color components will be in the specified + * ColorSpace. The supported transfer types are + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * and DataBuffer.TYPE_DOUBLE. The number of significant + * bits per color and alpha component will be 8, 16, 32, 16, 32, or 64, + * respectively. The number of color components will be the + * number of components in the ColorSpace. There will be + * an alpha component if hasAlpha is true. + * If hasAlpha is true, then + * the boolean isAlphaPremultiplied + * specifies how to interpret color and alpha samples in pixel values. + * If the boolean is true, color samples are assumed to have been + * multiplied by the alpha sample. The transparency + * specifies what alpha values can be represented by this color model. + * The acceptable transparency values are + * OPAQUE, BITMASK or TRANSLUCENT. + * The transferType is the type of primitive array used + * to represent pixel values. + * + * @param colorSpace The ColorSpace associated + * with this color model. + * @param hasAlpha If true, this color model supports alpha. + * @param isAlphaPremultiplied If true, alpha is premultiplied. + * @param transparency Specifies what alpha values can be represented + * by this color model. + * @param transferType Specifies the type of primitive array used to + * represent pixel values. + * + * @throws IllegalArgumentException If transferType is not one of + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @see ColorSpace + * @see java.awt.Transparency + * @since 1.4 + */ + public ComponentColorModel (ColorSpace colorSpace, + boolean hasAlpha, + boolean isAlphaPremultiplied, + int transparency, + int transferType) { + this(colorSpace, null, hasAlpha, isAlphaPremultiplied, + transparency, transferType); + } + + private static int bitsHelper(int transferType, + ColorSpace colorSpace, + boolean hasAlpha) { + int numBits = DataBuffer.getDataTypeSize(transferType); + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + ++numComponents; + } + return numBits * numComponents; + } + + private static int[] bitsArrayHelper(int[] origBits, + int transferType, + ColorSpace colorSpace, + boolean hasAlpha) { + switch(transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + if (origBits != null) { + return origBits; + } + break; + default: + break; + } + int numBits = DataBuffer.getDataTypeSize(transferType); + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + ++numComponents; + } + int[] bits = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bits[i] = numBits; + } + return bits; + } + + private void initScale() { + // This method is called the first time any method which uses + // pixel sample value to color component value scaling information + // is called if the transferType supports non-standard scaling + // as defined above (byte, ushort, int, and short), unless the + // method is getNormalizedComponents(Object, float[], int) (that + // method must be overridden to use non-standard scaling). This + // method also sets up the noUnnorm boolean variable for these + // transferTypes. After this method is called, the nonStdScale + // variable will be true if getNormalizedComponents() maps a + // sample value of 0 to anything other than 0.0f OR maps a + // sample value of 2^^n - 1 (2^^15 - 1 for short transferType) + // to anything other than 1.0f. Note that this can be independent + // of the colorSpace min/max component values, if the + // getNormalizedComponents() method has been overridden for some + // reason, e.g. to provide greater dynamic range in the sample + // values than in the color component values. Unfortunately, + // this method can't be called at construction time, since a + // subclass may still have uninitialized state that would cause + // getNormalizedComponents() to return an incorrect result. + needScaleInit = false; // only needs to called once + if (nonStdScale || signed) { + // The unnormalized form is only supported for unsigned + // transferTypes and when the ColorSpace min/max values + // are 0.0/1.0. When this method is called nonStdScale is + // true if the latter condition does not hold. In addition, + // the unnormalized form requires that the full range of + // the pixel sample values map to the full 0.0 - 1.0 range + // of color component values. That condition is checked + // later in this method. + noUnnorm = true; + } else { + noUnnorm = false; + } + float[] lowVal, highVal; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + { + byte[] bpixel = new byte[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + bpixel[i] = 0; + } + if (supportsAlpha) { + bpixel[numColorComponents] = + (byte) ((1 << nBits[numColorComponents]) - 1); + } + lowVal = getNormalizedComponents(bpixel, null, 0); + for (int i = 0; i < numColorComponents; i++) { + bpixel[i] = (byte) ((1 << nBits[i]) - 1); + } + highVal = getNormalizedComponents(bpixel, null, 0); + } + break; + case DataBuffer.TYPE_USHORT: + { + short[] uspixel = new short[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + uspixel[i] = 0; + } + if (supportsAlpha) { + uspixel[numColorComponents] = + (short) ((1 << nBits[numColorComponents]) - 1); + } + lowVal = getNormalizedComponents(uspixel, null, 0); + for (int i = 0; i < numColorComponents; i++) { + uspixel[i] = (short) ((1 << nBits[i]) - 1); + } + highVal = getNormalizedComponents(uspixel, null, 0); + } + break; + case DataBuffer.TYPE_INT: + { + int[] ipixel = new int[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + ipixel[i] = 0; + } + if (supportsAlpha) { + ipixel[numColorComponents] = + ((1 << nBits[numColorComponents]) - 1); + } + lowVal = getNormalizedComponents(ipixel, null, 0); + for (int i = 0; i < numColorComponents; i++) { + ipixel[i] = ((1 << nBits[i]) - 1); + } + highVal = getNormalizedComponents(ipixel, null, 0); + } + break; + case DataBuffer.TYPE_SHORT: + { + short[] spixel = new short[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + spixel[i] = 0; + } + if (supportsAlpha) { + spixel[numColorComponents] = 32767; + } + lowVal = getNormalizedComponents(spixel, null, 0); + for (int i = 0; i < numColorComponents; i++) { + spixel[i] = 32767; + } + highVal = getNormalizedComponents(spixel, null, 0); + } + break; + default: + lowVal = highVal = null; // to keep the compiler from complaining + break; + } + nonStdScale = false; + for (int i = 0; i < numColorComponents; i++) { + if ((lowVal[i] != 0.0f) || (highVal[i] != 1.0f)) { + nonStdScale = true; + break; + } + } + if (nonStdScale) { + noUnnorm = true; + is_sRGB_stdScale = false; + is_LinearRGB_stdScale = false; + is_LinearGray_stdScale = false; + is_ICCGray_stdScale = false; + compOffset = new float[numColorComponents]; + compScale = new float[numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + compOffset[i] = lowVal[i]; + compScale[i] = 1.0f / (highVal[i] - lowVal[i]); + } + } + } + + private int getRGBComponent(int pixel, int idx) { + if (numComponents > 1) { + throw new + IllegalArgumentException("More than one component per pixel"); + } + if (signed) { + throw new + IllegalArgumentException("Component value is signed"); + } + if (needScaleInit) { + initScale(); + } + // Since there is only 1 component, there is no alpha + + // Normalize the pixel in order to convert it + Object opixel = null; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + { + byte[] bpixel = { (byte) pixel }; + opixel = bpixel; + } + break; + case DataBuffer.TYPE_USHORT: + { + short[] spixel = { (short) pixel }; + opixel = spixel; + } + break; + case DataBuffer.TYPE_INT: + { + int[] ipixel = { pixel }; + opixel = ipixel; + } + break; + } + float[] norm = getNormalizedComponents(opixel, null, 0); + float[] rgb = colorSpace.toRGB(norm); + + return (int) (rgb[idx] * 255.0f + 0.5f); + } + + /** + * Returns the red color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion + * is done if necessary. The pixel value is specified as an int. + * The returned value will be a non pre-multiplied value. + * If the alpha is premultiplied, this method divides + * it out before returning the value (if the alpha value is 0, + * the red value will be 0). + * + * @param pixel The pixel from which you want to get the red color component. + * + * @return The red color component for the specified pixel, as an int. + * + * @throws IllegalArgumentException If there is more than + * one component in this ColorModel. + * @throws IllegalArgumentException If the component value for this + * ColorModel is signed + */ + public int getRed(int pixel) { + return getRGBComponent(pixel, 0); + } + + /** + * Returns the green color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion + * is done if necessary. The pixel value is specified as an int. + * The returned value will be a non + * pre-multiplied value. If the alpha is premultiplied, this method + * divides it out before returning the value (if the alpha value is 0, + * the green value will be 0). + * + * @param pixel The pixel from which you want to get the green color component. + * + * @return The green color component for the specified pixel, as an int. + * + * @throws IllegalArgumentException If there is more than + * one component in this ColorModel. + * @throws IllegalArgumentException If the component value for this + * ColorModel is signed + */ + public int getGreen(int pixel) { + return getRGBComponent(pixel, 1); + } + + /** + * Returns the blue color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion + * is done if necessary. The pixel value is specified as an int. + * The returned value will be a non + * pre-multiplied value. If the alpha is premultiplied, this method + * divides it out before returning the value (if the alpha value is 0, + * the blue value will be 0). + * + * @param pixel The pixel from which you want to get the blue color component. + * + * @return The blue color component for the specified pixel, as an int. + * + * @throws IllegalArgumentException If there is more than + * one component in this ColorModel. + * @throws IllegalArgumentException If the component value for this + * ColorModel is signed + */ + public int getBlue(int pixel) { + return getRGBComponent(pixel, 2); + } + + /** + * Returns the alpha component for the specified pixel, scaled + * from 0 to 255. The pixel value is specified as an int. + * + * @param pixel The pixel from which you want to get the alpha component. + * + * @return The alpha component for the specified pixel, as an int. + * + * @throws IllegalArgumentException If there is more than + * one component in this ColorModel. + * @throws IllegalArgumentException If the component value for this + * ColorModel is signed + */ + public int getAlpha(int pixel) { + if (supportsAlpha == false) { + return 255; + } + if (numComponents > 1) { + throw new + IllegalArgumentException("More than one component per pixel"); + } + if (signed) { + throw new + IllegalArgumentException("Component value is signed"); + } + + return (int) ((((float) pixel) / ((1<ColorModel. + * @throws IllegalArgumentException If the component value for this + * ColorModel is signed + */ + public int getRGB(int pixel) { + if (numComponents > 1) { + throw new + IllegalArgumentException("More than one component per pixel"); + } + if (signed) { + throw new + IllegalArgumentException("Component value is signed"); + } + + return (getAlpha(pixel) << 24) + | (getRed(pixel) << 16) + | (getGreen(pixel) << 8) + | (getBlue(pixel) << 0); + } + + private int extractComponent(Object inData, int idx, int precision) { + // Extract component idx from inData. The precision argument + // should be either 8 or 16. If it's 8, this method will return + // an 8-bit value. If it's 16, this method will return a 16-bit + // value for transferTypes other than TYPE_BYTE. For TYPE_BYTE, + // an 8-bit value will be returned. + + // This method maps the input value corresponding to a + // normalized ColorSpace component value of 0.0 to 0, and the + // input value corresponding to a normalized ColorSpace + // component value of 1.0 to 2^n - 1 (where n is 8 or 16), so + // it is appropriate only for ColorSpaces with min/max component + // values of 0.0/1.0. This will be true for sRGB, the built-in + // Linear RGB and Linear Gray spaces, and any other ICC grayscale + // spaces for which we have precomputed LUTs. + + boolean needAlpha = (supportsAlpha && isAlphaPremultiplied); + int alp = 0; + int comp; + int mask = (1 << nBits[idx]) - 1; + + switch (transferType) { + // Note: we do no clamping of the pixel data here - we + // assume that the data is scaled properly + case DataBuffer.TYPE_SHORT: { + short sdata[] = (short[]) inData; + float scalefactor = (float) ((1 << precision) - 1); + if (needAlpha) { + short s = sdata[numColorComponents]; + if (s != (short) 0) { + return (int) ((((float) sdata[idx]) / + ((float) s)) * scalefactor + 0.5f); + } else { + return 0; + } + } else { + return (int) ((sdata[idx] / 32767.0f) * scalefactor + 0.5f); + } + } + case DataBuffer.TYPE_FLOAT: { + float fdata[] = (float[]) inData; + float scalefactor = (float) ((1 << precision) - 1); + if (needAlpha) { + float f = fdata[numColorComponents]; + if (f != 0.0f) { + return (int) (((fdata[idx] / f) * scalefactor) + 0.5f); + } else { + return 0; + } + } else { + return (int) (fdata[idx] * scalefactor + 0.5f); + } + } + case DataBuffer.TYPE_DOUBLE: { + double ddata[] = (double[]) inData; + double scalefactor = (double) ((1 << precision) - 1); + if (needAlpha) { + double d = ddata[numColorComponents]; + if (d != 0.0) { + return (int) (((ddata[idx] / d) * scalefactor) + 0.5); + } else { + return 0; + } + } else { + return (int) (ddata[idx] * scalefactor + 0.5); + } + } + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])inData; + comp = bdata[idx] & mask; + precision = 8; + if (needAlpha) { + alp = bdata[numColorComponents] & mask; + } + break; + case DataBuffer.TYPE_USHORT: + short usdata[] = (short[])inData; + comp = usdata[idx] & mask; + if (needAlpha) { + alp = usdata[numColorComponents] & mask; + } + break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])inData; + comp = idata[idx]; + if (needAlpha) { + alp = idata[numColorComponents]; + } + break; + default: + throw new + UnsupportedOperationException("This method has not "+ + "been implemented for transferType " + transferType); + } + if (needAlpha) { + if (alp != 0) { + float scalefactor = (float) ((1 << precision) - 1); + float fcomp = ((float) comp) / ((float)mask); + float invalp = ((float) ((1<pixel value is specified by an array + * of data elements of type transferType passed in as an object + * reference. The returned value will be a non pre-multiplied value. If the + * alpha is premultiplied, this method divides it out before returning + * the value (if the alpha value is 0, the red value will be 0). Since + * ComponentColorModel 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 inData The pixel from which you want to get the red color component, + * specified by an array of data elements of type transferType. + * + * @return The red color component for the specified pixel, as an int. + * + * @throws ClassCastException If inData is not a primitive array + * of type transferType. + * @throws ArrayIndexOutOfBoundsException if inData is not + * large enough to hold a pixel value for this + * ColorModel. + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + */ + public int getRed(Object inData) { + return getRGBComponent(inData, 0); + } + + + /** + * Returns the green color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. + * A color conversion is done if necessary. The pixel value + * is specified by an array of data elements of type transferType + * passed in as an object reference. The returned value is a non pre-multiplied + * value. If the alpha is premultiplied, this method divides it out before + * returning the value (if the alpha value is 0, the green value will be 0). + * Since ComponentColorModel 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 inData The pixel from which you want to get the green color component, + * specified by an array of data elements of type transferType. + * + * @return The green color component for the specified pixel, as an int. + * + * @throws ClassCastException If inData is not a primitive array + * of type transferType. + * @throws ArrayIndexOutOfBoundsException if inData is not + * large enough to hold a pixel value for this + * ColorModel. + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + */ + public int getGreen(Object inData) { + return getRGBComponent(inData, 1); + } + + + /** + * Returns the blue color component for the specified pixel, scaled + * from 0 to 255 in the default RGB ColorSpace, sRGB. + * A color conversion is done if necessary. The pixel value is + * specified by an array of data elements of type transferType + * passed in as an object reference. The returned value is a non pre-multiplied + * value. If the alpha is premultiplied, this method divides it out before + * returning the value (if the alpha value is 0, the blue value will be 0). + * Since ComponentColorModel 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 inData The pixel from which you want to get the blue color component, + * specified by an array of data elements of type transferType. + * + * @return The blue color component for the specified pixel, as an int. + * + * @throws ClassCastException If inData is not a primitive array + * of type transferType. + * @throws ArrayIndexOutOfBoundsException if inData is not + * large enough to hold a pixel value for this + * ColorModel. + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + */ + public int getBlue(Object inData) { + return getRGBComponent(inData, 2); + } + + /** + * Returns the alpha component for the specified pixel, scaled from + * 0 to 255. The pixel value is specified by an array of data + * elements of type transferType passed in as an + * object reference. Since ComponentColorModel 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 inData The pixel from which you want to get the alpha component, + * specified by an array of data elements of type transferType. + * + * @return The alpha component for the specified pixel, as an int. + * + * @throws ClassCastException If inData is not a primitive array + * of type transferType. + * @throws ArrayIndexOutOfBoundsException if inData is not + * large enough to hold a pixel value for this + * ColorModel. + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + */ + public int getAlpha(Object inData) { + if (supportsAlpha == false) { + return 255; + } + + int alpha = 0; + int aIdx = numColorComponents; + int mask = (1 << nBits[aIdx]) - 1; + + switch (transferType) { + case DataBuffer.TYPE_SHORT: + short sdata[] = (short[])inData; + alpha = (int) ((sdata[aIdx] / 32767.0f) * 255.0f + 0.5f); + return alpha; + case DataBuffer.TYPE_FLOAT: + float fdata[] = (float[])inData; + alpha = (int) (fdata[aIdx] * 255.0f + 0.5f); + return alpha; + case DataBuffer.TYPE_DOUBLE: + double ddata[] = (double[])inData; + alpha = (int) (ddata[aIdx] * 255.0 + 0.5); + return alpha; + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])inData; + alpha = bdata[aIdx] & mask; + break; + case DataBuffer.TYPE_USHORT: + short usdata[] = (short[])inData; + alpha = usdata[aIdx] & mask; + break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])inData; + alpha = idata[aIdx]; + break; + default: + throw new + UnsupportedOperationException("This method has not "+ + "been implemented for transferType " + transferType); + } + + if (nBits[aIdx] == 8) { + return alpha; + } else { + return (int) + ((((float) alpha) / ((float) ((1 << nBits[aIdx]) - 1))) * + 255.0f + 0.5f); + } + } + + /** + * Returns the color/alpha components for the specified pixel in the + * default RGB color model format. A color conversion is done if + * necessary. The pixel value is specified by an + * array of data elements of type transferType passed + * in as an object reference. + * The returned value is in a non pre-multiplied format. If + * the alpha is premultiplied, this method divides it out of the + * color components (if the alpha value is 0, the color values will be 0). + * Since ComponentColorModel 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 inData The pixel from which you want to get the color/alpha components, + * specified by an array of data elements of type transferType. + * + * @return The color/alpha components for the specified pixel, as an int. + * + * @throws ClassCastException If inData is not a primitive array + * of type transferType. + * @throws ArrayIndexOutOfBoundsException if inData is not + * large enough to hold a pixel value for this + * ColorModel. + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * @see ColorModel#getRGBdefault + */ + public int getRGB(Object inData) { + if (needScaleInit) { + initScale(); + } + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + return (getAlpha(inData) << 24) + | (getRed(inData) << 16) + | (getGreen(inData) << 8) + | (getBlue(inData)); + } else if (colorSpaceType == ColorSpace.TYPE_GRAY) { + int gray = getRed(inData); // Red sRGB component should equal + // green and blue components + return (getAlpha(inData) << 24) + | (gray << 16) + | (gray << 8) + | gray; + } + float[] norm = getNormalizedComponents(inData, null, 0); + // Note that getNormalizedComponents returns non-premult values + float[] rgb = colorSpace.toRGB(norm); + return (getAlpha(inData) << 24) + | (((int) (rgb[0] * 255.0f + 0.5f)) << 16) + | (((int) (rgb[1] * 255.0f + 0.5f)) << 8) + | (((int) (rgb[2] * 255.0f + 0.5f)) << 0); + } + + /** + * 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 setDataElements + * method of a WritableRaster object. If the + * pixel + * parameter is null, a new array is allocated. Since + * ComponentColorModel 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 rgb the integer representation of the pixel in the RGB + * color model + * @param pixel the specified pixel + * @return The data element array representation of a pixel + * in this ColorModel. + * @throws ClassCastException If pixel is not null and + * is not a primitive array of type transferType. + * @throws ArrayIndexOutOfBoundsException If pixel is + * not large enough to hold a pixel value for this + * ColorModel. + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @see WritableRaster#setDataElements + * @see SampleModel#setDataElements + */ + public Object getDataElements(int rgb, Object pixel) { + // REMIND: Use rendering hints? + + int red, grn, blu, alp; + red = (rgb>>16) & 0xff; + grn = (rgb>>8) & 0xff; + blu = rgb & 0xff; + + if (needScaleInit) { + initScale(); + } + if (signed) { + // Handle SHORT, FLOAT, & DOUBLE here + + switch(transferType) { + case DataBuffer.TYPE_SHORT: + { + short sdata[]; + if (pixel == null) { + sdata = new short[numComponents]; + } else { + sdata = (short[])pixel; + } + float factor; + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + factor = 32767.0f / 255.0f; + if (is_LinearRGB_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + factor = 32767.0f / 65535.0f; + } + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + sdata[3] = + (short) (alp * (32767.0f / 255.0f) + 0.5f); + if (isAlphaPremultiplied) { + factor = alp * factor * (1.0f / 255.0f); + } + } + sdata[0] = (short) (red * factor + 0.5f); + sdata[1] = (short) (grn * factor + 0.5f); + sdata[2] = (short) (blu * factor + 0.5f); + } else if (is_LinearGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + float gray = ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu)) / 65535.0f; + factor = 32767.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + sdata[1] = + (short) (alp * (32767.0f / 255.0f) + 0.5f); + if (isAlphaPremultiplied) { + factor = alp * factor * (1.0f / 255.0f); + } + } + sdata[0] = (short) (gray * factor + 0.5f); + } else if (is_ICCGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + int gray = (int) ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu) + 0.5f); + gray = fromLinearGray16ToOtherGray16LUT[gray] & 0xffff; + factor = 32767.0f / 65535.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + sdata[1] = + (short) (alp * (32767.0f / 255.0f) + 0.5f); + if (isAlphaPremultiplied) { + factor = alp * factor * (1.0f / 255.0f); + } + } + sdata[0] = (short) (gray * factor + 0.5f); + } else { + factor = 1.0f / 255.0f; + float norm[] = new float[3]; + norm[0] = red * factor; + norm[1] = grn * factor; + norm[2] = blu * factor; + norm = colorSpace.fromRGB(norm); + if (nonStdScale) { + for (int i = 0; i < numColorComponents; i++) { + norm[i] = (norm[i] - compOffset[i]) * + compScale[i]; + // REMIND: need to analyze whether this + // clamping is necessary + if (norm[i] < 0.0f) { + norm[i] = 0.0f; + } + if (norm[i] > 1.0f) { + norm[i] = 1.0f; + } + } + } + factor = 32767.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + sdata[numColorComponents] = + (short) (alp * (32767.0f / 255.0f) + 0.5f); + if (isAlphaPremultiplied) { + factor *= alp * (1.0f / 255.0f); + } + } + for (int i = 0; i < numColorComponents; i++) { + sdata[i] = (short) (norm[i] * factor + 0.5f); + } + } + return sdata; + } + case DataBuffer.TYPE_FLOAT: + { + float fdata[]; + if (pixel == null) { + fdata = new float[numComponents]; + } else { + fdata = (float[])pixel; + } + float factor; + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + if (is_LinearRGB_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + factor = 1.0f / 65535.0f; + } else { + factor = 1.0f / 255.0f; + } + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[3] = alp * (1.0f / 255.0f); + if (isAlphaPremultiplied) { + factor *= fdata[3]; + } + } + fdata[0] = red * factor; + fdata[1] = grn * factor; + fdata[2] = blu * factor; + } else if (is_LinearGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + fdata[0] = ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu)) / 65535.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[1] = alp * (1.0f / 255.0f); + if (isAlphaPremultiplied) { + fdata[0] *= fdata[1]; + } + } + } else if (is_ICCGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + int gray = (int) ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu) + 0.5f); + fdata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & + 0xffff) / 65535.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[1] = alp * (1.0f / 255.0f); + if (isAlphaPremultiplied) { + fdata[0] *= fdata[1]; + } + } + } else { + float norm[] = new float[3]; + factor = 1.0f / 255.0f; + norm[0] = red * factor; + norm[1] = grn * factor; + norm[2] = blu * factor; + norm = colorSpace.fromRGB(norm); + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + fdata[numColorComponents] = alp * factor; + if (isAlphaPremultiplied) { + factor *= alp; + for (int i = 0; i < numColorComponents; i++) { + norm[i] *= factor; + } + } + } + for (int i = 0; i < numColorComponents; i++) { + fdata[i] = norm[i]; + } + } + return fdata; + } + case DataBuffer.TYPE_DOUBLE: + { + double ddata[]; + if (pixel == null) { + ddata = new double[numComponents]; + } else { + ddata = (double[])pixel; + } + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + double factor; + if (is_LinearRGB_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + factor = 1.0 / 65535.0; + } else { + factor = 1.0 / 255.0; + } + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[3] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + factor *= ddata[3]; + } + } + ddata[0] = red * factor; + ddata[1] = grn * factor; + ddata[2] = blu * factor; + } else if (is_LinearGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + ddata[0] = ((0.2125 * red) + + (0.7154 * grn) + + (0.0721 * blu)) / 65535.0; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[1] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + ddata[0] *= ddata[1]; + } + } + } else if (is_ICCGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + int gray = (int) ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu) + 0.5f); + ddata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & + 0xffff) / 65535.0; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[1] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + ddata[0] *= ddata[1]; + } + } + } else { + float factor = 1.0f / 255.0f; + float norm[] = new float[3]; + norm[0] = red * factor; + norm[1] = grn * factor; + norm[2] = blu * factor; + norm = colorSpace.fromRGB(norm); + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + ddata[numColorComponents] = alp * (1.0 / 255.0); + if (isAlphaPremultiplied) { + factor *= alp; + for (int i = 0; i < numColorComponents; i++) { + norm[i] *= factor; + } + } + } + for (int i = 0; i < numColorComponents; i++) { + ddata[i] = norm[i]; + } + } + return ddata; + } + } + } + + // Handle BYTE, USHORT, & INT here + //REMIND: maybe more efficient not to use int array for + //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT + int intpixel[]; + if (transferType == DataBuffer.TYPE_INT && + pixel != null) { + intpixel = (int[])pixel; + } else { + intpixel = new int[numComponents]; + } + + if (is_sRGB_stdScale || is_LinearRGB_stdScale) { + int precision; + float factor; + if (is_LinearRGB_stdScale) { + if (transferType == DataBuffer.TYPE_BYTE) { + red = fromsRGB8LUT8[red] & 0xff; + grn = fromsRGB8LUT8[grn] & 0xff; + blu = fromsRGB8LUT8[blu] & 0xff; + precision = 8; + factor = 1.0f / 255.0f; + } else { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + precision = 16; + factor = 1.0f / 65535.0f; + } + } else { + precision = 8; + factor = 1.0f / 255.0f; + } + if (supportsAlpha) { + alp = (rgb>>24)&0xff; + if (nBits[3] == 8) { + intpixel[3] = alp; + } + else { + intpixel[3] = (int) + (alp * (1.0f / 255.0f) * ((1<>24) & 0xff; + if (nBits[1] == 8) { + intpixel[1] = alp; + } else { + intpixel[1] = (int) (alp * (1.0f / 255.0f) * + ((1 << nBits[1]) - 1) + 0.5f); + } + if (isAlphaPremultiplied) { + gray *= (alp * (1.0f / 255.0f)); + } + } + intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f); + } else if (is_ICCGray_stdScale) { + red = fromsRGB8LUT16[red] & 0xffff; + grn = fromsRGB8LUT16[grn] & 0xffff; + blu = fromsRGB8LUT16[blu] & 0xffff; + int gray16 = (int) ((0.2125f * red) + + (0.7154f * grn) + + (0.0721f * blu) + 0.5f); + float gray = (fromLinearGray16ToOtherGray16LUT[gray16] & + 0xffff) / 65535.0f; + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + if (nBits[1] == 8) { + intpixel[1] = alp; + } else { + intpixel[1] = (int) (alp * (1.0f / 255.0f) * + ((1 << nBits[1]) - 1) + 0.5f); + } + if (isAlphaPremultiplied) { + gray *= (alp * (1.0f / 255.0f)); + } + } + intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f); + } else { + // Need to convert the color + float[] norm = new float[3]; + float factor = 1.0f / 255.0f; + norm[0] = red * factor; + norm[1] = grn * factor; + norm[2] = blu * factor; + norm = colorSpace.fromRGB(norm); + if (nonStdScale) { + for (int i = 0; i < numColorComponents; i++) { + norm[i] = (norm[i] - compOffset[i]) * + compScale[i]; + // REMIND: need to analyze whether this + // clamping is necessary + if (norm[i] < 0.0f) { + norm[i] = 0.0f; + } + if (norm[i] > 1.0f) { + norm[i] = 1.0f; + } + } + } + if (supportsAlpha) { + alp = (rgb>>24) & 0xff; + if (nBits[numColorComponents] == 8) { + intpixel[numColorComponents] = alp; + } + else { + intpixel[numColorComponents] = + (int) (alp * factor * + ((1< 23) { + // fix 4412670 - for components of 24 or more bits + // some calculations done above with float precision + // may lose enough precision that the integer result + // overflows nBits, so we need to clamp. + for (int i = 0; i < numComponents; i++) { + if (intpixel[i] > ((1<ColorModel. + * An IllegalArgumentException is thrown if the component value for this + * ColorModel is not conveniently representable in the + * unnormalized form. Color/alpha components are stored + * in the components array starting at offset + * (even if the array is allocated by this method). + * + * @param pixel The pixel value specified as an integer. + * @param components An integer array in which to store the unnormalized + * color/alpha components. If the components array is null, + * a new array is allocated. + * @param offset An offset into the components array. + * + * @return The components array. + * + * @throws IllegalArgumentException If there is more than one + * component in this ColorModel. + * @throws IllegalArgumentException If this + * ColorModel does not support the unnormalized form + * @throws ArrayIndexOutOfBoundsException If the components + * array is not null and is not large enough to hold all the color and + * alpha components (starting at offset). + */ + public int[] getComponents(int pixel, int[] components, int offset) { + if (numComponents > 1) { + throw new + IllegalArgumentException("More than one component per pixel"); + } + if (needScaleInit) { + initScale(); + } + if (noUnnorm) { + throw new + IllegalArgumentException( + "This ColorModel does not support the unnormalized form"); + } + if (components == null) { + components = new int[offset+1]; + } + + components[offset+0] = (pixel & ((1<ColorModel. The pixel value is specified by an + * array of data elements of type transferType passed in as + * an object reference. + * An IllegalArgumentException is thrown if the component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. + * Color/alpha components are stored in the components array + * starting at offset (even if the array is allocated by + * this method). Since ComponentColorModel can be + * subclassed, subclasses inherit the + * implementation of this method and if they don't override it then + * this method might throw an exception if they use an unsupported + * transferType. + * + * @param pixel A pixel value specified by an array of data elements of + * type transferType. + * @param components An integer array in which to store the unnormalized + * color/alpha components. If the components array is null, + * a new array is allocated. + * @param offset An offset into the components array. + * + * @return The components array. + * + * @throws IllegalArgumentException If this + * ComponentColorModel does not support the unnormalized form + * @throws UnsupportedOperationException in some cases iff the + * transfer type of this ComponentColorModel + * is not one of the following transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * or DataBuffer.TYPE_INT. + * @throws ClassCastException If pixel is not a primitive + * array of type transferType. + * @throws IllegalArgumentException If the components array is + * not null and is not large enough to hold all the color and alpha + * components (starting at offset), or if pixel is not large + * enough to hold a pixel value for this ColorModel. + */ + public int[] getComponents(Object pixel, int[] components, int offset) { + int intpixel[]; + if (needScaleInit) { + initScale(); + } + if (noUnnorm) { + throw new + IllegalArgumentException( + "This ColorModel does not support the unnormalized form"); + } + if (pixel instanceof int[]) { + intpixel = (int[])pixel; + } else { + intpixel = DataBuffer.toIntArray(pixel); + if (intpixel == null) { + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + transferType); + } + } + if (intpixel.length < numComponents) { + throw new IllegalArgumentException + ("Length of pixel array < number of components in model"); + } + if (components == null) { + components = new int[offset+numComponents]; + } + else if ((components.length-offset) < numComponents) { + throw new IllegalArgumentException + ("Length of components array < number of components in model"); + } + System.arraycopy(intpixel, 0, components, offset, numComponents); + + return components; + } + + /** + * Returns an array of all of the color/alpha components in unnormalized + * form, given a normalized component array. Unnormalized components + * are unsigned integral values between 0 and 2n - 1, where + * n is the number of bits for a particular component. Normalized + * components are float values between a per component minimum and + * maximum specified by the ColorSpace object for this + * ColorModel. An IllegalArgumentException + * will be thrown if color component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. If the + * components array is null, a new array + * will be allocated. The components array will + * be returned. Color/alpha components are stored in the + * components array starting at offset (even + * if the array is allocated by this method). An + * ArrayIndexOutOfBoundsException is thrown if the + * components array is not null and is not + * large enough to hold all the color and alpha + * components (starting at offset). An + * IllegalArgumentException is thrown if the + * normComponents array is not large enough to hold + * all the color and alpha components starting at + * normOffset. + * @param normComponents an array containing normalized components + * @param normOffset the offset into the normComponents + * array at which to start retrieving normalized components + * @param components an array that receives the components from + * normComponents + * @param offset the index into components at which to + * begin storing normalized components from + * normComponents + * @return an array containing unnormalized color and alpha + * components. + * @throws IllegalArgumentException If this + * ComponentColorModel does not support the unnormalized form + * @throws IllegalArgumentException if the length of + * normComponents minus normOffset + * is less than numComponents + */ + public int[] getUnnormalizedComponents(float[] normComponents, + int normOffset, + int[] components, int offset) { + if (needScaleInit) { + initScale(); + } + if (noUnnorm) { + throw new + IllegalArgumentException( + "This ColorModel does not support the unnormalized form"); + } + return super.getUnnormalizedComponents(normComponents, normOffset, + components, offset); + } + + /** + * Returns an array of all of the color/alpha components in normalized + * form, given an unnormalized component array. Unnormalized components + * are unsigned integral values between 0 and 2n - 1, where + * n is the number of bits for a particular component. Normalized + * components are float values between a per component minimum and + * maximum specified by the ColorSpace object for this + * ColorModel. An IllegalArgumentException + * will be thrown if color component values for this + * ColorModel are not conveniently representable in the + * unnormalized form. If the + * normComponents array is null, a new array + * will be allocated. The normComponents array + * will be returned. Color/alpha components are stored in the + * normComponents array starting at + * normOffset (even if the array is allocated by this + * method). An ArrayIndexOutOfBoundsException is thrown + * if the normComponents array is not null + * and is not large enough to hold all the color and alpha components + * (starting at normOffset). An + * IllegalArgumentException is thrown if the + * components array is not large enough to hold all the + * color and alpha components starting at offset. + * @param components an array containing unnormalized components + * @param offset the offset into the components array at + * which to start retrieving unnormalized components + * @param normComponents an array that receives the normalized components + * @param normOffset the index into normComponents at + * which to begin storing normalized components + * @return an array containing normalized color and alpha + * components. + * @throws IllegalArgumentException If this + * ComponentColorModel does not support the unnormalized form + */ + public float[] getNormalizedComponents(int[] components, int offset, + float[] normComponents, + int normOffset) { + if (needScaleInit) { + initScale(); + } + if (noUnnorm) { + throw new + IllegalArgumentException( + "This ColorModel does not support the unnormalized form"); + } + return super.getNormalizedComponents(components, offset, + normComponents, normOffset); + } + + /** + * Returns a pixel value represented as an int in this ColorModel, + * given an array of unnormalized color/alpha components. + * + * @param components An array of unnormalized color/alpha components. + * @param offset An offset into the components array. + * + * @return A pixel value represented as an int. + * + * @throws IllegalArgumentException If there is more than one component + * in this ColorModel. + * @throws IllegalArgumentException If this + * ComponentColorModel does not support the unnormalized form + */ + public int getDataElement(int[] components, int offset) { + if (needScaleInit) { + initScale(); + } + if (numComponents == 1) { + if (noUnnorm) { + throw new + IllegalArgumentException( + "This ColorModel does not support the unnormalized form"); + } + return components[offset+0]; + } + throw new IllegalArgumentException("This model returns "+ + numComponents+ + " elements in the pixel array."); + } + + /** + * Returns a data element array representation of a pixel in this + * ColorModel, given an array of unnormalized color/alpha + * components. This array can then be passed to the setDataElements + * method of a WritableRaster object. + * + * @param components An array of unnormalized color/alpha components. + * @param offset The integer offset into the components array. + * @param obj The object in which to store the data element array + * representation of the pixel. If obj variable is null, + * a new array is allocated. If obj is not null, it must + * be a primitive array of type transferType. An + * ArrayIndexOutOfBoundsException is thrown if + * obj is not large enough to hold a pixel value + * for this ColorModel. Since + * ComponentColorModel 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. + * + * @return The data element array representation of a pixel + * in this ColorModel. + * + * @throws IllegalArgumentException If the components array + * is not large enough to hold all the color and alpha components + * (starting at offset). + * @throws ClassCastException If obj is not null and is not a + * primitive array of type transferType. + * @throws ArrayIndexOutOfBoundsException If obj is not large + * enough to hold a pixel value for this ColorModel. + * @throws IllegalArgumentException If this + * ComponentColorModel does not support the unnormalized form + * @throws UnsupportedOperationException If the transfer type of + * this ComponentColorModel + * is not one of the following transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * or DataBuffer.TYPE_INT. + * + * @see WritableRaster#setDataElements + * @see SampleModel#setDataElements + */ + public Object getDataElements(int[] components, int offset, Object obj) { + if (needScaleInit) { + initScale(); + } + if (noUnnorm) { + throw new + IllegalArgumentException( + "This ColorModel does not support the unnormalized form"); + } + if ((components.length-offset) < numComponents) { + throw new IllegalArgumentException("Component array too small"+ + " (should be "+numComponents); + } + switch(transferType) { + case DataBuffer.TYPE_INT: + { + int[] pixel; + if (obj == null) { + pixel = new int[numComponents]; + } + else { + pixel = (int[]) obj; + } + System.arraycopy(components, offset, pixel, 0, + numComponents); + return pixel; + } + + case DataBuffer.TYPE_BYTE: + { + byte[] pixel; + if (obj == null) { + pixel = new byte[numComponents]; + } + else { + pixel = (byte[]) obj; + } + for (int i=0; i < numComponents; i++) { + pixel[i] = (byte) (components[offset+i]&0xff); + } + return pixel; + } + + case DataBuffer.TYPE_USHORT: + { + short[] pixel; + if (obj == null) { + pixel = new short[numComponents]; + } + else { + pixel = (short[]) obj; + } + for (int i=0; i < numComponents; i++) { + pixel[i] = (short) (components[offset+i]&0xffff); + } + return pixel; + } + + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + + transferType); + } + } + + /** + * Returns a pixel value represented as an int in this + * ColorModel, given an array of normalized color/alpha + * components. This method will throw an + * IllegalArgumentException if pixel values for this + * ColorModel are not conveniently representable as a + * single int. An + * ArrayIndexOutOfBoundsException is thrown if the + * normComponents array is not large enough to hold all the + * color and alpha components (starting at normOffset). + * @param normComponents an array of normalized color and alpha + * components + * @param normOffset the index into normComponents at which to + * begin retrieving the color and alpha components + * @return an int pixel value in this + * ColorModel corresponding to the specified components. + * @throws IllegalArgumentException if + * pixel values for this ColorModel are not + * conveniently representable as a single int + * @throws ArrayIndexOutOfBoundsException if + * the normComponents array is not large enough to + * hold all of the color and alpha components starting at + * normOffset + * @since 1.4 + */ + public int getDataElement(float[] normComponents, int normOffset) { + if (numComponents > 1) { + throw new + IllegalArgumentException("More than one component per pixel"); + } + if (signed) { + throw new + IllegalArgumentException("Component value is signed"); + } + if (needScaleInit) { + initScale(); + } + Object pixel = getDataElements(normComponents, normOffset, null); + switch (transferType) { + case DataBuffer.TYPE_BYTE: + { + byte bpixel[] = (byte[]) pixel; + return bpixel[0] & 0xff; + } + case DataBuffer.TYPE_USHORT: + { + short[] uspixel = (short[]) pixel; + return uspixel[0] & 0xffff; + } + case DataBuffer.TYPE_INT: + { + int[] ipixel = (int[]) pixel; + return ipixel[0]; + } + default: + throw new UnsupportedOperationException("This method has not been " + + "implemented for transferType " + transferType); + } + } + + /** + * Returns a data element array representation of a pixel in this + * ColorModel, given an array of normalized color/alpha + * components. This array can then be passed to the + * setDataElements method of a WritableRaster + * object. An ArrayIndexOutOfBoundsException is thrown + * if the normComponents array is not large enough to hold + * all the color and alpha components (starting at + * normOffset). If the obj variable is + * null, a new array will be allocated. If + * obj is not null, it must be a primitive + * array of type transferType; otherwise, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if + * obj is not large enough to hold a pixel value for this + * ColorModel. + * @param normComponents an array of normalized color and alpha + * components + * @param normOffset the index into normComponents at which to + * begin retrieving color and alpha components + * @param obj a primitive data array to hold the returned pixel + * @return an Object which is a primitive data array + * representation of a pixel + * @throws ClassCastException if obj + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * obj is not large enough to hold a pixel value + * for this ColorModel or the normComponents + * array is not large enough to hold all of the color and alpha + * components starting at normOffset + * @see WritableRaster#setDataElements + * @see SampleModel#setDataElements + * @since 1.4 + */ + public Object getDataElements(float[] normComponents, int normOffset, + Object obj) { + boolean needAlpha = supportsAlpha && isAlphaPremultiplied; + float[] stdNormComponents; + if (needScaleInit) { + initScale(); + } + if (nonStdScale) { + stdNormComponents = new float[numComponents]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + stdNormComponents[c] = (normComponents[nc] - compOffset[c]) * + compScale[c]; + // REMIND: need to analyze whether this + // clamping is necessary + if (stdNormComponents[c] < 0.0f) { + stdNormComponents[c] = 0.0f; + } + if (stdNormComponents[c] > 1.0f) { + stdNormComponents[c] = 1.0f; + } + } + if (supportsAlpha) { + stdNormComponents[numColorComponents] = + normComponents[numColorComponents + normOffset]; + } + normOffset = 0; + } else { + stdNormComponents = normComponents; + } + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte[] bpixel; + if (obj == null) { + bpixel = new byte[numComponents]; + } else { + bpixel = (byte[]) obj; + } + if (needAlpha) { + float alpha = + stdNormComponents[numColorComponents + normOffset]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + bpixel[c] = (byte) ((stdNormComponents[nc] * alpha) * + ((float) ((1 << nBits[c]) - 1)) + 0.5f); + } + bpixel[numColorComponents] = + (byte) (alpha * + ((float) ((1 << nBits[numColorComponents]) - 1)) + + 0.5f); + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + bpixel[c] = (byte) (stdNormComponents[nc] * + ((float) ((1 << nBits[c]) - 1)) + 0.5f); + } + } + return bpixel; + case DataBuffer.TYPE_USHORT: + short[] uspixel; + if (obj == null) { + uspixel = new short[numComponents]; + } else { + uspixel = (short[]) obj; + } + if (needAlpha) { + float alpha = + stdNormComponents[numColorComponents + normOffset]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + uspixel[c] = (short) ((stdNormComponents[nc] * alpha) * + ((float) ((1 << nBits[c]) - 1)) + + 0.5f); + } + uspixel[numColorComponents] = + (short) (alpha * + ((float) ((1 << nBits[numColorComponents]) - 1)) + + 0.5f); + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + uspixel[c] = (short) (stdNormComponents[nc] * + ((float) ((1 << nBits[c]) - 1)) + + 0.5f); + } + } + return uspixel; + case DataBuffer.TYPE_INT: + int[] ipixel; + if (obj == null) { + ipixel = new int[numComponents]; + } else { + ipixel = (int[]) obj; + } + if (needAlpha) { + float alpha = + stdNormComponents[numColorComponents + normOffset]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + ipixel[c] = (int) ((stdNormComponents[nc] * alpha) * + ((float) ((1 << nBits[c]) - 1)) + 0.5f); + } + ipixel[numColorComponents] = + (int) (alpha * + ((float) ((1 << nBits[numColorComponents]) - 1)) + + 0.5f); + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + ipixel[c] = (int) (stdNormComponents[nc] * + ((float) ((1 << nBits[c]) - 1)) + 0.5f); + } + } + return ipixel; + case DataBuffer.TYPE_SHORT: + short[] spixel; + if (obj == null) { + spixel = new short[numComponents]; + } else { + spixel = (short[]) obj; + } + if (needAlpha) { + float alpha = + stdNormComponents[numColorComponents + normOffset]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + spixel[c] = (short) + (stdNormComponents[nc] * alpha * 32767.0f + 0.5f); + } + spixel[numColorComponents] = (short) (alpha * 32767.0f + 0.5f); + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + spixel[c] = (short) + (stdNormComponents[nc] * 32767.0f + 0.5f); + } + } + return spixel; + case DataBuffer.TYPE_FLOAT: + float[] fpixel; + if (obj == null) { + fpixel = new float[numComponents]; + } else { + fpixel = (float[]) obj; + } + if (needAlpha) { + float alpha = normComponents[numColorComponents + normOffset]; + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + fpixel[c] = normComponents[nc] * alpha; + } + fpixel[numColorComponents] = alpha; + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + fpixel[c] = normComponents[nc]; + } + } + return fpixel; + case DataBuffer.TYPE_DOUBLE: + double[] dpixel; + if (obj == null) { + dpixel = new double[numComponents]; + } else { + dpixel = (double[]) obj; + } + if (needAlpha) { + double alpha = + (double) (normComponents[numColorComponents + normOffset]); + for (int c = 0, nc = normOffset; c < numColorComponents; + c++, nc++) { + dpixel[c] = normComponents[nc] * alpha; + } + dpixel[numColorComponents] = alpha; + } else { + for (int c = 0, nc = normOffset; c < numComponents; + c++, nc++) { + dpixel[c] = (double) normComponents[nc]; + } + } + return dpixel; + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + + transferType); + } + } + + /** + * Returns an array of all of the color/alpha components in normalized + * form, given a pixel in this ColorModel. The pixel + * value is specified by an array of data elements of type transferType + * passed in as an object reference. If pixel is not a primitive array + * of type transferType, a ClassCastException is thrown. + * An ArrayIndexOutOfBoundsException is thrown if + * pixel is not large enough to hold a pixel value for this + * ColorModel. + * Normalized components are float values between a per component minimum + * and maximum specified by the ColorSpace object for this + * ColorModel. If the + * normComponents array is null, a new array + * will be allocated. The normComponents array + * will be returned. Color/alpha components are stored in the + * normComponents array starting at + * normOffset (even if the array is allocated by this + * method). An ArrayIndexOutOfBoundsException is thrown + * if the normComponents array is not null + * and is not large enough to hold all the color and alpha components + * (starting at normOffset). + *

+ * This method must be overrridden by a subclass if that subclass + * is designed to translate pixel sample values to color component values + * in a non-default way. The default translations implemented by this + * class is described in the class comments. Any subclass implementing + * a non-default translation must follow the constraints on allowable + * translations defined there. + * @param pixel the specified pixel + * @param normComponents an array to receive the normalized components + * @param normOffset the offset into the normComponents + * array at which to start storing normalized components + * @return an array containing normalized color and alpha + * components. + * @throws ClassCastException if pixel is not a primitive + * array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * normComponents is not large enough to hold all + * color and alpha components starting at normOffset + * @throws ArrayIndexOutOfBoundsException if + * pixel is not large enough to hold a pixel + * value for this ColorModel. + * @since 1.4 + */ + public float[] getNormalizedComponents(Object pixel, + float[] normComponents, + int normOffset) { + if (normComponents == null) { + normComponents = new float[numComponents+normOffset]; + } + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte[] bpixel = (byte[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = ((float) (bpixel[c] & 0xff)) / + ((float) ((1 << nBits[c]) - 1)); + } + break; + case DataBuffer.TYPE_USHORT: + short[] uspixel = (short[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = ((float) (uspixel[c] & 0xffff)) / + ((float) ((1 << nBits[c]) - 1)); + } + break; + case DataBuffer.TYPE_INT: + int[] ipixel = (int[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = ((float) ipixel[c]) / + ((float) ((1 << nBits[c]) - 1)); + } + break; + case DataBuffer.TYPE_SHORT: + short[] spixel = (short[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = ((float) spixel[c]) / 32767.0f; + } + break; + case DataBuffer.TYPE_FLOAT: + float[] fpixel = (float[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = fpixel[c]; + } + break; + case DataBuffer.TYPE_DOUBLE: + double[] dpixel = (double[]) pixel; + for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { + normComponents[nc] = (float) dpixel[c]; + } + break; + default: + throw new UnsupportedOperationException("This method has not been "+ + "implemented for transferType " + + transferType); + } + + if (supportsAlpha && isAlphaPremultiplied) { + float alpha = normComponents[numColorComponents + normOffset]; + if (alpha != 0.0f) { + float invAlpha = 1.0f / alpha; + for (int c = normOffset; c < numColorComponents + normOffset; + c++) { + normComponents[c] *= invAlpha; + } + } + } + if (min != null) { + // Normally (i.e. when this class is not subclassed to override + // this method), the test (min != null) will be equivalent to + // the test (nonStdScale). However, there is an unlikely, but + // possible case, in which this method is overridden, nonStdScale + // is set true by initScale(), the subclass method for some + // reason calls this superclass method, but the min and + // diffMinMax arrays were never initialized by setupLUTs(). In + // that case, the right thing to do is follow the intended + // semantics of this method, and rescale the color components + // only if the ColorSpace min/max were detected to be other + // than 0.0/1.0 by setupLUTs(). Note that this implies the + // transferType is byte, ushort, int, or short - i.e. components + // derived from float and double pixel data are never rescaled. + for (int c = 0; c < numColorComponents; c++) { + normComponents[c + normOffset] = min[c] + + diffMinMax[c] * normComponents[c + normOffset]; + } + } + return normComponents; + } + + /** + * Forces the raster data to match the state specified in the + * isAlphaPremultiplied variable, assuming the data + * is currently correctly described by this ColorModel. + * It may multiply or divide the color raster data by alpha, or + * do nothing if the data is in the correct state. If the data needs + * to be coerced, this method also returns an instance of + * this ColorModel with + * the isAlphaPremultiplied flag set appropriately. + * Since ColorModel 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. + * + * @throws NullPointerException if raster is + * null and data coercion is required. + * @throws UnsupportedOperationException if the transfer type of + * this ComponentColorModel + * is not one of the supported transfer types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + */ + public ColorModel coerceData (WritableRaster raster, + boolean isAlphaPremultiplied) { + if ((supportsAlpha == false) || + (this.isAlphaPremultiplied == isAlphaPremultiplied)) + { + // Nothing to do + return this; + } + + int w = raster.getWidth(); + int h = raster.getHeight(); + int aIdx = raster.getNumBands() - 1; + float normAlpha; + int rminX = raster.getMinX(); + int rY = raster.getMinY(); + int rX; + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: { + byte pixel[] = null; + byte zpixel[] = null; + float alphaScale = 1.0f / ((float) ((1<raster is compatible with this + * ColorModel; false if it is not. + * + * @param raster The Raster object to test for compatibility. + * + * @return true if raster is compatible with this + * ColorModel, false if it is not. + */ + public boolean isCompatibleRaster(Raster raster) { + + SampleModel sm = raster.getSampleModel(); + + if (sm instanceof ComponentSampleModel) { + if (sm.getNumBands() != getNumComponents()) { + return false; + } + for (int i=0; iWritableRaster with the specified width and height, + * that has a data layout (SampleModel) compatible with + * this ColorModel. + * + * @param w The width of the WritableRaster you want to create. + * @param h The height of the WritableRaster you want to create. + * + * @return A WritableRaster that is compatible with + * this ColorModel. + * @see WritableRaster + * @see SampleModel + */ + public WritableRaster createCompatibleWritableRaster (int w, int h) { + int dataSize = w*h*numComponents; + WritableRaster raster = null; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + raster = Raster.createInterleavedRaster(transferType, + w, h, + numComponents, null); + break; + default: + SampleModel sm = createCompatibleSampleModel(w, h); + DataBuffer db = sm.createDataBuffer(); + raster = Raster.createWritableRaster(sm, db, null); + } + + return raster; + } + + /** + * Creates a SampleModel with the specified width and height, + * that has a data layout compatible with this ColorModel. + * + * @param w The width of the SampleModel you want to create. + * @param h The height of the SampleModel you want to create. + * + * @return A SampleModel that is compatible with this + * ColorModel. + * + * @see SampleModel + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + int[] bandOffsets = new int[numComponents]; + for (int i=0; i < numComponents; i++) { + bandOffsets[i] = i; + } + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, + numComponents, + w*numComponents, + bandOffsets); + default: + return new ComponentSampleModel(transferType, w, h, + numComponents, + w*numComponents, + bandOffsets); + } + } + + /** + * Checks whether or not the specified SampleModel + * is compatible with this ColorModel. + * + * @param sm The SampleModel to test for compatibility. + * + * @return true if the SampleModel is + * compatible with this ColorModel, false + * if it is not. + * + * @see SampleModel + */ + public boolean isCompatibleSampleModel(SampleModel sm) { + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + + // Must have the same number of components + if (numComponents != sm.getNumBands()) { + return false; + } + + if (sm.getTransferType() != transferType) { + return false; + } + + return true; + } + + /** + * Returns a Raster representing the alpha channel of an image, + * extracted from the input Raster. + * This method assumes that Raster objects associated with + * this ColorModel store the alpha band, if present, as + * the last band of image data. Returns null if there is no separate spatial + * alpha channel associated with this ColorModel. + * This method creates a new Raster, but will share the data + * array. + * + * @param raster The WritableRaster from which to extract the + * alpha channel. + * + * @return A WritableRaster containing the image's alpha channel. + * + */ + public WritableRaster getAlphaRaster(WritableRaster raster) { + if (hasAlpha() == false) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int[] band = new int[1]; + band[0] = raster.getNumBands() - 1; + return raster.createWritableChild(x, y, raster.getWidth(), + raster.getHeight(), x, y, + band); + } + + /** + * Compares this color model with another for equality. + * + * @param obj The object to compare with this color model. + * @return true if the color model objects are equal, + * false if they are not. + */ + public boolean equals(Object obj) { + if (!super.equals(obj)) { + return false; + } + + if (obj.getClass() != getClass()) { + return false; + } + + return true; + } + +} diff --git a/openjdk/java/awt/image/IndexColorModel.java b/openjdk/java/awt/image/IndexColorModel.java new file mode 100644 index 00000000..ac5160e5 --- /dev/null +++ b/openjdk/java/awt/image/IndexColorModel.java @@ -0,0 +1,1519 @@ +/* + * 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 IndexColorModel class is a ColorModel + * 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 BigInteger object. + * This color model is similar to an X11 PseudoColor visual. + *

+ * 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 + * IndexColorModel objects are never pre-multiplied with + * the alpha components. + *

+ * + * The transparency of an IndexColorModel 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 Transparency.OPAQUE + * 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 Transparency.BITMASK. + * Otherwise, the value is Transparency.TRANSLUCENT, indicating + * that some valid color has an alpha component that is + * neither completely transparent nor completely opaque + * (0.0 < alpha < 1.0). + * + * + *

+ * If an IndexColorModel object has + * a transparency value of Transparency.OPAQUE, + * then the hasAlpha + * and getNumComponents methods + * (both inherited from ColorModel) + * return false and 3, respectively. + * For any other transparency value, + * hasAlpha returns true + * and getNumComponents returns 4. + * + *

+ * + * The values used to index into the colormap are taken from the least + * significant n bits of pixel representations where + * n is based on the pixel size specified in the constructor. + * For pixel sizes smaller than 8 bits, n 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, n is equal to the + * pixel size. + * Pixel sizes larger than 16 bits are not supported by this class. + * Higher order bits beyond n are ignored in pixel representations. + * Index values greater than or equal to the map size, but less than + * 2n, are undefined and return 0 for all color and + * alpha components. + *

+ * For those methods that use a primitive array pixel representation of + * type transferType, the array length is always one. + * The transfer types supported are DataBuffer.TYPE_BYTE and + * DataBuffer.TYPE_USHORT. 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 IllegalArgumentException due to an invalid + * pixel value. + *

+ * 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}; + + /** + * Constructs an IndexColorModel 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 ColorSpace is the default sRGB space. + * Since there is no alpha information in any of the arguments + * to this constructor, the transparency value is always + * Transparency.OPAQUE. + * The transfer type is the smallest of DataBuffer.TYPE_BYTE + * or DataBuffer.TYPE_USHORT 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 bits is less + * than 1 or greater than 16 + * @throws IllegalArgumentException if size 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 IndexColorModel 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 ColorSpace is the default sRGB space. + * The transparency value may be Transparency.OPAQUE or + * Transparency.BITMASK depending on the arguments, as + * specified in the class description above. + * The transfer type is the smallest of DataBuffer.TYPE_BYTE + * or DataBuffer.TYPE_USHORT 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 bits is less than + * 1 or greater than 16 + * @throws IllegalArgumentException if size 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 IndexColorModel 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 ColorSpace is the default sRGB space. + * The transparency value may be any of Transparency.OPAQUE, + * Transparency.BITMASK, + * or Transparency.TRANSLUCENT + * depending on the arguments, as specified + * in the class description above. + * The transfer type is the smallest of DataBuffer.TYPE_BYTE + * or DataBuffer.TYPE_USHORT 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 bits is less + * than 1 or greater than 16 + * @throws IllegalArgumentException if size 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 IndexColorModel 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 ColorSpace is the default sRGB space. + * The transparency value may be any of Transparency.OPAQUE, + * Transparency.BITMASK, + * or Transparency.TRANSLUCENT + * depending on the arguments, as specified + * in the class description above. + * The transfer type is the smallest of + * DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT + * 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 cmap array + * @throws IllegalArgumentException if bits is less + * than 1 or greater than 16 + * @throws IllegalArgumentException if size 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 IndexColorModel 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 ColorSpace is the default sRGB space. + * The transparency value may be any of Transparency.OPAQUE, + * Transparency.BITMASK, + * or Transparency.TRANSLUCENT + * depending on the arguments, as specified + * in the class description above. + * The transfer type is the smallest of + * DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT + * 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 cmap array + * @param trans the index of the fully transparent pixel + * @throws IllegalArgumentException if bits is less than + * 1 or greater than 16 + * @throws IllegalArgumentException if size 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 IndexColorModel 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 ColorSpace is the default sRGB space. + * The transparency value may be any of Transparency.OPAQUE, + * Transparency.BITMASK, + * or Transparency.TRANSLUCENT + * depending on the arguments, as specified + * in the class description 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 cmap 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 + * DataBuffer.TYPE_BYTE or + * DataBuffer.TYPE_USHORT. + * @throws IllegalArgumentException if bits is less + * than 1 or greater than 16 + * @throws IllegalArgumentException if size is less + * than 1 + * @throws IllegalArgumentException if transferType is not + * one of DataBuffer.TYPE_BYTE or + * DataBuffer.TYPE_USHORT + */ + 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 IndexColorModel from an + * int array where each int 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 ColorSpace is the default sRGB space. + * The transparency value may be any of Transparency.OPAQUE, + * Transparency.BITMASK, + * or Transparency.TRANSLUCENT + * depending on the arguments, as specified + * in the class description above. + * The transfer type must be one of DataBuffer.TYPE_BYTE + * DataBuffer.TYPE_USHORT. + * The BigInteger object specifies the valid/invalid pixels + * in the cmap array. A pixel is valid if the + * BigInteger value at that index is set, and is invalid + * if the BigInteger 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 BigInteger 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 bits is less + * than 1 or greater than 16 + * @throws IllegalArgumentException if size is less + * than 1 + * @throws IllegalArgumentException if transferType is not + * one of DataBuffer.TYPE_BYTE or + * DataBuffer.TYPE_USHORT + * + * @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 IndexColorModel + * @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 IndexColorModel + */ + 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 + * IndexColorModel. + * @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 + * IndexColorModel 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 + * IndexColorModel 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 + * getMapSize 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 + * getMapSize 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 getMapSize 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 + * getMapSize 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 n bits of the pixel value, as specified in the + * class description 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 n bits of the pixel value, as specified in the + * class description 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 n bits of the pixel value, as specified in the + * class description 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 n bits of the pixel value, as specified in the + * class description 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 n bits of the pixel value, as specified in the + * class description 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 + * null, a new array is allocated. If pixel + * is not null, it must be + * a primitive array of type transferType; otherwise, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is + * thrown if pixel is not large enough to hold a pixel + * value for this ColorModel. The pixel array is returned. + *

+ * Since IndexColorModel 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 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 + * IndexColorModel. + * @throws ClassCastException if pixel + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * pixel is not large enough to hold a pixel value + * for this ColorModel + * @throws UnsupportedOperationException if transferType + * 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 ColorModel. The pixel value + * is specified as an int. If the components array is null, + * a new array is allocated that contains + * offset + getNumComponents() elements. + * The components array is returned, + * with the alpha component included + * only if hasAlpha returns true. + * Color/alpha components are stored in the components array starting + * at offset even if the array is allocated by this method. + * An ArrayIndexOutOfBoundsException + * is thrown if the components array is not null and is + * not large enough to hold all the color and alpha components + * starting at offset. + * @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 components 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 ColorModel. The pixel + * value is specified by an array of data elements of type + * transferType passed in as an object reference. + * If pixel is not a primitive array of type + * transferType, a ClassCastException + * is thrown. An ArrayIndexOutOfBoundsException + * is thrown if pixel is not large enough to hold + * a pixel value for this ColorModel. If the + * components array is null, a new array + * is allocated that contains + * offset + getNumComponents() elements. + * The components array is returned, + * with the alpha component included + * only if hasAlpha returns true. + * Color/alpha components are stored in the components + * array starting at offset even if the array is + * allocated by this method. An + * ArrayIndexOutOfBoundsException is also + * thrown if the components array is not + * null and is not large enough to hold all the color + * and alpha components starting at offset. + *

+ * Since IndexColorModel 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 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 components 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 pixel + * is not large enough to hold a pixel value for this + * ColorModel or if the + * components array is not null + * and is not large enough to hold all the color + * and alpha components starting at offset + * @throws ClassCastException if pixel is not a + * primitive array of type transferType + * @throws UnsupportedOperationException if transferType + * 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 + * ColorModel given an array of unnormalized + * color/alpha components. An + * ArrayIndexOutOfBoundsException + * is thrown if the components array is not large + * enough to hold all of the color and alpha components starting + * at offset. Since + * ColorModel 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 components at which to + * begin retrieving the color and alpha components + * @return an int pixel value in this + * ColorModel corresponding to the specified components. + * @throws ArrayIndexOutOfBoundsException if + * the components array is not large enough to + * hold all of the color and alpha components starting at + * offset + * @throws UnsupportedOperationException if transferType + * 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 + * ColorModel given an array of unnormalized color/alpha + * components. This array can then be passed to the + * setDataElements method of a WritableRaster + * object. An ArrayIndexOutOfBoundsException is + * thrown if the + * components array is not large enough to hold all of the + * color and alpha components starting at offset. + * If the pixel variable is null, a new array + * is allocated. If pixel is not null, + * it must be a primitive array of type transferType; + * otherwise, a ClassCastException is thrown. + * An ArrayIndexOutOfBoundsException is thrown if pixel + * is not large enough to hold a pixel value for this + * ColorModel. + *

+ * Since IndexColorModel 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 components at which to + * begin retrieving color and alpha components + * @param pixel the Object representing an array of color + * and alpha components + * @return an Object representing an array of color and + * alpha components. + * @throws ClassCastException if pixel + * is not a primitive array of type transferType + * @throws ArrayIndexOutOfBoundsException if + * pixel is not large enough to hold a pixel value + * for this ColorModel or the components + * array is not large enough to hold all of the color and alpha + * components starting at offset + * @throws UnsupportedOperationException if transferType + * 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 WritableRaster with the specified width + * and height that has a data layout (SampleModel) + * compatible with this ColorModel. This method + * only works for color models with 16 or fewer bits per pixel. + *

+ * Since IndexColorModel 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 WritableRaster + * @param h the height to apply to the new WritableRaster + * @return a WritableRaster 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 true if raster is compatible + * with this ColorModel or false if it + * is not compatible with this ColorModel. + * @param raster the {@link Raster} object to test for compatibility + * @return true if raster is compatible + * with this ColorModel; false 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 SampleModel with the specified + * width and height that has a data layout compatible with + * this ColorModel. + * @param w the width to apply to the new SampleModel + * @param h the height to apply to the new SampleModel + * @return a SampleModel object with the specified + * width and height. + * @throws IllegalArgumentException if w or + * h 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 SampleModel is compatible + * with this ColorModel. If sm is + * null, this method returns false. + * @param sm the specified SampleModel, + * or null + * @return true if the specified SampleModel + * is compatible with this ColorModel; false + * 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 BufferedImage of TYPE_INT_ARGB or + * TYPE_INT_RGB that has a Raster with pixel data + * computed by expanding the indices in the source Raster + * using the color/alpha component arrays of this ColorModel. + * Only the lower n bits of each index value in the source + * Raster, as specified in the + * class description above, are used to + * compute the color/alpha values in the returned image. + * If forceARGB is true, a TYPE_INT_ARGB image is + * returned regardless of whether or not this ColorModel + * has an alpha component array or a transparent pixel. + * @param raster the specified Raster + * @param forceARGB if true, the returned + * BufferedImage is TYPE_INT_ARGB; otherwise it is + * TYPE_INT_RGB + * @return a BufferedImage created with the specified + * Raster + * @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 true if pixel + * is valid; false 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 true if all pixels are valid; + * false otherwise. + * @since 1.3 + */ + public boolean isValid() { + return (validBits == null); + } + + /** + * Returns a BigInteger that indicates the valid/invalid + * pixels in the colormap. A bit is valid if the + * BigInteger value at that index is set, and is invalid + * if the BigInteger value at that index is not set. + * The only valid ranges to query in the BigInteger are + * between 0 and the map size. + * @return a BigInteger indicating the valid/invalid pixels. + * @since 1.3 + */ + public BigInteger getValidPixels() { + if (validBits == null) { + return getAllValid(); + } + else { + return validBits; + } + } + + /** + * Returns the String representation of the contents of + * this ColorModelobject. + * @return a String representing the contents of this + * ColorModel 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 + ); + } +} diff --git a/openjdk/response.txt b/openjdk/response.txt index 725d3dcd..107c4781 100644 --- a/openjdk/response.txt +++ b/openjdk/response.txt @@ -619,6 +619,7 @@ assembly.class ../../openjdk6-b12/jdk/src/share/classes/java/awt/image/*.class ../../openjdk6-b12/jdk/src/share/classes/sun/awt/image/*.class ../../openjdk6-b12/jdk/src/share/classes/sun/java2d/*.class + ../../openjdk6-b12/jdk/src/share/classes/sun/java2d/cmm/*.class ../../openjdk6-b12/jdk/src/share/classes/sun/swing/*.class ../classpath/gnu/java/awt/peer/*.class ../classpath/gnu/java/awt/peer/gtk/*.class