/*
* Copyright (c) 1995, 2013, 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 <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.
* In addition, for each component of the ColorSpace, the minimum
* normalized component value obtained via the <code>getMinValue()</code>
* method of ColorSpace must be 0.0, and the maximum value obtained via
* the <code>getMaxValue()</code> 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 <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
*
*/
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 <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
* 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 <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
* @throws IllegalArgumentException if <code>space</code> 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 <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);
}
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 <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) {
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 <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) {
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 <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) {
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 <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.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 <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 ||
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 <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 ClassCastException if <code>inData</code>
* is not a primitive array of type <code>transferType</code>
* @exception ArrayIndexOutOfBoundsException if
* <code>inData</code> is not large enough to hold a pixel value
* for this <code>ColorModel</code>
* @exception UnsupportedOperationException 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
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<<
nBits[3]) - 1)) + 0.5f);
if (
alp > ((1<<
nBits[3]) - 1)) {
// fix 4412670 - see comment below
alp = (1<<
nBits[3]) - 1;
}
}
intpixel[0] =
alp <<
maskOffsets[3];
}
if (
nBits[0] !=
precision) {
red = (int) ((
red *
factor * ((1<<
nBits[0]) - 1)) + 0.5f);
}
if (
nBits[1] !=
precision) {
grn = (int) ((
grn *
factor * ((1<<
nBits[1]) - 1)) + 0.5f);
}
if (
nBits[2] !=
precision) {
blu = (int) ((
blu *
factor * ((1<<
nBits[2]) - 1)) + 0.5f);
}
} else {
// Need to convert the color
float[]
norm = new float[3];
float
factor = 1.0f / 255.0f;
norm[0] =
red *
factor;
norm[1] =
grn *
factor;
norm[2] =
blu *
factor;
norm =
colorSpace.
fromRGB(
norm);
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
if (
isAlphaPremultiplied) {
factor *=
alp;
for (int
i = 0;
i < 3;
i++) {
norm[
i] *=
factor;
}
}
if (
nBits[3] != 8) {
alp = (int)
((
alp * (1.0f / 255.0f) * ((1<<
nBits[3]) - 1)) + 0.5f);
if (
alp > ((1<<
nBits[3]) - 1)) {
// fix 4412670 - see comment below
alp = (1<<
nBits[3]) - 1;
}
}
intpixel[0] =
alp <<
maskOffsets[3];
}
red = (int) ((
norm[0] * ((1<<
nBits[0]) - 1)) + 0.5f);
grn = (int) ((
norm[1] * ((1<<
nBits[1]) - 1)) + 0.5f);
blu = (int) ((
norm[2] * ((1<<
nBits[2]) - 1)) + 0.5f);
}
if (
maxBits > 23) {
// fix 4412670 - for components of 24 or more bits
// some calculations done above with float precision
// may lose enough precision that the integer result
// overflows nBits, so we need to clamp.
if (
red > ((1<<
nBits[0]) - 1)) {
red = (1<<
nBits[0]) - 1;
}
if (
grn > ((1<<
nBits[1]) - 1)) {
grn = (1<<
nBits[1]) - 1;
}
if (
blu > ((1<<
nBits[2]) - 1)) {
blu = (1<<
nBits[2]) - 1;
}
}
intpixel[0] |= (
red <<
maskOffsets[0]) |
(
grn <<
maskOffsets[1]) |
(
blu <<
maskOffsets[2]);
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
* @return an array containing the color and alpha components of the
* specified pixel starting at the specified offset.
* @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) {
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 <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 ArrayIndexOutOfBoundsException 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 ClassCastException if <code>obj</code>
* is not a primitive array of type <code>transferType</code>
* @exception ArrayIndexOutOfBoundsException 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;
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 <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));
}
}