/* * Copyright (c) 1995, 2006, Oracle and/or its affiliates. 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.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.awt.color.ICC_ColorSpace; import sun.java2d.cmm.CMSManager; import sun.java2d.cmm.ColorTransform; import sun.java2d.cmm.PCMM; import java.awt.Toolkit; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; /** * The ColorModel 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; /** * This is copied from java.awt.Toolkit since we need the library * loaded in java.awt.image also: * * WARNING: This is a temporary workaround for a problem in the * way the AWT loads native libraries. A number of classes in the * AWT package have a native method, initIDs(), which initializes * the JNI field and method ids used in the native portion of * their implementation. * * Since the use and storage of these ids is done by the * implementation libraries, the implementation of these method is * provided by the particular AWT implementations (for example, * "Toolkit"s/Peer), such as Motif, Microsoft Windows, or Tiny. The * problem is that this means that the native libraries must be * loaded by the java.* classes, which do not necessarily know the * names of the libraries to load. A better way of doing this * would be to provide a separate library which defines java.awt.* * initIDs, and exports the relevant symbols out to the * implementation libraries. * * For now, we know it's done by the implementation, and we assume * that the name of the library is "awt". -br. */ private static boolean loaded = false; static void loadLibraries() { if (!loaded) { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { System.loadLibrary("awt"); return null; } }); loaded = true; } } private static native void initIDs(); static { /* ensure that the proper libraries are loaded */ loadLibraries(); initIDs(); } 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 = 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 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 = 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 = 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 = 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 = 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; } }