/*
* Copyright (c) 1997, 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.color.
ICC_ColorSpace;
/**
* A <CODE>ColorModel</CODE> class that works with pixel values that
* represent color and alpha information as separate samples and that
* store each sample in a separate data element. This class can be
* used with an arbitrary <CODE>ColorSpace</CODE>. The number of
* color samples in the pixel values must be same as the number of
* color components in the <CODE>ColorSpace</CODE>. There may be a
* single alpha sample.
* <p>
* For those methods that use
* a primitive array pixel representation of type <CODE>transferType</CODE>,
* the array length is the same as the number of color and alpha samples.
* Color samples are stored first in the array followed by the alpha
* sample, if present. The order of the color samples is specified
* by the <CODE>ColorSpace</CODE>. Typically, this order reflects the
* name of the color space type. For example, for <CODE>TYPE_RGB</CODE>,
* index 0 corresponds to red, index 1 to green, and index 2 to blue.
* <p>
* The translation from pixel sample values to color/alpha components for
* display or processing purposes is based on a one-to-one correspondence of
* samples to components.
* Depending on the transfer type used to create an instance of
* <code>ComponentColorModel</code>, the pixel sample values
* represented by that instance may be signed or unsigned and may
* be of integral type or float or double (see below for details).
* The translation from sample values to normalized color/alpha components
* must follow certain rules. For float and double samples, the translation
* is an identity, i.e. normalized component values are equal to the
* corresponding sample values. For integral samples, the translation
* should be only a simple scale and offset, where the scale and offset
* constants may be different for each component. The result of
* applying the scale and offset constants is a set of color/alpha
* component values, which are guaranteed to fall within a certain
* range. Typically, the range for a color component will be the range
* defined by the <code>getMinValue</code> and <code>getMaxValue</code>
* methods of the <code>ColorSpace</code> class. The range for an
* alpha component should be 0.0 to 1.0.
* <p>
* Instances of <code>ComponentColorModel</code> created with transfer types
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* and <CODE>DataBuffer.TYPE_INT</CODE> have pixel sample values which
* are treated as unsigned integral values.
* The number of bits in a color or alpha sample of a pixel value might not
* be the same as the number of bits for the corresponding color or alpha
* sample passed to the
* <code>ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)</code>
* constructor. In
* that case, this class assumes that the least significant n bits of a sample
* value hold the component value, where n is the number of significant bits
* for the component passed to the constructor. It also assumes that
* any higher-order bits in a sample value are zero. Thus, sample values
* range from 0 to 2<sup>n</sup> - 1. This class maps these sample values
* to normalized color component values such that 0 maps to the value
* obtained from the <code>ColorSpace's</code> <code>getMinValue</code>
* method for each component and 2<sup>n</sup> - 1 maps to the value
* obtained from <code>getMaxValue</code>. To create a
* <code>ComponentColorModel</code> with a different color sample mapping
* requires subclassing this class and overriding the
* <code>getNormalizedComponents(Object, float[], int)</code> method.
* The mapping for an alpha sample always maps 0 to 0.0 and
* 2<sup>n</sup> - 1 to 1.0.
* <p>
* For instances with unsigned sample values,
* the unnormalized color/alpha component representation is only
* supported if two conditions hold. First, sample value value 0 must
* map to normalized component value 0.0 and sample value 2<sup>n</sup> - 1
* to 1.0. Second the min/max range of all color components of the
* <code>ColorSpace</code> must be 0.0 to 1.0. In this case, the
* component representation is the n least
* significant bits of the corresponding sample. Thus each component is
* an unsigned integral value between 0 and 2<sup>n</sup> - 1, where
* n is the number of significant bits for a particular component.
* If these conditions are not met, any method taking an unnormalized
* component argument will throw an <code>IllegalArgumentException</code>.
* <p>
* Instances of <code>ComponentColorModel</code> created with transfer types
* <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, and
* <CODE>DataBuffer.TYPE_DOUBLE</CODE> have pixel sample values which
* are treated as signed short, float, or double values.
* Such instances do not support the unnormalized color/alpha component
* representation, so any methods taking such a representation as an argument
* will throw an <code>IllegalArgumentException</code> when called on one
* of these instances. The normalized component values of instances
* of this class have a range which depends on the transfer
* type as follows: for float samples, the full range of the float data
* type; for double samples, the full range of the float data type
* (resulting from casting double to float); for short samples,
* from approximately -maxVal to +maxVal, where maxVal is the per
* component maximum value for the <code>ColorSpace</code>
* (-32767 maps to -maxVal, 0 maps to 0.0, and 32767 maps
* to +maxVal). A subclass may override the scaling for short sample
* values to normalized component values by overriding the
* <code>getNormalizedComponents(Object, float[], int)</code> method.
* For float and double samples, the normalized component values are
* taken to be equal to the corresponding sample values, and subclasses
* should not attempt to add any non-identity scaling for these transfer
* types.
* <p>
* Instances of <code>ComponentColorModel</code> created with transfer types
* <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, and
* <CODE>DataBuffer.TYPE_DOUBLE</CODE>
* use all the bits of all sample values. Thus all color/alpha components
* have 16 bits when using <CODE>DataBuffer.TYPE_SHORT</CODE>, 32 bits when
* using <CODE>DataBuffer.TYPE_FLOAT</CODE>, and 64 bits when using
* <CODE>DataBuffer.TYPE_DOUBLE</CODE>. When the
* <code>ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)</code>
* form of constructor is used with one of these transfer types, the
* bits array argument is ignored.
* <p>
* It is possible to have color/alpha sample values
* which cannot be reasonably interpreted as component values for rendering.
* This can happen when <code>ComponentColorModel</code> is subclassed to
* override the mapping of unsigned sample values to normalized color
* component values or when signed sample values outside a certain range
* are used. (As an example, specifying an alpha component as a signed
* short value outside the range 0 to 32767, normalized range 0.0 to 1.0, can
* lead to unexpected results.) It is the
* responsibility of applications to appropriately scale pixel data before
* rendering such that color components fall within the normalized range
* of the <code>ColorSpace</code> (obtained using the <code>getMinValue</code>
* and <code>getMaxValue</code> methods of the <code>ColorSpace</code> class)
* and the alpha component is between 0.0 and 1.0. If color or alpha
* component values fall outside these ranges, rendering results are
* indeterminate.
* <p>
* Methods that use a single int pixel representation throw
* an <CODE>IllegalArgumentException</CODE>, unless the number of components
* for the <CODE>ComponentColorModel</CODE> is one and the component
* value is unsigned -- in other words, a single color component using
* a transfer type of <CODE>DataBuffer.TYPE_BYTE</CODE>,
* <CODE>DataBuffer.TYPE_USHORT</CODE>, or <CODE>DataBuffer.TYPE_INT</CODE>
* and no alpha.
* <p>
* A <CODE>ComponentColorModel</CODE> can be used in conjunction with a
* <CODE>ComponentSampleModel</CODE>, a <CODE>BandedSampleModel</CODE>,
* or a <CODE>PixelInterleavedSampleModel</CODE> to construct a
* <CODE>BufferedImage</CODE>.
*
* @see ColorModel
* @see ColorSpace
* @see ComponentSampleModel
* @see BandedSampleModel
* @see PixelInterleavedSampleModel
* @see BufferedImage
*
*/
public class
ComponentColorModel extends
ColorModel {
/**
* <code>signed</code> is <code>true</code> for <code>short</code>,
* <code>float</code>, and <code>double</code> transfer types; it
* is <code>false</code> for <code>byte</code>, <code>ushort</code>,
* and <code>int</code> transfer types.
*/
private boolean
signed; // true for transfer types short, float, double
// false for byte, ushort, int
private boolean
is_sRGB_stdScale;
private boolean
is_LinearRGB_stdScale;
private boolean
is_LinearGray_stdScale;
private boolean
is_ICCGray_stdScale;
private byte[]
tosRGB8LUT;
private byte[]
fromsRGB8LUT8;
private short[]
fromsRGB8LUT16;
private byte[]
fromLinearGray16ToOtherGray8LUT;
private short[]
fromLinearGray16ToOtherGray16LUT;
private boolean
needScaleInit;
private boolean
noUnnorm;
private boolean
nonStdScale;
private float[]
min;
private float[]
diffMinMax;
private float[]
compOffset;
private float[]
compScale;
/**
* Constructs a <CODE>ComponentColorModel</CODE> from the specified
* parameters. Color components will be in the specified
* <CODE>ColorSpace</CODE>. The supported transfer types are
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>,
* <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>,
* and <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
* If not null, the <CODE>bits</CODE> array specifies the
* number of significant bits per color and alpha component and its
* length should be at least the number of components in the
* <CODE>ColorSpace</CODE> if there is no alpha
* information in the pixel values, or one more than this number if
* there is alpha information. When the <CODE>transferType</CODE> is
* <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>,
* or <CODE>DataBuffer.TYPE_DOUBLE</CODE> the <CODE>bits</CODE> array
* argument is ignored. <CODE>hasAlpha</CODE> indicates whether alpha
* information is present. If <CODE>hasAlpha</CODE> is true, then
* the boolean <CODE>isAlphaPremultiplied</CODE>
* 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 <CODE>transparency</CODE>
* specifies what alpha values can be represented by this color model.
* The acceptable <code>transparency</code> values are
* <CODE>OPAQUE</CODE>, <CODE>BITMASK</CODE> or <CODE>TRANSLUCENT</CODE>.
* The <CODE>transferType</CODE> is the type of primitive array used
* to represent pixel values.
*
* @param colorSpace The <CODE>ColorSpace</CODE> associated
* with this color model.
* @param bits The number of significant bits per component.
* May be null, in which case all bits of all
* component samples will be significant.
* Ignored if transferType is one of
* <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or
* <CODE>DataBuffer.TYPE_DOUBLE</CODE>,
* in which case all bits of all component
* samples will be significant.
* @param hasAlpha If true, this color model supports alpha.
* @param isAlphaPremultiplied If true, alpha is premultiplied.
* @param transparency Specifies what alpha values can be represented
* by this color model.
* @param transferType Specifies the type of primitive array used to
* represent pixel values.
*
* @throws IllegalArgumentException If the <CODE>bits</CODE> array
* argument is not null, its length is less than the number of
* color and alpha components, and transferType is one of
* <CODE>DataBuffer.TYPE_BYTE</CODE>,
* <CODE>DataBuffer.TYPE_USHORT</CODE>, or
* <CODE>DataBuffer.TYPE_INT</CODE>.
* @throws IllegalArgumentException If transferType is not one of
* <CODE>DataBuffer.TYPE_BYTE</CODE>,
* <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>,
* <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or
* <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*
* @see ColorSpace
* @see java.awt.Transparency
*/
public
ComponentColorModel (
ColorSpace colorSpace,
int[]
bits,
boolean
hasAlpha,
boolean
isAlphaPremultiplied,
int
transparency,
int
transferType) {
super (
bitsHelper(
transferType,
colorSpace,
hasAlpha),
bitsArrayHelper(
bits,
transferType,
colorSpace,
hasAlpha),
colorSpace,
hasAlpha,
isAlphaPremultiplied,
transparency,
transferType);
switch(
transferType) {
case
DataBuffer.
TYPE_BYTE:
case
DataBuffer.
TYPE_USHORT:
case
DataBuffer.
TYPE_INT:
signed = false;
needScaleInit = true;
break;
case
DataBuffer.
TYPE_SHORT:
signed = true;
needScaleInit = true;
break;
case
DataBuffer.
TYPE_FLOAT:
case
DataBuffer.
TYPE_DOUBLE:
signed = true;
needScaleInit = false;
noUnnorm = true;
nonStdScale = false;
break;
default:
throw new
IllegalArgumentException("This constructor is not "+
"compatible with transferType " +
transferType);
}
setupLUTs();
}
/**
* Constructs a <CODE>ComponentColorModel</CODE> from the specified
* parameters. Color components will be in the specified
* <CODE>ColorSpace</CODE>. The supported transfer types are
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>,
* <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>,
* and <CODE>DataBuffer.TYPE_DOUBLE</CODE>. The number of significant
* bits per color and alpha component will be 8, 16, 32, 16, 32, or 64,
* respectively. The number of color components will be the
* number of components in the <CODE>ColorSpace</CODE>. There will be
* an alpha component if <CODE>hasAlpha</CODE> is <CODE>true</CODE>.
* If <CODE>hasAlpha</CODE> is true, then
* the boolean <CODE>isAlphaPremultiplied</CODE>
* 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 <CODE>transparency</CODE>
* specifies what alpha values can be represented by this color model.
* The acceptable <code>transparency</code> values are
* <CODE>OPAQUE</CODE>, <CODE>BITMASK</CODE> or <CODE>TRANSLUCENT</CODE>.
* The <CODE>transferType</CODE> is the type of primitive array used
* to represent pixel values.
*
* @param colorSpace The <CODE>ColorSpace</CODE> associated
* with this color model.
* @param hasAlpha If true, this color model supports alpha.
* @param isAlphaPremultiplied If true, alpha is premultiplied.
* @param transparency Specifies what alpha values can be represented
* by this color model.
* @param transferType Specifies the type of primitive array used to
* represent pixel values.
*
* @throws IllegalArgumentException If transferType is not one of
* <CODE>DataBuffer.TYPE_BYTE</CODE>,
* <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>,
* <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or
* <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*
* @see ColorSpace
* @see java.awt.Transparency
* @since 1.4
*/
public
ComponentColorModel (
ColorSpace colorSpace,
boolean
hasAlpha,
boolean
isAlphaPremultiplied,
int
transparency,
int
transferType) {
this(
colorSpace, null,
hasAlpha,
isAlphaPremultiplied,
transparency,
transferType);
}
private static int
bitsHelper(int
transferType,
ColorSpace colorSpace,
boolean
hasAlpha) {
int
numBits =
DataBuffer.
getDataTypeSize(
transferType);
int
numComponents =
colorSpace.
getNumComponents();
if (
hasAlpha) {
++
numComponents;
}
return
numBits *
numComponents;
}
private static int[]
bitsArrayHelper(int[]
origBits,
int
transferType,
ColorSpace colorSpace,
boolean
hasAlpha) {
switch(
transferType) {
case
DataBuffer.
TYPE_BYTE:
case
DataBuffer.
TYPE_USHORT:
case
DataBuffer.
TYPE_INT:
if (
origBits != null) {
return
origBits;
}
break;
default:
break;
}
int
numBits =
DataBuffer.
getDataTypeSize(
transferType);
int
numComponents =
colorSpace.
getNumComponents();
if (
hasAlpha) {
++
numComponents;
}
int[]
bits = new int[
numComponents];
for (int
i = 0;
i <
numComponents;
i++) {
bits[
i] =
numBits;
}
return
bits;
}
private void
setupLUTs() {
// REMIND: there is potential to accelerate sRGB, LinearRGB,
// LinearGray, ICCGray, and non-ICC Gray spaces with non-standard
// scaling, if that becomes important
//
// NOTE: The is_xxx_stdScale and nonStdScale booleans are provisionally
// set here when this method is called at construction time. These
// variables may be set again when initScale is called later.
// When setupLUTs returns, nonStdScale is true if (the transferType
// is not float or double) AND (some minimum ColorSpace component
// value is not 0.0 OR some maximum ColorSpace component value
// is not 1.0). This is correct for the calls to
// getNormalizedComponents(Object, float[], int) from initScale().
// initScale() may change the value nonStdScale based on the
// return value of getNormalizedComponents() - this will only
// happen if getNormalizedComponents() has been overridden by a
// subclass to make the mapping of min/max pixel sample values
// something different from min/max color component values.
if (
is_sRGB) {
is_sRGB_stdScale = true;
nonStdScale = false;
} else if (
ColorModel.
isLinearRGBspace(
colorSpace)) {
// Note that the built-in Linear RGB space has a normalized
// range of 0.0 - 1.0 for each coordinate. Usage of these
// LUTs makes that assumption.
is_LinearRGB_stdScale = true;
nonStdScale = false;
if (
transferType ==
DataBuffer.
TYPE_BYTE) {
tosRGB8LUT =
ColorModel.
getLinearRGB8TosRGB8LUT();
fromsRGB8LUT8 =
ColorModel.
getsRGB8ToLinearRGB8LUT();
} else {
tosRGB8LUT =
ColorModel.
getLinearRGB16TosRGB8LUT();
fromsRGB8LUT16 =
ColorModel.
getsRGB8ToLinearRGB16LUT();
}
} else if ((
colorSpaceType ==
ColorSpace.
TYPE_GRAY) &&
(
colorSpace instanceof
ICC_ColorSpace) &&
(
colorSpace.
getMinValue(0) == 0.0f) &&
(
colorSpace.
getMaxValue(0) == 1.0f)) {
// Note that a normalized range of 0.0 - 1.0 for the gray
// component is required, because usage of these LUTs makes
// that assumption.
ICC_ColorSpace ics = (
ICC_ColorSpace)
colorSpace;
is_ICCGray_stdScale = true;
nonStdScale = false;
fromsRGB8LUT16 =
ColorModel.
getsRGB8ToLinearRGB16LUT();
if (
ColorModel.
isLinearGRAYspace(
ics)) {
is_LinearGray_stdScale = true;
if (
transferType ==
DataBuffer.
TYPE_BYTE) {
tosRGB8LUT =
ColorModel.
getGray8TosRGB8LUT(
ics);
} else {
tosRGB8LUT =
ColorModel.
getGray16TosRGB8LUT(
ics);
}
} else {
if (
transferType ==
DataBuffer.
TYPE_BYTE) {
tosRGB8LUT =
ColorModel.
getGray8TosRGB8LUT(
ics);
fromLinearGray16ToOtherGray8LUT =
ColorModel.
getLinearGray16ToOtherGray8LUT(
ics);
} else {
tosRGB8LUT =
ColorModel.
getGray16TosRGB8LUT(
ics);
fromLinearGray16ToOtherGray16LUT =
ColorModel.
getLinearGray16ToOtherGray16LUT(
ics);
}
}
} else if (
needScaleInit) {
// if transferType is byte, ushort, int, or short and we
// don't already know the ColorSpace has minVlaue == 0.0f and
// maxValue == 1.0f for all components, we need to check that
// now and setup the min[] and diffMinMax[] arrays if necessary.
nonStdScale = false;
for (int
i = 0;
i <
numColorComponents;
i++) {
if ((
colorSpace.
getMinValue(
i) != 0.0f) ||
(
colorSpace.
getMaxValue(
i) != 1.0f)) {
nonStdScale = true;
break;
}
}
if (
nonStdScale) {
min = new float[
numColorComponents];
diffMinMax = new float[
numColorComponents];
for (int
i = 0;
i <
numColorComponents;
i++) {
min[
i] =
colorSpace.
getMinValue(
i);
diffMinMax[
i] =
colorSpace.
getMaxValue(
i) -
min[
i];
}
}
}
}
private void
initScale() {
// This method is called the first time any method which uses
// pixel sample value to color component value scaling information
// is called if the transferType supports non-standard scaling
// as defined above (byte, ushort, int, and short), unless the
// method is getNormalizedComponents(Object, float[], int) (that
// method must be overridden to use non-standard scaling). This
// method also sets up the noUnnorm boolean variable for these
// transferTypes. After this method is called, the nonStdScale
// variable will be true if getNormalizedComponents() maps a
// sample value of 0 to anything other than 0.0f OR maps a
// sample value of 2^^n - 1 (2^^15 - 1 for short transferType)
// to anything other than 1.0f. Note that this can be independent
// of the colorSpace min/max component values, if the
// getNormalizedComponents() method has been overridden for some
// reason, e.g. to provide greater dynamic range in the sample
// values than in the color component values. Unfortunately,
// this method can't be called at construction time, since a
// subclass may still have uninitialized state that would cause
// getNormalizedComponents() to return an incorrect result.
needScaleInit = false; // only needs to called once
if (
nonStdScale ||
signed) {
// The unnormalized form is only supported for unsigned
// transferTypes and when the ColorSpace min/max values
// are 0.0/1.0. When this method is called nonStdScale is
// true if the latter condition does not hold. In addition,
// the unnormalized form requires that the full range of
// the pixel sample values map to the full 0.0 - 1.0 range
// of color component values. That condition is checked
// later in this method.
noUnnorm = true;
} else {
noUnnorm = false;
}
float[]
lowVal,
highVal;
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
{
byte[]
bpixel = new byte[
numComponents];
for (int
i = 0;
i <
numColorComponents;
i++) {
bpixel[
i] = 0;
}
if (
supportsAlpha) {
bpixel[
numColorComponents] =
(byte) ((1 <<
nBits[
numColorComponents]) - 1);
}
lowVal =
getNormalizedComponents(
bpixel, null, 0);
for (int
i = 0;
i <
numColorComponents;
i++) {
bpixel[
i] = (byte) ((1 <<
nBits[
i]) - 1);
}
highVal =
getNormalizedComponents(
bpixel, null, 0);
}
break;
case
DataBuffer.
TYPE_USHORT:
{
short[]
uspixel = new short[
numComponents];
for (int
i = 0;
i <
numColorComponents;
i++) {
uspixel[
i] = 0;
}
if (
supportsAlpha) {
uspixel[
numColorComponents] =
(short) ((1 <<
nBits[
numColorComponents]) - 1);
}
lowVal =
getNormalizedComponents(
uspixel, null, 0);
for (int
i = 0;
i <
numColorComponents;
i++) {
uspixel[
i] = (short) ((1 <<
nBits[
i]) - 1);
}
highVal =
getNormalizedComponents(
uspixel, null, 0);
}
break;
case
DataBuffer.
TYPE_INT:
{
int[]
ipixel = new int[
numComponents];
for (int
i = 0;
i <
numColorComponents;
i++) {
ipixel[
i] = 0;
}
if (
supportsAlpha) {
ipixel[
numColorComponents] =
((1 <<
nBits[
numColorComponents]) - 1);
}
lowVal =
getNormalizedComponents(
ipixel, null, 0);
for (int
i = 0;
i <
numColorComponents;
i++) {
ipixel[
i] = ((1 <<
nBits[
i]) - 1);
}
highVal =
getNormalizedComponents(
ipixel, null, 0);
}
break;
case
DataBuffer.
TYPE_SHORT:
{
short[]
spixel = new short[
numComponents];
for (int
i = 0;
i <
numColorComponents;
i++) {
spixel[
i] = 0;
}
if (
supportsAlpha) {
spixel[
numColorComponents] = 32767;
}
lowVal =
getNormalizedComponents(
spixel, null, 0);
for (int
i = 0;
i <
numColorComponents;
i++) {
spixel[
i] = 32767;
}
highVal =
getNormalizedComponents(
spixel, null, 0);
}
break;
default:
lowVal =
highVal = null; // to keep the compiler from complaining
break;
}
nonStdScale = false;
for (int
i = 0;
i <
numColorComponents;
i++) {
if ((
lowVal[
i] != 0.0f) || (
highVal[
i] != 1.0f)) {
nonStdScale = true;
break;
}
}
if (
nonStdScale) {
noUnnorm = true;
is_sRGB_stdScale = false;
is_LinearRGB_stdScale = false;
is_LinearGray_stdScale = false;
is_ICCGray_stdScale = false;
compOffset = new float[
numColorComponents];
compScale = new float[
numColorComponents];
for (int
i = 0;
i <
numColorComponents;
i++) {
compOffset[
i] =
lowVal[
i];
compScale[
i] = 1.0f / (
highVal[
i] -
lowVal[
i]);
}
}
}
private int
getRGBComponent(int
pixel, int
idx) {
if (
numComponents > 1) {
throw new
IllegalArgumentException("More than one component per pixel");
}
if (
signed) {
throw new
IllegalArgumentException("Component value is signed");
}
if (
needScaleInit) {
initScale();
}
// Since there is only 1 component, there is no alpha
// Normalize the pixel in order to convert it
Object opixel = null;
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
{
byte[]
bpixel = { (byte)
pixel };
opixel =
bpixel;
}
break;
case
DataBuffer.
TYPE_USHORT:
{
short[]
spixel = { (short)
pixel };
opixel =
spixel;
}
break;
case
DataBuffer.
TYPE_INT:
{
int[]
ipixel = {
pixel };
opixel =
ipixel;
}
break;
}
float[]
norm =
getNormalizedComponents(
opixel, null, 0);
float[]
rgb =
colorSpace.
toRGB(
norm);
return (int) (
rgb[
idx] * 255.0f + 0.5f);
}
/**
* Returns the red color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
* is done if necessary. The pixel value is specified as an int.
* The returned value will be a non pre-multiplied value.
* If the alpha is premultiplied, this method divides
* it out before returning the value (if the alpha value is 0,
* the red value will be 0).
*
* @param pixel The pixel from which you want to get the red color component.
*
* @return The red color component for the specified pixel, as an int.
*
* @throws IllegalArgumentException If there is more than
* one component in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If the component value for this
* <CODE>ColorModel</CODE> is signed
*/
public int
getRed(int
pixel) {
return
getRGBComponent(
pixel, 0);
}
/**
* Returns the green color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
* is done if necessary. The pixel value is specified as an int.
* The returned value will be a non
* pre-multiplied value. If the alpha is premultiplied, this method
* divides it out before returning the value (if the alpha value is 0,
* the green value will be 0).
*
* @param pixel The pixel from which you want to get the green color component.
*
* @return The green color component for the specified pixel, as an int.
*
* @throws IllegalArgumentException If there is more than
* one component in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If the component value for this
* <CODE>ColorModel</CODE> is signed
*/
public int
getGreen(int
pixel) {
return
getRGBComponent(
pixel, 1);
}
/**
* Returns the blue color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
* is done if necessary. The pixel value is specified as an int.
* The returned value will be a non
* pre-multiplied value. If the alpha is premultiplied, this method
* divides it out before returning the value (if the alpha value is 0,
* the blue value will be 0).
*
* @param pixel The pixel from which you want to get the blue color component.
*
* @return The blue color component for the specified pixel, as an int.
*
* @throws IllegalArgumentException If there is more than
* one component in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If the component value for this
* <CODE>ColorModel</CODE> is signed
*/
public int
getBlue(int
pixel) {
return
getRGBComponent(
pixel, 2);
}
/**
* Returns the alpha component for the specified pixel, scaled
* from 0 to 255. The pixel value is specified as an int.
*
* @param pixel The pixel from which you want to get the alpha component.
*
* @return The alpha component for the specified pixel, as an int.
*
* @throws IllegalArgumentException If there is more than
* one component in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If the component value for this
* <CODE>ColorModel</CODE> is signed
*/
public int
getAlpha(int
pixel) {
if (
supportsAlpha == false) {
return 255;
}
if (
numComponents > 1) {
throw new
IllegalArgumentException("More than one component per pixel");
}
if (
signed) {
throw new
IllegalArgumentException("Component value is signed");
}
return (int) ((((float)
pixel) / ((1<<
nBits[0])-1)) * 255.0f + 0.5f);
}
/**
* Returns the color/alpha components of the pixel in the default
* RGB color model format. A color conversion is done if necessary.
* The returned value will be in a non pre-multiplied format. If
* the alpha is premultiplied, this method divides it out of the
* color components (if the alpha value is 0, the color values will be 0).
*
* @param pixel The pixel from which you want to get the color/alpha components.
*
* @return The color/alpha components for the specified pixel, as an int.
*
* @throws IllegalArgumentException If there is more than
* one component in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If the component value for this
* <CODE>ColorModel</CODE> is signed
*/
public int
getRGB(int
pixel) {
if (
numComponents > 1) {
throw new
IllegalArgumentException("More than one component per pixel");
}
if (
signed) {
throw new
IllegalArgumentException("Component value is signed");
}
return (
getAlpha(
pixel) << 24)
| (
getRed(
pixel) << 16)
| (
getGreen(
pixel) << 8)
| (
getBlue(
pixel) << 0);
}
private int
extractComponent(
Object inData, int
idx, int
precision) {
// Extract component idx from inData. The precision argument
// should be either 8 or 16. If it's 8, this method will return
// an 8-bit value. If it's 16, this method will return a 16-bit
// value for transferTypes other than TYPE_BYTE. For TYPE_BYTE,
// an 8-bit value will be returned.
// This method maps the input value corresponding to a
// normalized ColorSpace component value of 0.0 to 0, and the
// input value corresponding to a normalized ColorSpace
// component value of 1.0 to 2^n - 1 (where n is 8 or 16), so
// it is appropriate only for ColorSpaces with min/max component
// values of 0.0/1.0. This will be true for sRGB, the built-in
// Linear RGB and Linear Gray spaces, and any other ICC grayscale
// spaces for which we have precomputed LUTs.
boolean
needAlpha = (
supportsAlpha &&
isAlphaPremultiplied);
int
alp = 0;
int
comp;
int
mask = (1 <<
nBits[
idx]) - 1;
switch (
transferType) {
// Note: we do no clamping of the pixel data here - we
// assume that the data is scaled properly
case
DataBuffer.
TYPE_SHORT: {
short
sdata[] = (short[])
inData;
float
scalefactor = (float) ((1 <<
precision) - 1);
if (
needAlpha) {
short
s =
sdata[
numColorComponents];
if (
s != (short) 0) {
return (int) ((((float)
sdata[
idx]) /
((float)
s)) *
scalefactor + 0.5f);
} else {
return 0;
}
} else {
return (int) ((
sdata[
idx] / 32767.0f) *
scalefactor + 0.5f);
}
}
case
DataBuffer.
TYPE_FLOAT: {
float
fdata[] = (float[])
inData;
float
scalefactor = (float) ((1 <<
precision) - 1);
if (
needAlpha) {
float
f =
fdata[
numColorComponents];
if (
f != 0.0f) {
return (int) (((
fdata[
idx] /
f) *
scalefactor) + 0.5f);
} else {
return 0;
}
} else {
return (int) (
fdata[
idx] *
scalefactor + 0.5f);
}
}
case
DataBuffer.
TYPE_DOUBLE: {
double
ddata[] = (double[])
inData;
double
scalefactor = (double) ((1 <<
precision) - 1);
if (
needAlpha) {
double
d =
ddata[
numColorComponents];
if (
d != 0.0) {
return (int) (((
ddata[
idx] /
d) *
scalefactor) + 0.5);
} else {
return 0;
}
} else {
return (int) (
ddata[
idx] *
scalefactor + 0.5);
}
}
case
DataBuffer.
TYPE_BYTE:
byte
bdata[] = (byte[])
inData;
comp =
bdata[
idx] &
mask;
precision = 8;
if (
needAlpha) {
alp =
bdata[
numColorComponents] &
mask;
}
break;
case
DataBuffer.
TYPE_USHORT:
short
usdata[] = (short[])
inData;
comp =
usdata[
idx] &
mask;
if (
needAlpha) {
alp =
usdata[
numColorComponents] &
mask;
}
break;
case
DataBuffer.
TYPE_INT:
int
idata[] = (int[])
inData;
comp =
idata[
idx];
if (
needAlpha) {
alp =
idata[
numColorComponents];
}
break;
default:
throw new
UnsupportedOperationException("This method has not "+
"been implemented for transferType " +
transferType);
}
if (
needAlpha) {
if (
alp != 0) {
float
scalefactor = (float) ((1 <<
precision) - 1);
float
fcomp = ((float)
comp) / ((float)
mask);
float
invalp = ((float) ((1<<
nBits[
numColorComponents]) - 1)) /
((float)
alp);
return (int) (
fcomp *
invalp *
scalefactor + 0.5f);
} else {
return 0;
}
} else {
if (
nBits[
idx] !=
precision) {
float
scalefactor = (float) ((1 <<
precision) - 1);
float
fcomp = ((float)
comp) / ((float)
mask);
return (int) (
fcomp *
scalefactor + 0.5f);
}
return
comp;
}
}
private int
getRGBComponent(
Object inData, int
idx) {
if (
needScaleInit) {
initScale();
}
if (
is_sRGB_stdScale) {
return
extractComponent(
inData,
idx, 8);
} else if (
is_LinearRGB_stdScale) {
int
lutidx =
extractComponent(
inData,
idx, 16);
return
tosRGB8LUT[
lutidx] & 0xff;
} else if (
is_ICCGray_stdScale) {
int
lutidx =
extractComponent(
inData, 0, 16);
return
tosRGB8LUT[
lutidx] & 0xff;
}
// Not CS_sRGB, CS_LINEAR_RGB, or any TYPE_GRAY ICC_ColorSpace
float[]
norm =
getNormalizedComponents(
inData, null, 0);
// Note that getNormalizedComponents returns non-premultiplied values
float[]
rgb =
colorSpace.
toRGB(
norm);
return (int) (
rgb[
idx] * 255.0f + 0.5f);
}
/**
* Returns the red color component for the specified pixel, scaled
* from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
* is done if necessary. The <CODE>pixel</CODE> value is specified by an array
* of data elements of type <CODE>transferType</CODE> passed in as an object
* reference. The returned value will be a non pre-multiplied value. If the
* alpha is premultiplied, this method divides it out before returning
* the value (if the alpha value is 0, the red value will be 0). Since
* <code>ComponentColorModel</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 pixel from which you want to get the red color component,
* specified by an array of data elements of type <CODE>transferType</CODE>.
*
* @return The red color component for the specified pixel, as an int.
*
* @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
* of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
* large enough to hold a pixel value for this
* <CODE>ColorModel</CODE>.
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*/
public int
getRed(
Object inData) {
return
getRGBComponent(
inData, 0);
}
/**
* Returns the green color component for the specified pixel, scaled
* from 0 to 255 in the default RGB <CODE>ColorSpace</CODE>, sRGB.
* A color conversion is done if necessary. The <CODE>pixel</CODE> 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. If the alpha is premultiplied, this method divides it out before
* returning the value (if the alpha value is 0, the green value will be 0).
* Since <code>ComponentColorModel</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 pixel from which you want to get the green color component,
* specified by an array of data elements of type <CODE>transferType</CODE>.
*
* @return The green color component for the specified pixel, as an int.
*
* @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
* of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
* large enough to hold a pixel value for this
* <CODE>ColorModel</CODE>.
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*/
public int
getGreen(
Object inData) {
return
getRGBComponent(
inData, 1);
}
/**
* Returns the blue color component for the specified pixel, scaled
* from 0 to 255 in the default RGB <CODE>ColorSpace</CODE>, sRGB.
* A color conversion is done if necessary. The <CODE>pixel</CODE> 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. If the alpha is premultiplied, this method divides it out before
* returning the value (if the alpha value is 0, the blue value will be 0).
* Since <code>ComponentColorModel</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 pixel from which you want to get the blue color component,
* specified by an array of data elements of type <CODE>transferType</CODE>.
*
* @return The blue color component for the specified pixel, as an int.
*
* @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
* of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
* large enough to hold a pixel value for this
* <CODE>ColorModel</CODE>.
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*/
public int
getBlue(
Object inData) {
return
getRGBComponent(
inData, 2);
}
/**
* Returns the alpha component for the specified pixel, scaled from
* 0 to 255. The pixel value is specified by an array of data
* elements of type <CODE>transferType</CODE> passed in as an
* object reference. Since <code>ComponentColorModel</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 pixel from which you want to get the alpha component,
* specified by an array of data elements of type <CODE>transferType</CODE>.
*
* @return The alpha component for the specified pixel, as an int.
*
* @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
* of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
* large enough to hold a pixel value for this
* <CODE>ColorModel</CODE>.
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*/
public int
getAlpha(
Object inData) {
if (
supportsAlpha == false) {
return 255;
}
int
alpha = 0;
int
aIdx =
numColorComponents;
int
mask = (1 <<
nBits[
aIdx]) - 1;
switch (
transferType) {
case
DataBuffer.
TYPE_SHORT:
short
sdata[] = (short[])
inData;
alpha = (int) ((
sdata[
aIdx] / 32767.0f) * 255.0f + 0.5f);
return
alpha;
case
DataBuffer.
TYPE_FLOAT:
float
fdata[] = (float[])
inData;
alpha = (int) (
fdata[
aIdx] * 255.0f + 0.5f);
return
alpha;
case
DataBuffer.
TYPE_DOUBLE:
double
ddata[] = (double[])
inData;
alpha = (int) (
ddata[
aIdx] * 255.0 + 0.5);
return
alpha;
case
DataBuffer.
TYPE_BYTE:
byte
bdata[] = (byte[])
inData;
alpha =
bdata[
aIdx] &
mask;
break;
case
DataBuffer.
TYPE_USHORT:
short
usdata[] = (short[])
inData;
alpha =
usdata[
aIdx] &
mask;
break;
case
DataBuffer.
TYPE_INT:
int
idata[] = (int[])
inData;
alpha =
idata[
aIdx];
break;
default:
throw new
UnsupportedOperationException("This method has not "+
"been implemented for transferType " +
transferType);
}
if (
nBits[
aIdx] == 8) {
return
alpha;
} else {
return (int)
((((float)
alpha) / ((float) ((1 <<
nBits[
aIdx]) - 1))) *
255.0f + 0.5f);
}
}
/**
* Returns the color/alpha components for the specified pixel in the
* default RGB color model format. A color conversion is done if
* necessary. The pixel value is specified by an
* array of data elements of type <CODE>transferType</CODE> passed
* in as an object reference.
* The returned value is in a non pre-multiplied format. If
* the alpha is premultiplied, this method divides it out of the
* color components (if the alpha value is 0, the color values will be 0).
* Since <code>ComponentColorModel</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 pixel from which you want to get the color/alpha components,
* specified by an array of data elements of type <CODE>transferType</CODE>.
*
* @return The color/alpha components for the specified pixel, as an int.
*
* @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
* of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
* large enough to hold a pixel value for this
* <CODE>ColorModel</CODE>.
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
* @see ColorModel#getRGBdefault
*/
public int
getRGB(
Object inData) {
if (
needScaleInit) {
initScale();
}
if (
is_sRGB_stdScale ||
is_LinearRGB_stdScale) {
return (
getAlpha(
inData) << 24)
| (
getRed(
inData) << 16)
| (
getGreen(
inData) << 8)
| (
getBlue(
inData));
} else if (
colorSpaceType ==
ColorSpace.
TYPE_GRAY) {
int
gray =
getRed(
inData); // Red sRGB component should equal
// green and blue components
return (
getAlpha(
inData) << 24)
| (
gray << 16)
| (
gray << 8)
|
gray;
}
float[]
norm =
getNormalizedComponents(
inData, null, 0);
// Note that getNormalizedComponents returns non-premult values
float[]
rgb =
colorSpace.
toRGB(
norm);
return (
getAlpha(
inData) << 24)
| (((int) (
rgb[0] * 255.0f + 0.5f)) << 16)
| (((int) (
rgb[1] * 255.0f + 0.5f)) << 8)
| (((int) (
rgb[2] * 255.0f + 0.5f)) << 0);
}
/**
* Returns a data element array representation of a pixel in this
* <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
* <CODE>pixel</CODE>
* parameter is null, a new array is allocated. Since
* <code>ComponentColorModel</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 representation of the pixel in the RGB
* color model
* @param pixel the specified pixel
* @return The data element array representation of a pixel
* in this <CODE>ColorModel</CODE>.
* @throws ClassCastException If <CODE>pixel</CODE> is not null and
* is not a primitive array of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException If <CODE>pixel</CODE> is
* not large enough to hold a pixel value for this
* <CODE>ColorModel</CODE>.
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*
* @see WritableRaster#setDataElements
* @see SampleModel#setDataElements
*/
public
Object getDataElements(int
rgb,
Object pixel) {
// REMIND: Use rendering hints?
int
red,
grn,
blu,
alp;
red = (
rgb>>16) & 0xff;
grn = (
rgb>>8) & 0xff;
blu =
rgb & 0xff;
if (
needScaleInit) {
initScale();
}
if (
signed) {
// Handle SHORT, FLOAT, & DOUBLE here
switch(
transferType) {
case
DataBuffer.
TYPE_SHORT:
{
short
sdata[];
if (
pixel == null) {
sdata = new short[
numComponents];
} else {
sdata = (short[])
pixel;
}
float
factor;
if (
is_sRGB_stdScale ||
is_LinearRGB_stdScale) {
factor = 32767.0f / 255.0f;
if (
is_LinearRGB_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
factor = 32767.0f / 65535.0f;
}
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
sdata[3] =
(short) (
alp * (32767.0f / 255.0f) + 0.5f);
if (
isAlphaPremultiplied) {
factor =
alp *
factor * (1.0f / 255.0f);
}
}
sdata[0] = (short) (
red *
factor + 0.5f);
sdata[1] = (short) (
grn *
factor + 0.5f);
sdata[2] = (short) (
blu *
factor + 0.5f);
} else if (
is_LinearGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
float
gray = ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu)) / 65535.0f;
factor = 32767.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
sdata[1] =
(short) (
alp * (32767.0f / 255.0f) + 0.5f);
if (
isAlphaPremultiplied) {
factor =
alp *
factor * (1.0f / 255.0f);
}
}
sdata[0] = (short) (
gray *
factor + 0.5f);
} else if (
is_ICCGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
int
gray = (int) ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu) + 0.5f);
gray =
fromLinearGray16ToOtherGray16LUT[
gray] & 0xffff;
factor = 32767.0f / 65535.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
sdata[1] =
(short) (
alp * (32767.0f / 255.0f) + 0.5f);
if (
isAlphaPremultiplied) {
factor =
alp *
factor * (1.0f / 255.0f);
}
}
sdata[0] = (short) (
gray *
factor + 0.5f);
} else {
factor = 1.0f / 255.0f;
float
norm[] = new float[3];
norm[0] =
red *
factor;
norm[1] =
grn *
factor;
norm[2] =
blu *
factor;
norm =
colorSpace.
fromRGB(
norm);
if (
nonStdScale) {
for (int
i = 0;
i <
numColorComponents;
i++) {
norm[
i] = (
norm[
i] -
compOffset[
i]) *
compScale[
i];
// REMIND: need to analyze whether this
// clamping is necessary
if (
norm[
i] < 0.0f) {
norm[
i] = 0.0f;
}
if (
norm[
i] > 1.0f) {
norm[
i] = 1.0f;
}
}
}
factor = 32767.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
sdata[
numColorComponents] =
(short) (
alp * (32767.0f / 255.0f) + 0.5f);
if (
isAlphaPremultiplied) {
factor *=
alp * (1.0f / 255.0f);
}
}
for (int
i = 0;
i <
numColorComponents;
i++) {
sdata[
i] = (short) (
norm[
i] *
factor + 0.5f);
}
}
return
sdata;
}
case
DataBuffer.
TYPE_FLOAT:
{
float
fdata[];
if (
pixel == null) {
fdata = new float[
numComponents];
} else {
fdata = (float[])
pixel;
}
float
factor;
if (
is_sRGB_stdScale ||
is_LinearRGB_stdScale) {
if (
is_LinearRGB_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
factor = 1.0f / 65535.0f;
} else {
factor = 1.0f / 255.0f;
}
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
fdata[3] =
alp * (1.0f / 255.0f);
if (
isAlphaPremultiplied) {
factor *=
fdata[3];
}
}
fdata[0] =
red *
factor;
fdata[1] =
grn *
factor;
fdata[2] =
blu *
factor;
} else if (
is_LinearGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
fdata[0] = ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu)) / 65535.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
fdata[1] =
alp * (1.0f / 255.0f);
if (
isAlphaPremultiplied) {
fdata[0] *=
fdata[1];
}
}
} else if (
is_ICCGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
int
gray = (int) ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu) + 0.5f);
fdata[0] = (
fromLinearGray16ToOtherGray16LUT[
gray] &
0xffff) / 65535.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
fdata[1] =
alp * (1.0f / 255.0f);
if (
isAlphaPremultiplied) {
fdata[0] *=
fdata[1];
}
}
} else {
float
norm[] = new float[3];
factor = 1.0f / 255.0f;
norm[0] =
red *
factor;
norm[1] =
grn *
factor;
norm[2] =
blu *
factor;
norm =
colorSpace.
fromRGB(
norm);
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
fdata[
numColorComponents] =
alp *
factor;
if (
isAlphaPremultiplied) {
factor *=
alp;
for (int
i = 0;
i <
numColorComponents;
i++) {
norm[
i] *=
factor;
}
}
}
for (int
i = 0;
i <
numColorComponents;
i++) {
fdata[
i] =
norm[
i];
}
}
return
fdata;
}
case
DataBuffer.
TYPE_DOUBLE:
{
double
ddata[];
if (
pixel == null) {
ddata = new double[
numComponents];
} else {
ddata = (double[])
pixel;
}
if (
is_sRGB_stdScale ||
is_LinearRGB_stdScale) {
double
factor;
if (
is_LinearRGB_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
factor = 1.0 / 65535.0;
} else {
factor = 1.0 / 255.0;
}
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
ddata[3] =
alp * (1.0 / 255.0);
if (
isAlphaPremultiplied) {
factor *=
ddata[3];
}
}
ddata[0] =
red *
factor;
ddata[1] =
grn *
factor;
ddata[2] =
blu *
factor;
} else if (
is_LinearGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
ddata[0] = ((0.2125 *
red) +
(0.7154 *
grn) +
(0.0721 *
blu)) / 65535.0;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
ddata[1] =
alp * (1.0 / 255.0);
if (
isAlphaPremultiplied) {
ddata[0] *=
ddata[1];
}
}
} else if (
is_ICCGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
int
gray = (int) ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu) + 0.5f);
ddata[0] = (
fromLinearGray16ToOtherGray16LUT[
gray] &
0xffff) / 65535.0;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
ddata[1] =
alp * (1.0 / 255.0);
if (
isAlphaPremultiplied) {
ddata[0] *=
ddata[1];
}
}
} else {
float
factor = 1.0f / 255.0f;
float
norm[] = new float[3];
norm[0] =
red *
factor;
norm[1] =
grn *
factor;
norm[2] =
blu *
factor;
norm =
colorSpace.
fromRGB(
norm);
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
ddata[
numColorComponents] =
alp * (1.0 / 255.0);
if (
isAlphaPremultiplied) {
factor *=
alp;
for (int
i = 0;
i <
numColorComponents;
i++) {
norm[
i] *=
factor;
}
}
}
for (int
i = 0;
i <
numColorComponents;
i++) {
ddata[
i] =
norm[
i];
}
}
return
ddata;
}
}
}
// Handle BYTE, USHORT, & INT here
//REMIND: maybe more efficient not to use int array for
//DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT
int
intpixel[];
if (
transferType ==
DataBuffer.
TYPE_INT &&
pixel != null) {
intpixel = (int[])
pixel;
} else {
intpixel = new int[
numComponents];
}
if (
is_sRGB_stdScale ||
is_LinearRGB_stdScale) {
int
precision;
float
factor;
if (
is_LinearRGB_stdScale) {
if (
transferType ==
DataBuffer.
TYPE_BYTE) {
red =
fromsRGB8LUT8[
red] & 0xff;
grn =
fromsRGB8LUT8[
grn] & 0xff;
blu =
fromsRGB8LUT8[
blu] & 0xff;
precision = 8;
factor = 1.0f / 255.0f;
} else {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
precision = 16;
factor = 1.0f / 65535.0f;
}
} else {
precision = 8;
factor = 1.0f / 255.0f;
}
if (
supportsAlpha) {
alp = (
rgb>>24)&0xff;
if (
nBits[3] == 8) {
intpixel[3] =
alp;
}
else {
intpixel[3] = (int)
(
alp * (1.0f / 255.0f) * ((1<<
nBits[3]) - 1) + 0.5f);
}
if (
isAlphaPremultiplied) {
factor *= (
alp * (1.0f / 255.0f));
precision = -1; // force component calculations below
}
}
if (
nBits[0] ==
precision) {
intpixel[0] =
red;
}
else {
intpixel[0] = (int) (
red *
factor * ((1<<
nBits[0]) - 1) + 0.5f);
}
if (
nBits[1] ==
precision) {
intpixel[1] = (int)(
grn);
}
else {
intpixel[1] = (int) (
grn *
factor * ((1<<
nBits[1]) - 1) + 0.5f);
}
if (
nBits[2] ==
precision) {
intpixel[2] = (int)(
blu);
}
else {
intpixel[2] = (int) (
blu *
factor * ((1<<
nBits[2]) - 1) + 0.5f);
}
} else if (
is_LinearGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
float
gray = ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu)) / 65535.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
if (
nBits[1] == 8) {
intpixel[1] =
alp;
} else {
intpixel[1] = (int) (
alp * (1.0f / 255.0f) *
((1 <<
nBits[1]) - 1) + 0.5f);
}
if (
isAlphaPremultiplied) {
gray *= (
alp * (1.0f / 255.0f));
}
}
intpixel[0] = (int) (
gray * ((1 <<
nBits[0]) - 1) + 0.5f);
} else if (
is_ICCGray_stdScale) {
red =
fromsRGB8LUT16[
red] & 0xffff;
grn =
fromsRGB8LUT16[
grn] & 0xffff;
blu =
fromsRGB8LUT16[
blu] & 0xffff;
int
gray16 = (int) ((0.2125f *
red) +
(0.7154f *
grn) +
(0.0721f *
blu) + 0.5f);
float
gray = (
fromLinearGray16ToOtherGray16LUT[
gray16] &
0xffff) / 65535.0f;
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
if (
nBits[1] == 8) {
intpixel[1] =
alp;
} else {
intpixel[1] = (int) (
alp * (1.0f / 255.0f) *
((1 <<
nBits[1]) - 1) + 0.5f);
}
if (
isAlphaPremultiplied) {
gray *= (
alp * (1.0f / 255.0f));
}
}
intpixel[0] = (int) (
gray * ((1 <<
nBits[0]) - 1) + 0.5f);
} else {
// Need to convert the color
float[]
norm = new float[3];
float
factor = 1.0f / 255.0f;
norm[0] =
red *
factor;
norm[1] =
grn *
factor;
norm[2] =
blu *
factor;
norm =
colorSpace.
fromRGB(
norm);
if (
nonStdScale) {
for (int
i = 0;
i <
numColorComponents;
i++) {
norm[
i] = (
norm[
i] -
compOffset[
i]) *
compScale[
i];
// REMIND: need to analyze whether this
// clamping is necessary
if (
norm[
i] < 0.0f) {
norm[
i] = 0.0f;
}
if (
norm[
i] > 1.0f) {
norm[
i] = 1.0f;
}
}
}
if (
supportsAlpha) {
alp = (
rgb>>24) & 0xff;
if (
nBits[
numColorComponents] == 8) {
intpixel[
numColorComponents] =
alp;
}
else {
intpixel[
numColorComponents] =
(int) (
alp *
factor *
((1<<
nBits[
numColorComponents]) - 1) + 0.5f);
}
if (
isAlphaPremultiplied) {
factor *=
alp;
for (int
i = 0;
i <
numColorComponents;
i++) {
norm[
i] *=
factor;
}
}
}
for (int
i = 0;
i <
numColorComponents;
i++) {
intpixel[
i] = (int) (
norm[
i] * ((1<<
nBits[
i]) - 1) + 0.5f);
}
}
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE: {
byte
bdata[];
if (
pixel == null) {
bdata = new byte[
numComponents];
} else {
bdata = (byte[])
pixel;
}
for (int
i = 0;
i <
numComponents;
i++) {
bdata[
i] = (byte)(0xff&
intpixel[
i]);
}
return
bdata;
}
case
DataBuffer.
TYPE_USHORT:{
short
sdata[];
if (
pixel == null) {
sdata = new short[
numComponents];
} else {
sdata = (short[])
pixel;
}
for (int
i = 0;
i <
numComponents;
i++) {
sdata[
i] = (short)(
intpixel[
i]&0xffff);
}
return
sdata;
}
case
DataBuffer.
TYPE_INT:
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.
for (int
i = 0;
i <
numComponents;
i++) {
if (
intpixel[
i] > ((1<<
nBits[
i]) - 1)) {
intpixel[
i] = (1<<
nBits[
i]) - 1;
}
}
}
return
intpixel;
}
throw new
IllegalArgumentException("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>.
* An IllegalArgumentException is thrown if the component value for this
* <CODE>ColorModel</CODE> is not conveniently representable in the
* unnormalized form. 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).
*
* @param pixel The pixel value specified as an integer.
* @param components An integer array in which to store the unnormalized
* color/alpha components. If the <CODE>components</CODE> array is null,
* a new array is allocated.
* @param offset An offset into the <CODE>components</CODE> array.
*
* @return The components array.
*
* @throws IllegalArgumentException If there is more than one
* component in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If this
* <CODE>ColorModel</CODE> does not support the unnormalized form
* @throws ArrayIndexOutOfBoundsException If the <CODE>components</CODE>
* array is not null and is not large enough to hold all the color and
* alpha components (starting at offset).
*/
public int[]
getComponents(int
pixel, int[]
components, int
offset) {
if (
numComponents > 1) {
throw new
IllegalArgumentException("More than one component per pixel");
}
if (
needScaleInit) {
initScale();
}
if (
noUnnorm) {
throw new
IllegalArgumentException(
"This ColorModel does not support the unnormalized form");
}
if (
components == null) {
components = new int[
offset+1];
}
components[
offset+0] = (
pixel & ((1<<
nBits[0]) - 1));
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.
* An IllegalArgumentException is thrown if the component values for this
* <CODE>ColorModel</CODE> are not conveniently representable in the
* unnormalized form.
* 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). Since <code>ComponentColorModel</code> can be
* subclassed, subclasses inherit the
* implementation of this method and if they don't override it then
* this method might throw an exception if they use an unsupported
* <code>transferType</code>.
*
* @param pixel A pixel value specified by an array of data elements of
* type <CODE>transferType</CODE>.
* @param components An integer array in which to store the unnormalized
* color/alpha components. If the <CODE>components</CODE> array is null,
* a new array is allocated.
* @param offset An offset into the <CODE>components</CODE> array.
*
* @return The <CODE>components</CODE> array.
*
* @throws IllegalArgumentException If this
* <CODE>ComponentColorModel</CODE> does not support the unnormalized form
* @throws UnsupportedOperationException in some cases iff the
* transfer type of this <CODE>ComponentColorModel</CODE>
* is not one of the following transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* or <CODE>DataBuffer.TYPE_INT</CODE>.
* @throws ClassCastException If <CODE>pixel</CODE> is not a primitive
* array of type <CODE>transferType</CODE>.
* @throws IllegalArgumentException If the <CODE>components</CODE> array is
* not null and is not large enough to hold all the color and alpha
* components (starting at offset), or if <CODE>pixel</CODE> is not large
* enough to hold a pixel value for this ColorModel.
*/
public int[]
getComponents(
Object pixel, int[]
components, int
offset) {
int
intpixel[];
if (
needScaleInit) {
initScale();
}
if (
noUnnorm) {
throw new
IllegalArgumentException(
"This ColorModel does not support the unnormalized form");
}
if (
pixel instanceof int[]) {
intpixel = (int[])
pixel;
} else {
intpixel =
DataBuffer.
toIntArray(
pixel);
if (
intpixel == null) {
throw new
UnsupportedOperationException("This method has not been "+
"implemented for transferType " +
transferType);
}
}
if (
intpixel.length <
numComponents) {
throw new
IllegalArgumentException
("Length of pixel array < number of components in model");
}
if (
components == null) {
components = new int[
offset+
numComponents];
}
else if ((
components.length-
offset) <
numComponents) {
throw new
IllegalArgumentException
("Length of components array < number of components in model");
}
System.
arraycopy(
intpixel, 0,
components,
offset,
numComponents);
return
components;
}
/**
* Returns an array of all of the color/alpha components in unnormalized
* form, given a normalized component array. Unnormalized components
* are unsigned integral values between 0 and 2<sup>n</sup> - 1, where
* n is the number of bits for a particular component. Normalized
* components are float values between a per component minimum and
* maximum specified by the <code>ColorSpace</code> object for this
* <code>ColorModel</code>. An <code>IllegalArgumentException</code>
* will be thrown if color component values for this
* <code>ColorModel</code> are not conveniently representable in the
* unnormalized form. If the
* <code>components</code> array is <code>null</code>, a new array
* will be allocated. The <code>components</code> array will
* be 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>). An
* <code>IllegalArgumentException</code> is thrown if the
* <code>normComponents</code> array is not large enough to hold
* all the color and alpha components starting at
* <code>normOffset</code>.
* @param normComponents an array containing normalized components
* @param normOffset the offset into the <code>normComponents</code>
* array at which to start retrieving normalized components
* @param components an array that receives the components from
* <code>normComponents</code>
* @param offset the index into <code>components</code> at which to
* begin storing normalized components from
* <code>normComponents</code>
* @return an array containing unnormalized color and alpha
* components.
* @throws IllegalArgumentException If this
* <CODE>ComponentColorModel</CODE> does not support the unnormalized form
* @throws IllegalArgumentException if the length of
* <code>normComponents</code> minus <code>normOffset</code>
* is less than <code>numComponents</code>
*/
public int[]
getUnnormalizedComponents(float[]
normComponents,
int
normOffset,
int[]
components, int
offset) {
if (
needScaleInit) {
initScale();
}
if (
noUnnorm) {
throw new
IllegalArgumentException(
"This ColorModel does not support the unnormalized form");
}
return super.getUnnormalizedComponents(
normComponents,
normOffset,
components,
offset);
}
/**
* Returns an array of all of the color/alpha components in normalized
* form, given an unnormalized component array. Unnormalized components
* are unsigned integral values between 0 and 2<sup>n</sup> - 1, where
* n is the number of bits for a particular component. Normalized
* components are float values between a per component minimum and
* maximum specified by the <code>ColorSpace</code> object for this
* <code>ColorModel</code>. An <code>IllegalArgumentException</code>
* will be thrown if color component values for this
* <code>ColorModel</code> are not conveniently representable in the
* unnormalized form. If the
* <code>normComponents</code> array is <code>null</code>, a new array
* will be allocated. The <code>normComponents</code> array
* will be returned. Color/alpha components are stored in the
* <code>normComponents</code> array starting at
* <code>normOffset</code> (even if the array is allocated by this
* method). An <code>ArrayIndexOutOfBoundsException</code> is thrown
* if the <code>normComponents</code> array is not <code>null</code>
* and is not large enough to hold all the color and alpha components
* (starting at <code>normOffset</code>). An
* <code>IllegalArgumentException</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 containing unnormalized components
* @param offset the offset into the <code>components</code> array at
* which to start retrieving unnormalized components
* @param normComponents an array that receives the normalized components
* @param normOffset the index into <code>normComponents</code> at
* which to begin storing normalized components
* @return an array containing normalized color and alpha
* components.
* @throws IllegalArgumentException If this
* <CODE>ComponentColorModel</CODE> does not support the unnormalized form
*/
public float[]
getNormalizedComponents(int[]
components, int
offset,
float[]
normComponents,
int
normOffset) {
if (
needScaleInit) {
initScale();
}
if (
noUnnorm) {
throw new
IllegalArgumentException(
"This ColorModel does not support the unnormalized form");
}
return super.getNormalizedComponents(
components,
offset,
normComponents,
normOffset);
}
/**
* Returns a pixel value represented as an int in this <CODE>ColorModel</CODE>,
* given an array of unnormalized color/alpha components.
*
* @param components An array of unnormalized color/alpha components.
* @param offset An offset into the <CODE>components</CODE> array.
*
* @return A pixel value represented as an int.
*
* @throws IllegalArgumentException If there is more than one component
* in this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If this
* <CODE>ComponentColorModel</CODE> does not support the unnormalized form
*/
public int
getDataElement(int[]
components, int
offset) {
if (
needScaleInit) {
initScale();
}
if (
numComponents == 1) {
if (
noUnnorm) {
throw new
IllegalArgumentException(
"This ColorModel does not support the unnormalized form");
}
return
components[
offset+0];
}
throw new
IllegalArgumentException("This model returns "+
numComponents+
" elements in the pixel array.");
}
/**
* Returns a data element array representation of a pixel in this
* <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.
*
* @param components An array of unnormalized color/alpha components.
* @param offset The integer offset into the <CODE>components</CODE> array.
* @param obj The object in which to store the data element array
* representation of the pixel. If <CODE>obj</CODE> variable is null,
* a new array is allocated. If <CODE>obj</CODE> is not null, it must
* be a primitive array of type <CODE>transferType</CODE>. 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>ComponentColorModel</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>.
*
* @return The data element array representation of a pixel
* in this <CODE>ColorModel</CODE>.
*
* @throws IllegalArgumentException If the components array
* is not large enough to hold all the color and alpha components
* (starting at offset).
* @throws ClassCastException If <CODE>obj</CODE> is not null and is not a
* primitive array of type <CODE>transferType</CODE>.
* @throws ArrayIndexOutOfBoundsException If <CODE>obj</CODE> is not large
* enough to hold a pixel value for this <CODE>ColorModel</CODE>.
* @throws IllegalArgumentException If this
* <CODE>ComponentColorModel</CODE> does not support the unnormalized form
* @throws UnsupportedOperationException If the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the following transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* or <CODE>DataBuffer.TYPE_INT</CODE>.
*
* @see WritableRaster#setDataElements
* @see SampleModel#setDataElements
*/
public
Object getDataElements(int[]
components, int
offset,
Object obj) {
if (
needScaleInit) {
initScale();
}
if (
noUnnorm) {
throw new
IllegalArgumentException(
"This ColorModel does not support the unnormalized form");
}
if ((
components.length-
offset) <
numComponents) {
throw new
IllegalArgumentException("Component array too small"+
" (should be "+
numComponents);
}
switch(
transferType) {
case
DataBuffer.
TYPE_INT:
{
int[]
pixel;
if (
obj == null) {
pixel = new int[
numComponents];
}
else {
pixel = (int[])
obj;
}
System.
arraycopy(
components,
offset,
pixel, 0,
numComponents);
return
pixel;
}
case
DataBuffer.
TYPE_BYTE:
{
byte[]
pixel;
if (
obj == null) {
pixel = new byte[
numComponents];
}
else {
pixel = (byte[])
obj;
}
for (int
i=0;
i <
numComponents;
i++) {
pixel[
i] = (byte) (
components[
offset+
i]&0xff);
}
return
pixel;
}
case
DataBuffer.
TYPE_USHORT:
{
short[]
pixel;
if (
obj == null) {
pixel = new short[
numComponents];
}
else {
pixel = (short[])
obj;
}
for (int
i=0;
i <
numComponents;
i++) {
pixel[
i] = (short) (
components[
offset+
i]&0xffff);
}
return
pixel;
}
default:
throw new
UnsupportedOperationException("This method has not been "+
"implemented for transferType " +
transferType);
}
}
/**
* Returns a pixel value represented as an <code>int</code> in this
* <code>ColorModel</code>, given an array of normalized color/alpha
* components. This method will throw an
* <code>IllegalArgumentException</code> if pixel values for this
* <code>ColorModel</code> are not conveniently representable as a
* single <code>int</code>. An
* <code>ArrayIndexOutOfBoundsException</code> is thrown if the
* <code>normComponents</code> array is not large enough to hold all the
* color and alpha components (starting at <code>normOffset</code>).
* @param normComponents an array of normalized color and alpha
* components
* @param normOffset the index into <code>normComponents</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.
* @throws IllegalArgumentException if
* pixel values for this <code>ColorModel</code> are not
* conveniently representable as a single <code>int</code>
* @throws ArrayIndexOutOfBoundsException if
* the <code>normComponents</code> array is not large enough to
* hold all of the color and alpha components starting at
* <code>normOffset</code>
* @since 1.4
*/
public int
getDataElement(float[]
normComponents, int
normOffset) {
if (
numComponents > 1) {
throw new
IllegalArgumentException("More than one component per pixel");
}
if (
signed) {
throw new
IllegalArgumentException("Component value is signed");
}
if (
needScaleInit) {
initScale();
}
Object pixel =
getDataElements(
normComponents,
normOffset, null);
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
{
byte
bpixel[] = (byte[])
pixel;
return
bpixel[0] & 0xff;
}
case
DataBuffer.
TYPE_USHORT:
{
short[]
uspixel = (short[])
pixel;
return
uspixel[0] & 0xffff;
}
case
DataBuffer.
TYPE_INT:
{
int[]
ipixel = (int[])
pixel;
return
ipixel[0];
}
default:
throw new
UnsupportedOperationException("This method has not been "
+ "implemented for transferType " +
transferType);
}
}
/**
* Returns a data element array representation of a pixel in this
* <code>ColorModel</code>, given an array of normalized 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>normComponents</code> array is not large enough to hold
* all the color and alpha components (starting at
* <code>normOffset</code>). If the <code>obj</code> variable is
* <code>null</code>, a new array will be allocated. If
* <code>obj</code> is not <code>null</code>, it must be a primitive
* array of type transferType; 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>.
* @param normComponents an array of normalized color and alpha
* components
* @param normOffset the index into <code>normComponents</code> at which to
* begin retrieving color and alpha components
* @param obj a primitive data array to hold the returned pixel
* @return an <code>Object</code> which is a primitive data array
* representation of a pixel
* @throws ClassCastException if <code>obj</code>
* is not a primitive array of type <code>transferType</code>
* @throws ArrayIndexOutOfBoundsException if
* <code>obj</code> is not large enough to hold a pixel value
* for this <code>ColorModel</code> or the <code>normComponents</code>
* array is not large enough to hold all of the color and alpha
* components starting at <code>normOffset</code>
* @see WritableRaster#setDataElements
* @see SampleModel#setDataElements
* @since 1.4
*/
public
Object getDataElements(float[]
normComponents, int
normOffset,
Object obj) {
boolean
needAlpha =
supportsAlpha &&
isAlphaPremultiplied;
float[]
stdNormComponents;
if (
needScaleInit) {
initScale();
}
if (
nonStdScale) {
stdNormComponents = new float[
numComponents];
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
stdNormComponents[
c] = (
normComponents[
nc] -
compOffset[
c]) *
compScale[
c];
// REMIND: need to analyze whether this
// clamping is necessary
if (
stdNormComponents[
c] < 0.0f) {
stdNormComponents[
c] = 0.0f;
}
if (
stdNormComponents[
c] > 1.0f) {
stdNormComponents[
c] = 1.0f;
}
}
if (
supportsAlpha) {
stdNormComponents[
numColorComponents] =
normComponents[
numColorComponents +
normOffset];
}
normOffset = 0;
} else {
stdNormComponents =
normComponents;
}
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
byte[]
bpixel;
if (
obj == null) {
bpixel = new byte[
numComponents];
} else {
bpixel = (byte[])
obj;
}
if (
needAlpha) {
float
alpha =
stdNormComponents[
numColorComponents +
normOffset];
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
bpixel[
c] = (byte) ((
stdNormComponents[
nc] *
alpha) *
((float) ((1 <<
nBits[
c]) - 1)) + 0.5f);
}
bpixel[
numColorComponents] =
(byte) (
alpha *
((float) ((1 <<
nBits[
numColorComponents]) - 1)) +
0.5f);
} else {
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
bpixel[
c] = (byte) (
stdNormComponents[
nc] *
((float) ((1 <<
nBits[
c]) - 1)) + 0.5f);
}
}
return
bpixel;
case
DataBuffer.
TYPE_USHORT:
short[]
uspixel;
if (
obj == null) {
uspixel = new short[
numComponents];
} else {
uspixel = (short[])
obj;
}
if (
needAlpha) {
float
alpha =
stdNormComponents[
numColorComponents +
normOffset];
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
uspixel[
c] = (short) ((
stdNormComponents[
nc] *
alpha) *
((float) ((1 <<
nBits[
c]) - 1)) +
0.5f);
}
uspixel[
numColorComponents] =
(short) (
alpha *
((float) ((1 <<
nBits[
numColorComponents]) - 1)) +
0.5f);
} else {
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
uspixel[
c] = (short) (
stdNormComponents[
nc] *
((float) ((1 <<
nBits[
c]) - 1)) +
0.5f);
}
}
return
uspixel;
case
DataBuffer.
TYPE_INT:
int[]
ipixel;
if (
obj == null) {
ipixel = new int[
numComponents];
} else {
ipixel = (int[])
obj;
}
if (
needAlpha) {
float
alpha =
stdNormComponents[
numColorComponents +
normOffset];
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
ipixel[
c] = (int) ((
stdNormComponents[
nc] *
alpha) *
((float) ((1 <<
nBits[
c]) - 1)) + 0.5f);
}
ipixel[
numColorComponents] =
(int) (
alpha *
((float) ((1 <<
nBits[
numColorComponents]) - 1)) +
0.5f);
} else {
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
ipixel[
c] = (int) (
stdNormComponents[
nc] *
((float) ((1 <<
nBits[
c]) - 1)) + 0.5f);
}
}
return
ipixel;
case
DataBuffer.
TYPE_SHORT:
short[]
spixel;
if (
obj == null) {
spixel = new short[
numComponents];
} else {
spixel = (short[])
obj;
}
if (
needAlpha) {
float
alpha =
stdNormComponents[
numColorComponents +
normOffset];
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
spixel[
c] = (short)
(
stdNormComponents[
nc] *
alpha * 32767.0f + 0.5f);
}
spixel[
numColorComponents] = (short) (
alpha * 32767.0f + 0.5f);
} else {
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
spixel[
c] = (short)
(
stdNormComponents[
nc] * 32767.0f + 0.5f);
}
}
return
spixel;
case
DataBuffer.
TYPE_FLOAT:
float[]
fpixel;
if (
obj == null) {
fpixel = new float[
numComponents];
} else {
fpixel = (float[])
obj;
}
if (
needAlpha) {
float
alpha =
normComponents[
numColorComponents +
normOffset];
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
fpixel[
c] =
normComponents[
nc] *
alpha;
}
fpixel[
numColorComponents] =
alpha;
} else {
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
fpixel[
c] =
normComponents[
nc];
}
}
return
fpixel;
case
DataBuffer.
TYPE_DOUBLE:
double[]
dpixel;
if (
obj == null) {
dpixel = new double[
numComponents];
} else {
dpixel = (double[])
obj;
}
if (
needAlpha) {
double
alpha =
(double) (
normComponents[
numColorComponents +
normOffset]);
for (int
c = 0,
nc =
normOffset;
c <
numColorComponents;
c++,
nc++) {
dpixel[
c] =
normComponents[
nc] *
alpha;
}
dpixel[
numColorComponents] =
alpha;
} else {
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
dpixel[
c] = (double)
normComponents[
nc];
}
}
return
dpixel;
default:
throw new
UnsupportedOperationException("This method has not been "+
"implemented for transferType " +
transferType);
}
}
/**
* Returns an array of all of the color/alpha components in normalized
* form, given a pixel in this <code>ColorModel</code>. 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 <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>.
* Normalized components are float values between a per component minimum
* and maximum specified by the <code>ColorSpace</code> object for this
* <code>ColorModel</code>. If the
* <code>normComponents</code> array is <code>null</code>, a new array
* will be allocated. The <code>normComponents</code> array
* will be returned. Color/alpha components are stored in the
* <code>normComponents</code> array starting at
* <code>normOffset</code> (even if the array is allocated by this
* method). An <code>ArrayIndexOutOfBoundsException</code> is thrown
* if the <code>normComponents</code> array is not <code>null</code>
* and is not large enough to hold all the color and alpha components
* (starting at <code>normOffset</code>).
* <p>
* This method must be overridden by a subclass if that subclass
* is designed to translate pixel sample values to color component values
* in a non-default way. The default translations implemented by this
* class is described in the class comments. Any subclass implementing
* a non-default translation must follow the constraints on allowable
* translations defined there.
* @param pixel the specified pixel
* @param normComponents an array to receive the normalized components
* @param normOffset the offset into the <code>normComponents</code>
* array at which to start storing normalized components
* @return an array containing normalized color and alpha
* components.
* @throws ClassCastException if <code>pixel</code> is not a primitive
* array of type transferType
* @throws ArrayIndexOutOfBoundsException if
* <code>normComponents</code> is not large enough to hold all
* color and alpha components starting at <code>normOffset</code>
* @throws ArrayIndexOutOfBoundsException if
* <code>pixel</code> is not large enough to hold a pixel
* value for this <code>ColorModel</code>.
* @since 1.4
*/
public float[]
getNormalizedComponents(
Object pixel,
float[]
normComponents,
int
normOffset) {
if (
normComponents == null) {
normComponents = new float[
numComponents+
normOffset];
}
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
byte[]
bpixel = (byte[])
pixel;
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
normComponents[
nc] = ((float) (
bpixel[
c] & 0xff)) /
((float) ((1 <<
nBits[
c]) - 1));
}
break;
case
DataBuffer.
TYPE_USHORT:
short[]
uspixel = (short[])
pixel;
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
normComponents[
nc] = ((float) (
uspixel[
c] & 0xffff)) /
((float) ((1 <<
nBits[
c]) - 1));
}
break;
case
DataBuffer.
TYPE_INT:
int[]
ipixel = (int[])
pixel;
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
normComponents[
nc] = ((float)
ipixel[
c]) /
((float) ((1 <<
nBits[
c]) - 1));
}
break;
case
DataBuffer.
TYPE_SHORT:
short[]
spixel = (short[])
pixel;
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
normComponents[
nc] = ((float)
spixel[
c]) / 32767.0f;
}
break;
case
DataBuffer.
TYPE_FLOAT:
float[]
fpixel = (float[])
pixel;
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
normComponents[
nc] =
fpixel[
c];
}
break;
case
DataBuffer.
TYPE_DOUBLE:
double[]
dpixel = (double[])
pixel;
for (int
c = 0,
nc =
normOffset;
c <
numComponents;
c++,
nc++) {
normComponents[
nc] = (float)
dpixel[
c];
}
break;
default:
throw new
UnsupportedOperationException("This method has not been "+
"implemented for transferType " +
transferType);
}
if (
supportsAlpha &&
isAlphaPremultiplied) {
float
alpha =
normComponents[
numColorComponents +
normOffset];
if (
alpha != 0.0f) {
float
invAlpha = 1.0f /
alpha;
for (int
c =
normOffset;
c <
numColorComponents +
normOffset;
c++) {
normComponents[
c] *=
invAlpha;
}
}
}
if (
min != null) {
// Normally (i.e. when this class is not subclassed to override
// this method), the test (min != null) will be equivalent to
// the test (nonStdScale). However, there is an unlikely, but
// possible case, in which this method is overridden, nonStdScale
// is set true by initScale(), the subclass method for some
// reason calls this superclass method, but the min and
// diffMinMax arrays were never initialized by setupLUTs(). In
// that case, the right thing to do is follow the intended
// semantics of this method, and rescale the color components
// only if the ColorSpace min/max were detected to be other
// than 0.0/1.0 by setupLUTs(). Note that this implies the
// transferType is byte, ushort, int, or short - i.e. components
// derived from float and double pixel data are never rescaled.
for (int
c = 0;
c <
numColorComponents;
c++) {
normComponents[
c +
normOffset] =
min[
c] +
diffMinMax[
c] *
normComponents[
c +
normOffset];
}
}
return
normComponents;
}
/**
* Forces the raster data to match the state specified in the
* <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 also returns an instance of
* this <CODE>ColorModel</CODE> with
* the <CODE>isAlphaPremultiplied</CODE> flag set appropriately.
* 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
* <code>transferType</code>.
*
* @throws NullPointerException if <code>raster</code> is
* <code>null</code> and data coercion is required.
* @throws UnsupportedOperationException if the transfer type of
* this <CODE>ComponentColorModel</CODE>
* is not one of the supported transfer types:
* <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
* <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
* <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
*/
public
ColorModel coerceData (
WritableRaster raster,
boolean
isAlphaPremultiplied) {
if ((
supportsAlpha == false) ||
(this.
isAlphaPremultiplied ==
isAlphaPremultiplied))
{
// Nothing to do
return this;
}
int
w =
raster.
getWidth();
int
h =
raster.
getHeight();
int
aIdx =
raster.
getNumBands() - 1;
float
normAlpha;
int
rminX =
raster.
getMinX();
int
rY =
raster.
getMinY();
int
rX;
if (
isAlphaPremultiplied) {
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE: {
byte
pixel[] = null;
byte
zpixel[] = null;
float
alphaScale = 1.0f / ((float) ((1<<
nBits[
aIdx]) - 1));
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (byte[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha = (
pixel[
aIdx] & 0xff) *
alphaScale;
if (
normAlpha != 0.0f) {
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] = (byte)((
pixel[
c] & 0xff) *
normAlpha + 0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
} else {
if (
zpixel == null) {
zpixel = new byte[
numComponents];
java.util.
Arrays.
fill(
zpixel, (byte) 0);
}
raster.
setDataElements(
rX,
rY,
zpixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_USHORT: {
short
pixel[] = null;
short
zpixel[] = null;
float
alphaScale = 1.0f / ((float) ((1<<
nBits[
aIdx]) - 1));
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (short[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha = (
pixel[
aIdx] & 0xffff) *
alphaScale;
if (
normAlpha != 0.0f) {
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] = (short)
((
pixel[
c] & 0xffff) *
normAlpha +
0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
} else {
if (
zpixel == null) {
zpixel = new short[
numComponents];
java.util.
Arrays.
fill(
zpixel, (short) 0);
}
raster.
setDataElements(
rX,
rY,
zpixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_INT: {
int
pixel[] = null;
int
zpixel[] = null;
float
alphaScale = 1.0f / ((float) ((1<<
nBits[
aIdx]) - 1));
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (int[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha =
pixel[
aIdx] *
alphaScale;
if (
normAlpha != 0.0f) {
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] = (int) (
pixel[
c] *
normAlpha +
0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
} else {
if (
zpixel == null) {
zpixel = new int[
numComponents];
java.util.
Arrays.
fill(
zpixel, 0);
}
raster.
setDataElements(
rX,
rY,
zpixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_SHORT: {
short
pixel[] = null;
short
zpixel[] = null;
float
alphaScale = 1.0f / 32767.0f;
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (short[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha =
pixel[
aIdx] *
alphaScale;
if (
normAlpha != 0.0f) {
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] = (short) (
pixel[
c] *
normAlpha +
0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
} else {
if (
zpixel == null) {
zpixel = new short[
numComponents];
java.util.
Arrays.
fill(
zpixel, (short) 0);
}
raster.
setDataElements(
rX,
rY,
zpixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_FLOAT: {
float
pixel[] = null;
float
zpixel[] = null;
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (float[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha =
pixel[
aIdx];
if (
normAlpha != 0.0f) {
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] *=
normAlpha;
}
raster.
setDataElements(
rX,
rY,
pixel);
} else {
if (
zpixel == null) {
zpixel = new float[
numComponents];
java.util.
Arrays.
fill(
zpixel, 0.0f);
}
raster.
setDataElements(
rX,
rY,
zpixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_DOUBLE: {
double
pixel[] = null;
double
zpixel[] = null;
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (double[])
raster.
getDataElements(
rX,
rY,
pixel);
double
dnormAlpha =
pixel[
aIdx];
if (
dnormAlpha != 0.0) {
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] *=
dnormAlpha;
}
raster.
setDataElements(
rX,
rY,
pixel);
} else {
if (
zpixel == null) {
zpixel = new double[
numComponents];
java.util.
Arrays.
fill(
zpixel, 0.0);
}
raster.
setDataElements(
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: {
byte
pixel[] = null;
float
alphaScale = 1.0f / ((float) ((1<<
nBits[
aIdx]) - 1));
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (byte[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha = (
pixel[
aIdx] & 0xff) *
alphaScale;
if (
normAlpha != 0.0f) {
float
invAlpha = 1.0f /
normAlpha;
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] = (byte)
((
pixel[
c] & 0xff) *
invAlpha + 0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_USHORT: {
short
pixel[] = null;
float
alphaScale = 1.0f / ((float) ((1<<
nBits[
aIdx]) - 1));
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (short[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha = (
pixel[
aIdx] & 0xffff) *
alphaScale;
if (
normAlpha != 0.0f) {
float
invAlpha = 1.0f /
normAlpha;
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] = (short)
((
pixel[
c] & 0xffff) *
invAlpha + 0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_INT: {
int
pixel[] = null;
float
alphaScale = 1.0f / ((float) ((1<<
nBits[
aIdx]) - 1));
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (int[])
raster.
getDataElements(
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.
setDataElements(
rX,
rY,
pixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_SHORT: {
short
pixel[] = null;
float
alphaScale = 1.0f / 32767.0f;
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (short[])
raster.
getDataElements(
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] = (short)
(
pixel[
c] *
invAlpha + 0.5f);
}
raster.
setDataElements(
rX,
rY,
pixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_FLOAT: {
float
pixel[] = null;
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (float[])
raster.
getDataElements(
rX,
rY,
pixel);
normAlpha =
pixel[
aIdx];
if (
normAlpha != 0.0f) {
float
invAlpha = 1.0f /
normAlpha;
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] *=
invAlpha;
}
raster.
setDataElements(
rX,
rY,
pixel);
}
}
}
}
break;
case
DataBuffer.
TYPE_DOUBLE: {
double
pixel[] = null;
for (int
y = 0;
y <
h;
y++,
rY++) {
rX =
rminX;
for (int
x = 0;
x <
w;
x++,
rX++) {
pixel = (double[])
raster.
getDataElements(
rX,
rY,
pixel);
double
dnormAlpha =
pixel[
aIdx];
if (
dnormAlpha != 0.0) {
double
invAlpha = 1.0 /
dnormAlpha;
for (int
c=0;
c <
aIdx;
c++) {
pixel[
c] *=
invAlpha;
}
raster.
setDataElements(
rX,
rY,
pixel);
}
}
}
}
break;
default:
throw new
UnsupportedOperationException("This method has not been "+
"implemented for transferType " +
transferType);
}
}
// Return a new color model
if (!
signed) {
return new
ComponentColorModel(
colorSpace,
nBits,
supportsAlpha,
isAlphaPremultiplied,
transparency,
transferType);
} else {
return new
ComponentColorModel(
colorSpace,
supportsAlpha,
isAlphaPremultiplied,
transparency,
transferType);
}
}
/**
* Returns true if <CODE>raster</CODE> is compatible with this
* <CODE>ColorModel</CODE>; false if it is not.
*
* @param raster The <CODE>Raster</CODE> object to test for compatibility.
*
* @return <CODE>true</CODE> if <CODE>raster</CODE> is compatible with this
* <CODE>ColorModel</CODE>, <CODE>false</CODE> if it is not.
*/
public boolean
isCompatibleRaster(
Raster raster) {
SampleModel sm =
raster.
getSampleModel();
if (
sm instanceof
ComponentSampleModel) {
if (
sm.
getNumBands() !=
getNumComponents()) {
return false;
}
for (int
i=0;
i<
nBits.length;
i++) {
if (
sm.
getSampleSize(
i) <
nBits[
i]) {
return false;
}
}
return (
raster.
getTransferType() ==
transferType);
}
else {
return false;
}
}
/**
* 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 of the <CODE>WritableRaster</CODE> you want to create.
* @param h The height of the <CODE>WritableRaster</CODE> you want to create.
*
* @return A <CODE>WritableRaster</CODE> that is compatible with
* this <CODE>ColorModel</CODE>.
* @see WritableRaster
* @see SampleModel
*/
public
WritableRaster createCompatibleWritableRaster (int
w, int
h) {
int
dataSize =
w*
h*
numComponents;
WritableRaster raster = null;
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
case
DataBuffer.
TYPE_USHORT:
raster =
Raster.
createInterleavedRaster(
transferType,
w,
h,
numComponents, null);
break;
default:
SampleModel sm =
createCompatibleSampleModel(
w,
h);
DataBuffer db =
sm.
createDataBuffer();
raster =
Raster.
createWritableRaster(
sm,
db, null);
}
return
raster;
}
/**
* Creates a <CODE>SampleModel</CODE> with the specified width and height,
* that has a data layout compatible with this <CODE>ColorModel</CODE>.
*
* @param w The width of the <CODE>SampleModel</CODE> you want to create.
* @param h The height of the <CODE>SampleModel</CODE> you want to create.
*
* @return A <CODE>SampleModel</CODE> that is compatible with this
* <CODE>ColorModel</CODE>.
*
* @see SampleModel
*/
public
SampleModel createCompatibleSampleModel(int
w, int
h) {
int[]
bandOffsets = new int[
numComponents];
for (int
i=0;
i <
numComponents;
i++) {
bandOffsets[
i] =
i;
}
switch (
transferType) {
case
DataBuffer.
TYPE_BYTE:
case
DataBuffer.
TYPE_USHORT:
return new
PixelInterleavedSampleModel(
transferType,
w,
h,
numComponents,
w*
numComponents,
bandOffsets);
default:
return new
ComponentSampleModel(
transferType,
w,
h,
numComponents,
w*
numComponents,
bandOffsets);
}
}
/**
* Checks whether or not the specified <CODE>SampleModel</CODE>
* is compatible with this <CODE>ColorModel</CODE>.
*
* @param sm The <CODE>SampleModel</CODE> to test for compatibility.
*
* @return <CODE>true</CODE> if the <CODE>SampleModel</CODE> is
* compatible with this <CODE>ColorModel</CODE>, <CODE>false</CODE>
* if it is not.
*
* @see SampleModel
*/
public boolean
isCompatibleSampleModel(
SampleModel sm) {
if (!(
sm instanceof
ComponentSampleModel)) {
return false;
}
// Must have the same number of components
if (
numComponents !=
sm.
getNumBands()) {
return false;
}
if (
sm.
getTransferType() !=
transferType) {
return false;
}
return true;
}
/**
* Returns a <CODE>Raster</CODE> representing the alpha channel of an image,
* extracted from the input <CODE>Raster</CODE>.
* This method assumes that <CODE>Raster</CODE> objects associated with
* this <CODE>ColorModel</CODE> store the alpha band, if present, as
* the last band of image data. Returns null if there is no separate spatial
* alpha channel associated with this <CODE>ColorModel</CODE>.
* This method creates a new <CODE>Raster</CODE>, but will share the data
* array.
*
* @param raster The <CODE>WritableRaster</CODE> from which to extract the
* alpha channel.
*
* @return A <CODE>WritableRaster</CODE> containing the image's alpha channel.
*
*/
public
WritableRaster getAlphaRaster(
WritableRaster raster) {
if (
hasAlpha() == false) {
return null;
}
int
x =
raster.
getMinX();
int
y =
raster.
getMinY();
int[]
band = new int[1];
band[0] =
raster.
getNumBands() - 1;
return
raster.
createWritableChild(
x,
y,
raster.
getWidth(),
raster.
getHeight(),
x,
y,
band);
}
/**
* Compares this color model with another for equality.
*
* @param obj The object to compare with this color model.
* @return <CODE>true</CODE> if the color model objects are equal,
* <CODE>false</CODE> if they are not.
*/
public boolean
equals(
Object obj) {
if (!super.equals(
obj)) {
return false;
}
if (
obj.
getClass() !=
getClass()) {
return false;
}
return true;
}
}