/*
* Copyright (c) 1995, 2001, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.awt.image;
import java.awt.color.ColorSpace;
import java.awt.Transparency;
/**
* The DirectColorModel
class is a ColorModel
* 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.
* In addition, for each component of the ColorSpace, the minimum
* normalized component value obtained via the getMinValue()
* method of ColorSpace must be 0.0, and the maximum value obtained via
* the getMaxValue()
method must be 1.0 (these min/max
* values are typical for RGB spaces).
* 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 transferType
, 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:
*
* 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 DirectColorModel
is
* typically used with image data which uses masks to define packed
* samples. For example, a DirectColorModel
can be used in
* conjunction with a SinglePixelPackedSampleModel
to
* construct a {@link BufferedImage}. Normally the masks used by the
* {@link SampleModel} and the ColorModel
would be the
* same. However, if they are different, the color interpretation
* of pixel data will be done according to the masks of the
* ColorModel
.
*
* 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 IllegalArgumentException
* due to an invalid pixel value.
*
* This color model is similar to an X11 TrueColor visual.
* The default RGB ColorModel specified by the
* {@link ColorModel#getRGBdefault() getRGBdefault} method is a
* DirectColorModel
with the following parameters:
*
* 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 **
* 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
*
*/
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;
private boolean is_LinearRGB;
private int lRGBprecision;
private byte[] tosRGB8LUT;
private byte[] fromsRGB8LUT8;
private short[] fromsRGB8LUT16;
/**
* Constructs a DirectColorModel
from the specified masks
* that indicate which bits in an int
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 int
pixel representation.
* The ColorSpace
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 DirectColorModel
from the specified masks
* that indicate which bits in an int
pixel representation
* contain the red, green and blue color samples and the alpha sample,
* if present. If amask
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 int
pixel representation. Alpha, if present, is not
* premultiplied. The ColorSpace
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 DirectColorModel
from the specified
* parameters. Color components are in the specified
* ColorSpace
, which must be of type ColorSpace.TYPE_RGB
* and have minimum normalized component values which are all 0.0
* and maximum values which are all 1.0.
* The masks specify which bits in an int
pixel
* representation contain the red, green and blue color samples and
* the alpha sample, if present. If amask
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 int
pixel
* representation. If there is alpha, the boolean
* isAlphaPremultiplied
specifies how to interpret
* color and alpha samples in pixel values. If the boolean
* is true
, color samples are assumed to have been
* multiplied by the alpha sample. The transparency 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 ColorSpace
* @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 true
if color samples are
* premultiplied by the alpha sample; false
otherwise
* @param transferType the type of array used to represent pixel values
* @throws IllegalArgumentException if space
is not a
* TYPE_RGB space or if the min/max normalized component
* values are not 0.0/1.0.
*/
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);
if (ColorModel.isLinearRGBspace(colorSpace)) {
is_LinearRGB = true;
if (maxBits <= 8) {
lRGBprecision = 8;
tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT();
fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT();
} else {
lRGBprecision = 16;
tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT();
fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT();
}
} else if (!is_sRGB) {
for (int i = 0; i < 3; i++) {
// super constructor checks that space is TYPE_RGB
// check here that min/max are all 0.0/1.0
if ((space.getMinValue(i) != 0.0f) ||
(space.getMaxValue(i) != 1.0f)) {
throw new IllegalArgumentException(
"Illegal min/max RGB component value");
}
}
}
setFields();
}
/**
* Returns the mask indicating which bits in an int
pixel
* representation contain the red color component.
* @return the mask, which indicates which bits of the int
* pixel representation contain the red color sample.
*/
final public int getRedMask() {
return maskArray[0];
}
/**
* Returns the mask indicating which bits in an int
pixel
* representation contain the green color component.
* @return the mask, which indicates which bits of the int
* pixel representation contain the green color sample.
*/
final public int getGreenMask() {
return maskArray[1];
}
/**
* Returns the mask indicating which bits in an int
pixel
* representation contain the blue color component.
* @return the mask, which indicates which bits of the int
* pixel representation contain the blue color sample.
*/
final public int getBlueMask() {
return maskArray[2];
}
/**
* Returns the mask indicating which bits in an int
pixel
* representation contain the alpha component.
* @return the mask, which indicates which bits of the int
* 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);
}
private int getsRGBComponentFromsRGB(int pixel, int idx) {
int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]);
if (isAlphaPremultiplied) {
int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
c = (a == 0) ? 0 :
(int) (((c * scaleFactors[idx]) * 255.0f /
(a * scaleFactors[3])) + 0.5f);
} else if (scaleFactors[idx] != 1.0f) {
c = (int) ((c * scaleFactors[idx]) + 0.5f);
}
return c;
}
private int getsRGBComponentFromLinearRGB(int pixel, int idx) {
int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]);
if (isAlphaPremultiplied) {
float factor = (float) ((1 << lRGBprecision) - 1);
int a = ((pixel & maskArray[3]) >>> maskOffsets[3]);
c = (a == 0) ? 0 :
(int) (((c * scaleFactors[idx]) * factor /
(a * scaleFactors[3])) + 0.5f);
} else if (nBits[idx] != lRGBprecision) {
if (lRGBprecision == 16) {
c = (int) ((c * scaleFactors[idx] * 257.0f) + 0.5f);
} else {
c = (int) ((c * scaleFactors[idx]) + 0.5f);
}
}
// now range of c is 0-255 or 0-65535, depending on lRGBprecision
return tosRGB8LUT[c] & 0xff;
}
/**
* Returns the red color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace
, sRGB. A
* color conversion is done if necessary. The pixel value is specified
* as an int
.
* The returned value 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 ColorSpace
.
*/
final public int getRed(int pixel) {
if (is_sRGB) {
return getsRGBComponentFromsRGB(pixel, 0);
} else if (is_LinearRGB) {
return getsRGBComponentFromLinearRGB(pixel, 0);
}
float rgb[] = getDefaultRGBComponents(pixel);
return (int) (rgb[0] * 255.0f + 0.5f);
}
/**
* Returns the green color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace
, sRGB. A
* color conversion is done if necessary. The pixel value is specified
* as an int
.
* The returned value 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 ColorSpace
.
*/
final public int getGreen(int pixel) {
if (is_sRGB) {
return getsRGBComponentFromsRGB(pixel, 1);
} else if (is_LinearRGB) {
return getsRGBComponentFromLinearRGB(pixel, 1);
}
float rgb[] = getDefaultRGBComponents(pixel);
return (int) (rgb[1] * 255.0f + 0.5f);
}
/**
* Returns the blue color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace
, sRGB. A
* color conversion is done if necessary. The pixel value is specified
* as an int
.
* The returned value 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 ColorSpace
.
*/
final public int getBlue(int pixel) {
if (is_sRGB) {
return getsRGBComponentFromsRGB(pixel, 2);
} else if (is_LinearRGB) {
return getsRGBComponentFromLinearRGB(pixel, 2);
}
float rgb[] = getDefaultRGBComponents(pixel);
return (int) (rgb[2] * 255.0f + 0.5f);
}
/**
* Returns the alpha component for the specified pixel, scaled
* from 0 to 255. The pixel value is specified as an int
.
* @param pixel the specified pixel
* @return the value of the alpha component of pixel
* 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.0f) {
a = (int)(a * scaleFactors[3] + 0.5f);
}
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 int
.
* 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 || is_LinearRGB) {
return (getAlpha(pixel) << 24)
| (getRed(pixel) << 16)
| (getGreen(pixel) << 8)
| (getBlue(pixel) << 0);
}
float rgb[] = getDefaultRGBComponents(pixel);
return (getAlpha(pixel) << 24)
| (((int) (rgb[0] * 255.0f + 0.5f)) << 16)
| (((int) (rgb[1] * 255.0f + 0.5f)) << 8)
| (((int) (rgb[2] * 255.0f + 0.5f)) << 0);
}
/**
* Returns 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. 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 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
. Since
* DirectColorModel
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
.
* An UnsupportedOperationException
is thrown if this
* transferType
is not supported by this
* ColorModel
.
* @param inData the array containing the pixel value
* @return the value of the red component of the specified pixel.
* @throws ArrayIndexOutOfBoundsException if inData
is not
* large enough to hold a pixel value for this color model
* @throws ClassCastException if inData
is not a
* primitive array of type transferType
* @throws UnsupportedOperationException if this transferType
* 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 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. 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 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
. Since
* DirectColorModel
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
.
* An UnsupportedOperationException
is
* thrown if this transferType
is not supported by this
* ColorModel
.
* @param inData the array containing the pixel value
* @return the value of the green component of the specified pixel.
* @throws ArrayIndexOutOfBoundsException if inData
is not
* large enough to hold a pixel value for this color model
* @throws ClassCastException if inData
is not a
* primitive array of type transferType
* @throws UnsupportedOperationException if this transferType
* 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 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. 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 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
. Since
* DirectColorModel
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
.
* An UnsupportedOperationException
is
* thrown if this transferType
is not supported by this
* ColorModel
.
* @param inData the array containing the pixel value
* @return the value of the blue component of the specified pixel.
* @throws ArrayIndexOutOfBoundsException if inData
is not
* large enough to hold a pixel value for this color model
* @throws ClassCastException if inData
is not a
* primitive array of type transferType
* @throws UnsupportedOperationException if this transferType
* 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 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
. Since
* DirectColorModel
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
.
* If this transferType
is not supported, an
* UnsupportedOperationException
is thrown.
* @param inData the specified pixel
* @return the alpha component of the specified pixel, scaled from
* 0 to 255.
* @exception ClassCastException
if inData
* is not a primitive array of type transferType
* @exception ArrayIndexOutOfBoundsException
if
* inData
is not large enough to hold a pixel value
* for this ColorModel
* @exception UnsupportedOperationException
if this
* tranferType
is not supported by this
* ColorModel
*/
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 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 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 DirectColorModel
can be
* subclassed, subclasses inherit the implementation of this method
* and if they don't override it then
* they throw an exception if they use an unsupported
* transferType
.
*
* @param inData the specified pixel
* @return the color and alpha components of the specified pixel.
* @exception UnsupportedOperationException if this
* transferType
is not supported by this
* ColorModel
* @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
* ColorModel
, given an integer pixel representation in the
* default RGB color model.
* This array can then be passed to the setDataElements
* method of a WritableRaster
object. If the pixel variable
* is null
, a new array is allocated. If pixel
* is not null
, it must be a primitive array of type
* transferType
; otherwise, a
* ClassCastException
is thrown. An
* ArrayIndexOutOfBoundsException
is
* thrown if pixel
is not large enough to hold a pixel
* value for this ColorModel
. The pixel array is returned.
* Since DirectColorModel
can be subclassed, subclasses
* inherit the implementation of this method and if they don't
* override it then they throw an exception if they use an unsupported
* transferType
.
*
* @param rgb the integer pixel representation in the default RGB
* color model
* @param pixel the specified pixel
* @return an array representation of the specified pixel in this
* ColorModel
* @exception ClassCastException if pixel
* is not a primitive array of type transferType
* @exception ArrayIndexOutOfBoundsException if
* pixel
is not large enough to hold a pixel value
* for this ColorModel
* @exception UnsupportedOperationException if this
* transferType
is not supported by this
* ColorModel
* @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 intpixel[] = null;
if (transferType == DataBuffer.TYPE_INT &&
pixel != null) {
intpixel = (int[])pixel;
intpixel[0] = 0;
} else {
intpixel = new int[1];
}
ColorModel defaultCM = ColorModel.getRGBdefault();
if (this == defaultCM || equals(defaultCM)) {
intpixel[0] = rgb;
return intpixel;
}
int red, grn, blu, alp;
red = (rgb>>16) & 0xff;
grn = (rgb>>8) & 0xff;
blu = rgb & 0xff;
if (is_sRGB || is_LinearRGB) {
int precision;
float factor;
if (is_LinearRGB) {
if (lRGBprecision == 8) {
red = fromsRGB8LUT8[red] & 0xff;
grn = fromsRGB8LUT8[grn] & 0xff;
blu = fromsRGB8LUT8[blu] & 0xff;
precision = 8;
factor = 1.0f / 255.0f;
} else {
red = fromsRGB8LUT16[red] & 0xffff;
grn = fromsRGB8LUT16[grn] & 0xffff;
blu = fromsRGB8LUT16[blu] & 0xffff;
precision = 16;
factor = 1.0f / 65535.0f;
}
} else {
precision = 8;
factor = 1.0f / 255.0f;
}
if (supportsAlpha) {
alp = (rgb>>24) & 0xff;
if (isAlphaPremultiplied) {
factor *= (alp * (1.0f / 255.0f));
precision = -1; // force component calculations below
}
if (nBits[3] != 8) {
alp = (int)
((alp * (1.0f / 255.0f) * ((1<int
. If the components
array is
* null
, a new array is allocated. The
* components
array is 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
.
* @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.
*/
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 ColorModel
. The pixel value is specified by an
* array of data elements of type transferType
passed in as
* an object reference. If pixel
is not a primitive array
* of type transferType
, a ClassCastException
* is thrown. An ArrayIndexOutOfBoundsException
is
* thrown if pixel
is not large enough to hold a
* pixel value for this ColorModel
. If the
* components
array is null
, a new
* array is allocated. The components
array is 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 DirectColorModel
can be subclassed, subclasses
* inherit the implementation of this method and if they don't
* override it then they throw an exception if they use an unsupported
* transferType
.
* @param pixel the specified pixel
* @param components 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.
* @exception ClassCastException if pixel
* is not a primitive array of type transferType
* @exception ArrayIndexOutOfBoundsException if
* pixel
is not large enough to hold a pixel value
* for this ColorModel
, or if components
* is not null
and is not large enough to hold all the
* color and alpha components, starting at offset
* @exception UnsupportedOperationException if this
* transferType
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 WritableRaster
with the specified width and
* height that has a data layout (SampleModel
) compatible
* with this ColorModel
.
* @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 IllegalArgumentException if w
or h
* is less than or equal to zero
* @see WritableRaster
* @see SampleModel
*/
final public WritableRaster createCompatibleWritableRaster (int w,
int h) {
if ((w <= 0) || (h <= 0)) {
throw new IllegalArgumentException("Width (" + w + ") and height (" + h +
") cannot be <= 0");
}
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 int
in this
* ColorModel
, given an array of unnormalized color/alpha
* components. An ArrayIndexOutOfBoundsException
is
* thrown if the components
array is
* not large enough to hold all the color and alpha components, starting
* at offset
.
* @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.
* @exception ArrayIndexOutOfBoundsException
if
* the components
array is not large enough to
* hold all of the color and alpha components starting at
* offset
*/
public int getDataElement(int[] components, int offset) {
int pixel = 0;
for (int i=0; i < numComponents; i++) {
pixel |= ((components[offset+i]<setDataElements
* method of a WritableRaster
object.
* 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 is 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 DirectColorModel
can be subclassed, subclasses
* inherit the implementation of this method and if they don't
* override it then they throw an exception if they use an unsupported
* transferType
.
* @param components an array of unnormalized color and alpha
* components
* @param offset the index into components
at which to
* begin retrieving color and alpha components
* @param obj the Object
representing an array of color
* and alpha components
* @return an Object
representing an array of color and
* alpha components.
* @exception ClassCastException
if obj
* is not a primitive array of type transferType
* @exception 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
* @exception UnsupportedOperationException if this
* transferType
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]<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 this transferType is
* not supported by this ColorModel
. Since
* ColorModel
can be subclassed, subclasses inherit the
* implementation of this method and if they don't override it then
* they throw an exception if they use an unsupported transferType.
*
* @param raster the WritableRaster
data
* @param isAlphaPremultiplied true
if the alpha is
* premultiplied; false
otherwise
* @return a ColorModel
object that represents the
* coerced data.
* @exception UnsupportedOperationException if this
* transferType
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;
float alphaScale = 1.0f / ((float) ((1 << nBits[aIdx]) - 1));
int rminX = raster.getMinX();
int rY = raster.getMinY();
int rX;
int pixel[] = null;
int zpixel[] = 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 +
0.5f);
}
raster.setPixel(rX, rY, pixel);
} else {
if (zpixel == null) {
zpixel = new int[numComponents];
java.util.Arrays.fill(zpixel, 0);
}
raster.setPixel(rX, rY, zpixel);
}
}
}
}
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 +
0.5f);
}
raster.setPixel(rX, rY, pixel);
} else {
if (zpixel == null) {
zpixel = new int[numComponents];
java.util.Arrays.fill(zpixel, 0);
}
raster.setPixel(rX, rY, zpixel);
}
}
}
}
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 +
0.5f);
}
raster.setPixel(rX, rY, pixel);
} else {
if (zpixel == null) {
zpixel = new int[numComponents];
java.util.Arrays.fill(zpixel, 0);
}
raster.setPixel(rX, rY, zpixel);
}
}
}
}
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.0f) {
float invAlpha = 1.0f / normAlpha;
for (int c=0; c < aIdx; c++) {
pixel[c] = (int) (pixel[c] * invAlpha +
0.5f);
}
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) {
float invAlpha = 1.0f / normAlpha;
for (int c=0; c < aIdx; c++) {
pixel[c] = (int) (pixel[c] * invAlpha +
0.5f);
}
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) {
float invAlpha = 1.0f / normAlpha;
for (int c=0; c < aIdx; c++) {
pixel[c] = (int) (pixel[c] * invAlpha +
0.5f);
}
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 true
if raster
is compatible
* with this ColorModel
and false
if it is
* not.
* @param raster the {@link Raster} object to test for compatibility
* @return true
if raster
is compatible
* with this ColorModel
; false
otherwise.
*/
public boolean isCompatibleRaster(Raster raster) {
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; iDirectColorModel
.
* @return a String
representing this
* DirectColorModel
.
*/
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));
}
}