alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ComponentColorModel.java)

This example Java source code file (ComponentColorModel.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt, color, colormodel, colorspace, component, componentcolormodel, componentsamplemodel, icc_colorspace, illegalargumentexception, length, more, object, samplemodel, this, unsupportedoperationexception, writableraster

The ComponentColorModel.java Java example source code

/*
 * 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 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.  The number of
 * color samples in the pixel values must be same as the number of
 * color components in the <CODE>ColorSpace. There may be a
 * single alpha sample.
 * <p>
 * For those methods that use
 * a primitive array pixel representation of type <CODE>transferType,
 * 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.  Typically, this order reflects the
 * name of the color space type. For example, for <CODE>TYPE_RGB,
 * 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, 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 and getMaxValue
 * methods of the <code>ColorSpace class.  The range for an
 * alpha component should be 0.0 to 1.0.
 * <p>
 * Instances of <code>ComponentColorModel created with transfer types
 * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
 * and <CODE>DataBuffer.TYPE_INT 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)
 * 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 - 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 getMinValue
 * method for each component and 2<sup>n - 1 maps to the value
 * obtained from <code>getMaxValue.  To create a
 * <code>ComponentColorModel with a different color sample mapping
 * requires subclassing this class and overriding the
 * <code>getNormalizedComponents(Object, float[], int) method.
 * The mapping for an alpha sample always maps 0 to 0.0 and
 * 2<sup>n - 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 - 1
 * to 1.0.  Second the min/max range of all color components of the
 * <code>ColorSpace 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 - 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.
 * <p>
 * Instances of <code>ComponentColorModel created with transfer types
 * <CODE>DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, and
 * <CODE>DataBuffer.TYPE_DOUBLE 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 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
 * (-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) 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 created with transfer types
 * <CODE>DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, and
 * <CODE>DataBuffer.TYPE_DOUBLE
 * use all the bits of all sample values.  Thus all color/alpha components
 * have 16 bits when using <CODE>DataBuffer.TYPE_SHORT, 32 bits when
 * using <CODE>DataBuffer.TYPE_FLOAT, and 64 bits when using
 * <CODE>DataBuffer.TYPE_DOUBLE.  When the
 * <code>ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)
 * 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 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 (obtained using the getMinValue
 * and <code>getMaxValue methods of the ColorSpace 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, unless the number of components
 * for the <CODE>ComponentColorModel 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>DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
 * and no alpha.
 * <p>
 * A <CODE>ComponentColorModel can be used in conjunction with a
 * <CODE>ComponentSampleModel, a BandedSampleModel,
 * or a <CODE>PixelInterleavedSampleModel to construct a
 * <CODE>BufferedImage.
 *
 * @see ColorModel
 * @see ColorSpace
 * @see ComponentSampleModel
 * @see BandedSampleModel
 * @see PixelInterleavedSampleModel
 * @see BufferedImage
 *
 */
public class ComponentColorModel extends ColorModel {

    /**
     * <code>signed  is true for short,
     * <code>float, and double transfer types; it
     * is <code>false for byte, ushort,
     * and <code>int 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 from the specified
     * parameters. Color components will be in the specified
     * <CODE>ColorSpace.  The supported transfer types are
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT,
     * <CODE>DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
     * and <CODE>DataBuffer.TYPE_DOUBLE.
     * If not null, the <CODE>bits 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 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 is
     * <CODE>DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
     * or <CODE>DataBuffer.TYPE_DOUBLE the bits array
     * argument is ignored.  <CODE>hasAlpha indicates whether alpha
     * information is present.  If <CODE>hasAlpha is true, then
     * the boolean <CODE>isAlphaPremultiplied
     * specifies how to interpret color and alpha samples in pixel values.
     * If the boolean is true, color samples are assumed to have been
     * multiplied by the alpha sample. The <CODE>transparency
     * specifies what alpha values can be represented by this color model.
     * The acceptable <code>transparency values are
     * <CODE>OPAQUE, BITMASK or TRANSLUCENT.
     * The <CODE>transferType is the type of primitive array used
     * to represent pixel values.
     *
     * @param colorSpace       The <CODE>ColorSpace 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>DataBuffer.TYPE_FLOAT, or
     *                         <CODE>DataBuffer.TYPE_DOUBLE,
     *                         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 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>DataBuffer.TYPE_USHORT, or
     *         <CODE>DataBuffer.TYPE_INT.
     * @throws IllegalArgumentException If transferType is not one of
     *         <CODE>DataBuffer.TYPE_BYTE,
     *         <CODE>DataBuffer.TYPE_USHORT,
     *         <CODE>DataBuffer.TYPE_INT,
     *         <CODE>DataBuffer.TYPE_SHORT,
     *         <CODE>DataBuffer.TYPE_FLOAT, or
     *         <CODE>DataBuffer.TYPE_DOUBLE.
     *
     * @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 from the specified
     * parameters. Color components will be in the specified
     * <CODE>ColorSpace.  The supported transfer types are
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT,
     * <CODE>DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
     * and <CODE>DataBuffer.TYPE_DOUBLE.  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.  There will be
     * an alpha component if <CODE>hasAlpha is true.
     * If <CODE>hasAlpha is true, then
     * the boolean <CODE>isAlphaPremultiplied
     * specifies how to interpret color and alpha samples in pixel values.
     * If the boolean is true, color samples are assumed to have been
     * multiplied by the alpha sample. The <CODE>transparency
     * specifies what alpha values can be represented by this color model.
     * The acceptable <code>transparency values are
     * <CODE>OPAQUE, BITMASK or TRANSLUCENT.
     * The <CODE>transferType is the type of primitive array used
     * to represent pixel values.
     *
     * @param colorSpace       The <CODE>ColorSpace 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>DataBuffer.TYPE_USHORT,
     *         <CODE>DataBuffer.TYPE_INT,
     *         <CODE>DataBuffer.TYPE_SHORT,
     *         <CODE>DataBuffer.TYPE_FLOAT, or
     *         <CODE>DataBuffer.TYPE_DOUBLE.
     *
     * @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.
     * @throws IllegalArgumentException If the component value for this
     * <CODE>ColorModel 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.
     * @throws IllegalArgumentException If the component value for this
     * <CODE>ColorModel 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.
     * @throws IllegalArgumentException If the component value for this
     * <CODE>ColorModel 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.
     * @throws IllegalArgumentException If the component value for this
     * <CODE>ColorModel 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<.
     * @throws IllegalArgumentException If the component value for this
     * <CODE>ColorModel 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< value is specified by an array
     * of data elements of type <CODE>transferType 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 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.
     *
     * @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.
     *
     * @return The red color component for the specified pixel, as an int.
     *
     * @throws ClassCastException If <CODE>inData is not a primitive array
     * of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException if <CODE>inData is not
     * large enough to hold a pixel value for this
     * <CODE>ColorModel.
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     */
    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, sRGB.
     * A color conversion is done if necessary.  The <CODE>pixel value
     * is specified by an array of data elements of type <CODE>transferType
     * 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 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.
     *
     * @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.
     *
     * @return The green color component for the specified pixel, as an int.
     *
     * @throws ClassCastException If <CODE>inData is not a primitive array
     * of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException if <CODE>inData is not
     * large enough to hold a pixel value for this
     * <CODE>ColorModel.
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     */
    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, sRGB.
     * A color conversion is done if necessary.  The <CODE>pixel value is
     * specified by an array of data elements of type <CODE>transferType
     * 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 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.
     *
     * @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.
     *
     * @return The blue color component for the specified pixel, as an int.
     *
     * @throws ClassCastException If <CODE>inData is not a primitive array
     * of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException if <CODE>inData is not
     * large enough to hold a pixel value for this
     * <CODE>ColorModel.
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     */
    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 passed in as an
     * object reference.  Since <code>ComponentColorModel 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.
     *
     * @param inData The pixel from which you want to get the alpha component,
     * specified by an array of data elements of type <CODE>transferType.
     *
     * @return The alpha component for the specified pixel, as an int.
     *
     * @throws ClassCastException If <CODE>inData is not a primitive array
     * of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException if <CODE>inData is not
     * large enough to hold a pixel value for this
     * <CODE>ColorModel.
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     */
    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 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 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.
     *
     * @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.
     *
     * @return The color/alpha components for the specified pixel, as an int.
     *
     * @throws ClassCastException If <CODE>inData is not a primitive array
     * of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException if <CODE>inData is not
     * large enough to hold a pixel value for this
     * <CODE>ColorModel.
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     * @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, given an integer pixel representation
     * in the default RGB color model.
     * This array can then be passed to the <CODE>setDataElements
     * method of a <CODE>WritableRaster object.  If the
     * <CODE>pixel
     * parameter is null, a new array is allocated.  Since
     * <code>ComponentColorModel 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.
     *
     * @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.
     * @throws ClassCastException If <CODE>pixel is not null and
     * is not a primitive array of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException If <CODE>pixel is
     * not large enough to hold a pixel value for this
     * <CODE>ColorModel.
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     *
     * @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<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<.
     * An IllegalArgumentException is thrown if the component value for this
     * <CODE>ColorModel is not conveniently representable in the
     * unnormalized form.  Color/alpha components are stored
     * in the <CODE>components array starting at offset
     * (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 array is null,
     * a new array is allocated.
     * @param offset An offset into the <CODE>components array.
     *
     * @return The components array.
     *
     * @throws IllegalArgumentException If there is more than one
     * component in this <CODE>ColorModel.
     * @throws IllegalArgumentException If this
     * <CODE>ColorModel does not support the unnormalized form
     * @throws ArrayIndexOutOfBoundsException If the <CODE>components
     * 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<.  The pixel value is specified by an
     * array of data elements of type <CODE>transferType passed in as
     * an object reference.
     * An IllegalArgumentException is thrown if the component values for this
     * <CODE>ColorModel are not conveniently representable in the
     * unnormalized form.
     * Color/alpha components are stored in the <CODE>components array
     * starting at  <CODE>offset (even if the array is allocated by
     * this method).  Since <code>ComponentColorModel 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.
     *
     * @param pixel A pixel value specified by an array of data elements of
     * type <CODE>transferType.
     * @param components An integer array in which to store the unnormalized
     * color/alpha components. If the <CODE>components array is null,
     * a new array is allocated.
     * @param offset An offset into the <CODE>components array.
     *
     * @return The <CODE>components array.
     *
     * @throws IllegalArgumentException If this
     * <CODE>ComponentColorModel does not support the unnormalized form
     * @throws UnsupportedOperationException in some cases iff the
     * transfer type of this <CODE>ComponentColorModel
     * is not one of the following transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * or <CODE>DataBuffer.TYPE_INT.
     * @throws ClassCastException If <CODE>pixel is not a primitive
     * array of type <CODE>transferType.
     * @throws IllegalArgumentException If the <CODE>components array is
     * not null and is not large enough to hold all the color and alpha
     * components (starting at offset), or if <CODE>pixel 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 - 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 object for this
     * <code>ColorModel.  An IllegalArgumentException
     * will be thrown if color component values for this
     * <code>ColorModel are not conveniently representable in the
     * unnormalized form.  If the
     * <code>components array is null, a new array
     * will be allocated.  The <code>components array will
     * be returned.  Color/alpha components are stored in the
     * <code>components array starting at offset (even
     * if the array is allocated by this method). An
     * <code>ArrayIndexOutOfBoundsException is thrown if the
     * <code>components array is not null and is not
     * large enough to hold all the color and alpha
     * components (starting at <code>offset).  An
     * <code>IllegalArgumentException is thrown if the
     * <code>normComponents array is not large enough to hold
     * all the color and alpha components starting at
     * <code>normOffset.
     * @param normComponents an array containing normalized components
     * @param normOffset the offset into the <code>normComponents
     * array at which to start retrieving normalized components
     * @param components an array that receives the components from
     * <code>normComponents
     * @param offset the index into <code>components at which to
     * begin storing normalized components from
     * <code>normComponents
     * @return an array containing unnormalized color and alpha
     * components.
     * @throws IllegalArgumentException If this
     * <CODE>ComponentColorModel does not support the unnormalized form
     * @throws IllegalArgumentException if the length of
     *          <code>normComponents minus normOffset
     *          is less than <code>numComponents
     */
    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 - 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 object for this
     * <code>ColorModel.  An IllegalArgumentException
     * will be thrown if color component values for this
     * <code>ColorModel are not conveniently representable in the
     * unnormalized form.  If the
     * <code>normComponents array is null, a new array
     * will be allocated.  The <code>normComponents array
     * will be returned.  Color/alpha components are stored in the
     * <code>normComponents array starting at
     * <code>normOffset (even if the array is allocated by this
     * method).  An <code>ArrayIndexOutOfBoundsException is thrown
     * if the <code>normComponents array is not null
     * and is not large enough to hold all the color and alpha components
     * (starting at <code>normOffset).  An
     * <code>IllegalArgumentException is thrown if the
     * <code>components array is not large enough to hold all the
     * color and alpha components starting at <code>offset.
     * @param components an array containing unnormalized components
     * @param offset the offset into the <code>components array at
     * which to start retrieving unnormalized components
     * @param normComponents an array that receives the normalized components
     * @param normOffset the index into <code>normComponents at
     * which to begin storing normalized components
     * @return an array containing normalized color and alpha
     * components.
     * @throws IllegalArgumentException If this
     * <CODE>ComponentColorModel 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,
     * 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 array.
     *
     * @return A pixel value represented as an int.
     *
     * @throws IllegalArgumentException If there is more than one component
     * in this <CODE>ColorModel.
     * @throws IllegalArgumentException If this
     * <CODE>ComponentColorModel 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, given an array of unnormalized color/alpha
     * components. This array can then be passed to the <CODE>setDataElements
     * method of a <CODE>WritableRaster object.
     *
     * @param components An array of unnormalized color/alpha components.
     * @param offset The integer offset into the <CODE>components array.
     * @param obj The object in which to store the data element array
     * representation of the pixel. If <CODE>obj variable is null,
     * a new array is allocated.  If <CODE>obj is not null, it must
     * be a primitive array of type <CODE>transferType. An
     * <CODE>ArrayIndexOutOfBoundsException is thrown if
     * <CODE>obj is not large enough to hold a pixel value
     * for this <CODE>ColorModel.  Since
     * <code>ComponentColorModel 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.
     *
     * @return The data element array representation of a pixel
     * in this <CODE>ColorModel.
     *
     * @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 is not null and is not a
     * primitive  array of type <CODE>transferType.
     * @throws ArrayIndexOutOfBoundsException If <CODE>obj is not large
     * enough to hold a pixel value for this <CODE>ColorModel.
     * @throws IllegalArgumentException If this
     * <CODE>ComponentColorModel does not support the unnormalized form
     * @throws UnsupportedOperationException If the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the following transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * or <CODE>DataBuffer.TYPE_INT.
     *
     * @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 in this
     * <code>ColorModel, given an array of normalized color/alpha
     * components.  This method will throw an
     * <code>IllegalArgumentException if pixel values for this
     * <code>ColorModel are not conveniently representable as a
     * single <code>int.  An
     * <code>ArrayIndexOutOfBoundsException is thrown if  the
     * <code>normComponents array is not large enough to hold all the
     * color and alpha components (starting at <code>normOffset).
     * @param normComponents an array of normalized color and alpha
     * components
     * @param normOffset the index into <code>normComponents at which to
     * begin retrieving the color and alpha components
     * @return an <code>int pixel value in this
     * <code>ColorModel corresponding to the specified components.
     * @throws IllegalArgumentException if
     *  pixel values for this <code>ColorModel are not
     *  conveniently representable as a single <code>int
     * @throws ArrayIndexOutOfBoundsException if
     *  the <code>normComponents array is not large enough to
     *  hold all of the color and alpha components starting at
     *  <code>normOffset
     * @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, given an array of normalized color/alpha
     * components.  This array can then be passed to the
     * <code>setDataElements method of a WritableRaster
     * object.  An <code>ArrayIndexOutOfBoundsException is thrown
     * if the <code>normComponents array is not large enough to hold
     * all the color and alpha components (starting at
     * <code>normOffset).  If the obj variable is
     * <code>null, a new array will be allocated.  If
     * <code>obj is not null, it must be a primitive
     * array of type transferType; otherwise, a
     * <code>ClassCastException is thrown.  An
     * <code>ArrayIndexOutOfBoundsException is thrown if
     * <code>obj is not large enough to hold a pixel value for this
     * <code>ColorModel.
     * @param normComponents an array of normalized color and alpha
     * components
     * @param normOffset the index into <code>normComponents at which to
     * begin retrieving color and alpha components
     * @param obj a primitive data array to hold the returned pixel
     * @return an <code>Object which is a primitive data array
     * representation of a pixel
     * @throws ClassCastException if <code>obj
     *  is not a primitive array of type <code>transferType
     * @throws ArrayIndexOutOfBoundsException if
     *  <code>obj is not large enough to hold a pixel value
     *  for this <code>ColorModel or the normComponents
     *  array is not large enough to hold all of the color and alpha
     *  components starting at <code>normOffset
     * @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.  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 is thrown.
     * An <code>ArrayIndexOutOfBoundsException is thrown if
     * <code>pixel is not large enough to hold a pixel value for this
     * <code>ColorModel.
     * Normalized components are float values between a per component minimum
     * and maximum specified by the <code>ColorSpace object for this
     * <code>ColorModel.  If the
     * <code>normComponents array is null, a new array
     * will be allocated.  The <code>normComponents array
     * will be returned.  Color/alpha components are stored in the
     * <code>normComponents array starting at
     * <code>normOffset (even if the array is allocated by this
     * method).  An <code>ArrayIndexOutOfBoundsException is thrown
     * if the <code>normComponents array is not null
     * and is not large enough to hold all the color and alpha components
     * (starting at <code>normOffset).
     * <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
     * array at which to start storing normalized components
     * @return an array containing normalized color and alpha
     * components.
     * @throws ClassCastException if <code>pixel is not a primitive
     *          array of type transferType
     * @throws ArrayIndexOutOfBoundsException if
     *          <code>normComponents is not large enough to hold all
     *          color and alpha components starting at <code>normOffset
     * @throws ArrayIndexOutOfBoundsException if
     *          <code>pixel is not large enough to hold a pixel
     *          value for this <code>ColorModel.
     * @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 variable, assuming the data
     * is currently correctly described by this <CODE>ColorModel.
     * It may multiply or divide the color raster data by alpha, or
     * do nothing if the data is in the correct state.  If the data needs
     * to be coerced, this method also returns an instance of
     * this <CODE>ColorModel with
     * the <CODE>isAlphaPremultiplied flag set appropriately.
     * Since <code>ColorModel can be subclassed, subclasses inherit
     * the implementation of this method and if they don't override it
     * then they throw an exception if they use an unsupported
     * <code>transferType.
     *
     * @throws NullPointerException if <code>raster is
     * <code>null and data coercion is required.
     * @throws UnsupportedOperationException if the transfer type of
     * this <CODE>ComponentColorModel
     * is not one of the supported transfer types:
     * <CODE>DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
     * <CODE>DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
     * <CODE>DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
     */
    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< is compatible with this
      * <CODE>ColorModel; false if it is not.
      *
      * @param raster The <CODE>Raster object to test for compatibility.
      *
      * @return <CODE>true if raster is compatible with this
      * <CODE>ColorModel, false 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 with the specified width and height,
     * that  has a data layout (<CODE>SampleModel) compatible with
     * this <CODE>ColorModel.
     *
     * @param w The width of the <CODE>WritableRaster you want to create.
     * @param h The height of the <CODE>WritableRaster you want to create.
     *
     * @return A <CODE>WritableRaster that is compatible with
     * this <CODE>ColorModel.
     * @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 with the specified width and height,
     * that  has a data layout compatible with this <CODE>ColorModel.
     *
     * @param w The width of the <CODE>SampleModel you want to create.
     * @param h The height of the <CODE>SampleModel you want to create.
     *
     * @return A <CODE>SampleModel that is compatible with this
     * <CODE>ColorModel.
     *
     * @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
     * is compatible with this <CODE>ColorModel.
     *
     * @param sm The <CODE>SampleModel to test for compatibility.
     *
     * @return <CODE>true if the SampleModel is
     * compatible with this <CODE>ColorModel, false
     * 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 representing the alpha channel of an image,
     * extracted from the input <CODE>Raster.
     * This method assumes that <CODE>Raster objects associated with
     * this <CODE>ColorModel 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.
     * This method creates a new <CODE>Raster, but will share the data
     * array.
     *
     * @param raster The <CODE>WritableRaster from which to extract the
     * alpha  channel.
     *
     * @return A <CODE>WritableRaster 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 if the color model objects are equal,
     * <CODE>false if they are not.
     */
    public boolean equals(Object obj) {
        if (!super.equals(obj)) {
            return false;
        }

        if (obj.getClass() !=  getClass()) {
            return false;
        }

        return true;
    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java ComponentColorModel.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.