1 /*
   2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.image;
  27 
  28 import java.awt.color.ColorSpace;
  29 import java.awt.color.ICC_ColorSpace;
  30 import java.util.Arrays;
  31 import java.util.Objects;
  32 
  33 /**
  34  * A {@code ColorModel} class that works with pixel values that
  35  * represent color and alpha information as separate samples and that
  36  * store each sample in a separate data element.  This class can be
  37  * used with an arbitrary {@code ColorSpace}.  The number of
  38  * color samples in the pixel values must be same as the number of
  39  * color components in the {@code ColorSpace}. There may be a
  40  * single alpha sample.
  41  * <p>
  42  * For those methods that use
  43  * a primitive array pixel representation of type {@code transferType},
  44  * the array length is the same as the number of color and alpha samples.
  45  * Color samples are stored first in the array followed by the alpha
  46  * sample, if present.  The order of the color samples is specified
  47  * by the {@code ColorSpace}.  Typically, this order reflects the
  48  * name of the color space type. For example, for {@code TYPE_RGB},
  49  * index 0 corresponds to red, index 1 to green, and index 2 to blue.
  50  * <p>
  51  * The translation from pixel sample values to color/alpha components for
  52  * display or processing purposes is based on a one-to-one correspondence of
  53  * samples to components.
  54  * Depending on the transfer type used to create an instance of
  55  * {@code ComponentColorModel}, the pixel sample values
  56  * represented by that instance may be signed or unsigned and may
  57  * be of integral type or float or double (see below for details).
  58  * The translation from sample values to normalized color/alpha components
  59  * must follow certain rules.  For float and double samples, the translation
  60  * is an identity, i.e. normalized component values are equal to the
  61  * corresponding sample values.  For integral samples, the translation
  62  * should be only a simple scale and offset, where the scale and offset
  63  * constants may be different for each component.  The result of
  64  * applying the scale and offset constants is a set of color/alpha
  65  * component values, which are guaranteed to fall within a certain
  66  * range.  Typically, the range for a color component will be the range
  67  * defined by the {@code getMinValue} and {@code getMaxValue}
  68  * methods of the {@code ColorSpace} class.  The range for an
  69  * alpha component should be 0.0 to 1.0.
  70  * <p>
  71  * Instances of {@code ComponentColorModel} created with transfer types
  72  * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
  73  * and {@code DataBuffer.TYPE_INT} have pixel sample values which
  74  * are treated as unsigned integral values.
  75  * The number of bits in a color or alpha sample of a pixel value might not
  76  * be the same as the number of bits for the corresponding color or alpha
  77  * sample passed to the
  78  * {@code ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)}
  79  * constructor.  In
  80  * that case, this class assumes that the least significant n bits of a sample
  81  * value hold the component value, where n is the number of significant bits
  82  * for the component passed to the constructor.  It also assumes that
  83  * any higher-order bits in a sample value are zero.  Thus, sample values
  84  * range from 0 to 2<sup>n</sup> - 1.  This class maps these sample values
  85  * to normalized color component values such that 0 maps to the value
  86  * obtained from the {@code ColorSpace's getMinValue}
  87  * method for each component and 2<sup>n</sup> - 1 maps to the value
  88  * obtained from {@code getMaxValue}.  To create a
  89  * {@code ComponentColorModel} with a different color sample mapping
  90  * requires subclassing this class and overriding the
  91  * {@code getNormalizedComponents(Object, float[], int)} method.
  92  * The mapping for an alpha sample always maps 0 to 0.0 and
  93  * 2<sup>n</sup> - 1 to 1.0.
  94  * <p>
  95  * For instances with unsigned sample values,
  96  * the unnormalized color/alpha component representation is only
  97  * supported if two conditions hold.  First, sample value 0 must
  98  * map to normalized component value 0.0 and sample value 2<sup>n</sup> - 1
  99  * to 1.0.  Second the min/max range of all color components of the
 100  * {@code ColorSpace} must be 0.0 to 1.0.  In this case, the
 101  * component representation is the n least
 102  * significant bits of the corresponding sample.  Thus each component is
 103  * an unsigned integral value between 0 and 2<sup>n</sup> - 1, where
 104  * n is the number of significant bits for a particular component.
 105  * If these conditions are not met, any method taking an unnormalized
 106  * component argument will throw an {@code IllegalArgumentException}.
 107  * <p>
 108  * Instances of {@code ComponentColorModel} created with transfer types
 109  * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, and
 110  * {@code DataBuffer.TYPE_DOUBLE} have pixel sample values which
 111  * are treated as signed short, float, or double values.
 112  * Such instances do not support the unnormalized color/alpha component
 113  * representation, so any methods taking such a representation as an argument
 114  * will throw an {@code IllegalArgumentException} when called on one
 115  * of these instances.  The normalized component values of instances
 116  * of this class have a range which depends on the transfer
 117  * type as follows: for float samples, the full range of the float data
 118  * type; for double samples, the full range of the float data type
 119  * (resulting from casting double to float); for short samples,
 120  * from approximately -maxVal to +maxVal, where maxVal is the per
 121  * component maximum value for the {@code ColorSpace}
 122  * (-32767 maps to -maxVal, 0 maps to 0.0, and 32767 maps
 123  * to +maxVal).  A subclass may override the scaling for short sample
 124  * values to normalized component values by overriding the
 125  * {@code getNormalizedComponents(Object, float[], int)} method.
 126  * For float and double samples, the normalized component values are
 127  * taken to be equal to the corresponding sample values, and subclasses
 128  * should not attempt to add any non-identity scaling for these transfer
 129  * types.
 130  * <p>
 131  * Instances of {@code ComponentColorModel} created with transfer types
 132  * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, and
 133  * {@code DataBuffer.TYPE_DOUBLE}
 134  * use all the bits of all sample values.  Thus all color/alpha components
 135  * have 16 bits when using {@code DataBuffer.TYPE_SHORT}, 32 bits when
 136  * using {@code DataBuffer.TYPE_FLOAT}, and 64 bits when using
 137  * {@code DataBuffer.TYPE_DOUBLE}.  When the
 138  * {@code ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)}
 139  * form of constructor is used with one of these transfer types, the
 140  * bits array argument is ignored.
 141  * <p>
 142  * It is possible to have color/alpha sample values
 143  * which cannot be reasonably interpreted as component values for rendering.
 144  * This can happen when {@code ComponentColorModel} is subclassed to
 145  * override the mapping of unsigned sample values to normalized color
 146  * component values or when signed sample values outside a certain range
 147  * are used.  (As an example, specifying an alpha component as a signed
 148  * short value outside the range 0 to 32767, normalized range 0.0 to 1.0, can
 149  * lead to unexpected results.) It is the
 150  * responsibility of applications to appropriately scale pixel data before
 151  * rendering such that color components fall within the normalized range
 152  * of the {@code ColorSpace} (obtained using the {@code getMinValue}
 153  * and {@code getMaxValue} methods of the {@code ColorSpace} class)
 154  * and the alpha component is between 0.0 and 1.0.  If color or alpha
 155  * component values fall outside these ranges, rendering results are
 156  * indeterminate.
 157  * <p>
 158  * Methods that use a single int pixel representation throw
 159  * an {@code IllegalArgumentException}, unless the number of components
 160  * for the {@code ComponentColorModel} is one and the component
 161  * value is unsigned -- in other words,  a single color component using
 162  * a transfer type of {@code DataBuffer.TYPE_BYTE},
 163  * {@code DataBuffer.TYPE_USHORT}, or {@code DataBuffer.TYPE_INT}
 164  * and no alpha.
 165  * <p>
 166  * A {@code ComponentColorModel} can be used in conjunction with a
 167  * {@code ComponentSampleModel}, a {@code BandedSampleModel},
 168  * or a {@code PixelInterleavedSampleModel} to construct a
 169  * {@code BufferedImage}.
 170  *
 171  * @see ColorModel
 172  * @see ColorSpace
 173  * @see ComponentSampleModel
 174  * @see BandedSampleModel
 175  * @see PixelInterleavedSampleModel
 176  * @see BufferedImage
 177  *
 178  */
 179 public class ComponentColorModel extends ColorModel {
 180 
 181     /**
 182      * {@code signed}  is {@code true} for {@code short},
 183      * {@code float}, and {@code double} transfer types; it
 184      * is {@code false} for {@code byte}, {@code ushort},
 185      * and {@code int} transfer types.
 186      */
 187     private boolean signed; // true for transfer types short, float, double
 188                             // false for byte, ushort, int
 189     private boolean is_sRGB_stdScale;
 190     private boolean is_LinearRGB_stdScale;
 191     private boolean is_LinearGray_stdScale;
 192     private boolean is_ICCGray_stdScale;
 193     private byte[] tosRGB8LUT;
 194     private byte[] fromsRGB8LUT8;
 195     private short[] fromsRGB8LUT16;
 196     private byte[] fromLinearGray16ToOtherGray8LUT;
 197     private short[] fromLinearGray16ToOtherGray16LUT;
 198     private boolean needScaleInit;
 199     private boolean noUnnorm;
 200     private boolean nonStdScale;
 201     private float[] min;
 202     private float[] diffMinMax;
 203     private float[] compOffset;
 204     private float[] compScale;
 205     private volatile int hashCode;
 206 
 207     /**
 208      * Constructs a {@code ComponentColorModel} from the specified
 209      * parameters. Color components will be in the specified
 210      * {@code ColorSpace}.  The supported transfer types are
 211      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
 212      * {@code DataBuffer.TYPE_INT},
 213      * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT},
 214      * and {@code DataBuffer.TYPE_DOUBLE}.
 215      * If not null, the {@code bits} array specifies the
 216      * number of significant bits per color and alpha component and its
 217      * length should be at least the number of components in the
 218      * {@code ColorSpace} if there is no alpha
 219      * information in the pixel values, or one more than this number if
 220      * there is alpha information.  When the {@code transferType} is
 221      * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT},
 222      * or {@code DataBuffer.TYPE_DOUBLE} the {@code bits} array
 223      * argument is ignored.  {@code hasAlpha} indicates whether alpha
 224      * information is present.  If {@code hasAlpha} is true, then
 225      * the boolean {@code isAlphaPremultiplied}
 226      * specifies how to interpret color and alpha samples in pixel values.
 227      * If the boolean is true, color samples are assumed to have been
 228      * multiplied by the alpha sample. The {@code transparency}
 229      * specifies what alpha values can be represented by this color model.
 230      * The acceptable {@code transparency} values are
 231      * {@code OPAQUE}, {@code BITMASK} or {@code TRANSLUCENT}.
 232      * The {@code transferType} is the type of primitive array used
 233      * to represent pixel values.
 234      *
 235      * @param colorSpace       The {@code ColorSpace} associated
 236      *                         with this color model.
 237      * @param bits             The number of significant bits per component.
 238      *                         May be null, in which case all bits of all
 239      *                         component samples will be significant.
 240      *                         Ignored if transferType is one of
 241      *                         {@code DataBuffer.TYPE_SHORT},
 242      *                         {@code DataBuffer.TYPE_FLOAT}, or
 243      *                         {@code DataBuffer.TYPE_DOUBLE},
 244      *                         in which case all bits of all component
 245      *                         samples will be significant.
 246      * @param hasAlpha         If true, this color model supports alpha.
 247      * @param isAlphaPremultiplied If true, alpha is premultiplied.
 248      * @param transparency     Specifies what alpha values can be represented
 249      *                         by this color model.
 250      * @param transferType     Specifies the type of primitive array used to
 251      *                         represent pixel values.
 252      *
 253      * @throws IllegalArgumentException If the {@code bits} array
 254      *         argument is not null, its length is less than the number of
 255      *         color and alpha components, and transferType is one of
 256      *         {@code DataBuffer.TYPE_BYTE},
 257      *         {@code DataBuffer.TYPE_USHORT}, or
 258      *         {@code DataBuffer.TYPE_INT}.
 259      * @throws IllegalArgumentException If transferType is not one of
 260      *         {@code DataBuffer.TYPE_BYTE},
 261      *         {@code DataBuffer.TYPE_USHORT},
 262      *         {@code DataBuffer.TYPE_INT},
 263      *         {@code DataBuffer.TYPE_SHORT},
 264      *         {@code DataBuffer.TYPE_FLOAT}, or
 265      *         {@code DataBuffer.TYPE_DOUBLE}.
 266      *
 267      * @see ColorSpace
 268      * @see java.awt.Transparency
 269      */
 270     public ComponentColorModel (ColorSpace colorSpace,
 271                                 int[] bits,
 272                                 boolean hasAlpha,
 273                                 boolean isAlphaPremultiplied,
 274                                 int transparency,
 275                                 int transferType) {
 276         super (bitsHelper(transferType, colorSpace, hasAlpha),
 277                bitsArrayHelper(bits, transferType, colorSpace, hasAlpha),
 278                colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
 279                transferType);
 280         switch(transferType) {
 281             case DataBuffer.TYPE_BYTE:
 282             case DataBuffer.TYPE_USHORT:
 283             case DataBuffer.TYPE_INT:
 284                 signed = false;
 285                 needScaleInit = true;
 286                 break;
 287             case DataBuffer.TYPE_SHORT:
 288                 signed = true;
 289                 needScaleInit = true;
 290                 break;
 291             case DataBuffer.TYPE_FLOAT:
 292             case DataBuffer.TYPE_DOUBLE:
 293                 signed = true;
 294                 needScaleInit = false;
 295                 noUnnorm = true;
 296                 nonStdScale = false;
 297                 break;
 298             default:
 299                 throw new IllegalArgumentException("This constructor is not "+
 300                          "compatible with transferType " + transferType);
 301         }
 302         setupLUTs();
 303     }
 304 
 305     /**
 306      * Constructs a {@code ComponentColorModel} from the specified
 307      * parameters. Color components will be in the specified
 308      * {@code ColorSpace}.  The supported transfer types are
 309      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
 310      * {@code DataBuffer.TYPE_INT},
 311      * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT},
 312      * and {@code DataBuffer.TYPE_DOUBLE}.  The number of significant
 313      * bits per color and alpha component will be 8, 16, 32, 16, 32,  or 64,
 314      * respectively.  The number of color components will be the
 315      * number of components in the {@code ColorSpace}.  There will be
 316      * an alpha component if {@code hasAlpha} is {@code true}.
 317      * If {@code hasAlpha} is true, then
 318      * the boolean {@code isAlphaPremultiplied}
 319      * specifies how to interpret color and alpha samples in pixel values.
 320      * If the boolean is true, color samples are assumed to have been
 321      * multiplied by the alpha sample. The {@code transparency}
 322      * specifies what alpha values can be represented by this color model.
 323      * The acceptable {@code transparency} values are
 324      * {@code OPAQUE}, {@code BITMASK} or {@code TRANSLUCENT}.
 325      * The {@code transferType} is the type of primitive array used
 326      * to represent pixel values.
 327      *
 328      * @param colorSpace       The {@code ColorSpace} associated
 329      *                         with this color model.
 330      * @param hasAlpha         If true, this color model supports alpha.
 331      * @param isAlphaPremultiplied If true, alpha is premultiplied.
 332      * @param transparency     Specifies what alpha values can be represented
 333      *                         by this color model.
 334      * @param transferType     Specifies the type of primitive array used to
 335      *                         represent pixel values.
 336      *
 337      * @throws IllegalArgumentException If transferType is not one of
 338      *         {@code DataBuffer.TYPE_BYTE},
 339      *         {@code DataBuffer.TYPE_USHORT},
 340      *         {@code DataBuffer.TYPE_INT},
 341      *         {@code DataBuffer.TYPE_SHORT},
 342      *         {@code DataBuffer.TYPE_FLOAT}, or
 343      *         {@code DataBuffer.TYPE_DOUBLE}.
 344      *
 345      * @see ColorSpace
 346      * @see java.awt.Transparency
 347      * @since 1.4
 348      */
 349     public ComponentColorModel (ColorSpace colorSpace,
 350                                 boolean hasAlpha,
 351                                 boolean isAlphaPremultiplied,
 352                                 int transparency,
 353                                 int transferType) {
 354         this(colorSpace, null, hasAlpha, isAlphaPremultiplied,
 355              transparency, transferType);
 356     }
 357 
 358     private static int bitsHelper(int transferType,
 359                                   ColorSpace colorSpace,
 360                                   boolean hasAlpha) {
 361         int numBits = DataBuffer.getDataTypeSize(transferType);
 362         int numComponents = colorSpace.getNumComponents();
 363         if (hasAlpha) {
 364             ++numComponents;
 365         }
 366         return numBits * numComponents;
 367     }
 368 
 369     private static int[] bitsArrayHelper(int[] origBits,
 370                                          int transferType,
 371                                          ColorSpace colorSpace,
 372                                          boolean hasAlpha) {
 373         switch(transferType) {
 374             case DataBuffer.TYPE_BYTE:
 375             case DataBuffer.TYPE_USHORT:
 376             case DataBuffer.TYPE_INT:
 377                 if (origBits != null) {
 378                     return origBits;
 379                 }
 380                 break;
 381             default:
 382                 break;
 383         }
 384         int numBits = DataBuffer.getDataTypeSize(transferType);
 385         int numComponents = colorSpace.getNumComponents();
 386         if (hasAlpha) {
 387             ++numComponents;
 388         }
 389         int[] bits = new int[numComponents];
 390         for (int i = 0; i < numComponents; i++) {
 391             bits[i] = numBits;
 392         }
 393         return bits;
 394     }
 395 
 396     private void setupLUTs() {
 397         // REMIND: there is potential to accelerate sRGB, LinearRGB,
 398         // LinearGray, ICCGray, and non-ICC Gray spaces with non-standard
 399         // scaling, if that becomes important
 400         //
 401         // NOTE: The is_xxx_stdScale and nonStdScale booleans are provisionally
 402         // set here when this method is called at construction time.  These
 403         // variables may be set again when initScale is called later.
 404         // When setupLUTs returns, nonStdScale is true if (the transferType
 405         // is not float or double) AND (some minimum ColorSpace component
 406         // value is not 0.0 OR some maximum ColorSpace component value
 407         // is not 1.0).  This is correct for the calls to
 408         // getNormalizedComponents(Object, float[], int) from initScale().
 409         // initScale() may change the value nonStdScale based on the
 410         // return value of getNormalizedComponents() - this will only
 411         // happen if getNormalizedComponents() has been overridden by a
 412         // subclass to make the mapping of min/max pixel sample values
 413         // something different from min/max color component values.
 414         if (is_sRGB) {
 415             is_sRGB_stdScale = true;
 416             nonStdScale = false;
 417         } else if (ColorModel.isLinearRGBspace(colorSpace)) {
 418             // Note that the built-in Linear RGB space has a normalized
 419             // range of 0.0 - 1.0 for each coordinate.  Usage of these
 420             // LUTs makes that assumption.
 421             is_LinearRGB_stdScale = true;
 422             nonStdScale = false;
 423             if (transferType == DataBuffer.TYPE_BYTE) {
 424                 tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT();
 425                 fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT();
 426             } else {
 427                 tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT();
 428                 fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT();
 429             }
 430         } else if ((colorSpaceType == ColorSpace.TYPE_GRAY) &&
 431                    (colorSpace instanceof ICC_ColorSpace) &&
 432                    (colorSpace.getMinValue(0) == 0.0f) &&
 433                    (colorSpace.getMaxValue(0) == 1.0f)) {
 434             // Note that a normalized range of 0.0 - 1.0 for the gray
 435             // component is required, because usage of these LUTs makes
 436             // that assumption.
 437             ICC_ColorSpace ics = (ICC_ColorSpace) colorSpace;
 438             is_ICCGray_stdScale = true;
 439             nonStdScale = false;
 440             fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT();
 441             if (ColorModel.isLinearGRAYspace(ics)) {
 442                 is_LinearGray_stdScale = true;
 443                 if (transferType == DataBuffer.TYPE_BYTE) {
 444                     tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics);
 445                 } else {
 446                     tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics);
 447                 }
 448             } else {
 449                 if (transferType == DataBuffer.TYPE_BYTE) {
 450                     tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics);
 451                     fromLinearGray16ToOtherGray8LUT =
 452                         ColorModel.getLinearGray16ToOtherGray8LUT(ics);
 453                 } else {
 454                     tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics);
 455                     fromLinearGray16ToOtherGray16LUT =
 456                         ColorModel.getLinearGray16ToOtherGray16LUT(ics);
 457                 }
 458             }
 459         } else if (needScaleInit) {
 460             // if transferType is byte, ushort, int, or short and we
 461             // don't already know the ColorSpace has minVlaue == 0.0f and
 462             // maxValue == 1.0f for all components, we need to check that
 463             // now and setup the min[] and diffMinMax[] arrays if necessary.
 464             nonStdScale = false;
 465             for (int i = 0; i < numColorComponents; i++) {
 466                 if ((colorSpace.getMinValue(i) != 0.0f) ||
 467                     (colorSpace.getMaxValue(i) != 1.0f)) {
 468                     nonStdScale = true;
 469                     break;
 470                 }
 471             }
 472             if (nonStdScale) {
 473                 min = new float[numColorComponents];
 474                 diffMinMax = new float[numColorComponents];
 475                 for (int i = 0; i < numColorComponents; i++) {
 476                     min[i] = colorSpace.getMinValue(i);
 477                     diffMinMax[i] = colorSpace.getMaxValue(i) - min[i];
 478                 }
 479             }
 480         }
 481     }
 482 
 483     private void initScale() {
 484         // This method is called the first time any method which uses
 485         // pixel sample value to color component value scaling information
 486         // is called if the transferType supports non-standard scaling
 487         // as defined above (byte, ushort, int, and short), unless the
 488         // method is getNormalizedComponents(Object, float[], int) (that
 489         // method must be overridden to use non-standard scaling).  This
 490         // method also sets up the noUnnorm boolean variable for these
 491         // transferTypes.  After this method is called, the nonStdScale
 492         // variable will be true if getNormalizedComponents() maps a
 493         // sample value of 0 to anything other than 0.0f OR maps a
 494         // sample value of 2^^n - 1 (2^^15 - 1 for short transferType)
 495         // to anything other than 1.0f.  Note that this can be independent
 496         // of the colorSpace min/max component values, if the
 497         // getNormalizedComponents() method has been overridden for some
 498         // reason, e.g. to provide greater dynamic range in the sample
 499         // values than in the color component values.  Unfortunately,
 500         // this method can't be called at construction time, since a
 501         // subclass may still have uninitialized state that would cause
 502         // getNormalizedComponents() to return an incorrect result.
 503         needScaleInit = false; // only needs to called once
 504         if (nonStdScale || signed) {
 505             // The unnormalized form is only supported for unsigned
 506             // transferTypes and when the ColorSpace min/max values
 507             // are 0.0/1.0.  When this method is called nonStdScale is
 508             // true if the latter condition does not hold.  In addition,
 509             // the unnormalized form requires that the full range of
 510             // the pixel sample values map to the full 0.0 - 1.0 range
 511             // of color component values.  That condition is checked
 512             // later in this method.
 513             noUnnorm = true;
 514         } else {
 515             noUnnorm = false;
 516         }
 517         float[] lowVal, highVal;
 518         switch (transferType) {
 519         case DataBuffer.TYPE_BYTE:
 520             {
 521                 byte[] bpixel = new byte[numComponents];
 522                 for (int i = 0; i < numColorComponents; i++) {
 523                     bpixel[i] = 0;
 524                 }
 525                 if (supportsAlpha) {
 526                     bpixel[numColorComponents] =
 527                         (byte) ((1 << nBits[numColorComponents]) - 1);
 528                 }
 529                 lowVal = getNormalizedComponents(bpixel, null, 0);
 530                 for (int i = 0; i < numColorComponents; i++) {
 531                     bpixel[i] = (byte) ((1 << nBits[i]) - 1);
 532                 }
 533                 highVal = getNormalizedComponents(bpixel, null, 0);
 534             }
 535             break;
 536         case DataBuffer.TYPE_USHORT:
 537             {
 538                 short[] uspixel = new short[numComponents];
 539                 for (int i = 0; i < numColorComponents; i++) {
 540                     uspixel[i] = 0;
 541                 }
 542                 if (supportsAlpha) {
 543                     uspixel[numColorComponents] =
 544                         (short) ((1 << nBits[numColorComponents]) - 1);
 545                 }
 546                 lowVal = getNormalizedComponents(uspixel, null, 0);
 547                 for (int i = 0; i < numColorComponents; i++) {
 548                     uspixel[i] = (short) ((1 << nBits[i]) - 1);
 549                 }
 550                 highVal = getNormalizedComponents(uspixel, null, 0);
 551             }
 552             break;
 553         case DataBuffer.TYPE_INT:
 554             {
 555                 int[] ipixel = new int[numComponents];
 556                 for (int i = 0; i < numColorComponents; i++) {
 557                     ipixel[i] = 0;
 558                 }
 559                 if (supportsAlpha) {
 560                     ipixel[numColorComponents] =
 561                         ((1 << nBits[numColorComponents]) - 1);
 562                 }
 563                 lowVal = getNormalizedComponents(ipixel, null, 0);
 564                 for (int i = 0; i < numColorComponents; i++) {
 565                     ipixel[i] = ((1 << nBits[i]) - 1);
 566                 }
 567                 highVal = getNormalizedComponents(ipixel, null, 0);
 568             }
 569             break;
 570         case DataBuffer.TYPE_SHORT:
 571             {
 572                 short[] spixel = new short[numComponents];
 573                 for (int i = 0; i < numColorComponents; i++) {
 574                     spixel[i] = 0;
 575                 }
 576                 if (supportsAlpha) {
 577                     spixel[numColorComponents] = 32767;
 578                 }
 579                 lowVal = getNormalizedComponents(spixel, null, 0);
 580                 for (int i = 0; i < numColorComponents; i++) {
 581                     spixel[i] = 32767;
 582                 }
 583                 highVal = getNormalizedComponents(spixel, null, 0);
 584             }
 585             break;
 586         default:
 587             lowVal = highVal = null;  // to keep the compiler from complaining
 588             break;
 589         }
 590         nonStdScale = false;
 591         for (int i = 0; i < numColorComponents; i++) {
 592             if ((lowVal[i] != 0.0f) || (highVal[i] != 1.0f)) {
 593                 nonStdScale = true;
 594                 break;
 595             }
 596         }
 597         if (nonStdScale) {
 598             noUnnorm = true;
 599             is_sRGB_stdScale = false;
 600             is_LinearRGB_stdScale = false;
 601             is_LinearGray_stdScale = false;
 602             is_ICCGray_stdScale = false;
 603             compOffset = new float[numColorComponents];
 604             compScale = new float[numColorComponents];
 605             for (int i = 0; i < numColorComponents; i++) {
 606                 compOffset[i] = lowVal[i];
 607                 compScale[i] = 1.0f / (highVal[i] - lowVal[i]);
 608             }
 609         }
 610     }
 611 
 612     private int getRGBComponent(int pixel, int idx) {
 613         if (numComponents > 1) {
 614             throw new
 615                 IllegalArgumentException("More than one component per pixel");
 616         }
 617         if (signed) {
 618             throw new
 619                 IllegalArgumentException("Component value is signed");
 620         }
 621         if (needScaleInit) {
 622             initScale();
 623         }
 624         // Since there is only 1 component, there is no alpha
 625 
 626         // Normalize the pixel in order to convert it
 627         Object opixel = null;
 628         switch (transferType) {
 629         case DataBuffer.TYPE_BYTE:
 630             {
 631                 byte[] bpixel = { (byte) pixel };
 632                 opixel = bpixel;
 633             }
 634             break;
 635         case DataBuffer.TYPE_USHORT:
 636             {
 637                 short[] spixel = { (short) pixel };
 638                 opixel = spixel;
 639             }
 640             break;
 641         case DataBuffer.TYPE_INT:
 642             {
 643                 int[] ipixel = { pixel };
 644                 opixel = ipixel;
 645             }
 646             break;
 647         }
 648         float[] norm = getNormalizedComponents(opixel, null, 0);
 649         float[] rgb = colorSpace.toRGB(norm);
 650 
 651         return (int) (rgb[idx] * 255.0f + 0.5f);
 652     }
 653 
 654     /**
 655      * Returns the red color component for the specified pixel, scaled
 656      * from 0 to 255 in the default RGB ColorSpace, sRGB.  A color conversion
 657      * is done if necessary.  The pixel value is specified as an int.
 658      * The returned value will be a non pre-multiplied value.
 659      * If the alpha is premultiplied, this method divides
 660      * it out before returning the value (if the alpha value is 0,
 661      * the red value will be 0).
 662      *
 663      * @param pixel The pixel from which you want to get the red color component.
 664      *
 665      * @return The red color component for the specified pixel, as an int.
 666      *
 667      * @throws IllegalArgumentException If there is more than
 668      * one component in this {@code ColorModel}.
 669      * @throws IllegalArgumentException If the component value for this
 670      * {@code ColorModel} is signed
 671      */
 672     public int getRed(int pixel) {
 673         return getRGBComponent(pixel, 0);
 674     }
 675 
 676     /**
 677      * Returns the green color component for the specified pixel, scaled
 678      * from 0 to 255 in the default RGB ColorSpace, sRGB.  A color conversion
 679      * is done if necessary.  The pixel value is specified as an int.
 680      * The returned value will be a non
 681      * pre-multiplied value. If the alpha is premultiplied, this method
 682      * divides it out before returning the value (if the alpha value is 0,
 683      * the green value will be 0).
 684      *
 685      * @param pixel The pixel from which you want to get the green color component.
 686      *
 687      * @return The green color component for the specified pixel, as an int.
 688      *
 689      * @throws IllegalArgumentException If there is more than
 690      * one component in this {@code ColorModel}.
 691      * @throws IllegalArgumentException If the component value for this
 692      * {@code ColorModel} is signed
 693      */
 694     public int getGreen(int pixel) {
 695         return getRGBComponent(pixel, 1);
 696     }
 697 
 698     /**
 699      * Returns the blue color component for the specified pixel, scaled
 700      * from 0 to 255 in the default RGB ColorSpace, sRGB.  A color conversion
 701      * is done if necessary.  The pixel value is specified as an int.
 702      * The returned value will be a non
 703      * pre-multiplied value. If the alpha is premultiplied, this method
 704      * divides it out before returning the value (if the alpha value is 0,
 705      * the blue value will be 0).
 706      *
 707      * @param pixel The pixel from which you want to get the blue color component.
 708      *
 709      * @return The blue color component for the specified pixel, as an int.
 710      *
 711      * @throws IllegalArgumentException If there is more than
 712      * one component in this {@code ColorModel}.
 713      * @throws IllegalArgumentException If the component value for this
 714      * {@code ColorModel} is signed
 715      */
 716     public int getBlue(int pixel) {
 717         return getRGBComponent(pixel, 2);
 718     }
 719 
 720     /**
 721      * Returns the alpha component for the specified pixel, scaled
 722      * from 0 to 255.   The pixel value is specified as an int.
 723      *
 724      * @param pixel The pixel from which you want to get the alpha component.
 725      *
 726      * @return The alpha component for the specified pixel, as an int.
 727      *
 728      * @throws IllegalArgumentException If there is more than
 729      * one component in this {@code ColorModel}.
 730      * @throws IllegalArgumentException If the component value for this
 731      * {@code ColorModel} is signed
 732      */
 733     public int getAlpha(int pixel) {
 734         if (supportsAlpha == false) {
 735             return 255;
 736         }
 737         if (numComponents > 1) {
 738             throw new
 739                 IllegalArgumentException("More than one component per pixel");
 740         }
 741         if (signed) {
 742             throw new
 743                 IllegalArgumentException("Component value is signed");
 744         }
 745 
 746         return (int) ((((float) pixel) / ((1<<nBits[0])-1)) * 255.0f + 0.5f);
 747     }
 748 
 749     /**
 750      * Returns the color/alpha components of the pixel in the default
 751      * RGB color model format.  A color conversion is done if necessary.
 752      * The returned value will be in a non pre-multiplied format. If
 753      * the alpha is premultiplied, this method divides it out of the
 754      * color components (if the alpha value is 0, the color values will be 0).
 755      *
 756      * @param pixel The pixel from which you want to get the color/alpha components.
 757      *
 758      * @return The color/alpha components for the specified pixel, as an int.
 759      *
 760      * @throws IllegalArgumentException If there is more than
 761      * one component in this {@code ColorModel}.
 762      * @throws IllegalArgumentException If the component value for this
 763      * {@code ColorModel} is signed
 764      */
 765     public int getRGB(int pixel) {
 766         if (numComponents > 1) {
 767             throw new
 768                 IllegalArgumentException("More than one component per pixel");
 769         }
 770         if (signed) {
 771             throw new
 772                 IllegalArgumentException("Component value is signed");
 773         }
 774 
 775         return (getAlpha(pixel) << 24)
 776             | (getRed(pixel) << 16)
 777             | (getGreen(pixel) << 8)
 778             | (getBlue(pixel) << 0);
 779     }
 780 
 781     private int extractComponent(Object inData, int idx, int precision) {
 782         // Extract component idx from inData.  The precision argument
 783         // should be either 8 or 16.  If it's 8, this method will return
 784         // an 8-bit value.  If it's 16, this method will return a 16-bit
 785         // value for transferTypes other than TYPE_BYTE.  For TYPE_BYTE,
 786         // an 8-bit value will be returned.
 787 
 788         // This method maps the input value corresponding to a
 789         // normalized ColorSpace component value of 0.0 to 0, and the
 790         // input value corresponding to a normalized ColorSpace
 791         // component value of 1.0 to 2^n - 1 (where n is 8 or 16), so
 792         // it is appropriate only for ColorSpaces with min/max component
 793         // values of 0.0/1.0.  This will be true for sRGB, the built-in
 794         // Linear RGB and Linear Gray spaces, and any other ICC grayscale
 795         // spaces for which we have precomputed LUTs.
 796 
 797         boolean needAlpha = (supportsAlpha && isAlphaPremultiplied);
 798         int alp = 0;
 799         int comp;
 800         int mask = (1 << nBits[idx]) - 1;
 801 
 802         switch (transferType) {
 803             // Note: we do no clamping of the pixel data here - we
 804             // assume that the data is scaled properly
 805             case DataBuffer.TYPE_SHORT: {
 806                 short sdata[] = (short[]) inData;
 807                 float scalefactor = (float) ((1 << precision) - 1);
 808                 if (needAlpha) {
 809                     short s = sdata[numColorComponents];
 810                     if (s != (short) 0) {
 811                         return (int) ((((float) sdata[idx]) /
 812                                        ((float) s)) * scalefactor + 0.5f);
 813                     } else {
 814                         return 0;
 815                     }
 816                 } else {
 817                     return (int) ((sdata[idx] / 32767.0f) * scalefactor + 0.5f);
 818                 }
 819             }
 820             case DataBuffer.TYPE_FLOAT: {
 821                 float fdata[] = (float[]) inData;
 822                 float scalefactor = (float) ((1 << precision) - 1);
 823                 if (needAlpha) {
 824                     float f = fdata[numColorComponents];
 825                     if (f != 0.0f) {
 826                         return (int) (((fdata[idx] / f) * scalefactor) + 0.5f);
 827                     } else {
 828                         return 0;
 829                     }
 830                 } else {
 831                     return (int) (fdata[idx] * scalefactor + 0.5f);
 832                 }
 833             }
 834             case DataBuffer.TYPE_DOUBLE: {
 835                 double ddata[] = (double[]) inData;
 836                 double scalefactor = (double) ((1 << precision) - 1);
 837                 if (needAlpha) {
 838                     double d = ddata[numColorComponents];
 839                     if (d != 0.0) {
 840                         return (int) (((ddata[idx] / d) * scalefactor) + 0.5);
 841                     } else {
 842                         return 0;
 843                     }
 844                 } else {
 845                     return (int) (ddata[idx] * scalefactor + 0.5);
 846                 }
 847             }
 848             case DataBuffer.TYPE_BYTE:
 849                byte bdata[] = (byte[])inData;
 850                comp = bdata[idx] & mask;
 851                precision = 8;
 852                if (needAlpha) {
 853                    alp = bdata[numColorComponents] & mask;
 854                }
 855             break;
 856             case DataBuffer.TYPE_USHORT:
 857                short usdata[] = (short[])inData;
 858                comp = usdata[idx] & mask;
 859                if (needAlpha) {
 860                    alp = usdata[numColorComponents] & mask;
 861                }
 862             break;
 863             case DataBuffer.TYPE_INT:
 864                int idata[] = (int[])inData;
 865                comp = idata[idx];
 866                if (needAlpha) {
 867                    alp = idata[numColorComponents];
 868                }
 869             break;
 870             default:
 871                throw new
 872                    UnsupportedOperationException("This method has not "+
 873                    "been implemented for transferType " + transferType);
 874         }
 875         if (needAlpha) {
 876             if (alp != 0) {
 877                 float scalefactor = (float) ((1 << precision) - 1);
 878                 float fcomp = ((float) comp) / ((float)mask);
 879                 float invalp = ((float) ((1<<nBits[numColorComponents]) - 1)) /
 880                                ((float) alp);
 881                 return (int) (fcomp * invalp * scalefactor + 0.5f);
 882             } else {
 883                 return 0;
 884             }
 885         } else {
 886             if (nBits[idx] != precision) {
 887                 float scalefactor = (float) ((1 << precision) - 1);
 888                 float fcomp = ((float) comp) / ((float)mask);
 889                 return (int) (fcomp * scalefactor + 0.5f);
 890             }
 891             return comp;
 892         }
 893     }
 894 
 895     private int getRGBComponent(Object inData, int idx) {
 896         if (needScaleInit) {
 897             initScale();
 898         }
 899         if (is_sRGB_stdScale) {
 900             return extractComponent(inData, idx, 8);
 901         } else if (is_LinearRGB_stdScale) {
 902             int lutidx = extractComponent(inData, idx, 16);
 903             return tosRGB8LUT[lutidx] & 0xff;
 904         } else if (is_ICCGray_stdScale) {
 905             int lutidx = extractComponent(inData, 0, 16);
 906             return tosRGB8LUT[lutidx] & 0xff;
 907         }
 908 
 909         // Not CS_sRGB, CS_LINEAR_RGB, or any TYPE_GRAY ICC_ColorSpace
 910         float[] norm = getNormalizedComponents(inData, null, 0);
 911         // Note that getNormalizedComponents returns non-premultiplied values
 912         float[] rgb = colorSpace.toRGB(norm);
 913         return (int) (rgb[idx] * 255.0f + 0.5f);
 914     }
 915 
 916     /**
 917      * Returns the red color component for the specified pixel, scaled
 918      * from 0 to 255 in the default RGB ColorSpace, sRGB.  A color conversion
 919      * is done if necessary.  The {@code pixel} value is specified by an array
 920      * of data elements of type {@code transferType} passed in as an object
 921      * reference. The returned value will be a non pre-multiplied value. If the
 922      * alpha is premultiplied, this method divides it out before returning
 923      * the value (if the alpha value is 0, the red value will be 0). Since
 924      * {@code ComponentColorModel} can be subclassed, subclasses
 925      * inherit the implementation of this method and if they don't override
 926      * it then they throw an exception if they use an unsupported
 927      * {@code transferType}.
 928      *
 929      * @param inData The pixel from which you want to get the red color component,
 930      * specified by an array of data elements of type {@code transferType}.
 931      *
 932      * @return The red color component for the specified pixel, as an int.
 933      *
 934      * @throws ClassCastException If {@code inData} is not a primitive array
 935      * of type {@code transferType}.
 936      * @throws ArrayIndexOutOfBoundsException if {@code inData} is not
 937      * large enough to hold a pixel value for this
 938      * {@code ColorModel}.
 939      * @throws UnsupportedOperationException If the transfer type of
 940      * this {@code ComponentColorModel}
 941      * is not one of the supported transfer types:
 942      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
 943      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
 944      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
 945      */
 946     public int getRed(Object inData) {
 947         return getRGBComponent(inData, 0);
 948     }
 949 
 950 
 951     /**
 952      * Returns the green color component for the specified pixel, scaled
 953      * from 0 to 255 in the default RGB {@code ColorSpace}, sRGB.
 954      * A color conversion is done if necessary.  The {@code pixel} value
 955      * is specified by an array of data elements of type {@code transferType}
 956      * passed in as an object reference. The returned value is a non pre-multiplied
 957      * value. If the alpha is premultiplied, this method divides it out before
 958      * returning the value (if the alpha value is 0, the green value will be 0).
 959      * Since {@code ComponentColorModel} can be subclassed,
 960      * subclasses inherit the implementation of this method and if they
 961      * don't override it then they throw an exception if they use an
 962      * unsupported {@code transferType}.
 963      *
 964      * @param inData The pixel from which you want to get the green color component,
 965      * specified by an array of data elements of type {@code transferType}.
 966      *
 967      * @return The green color component for the specified pixel, as an int.
 968      *
 969      * @throws ClassCastException If {@code inData} is not a primitive array
 970      * of type {@code transferType}.
 971      * @throws ArrayIndexOutOfBoundsException if {@code inData} is not
 972      * large enough to hold a pixel value for this
 973      * {@code ColorModel}.
 974      * @throws UnsupportedOperationException If the transfer type of
 975      * this {@code ComponentColorModel}
 976      * is not one of the supported transfer types:
 977      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
 978      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
 979      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
 980      */
 981     public int getGreen(Object inData) {
 982         return getRGBComponent(inData, 1);
 983     }
 984 
 985 
 986     /**
 987      * Returns the blue color component for the specified pixel, scaled
 988      * from 0 to 255 in the default RGB {@code ColorSpace}, sRGB.
 989      * A color conversion is done if necessary.  The {@code pixel} value is
 990      * specified by an array of data elements of type {@code transferType}
 991      * passed in as an object reference. The returned value is a non pre-multiplied
 992      * value. If the alpha is premultiplied, this method divides it out before
 993      * returning the value (if the alpha value is 0, the blue value will be 0).
 994      * Since {@code ComponentColorModel} can be subclassed,
 995      * subclasses inherit the implementation of this method and if they
 996      * don't override it then they throw an exception if they use an
 997      * unsupported {@code transferType}.
 998      *
 999      * @param inData The pixel from which you want to get the blue color component,
1000      * specified by an array of data elements of type {@code transferType}.
1001      *
1002      * @return The blue color component for the specified pixel, as an int.
1003      *
1004      * @throws ClassCastException If {@code inData} is not a primitive array
1005      * of type {@code transferType}.
1006      * @throws ArrayIndexOutOfBoundsException if {@code inData} is not
1007      * large enough to hold a pixel value for this
1008      * {@code ColorModel}.
1009      * @throws UnsupportedOperationException If the transfer type of
1010      * this {@code ComponentColorModel}
1011      * is not one of the supported transfer types:
1012      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
1013      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
1014      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
1015      */
1016     public int getBlue(Object inData) {
1017         return getRGBComponent(inData, 2);
1018     }
1019 
1020     /**
1021      * Returns the alpha component for the specified pixel, scaled from
1022      * 0 to 255.  The pixel value is specified by an array of data
1023      * elements of type {@code transferType} passed in as an
1024      * object reference.  Since {@code ComponentColorModel} can be
1025      * subclassed, subclasses inherit the
1026      * implementation of this method and if they don't override it then
1027      * they throw an exception if they use an unsupported
1028      * {@code transferType}.
1029      *
1030      * @param inData The pixel from which you want to get the alpha component,
1031      * specified by an array of data elements of type {@code transferType}.
1032      *
1033      * @return The alpha component for the specified pixel, as an int.
1034      *
1035      * @throws ClassCastException If {@code inData} is not a primitive array
1036      * of type {@code transferType}.
1037      * @throws ArrayIndexOutOfBoundsException if {@code inData} is not
1038      * large enough to hold a pixel value for this
1039      * {@code ColorModel}.
1040      * @throws UnsupportedOperationException If the transfer type of
1041      * this {@code ComponentColorModel}
1042      * is not one of the supported transfer types:
1043      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
1044      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
1045      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
1046      */
1047     public int getAlpha(Object inData) {
1048         if (supportsAlpha == false) {
1049             return 255;
1050         }
1051 
1052         int alpha = 0;
1053         int aIdx = numColorComponents;
1054         int mask = (1 << nBits[aIdx]) - 1;
1055 
1056         switch (transferType) {
1057             case DataBuffer.TYPE_SHORT:
1058                 short sdata[] = (short[])inData;
1059                 alpha = (int) ((sdata[aIdx] / 32767.0f) * 255.0f + 0.5f);
1060                 return alpha;
1061             case DataBuffer.TYPE_FLOAT:
1062                 float fdata[] = (float[])inData;
1063                 alpha = (int) (fdata[aIdx] * 255.0f + 0.5f);
1064                 return alpha;
1065             case DataBuffer.TYPE_DOUBLE:
1066                 double ddata[] = (double[])inData;
1067                 alpha = (int) (ddata[aIdx] * 255.0 + 0.5);
1068                 return alpha;
1069             case DataBuffer.TYPE_BYTE:
1070                byte bdata[] = (byte[])inData;
1071                alpha = bdata[aIdx] & mask;
1072             break;
1073             case DataBuffer.TYPE_USHORT:
1074                short usdata[] = (short[])inData;
1075                alpha = usdata[aIdx] & mask;
1076             break;
1077             case DataBuffer.TYPE_INT:
1078                int idata[] = (int[])inData;
1079                alpha = idata[aIdx];
1080             break;
1081             default:
1082                throw new
1083                    UnsupportedOperationException("This method has not "+
1084                    "been implemented for transferType " + transferType);
1085         }
1086 
1087         if (nBits[aIdx] == 8) {
1088             return alpha;
1089         } else {
1090             return (int)
1091                 ((((float) alpha) / ((float) ((1 << nBits[aIdx]) - 1))) *
1092                  255.0f + 0.5f);
1093         }
1094     }
1095 
1096     /**
1097      * Returns the color/alpha components for the specified pixel in the
1098      * default RGB color model format.  A color conversion is done if
1099      * necessary.  The pixel value is specified by an
1100      * array of data elements of type {@code transferType} passed
1101      * in as an object reference.
1102      * The returned value is in a non pre-multiplied format. If
1103      * the alpha is premultiplied, this method divides it out of the
1104      * color components (if the alpha value is 0, the color values will be 0).
1105      * Since {@code ComponentColorModel} can be subclassed,
1106      * subclasses inherit the implementation of this method and if they
1107      * don't override it then they throw an exception if they use an
1108      * unsupported {@code transferType}.
1109      *
1110      * @param inData The pixel from which you want to get the color/alpha components,
1111      * specified by an array of data elements of type {@code transferType}.
1112      *
1113      * @return The color/alpha components for the specified pixel, as an int.
1114      *
1115      * @throws ClassCastException If {@code inData} is not a primitive array
1116      * of type {@code transferType}.
1117      * @throws ArrayIndexOutOfBoundsException if {@code inData} is not
1118      * large enough to hold a pixel value for this
1119      * {@code ColorModel}.
1120      * @throws UnsupportedOperationException If the transfer type of
1121      * this {@code ComponentColorModel}
1122      * is not one of the supported transfer types:
1123      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
1124      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
1125      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
1126      * @see ColorModel#getRGBdefault
1127      */
1128     public int getRGB(Object inData) {
1129         if (needScaleInit) {
1130             initScale();
1131         }
1132         if (is_sRGB_stdScale || is_LinearRGB_stdScale) {
1133             return (getAlpha(inData) << 24)
1134                 | (getRed(inData) << 16)
1135                 | (getGreen(inData) << 8)
1136                 | (getBlue(inData));
1137         } else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
1138             int gray = getRed(inData); // Red sRGB component should equal
1139                                        // green and blue components
1140             return (getAlpha(inData) << 24)
1141                 | (gray << 16)
1142                 | (gray <<  8)
1143                 | gray;
1144         }
1145         float[] norm = getNormalizedComponents(inData, null, 0);
1146         // Note that getNormalizedComponents returns non-premult values
1147         float[] rgb = colorSpace.toRGB(norm);
1148         return (getAlpha(inData) << 24)
1149             | (((int) (rgb[0] * 255.0f + 0.5f)) << 16)
1150             | (((int) (rgb[1] * 255.0f + 0.5f)) << 8)
1151             | (((int) (rgb[2] * 255.0f + 0.5f)) << 0);
1152     }
1153 
1154     /**
1155      * Returns a data element array representation of a pixel in this
1156      * {@code ColorModel}, given an integer pixel representation
1157      * in the default RGB color model.
1158      * This array can then be passed to the {@code setDataElements}
1159      * method of a {@code WritableRaster} object.  If the
1160      * {@code pixel}
1161      * parameter is null, a new array is allocated.  Since
1162      * {@code ComponentColorModel} can be subclassed, subclasses
1163      * inherit the implementation of this method and if they don't
1164      * override it then
1165      * they throw an exception if they use an unsupported
1166      * {@code transferType}.
1167      *
1168      * @param rgb the integer representation of the pixel in the RGB
1169      *            color model
1170      * @param pixel the specified pixel
1171      * @return The data element array representation of a pixel
1172      * in this {@code ColorModel}.
1173      * @throws ClassCastException If {@code pixel} is not null and
1174      * is not a primitive array of type {@code transferType}.
1175      * @throws ArrayIndexOutOfBoundsException If {@code pixel} is
1176      * not large enough to hold a pixel value for this
1177      * {@code ColorModel}.
1178      * @throws UnsupportedOperationException If the transfer type of
1179      * this {@code ComponentColorModel}
1180      * is not one of the supported transfer types:
1181      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
1182      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
1183      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
1184      *
1185      * @see WritableRaster#setDataElements
1186      * @see SampleModel#setDataElements
1187      */
1188     public Object getDataElements(int rgb, Object pixel) {
1189         // REMIND: Use rendering hints?
1190 
1191         int red, grn, blu, alp;
1192         red = (rgb>>16) & 0xff;
1193         grn = (rgb>>8) & 0xff;
1194         blu = rgb & 0xff;
1195 
1196         if (needScaleInit) {
1197             initScale();
1198         }
1199         if (signed) {
1200             // Handle SHORT, FLOAT, & DOUBLE here
1201 
1202             switch(transferType) {
1203             case DataBuffer.TYPE_SHORT:
1204                 {
1205                     short sdata[];
1206                     if (pixel == null) {
1207                         sdata = new short[numComponents];
1208                     } else {
1209                         sdata = (short[])pixel;
1210                     }
1211                     float factor;
1212                     if (is_sRGB_stdScale || is_LinearRGB_stdScale) {
1213                         factor = 32767.0f / 255.0f;
1214                         if (is_LinearRGB_stdScale) {
1215                             red = fromsRGB8LUT16[red] & 0xffff;
1216                             grn = fromsRGB8LUT16[grn] & 0xffff;
1217                             blu = fromsRGB8LUT16[blu] & 0xffff;
1218                             factor = 32767.0f / 65535.0f;
1219                         }
1220                         if (supportsAlpha) {
1221                             alp = (rgb>>24) & 0xff;
1222                             sdata[3] =
1223                                 (short) (alp * (32767.0f / 255.0f) + 0.5f);
1224                             if (isAlphaPremultiplied) {
1225                                 factor = alp * factor * (1.0f / 255.0f);
1226                             }
1227                         }
1228                         sdata[0] = (short) (red * factor + 0.5f);
1229                         sdata[1] = (short) (grn * factor + 0.5f);
1230                         sdata[2] = (short) (blu * factor + 0.5f);
1231                     } else if (is_LinearGray_stdScale) {
1232                         red = fromsRGB8LUT16[red] & 0xffff;
1233                         grn = fromsRGB8LUT16[grn] & 0xffff;
1234                         blu = fromsRGB8LUT16[blu] & 0xffff;
1235                         float gray = ((0.2125f * red) +
1236                                       (0.7154f * grn) +
1237                                       (0.0721f * blu)) / 65535.0f;
1238                         factor = 32767.0f;
1239                         if (supportsAlpha) {
1240                             alp = (rgb>>24) & 0xff;
1241                             sdata[1] =
1242                                 (short) (alp * (32767.0f / 255.0f) + 0.5f);
1243                             if (isAlphaPremultiplied) {
1244                                 factor = alp * factor * (1.0f / 255.0f);
1245                             }
1246                         }
1247                         sdata[0] = (short) (gray * factor + 0.5f);
1248                     } else if (is_ICCGray_stdScale) {
1249                         red = fromsRGB8LUT16[red] & 0xffff;
1250                         grn = fromsRGB8LUT16[grn] & 0xffff;
1251                         blu = fromsRGB8LUT16[blu] & 0xffff;
1252                         int gray = (int) ((0.2125f * red) +
1253                                           (0.7154f * grn) +
1254                                           (0.0721f * blu) + 0.5f);
1255                         gray = fromLinearGray16ToOtherGray16LUT[gray] & 0xffff;
1256                         factor = 32767.0f / 65535.0f;
1257                         if (supportsAlpha) {
1258                             alp = (rgb>>24) & 0xff;
1259                             sdata[1] =
1260                                 (short) (alp * (32767.0f / 255.0f) + 0.5f);
1261                             if (isAlphaPremultiplied) {
1262                                 factor = alp * factor * (1.0f / 255.0f);
1263                             }
1264                         }
1265                         sdata[0] = (short) (gray * factor + 0.5f);
1266                     } else {
1267                         factor = 1.0f / 255.0f;
1268                         float norm[] = new float[3];
1269                         norm[0] = red * factor;
1270                         norm[1] = grn * factor;
1271                         norm[2] = blu * factor;
1272                         norm = colorSpace.fromRGB(norm);
1273                         if (nonStdScale) {
1274                             for (int i = 0; i < numColorComponents; i++) {
1275                                 norm[i] = (norm[i] - compOffset[i]) *
1276                                           compScale[i];
1277                                 // REMIND: need to analyze whether this
1278                                 // clamping is necessary
1279                                 if (norm[i] < 0.0f) {
1280                                     norm[i] = 0.0f;
1281                                 }
1282                                 if (norm[i] > 1.0f) {
1283                                     norm[i] = 1.0f;
1284                                 }
1285                             }
1286                         }
1287                         factor = 32767.0f;
1288                         if (supportsAlpha) {
1289                             alp = (rgb>>24) & 0xff;
1290                             sdata[numColorComponents] =
1291                                 (short) (alp * (32767.0f / 255.0f) + 0.5f);
1292                             if (isAlphaPremultiplied) {
1293                                 factor *= alp * (1.0f / 255.0f);
1294                             }
1295                         }
1296                         for (int i = 0; i < numColorComponents; i++) {
1297                             sdata[i] = (short) (norm[i] * factor + 0.5f);
1298                         }
1299                     }
1300                     return sdata;
1301                 }
1302             case DataBuffer.TYPE_FLOAT:
1303                 {
1304                     float fdata[];
1305                     if (pixel == null) {
1306                         fdata = new float[numComponents];
1307                     } else {
1308                         fdata = (float[])pixel;
1309                     }
1310                     float factor;
1311                     if (is_sRGB_stdScale || is_LinearRGB_stdScale) {
1312                         if (is_LinearRGB_stdScale) {
1313                             red = fromsRGB8LUT16[red] & 0xffff;
1314                             grn = fromsRGB8LUT16[grn] & 0xffff;
1315                             blu = fromsRGB8LUT16[blu] & 0xffff;
1316                             factor = 1.0f / 65535.0f;
1317                         } else {
1318                             factor = 1.0f / 255.0f;
1319                         }
1320                         if (supportsAlpha) {
1321                             alp = (rgb>>24) & 0xff;
1322                             fdata[3] = alp * (1.0f / 255.0f);
1323                             if (isAlphaPremultiplied) {
1324                                 factor *= fdata[3];
1325                             }
1326                         }
1327                         fdata[0] = red * factor;
1328                         fdata[1] = grn * factor;
1329                         fdata[2] = blu * factor;
1330                     } else if (is_LinearGray_stdScale) {
1331                         red = fromsRGB8LUT16[red] & 0xffff;
1332                         grn = fromsRGB8LUT16[grn] & 0xffff;
1333                         blu = fromsRGB8LUT16[blu] & 0xffff;
1334                         fdata[0] = ((0.2125f * red) +
1335                                     (0.7154f * grn) +
1336                                     (0.0721f * blu)) / 65535.0f;
1337                         if (supportsAlpha) {
1338                             alp = (rgb>>24) & 0xff;
1339                             fdata[1] = alp * (1.0f / 255.0f);
1340                             if (isAlphaPremultiplied) {
1341                                 fdata[0] *= fdata[1];
1342                             }
1343                         }
1344                     } else if (is_ICCGray_stdScale) {
1345                         red = fromsRGB8LUT16[red] & 0xffff;
1346                         grn = fromsRGB8LUT16[grn] & 0xffff;
1347                         blu = fromsRGB8LUT16[blu] & 0xffff;
1348                         int gray = (int) ((0.2125f * red) +
1349                                           (0.7154f * grn) +
1350                                           (0.0721f * blu) + 0.5f);
1351                         fdata[0] = (fromLinearGray16ToOtherGray16LUT[gray] &
1352                                     0xffff) / 65535.0f;
1353                         if (supportsAlpha) {
1354                             alp = (rgb>>24) & 0xff;
1355                             fdata[1] = alp * (1.0f / 255.0f);
1356                             if (isAlphaPremultiplied) {
1357                                 fdata[0] *= fdata[1];
1358                             }
1359                         }
1360                     } else {
1361                         float norm[] = new float[3];
1362                         factor = 1.0f / 255.0f;
1363                         norm[0] = red * factor;
1364                         norm[1] = grn * factor;
1365                         norm[2] = blu * factor;
1366                         norm = colorSpace.fromRGB(norm);
1367                         if (supportsAlpha) {
1368                             alp = (rgb>>24) & 0xff;
1369                             fdata[numColorComponents] = alp * factor;
1370                             if (isAlphaPremultiplied) {
1371                                 factor *= alp;
1372                                 for (int i = 0; i < numColorComponents; i++) {
1373                                     norm[i] *= factor;
1374                                 }
1375                             }
1376                         }
1377                         for (int i = 0; i < numColorComponents; i++) {
1378                             fdata[i] = norm[i];
1379                         }
1380                     }
1381                     return fdata;
1382                 }
1383             case DataBuffer.TYPE_DOUBLE:
1384                 {
1385                     double ddata[];
1386                     if (pixel == null) {
1387                         ddata = new double[numComponents];
1388                     } else {
1389                         ddata = (double[])pixel;
1390                     }
1391                     if (is_sRGB_stdScale || is_LinearRGB_stdScale) {
1392                         double factor;
1393                         if (is_LinearRGB_stdScale) {
1394                             red = fromsRGB8LUT16[red] & 0xffff;
1395                             grn = fromsRGB8LUT16[grn] & 0xffff;
1396                             blu = fromsRGB8LUT16[blu] & 0xffff;
1397                             factor = 1.0 / 65535.0;
1398                         } else {
1399                             factor = 1.0 / 255.0;
1400                         }
1401                         if (supportsAlpha) {
1402                             alp = (rgb>>24) & 0xff;
1403                             ddata[3] = alp * (1.0 / 255.0);
1404                             if (isAlphaPremultiplied) {
1405                                 factor *= ddata[3];
1406                             }
1407                         }
1408                         ddata[0] = red * factor;
1409                         ddata[1] = grn * factor;
1410                         ddata[2] = blu * factor;
1411                     } else if (is_LinearGray_stdScale) {
1412                         red = fromsRGB8LUT16[red] & 0xffff;
1413                         grn = fromsRGB8LUT16[grn] & 0xffff;
1414                         blu = fromsRGB8LUT16[blu] & 0xffff;
1415                         ddata[0] = ((0.2125 * red) +
1416                                     (0.7154 * grn) +
1417                                     (0.0721 * blu)) / 65535.0;
1418                         if (supportsAlpha) {
1419                             alp = (rgb>>24) & 0xff;
1420                             ddata[1] = alp * (1.0 / 255.0);
1421                             if (isAlphaPremultiplied) {
1422                                 ddata[0] *= ddata[1];
1423                             }
1424                         }
1425                     } else if (is_ICCGray_stdScale) {
1426                         red = fromsRGB8LUT16[red] & 0xffff;
1427                         grn = fromsRGB8LUT16[grn] & 0xffff;
1428                         blu = fromsRGB8LUT16[blu] & 0xffff;
1429                         int gray = (int) ((0.2125f * red) +
1430                                           (0.7154f * grn) +
1431                                           (0.0721f * blu) + 0.5f);
1432                         ddata[0] = (fromLinearGray16ToOtherGray16LUT[gray] &
1433                                     0xffff) / 65535.0;
1434                         if (supportsAlpha) {
1435                             alp = (rgb>>24) & 0xff;
1436                             ddata[1] = alp * (1.0 / 255.0);
1437                             if (isAlphaPremultiplied) {
1438                                 ddata[0] *= ddata[1];
1439                             }
1440                         }
1441                     } else {
1442                         float factor = 1.0f / 255.0f;
1443                         float norm[] = new float[3];
1444                         norm[0] = red * factor;
1445                         norm[1] = grn * factor;
1446                         norm[2] = blu * factor;
1447                         norm = colorSpace.fromRGB(norm);
1448                         if (supportsAlpha) {
1449                             alp = (rgb>>24) & 0xff;
1450                             ddata[numColorComponents] = alp * (1.0 / 255.0);
1451                             if (isAlphaPremultiplied) {
1452                                 factor *= alp;
1453                                 for (int i = 0; i < numColorComponents; i++) {
1454                                     norm[i] *= factor;
1455                                 }
1456                             }
1457                         }
1458                         for (int i = 0; i < numColorComponents; i++) {
1459                             ddata[i] = norm[i];
1460                         }
1461                     }
1462                     return ddata;
1463                 }
1464             }
1465         }
1466 
1467         // Handle BYTE, USHORT, & INT here
1468         //REMIND: maybe more efficient not to use int array for
1469         //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT
1470         int intpixel[];
1471         if (transferType == DataBuffer.TYPE_INT &&
1472             pixel != null) {
1473            intpixel = (int[])pixel;
1474         } else {
1475             intpixel = new int[numComponents];
1476         }
1477 
1478         if (is_sRGB_stdScale || is_LinearRGB_stdScale) {
1479             int precision;
1480             float factor;
1481             if (is_LinearRGB_stdScale) {
1482                 if (transferType == DataBuffer.TYPE_BYTE) {
1483                     red = fromsRGB8LUT8[red] & 0xff;
1484                     grn = fromsRGB8LUT8[grn] & 0xff;
1485                     blu = fromsRGB8LUT8[blu] & 0xff;
1486                     precision = 8;
1487                     factor = 1.0f / 255.0f;
1488                 } else {
1489                     red = fromsRGB8LUT16[red] & 0xffff;
1490                     grn = fromsRGB8LUT16[grn] & 0xffff;
1491                     blu = fromsRGB8LUT16[blu] & 0xffff;
1492                     precision = 16;
1493                     factor = 1.0f / 65535.0f;
1494                 }
1495             } else {
1496                 precision = 8;
1497                 factor = 1.0f / 255.0f;
1498             }
1499             if (supportsAlpha) {
1500                 alp = (rgb>>24)&0xff;
1501                 if (nBits[3] == 8) {
1502                     intpixel[3] = alp;
1503                 }
1504                 else {
1505                     intpixel[3] = (int)
1506                         (alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1) + 0.5f);
1507                 }
1508                 if (isAlphaPremultiplied) {
1509                     factor *= (alp * (1.0f / 255.0f));
1510                     precision = -1;  // force component calculations below
1511                 }
1512             }
1513             if (nBits[0] == precision) {
1514                 intpixel[0] = red;
1515             }
1516             else {
1517                 intpixel[0] = (int) (red * factor * ((1<<nBits[0]) - 1) + 0.5f);
1518             }
1519             if (nBits[1] == precision) {
1520                 intpixel[1] = grn;
1521             }
1522             else {
1523                 intpixel[1] = (int) (grn * factor * ((1<<nBits[1]) - 1) + 0.5f);
1524             }
1525             if (nBits[2] == precision) {
1526                 intpixel[2] = blu;
1527             }
1528             else {
1529                 intpixel[2] = (int) (blu * factor * ((1<<nBits[2]) - 1) + 0.5f);
1530             }
1531         } else if (is_LinearGray_stdScale) {
1532             red = fromsRGB8LUT16[red] & 0xffff;
1533             grn = fromsRGB8LUT16[grn] & 0xffff;
1534             blu = fromsRGB8LUT16[blu] & 0xffff;
1535             float gray = ((0.2125f * red) +
1536                           (0.7154f * grn) +
1537                           (0.0721f * blu)) / 65535.0f;
1538             if (supportsAlpha) {
1539                 alp = (rgb>>24) & 0xff;
1540                 if (nBits[1] == 8) {
1541                     intpixel[1] = alp;
1542                 } else {
1543                     intpixel[1] = (int) (alp * (1.0f / 255.0f) *
1544                                          ((1 << nBits[1]) - 1) + 0.5f);
1545                 }
1546                 if (isAlphaPremultiplied) {
1547                     gray *= (alp * (1.0f / 255.0f));
1548                 }
1549             }
1550             intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f);
1551         } else if (is_ICCGray_stdScale) {
1552             red = fromsRGB8LUT16[red] & 0xffff;
1553             grn = fromsRGB8LUT16[grn] & 0xffff;
1554             blu = fromsRGB8LUT16[blu] & 0xffff;
1555             int gray16 = (int) ((0.2125f * red) +
1556                                 (0.7154f * grn) +
1557                                 (0.0721f * blu) + 0.5f);
1558             float gray = (fromLinearGray16ToOtherGray16LUT[gray16] &
1559                           0xffff) / 65535.0f;
1560             if (supportsAlpha) {
1561                 alp = (rgb>>24) & 0xff;
1562                 if (nBits[1] == 8) {
1563                     intpixel[1] = alp;
1564                 } else {
1565                     intpixel[1] = (int) (alp * (1.0f / 255.0f) *
1566                                          ((1 << nBits[1]) - 1) + 0.5f);
1567                 }
1568                 if (isAlphaPremultiplied) {
1569                     gray *= (alp * (1.0f / 255.0f));
1570                 }
1571             }
1572             intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f);
1573         } else {
1574             // Need to convert the color
1575             float[] norm = new float[3];
1576             float factor = 1.0f / 255.0f;
1577             norm[0] = red * factor;
1578             norm[1] = grn * factor;
1579             norm[2] = blu * factor;
1580             norm = colorSpace.fromRGB(norm);
1581             if (nonStdScale) {
1582                 for (int i = 0; i < numColorComponents; i++) {
1583                     norm[i] = (norm[i] - compOffset[i]) *
1584                               compScale[i];
1585                     // REMIND: need to analyze whether this
1586                     // clamping is necessary
1587                     if (norm[i] < 0.0f) {
1588                         norm[i] = 0.0f;
1589                     }
1590                     if (norm[i] > 1.0f) {
1591                         norm[i] = 1.0f;
1592                     }
1593                 }
1594             }
1595             if (supportsAlpha) {
1596                 alp = (rgb>>24) & 0xff;
1597                 if (nBits[numColorComponents] == 8) {
1598                     intpixel[numColorComponents] = alp;
1599                 }
1600                 else {
1601                     intpixel[numColorComponents] =
1602                         (int) (alp * factor *
1603                                ((1<<nBits[numColorComponents]) - 1) + 0.5f);
1604                 }
1605                 if (isAlphaPremultiplied) {
1606                     factor *= alp;
1607                     for (int i = 0; i < numColorComponents; i++) {
1608                         norm[i] *= factor;
1609                     }
1610                 }
1611             }
1612             for (int i = 0; i < numColorComponents; i++) {
1613                 intpixel[i] = (int) (norm[i] * ((1<<nBits[i]) - 1) + 0.5f);
1614             }
1615         }
1616 
1617         switch (transferType) {
1618             case DataBuffer.TYPE_BYTE: {
1619                byte bdata[];
1620                if (pixel == null) {
1621                    bdata = new byte[numComponents];
1622                } else {
1623                    bdata = (byte[])pixel;
1624                }
1625                for (int i = 0; i < numComponents; i++) {
1626                    bdata[i] = (byte)(0xff&intpixel[i]);
1627                }
1628                return bdata;
1629             }
1630             case DataBuffer.TYPE_USHORT:{
1631                short sdata[];
1632                if (pixel == null) {
1633                    sdata = new short[numComponents];
1634                } else {
1635                    sdata = (short[])pixel;
1636                }
1637                for (int i = 0; i < numComponents; i++) {
1638                    sdata[i] = (short)(intpixel[i]&0xffff);
1639                }
1640                return sdata;
1641             }
1642             case DataBuffer.TYPE_INT:
1643                 if (maxBits > 23) {
1644                     // fix 4412670 - for components of 24 or more bits
1645                     // some calculations done above with float precision
1646                     // may lose enough precision that the integer result
1647                     // overflows nBits, so we need to clamp.
1648                     for (int i = 0; i < numComponents; i++) {
1649                         if (intpixel[i] > ((1<<nBits[i]) - 1)) {
1650                             intpixel[i] = (1<<nBits[i]) - 1;
1651                         }
1652                     }
1653                 }
1654                 return intpixel;
1655         }
1656         throw new IllegalArgumentException("This method has not been "+
1657                  "implemented for transferType " + transferType);
1658     }
1659 
1660    /** Returns an array of unnormalized color/alpha components given a pixel
1661      * in this {@code ColorModel}.
1662      * An IllegalArgumentException is thrown if the component value for this
1663      * {@code ColorModel} is not conveniently representable in the
1664      * unnormalized form.  Color/alpha components are stored
1665      * in the {@code components} array starting at {@code offset}
1666      * (even if the array is allocated by this method).
1667      *
1668      * @param pixel The pixel value specified as an integer.
1669      * @param components An integer array in which to store the unnormalized
1670      * color/alpha components. If the {@code components} array is null,
1671      * a new array is allocated.
1672      * @param offset An offset into the {@code components} array.
1673      *
1674      * @return The components array.
1675      *
1676      * @throws IllegalArgumentException If there is more than one
1677      * component in this {@code ColorModel}.
1678      * @throws IllegalArgumentException If this
1679      * {@code ColorModel} does not support the unnormalized form
1680      * @throws ArrayIndexOutOfBoundsException If the {@code components}
1681      * array is not null and is not large enough to hold all the color and
1682      * alpha components (starting at offset).
1683      */
1684     public int[] getComponents(int pixel, int[] components, int offset) {
1685         if (numComponents > 1) {
1686             throw new
1687                 IllegalArgumentException("More than one component per pixel");
1688         }
1689         if (needScaleInit) {
1690             initScale();
1691         }
1692         if (noUnnorm) {
1693             throw new
1694                 IllegalArgumentException(
1695                     "This ColorModel does not support the unnormalized form");
1696         }
1697         if (components == null) {
1698             components = new int[offset+1];
1699         }
1700 
1701         components[offset+0] = (pixel & ((1<<nBits[0]) - 1));
1702         return components;
1703     }
1704 
1705     /**
1706      * Returns an array of unnormalized color/alpha components given a pixel
1707      * in this {@code ColorModel}.  The pixel value is specified by an
1708      * array of data elements of type {@code transferType} passed in as
1709      * an object reference.
1710      * An IllegalArgumentException is thrown if the component values for this
1711      * {@code ColorModel} are not conveniently representable in the
1712      * unnormalized form.
1713      * Color/alpha components are stored in the {@code components} array
1714      * starting at  {@code offset} (even if the array is allocated by
1715      * this method).  Since {@code ComponentColorModel} can be
1716      * subclassed, subclasses inherit the
1717      * implementation of this method and if they don't override it then
1718      * this method might throw an exception if they use an unsupported
1719      * {@code transferType}.
1720      *
1721      * @param pixel A pixel value specified by an array of data elements of
1722      * type {@code transferType}.
1723      * @param components An integer array in which to store the unnormalized
1724      * color/alpha components. If the {@code components} array is null,
1725      * a new array is allocated.
1726      * @param offset An offset into the {@code components} array.
1727      *
1728      * @return The {@code components} array.
1729      *
1730      * @throws IllegalArgumentException If this
1731      * {@code ComponentColorModel} does not support the unnormalized form
1732      * @throws UnsupportedOperationException in some cases iff the
1733      * transfer type of this {@code ComponentColorModel}
1734      * is not one of the following transfer types:
1735      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
1736      * or {@code DataBuffer.TYPE_INT}.
1737      * @throws ClassCastException If {@code pixel} is not a primitive
1738      * array of type {@code transferType}.
1739      * @throws IllegalArgumentException If the {@code components} array is
1740      * not null and is not large enough to hold all the color and alpha
1741      * components (starting at offset), or if {@code pixel} is not large
1742      * enough to hold a pixel value for this ColorModel.
1743      */
1744     public int[] getComponents(Object pixel, int[] components, int offset) {
1745         int intpixel[];
1746         if (needScaleInit) {
1747             initScale();
1748         }
1749         if (noUnnorm) {
1750             throw new
1751                 IllegalArgumentException(
1752                     "This ColorModel does not support the unnormalized form");
1753         }
1754         if (pixel instanceof int[]) {
1755             intpixel = (int[])pixel;
1756         } else {
1757             intpixel = DataBuffer.toIntArray(pixel);
1758             if (intpixel == null) {
1759                throw new UnsupportedOperationException("This method has not been "+
1760                    "implemented for transferType " + transferType);
1761             }
1762         }
1763         if (intpixel.length < numComponents) {
1764             throw new IllegalArgumentException
1765                 ("Length of pixel array < number of components in model");
1766         }
1767         if (components == null) {
1768             components = new int[offset+numComponents];
1769         }
1770         else if ((components.length-offset) < numComponents) {
1771             throw new IllegalArgumentException
1772                 ("Length of components array < number of components in model");
1773         }
1774         System.arraycopy(intpixel, 0, components, offset, numComponents);
1775 
1776         return components;
1777     }
1778 
1779     /**
1780      * Returns an array of all of the color/alpha components in unnormalized
1781      * form, given a normalized component array.  Unnormalized components
1782      * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where
1783      * n is the number of bits for a particular component.  Normalized
1784      * components are float values between a per component minimum and
1785      * maximum specified by the {@code ColorSpace} object for this
1786      * {@code ColorModel}.  An {@code IllegalArgumentException}
1787      * will be thrown if color component values for this
1788      * {@code ColorModel} are not conveniently representable in the
1789      * unnormalized form.  If the
1790      * {@code components} array is {@code null}, a new array
1791      * will be allocated.  The {@code components} array will
1792      * be returned.  Color/alpha components are stored in the
1793      * {@code components} array starting at {@code offset} (even
1794      * if the array is allocated by this method). An
1795      * {@code ArrayIndexOutOfBoundsException} is thrown if the
1796      * {@code components} array is not {@code null} and is not
1797      * large enough to hold all the color and alpha
1798      * components (starting at {@code offset}).  An
1799      * {@code IllegalArgumentException} is thrown if the
1800      * {@code normComponents} array is not large enough to hold
1801      * all the color and alpha components starting at
1802      * {@code normOffset}.
1803      * @param normComponents an array containing normalized components
1804      * @param normOffset the offset into the {@code normComponents}
1805      * array at which to start retrieving normalized components
1806      * @param components an array that receives the components from
1807      * {@code normComponents}
1808      * @param offset the index into {@code components} at which to
1809      * begin storing normalized components from
1810      * {@code normComponents}
1811      * @return an array containing unnormalized color and alpha
1812      * components.
1813      * @throws IllegalArgumentException If this
1814      * {@code ComponentColorModel} does not support the unnormalized form
1815      * @throws IllegalArgumentException if the length of
1816      *          {@code normComponents} minus {@code normOffset}
1817      *          is less than {@code numComponents}
1818      */
1819     public int[] getUnnormalizedComponents(float[] normComponents,
1820                                            int normOffset,
1821                                            int[] components, int offset) {
1822         if (needScaleInit) {
1823             initScale();
1824         }
1825         if (noUnnorm) {
1826             throw new
1827                 IllegalArgumentException(
1828                     "This ColorModel does not support the unnormalized form");
1829         }
1830         return super.getUnnormalizedComponents(normComponents, normOffset,
1831                                                components, offset);
1832     }
1833 
1834     /**
1835      * Returns an array of all of the color/alpha components in normalized
1836      * form, given an unnormalized component array.  Unnormalized components
1837      * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where
1838      * n is the number of bits for a particular component.  Normalized
1839      * components are float values between a per component minimum and
1840      * maximum specified by the {@code ColorSpace} object for this
1841      * {@code ColorModel}.  An {@code IllegalArgumentException}
1842      * will be thrown if color component values for this
1843      * {@code ColorModel} are not conveniently representable in the
1844      * unnormalized form.  If the
1845      * {@code normComponents} array is {@code null}, a new array
1846      * will be allocated.  The {@code normComponents} array
1847      * will be returned.  Color/alpha components are stored in the
1848      * {@code normComponents} array starting at
1849      * {@code normOffset} (even if the array is allocated by this
1850      * method).  An {@code ArrayIndexOutOfBoundsException} is thrown
1851      * if the {@code normComponents} array is not {@code null}
1852      * and is not large enough to hold all the color and alpha components
1853      * (starting at {@code normOffset}).  An
1854      * {@code IllegalArgumentException} is thrown if the
1855      * {@code components} array is not large enough to hold all the
1856      * color and alpha components starting at {@code offset}.
1857      * @param components an array containing unnormalized components
1858      * @param offset the offset into the {@code components} array at
1859      * which to start retrieving unnormalized components
1860      * @param normComponents an array that receives the normalized components
1861      * @param normOffset the index into {@code normComponents} at
1862      * which to begin storing normalized components
1863      * @return an array containing normalized color and alpha
1864      * components.
1865      * @throws IllegalArgumentException If this
1866      * {@code ComponentColorModel} does not support the unnormalized form
1867      */
1868     public float[] getNormalizedComponents(int[] components, int offset,
1869                                            float[] normComponents,
1870                                            int normOffset) {
1871         if (needScaleInit) {
1872             initScale();
1873         }
1874         if (noUnnorm) {
1875             throw new
1876                 IllegalArgumentException(
1877                     "This ColorModel does not support the unnormalized form");
1878         }
1879         return super.getNormalizedComponents(components, offset,
1880                                              normComponents, normOffset);
1881     }
1882 
1883     /**
1884      * Returns a pixel value represented as an int in this {@code ColorModel},
1885      * given an array of unnormalized color/alpha components.
1886      *
1887      * @param components An array of unnormalized color/alpha components.
1888      * @param offset An offset into the {@code components} array.
1889      *
1890      * @return A pixel value represented as an int.
1891      *
1892      * @throws IllegalArgumentException If there is more than one component
1893      * in this {@code ColorModel}.
1894      * @throws IllegalArgumentException If this
1895      * {@code ComponentColorModel} does not support the unnormalized form
1896      */
1897     public int getDataElement(int[] components, int offset) {
1898         if (needScaleInit) {
1899             initScale();
1900         }
1901         if (numComponents == 1) {
1902             if (noUnnorm) {
1903                 throw new
1904                     IllegalArgumentException(
1905                     "This ColorModel does not support the unnormalized form");
1906             }
1907             return components[offset+0];
1908         }
1909         throw new IllegalArgumentException("This model returns "+
1910                                            numComponents+
1911                                            " elements in the pixel array.");
1912     }
1913 
1914     /**
1915      * Returns a data element array representation of a pixel in this
1916      * {@code ColorModel}, given an array of unnormalized color/alpha
1917      * components. This array can then be passed to the {@code setDataElements}
1918      * method of a {@code WritableRaster} object.
1919      *
1920      * @param components An array of unnormalized color/alpha components.
1921      * @param offset The integer offset into the {@code components} array.
1922      * @param obj The object in which to store the data element array
1923      * representation of the pixel. If {@code obj} variable is null,
1924      * a new array is allocated.  If {@code obj} is not null, it must
1925      * be a primitive array of type {@code transferType}. An
1926      * {@code ArrayIndexOutOfBoundsException} is thrown if
1927      * {@code obj} is not large enough to hold a pixel value
1928      * for this {@code ColorModel}.  Since
1929      * {@code ComponentColorModel} can be subclassed, subclasses
1930      * inherit the implementation of this method and if they don't
1931      * override it then they throw an exception if they use an
1932      * unsupported {@code transferType}.
1933      *
1934      * @return The data element array representation of a pixel
1935      * in this {@code ColorModel}.
1936      *
1937      * @throws IllegalArgumentException If the components array
1938      * is not large enough to hold all the color and alpha components
1939      * (starting at offset).
1940      * @throws ClassCastException If {@code obj} is not null and is not a
1941      * primitive  array of type {@code transferType}.
1942      * @throws ArrayIndexOutOfBoundsException If {@code obj} is not large
1943      * enough to hold a pixel value for this {@code ColorModel}.
1944      * @throws IllegalArgumentException If this
1945      * {@code ComponentColorModel} does not support the unnormalized form
1946      * @throws UnsupportedOperationException If the transfer type of
1947      * this {@code ComponentColorModel}
1948      * is not one of the following transfer types:
1949      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
1950      * or {@code DataBuffer.TYPE_INT}.
1951      *
1952      * @see WritableRaster#setDataElements
1953      * @see SampleModel#setDataElements
1954      */
1955     public Object getDataElements(int[] components, int offset, Object obj) {
1956         if (needScaleInit) {
1957             initScale();
1958         }
1959         if (noUnnorm) {
1960             throw new
1961                 IllegalArgumentException(
1962                     "This ColorModel does not support the unnormalized form");
1963         }
1964         if ((components.length-offset) < numComponents) {
1965             throw new IllegalArgumentException("Component array too small"+
1966                                                " (should be "+numComponents);
1967         }
1968         switch(transferType) {
1969         case DataBuffer.TYPE_INT:
1970             {
1971                 int[] pixel;
1972                 if (obj == null) {
1973                     pixel = new int[numComponents];
1974                 }
1975                 else {
1976                     pixel = (int[]) obj;
1977                 }
1978                 System.arraycopy(components, offset, pixel, 0,
1979                                  numComponents);
1980                 return pixel;
1981             }
1982 
1983         case DataBuffer.TYPE_BYTE:
1984             {
1985                 byte[] pixel;
1986                 if (obj == null) {
1987                     pixel = new byte[numComponents];
1988                 }
1989                 else {
1990                     pixel = (byte[]) obj;
1991                 }
1992                 for (int i=0; i < numComponents; i++) {
1993                     pixel[i] = (byte) (components[offset+i]&0xff);
1994                 }
1995                 return pixel;
1996             }
1997 
1998         case DataBuffer.TYPE_USHORT:
1999             {
2000                 short[] pixel;
2001                 if (obj == null) {
2002                     pixel = new short[numComponents];
2003                 }
2004                 else {
2005                     pixel = (short[]) obj;
2006                 }
2007                 for (int i=0; i < numComponents; i++) {
2008                     pixel[i] = (short) (components[offset+i]&0xffff);
2009                 }
2010                 return pixel;
2011             }
2012 
2013         default:
2014             throw new UnsupportedOperationException("This method has not been "+
2015                                         "implemented for transferType " +
2016                                         transferType);
2017         }
2018     }
2019 
2020     /**
2021      * Returns a pixel value represented as an {@code int} in this
2022      * {@code ColorModel}, given an array of normalized color/alpha
2023      * components.  This method will throw an
2024      * {@code IllegalArgumentException} if pixel values for this
2025      * {@code ColorModel} are not conveniently representable as a
2026      * single {@code int}.  An
2027      * {@code ArrayIndexOutOfBoundsException} is thrown if  the
2028      * {@code normComponents} array is not large enough to hold all the
2029      * color and alpha components (starting at {@code normOffset}).
2030      * @param normComponents an array of normalized color and alpha
2031      * components
2032      * @param normOffset the index into {@code normComponents} at which to
2033      * begin retrieving the color and alpha components
2034      * @return an {@code int} pixel value in this
2035      * {@code ColorModel} corresponding to the specified components.
2036      * @throws IllegalArgumentException if
2037      *  pixel values for this {@code ColorModel} are not
2038      *  conveniently representable as a single {@code int}
2039      * @throws ArrayIndexOutOfBoundsException if
2040      *  the {@code normComponents} array is not large enough to
2041      *  hold all of the color and alpha components starting at
2042      *  {@code normOffset}
2043      * @since 1.4
2044      */
2045     public int getDataElement(float[] normComponents, int normOffset) {
2046         if (numComponents > 1) {
2047             throw new
2048                 IllegalArgumentException("More than one component per pixel");
2049         }
2050         if (signed) {
2051             throw new
2052                 IllegalArgumentException("Component value is signed");
2053         }
2054         if (needScaleInit) {
2055             initScale();
2056         }
2057         Object pixel = getDataElements(normComponents, normOffset, null);
2058         switch (transferType) {
2059         case DataBuffer.TYPE_BYTE:
2060             {
2061                 byte bpixel[] = (byte[]) pixel;
2062                 return bpixel[0] & 0xff;
2063             }
2064         case DataBuffer.TYPE_USHORT:
2065             {
2066                 short[] uspixel = (short[]) pixel;
2067                 return uspixel[0] & 0xffff;
2068             }
2069         case DataBuffer.TYPE_INT:
2070             {
2071                 int[] ipixel = (int[]) pixel;
2072                 return ipixel[0];
2073             }
2074         default:
2075             throw new UnsupportedOperationException("This method has not been "
2076                 + "implemented for transferType " + transferType);
2077         }
2078     }
2079 
2080     /**
2081      * Returns a data element array representation of a pixel in this
2082      * {@code ColorModel}, given an array of normalized color/alpha
2083      * components.  This array can then be passed to the
2084      * {@code setDataElements} method of a {@code WritableRaster}
2085      * object.  An {@code ArrayIndexOutOfBoundsException} is thrown
2086      * if the {@code normComponents} array is not large enough to hold
2087      * all the color and alpha components (starting at
2088      * {@code normOffset}).  If the {@code obj} variable is
2089      * {@code null}, a new array will be allocated.  If
2090      * {@code obj} is not {@code null}, it must be a primitive
2091      * array of type transferType; otherwise, a
2092      * {@code ClassCastException} is thrown.  An
2093      * {@code ArrayIndexOutOfBoundsException} is thrown if
2094      * {@code obj} is not large enough to hold a pixel value for this
2095      * {@code ColorModel}.
2096      * @param normComponents an array of normalized color and alpha
2097      * components
2098      * @param normOffset the index into {@code normComponents} at which to
2099      * begin retrieving color and alpha components
2100      * @param obj a primitive data array to hold the returned pixel
2101      * @return an {@code Object} which is a primitive data array
2102      * representation of a pixel
2103      * @throws ClassCastException if {@code obj}
2104      *  is not a primitive array of type {@code transferType}
2105      * @throws ArrayIndexOutOfBoundsException if
2106      *  {@code obj} is not large enough to hold a pixel value
2107      *  for this {@code ColorModel} or the {@code normComponents}
2108      *  array is not large enough to hold all of the color and alpha
2109      *  components starting at {@code normOffset}
2110      * @see WritableRaster#setDataElements
2111      * @see SampleModel#setDataElements
2112      * @since 1.4
2113      */
2114     public Object getDataElements(float[] normComponents, int normOffset,
2115                                   Object obj) {
2116         boolean needAlpha = supportsAlpha && isAlphaPremultiplied;
2117         float[] stdNormComponents;
2118         if (needScaleInit) {
2119             initScale();
2120         }
2121         if (nonStdScale) {
2122             stdNormComponents = new float[numComponents];
2123             for (int c = 0, nc = normOffset; c < numColorComponents;
2124                  c++, nc++) {
2125                 stdNormComponents[c] = (normComponents[nc] - compOffset[c]) *
2126                                        compScale[c];
2127                 // REMIND: need to analyze whether this
2128                 // clamping is necessary
2129                 if (stdNormComponents[c] < 0.0f) {
2130                     stdNormComponents[c] = 0.0f;
2131                 }
2132                 if (stdNormComponents[c] > 1.0f) {
2133                     stdNormComponents[c] = 1.0f;
2134                 }
2135             }
2136             if (supportsAlpha) {
2137                 stdNormComponents[numColorComponents] =
2138                     normComponents[numColorComponents + normOffset];
2139             }
2140             normOffset = 0;
2141         } else {
2142             stdNormComponents = normComponents;
2143         }
2144         switch (transferType) {
2145         case DataBuffer.TYPE_BYTE:
2146             byte[] bpixel;
2147             if (obj == null) {
2148                 bpixel = new byte[numComponents];
2149             } else {
2150                 bpixel = (byte[]) obj;
2151             }
2152             if (needAlpha) {
2153                 float alpha =
2154                     stdNormComponents[numColorComponents + normOffset];
2155                 for (int c = 0, nc = normOffset; c < numColorComponents;
2156                      c++, nc++) {
2157                     bpixel[c] = (byte) ((stdNormComponents[nc] * alpha) *
2158                                         ((float) ((1 << nBits[c]) - 1)) + 0.5f);
2159                 }
2160                 bpixel[numColorComponents] =
2161                     (byte) (alpha *
2162                             ((float) ((1 << nBits[numColorComponents]) - 1)) +
2163                             0.5f);
2164             } else {
2165                 for (int c = 0, nc = normOffset; c < numComponents;
2166                      c++, nc++) {
2167                     bpixel[c] = (byte) (stdNormComponents[nc] *
2168                                         ((float) ((1 << nBits[c]) - 1)) + 0.5f);
2169                 }
2170             }
2171             return bpixel;
2172         case DataBuffer.TYPE_USHORT:
2173             short[] uspixel;
2174             if (obj == null) {
2175                 uspixel = new short[numComponents];
2176             } else {
2177                 uspixel = (short[]) obj;
2178             }
2179             if (needAlpha) {
2180                 float alpha =
2181                     stdNormComponents[numColorComponents + normOffset];
2182                 for (int c = 0, nc = normOffset; c < numColorComponents;
2183                      c++, nc++) {
2184                     uspixel[c] = (short) ((stdNormComponents[nc] * alpha) *
2185                                           ((float) ((1 << nBits[c]) - 1)) +
2186                                           0.5f);
2187                 }
2188                 uspixel[numColorComponents] =
2189                     (short) (alpha *
2190                              ((float) ((1 << nBits[numColorComponents]) - 1)) +
2191                              0.5f);
2192             } else {
2193                 for (int c = 0, nc = normOffset; c < numComponents;
2194                      c++, nc++) {
2195                     uspixel[c] = (short) (stdNormComponents[nc] *
2196                                           ((float) ((1 << nBits[c]) - 1)) +
2197                                           0.5f);
2198                 }
2199             }
2200             return uspixel;
2201         case DataBuffer.TYPE_INT:
2202             int[] ipixel;
2203             if (obj == null) {
2204                 ipixel = new int[numComponents];
2205             } else {
2206                 ipixel = (int[]) obj;
2207             }
2208             if (needAlpha) {
2209                 float alpha =
2210                     stdNormComponents[numColorComponents + normOffset];
2211                 for (int c = 0, nc = normOffset; c < numColorComponents;
2212                      c++, nc++) {
2213                     ipixel[c] = (int) ((stdNormComponents[nc] * alpha) *
2214                                        ((float) ((1 << nBits[c]) - 1)) + 0.5f);
2215                 }
2216                 ipixel[numColorComponents] =
2217                     (int) (alpha *
2218                            ((float) ((1 << nBits[numColorComponents]) - 1)) +
2219                            0.5f);
2220             } else {
2221                 for (int c = 0, nc = normOffset; c < numComponents;
2222                      c++, nc++) {
2223                     ipixel[c] = (int) (stdNormComponents[nc] *
2224                                        ((float) ((1 << nBits[c]) - 1)) + 0.5f);
2225                 }
2226             }
2227             return ipixel;
2228         case DataBuffer.TYPE_SHORT:
2229             short[] spixel;
2230             if (obj == null) {
2231                 spixel = new short[numComponents];
2232             } else {
2233                 spixel = (short[]) obj;
2234             }
2235             if (needAlpha) {
2236                 float alpha =
2237                     stdNormComponents[numColorComponents + normOffset];
2238                 for (int c = 0, nc = normOffset; c < numColorComponents;
2239                      c++, nc++) {
2240                     spixel[c] = (short)
2241                         (stdNormComponents[nc] * alpha * 32767.0f + 0.5f);
2242                 }
2243                 spixel[numColorComponents] = (short) (alpha * 32767.0f + 0.5f);
2244             } else {
2245                 for (int c = 0, nc = normOffset; c < numComponents;
2246                      c++, nc++) {
2247                     spixel[c] = (short)
2248                         (stdNormComponents[nc] * 32767.0f + 0.5f);
2249                 }
2250             }
2251             return spixel;
2252         case DataBuffer.TYPE_FLOAT:
2253             float[] fpixel;
2254             if (obj == null) {
2255                 fpixel = new float[numComponents];
2256             } else {
2257                 fpixel = (float[]) obj;
2258             }
2259             if (needAlpha) {
2260                 float alpha = normComponents[numColorComponents + normOffset];
2261                 for (int c = 0, nc = normOffset; c < numColorComponents;
2262                      c++, nc++) {
2263                     fpixel[c] = normComponents[nc] * alpha;
2264                 }
2265                 fpixel[numColorComponents] = alpha;
2266             } else {
2267                 for (int c = 0, nc = normOffset; c < numComponents;
2268                      c++, nc++) {
2269                     fpixel[c] = normComponents[nc];
2270                 }
2271             }
2272             return fpixel;
2273         case DataBuffer.TYPE_DOUBLE:
2274             double[] dpixel;
2275             if (obj == null) {
2276                 dpixel = new double[numComponents];
2277             } else {
2278                 dpixel = (double[]) obj;
2279             }
2280             if (needAlpha) {
2281                 double alpha =
2282                     (double) (normComponents[numColorComponents + normOffset]);
2283                 for (int c = 0, nc = normOffset; c < numColorComponents;
2284                      c++, nc++) {
2285                     dpixel[c] = normComponents[nc] * alpha;
2286                 }
2287                 dpixel[numColorComponents] = alpha;
2288             } else {
2289                 for (int c = 0, nc = normOffset; c < numComponents;
2290                      c++, nc++) {
2291                     dpixel[c] = (double) normComponents[nc];
2292                 }
2293             }
2294             return dpixel;
2295         default:
2296             throw new UnsupportedOperationException("This method has not been "+
2297                                         "implemented for transferType " +
2298                                         transferType);
2299         }
2300     }
2301 
2302     /**
2303      * Returns an array of all of the color/alpha components in normalized
2304      * form, given a pixel in this {@code ColorModel}.  The pixel
2305      * value is specified by an array of data elements of type transferType
2306      * passed in as an object reference.  If pixel is not a primitive array
2307      * of type transferType, a {@code ClassCastException} is thrown.
2308      * An {@code ArrayIndexOutOfBoundsException} is thrown if
2309      * {@code pixel} is not large enough to hold a pixel value for this
2310      * {@code ColorModel}.
2311      * Normalized components are float values between a per component minimum
2312      * and maximum specified by the {@code ColorSpace} object for this
2313      * {@code ColorModel}.  If the
2314      * {@code normComponents} array is {@code null}, a new array
2315      * will be allocated.  The {@code normComponents} array
2316      * will be returned.  Color/alpha components are stored in the
2317      * {@code normComponents} array starting at
2318      * {@code normOffset} (even if the array is allocated by this
2319      * method).  An {@code ArrayIndexOutOfBoundsException} is thrown
2320      * if the {@code normComponents} array is not {@code null}
2321      * and is not large enough to hold all the color and alpha components
2322      * (starting at {@code normOffset}).
2323      * <p>
2324      * This method must be overridden by a subclass if that subclass
2325      * is designed to translate pixel sample values to color component values
2326      * in a non-default way.  The default translations implemented by this
2327      * class is described in the class comments.  Any subclass implementing
2328      * a non-default translation must follow the constraints on allowable
2329      * translations defined there.
2330      * @param pixel the specified pixel
2331      * @param normComponents an array to receive the normalized components
2332      * @param normOffset the offset into the {@code normComponents}
2333      * array at which to start storing normalized components
2334      * @return an array containing normalized color and alpha
2335      * components.
2336      * @throws ClassCastException if {@code pixel} is not a primitive
2337      *          array of type transferType
2338      * @throws ArrayIndexOutOfBoundsException if
2339      *          {@code normComponents} is not large enough to hold all
2340      *          color and alpha components starting at {@code normOffset}
2341      * @throws ArrayIndexOutOfBoundsException if
2342      *          {@code pixel} is not large enough to hold a pixel
2343      *          value for this {@code ColorModel}.
2344      * @since 1.4
2345      */
2346     public float[] getNormalizedComponents(Object pixel,
2347                                            float[] normComponents,
2348                                            int normOffset) {
2349         if (normComponents == null) {
2350             normComponents = new float[numComponents+normOffset];
2351         }
2352         switch (transferType) {
2353         case DataBuffer.TYPE_BYTE:
2354             byte[] bpixel = (byte[]) pixel;
2355             for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
2356                 normComponents[nc] = ((float) (bpixel[c] & 0xff)) /
2357                                      ((float) ((1 << nBits[c]) - 1));
2358             }
2359             break;
2360         case DataBuffer.TYPE_USHORT:
2361             short[] uspixel = (short[]) pixel;
2362             for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
2363                 normComponents[nc] = ((float) (uspixel[c] & 0xffff)) /
2364                                      ((float) ((1 << nBits[c]) - 1));
2365             }
2366             break;
2367         case DataBuffer.TYPE_INT:
2368             int[] ipixel = (int[]) pixel;
2369             for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
2370                 normComponents[nc] = ((float) ipixel[c]) /
2371                                      ((float) ((1 << nBits[c]) - 1));
2372             }
2373             break;
2374         case DataBuffer.TYPE_SHORT:
2375             short[] spixel = (short[]) pixel;
2376             for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
2377                 normComponents[nc] = ((float) spixel[c]) / 32767.0f;
2378             }
2379             break;
2380         case DataBuffer.TYPE_FLOAT:
2381             float[] fpixel = (float[]) pixel;
2382             for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
2383                 normComponents[nc] = fpixel[c];
2384             }
2385             break;
2386         case DataBuffer.TYPE_DOUBLE:
2387             double[] dpixel = (double[]) pixel;
2388             for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
2389                 normComponents[nc] = (float) dpixel[c];
2390             }
2391             break;
2392         default:
2393             throw new UnsupportedOperationException("This method has not been "+
2394                                         "implemented for transferType " +
2395                                         transferType);
2396         }
2397 
2398         if (supportsAlpha && isAlphaPremultiplied) {
2399             float alpha = normComponents[numColorComponents + normOffset];
2400             if (alpha != 0.0f) {
2401                 float invAlpha = 1.0f / alpha;
2402                 for (int c = normOffset; c < numColorComponents + normOffset;
2403                      c++) {
2404                     normComponents[c] *= invAlpha;
2405                 }
2406             }
2407         }
2408         if (min != null) {
2409             // Normally (i.e. when this class is not subclassed to override
2410             // this method), the test (min != null) will be equivalent to
2411             // the test (nonStdScale).  However, there is an unlikely, but
2412             // possible case, in which this method is overridden, nonStdScale
2413             // is set true by initScale(), the subclass method for some
2414             // reason calls this superclass method, but the min and
2415             // diffMinMax arrays were never initialized by setupLUTs().  In
2416             // that case, the right thing to do is follow the intended
2417             // semantics of this method, and rescale the color components
2418             // only if the ColorSpace min/max were detected to be other
2419             // than 0.0/1.0 by setupLUTs().  Note that this implies the
2420             // transferType is byte, ushort, int, or short - i.e. components
2421             // derived from float and double pixel data are never rescaled.
2422             for (int c = 0; c < numColorComponents; c++) {
2423                 normComponents[c + normOffset] = min[c] +
2424                     diffMinMax[c] * normComponents[c + normOffset];
2425             }
2426         }
2427         return normComponents;
2428     }
2429 
2430     /**
2431      * Forces the raster data to match the state specified in the
2432      * {@code isAlphaPremultiplied} variable, assuming the data
2433      * is currently correctly described by this {@code ColorModel}.
2434      * It may multiply or divide the color raster data by alpha, or
2435      * do nothing if the data is in the correct state.  If the data needs
2436      * to be coerced, this method also returns an instance of
2437      * this {@code ColorModel} with
2438      * the {@code isAlphaPremultiplied} flag set appropriately.
2439      * Since {@code ColorModel} can be subclassed, subclasses inherit
2440      * the implementation of this method and if they don't override it
2441      * then they throw an exception if they use an unsupported
2442      * {@code transferType}.
2443      *
2444      * @throws NullPointerException if {@code raster} is
2445      * {@code null} and data coercion is required.
2446      * @throws UnsupportedOperationException if the transfer type of
2447      * this {@code ComponentColorModel}
2448      * is not one of the supported transfer types:
2449      * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT},
2450      * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT},
2451      * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}.
2452      */
2453     public ColorModel coerceData (WritableRaster raster,
2454                                   boolean isAlphaPremultiplied) {
2455         if ((supportsAlpha == false) ||
2456             (this.isAlphaPremultiplied == isAlphaPremultiplied))
2457         {
2458             // Nothing to do
2459             return this;
2460         }
2461 
2462         int w = raster.getWidth();
2463         int h = raster.getHeight();
2464         int aIdx = raster.getNumBands() - 1;
2465         float normAlpha;
2466         int rminX = raster.getMinX();
2467         int rY = raster.getMinY();
2468         int rX;
2469         if (isAlphaPremultiplied) {
2470             switch (transferType) {
2471                 case DataBuffer.TYPE_BYTE: {
2472                     byte pixel[] = null;
2473                     byte zpixel[] = null;
2474                     float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1));
2475                     for (int y = 0; y < h; y++, rY++) {
2476                         rX = rminX;
2477                         for (int x = 0; x < w; x++, rX++) {
2478                             pixel = (byte[])raster.getDataElements(rX, rY,
2479                                                                    pixel);
2480                             normAlpha = (pixel[aIdx] & 0xff) * alphaScale;
2481                             if (normAlpha != 0.0f) {
2482                                 for (int c=0; c < aIdx; c++) {
2483                                     pixel[c] = (byte)((pixel[c] & 0xff) *
2484                                                       normAlpha + 0.5f);
2485                                 }
2486                                 raster.setDataElements(rX, rY, pixel);
2487                             } else {
2488                                 if (zpixel == null) {
2489                                     zpixel = new byte[numComponents];
2490                                     java.util.Arrays.fill(zpixel, (byte) 0);
2491                                 }
2492                                 raster.setDataElements(rX, rY, zpixel);
2493                             }
2494                         }
2495                     }
2496                 }
2497                 break;
2498                 case DataBuffer.TYPE_USHORT: {
2499                     short pixel[] = null;
2500                     short zpixel[] = null;
2501                     float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1));
2502                     for (int y = 0; y < h; y++, rY++) {
2503                         rX = rminX;
2504                         for (int x = 0; x < w; x++, rX++) {
2505                             pixel = (short[])raster.getDataElements(rX, rY,
2506                                                                     pixel);
2507                             normAlpha = (pixel[aIdx] & 0xffff) * alphaScale;
2508                             if (normAlpha != 0.0f) {
2509                                 for (int c=0; c < aIdx; c++) {
2510                                     pixel[c] = (short)
2511                                         ((pixel[c] & 0xffff) * normAlpha +
2512                                          0.5f);
2513                                 }
2514                                 raster.setDataElements(rX, rY, pixel);
2515                             } else {
2516                                 if (zpixel == null) {
2517                                     zpixel = new short[numComponents];
2518                                     java.util.Arrays.fill(zpixel, (short) 0);
2519                                 }
2520                                 raster.setDataElements(rX, rY, zpixel);
2521                             }
2522                         }
2523                     }
2524                 }
2525                 break;
2526                 case DataBuffer.TYPE_INT: {
2527                     int pixel[] = null;
2528                     int zpixel[] = null;
2529                     float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1));
2530                     for (int y = 0; y < h; y++, rY++) {
2531                         rX = rminX;
2532                         for (int x = 0; x < w; x++, rX++) {
2533                             pixel = (int[])raster.getDataElements(rX, rY,
2534                                                                   pixel);
2535                             normAlpha = pixel[aIdx] * alphaScale;
2536                             if (normAlpha != 0.0f) {
2537                                 for (int c=0; c < aIdx; c++) {
2538                                     pixel[c] = (int) (pixel[c] * normAlpha +
2539                                                       0.5f);
2540                                 }
2541                                 raster.setDataElements(rX, rY, pixel);
2542                             } else {
2543                                 if (zpixel == null) {
2544                                     zpixel = new int[numComponents];
2545                                     java.util.Arrays.fill(zpixel, 0);
2546                                 }
2547                                 raster.setDataElements(rX, rY, zpixel);
2548                             }
2549                         }
2550                     }
2551                 }
2552                 break;
2553                 case DataBuffer.TYPE_SHORT: {
2554                     short pixel[] = null;
2555                     short zpixel[] = null;
2556                     float alphaScale = 1.0f / 32767.0f;
2557                     for (int y = 0; y < h; y++, rY++) {
2558                         rX = rminX;
2559                         for (int x = 0; x < w; x++, rX++) {
2560                             pixel = (short[]) raster.getDataElements(rX, rY,
2561                                                                      pixel);
2562                             normAlpha = pixel[aIdx] * alphaScale;
2563                             if (normAlpha != 0.0f) {
2564                                 for (int c=0; c < aIdx; c++) {
2565                                     pixel[c] = (short) (pixel[c] * normAlpha +
2566                                                         0.5f);
2567                                 }
2568                                 raster.setDataElements(rX, rY, pixel);
2569                             } else {
2570                                 if (zpixel == null) {
2571                                     zpixel = new short[numComponents];
2572                                     java.util.Arrays.fill(zpixel, (short) 0);
2573                                 }
2574                                 raster.setDataElements(rX, rY, zpixel);
2575                             }
2576                         }
2577                     }
2578                 }
2579                 break;
2580                 case DataBuffer.TYPE_FLOAT: {
2581                     float pixel[] = null;
2582                     float zpixel[] = null;
2583                     for (int y = 0; y < h; y++, rY++) {
2584                         rX = rminX;
2585                         for (int x = 0; x < w; x++, rX++) {
2586                             pixel = (float[]) raster.getDataElements(rX, rY,
2587                                                                      pixel);
2588                             normAlpha = pixel[aIdx];
2589                             if (normAlpha != 0.0f) {
2590                                 for (int c=0; c < aIdx; c++) {
2591                                     pixel[c] *= normAlpha;
2592                                 }
2593                                 raster.setDataElements(rX, rY, pixel);
2594                             } else {
2595                                 if (zpixel == null) {
2596                                     zpixel = new float[numComponents];
2597                                     java.util.Arrays.fill(zpixel, 0.0f);
2598                                 }
2599                                 raster.setDataElements(rX, rY, zpixel);
2600                             }
2601                         }
2602                     }
2603                 }
2604                 break;
2605                 case DataBuffer.TYPE_DOUBLE: {
2606                     double pixel[] = null;
2607                     double zpixel[] = null;
2608                     for (int y = 0; y < h; y++, rY++) {
2609                         rX = rminX;
2610                         for (int x = 0; x < w; x++, rX++) {
2611                             pixel = (double[]) raster.getDataElements(rX, rY,
2612                                                                       pixel);
2613                             double dnormAlpha = pixel[aIdx];
2614                             if (dnormAlpha != 0.0) {
2615                                 for (int c=0; c < aIdx; c++) {
2616                                     pixel[c] *= dnormAlpha;
2617                                 }
2618                                 raster.setDataElements(rX, rY, pixel);
2619                             } else {
2620                                 if (zpixel == null) {
2621                                     zpixel = new double[numComponents];
2622                                     java.util.Arrays.fill(zpixel, 0.0);
2623                                 }
2624                                 raster.setDataElements(rX, rY, zpixel);
2625                             }
2626                         }
2627                     }
2628                 }
2629                 break;
2630                 default:
2631                     throw new UnsupportedOperationException("This method has not been "+
2632                          "implemented for transferType " + transferType);
2633             }
2634         }
2635         else {
2636             // We are premultiplied and want to divide it out
2637             switch (transferType) {
2638                 case DataBuffer.TYPE_BYTE: {
2639                     byte pixel[] = null;
2640                     float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1));
2641                     for (int y = 0; y < h; y++, rY++) {
2642                         rX = rminX;
2643                         for (int x = 0; x < w; x++, rX++) {
2644                             pixel = (byte[])raster.getDataElements(rX, rY,
2645                                                                    pixel);
2646                             normAlpha = (pixel[aIdx] & 0xff) * alphaScale;
2647                             if (normAlpha != 0.0f) {
2648                                 float invAlpha = 1.0f / normAlpha;
2649                                 for (int c=0; c < aIdx; c++) {
2650                                     pixel[c] = (byte)
2651                                         ((pixel[c] & 0xff) * invAlpha + 0.5f);
2652                                 }
2653                                 raster.setDataElements(rX, rY, pixel);
2654                             }
2655                         }
2656                     }
2657                 }
2658                 break;
2659                 case DataBuffer.TYPE_USHORT: {
2660                     short pixel[] = null;
2661                     float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1));
2662                     for (int y = 0; y < h; y++, rY++) {
2663                         rX = rminX;
2664                         for (int x = 0; x < w; x++, rX++) {
2665                             pixel = (short[])raster.getDataElements(rX, rY,
2666                                                                     pixel);
2667                             normAlpha = (pixel[aIdx] & 0xffff) * alphaScale;
2668                             if (normAlpha != 0.0f) {
2669                                 float invAlpha = 1.0f / normAlpha;
2670                                 for (int c=0; c < aIdx; c++) {
2671                                     pixel[c] = (short)
2672                                         ((pixel[c] & 0xffff) * invAlpha + 0.5f);
2673                                 }
2674                                 raster.setDataElements(rX, rY, pixel);
2675                             }
2676                         }
2677                     }
2678                 }
2679                 break;
2680                 case DataBuffer.TYPE_INT: {
2681                     int pixel[] = null;
2682                     float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1));
2683                     for (int y = 0; y < h; y++, rY++) {
2684                         rX = rminX;
2685                         for (int x = 0; x < w; x++, rX++) {
2686                             pixel = (int[])raster.getDataElements(rX, rY,
2687                                                                   pixel);
2688                             normAlpha = pixel[aIdx] * alphaScale;
2689                             if (normAlpha != 0.0f) {
2690                                 float invAlpha = 1.0f / normAlpha;
2691                                 for (int c=0; c < aIdx; c++) {
2692                                     pixel[c] = (int)
2693                                         (pixel[c] * invAlpha + 0.5f);
2694                                 }
2695                                 raster.setDataElements(rX, rY, pixel);
2696                             }
2697                         }
2698                     }
2699                 }
2700                 break;
2701                 case DataBuffer.TYPE_SHORT: {
2702                     short pixel[] = null;
2703                     float alphaScale = 1.0f / 32767.0f;
2704                     for (int y = 0; y < h; y++, rY++) {
2705                         rX = rminX;
2706                         for (int x = 0; x < w; x++, rX++) {
2707                             pixel = (short[])raster.getDataElements(rX, rY,
2708                                                                     pixel);
2709                             normAlpha = pixel[aIdx] * alphaScale;
2710                             if (normAlpha != 0.0f) {
2711                                 float invAlpha = 1.0f / normAlpha;
2712                                 for (int c=0; c < aIdx; c++) {
2713                                     pixel[c] = (short)
2714                                         (pixel[c] * invAlpha + 0.5f);
2715                                 }
2716                                 raster.setDataElements(rX, rY, pixel);
2717                             }
2718                         }
2719                     }
2720                 }
2721                 break;
2722                 case DataBuffer.TYPE_FLOAT: {
2723                     float pixel[] = null;
2724                     for (int y = 0; y < h; y++, rY++) {
2725                         rX = rminX;
2726                         for (int x = 0; x < w; x++, rX++) {
2727                             pixel = (float[])raster.getDataElements(rX, rY,
2728                                                                     pixel);
2729                             normAlpha = pixel[aIdx];
2730                             if (normAlpha != 0.0f) {
2731                                 float invAlpha = 1.0f / normAlpha;
2732                                 for (int c=0; c < aIdx; c++) {
2733                                     pixel[c] *= invAlpha;
2734                                 }
2735                                 raster.setDataElements(rX, rY, pixel);
2736                             }
2737                         }
2738                     }
2739                 }
2740                 break;
2741                 case DataBuffer.TYPE_DOUBLE: {
2742                     double pixel[] = null;
2743                     for (int y = 0; y < h; y++, rY++) {
2744                         rX = rminX;
2745                         for (int x = 0; x < w; x++, rX++) {
2746                             pixel = (double[])raster.getDataElements(rX, rY,
2747                                                                      pixel);
2748                             double dnormAlpha = pixel[aIdx];
2749                             if (dnormAlpha != 0.0) {
2750                                 double invAlpha = 1.0 / dnormAlpha;
2751                                 for (int c=0; c < aIdx; c++) {
2752                                     pixel[c] *= invAlpha;
2753                                 }
2754                                 raster.setDataElements(rX, rY, pixel);
2755                             }
2756                         }
2757                     }
2758                 }
2759                 break;
2760                 default:
2761                     throw new UnsupportedOperationException("This method has not been "+
2762                          "implemented for transferType " + transferType);
2763             }
2764         }
2765 
2766         // Return a new color model
2767         if (!signed) {
2768             return new ComponentColorModel(colorSpace, nBits, supportsAlpha,
2769                                            isAlphaPremultiplied, transparency,
2770                                            transferType);
2771         } else {
2772             return new ComponentColorModel(colorSpace, supportsAlpha,
2773                                            isAlphaPremultiplied, transparency,
2774                                            transferType);
2775         }
2776 
2777     }
2778 
2779     /**
2780       * Returns true if {@code raster} is compatible with this
2781       * {@code ColorModel}; false if it is not.
2782       *
2783       * @param raster The {@code Raster} object to test for compatibility.
2784       *
2785       * @return {@code true} if {@code raster} is compatible with this
2786       * {@code ColorModel}, {@code false} if it is not.
2787       */
2788     public boolean isCompatibleRaster(Raster raster) {
2789 
2790         SampleModel sm = raster.getSampleModel();
2791 
2792         if (sm instanceof ComponentSampleModel) {
2793             if (sm.getNumBands() != getNumComponents()) {
2794                 return false;
2795             }
2796             for (int i=0; i<nBits.length; i++) {
2797                 if (sm.getSampleSize(i) < nBits[i]) {
2798                     return false;
2799                 }
2800             }
2801             return (raster.getTransferType() == transferType);
2802         }
2803         else {
2804             return false;
2805         }
2806     }
2807 
2808     /**
2809      * Creates a {@code WritableRaster} with the specified width and height,
2810      * that  has a data layout ({@code SampleModel}) compatible with
2811      * this {@code ColorModel}.
2812      *
2813      * @param w The width of the {@code WritableRaster} you want to create.
2814      * @param h The height of the {@code WritableRaster} you want to create.
2815      *
2816      * @return A {@code WritableRaster} that is compatible with
2817      * this {@code ColorModel}.
2818      * @see WritableRaster
2819      * @see SampleModel
2820      */
2821     public WritableRaster createCompatibleWritableRaster (int w, int h) {
2822         int dataSize = w*h*numComponents;
2823         WritableRaster raster = null;
2824 
2825         switch (transferType) {
2826         case DataBuffer.TYPE_BYTE:
2827         case DataBuffer.TYPE_USHORT:
2828             raster = Raster.createInterleavedRaster(transferType,
2829                                                     w, h,
2830                                                     numComponents, null);
2831             break;
2832         default:
2833             SampleModel sm = createCompatibleSampleModel(w, h);
2834             DataBuffer db = sm.createDataBuffer();
2835             raster = Raster.createWritableRaster(sm, db, null);
2836         }
2837 
2838         return raster;
2839     }
2840 
2841     /**
2842      * Creates a {@code SampleModel} with the specified width and height,
2843      * that  has a data layout compatible with this {@code ColorModel}.
2844      *
2845      * @param w The width of the {@code SampleModel} you want to create.
2846      * @param h The height of the {@code SampleModel} you want to create.
2847      *
2848      * @return A {@code SampleModel} that is compatible with this
2849      * {@code ColorModel}.
2850      *
2851      * @see SampleModel
2852      */
2853     public SampleModel createCompatibleSampleModel(int w, int h) {
2854         int[] bandOffsets = new int[numComponents];
2855         for (int i=0; i < numComponents; i++) {
2856             bandOffsets[i] = i;
2857         }
2858         switch (transferType) {
2859         case DataBuffer.TYPE_BYTE:
2860         case DataBuffer.TYPE_USHORT:
2861             return new PixelInterleavedSampleModel(transferType, w, h,
2862                                                    numComponents,
2863                                                    w*numComponents,
2864                                                    bandOffsets);
2865         default:
2866             return new ComponentSampleModel(transferType, w, h,
2867                                             numComponents,
2868                                             w*numComponents,
2869                                             bandOffsets);
2870         }
2871     }
2872 
2873     /**
2874      * Checks whether or not the specified {@code SampleModel}
2875      * is compatible with this {@code ColorModel}.
2876      *
2877      * @param sm The {@code SampleModel} to test for compatibility.
2878      *
2879      * @return {@code true} if the {@code SampleModel} is
2880      * compatible with this {@code ColorModel}, {@code false}
2881      * if it is not.
2882      *
2883      * @see SampleModel
2884      */
2885     public boolean isCompatibleSampleModel(SampleModel sm) {
2886         if (!(sm instanceof ComponentSampleModel)) {
2887             return false;
2888         }
2889 
2890         // Must have the same number of components
2891         if (numComponents != sm.getNumBands()) {
2892             return false;
2893         }
2894 
2895         if (sm.getTransferType() != transferType) {
2896             return false;
2897         }
2898 
2899         return true;
2900     }
2901 
2902     /**
2903      * Returns a {@code Raster} representing the alpha channel of an image,
2904      * extracted from the input {@code Raster}.
2905      * This method assumes that {@code Raster} objects associated with
2906      * this {@code ColorModel} store the alpha band, if present, as
2907      * the last band of image data. Returns null if there is no separate spatial
2908      * alpha channel associated with this {@code ColorModel}.
2909      * This method creates a new {@code Raster}, but will share the data
2910      * array.
2911      *
2912      * @param raster The {@code WritableRaster} from which to extract the
2913      * alpha  channel.
2914      *
2915      * @return A {@code WritableRaster} containing the image's alpha channel.
2916      *
2917      */
2918     public WritableRaster getAlphaRaster(WritableRaster raster) {
2919         if (hasAlpha() == false) {
2920             return null;
2921         }
2922 
2923         int x = raster.getMinX();
2924         int y = raster.getMinY();
2925         int[] band = new int[1];
2926         band[0] = raster.getNumBands() - 1;
2927         return raster.createWritableChild(x, y, raster.getWidth(),
2928                                           raster.getHeight(), x, y,
2929                                           band);
2930     }
2931 
2932     /**
2933      * Tests if the specified {@code Object} is an instance
2934      * of {@code ComponentColorModel} and equals this
2935      * {@code ComponentColorModel}.
2936      * @param obj the {@code Object} to test for equality
2937      * @return {@code true} if the specified {@code Object}
2938      * is an instance of {@code ComponentColorModel} and equals this
2939      * {@code ComponentColorModel}; {@code false} otherwise.
2940      */
2941     @Override
2942     public boolean equals(Object obj) {
2943         if (!(obj instanceof ComponentColorModel)) {
2944             return false;
2945         }
2946 
2947         ComponentColorModel cm = (ComponentColorModel) obj;
2948         if (supportsAlpha != cm.hasAlpha() ||
2949             isAlphaPremultiplied != cm.isAlphaPremultiplied() ||
2950             pixel_bits != cm.getPixelSize() ||
2951             transparency != cm.getTransparency() ||
2952             numComponents != cm.getNumComponents() ||
2953             (!(colorSpace.equals(cm.colorSpace))) ||
2954             transferType != cm.transferType)
2955         {
2956             return false;
2957         }
2958 
2959         int[] nb = cm.getComponentSize();
2960 
2961         if ((nBits != null) && (nb != null)) {
2962             for (int i = 0; i < numComponents; i++) {
2963                 if (nBits[i] != nb[i]) {
2964                     return false;
2965                 }
2966             }
2967         } else {
2968             return ((nBits == null) && (nb == null));
2969         }
2970 
2971         return true;
2972     }
2973 
2974     /**
2975      * Returns the hash code for this ComponentColorModel.
2976      *
2977      * @return    a hash code for this ComponentColorModel.
2978      */
2979     @Override
2980     public int hashCode() {
2981         int result = hashCode;
2982         if (result == 0) {
2983             result = 7;
2984             result = 89 * result + this.pixel_bits;
2985             result = 89 * result + Arrays.hashCode(this.nBits);
2986             result = 89 * result + this.transparency;
2987             result = 89 * result + (this.supportsAlpha ? 1 : 0);
2988             result = 89 * result + (this.isAlphaPremultiplied ? 1 : 0);
2989             result = 89 * result + this.numComponents;
2990             result = 89 * result + Objects.hashCode(this.colorSpace);
2991             result = 89 * result + this.transferType;
2992             hashCode = result;
2993         }
2994         return result;
2995     }
2996 }