blob: 0f25e909b9927525219a5ef02d56fabc53761908 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2003 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.awt.image;
27
28import java.awt.color.ColorSpace;
29import 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 */
177public 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 overrridden 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}