- /*
- * @(#)DirectColorModel.java 1.69 00/02/02
- *
- * Copyright 1995-2000 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the proprietary information of Sun Microsystems, Inc.
- * Use is subject to license terms.
- *
- */
-
- package java.awt.image;
-
- import java.awt.color.ColorSpace;
- import java.awt.Transparency;
-
- /**
- * The <code>DirectColorModel</code> class is a <code>ColorModel</code>
- * class that works with pixel values that represent RGB
- * color and alpha information as separate samples and that pack all
- * samples for a single pixel into a single int, short, or byte quantity.
- * This class can be used only with ColorSpaces of type ColorSpace.TYPE_RGB.
- * There must be three color samples in the pixel values and there can
- * be a single alpha sample. For those methods that use a primitive array
- * pixel representation of type <code>transferType</code>, the array
- * length is always one. The transfer
- * types supported are DataBuffer.TYPE_BYTE,
- * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT.
- * Color and alpha samples are stored in the single
- * element of the array in bits indicated by bit masks. Each bit mask
- * must be contiguous and masks must not overlap. The same masks apply to
- * the single int pixel representation used by other methods. The
- * correspondence of masks and color/alpha samples is as follows:
- * <ul>
- * <li> Masks are identified by indices running from 0 through 2
- * if no alpha is present, or 3 if an alpha is present.
- * <li> The first three indices refer to color samples;
- * index 0 corresponds to red, index 1 to green, and index 2 to blue.
- * <li> Index 3 corresponds to the alpha sample, if present.
- * </ul>
- * <p>
- * The translation from pixel values to color/alpha components for
- * display or processing purposes is a one-to-one correspondence of
- * samples to components. A <code>DirectColorModel</code> is
- * typically used with image data which uses masks to define packed
- * samples. For example, a <code>DirectColorModel</code> can be used in
- * conjunction with a <code>SinglePixelPackedSampleModel</code> to
- * construct a {@link BufferedImage}. Normally the masks used by the
- * {@link SampleModel} and the <code>ColorModel</code> would be the
- * same. However, if they are different, the color interpretation
- * of pixel data will be done according to the masks of the
- * <code>ColorModel</code>.
- * <p>
- * 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 which use this
- * representation will not throw an <code>IllegalArgumentException</code>
- * due to an invalid pixel value.
- * <p>
- * This color model is similar to an X11 TrueColor visual.
- * The default RGB ColorModel specified by the
- * {@link ColorModel#getRGBdefault() getRGBdefault} method is a
- * <code>DirectColorModel</code> with the following parameters:
- * <pre>
- * Number of bits: 32
- * Red mask: 0x00ff0000
- * Green mask: 0x0000ff00
- * Blue mask: 0x000000ff
- * Alpha mask: 0xff000000
- * Color space: sRGB
- * isAlphaPremultiplied: False
- * Transparency: Transparency.TRANSLUCENT
- * transferType: DataBuffer.TYPE_INT
- * </pre>
- * <p>
- * Many of the methods in this class are final. This is because 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 behavior of those methods.
- *
- * @see ColorModel
- * @see ColorSpace
- * @see SinglePixelPackedSampleModel
- * @see BufferedImage
- * @see ColorModel#getRGBdefault
- *
- * @version 10 Feb 1997
- */
- public class DirectColorModel extends PackedColorModel {
- private int red_mask;
- private int green_mask;
- private int blue_mask;
- private int alpha_mask;
- private int red_offset;
- private int green_offset;
- private int blue_offset;
- private int alpha_offset;
- private int red_scale;
- private int green_scale;
- private int blue_scale;
- private int alpha_scale;
-
- /**
- * Constructs a <code>DirectColorModel</code> from the specified masks
- * that indicate which bits in an <code>int</code> pixel representation
- * contain the red, green and blue color samples. As pixel values do not
- * contain alpha information, all pixels are treated as opaque, which
- * means that alpha = 1.0. All of the bits
- * in each mask must be contiguous and fit in the specified number
- * of least significant bits of an <code>int</code> pixel representation.
- * The <code>ColorSpace</code> is the default sRGB space. The
- * transparency value is Transparency.OPAQUE. The transfer type
- * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
- * or DataBuffer.TYPE_INT that can hold a single pixel.
- * @param bits the number of bits in the pixel values; for example,
- * the sum of the number of bits in the masks.
- * @param rmask specifies a mask indicating which bits in an
- * integer pixel contain the red component
- * @param gmask specifies a mask indicating which bits in an
- * integer pixel contain the green component
- * @param bmask specifies a mask indicating which bits in an
- * integer pixel contain the blue component
- *
- */
- public DirectColorModel(int bits,
- int rmask, int gmask, int bmask) {
- this(bits, rmask, gmask, bmask, 0);
- }
-
- /**
- * Constructs a <code>DirectColorModel</code> from the specified masks
- * that indicate which bits in an <code>int</code> pixel representation
- * contain the red, green and blue color samples and the alpha sample,
- * if present. If <code>amask</code> is 0, pixel values do not contain
- * alpha information and all pixels are treated as opaque, which means
- * that alpha = 1.0. All of the bits in each mask must
- * be contiguous and fit in the specified number of least significant bits
- * of an <code>int</code> pixel representation. Alpha, if present, is not
- * premultiplied. The <code>ColorSpace</code> is the default sRGB space.
- * The transparency value is Transparency.OPAQUE if no alpha is
- * present, or Transparency.TRANSLUCENT otherwise. The transfer type
- * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
- * or DataBuffer.TYPE_INT that can hold a single pixel.
- * @param bits the number of bits in the pixel values; for example,
- * the sum of the number of bits in the masks.
- * @param rmask specifies a mask indicating which bits in an
- * integer pixel contain the red component
- * @param gmask specifies a mask indicating which bits in an
- * integer pixel contain the green component
- * @param bmask specifies a mask indicating which bits in an
- * integer pixel contain the blue component
- * @param amask specifies a mask indicating which bits in an
- * integer pixel contain the alpha component
- */
- public DirectColorModel(int bits, int rmask, int gmask,
- int bmask, int amask) {
- super (ColorSpace.getInstance(ColorSpace.CS_sRGB),
- bits, rmask, gmask, bmask, amask, false,
- amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT,
- ColorModel.getDefaultTransferType(bits));
- setFields();
- }
-
- /**
- * Constructs a <code>DirectColorModel</code> from the specified
- * parameters. Color components are in the specified
- * <code>ColorSpace</code>, which must be of type ColorSpace.TYPE_RGB.
- * The masks specify which bits in an <code>int</code> pixel
- * representation contain the red, green and blue color samples and
- * the alpha sample, if present. If <code>amask</code> is 0, pixel
- * values do not contain alpha information and all pixels are treated
- * as opaque, which means that alpha = 1.0. All of the
- * bits in each mask must be contiguous and fit in the specified number
- * of least significant bits of an <code>int</code> pixel
- * representation. If there is alpha, the <code>boolean</code>
- * <code>isAlphaPremultiplied</code> specifies how to interpret
- * color and alpha samples in pixel values. If the <code>boolean</code>
- * is <code>true</code>, color samples are assumed to have been
- * multiplied by the alpha sample. The transparency value is
- * Transparency.OPAQUE, if no alpha is present, or
- * Transparency.TRANSLUCENT otherwise. The transfer type
- * is the type of primitive array used to represent pixel values and
- * must be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
- * DataBuffer.TYPE_INT.
- * @param space the specified <code>ColorSpace</code>
- * @param bits the number of bits in the pixel values; for example,
- * the sum of the number of bits in the masks.
- * @param rmask specifies a mask indicating which bits in an
- * integer pixel contain the red component
- * @param gmask specifies a mask indicating which bits in an
- * integer pixel contain the green component
- * @param bmask specifies a mask indicating which bits in an
- * integer pixel contain the blue component
- * @param amask specifies a mask indicating which bits in an
- * integer pixel contain the alpha component
- * @param isAlphaPremultiplied <code>true</code> if color samples are
- * premultiplied by the alpha sample; <code>false</code> otherwise
- * @param transferType the type of array used to represent pixel values
- */
- public DirectColorModel(ColorSpace space, int bits, int rmask,
- int gmask, int bmask, int amask,
- boolean isAlphaPremultiplied,
- int transferType) {
- super (space, bits, rmask, gmask, bmask, amask,
- isAlphaPremultiplied,
- amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT,
- transferType);
- setFields();
- }
-
- /**
- * Returns the mask indicating which bits in an <code>int</code> pixel
- * representation contain the red color component.
- * @return the mask, which indicates which bits of the <code>int</code>
- * pixel representation contain the red color sample.
- */
- final public int getRedMask() {
- return maskArray[0];
- }
-
- /**
- * Returns the mask indicating which bits in an <code>int</code> pixel
- * representation contain the green color component.
- * @return the mask, which indicates which bits of the <code>int</code>
- * pixel representation contain the green color sample.
- */
- final public int getGreenMask() {
- return maskArray[1];
- }
-
- /**
- * Returns the mask indicating which bits in an <code>int</code> pixel
- * representation contain the blue color component.
- * @return the mask, which indicates which bits of the <code>int</code>
- * pixel representation contain the blue color sample.
- */
- final public int getBlueMask() {
- return maskArray[2];
- }
-
- /**
- * Returns the mask indicating which bits in an <code>int</code> pixel
- * representation contain the alpha component.
- * @return the mask, which indicates which bits of the <code>int</code>
- * pixel representation contain the alpha sample.
- */
- final public int getAlphaMask() {
- if (supportsAlpha) {
- return maskArray[3];
- } else {
- return 0;
- }
- }
-
-
- /*
- * Given an int pixel in this ColorModel's ColorSpace, converts
- * it to the default sRGB ColorSpace and returns the R, G, and B
- * components as float values between 0.0 and 1.0.
- */
- private float[] getDefaultRGBComponents(int pixel) {
- int components[] = getComponents(pixel, null, 0);
- float norm[] = getNormalizedComponents(components, 0, null, 0);
- // Note that getNormalizedComponents returns non-premultiplied values
- return colorSpace.toRGB(norm);
- }
-
-
- /**
- * Returns the red color component for the specified pixel, scaled
- * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A
- * color conversion is done if necessary. The pixel value is specified
- * as an <code>int</code>.
- * The returned value is a non pre-multiplied value. Thus, if the
- * alpha is premultiplied, this method divides it out before returning
- * the value. If the alpha value is 0, for example, the red value
- * is 0.
- * @param pixel the specified pixel
- * @return the red color component for the specified pixel, from
- * 0 to 255 in the sRGB <code>ColorSpace</code>.
- */
- final public int getRed(int pixel) {
- if (!is_sRGB) {
- float rgb[] = getDefaultRGBComponents(pixel);
- return (int) (rgb[0] * 255.0f);
- }
- int r = ((pixel & maskArray[0]) >>> maskOffsets[0]);
- if (scaleFactors[0] != 1.) {
- r = (int)(r * scaleFactors[0]);
- }
- if (isAlphaPremultiplied) {
- int a = getAlpha(pixel);
- r = (a == 0) ? 0 : (r * 255/a);
- if (r > 255) {
- r = 255;
- }
- }
- return r;
- }
-
- /**
- * Returns the green color component for the specified pixel, scaled
- * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A
- * color conversion is done if necessary. The pixel value is specified
- * as an <code>int</code>.
- * The returned value is a non pre-multiplied value. Thus, if the
- * alpha is premultiplied, this method divides it out before returning
- * the value. If the alpha value is 0, for example, the green value
- * is 0.
- * @param pixel the specified pixel
- * @return the green color component for the specified pixel, from
- * 0 to 255 in the sRGB <code>ColorSpace</code>.
- */
- final public int getGreen(int pixel) {
- if (!is_sRGB) {
- float rgb[] = getDefaultRGBComponents(pixel);
- return (int) (rgb[1] * 255.0f);
- }
- int g = ((pixel & maskArray[1]) >>> maskOffsets[1]);
- if (scaleFactors[1] != 1.) {
- g = (int) (g * scaleFactors[1]);
- }
-
- if (isAlphaPremultiplied) {
- int a = getAlpha(pixel);
- g = (a == 0) ? 0 : (g * 255/a);
- if (g > 255) {
- g = 255;
- }
- }
- return g;
- }
-
- /**
- * Returns the blue color component for the specified pixel, scaled
- * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A
- * color conversion is done if necessary. The pixel value is specified
- * as an <code>int</code>.
- * The returned value is a non pre-multiplied value. Thus, if the
- * alpha is premultiplied, this method divides it out before returning
- * the value. If the alpha value is 0, for example, the blue value
- * is 0.
- * @param pixel the specified pixel
- * @return the blue color component for the specified pixel, from
- * 0 to 255 in the sRGB <code>ColorSpace</code>.
- */
- final public int getBlue(int pixel) {
- if (!is_sRGB) {
- float rgb[] = getDefaultRGBComponents(pixel);
- return (int) (rgb[2] * 255.0f);
- }
- int b = ((pixel & maskArray[2]) >>> maskOffsets[2]);
- if (scaleFactors[2] != 1.) {
- b = (int)(b * scaleFactors[2]);
- }
-
- if (isAlphaPremultiplied) {
- int a = getAlpha(pixel);
- b = (a == 0) ? 0 : (b * 255/a);
- if (b > 255) {
- b = 255;
- }
- }
- return b;
- }
-
- /**
- * Returns the alpha component for the specified pixel, scaled
- * from 0 to 255. The pixel value is specified as an <code>int</code>.
- * @param pixel the specified pixel
- * @return the value of the alpha component of <code>pixel</code>
- * from 0 to 255.
- */
- final public int getAlpha(int pixel) {
- if (!supportsAlpha) return 255;
- int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
- if (scaleFactors[3] != 1.) {
- a = (int)(a * scaleFactors[3]);
- }
- return a;
- }
-
- /**
- * 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 <code>int</code>.
- * The returned value is in a non pre-multiplied format. Thus, if
- * the alpha is premultiplied, this method divides it out of the
- * color components. If the alpha value is 0, for example, the color
- * values are each 0.
- * @param pixel the specified pixel
- * @return the RGB value of the color/alpha components of the specified
- * pixel.
- * @see ColorModel#getRGBdefault
- */
- final public int getRGB(int pixel) {
- if (!is_sRGB) {
- float rgb[] = getDefaultRGBComponents(pixel);
- return (getAlpha(pixel) << 24)
- | (((int) (rgb[0] * 255.0f)) << 16)
- | (((int) (rgb[1] * 255.0f)) << 8)
- | (((int) (rgb[2] * 255.0f)) << 0);
- }
- 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 <code>ColorSpace</code>, sRGB. A
- * color conversion is done if necessary. The pixel value is specified
- * by an array of data elements of type <code>transferType</code> passed
- * in as an object reference.
- * The returned value is a non pre-multiplied value. Thus, if the
- * alpha is premultiplied, this method divides it out before returning
- * the value. If the alpha value is 0, for example, the red value
- * is 0.
- * If <code>inData</code> is not a primitive array of type
- * <code>transferType</code>, a <code>ClassCastException</code> is
- * thrown. An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>inData</code> is not large enough to hold a
- * pixel value for this <code>ColorModel</code>. Since
- * <code>DirectColorModel</code> can be subclassed, subclasses inherit
- * the implementation of this method and if they don't override it
- * then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- * An <code>UnsupportedOperationException</code> is thrown if this
- * <code>transferType</code> is not supported by this
- * <code>ColorModel</code>.
- * @param inData the array containing the pixel value
- * @return the value of the red component of the specified pixel.
- * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
- * large enough to hold a pixel value for this color model
- * @throws ClassCastException if <code>inData</code> is not a
- * primitive array of type <code>transferType</code>
- * @throws UnsupportedOperationException if this <code>transferType</code>
- * is not supported by this color model
- */
- public int getRed(Object inData) {
- int pixel=0;
- 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] & 0xffff;
- 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 getRed(pixel);
- }
-
-
- /**
- * Returns the green color component for the specified pixel, scaled
- * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A
- * color conversion is done if necessary. The pixel value is specified
- * by an array of data elements of type <code>transferType</code> passed
- * in as an object reference.
- * The returned value is a non pre-multiplied value. Thus, if the
- * alpha is premultiplied, this method divides it out before returning
- * the value. If the alpha value is 0, for example, the green value
- * is 0. If <code>inData</code> is not a primitive array of type
- * <code>transferType</code>, a <code>ClassCastException</code> is thrown.
- * An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>inData</code> is not large enough to hold a pixel
- * value for this <code>ColorModel</code>. Since
- * <code>DirectColorModel</code> can be subclassed, subclasses inherit
- * the implementation of this method and if they don't override it
- * then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- * An <code>UnsupportedOperationException</code> is
- * thrown if this <code>transferType</code> is not supported by this
- * <code>ColorModel</code>.
- * @param inData the array containing the pixel value
- * @return the value of the green component of the specified pixel.
- * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
- * large enough to hold a pixel value for this color model
- * @throws ClassCastException if <code>inData</code> is not a
- * primitive array of type <code>transferType</code>
- * @throws UnsupportedOperationException if this <code>transferType</code>
- * is not supported by this color model
- */
- public int getGreen(Object inData) {
- int pixel=0;
- 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] & 0xffff;
- 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 getGreen(pixel);
- }
-
-
- /**
- * Returns the blue color component for the specified pixel, scaled
- * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A
- * color conversion is done if necessary. The pixel value is specified
- * by an array of data elements of type <code>transferType</code> passed
- * in as an object reference.
- * The returned value is a non pre-multiplied value. Thus, if the
- * alpha is premultiplied, this method divides it out before returning
- * the value. If the alpha value is 0, for example, the blue value
- * is 0. If <code>inData</code> is not a primitive array of type
- * <code>transferType</code>, a <code>ClassCastException</code> is thrown.
- * An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>inData</code> is not large enough to hold a pixel
- * value for this <code>ColorModel</code>. Since
- * <code>DirectColorModel</code> can be subclassed, subclasses inherit
- * the implementation of this method and if they don't override it
- * then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- * An <code>UnsupportedOperationException</code> is
- * thrown if this <code>transferType</code> is not supported by this
- * <code>ColorModel</code>.
- * @param inData the array containing the pixel value
- * @return the value of the blue component of the specified pixel.
- * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
- * large enough to hold a pixel value for this color model
- * @throws ClassCastException if <code>inData</code> is not a
- * primitive array of type <code>transferType</code>
- * @throws UnsupportedOperationException if this <code>transferType</code>
- * is not supported by this color model
- */
- public int getBlue(Object inData) {
- int pixel=0;
- 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] & 0xffff;
- 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 getBlue(pixel);
- }
-
- /**
- * 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 <code>transferType</code> passed in as an object
- * reference.
- * If <code>inData</code> is not a primitive array of type
- * <code>transferType</code>, a <code>ClassCastException</code> is
- * thrown. An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>inData</code> is not large enough to hold a pixel
- * value for this <code>ColorModel</code>. Since
- * <code>DirectColorModel</code> can be subclassed, subclasses inherit
- * the implementation of this method and if they don't override it
- * then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- * If this <code>transferType</code> is not supported, an
- * <code>UnsupportedOperationException</code> is thrown.
- * @param inData the specified pixel
- * @return the alpha component of the specified pixel, scaled from
- * 0 to 255.
- * @exception <code>ClassCastException</code> if <code>inData</code>
- * is not a primitive array of type <code>transferType</code>
- * @exception <code>ArrayIndexOutOfBoundsException</code> if
- * <code>inData</code> is not large enough to hold a pixel value
- * for this <code>ColorModel</code>
- * @exception <code>UnsupportedOperationException</code> if this
- * <code>tranferType</code> is not supported by this
- * <code>ColorModel</code>
- */
- public int getAlpha(Object inData) {
- int pixel=0;
- 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] & 0xffff;
- 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 getAlpha(pixel);
- }
-
- /**
- * 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 <code>transferType</code> passed in as an object
- * reference. If <code>inData</code> is not a primitive array of type
- * <code>transferType</code>, a <code>ClassCastException</code> is
- * thrown. An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>inData</code> is not large enough to hold a pixel
- * value for this <code>ColorModel</code>.
- * The returned value is in a non pre-multiplied format. Thus, if
- * the alpha is premultiplied, this method divides it out of the
- * color components. If the alpha value is 0, for example, the color
- * values is 0. Since <code>DirectColorModel</code> can be
- * subclassed, subclasses inherit the implementation of this method
- * and if they don't override it then
- * they throw an exception if they use an unsupported
- * <code>transferType</code>.
- *
- * @param inData the specified pixel
- * @return the color and alpha components of the specified pixel.
- * @exception UnsupportedOperationException if this
- * <code>transferType</code> is not supported by this
- * <code>ColorModel</code>
- * @see ColorModel#getRGBdefault
- */
- public int getRGB(Object inData) {
- int pixel=0;
- 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] & 0xffff;
- 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 getRGB(pixel);
- }
-
- /**
- * Returns a data element array representation of a pixel in this
- * <code>ColorModel</code>, given an integer pixel representation in the
- * default RGB color model.
- * This array can then be passed to the <code>setDataElements</code>
- * method of a <code>WritableRaster</code> object. If the pixel variable
- * is <code>null</code>, a new array is allocated. If <code>pixel</code>
- * is not <code>null</code>, it must be a primitive array of type
- * <code>transferType</code> otherwise, a
- * <code>ClassCastException</code> is thrown. An
- * <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>pixel</code> is not large enough to hold a pixel
- * value for this <code>ColorModel</code>. The pixel array is returned.
- * Since <code>DirectColorModel</code> can be subclassed, subclasses
- * inherit the implementation of this method and if they don't
- * override it then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- *
- * @param rgb the integer pixel representation in the default RGB
- * color model
- * @param pixel the specified pixel
- * @return an array representation of the specified pixel in this
- * <code>ColorModel</code>
- * @exception ClassCastException if <code>pixel</code>
- * is not a primitive array of type <code>transferType</code>
- * @exception ArrayIndexOutOfBoundsException if
- * <code>pixel</code> is not large enough to hold a pixel value
- * for this <code>ColorModel</code>
- * @exception UnsupportedOperationException if this
- * <code>transferType</code> is not supported by this
- * <code>ColorModel</code>
- * @see WritableRaster#setDataElements
- * @see SampleModel#setDataElements
- */
- public Object getDataElements(int rgb, Object pixel) {
- //REMIND: maybe more efficient not to use int array for
- //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT
- int i;
- int intpixel[] = null;
- if (transferType == DataBuffer.TYPE_INT &&
- pixel != null) {
- intpixel = (int[])pixel;
- } else {
- intpixel = new int[1];
- }
-
- ColorModel defaultCM = ColorModel.getRGBdefault();
- if (this == defaultCM || equals(defaultCM)) {
- intpixel[0] = rgb;
- } else if (is_sRGB) {
- double normAlpha = 1.;
- int c;
- if (supportsAlpha && isAlphaPremultiplied) {
- normAlpha = ((rgb>>24)&0xff)/255.;
- }
-
- int[] shifts = {16, 8, 0, 24};
-
- intpixel[0] = 0;
- for (i=0; i < 3; i++) {
- c = (int)(((rgb>>shifts[i])&0xff)*normAlphascaleFactors[i]);
- intpixel[0] |= (c << maskOffsets[i]) & maskArray[i];
- }
- if (supportsAlpha) {
- c = (int) (((rgb>>shifts[3])&0xff) / scaleFactors[3]);
- intpixel[0] |= (c << maskOffsets[3]) & maskArray[3];
- }
- } else {
- int components[] = defaultCM.getComponents(rgb, null, 0);
- float norm[] = defaultCM.getNormalizedComponents(components, 0,
- null, 0);
- float rgbf[] = colorSpace.fromRGB(norm);
- double normAlpha = 1.;
- int c;
- if (supportsAlpha && isAlphaPremultiplied) {
- normAlpha = ((rgb>>24)&0xff)/255.;
- }
-
- intpixel[0] = 0;
- for (i=0; i < 3; i++) {
- c = (int) ((rgbf[i] * 255.0)*normAlphascaleFactors[i]);
- intpixel[0] |= (c << maskOffsets[i]) & maskArray[i];
- }
- if (supportsAlpha) {
- c = (int) (((rgb>>24)&0xff) / scaleFactors[3]);
- intpixel[0] |= (c << maskOffsets[3]) & maskArray[3];
- }
- }
- switch (transferType) {
- case DataBuffer.TYPE_BYTE: {
- byte bdata[];
- if (pixel == null) {
- bdata = new byte[1];
- } else {
- bdata = (byte[])pixel;
- }
- bdata[0] = (byte)(0xff&intpixel[0]);
- return bdata;
- }
- case DataBuffer.TYPE_USHORT:{
- short sdata[];
- if (pixel == null) {
- sdata = new short[1];
- } else {
- sdata = (short[])pixel;
- }
- sdata[0] = (short)(intpixel[0]&0xffff);
- return sdata;
- }
- case DataBuffer.TYPE_INT:
- return intpixel;
- }
- throw new UnsupportedOperationException("This method has not been "+
- "implemented for transferType " + transferType);
-
- }
-
- /**
- * Returns an array of unnormalized color/alpha components given a pixel
- * in this <code>ColorModel</code>. The pixel value is specified as an
- * <code>int</code>. If the <code>components</code> array is
- * <code>null</code>, a new array is allocated. The
- * <code>components</code> array is returned. Color/alpha components are
- * stored in the <code>components</code> array starting at
- * <code>offset</code>, even if the array is allocated by this method.
- * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * <code>components</code> array is not <code>null</code> and is not large
- * enough to hold all the color and alpha components, starting at
- * <code>offset</code>.
- * @param pixel the specified pixel
- * @param components the array to receive the color and alpha
- * components of the specified pixel
- * @param offset the offset into the <code>components</code> array at
- * which to start storing the color and alpha components
- * @return an array containing the color and alpha components of the
- * specified pixel starting at the specified offset.
- */
- final public int[] getComponents(int pixel, int[] components, int offset) {
- if (components == null) {
- components = new int[offset+numComponents];
- }
-
- for (int i=0; i < numComponents; i++) {
- components[offset+i] = (pixel & maskArray[i]) >>> maskOffsets[i];
- }
-
- return components;
- }
-
- /**
- * Returns an array of unnormalized color/alpha components given a pixel
- * in this <code>ColorModel</code>. The pixel value is specified by an
- * array of data elements of type <code>transferType</code> passed in as
- * an object reference. If <code>pixel</code> is not a primitive array
- * of type <code>transferType</code>, a <code>ClassCastException</code>
- * is thrown. An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if <code>pixel</code> is not large enough to hold a
- * pixel value for this <code>ColorModel</code>. If the
- * <code>components</code> array is <code>null</code>, a new
- * array is allocated. The <code>components</code> array is returned.
- * Color/alpha components are stored in the <code>components</code> array
- * starting at <code>offset</code>, even if the array is allocated by
- * this method. An <code>ArrayIndexOutOfBoundsException</code>
- * is thrown if the <code>components</code> array is not
- * <code>null</code> and is not large enough to hold all the color and
- * alpha components, starting at <code>offset</code>.
- * Since <code>DirectColorModel</code> can be subclassed, subclasses
- * inherit the implementation of this method and if they don't
- * override it then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- * @param pixel the specified pixel
- * @param components the array to receive the color and alpha
- * components of the specified pixel
- * @param offset the offset into the <code>components</code> array at
- * which to start storing the color and alpha components
- * @exception ClassCastException if <code>pixel</code>
- * is not a primitive array of type <code>transferType</code>
- * @exception ArrayIndexOutOfBoundsException if
- * <code>pixel</code> is not large enough to hold a pixel value
- * for this <code>ColorModel</code>, or if <code>components</code>
- * is not <code>null</code> and is not large enough to hold all the
- * color and alpha components, starting at <code>offset</code>
- * @exception UnsupportedOperationException if this
- * <code>transferType</code> is not supported by this
- * color model
- */
- final public int[] getComponents(Object pixel, int[] components,
- int offset) {
- int intpixel=0;
- 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);
- }
-
- /**
- * Creates a <code>WritableRaster</code> with the specified width and
- * height that has a data layout (<code>SampleModel</code>) compatible
- * with this <code>ColorModel</code>.
- * @param w the width to apply to the new <code>WritableRaster</code>
- * @param h the height to apply to the new <code>WritableRaster</code>
- * @return a <code>WritableRaster</code> object with the specified
- * width and height.
- * @throws IllegalArgumentException if <code>w</code> or <code>h</code>
- * is less than or equal to zero
- * @see WritableRaster
- * @see SampleModel
- */
- final public WritableRaster createCompatibleWritableRaster (int w,
- int h) {
- int[] bandmasks;
- if (supportsAlpha) {
- bandmasks = new int[4];
- bandmasks[3] = alpha_mask;
- }
- else {
- bandmasks = new int[3];
- }
- bandmasks[0] = red_mask;
- bandmasks[1] = green_mask;
- bandmasks[2] = blue_mask;
-
- if (pixel_bits > 16) {
- return Raster.createPackedRaster(DataBuffer.TYPE_INT,
- w,h,bandmasks,null);
- }
- else if (pixel_bits > 8) {
- return Raster.createPackedRaster(DataBuffer.TYPE_USHORT,
- w,h,bandmasks,null);
- }
- else {
- return Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
- w,h,bandmasks,null);
- }
- }
-
- /**
- * Returns a pixel value represented as an <code>int</code> in this
- * <code>ColorModel</code>, given an array of unnormalized color/alpha
- * components. An <code>ArrayIndexOutOfBoundsException</code> is
- * thrown if the <code>components</code> array is
- * not large enough to hold all the color and alpha components, starting
- * at <code>offset</code>.
- * @param components an array of unnormalized color and alpha
- * components
- * @param offset the index into <code>components</code> at which to
- * begin retrieving the color and alpha components
- * @return an <code>int</code> pixel value in this
- * <code>ColorModel</code> corresponding to the specified components.
- * @exception <code>ArrayIndexOutOfBoundsException</code> if
- * the <code>components</code> array is not large enough to
- * hold all of the color and alpha components starting at
- * <code>offset</code>
- */
- public int getDataElement(int[] components, int offset) {
- int pixel = 0;
- for (int i=0; i < numComponents; i++) {
- pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]);
- }
- return pixel;
- }
-
- /**
- * Returns a data element array representation of a pixel in this
- * <code>ColorModel</code>, given an array of unnormalized color/alpha
- * components.
- * This array can then be passed to the <code>setDataElements</code>
- * method of a <code>WritableRaster</code> object.
- * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
- * <code>components</code> array
- * is not large enough to hold all the color and alpha components,
- * starting at offset. If the <code>obj</code> variable is
- * <code>null</code>, a new array is allocated. If <code>obj</code> is
- * not <code>null</code>, it must be a primitive array
- * of type <code>transferType</code> otherwise, a
- * <code>ClassCastException</code> is thrown.
- * An <code>ArrayIndexOutOfBoundsException</code> is thrown if
- * <code>obj</code> is not large enough to hold a pixel value for this
- * <code>ColorModel</code>.
- * Since <code>DirectColorModel</code> can be subclassed, subclasses
- * inherit the implementation of this method and if they don't
- * override it then they throw an exception if they use an unsupported
- * <code>transferType</code>.
- * @param components an array of unnormalized color and alpha
- * components
- * @param offset the index into <code>components</code> at which to
- * begin retrieving color and alpha components
- * @param obj the <code>Object</code> representing an array of color
- * and alpha components
- * @return an <code>Object</code> representing an array of color and
- * alpha components.
- * @exception <code>ClassCastException</code> if <code>obj</code>
- * is not a primitive array of type <code>transferType</code>
- * @exception <code>ArrayIndexOutOfBoundsException</code> if
- * <code>obj</code> is not large enough to hold a pixel value
- * for this <code>ColorModel</code> or the <code>components</code>
- * array is not large enough to hold all of the color and alpha
- * components starting at <code>offset</code>
- * @exception UnsupportedOperationException if this
- * <code>transferType</code> is not supported by this
- * color model
- * @see WritableRaster#setDataElements
- * @see SampleModel#setDataElements
- */
- public Object getDataElements(int[] components, int offset, Object obj) {
- int pixel = 0;
- for (int i=0; i < numComponents; i++) {
- pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]);
- }
- switch (transferType) {
- case DataBuffer.TYPE_BYTE:
- if (obj instanceof byte[]) {
- byte bdata[] = (byte[])obj;
- bdata[0] = (byte)(pixel&0xff);
- return bdata;
- } else {
- byte bdata[] = {(byte)(pixel&0xff)};
- return bdata;
- }
- case DataBuffer.TYPE_USHORT:
- if (obj instanceof short[]) {
- short sdata[] = (short[])obj;
- sdata[0] = (short)(pixel&0xffff);
- return sdata;
- } else {
- short sdata[] = {(short)(pixel&0xffff)};
- return sdata;
- }
- case DataBuffer.TYPE_INT:
- if (obj instanceof int[]) {
- int idata[] = (int[])obj;
- idata[0] = pixel;
- return idata;
- } else {
- int idata[] = {pixel};
- return idata;
- }
- default:
- throw new ClassCastException("This method has not been "+
- "implemented for transferType " + transferType);
- }
- }
-
- /**
- * Forces the raster data to match the state specified in the
- * <code>isAlphaPremultiplied</code> variable, assuming the data is
- * currently correctly described by this <code>ColorModel</code>. 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
- * <code>ColorModel</code> with the <code>isAlphaPremultiplied</code>
- * flag set appropriately. This method will throw a
- * <code>UnsupportedOperationException</code> if this transferType is
- * not supported by this <code>ColorModel</code>. Since
- * <code>ColorModel</code> can be subclassed, subclasses inherit the
- * implementation of this method and if they don't override it then
- * they throw an exception if they use an unsupported transferType.
- *
- * @param raster the <code>WritableRaster</code> data
- * @param isAlphaPremultiplied <code>true</code> if the alpha is
- * premultiplied; <code>false</code> otherwise
- * @return a <code>ColorModel</code> object that represents the
- * coerced data.
- * @exception UnsupportedOperationException if this
- * <code>transferType</code> is not supported by this
- * color model
- */
- final public ColorModel coerceData (WritableRaster raster,
- boolean isAlphaPremultiplied)
- {
- if (!supportsAlpha ||
- this.isAlphaPremultiplied() == isAlphaPremultiplied) {
- return this;
- }
-
- int w = raster.getWidth();
- int h = raster.getHeight();
- int aIdx = numColorComponents;
- float normAlpha;
- int alphaScale = (1 << nBits[aIdx]) - 1;
-
- int rminX = raster.getMinX();
- int rY = raster.getMinY();
- int rX;
- int pixel[] = null;
-
- if (isAlphaPremultiplied) {
- // Must mean that we are currently not premultiplied so
- // multiply by alpha
- switch (transferType) {
- case DataBuffer.TYPE_BYTE: {
- for (int y = 0; y < h; y++, rY++) {
- rX = rminX;
- for (int x = 0; x < w; x++, rX++) {
- pixel = raster.getPixel(rX, rY, pixel);
- normAlpha = pixel[aIdx]/alphaScale;
- if (normAlpha != 0.f) {
- for (int c=0; c < aIdx; c++) {
- pixel[c] = (int)(pixel[c]*normAlpha);
- }
- raster.setPixel(rX, rY, pixel);
- }
- }
- }
- }
- break;
- case DataBuffer.TYPE_USHORT: {
- for (int y = 0; y < h; y++, rY++) {
- rX = rminX;
- for (int x = 0; x < w; x++, rX++) {
- pixel = raster.getPixel(rX, rY, pixel);
- normAlpha = pixel[aIdx]/alphaScale;
- if (normAlpha != 0.f) {
- for (int c=0; c < aIdx; c++) {
- pixel[c] = (int)(pixel[c]*normAlpha);
- }
- raster.setPixel(rX, rY, pixel);
- }
- }
- }
- }
- break;
- case DataBuffer.TYPE_INT: {
- for (int y = 0; y < h; y++, rY++) {
- rX = rminX;
- for (int x = 0; x < w; x++, rX++) {
- pixel = raster.getPixel(rX, rY, pixel);
- normAlpha = pixel[aIdx]/alphaScale;
- if (normAlpha != 0.f) {
- for (int c=0; c < aIdx; c++) {
- pixel[c] = (int)(pixel[c]*normAlpha);
- }
- raster.setPixel(rX, rY, pixel);
- }
- }
- }
- }
- break;
- default:
- throw new UnsupportedOperationException("This method has not been "+
- "implemented for transferType " + transferType);
- }
- }
- else {
- // We are premultiplied and want to divide it out
- switch (transferType) {
- case DataBuffer.TYPE_BYTE: {
- for (int y = 0; y < h; y++, rY++) {
- rX = rminX;
- for (int x = 0; x < w; x++, rX++) {
- pixel = raster.getPixel(rX, rY, pixel);
- normAlpha = pixel[aIdx]/alphaScale;
- if (normAlpha != 0) {
- for (int c=0; c < aIdx; c++) {
- pixel[c] /= normAlpha;
- }
- }
- raster.setPixel(rX, rY, pixel);
- }
- }
- }
- break;
- case DataBuffer.TYPE_USHORT: {
- for (int y = 0; y < h; y++, rY++) {
- rX = rminX;
- for (int x = 0; x < w; x++, rX++) {
- pixel = raster.getPixel(rX, rY, pixel);
- normAlpha = pixel[aIdx]/alphaScale;
- if (normAlpha != 0) {
- for (int c=0; c < aIdx; c++) {
- pixel[c] /= normAlpha;
- }
- }
- raster.setPixel(rX, rY, pixel);
- }
- }
- }
- break;
- case DataBuffer.TYPE_INT: {
- for (int y = 0; y < h; y++, rY++) {
- rX = rminX;
- for (int x = 0; x < w; x++, rX++) {
- pixel = raster.getPixel(rX, rY, pixel);
- normAlpha = pixel[aIdx]/alphaScale;
- if (normAlpha != 0) {
- for (int c=0; c < aIdx; c++) {
- pixel[c] /= normAlpha;
- }
- }
- raster.setPixel(rX, rY, pixel);
- }
- }
- }
- break;
- default:
- throw new UnsupportedOperationException("This method has not been "+
- "implemented for transferType " + transferType);
- }
- }
-
- // Return a new color model
- return new DirectColorModel(colorSpace, pixel_bits, maskArray[0],
- maskArray[1], maskArray[2], maskArray[3],
- isAlphaPremultiplied,
- transferType);
-
- }
-
- /**
- * Returns <code>true</code> if <code>raster</code> is compatible
- * with this <code>ColorModel</code> and <code>false</code> if it is
- * not.
- * @param raster the {@link Raster} object to test for compatibility
- * @return <code>true</code> if <code>raster</code> is compatible
- * with this <code>ColorModel</code> <code>false</code> otherwise.
- */
- public boolean isCompatibleRaster(Raster raster) {
- SampleModel sm = raster.getSampleModel();
- SinglePixelPackedSampleModel spsm;
- if (sm instanceof SinglePixelPackedSampleModel) {
- spsm = (SinglePixelPackedSampleModel) sm;
- }
- else {
- return false;
- }
- if (spsm.getNumBands() != getNumComponents()) {
- return false;
- }
-
- int[] bitMasks = spsm.getBitMasks();
- for (int i=0; i<numComponents; i++) {
- if (bitMasks[i] != maskArray[i]) {
- return false;
- }
- }
-
- return (raster.getTransferType() == transferType);
- }
-
- private void setFields() {
- // Set the private fields
- // REMIND: Get rid of these from the native code
- red_mask = maskArray[0];
- red_offset = maskOffsets[0];
- green_mask = maskArray[1];
- green_offset = maskOffsets[1];
- blue_mask = maskArray[2];
- blue_offset = maskOffsets[2];
- if (nBits[0] < 8) {
- red_scale = (1 << nBits[0]) - 1;
- }
- if (nBits[1] < 8) {
- green_scale = (1 << nBits[1]) - 1;
- }
- if (nBits[2] < 8) {
- blue_scale = (1 << nBits[2]) - 1;
- }
- if (supportsAlpha) {
- alpha_mask = maskArray[3];
- alpha_offset = maskOffsets[3];
- if (nBits[3] < 8) {
- alpha_scale = (1 << nBits[3]) - 1;
- }
- }
- }
-
- /**
- * Returns a <code>String</code> that represents this
- * <code>DirectColorModel</code>.
- * @return a <code>String</code> representing this
- * <code>DirectColorModel</code>.
- */
- public String toString() {
- return new String("DirectColorModel: rmask="
- +Integer.toHexString(red_mask)+" gmask="
- +Integer.toHexString(green_mask)+" bmask="
- +Integer.toHexString(blue_mask)+" amask="
- +Integer.toHexString(alpha_mask));
- }
- }
-