- /*
- * @(#)ComponentColorModel.java 1.68 03/12/19
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN 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
- *
- * @version 10 Feb 1997
- */
- 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 overrridden 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;
- }
-
- }
-