View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, 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</CODE> 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</CODE>.  The number of
36   * color samples in the pixel values must be same as the number of
37   * color components in the <CODE>ColorSpace</CODE>. 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</CODE>,
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</CODE>.  Typically, this order reflects the
46   * name of the color space type. For example, for <CODE>TYPE_RGB</CODE>,
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</code>, 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</code> and <code>getMaxValue</code>
66   * methods of the <code>ColorSpace</code> class.  The range for an
67   * alpha component should be 0.0 to 1.0.
68   * <p>
69   * Instances of <code>ComponentColorModel</code> created with transfer types
70   * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
71   * and <CODE>DataBuffer.TYPE_INT</CODE> 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)</code>
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</code> <code>getMinValue</code>
85   * method for each component and 2<sup>n</sup> - 1 maps to the value
86   * obtained from <code>getMaxValue</code>.  To create a
87   * <code>ComponentColorModel</code> with a different color sample mapping
88   * requires subclassing this class and overriding the
89   * <code>getNormalizedComponents(Object, float[], int)</code> 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 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</code> 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</code>.
105  * <p>
106  * Instances of <code>ComponentColorModel</code> created with transfer types
107  * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, and
108  * <CODE>DataBuffer.TYPE_DOUBLE</CODE> 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</code> 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</code>
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)</code> 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</code> created with transfer types
130  * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>, and
131  * <CODE>DataBuffer.TYPE_DOUBLE</CODE>
132  * use all the bits of all sample values.  Thus all color/alpha components
133  * have 16 bits when using <CODE>DataBuffer.TYPE_SHORT</CODE>, 32 bits when
134  * using <CODE>DataBuffer.TYPE_FLOAT</CODE>, and 64 bits when using
135  * <CODE>DataBuffer.TYPE_DOUBLE</CODE>.  When the
136  * <code>ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)</code>
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</code> 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</code> (obtained using the <code>getMinValue</code>
151  * and <code>getMaxValue</code> methods of the <code>ColorSpace</code> 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</CODE>, unless the number of components
158  * for the <CODE>ComponentColorModel</CODE> 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</CODE>,
161  * <CODE>DataBuffer.TYPE_USHORT</CODE>, or <CODE>DataBuffer.TYPE_INT</CODE>
162  * and no alpha.
163  * <p>
164  * A <CODE>ComponentColorModel</CODE> can be used in conjunction with a
165  * <CODE>ComponentSampleModel</CODE>, a <CODE>BandedSampleModel</CODE>,
166  * or a <CODE>PixelInterleavedSampleModel</CODE> to construct a
167  * <CODE>BufferedImage</CODE>.
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</code>  is <code>true</code> for <code>short</code>,
181      * <code>float</code>, and <code>double</code> transfer types; it
182      * is <code>false</code> for <code>byte</code>, <code>ushort</code>,
183      * and <code>int</code> 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</CODE> from the specified
206      * parameters. Color components will be in the specified
207      * <CODE>ColorSpace</CODE>.  The supported transfer types are
208      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
209      * <CODE>DataBuffer.TYPE_INT</CODE>,
210      * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>,
211      * and <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
212      * If not null, the <CODE>bits</CODE> 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</CODE> 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</CODE> is
218      * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>,
219      * or <CODE>DataBuffer.TYPE_DOUBLE</CODE> the <CODE>bits</CODE> array
220      * argument is ignored.  <CODE>hasAlpha</CODE> indicates whether alpha
221      * information is present.  If <CODE>hasAlpha</CODE> is true, then
222      * the boolean <CODE>isAlphaPremultiplied</CODE>
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</CODE>
226      * specifies what alpha values can be represented by this color model.
227      * The acceptable <code>transparency</code> values are
228      * <CODE>OPAQUE</CODE>, <CODE>BITMASK</CODE> or <CODE>TRANSLUCENT</CODE>.
229      * The <CODE>transferType</CODE> is the type of primitive array used
230      * to represent pixel values.
231      *
232      * @param colorSpace       The <CODE>ColorSpace</CODE> 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</CODE>,
239      *                         <CODE>DataBuffer.TYPE_FLOAT</CODE>, or
240      *                         <CODE>DataBuffer.TYPE_DOUBLE</CODE>,
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</CODE> 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</CODE>,
254      *         <CODE>DataBuffer.TYPE_USHORT</CODE>, or
255      *         <CODE>DataBuffer.TYPE_INT</CODE>.
256      * @throws IllegalArgumentException If transferType is not one of
257      *         <CODE>DataBuffer.TYPE_BYTE</CODE>,
258      *         <CODE>DataBuffer.TYPE_USHORT</CODE>,
259      *         <CODE>DataBuffer.TYPE_INT</CODE>,
260      *         <CODE>DataBuffer.TYPE_SHORT</CODE>,
261      *         <CODE>DataBuffer.TYPE_FLOAT</CODE>, or
262      *         <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE> from the specified
304      * parameters. Color components will be in the specified
305      * <CODE>ColorSpace</CODE>.  The supported transfer types are
306      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
307      * <CODE>DataBuffer.TYPE_INT</CODE>,
308      * <CODE>DataBuffer.TYPE_SHORT</CODE>, <CODE>DataBuffer.TYPE_FLOAT</CODE>,
309      * and <CODE>DataBuffer.TYPE_DOUBLE</CODE>.  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</CODE>.  There will be
313      * an alpha component if <CODE>hasAlpha</CODE> is <CODE>true</CODE>.
314      * If <CODE>hasAlpha</CODE> is true, then
315      * the boolean <CODE>isAlphaPremultiplied</CODE>
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</CODE>
319      * specifies what alpha values can be represented by this color model.
320      * The acceptable <code>transparency</code> values are
321      * <CODE>OPAQUE</CODE>, <CODE>BITMASK</CODE> or <CODE>TRANSLUCENT</CODE>.
322      * The <CODE>transferType</CODE> is the type of primitive array used
323      * to represent pixel values.
324      *
325      * @param colorSpace       The <CODE>ColorSpace</CODE> 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</CODE>,
336      *         <CODE>DataBuffer.TYPE_USHORT</CODE>,
337      *         <CODE>DataBuffer.TYPE_INT</CODE>,
338      *         <CODE>DataBuffer.TYPE_SHORT</CODE>,
339      *         <CODE>DataBuffer.TYPE_FLOAT</CODE>, or
340      *         <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE>.
666      * @throws IllegalArgumentException If the component value for this
667      * <CODE>ColorModel</CODE> 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</CODE>.
688      * @throws IllegalArgumentException If the component value for this
689      * <CODE>ColorModel</CODE> 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</CODE>.
710      * @throws IllegalArgumentException If the component value for this
711      * <CODE>ColorModel</CODE> 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</CODE>.
727      * @throws IllegalArgumentException If the component value for this
728      * <CODE>ColorModel</CODE> 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</CODE>.
759      * @throws IllegalArgumentException If the component value for this
760      * <CODE>ColorModel</CODE> 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</CODE> value is specified by an array
917      * of data elements of type <CODE>transferType</CODE> 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</code> 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</code>.
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</CODE>.
928      *
929      * @return The red color component for the specified pixel, as an int.
930      *
931      * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
932      * of type <CODE>transferType</CODE>.
933      * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
934      * large enough to hold a pixel value for this
935      * <CODE>ColorModel</CODE>.
936      * @throws UnsupportedOperationException If the transfer type of
937      * this <CODE>ComponentColorModel</CODE>
938      * is not one of the supported transfer types:
939      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
940      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
941      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE>, sRGB.
951      * A color conversion is done if necessary.  The <CODE>pixel</CODE> value
952      * is specified by an array of data elements of type <CODE>transferType</CODE>
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</code> 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</code>.
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</CODE>.
963      *
964      * @return The green color component for the specified pixel, as an int.
965      *
966      * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
967      * of type <CODE>transferType</CODE>.
968      * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
969      * large enough to hold a pixel value for this
970      * <CODE>ColorModel</CODE>.
971      * @throws UnsupportedOperationException If the transfer type of
972      * this <CODE>ComponentColorModel</CODE>
973      * is not one of the supported transfer types:
974      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
975      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
976      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE>, sRGB.
986      * A color conversion is done if necessary.  The <CODE>pixel</CODE> value is
987      * specified by an array of data elements of type <CODE>transferType</CODE>
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</code> 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</code>.
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</CODE>.
998      *
999      * @return The blue color component for the specified pixel, as an int.
1000      *
1001      * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
1002      * of type <CODE>transferType</CODE>.
1003      * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
1004      * large enough to hold a pixel value for this
1005      * <CODE>ColorModel</CODE>.
1006      * @throws UnsupportedOperationException If the transfer type of
1007      * this <CODE>ComponentColorModel</CODE>
1008      * is not one of the supported transfer types:
1009      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
1010      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
1011      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE> passed in as an
1021      * object reference.  Since <code>ComponentColorModel</code> 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</code>.
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</CODE>.
1029      *
1030      * @return The alpha component for the specified pixel, as an int.
1031      *
1032      * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
1033      * of type <CODE>transferType</CODE>.
1034      * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
1035      * large enough to hold a pixel value for this
1036      * <CODE>ColorModel</CODE>.
1037      * @throws UnsupportedOperationException If the transfer type of
1038      * this <CODE>ComponentColorModel</CODE>
1039      * is not one of the supported transfer types:
1040      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
1041      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
1042      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE> 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</code> 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</code>.
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</CODE>.
1109      *
1110      * @return The color/alpha components for the specified pixel, as an int.
1111      *
1112      * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
1113      * of type <CODE>transferType</CODE>.
1114      * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
1115      * large enough to hold a pixel value for this
1116      * <CODE>ColorModel</CODE>.
1117      * @throws UnsupportedOperationException If the transfer type of
1118      * this <CODE>ComponentColorModel</CODE>
1119      * is not one of the supported transfer types:
1120      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
1121      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
1122      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE>, given an integer pixel representation
1154      * in the default RGB color model.
1155      * This array can then be passed to the <CODE>setDataElements</CODE>
1156      * method of a <CODE>WritableRaster</CODE> object.  If the
1157      * <CODE>pixel</CODE>
1158      * parameter is null, a new array is allocated.  Since
1159      * <code>ComponentColorModel</code> 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</code>.
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</CODE>.
1170      * @throws ClassCastException If <CODE>pixel</CODE> is not null and
1171      * is not a primitive array of type <CODE>transferType</CODE>.
1172      * @throws ArrayIndexOutOfBoundsException If <CODE>pixel</CODE> is
1173      * not large enough to hold a pixel value for this
1174      * <CODE>ColorModel</CODE>.
1175      * @throws UnsupportedOperationException If the transfer type of
1176      * this <CODE>ComponentColorModel</CODE>
1177      * is not one of the supported transfer types:
1178      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
1179      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
1180      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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] = (int)(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] = (int)(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</CODE>.
1659      * An IllegalArgumentException is thrown if the component value for this
1660      * <CODE>ColorModel</CODE> is not conveniently representable in the
1661      * unnormalized form.  Color/alpha components are stored
1662      * in the <CODE>components</CODE> array starting at <CODE>offset</CODE>
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</CODE> array is null,
1668      * a new array is allocated.
1669      * @param offset An offset into the <CODE>components</CODE> array.
1670      *
1671      * @return The components array.
1672      *
1673      * @throws IllegalArgumentException If there is more than one
1674      * component in this <CODE>ColorModel</CODE>.
1675      * @throws IllegalArgumentException If this
1676      * <CODE>ColorModel</CODE> does not support the unnormalized form
1677      * @throws ArrayIndexOutOfBoundsException If the <CODE>components</CODE>
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</CODE>.  The pixel value is specified by an
1705      * array of data elements of type <CODE>transferType</CODE> passed in as
1706      * an object reference.
1707      * An IllegalArgumentException is thrown if the component values for this
1708      * <CODE>ColorModel</CODE> are not conveniently representable in the
1709      * unnormalized form.
1710      * Color/alpha components are stored in the <CODE>components</CODE> array
1711      * starting at  <CODE>offset</CODE> (even if the array is allocated by
1712      * this method).  Since <code>ComponentColorModel</code> 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</code>.
1717      *
1718      * @param pixel A pixel value specified by an array of data elements of
1719      * type <CODE>transferType</CODE>.
1720      * @param components An integer array in which to store the unnormalized
1721      * color/alpha components. If the <CODE>components</CODE> array is null,
1722      * a new array is allocated.
1723      * @param offset An offset into the <CODE>components</CODE> array.
1724      *
1725      * @return The <CODE>components</CODE> array.
1726      *
1727      * @throws IllegalArgumentException If this
1728      * <CODE>ComponentColorModel</CODE> does not support the unnormalized form
1729      * @throws UnsupportedOperationException in some cases iff the
1730      * transfer type of this <CODE>ComponentColorModel</CODE>
1731      * is not one of the following transfer types:
1732      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
1733      * or <CODE>DataBuffer.TYPE_INT</CODE>.
1734      * @throws ClassCastException If <CODE>pixel</CODE> is not a primitive
1735      * array of type <CODE>transferType</CODE>.
1736      * @throws IllegalArgumentException If the <CODE>components</CODE> 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</CODE> 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</code> object for this
1783      * <code>ColorModel</code>.  An <code>IllegalArgumentException</code>
1784      * will be thrown if color component values for this
1785      * <code>ColorModel</code> are not conveniently representable in the
1786      * unnormalized form.  If the
1787      * <code>components</code> array is <code>null</code>, a new array
1788      * will be allocated.  The <code>components</code> array will
1789      * be returned.  Color/alpha components are stored in the
1790      * <code>components</code> array starting at <code>offset</code> (even
1791      * if the array is allocated by this method). An
1792      * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
1793      * <code>components</code> array is not <code>null</code> and is not
1794      * large enough to hold all the color and alpha
1795      * components (starting at <code>offset</code>).  An
1796      * <code>IllegalArgumentException</code> is thrown if the
1797      * <code>normComponents</code> array is not large enough to hold
1798      * all the color and alpha components starting at
1799      * <code>normOffset</code>.
1800      * @param normComponents an array containing normalized components
1801      * @param normOffset the offset into the <code>normComponents</code>
1802      * array at which to start retrieving normalized components
1803      * @param components an array that receives the components from
1804      * <code>normComponents</code>
1805      * @param offset the index into <code>components</code> at which to
1806      * begin storing normalized components from
1807      * <code>normComponents</code>
1808      * @return an array containing unnormalized color and alpha
1809      * components.
1810      * @throws IllegalArgumentException If this
1811      * <CODE>ComponentColorModel</CODE> does not support the unnormalized form
1812      * @throws IllegalArgumentException if the length of
1813      *          <code>normComponents</code> minus <code>normOffset</code>
1814      *          is less than <code>numComponents</code>
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</code> object for this
1838      * <code>ColorModel</code>.  An <code>IllegalArgumentException</code>
1839      * will be thrown if color component values for this
1840      * <code>ColorModel</code> are not conveniently representable in the
1841      * unnormalized form.  If the
1842      * <code>normComponents</code> array is <code>null</code>, a new array
1843      * will be allocated.  The <code>normComponents</code> array
1844      * will be returned.  Color/alpha components are stored in the
1845      * <code>normComponents</code> array starting at
1846      * <code>normOffset</code> (even if the array is allocated by this
1847      * method).  An <code>ArrayIndexOutOfBoundsException</code> is thrown
1848      * if the <code>normComponents</code> array is not <code>null</code>
1849      * and is not large enough to hold all the color and alpha components
1850      * (starting at <code>normOffset</code>).  An
1851      * <code>IllegalArgumentException</code> is thrown if the
1852      * <code>components</code> array is not large enough to hold all the
1853      * color and alpha components starting at <code>offset</code>.
1854      * @param components an array containing unnormalized components
1855      * @param offset the offset into the <code>components</code> 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</code> 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</CODE> 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</CODE>,
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</CODE> 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</CODE>.
1891      * @throws IllegalArgumentException If this
1892      * <CODE>ComponentColorModel</CODE> 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</CODE>, given an array of unnormalized color/alpha
1914      * components. This array can then be passed to the <CODE>setDataElements</CODE>
1915      * method of a <CODE>WritableRaster</CODE> object.
1916      *
1917      * @param components An array of unnormalized color/alpha components.
1918      * @param offset The integer offset into the <CODE>components</CODE> array.
1919      * @param obj The object in which to store the data element array
1920      * representation of the pixel. If <CODE>obj</CODE> variable is null,
1921      * a new array is allocated.  If <CODE>obj</CODE> is not null, it must
1922      * be a primitive array of type <CODE>transferType</CODE>. An
1923      * <CODE>ArrayIndexOutOfBoundsException</CODE> is thrown if
1924      * <CODE>obj</CODE> is not large enough to hold a pixel value
1925      * for this <CODE>ColorModel</CODE>.  Since
1926      * <code>ComponentColorModel</code> 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</code>.
1930      *
1931      * @return The data element array representation of a pixel
1932      * in this <CODE>ColorModel</CODE>.
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</CODE> is not null and is not a
1938      * primitive  array of type <CODE>transferType</CODE>.
1939      * @throws ArrayIndexOutOfBoundsException If <CODE>obj</CODE> is not large
1940      * enough to hold a pixel value for this <CODE>ColorModel</CODE>.
1941      * @throws IllegalArgumentException If this
1942      * <CODE>ComponentColorModel</CODE> does not support the unnormalized form
1943      * @throws UnsupportedOperationException If the transfer type of
1944      * this <CODE>ComponentColorModel</CODE>
1945      * is not one of the following transfer types:
1946      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
1947      * or <CODE>DataBuffer.TYPE_INT</CODE>.
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</code> in this
2019      * <code>ColorModel</code>, given an array of normalized color/alpha
2020      * components.  This method will throw an
2021      * <code>IllegalArgumentException</code> if pixel values for this
2022      * <code>ColorModel</code> are not conveniently representable as a
2023      * single <code>int</code>.  An
2024      * <code>ArrayIndexOutOfBoundsException</code> is thrown if  the
2025      * <code>normComponents</code> array is not large enough to hold all the
2026      * color and alpha components (starting at <code>normOffset</code>).
2027      * @param normComponents an array of normalized color and alpha
2028      * components
2029      * @param normOffset the index into <code>normComponents</code> at which to
2030      * begin retrieving the color and alpha components
2031      * @return an <code>int</code> pixel value in this
2032      * <code>ColorModel</code> corresponding to the specified components.
2033      * @throws IllegalArgumentException if
2034      *  pixel values for this <code>ColorModel</code> are not
2035      *  conveniently representable as a single <code>int</code>
2036      * @throws ArrayIndexOutOfBoundsException if
2037      *  the <code>normComponents</code> array is not large enough to
2038      *  hold all of the color and alpha components starting at
2039      *  <code>normOffset</code>
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</code>, given an array of normalized color/alpha
2080      * components.  This array can then be passed to the
2081      * <code>setDataElements</code> method of a <code>WritableRaster</code>
2082      * object.  An <code>ArrayIndexOutOfBoundsException</code> is thrown
2083      * if the <code>normComponents</code> array is not large enough to hold
2084      * all the color and alpha components (starting at
2085      * <code>normOffset</code>).  If the <code>obj</code> variable is
2086      * <code>null</code>, a new array will be allocated.  If
2087      * <code>obj</code> is not <code>null</code>, it must be a primitive
2088      * array of type transferType; otherwise, a
2089      * <code>ClassCastException</code> is thrown.  An
2090      * <code>ArrayIndexOutOfBoundsException</code> is thrown if
2091      * <code>obj</code> is not large enough to hold a pixel value for this
2092      * <code>ColorModel</code>.
2093      * @param normComponents an array of normalized color and alpha
2094      * components
2095      * @param normOffset the index into <code>normComponents</code> 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</code> which is a primitive data array
2099      * representation of a pixel
2100      * @throws ClassCastException if <code>obj</code>
2101      *  is not a primitive array of type <code>transferType</code>
2102      * @throws ArrayIndexOutOfBoundsException if
2103      *  <code>obj</code> is not large enough to hold a pixel value
2104      *  for this <code>ColorModel</code> or the <code>normComponents</code>
2105      *  array is not large enough to hold all of the color and alpha
2106      *  components starting at <code>normOffset</code>
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</code>.  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</code> is thrown.
2305      * An <code>ArrayIndexOutOfBoundsException</code> is thrown if
2306      * <code>pixel</code> is not large enough to hold a pixel value for this
2307      * <code>ColorModel</code>.
2308      * Normalized components are float values between a per component minimum
2309      * and maximum specified by the <code>ColorSpace</code> object for this
2310      * <code>ColorModel</code>.  If the
2311      * <code>normComponents</code> array is <code>null</code>, a new array
2312      * will be allocated.  The <code>normComponents</code> array
2313      * will be returned.  Color/alpha components are stored in the
2314      * <code>normComponents</code> array starting at
2315      * <code>normOffset</code> (even if the array is allocated by this
2316      * method).  An <code>ArrayIndexOutOfBoundsException</code> is thrown
2317      * if the <code>normComponents</code> array is not <code>null</code>
2318      * and is not large enough to hold all the color and alpha components
2319      * (starting at <code>normOffset</code>).
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</code>
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</code> is not a primitive
2334      *          array of type transferType
2335      * @throws ArrayIndexOutOfBoundsException if
2336      *          <code>normComponents</code> is not large enough to hold all
2337      *          color and alpha components starting at <code>normOffset</code>
2338      * @throws ArrayIndexOutOfBoundsException if
2339      *          <code>pixel</code> is not large enough to hold a pixel
2340      *          value for this <code>ColorModel</code>.
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</CODE> variable, assuming the data
2430      * is currently correctly described by this <CODE>ColorModel</CODE>.
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</CODE> with
2435      * the <CODE>isAlphaPremultiplied</CODE> flag set appropriately.
2436      * Since <code>ColorModel</code> 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</code>.
2440      *
2441      * @throws NullPointerException if <code>raster</code> is
2442      * <code>null</code> and data coercion is required.
2443      * @throws UnsupportedOperationException if the transfer type of
2444      * this <CODE>ComponentColorModel</CODE>
2445      * is not one of the supported transfer types:
2446      * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
2447      * <CODE>DataBuffer.TYPE_INT</CODE>, <CODE>DataBuffer.TYPE_SHORT</CODE>,
2448      * <CODE>DataBuffer.TYPE_FLOAT</CODE>, or <CODE>DataBuffer.TYPE_DOUBLE</CODE>.
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</CODE> is compatible with this
2778       * <CODE>ColorModel</CODE>; false if it is not.
2779       *
2780       * @param raster The <CODE>Raster</CODE> object to test for compatibility.
2781       *
2782       * @return <CODE>true</CODE> if <CODE>raster</CODE> is compatible with this
2783       * <CODE>ColorModel</CODE>, <CODE>false</CODE> 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</CODE> with the specified width and height,
2807      * that  has a data layout (<CODE>SampleModel</CODE>) compatible with
2808      * this <CODE>ColorModel</CODE>.
2809      *
2810      * @param w The width of the <CODE>WritableRaster</CODE> you want to create.
2811      * @param h The height of the <CODE>WritableRaster</CODE> you want to create.
2812      *
2813      * @return A <CODE>WritableRaster</CODE> that is compatible with
2814      * this <CODE>ColorModel</CODE>.
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</CODE> with the specified width and height,
2840      * that  has a data layout compatible with this <CODE>ColorModel</CODE>.
2841      *
2842      * @param w The width of the <CODE>SampleModel</CODE> you want to create.
2843      * @param h The height of the <CODE>SampleModel</CODE> you want to create.
2844      *
2845      * @return A <CODE>SampleModel</CODE> that is compatible with this
2846      * <CODE>ColorModel</CODE>.
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</CODE>
2872      * is compatible with this <CODE>ColorModel</CODE>.
2873      *
2874      * @param sm The <CODE>SampleModel</CODE> to test for compatibility.
2875      *
2876      * @return <CODE>true</CODE> if the <CODE>SampleModel</CODE> is
2877      * compatible with this <CODE>ColorModel</CODE>, <CODE>false</CODE>
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</CODE> representing the alpha channel of an image,
2901      * extracted from the input <CODE>Raster</CODE>.
2902      * This method assumes that <CODE>Raster</CODE> objects associated with
2903      * this <CODE>ColorModel</CODE> 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</CODE>.
2906      * This method creates a new <CODE>Raster</CODE>, but will share the data
2907      * array.
2908      *
2909      * @param raster The <CODE>WritableRaster</CODE> from which to extract the
2910      * alpha  channel.
2911      *
2912      * @return A <CODE>WritableRaster</CODE> 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</CODE> if the color model objects are equal,
2934      * <CODE>false</CODE> 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 }