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