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