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