Source code: non_com/media/jai/FloatDoubleColorModel.java
1 /*
2 * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * -Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * -Redistribution in binary form must reproduct the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
15 * be used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * This software is provided "AS IS," without a warranty of any kind. ALL
19 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
20 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
21 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
22 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
23 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
24 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
25 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
26 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
27 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 *
30 * You acknowledge that Software is not designed,licensed or intended for use in
31 * the design, construction, operation or maintenance of any nuclear facility.
32 */
33 package non_com.media.jai;
34
35 import non_com.media.jai.codec.JaiI18N;
36
37 import java.awt.Point;
38 import java.awt.Transparency;
39 import java.awt.color.ColorSpace;
40 import java.awt.image.ColorModel;
41 import java.awt.image.ComponentColorModel;
42 import java.awt.image.ComponentSampleModel;
43 import java.awt.image.DataBuffer;
44 import java.awt.image.Raster;
45 import java.awt.image.SampleModel;
46 import java.awt.image.WritableRaster;
47
48 /**
49 * A <code>ColorModel</code> class that works with pixel values that represent
50 * color and alpha information as separate samples, using float or double
51 * elements. This class can be used with an arbitrary <code>ColorSpace</code>.
52 * The number of color samples in the pixel values must be same as the number
53 * of color components in the <code>ColorSpace</code>. There may be a single
54 * alpha sample. <p>
55 *
56 * Sample values are taken as ranging from 0.0 to 1.0; that is, when converting
57 * to 8-bit RGB, a multiplication by 255 is performed and values outside of the
58 * range 0-255 are clamped at the closest endpoint. <p>
59 *
60 * For maximum efficiency, pixel data being interpreted by this class should be
61 * in the sRGB color space. This will result in only the trivial conversion
62 * (scaling by 255 and dividing by any premultiplied alpha) to be performed.
63 * Other color spaces require more general conversions. <p>
64 *
65 * For those methods that use a primitive array pixel representation of type
66 * <code>transferType</code>, the array length is the same as the number of
67 * color and alpha samples. Color samples are stored first in the array
68 * followed by the alpha sample, if present. The order of the color samples is
69 * specified by the <code>ColorSpace</code>. Typically, this order reflects the
70 * name of the color space type. For example, for <code>TYPE_RGB</code>, index
71 * 0 corresponds to red, index 1 to green, and index 2 to blue. The transfer
72 * types supported are <code>DataBuffer.TYPE_FLOAT</code>, <code>DataBuffer.TYPE_DOUBLE</code>
73 * . <p>
74 *
75 * The translation from pixel values to color/alpha components for display or
76 * processing purposes is a one-to-one correspondence of samples to components.
77 * <p>
78 *
79 * Methods that use a single int pixel representation throw an <code>IllegalArgumentException</code>
80 * . <p>
81 *
82 * A <code>FloatDoubleColorModel</code> can be used in conjunction with a
83 * <code>ComponentSampleModelJAI</code>.
84 *
85 * @see java.awt.image.ColorModel
86 * @see java.awt.color.ColorSpace
87 * @see java.awt.image.ComponentSampleModel
88 * @see ComponentSampleModelJAI
89 */
90 public class FloatDoubleColorModel extends ComponentColorModel {
91
92 /**
93 * The associated <code>ColorSpace</code>.
94 */
95 protected ColorSpace colorSpace;
96
97 /**
98 * The type or family of the associated <code>ColorSpace</code>.
99 */
100 protected int colorSpaceType;
101
102 /**
103 * The number of components of the associated <code>ColorSpace</code>.
104 */
105 protected int numColorComponents;
106
107 /**
108 * The number of components represented by this <code>ColorModel</code>. This
109 * will differ from the number of components of the associated <code>ColorSpace</code>
110 * if there is an alpha channel.
111 */
112 protected int numComponents;
113
114 /**
115 * Specifies what alpha values can be represented by this <code>ColorModel</code>
116 * .
117 */
118 protected int transparency;
119
120 /**
121 * Whether this <code>ColorModel</code> supports alpha.
122 */
123 protected boolean hasAlpha;
124
125 /**
126 * Whether alpha is premultiplied.
127 */
128 protected boolean isAlphaPremultiplied;
129
130
131 /**
132 * Constructs a <code>ComponentColorModel</code> from the specified
133 * parameters. Color components will be in the specified <code>ColorSpace</code>
134 * . <code>hasAlpha</code> indicates whether alpha information is present. If
135 * <code>hasAlpha</code> is true, then the boolean <code>isAlphaPremultiplied</code>
136 * specifies how to interpret color and alpha samples in pixel values. If the
137 * boolean is <code>true</code>, color samples are assumed to have been
138 * multiplied by the alpha sample. The <code>transparency</code> specifies
139 * what alpha values can be represented by this color model. The <code>transferType</code>
140 * is the type of primitive array used to represent pixel values.
141 *
142 * @param colorSpace The <code>ColorSpace</code> associated
143 * with this color model.
144 * @param hasAlpha If true, this color model supports
145 * alpha.
146 * @param isAlphaPremultiplied If true, alpha is premultiplied.
147 * @param transparency Specifies what alpha values can be
148 * represented by this color model.
149 * @param transferType Specifies the type of primitive array
150 * used to represent pixel values, one of DataBuffer.TYPE_FLOAT or
151 * TYPE_DOUBLE.
152 * @throws IllegalArgumentException If the transfer type is not
153 * DataBuffer.TYPE_FLOAT or TYPE_DOUBLE.
154 * @see java.awt.color.ColorSpace
155 * @see java.awt.Transparency
156 */
157 public FloatDoubleColorModel(ColorSpace colorSpace,
158 boolean hasAlpha,
159 boolean isAlphaPremultiplied,
160 int transparency,
161 int transferType) {
162 super(colorSpace, bitsHelper(transferType, colorSpace, hasAlpha),
163 hasAlpha, isAlphaPremultiplied,
164 transparency,
165 transferType);
166
167 if (transferType != DataBuffer.TYPE_FLOAT &&
168 transferType != DataBuffer.TYPE_DOUBLE) {
169 throw new IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel0"));
170 }
171
172 this.colorSpace = colorSpace;
173 this.colorSpaceType = colorSpace.getType();
174 this.numComponents =
175 this.numColorComponents = colorSpace.getNumComponents();
176 if (hasAlpha) {
177 ++numComponents;
178 }
179 this.transparency = transparency;
180 this.hasAlpha = hasAlpha;
181 this.isAlphaPremultiplied = isAlphaPremultiplied;
182 }
183
184
185 private static int[] bitsHelper(int transferType,
186 ColorSpace colorSpace,
187 boolean hasAlpha) {
188 int numBits = (transferType == DataBuffer.TYPE_FLOAT) ? 32 : 64;
189 int numComponents = colorSpace.getNumComponents();
190 if (hasAlpha) {
191 ++numComponents;
192 }
193 int[] bits = new int[numComponents];
194 for (int i = 0; i < numComponents; i++) {
195 bits[i] = numBits;
196 }
197
198 return bits;
199 }
200
201
202 /**
203 * Throws an <code>IllegalArgumentException</code>, since pixel values for
204 * this <code>ColorModel</code> are not conveniently representable as a
205 * single <code>int</code>.
206 *
207 * @param pixel Description of Parameter
208 * @return The Red value
209 */
210 public int getRed(int pixel) {
211 throw new IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel1"));
212 }
213
214
215 /**
216 * Throws an <code>IllegalArgumentException</code>, since pixel values for
217 * this <code>ColorModel</code> are not conveniently representable as a
218 * single <code>int</code>.
219 *
220 * @param pixel Description of Parameter
221 * @return The Green value
222 */
223 public int getGreen(int pixel) {
224 throw new IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel2"));
225 }
226
227
228 /**
229 * Throws an <code>IllegalArgumentException</code>, since pixel values for
230 * this <code>ColorModel</code> are not conveniently representable as a
231 * single <code>int</code>.
232 *
233 * @param pixel Description of Parameter
234 * @return The Blue value
235 */
236 public int getBlue(int pixel) {
237 throw new IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel3"));
238 }
239
240
241 /**
242 * Throws an <code>IllegalArgumentException</code>, since pixel values for
243 * this <code>ColorModel</code> are not conveniently representable as a
244 * single <code>int</code>.
245 *
246 * @param pixel Description of Parameter
247 * @return The Alpha value
248 */
249 public int getAlpha(int pixel) {
250 throw new IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel4"));
251 }
252
253
254 /**
255 * Throws an <code>IllegalArgumentException</code>, since pixel values for
256 * this <code>ColorModel</code> are not conveniently representable as a
257 * single <code>int</code>.
258 *
259 * @param pixel Description of Parameter
260 * @return The RGB value
261 */
262 public int getRGB(int pixel) {
263 throw new IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel5"));
264 }
265
266
267 /**
268 * Returns the red color component for the specified pixel, scaled from 0 to
269 * 255 in the default RGB <code>ColorSpace</code>, sRGB. A color conversion
270 * is done if necessary. The <code>pixel</code> value is specified by an
271 * array of data elements of type <code>transferType</code> passed in as an
272 * object reference. The returned value will be a non pre-multiplied value.
273 * If the alpha is premultiplied, this method divides it out before returning
274 * the value (if the alpha value is 0, the red value will be 0).
275 *
276 * @param inData The pixel from which to get the
277 * red color component, specified by an array of data elements of type
278 * <code>transferType</code>.
279 * @return The red color component for the
280 * specified pixel, as an int.
281 * @throws ClassCastException If <code>inData</code> is not a
282 * primitive array of type <code>transferType</code>.
283 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
284 * large enough to hold a pixel value for this <code>ColorModel</code>.
285 */
286 public int getRed(Object inData) {
287 return getSample(inData, 0);
288 }
289
290
291 /**
292 * Returns the green color component for the specified pixel, scaled from 0
293 * to 255 in the default RGB <code>ColorSpace</code>, sRGB. A color
294 * conversion is done if necessary. The <code>pixel</code> value is specified
295 * by an array of data elements of type <code>transferType</code> passed in
296 * as an object reference. The returned value will be a non pre-multiplied
297 * value. If the alpha is premultiplied, this method divides it out before
298 * returning the value (if the alpha value is 0, the green value will be 0).
299 *
300 * @param inData The pixel from which to get the
301 * green color component, specified by an array of data elements of type
302 * <code>transferType</code>.
303 * @return The green color component for the
304 * specified pixel, as an int.
305 * @throws ClassCastException If <code>inData</code> is not a
306 * primitive array of type <code>transferType</code>.
307 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
308 * large enough to hold a pixel value for this <code>ColorModel</code>.
309 */
310 public int getGreen(Object inData) {
311 return getSample(inData, 1);
312 }
313
314
315 /**
316 * Returns the blue color component for the specified pixel, scaled from 0 to
317 * 255 in the default RGB <code>ColorSpace</code>, sRGB. A color conversion
318 * is done if necessary. The <code>pixel</code> value is specified by an
319 * array of data elements of type <code>transferType</code> passed in as an
320 * object reference. The returned value will be a non pre-multiplied value.
321 * If the alpha is premultiplied, this method divides it out before returning
322 * the value (if the alpha value is 0, the blue value will be 0).
323 *
324 * @param inData The pixel from which to get the
325 * blue color component, specified by an array of data elements of type
326 * <code>transferType</code>.
327 * @return The blue color component for the
328 * specified pixel, as an int.
329 * @throws ClassCastException If <code>inData</code> is not a
330 * primitive array of type <code>transferType</code>.
331 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
332 * large enough to hold a pixel value for this <code>ColorModel</code>.
333 */
334 public int getBlue(Object inData) {
335 return getSample(inData, 2);
336 }
337
338
339 /**
340 * Returns the alpha component for the specified pixel, scaled from 0 to 255.
341 * The pixel value is specified by an array of data elements of type <code>transferType</code>
342 * passed in as an object reference. If the <code>ColorModel</code> does not
343 * have alpha, 255 is returned.
344 *
345 * @param inData The pixel from which to get the
346 * alpha component, specified by an array of data elements of type <code>transferType</code>
347 * .
348 * @return The alpha component for the
349 * specified pixel, as an int.
350 * @throws IllegalArgumentException if <code>inData</code> is <code>null</code>
351 * and the <code>colorModel</code> has alpha.
352 * @throws ClassCastException If <code>inData</code> is not a
353 * primitive array of type <code>transferType</code> and the <code>ColorModel</code>
354 * has alpha.
355 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
356 * large enough to hold a pixel value for this <code>ColorModel</code>
357 * and the <code>ColorModel</code> has alpha.
358 */
359 public int getAlpha(Object inData) {
360 if (inData == null) {
361 throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
362 }
363
364 if (hasAlpha == false) {
365 return 255;
366 }
367
368 if (transferType == DataBuffer.TYPE_FLOAT) {
369 float[] fdata = (float[]) inData;
370 return (int) (fdata[numColorComponents] * 255.0F);
371 }
372 else {
373 double[] ddata = (double[]) inData;
374 return (int) (ddata[numColorComponents] * 255.0);
375 }
376 }
377
378
379 /**
380 * Returns the color/alpha components for the specified pixel in the default
381 * RGB color model format. A color conversion is done if necessary. The pixel
382 * value is specified by an array of data elements of type <code>transferType</code>
383 * passed in as an object reference. The returned value is in a non
384 * pre-multiplied format. If the alpha is premultiplied, this method divides
385 * it out of the color components (if the alpha value is 0, the color values
386 * will be 0).
387 *
388 * @param inData The pixel from which to get the
389 * color/alpha components, specified by an array of data elements of type
390 * <code>transferType</code>.
391 * @return The color/alpha components for the
392 * specified pixel, as an int.
393 * @throws ClassCastException If <code>inData</code> is not a
394 * primitive array of type <code>transferType</code>.
395 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not
396 * large enough to hold a pixel value for this <code>ColorModel</code>.
397 */
398 public int getRGB(Object inData) {
399 boolean needAlpha = (hasAlpha && isAlphaPremultiplied);
400 int alpha = 255;
401 int red;
402 int green;
403 int blue;
404
405 if (colorSpace.isCS_sRGB()) {
406 if (transferType == DataBuffer.TYPE_FLOAT) {
407 float[] fdata = (float[]) inData;
408 float fred = fdata[0];
409 float fgreen = fdata[1];
410 float fblue = fdata[2];
411 float fscale = 255.0F;
412 if (needAlpha) {
413 float falpha = fdata[3];
414 fscale /= falpha;
415 alpha = clamp(255.0F * falpha);
416 }
417
418 red = clamp(fred * fscale);
419 green = clamp(fgreen * fscale);
420 blue = clamp(fblue * fscale);
421 }
422 else {
423 double[] ddata = (double[]) inData;
424 double dred = ddata[0];
425 double dgreen = ddata[1];
426 double dblue = ddata[2];
427 double dscale = 255.0;
428 if (needAlpha) {
429 double dalpha = ddata[3];
430 dscale /= dalpha;
431 alpha = clamp(255.0 * dalpha);
432 }
433
434 red = clamp(dred * dscale);
435 green = clamp(dgreen * dscale);
436 blue = clamp(dblue * dscale);
437 }
438 }
439 else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
440 if (transferType == DataBuffer.TYPE_FLOAT) {
441 float[] fdata = (float[]) inData;
442 float fgray = fdata[0];
443 if (needAlpha) {
444 float falp = fdata[1];
445 red = green = blue = clamp(fgray * 255.0F / falp);
446 alpha = clamp(255.0F * falp);
447 }
448 else {
449 red = green = blue = clamp(fgray * 255.0F);
450 }
451 }
452 else {
453 double[] ddata = (double[]) inData;
454 double dgray = ddata[0];
455 if (needAlpha) {
456 double dalp = ddata[1];
457 red = green = blue = clamp(dgray * 255.0 / dalp);
458 alpha = clamp(255.0 * dalp);
459 }
460 else {
461 red = green = blue = clamp(dgray * 255.0);
462 }
463 }
464 }
465 else {
466 // Not Gray or sRGB
467 float[] norm;
468 float[] rgb;
469 if (transferType == DataBuffer.TYPE_FLOAT) {
470 float[] fdata = (float[]) inData;
471 if (needAlpha) {
472 float falp = fdata[numColorComponents];
473 float invfalp = 1.0F / falp;
474 norm = new float[numColorComponents];
475 for (int i = 0; i < numColorComponents; i++) {
476 norm[i] = fdata[i] * invfalp;
477 }
478 alpha = clamp(255.0F * falp);
479 }
480 else {
481 norm = fdata;
482 }
483 }
484 else {
485 double[] ddata = (double[]) inData;
486 norm = new float[numColorComponents];
487 if (needAlpha) {
488 double dalp = ddata[numColorComponents];
489 double invdalp = 1.0 / dalp;
490 for (int i = 0; i < numColorComponents; i++) {
491 norm[i] = (float) (ddata[i] * invdalp);
492 }
493 alpha = clamp(255.0 * dalp);
494 }
495 else {
496 for (int i = 0; i < numColorComponents; i++) {
497 norm[i] = (float) ddata[i];
498 }
499 }
500 }
501
502 // Perform color conversion
503 rgb = colorSpace.toRGB(norm);
504
505 red = clamp(rgb[0] * 255.0F);
506 green = clamp(rgb[1] * 255.0F);
507 blue = clamp(rgb[2] * 255.0F);
508 }
509
510 return (alpha << 24) | (red << 16) | (green << 8) | blue;
511 }
512
513
514 /**
515 * Returns a data element array representation of a pixel in this <code>ColorModel</code>
516 * , given an integer pixel representation in the default RGB color model.
517 * This array can then be passed to the <code>setDataElements</code> method
518 * of a <code>WritableRaster</code> object. If the <code>pixel</code>
519 * parameter is null, a new array is allocated. If the colorSpaceType is of
520 * TYPE_GRAY then the rgb components are converted to gray using appropriate
521 * weights
522 *
523 * @param rgb An ARGB value packed into an int.
524 * @param pixel The float or double array
525 * representation of the pixel.
526 * @return The DataElements value
527 * @throws ClassCastException If <code>pixel</code> is not null
528 * and is not a primitive array of type <code>transferType</code>.
529 * @throws ArrayIndexOutOfBoundsException If <code>pixel</code> is not large
530 * enough to hold a pixel value for this <code>ColorModel</code>.
531 */
532 public Object getDataElements(int rgb, Object pixel) {
533 if (transferType == DataBuffer.TYPE_FLOAT) {
534 float[] floatPixel;
535
536 if (pixel == null) {
537 floatPixel = new float[numComponents];
538 }
539 else {
540 if (!(pixel instanceof float[])) {
541 throw new ClassCastException(JaiI18N.getString("FloatDoubleColorModel7"));
542 }
543 floatPixel = (float[]) pixel;
544 if (floatPixel.length < numComponents) {
545 throw new ArrayIndexOutOfBoundsException(JaiI18N.getString("FloatDoubleColorModel8"));
546 }
547 }
548
549 float inv255 = 1.0F / 255.0F;
550 if (colorSpace.isCS_sRGB()) {
551 int alp = (rgb >> 24) & 0xff;
552 int red = (rgb >> 16) & 0xff;
553 int grn = (rgb >> 8) & 0xff;
554 int blu = (rgb) & 0xff;
555 float norm = inv255;
556 if (isAlphaPremultiplied) {
557 norm *= alp;
558 }
559 floatPixel[0] = red * norm;
560 floatPixel[1] = grn * norm;
561 floatPixel[2] = blu * norm;
562 if (hasAlpha) {
563 floatPixel[3] = alp * inv255;
564 }
565 }
566 else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
567 float gray = ((((rgb >> 16) & 0xff) * (.299F * inv255)) +
568 (((rgb >> 8) & 0xff) * (.587F * inv255)) +
569 (((rgb) & 0xff) * (.114F * inv255)));
570
571 floatPixel[0] = gray;
572
573 if (hasAlpha) {
574 int alpha = (rgb >> 24) & 0xff;
575 floatPixel[1] = alpha * inv255;
576 }
577 }
578 else {
579 // Need to convert the color
580 float[] norm = new float[3];
581 norm[0] = ((rgb >> 16) & 0xff) * inv255;
582 norm[1] = ((rgb >> 8) & 0xff) * inv255;
583 norm[2] = ((rgb) & 0xff) * inv255;
584
585 norm = colorSpace.fromRGB(norm);
586 for (int i = 0; i < numColorComponents; i++) {
587 floatPixel[i] = norm[i];
588 }
589 if (hasAlpha) {
590 int alpha = (rgb >> 24) & 0xff;
591 floatPixel[numColorComponents] = alpha * inv255;
592 }
593 }
594
595 return floatPixel;
596 }
597 else {
598 // transferType == DataBuffer.TYPE_DOUBLE
599 double[] doublePixel;
600
601 if (pixel == null) {
602 doublePixel = new double[numComponents];
603 }
604 else {
605 if (!(pixel instanceof double[])) {
606 throw new ClassCastException(JaiI18N.getString("FloatDoubleColorModel7"));
607 }
608 doublePixel = (double[]) pixel;
609 if (doublePixel.length < numComponents) {
610 throw new ArrayIndexOutOfBoundsException(JaiI18N.getString("FloatDoubleColorModel8"));
611 }
612 }
613
614 double inv255 = 1.0 / 255.0;
615 if (colorSpace.isCS_sRGB()) {
616 int alp = (rgb >> 24) & 0xff;
617 int red = (rgb >> 16) & 0xff;
618 int grn = (rgb >> 8) & 0xff;
619 int blu = (rgb) & 0xff;
620 double norm = inv255;
621 if (isAlphaPremultiplied) {
622 norm *= alp;
623 }
624 doublePixel[0] = red * norm;
625 doublePixel[1] = grn * norm;
626 doublePixel[2] = blu * norm;
627 if (hasAlpha) {
628 doublePixel[3] = alp * inv255;
629 }
630 }
631 else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
632 double gray = ((((rgb >> 16) & 0xff) * (.299 * inv255)) +
633 (((rgb >> 8) & 0xff) * (.587 * inv255)) +
634 (((rgb) & 0xff) * (.114 * inv255)));
635
636 doublePixel[0] = gray;
637
638 if (hasAlpha) {
639 int alpha = (rgb >> 24) & 0xff;
640 doublePixel[1] = alpha * inv255;
641 }
642 }
643 else {
644 float inv255F = 1.0F / 255.0F;
645
646 // Need to convert the color, need data in float form
647 float[] norm = new float[3];
648 norm[0] = ((rgb >> 16) & 0xff) * inv255F;
649 norm[1] = ((rgb >> 8) & 0xff) * inv255F;
650 norm[2] = ((rgb) & 0xff) * inv255F;
651
652 norm = colorSpace.fromRGB(norm);
653 for (int i = 0; i < numColorComponents; i++) {
654 doublePixel[i] = (double) norm[i];
655 }
656 if (hasAlpha) {
657 int alpha = (rgb >> 24) & 0xff;
658 doublePixel[numColorComponents] = alpha * inv255;
659 }
660 }
661
662 return doublePixel;
663 }
664 }
665
666
667 /**
668 * Throws an <code>IllegalArgumentException</code>, since pixel values for
669 * this <code>ColorModel</code> are not conveniently representable as a
670 * single <code>int</code>.
671 *
672 * @param pixel Description of Parameter
673 * @param components Description of Parameter
674 * @param offset Description of Parameter
675 * @return The Components value
676 */
677 public int[] getComponents(int pixel, int[] components, int offset) {
678 throw new
679 IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel9"));
680 }
681
682
683 /**
684 * Throws an <code>IllegalArgumentException</code> since the pixel values
685 * cannot be placed into an <code>int</code> array.
686 *
687 * @param pixel Description of Parameter
688 * @param components Description of Parameter
689 * @param offset Description of Parameter
690 * @return The Components value
691 */
692 public int[] getComponents(Object pixel, int[] components, int offset) {
693 throw new
694 IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel9"));
695 }
696
697
698 /**
699 * Throws an <code>IllegalArgumentException</code>, since pixel values for
700 * this <code>ColorModel</code> are not conveniently representable as a
701 * single <code>int</code>.
702 *
703 * @param components Description of Parameter
704 * @param offset Description of Parameter
705 * @return The DataElement value
706 */
707 public int getDataElement(int[] components, int offset) {
708 throw new
709 IllegalArgumentException(JaiI18N.getString("FloatDoubleColorModel9"));
710 }
711
712
713 /**
714 * Returns a data element array representation of a pixel in this <code>ColorModel</code>
715 * , given an array of unnormalized color/alpha components. This array can
716 * then be passed to the <code>setDataElements</code> method of a <code>WritableRaster</code>
717 * object.
718 *
719 * @param components An array of unnormalized
720 * color/alpha components.
721 * @param offset The integer offset into the <code>components</code>
722 * array.
723 * @param obj The object in which to store the
724 * data element array representation of the pixel. If <code>obj</code>
725 * variable is null, a new array is allocated. If <code>obj</code> is not
726 * null, it must be a primitive array of type <code>transferType</code>.
727 * An <code>ArrayIndexOutOfBoundsException</code> is thrown if <code>obj</code>
728 * is not large enough to hold a pixel value for this <code>ColorModel</code>
729 * .
730 * @return The data element array
731 * representation of a pixel in this <code>ColorModel</code>.
732 * @throws IllegalArgumentException If the components array is not
733 * large enough to hold all the color and alpha components (starting at
734 * offset).
735 * @throws ClassCastException If <code>obj</code> is not null
736 * and is not a primitive array of type <code>transferType</code>.
737 * @throws ArrayIndexOutOfBoundsException If <code>obj</code> is not large
738 * enough to hold a pixel value for this <code>ColorModel</code>.
739 */
740 public Object getDataElements(int[] components, int offset, Object obj) {
741 if ((components.length - offset) < numComponents) {
742 throw new IllegalArgumentException(numComponents + " " +
743 JaiI18N.getString("FloatDoubleColorModel10"));
744 }
745 if (transferType == DataBuffer.TYPE_FLOAT) {
746 float[] pixel;
747 if (obj == null) {
748 pixel = new float[components.length];
749 }
750 else {
751 pixel = (float[]) obj;
752 }
753 for (int i = 0; i < numComponents; i++) {
754 pixel[i] = (float) (components[offset + i]);
755 }
756
757 return pixel;
758 }
759 else {
760 double[] pixel;
761 if (obj == null) {
762 pixel = new double[components.length];
763 }
764 else {
765 pixel = (double[]) obj;
766 }
767 for (int i = 0; i < numComponents; i++) {
768 pixel[i] = (double) (components[offset + i]);
769 }
770
771 return pixel;
772 }
773 }
774
775
776 /**
777 * Returns <code>true</code> if the supplied <code>Raster</code>'s <code>SampleModel</code>
778 * is compatible with this <code>FloatDoubleColorModel</code>.
779 *
780 * @param raster a <code>Raster</code>to be checked for compatibility.
781 * @return The CompatibleRaster value
782 */
783 public boolean isCompatibleRaster(Raster raster) {
784 SampleModel sm = raster.getSampleModel();
785 return isCompatibleSampleModel(sm);
786 }
787
788
789 /**
790 * Checks whether or not the specified <code>SampleModel</code> is compatible
791 * with this <code>ColorModel</code>. A <code>SampleModel</code> is
792 * compatible if it is an instance of <code>ComponentSampleModel</code>, has
793 * the sample number of bands as the total number of components (including
794 * alpha) in the <code>ColorSpace</code> used by this <code>ColorModel</code>
795 * , and has the same data type (float or double) as this <code>ColorModel</code>
796 * .
797 *
798 * @param sm The <code>SampleModel</code> to test for compatibility.
799 * @return <code>true</code> if the <code>SampleModel</code> is compatible
800 * with this <code>ColorModel</code>, <code>false</code> if it is not.
801 * @see java.awt.image.SampleModel
802 * @see java.awt.image.ComponentSampleModel
803 */
804 public boolean isCompatibleSampleModel(SampleModel sm) {
805 if (sm instanceof ComponentSampleModel) {
806 if (sm.getNumBands() != getNumComponents()) {
807 return false;
808 }
809 if (sm.getDataType() != transferType) {
810 return false;
811 }
812 return true;
813 }
814 else {
815 return false;
816 }
817 }
818
819
820 /**
821 * Forces the <code>raster</code> data to match the state specified in the
822 * <code>isAlphaPremultiplied</code> variable, assuming the data is currently
823 * correctly described by this <code>ColorModel</code>. It may multiply or
824 * divide the color <code>raster</code> data by alpha, or do nothing if the
825 * data is in the correct state. If the data needs to be coerced, this method
826 * also returns an instance of <code>FloatDoubleColorModel</code> with the
827 * <code>isAlphaPremultiplied</code> flag set appropriately.
828 *
829 * @param raster Description of Parameter
830 * @param isAlphaPremultiplied Description of Parameter
831 * @return Description of the Returned Value
832 * @throws IllegalArgumentException if transfer type of <code>raster</code>
833 * is not the same as that of this <code>FloatDoubleColorModel</code>.
834 */
835 public ColorModel coerceData(WritableRaster raster,
836 boolean isAlphaPremultiplied) {
837 if ((hasAlpha == false) ||
838 (this.isAlphaPremultiplied == isAlphaPremultiplied)) {
839 // Nothing to do
840 return this;
841 }
842
843 int w = raster.getWidth();
844 int h = raster.getHeight();
845 int aIdx = raster.getNumBands() - 1;
846 int rminX = raster.getMinX();
847 int rY = raster.getMinY();
848 int rX;
849
850 if (raster.getTransferType() != transferType) {
851 throw new IllegalArgumentException(
852 JaiI18N.getString("FloatDoubleColorModel6"));
853 }
854
855 if (isAlphaPremultiplied) {
856 switch (transferType) {
857 case DataBuffer.TYPE_FLOAT:
858 {
859 float pixel[] = null;
860 for (int y = 0; y < h; y++, rY++) {
861 rX = rminX;
862 for (int x = 0; x < w; x++, rX++) {
863 pixel = (float[]) raster.getDataElements(rX, rY,
864 pixel);
865 float fAlpha = pixel[aIdx];
866 if (fAlpha != 0) {
867 for (int c = 0; c < aIdx; c++) {
868 pixel[c] *= fAlpha;
869 }
870 raster.setDataElements(rX, rY, pixel);
871 }
872 }
873 }
874 }
875 break;
876 case DataBuffer.TYPE_DOUBLE:
877 {
878 double pixel[] = null;
879 for (int y = 0; y < h; y++, rY++) {
880 rX = rminX;
881 for (int x = 0; x < w; x++, rX++) {
882 pixel = (double[]) raster.getDataElements(rX, rY,
883 pixel);
884 double dAlpha = pixel[aIdx];
885 if (dAlpha != 0) {
886 for (int c = 0; c < aIdx; c++) {
887 pixel[c] *= dAlpha;
888 }
889 raster.setDataElements(rX, rY, pixel);
890 }
891 }
892 }
893 }
894 break;
895 default:
896 throw new RuntimeException(JaiI18N.getString("FloatDoubleColorModel0"));
897 }
898
899 if (isAlphaPremultiplied) {
900
901 }
902 }
903 else {
904 // We are premultiplied and want to divide it out
905 switch (transferType) {
906 case DataBuffer.TYPE_FLOAT:
907 {
908 for (int y = 0; y < h; y++, rY++) {
909 rX = rminX;
910 for (int x = 0; x < w; x++, rX++) {
911 float pixel[] = null;
912 pixel = (float[]) raster.getDataElements(rX, rY,
913 pixel);
914 float fAlpha = pixel[aIdx];
915 if (fAlpha != 0) {
916 float invFAlpha = 1.0F / fAlpha;
917 for (int c = 0; c < aIdx; c++) {
918 pixel[c] *= invFAlpha;
919 }
920 }
921 raster.setDataElements(rX, rY, pixel);
922 }
923 }
924 }
925 break;
926 case DataBuffer.TYPE_DOUBLE:
927 {
928 for (int y = 0; y < h; y++, rY++) {
929 rX = rminX;
930 for (int x = 0; x < w; x++, rX++) {
931 double pixel[] = null;
932 pixel = (double[]) raster.getDataElements(rX, rY,
933 pixel);
934 double dAlpha = pixel[aIdx];
935 if (dAlpha != 0) {
936 double invDAlpha = 1.0 / dAlpha;
937 for (int c = 0; c < aIdx; c++) {
938 pixel[c] *= invDAlpha;
939 }
940 }
941 raster.setDataElements(rX, rY, pixel);
942 }
943 }
944 }
945 break;
946 default:
947 throw new RuntimeException(JaiI18N.getString("FloatDoubleColorModel0"));
948 }
949 }
950
951 // Return a new color model
952 return new FloatDoubleColorModel(colorSpace, hasAlpha,
953 isAlphaPremultiplied, transparency,
954 transferType);
955 }
956
957
958 /**
959 * Creates a <code>WritableRaster</code> with the specified width and height,
960 * that has a data layout (<code>SampleModel</code>) compatible with this
961 * <code>ColorModel</code>. The returned <code>WritableRaster</code>'s <code>SampleModel</code>
962 * will be an instance of <code>ComponentSampleModel</code>.
963 *
964 * @param w The width of the <code>WritableRaster</code>
965 * @param h The height of the <code>WritableRaster</code>
966 * @return A <code>WritableRaster</code> that is compatible with this
967 * <code>ColorModel</code>.
968 * @see java.awt.image.WritableRaster
969 * @see java.awt.image.SampleModel
970 */
971 public WritableRaster createCompatibleWritableRaster(int w, int h) {
972 SampleModel sm = createCompatibleSampleModel(w, h);
973 return RasterFactory.createWritableRaster(sm, new Point(0, 0));
974 }
975
976
977 /**
978 * Creates a <code>SampleModel</code> with the specified width and height
979 * that has a data layout compatible with this <code>ColorModel</code>. The
980 * returned <code>SampleModel</code> will be an instance of <code>ComponentSampleModel</code>
981 * .
982 *
983 * @param w The width of the <code>SampleModel</code>.
984 * @param h The height of the <code>SampleModel</code>.
985 * @return A <code>SampleModel</code> that is compatible with this <code>ColorModel</code>
986 * .
987 * @see java.awt.image.SampleModel
988 * @see java.awt.image.ComponentSampleModel
989 */
990 public SampleModel createCompatibleSampleModel(int w, int h) {
991 int[] bandOffsets = new int[numComponents];
992 for (int i = 0; i < numComponents; i++) {
993 bandOffsets[i] = i;
994 }
995 return new ComponentSampleModelJAI(transferType,
996 w, h,
997 numComponents,
998 w * numComponents,
999 bandOffsets);
1000 }
1001
1002
1003 /**
1004 * Returns a <code>String</code> containing the values of all valid fields.
1005 *
1006 * @return Description of the Returned Value
1007 */
1008 public String toString() {
1009 return "FloatDoubleColorModel: " + super.toString();
1010 }
1011
1012
1013 private int getSample(Object inData, int sample) {
1014 boolean needAlpha = (hasAlpha && isAlphaPremultiplied);
1015 int type = colorSpaceType;
1016
1017 boolean is_sRGB = colorSpace.isCS_sRGB();
1018
1019 if (type == ColorSpace.TYPE_GRAY) {
1020 sample = 0;
1021 is_sRGB = true;
1022 }
1023
1024 if (is_sRGB) {
1025 if (transferType == DataBuffer.TYPE_FLOAT) {
1026 float[] fdata = (float[]) inData;
1027 float fsample = fdata[sample] * 255;
1028 if (needAlpha) {
1029 float falp = fdata[numColorComponents];
1030 if (falp == 0.0) {
1031 return 0;
1032 }
1033 else {
1034 return clamp(fsample / falp);
1035 }
1036 }
1037 else {
1038 return clamp(fsample);
1039 }
1040 }
1041 else {
1042 double[] ddata = (double[]) inData;
1043 double dsample = ddata[sample] * 255.0;
1044 if (needAlpha) {
1045 double dalp = ddata[numColorComponents];
1046 if (dalp == 0.0) {
1047 return 0;
1048 }
1049 else {
1050 return clamp(dsample / dalp);
1051 }
1052 }
1053 else {
1054 return clamp(dsample);
1055 }
1056 }
1057 }
1058
1059 // Not TYPE_GRAY or TYPE_RGB ColorSpace
1060 float[] norm;
1061 float[] rgb;
1062 if (transferType == DataBuffer.TYPE_FLOAT) {
1063 float[] fdata = (float[]) inData;
1064 if (needAlpha) {
1065 float falp = fdata[numColorComponents];
1066 if (falp == 0.0) {
1067 return 0;
1068 }
1069 norm = new float[numColorComponents];
1070 for (int i = 0; i < numColorComponents; i++) {
1071 norm[i] = fdata[i] / falp;
1072 }
1073 rgb = colorSpace.toRGB(norm);
1074 }
1075 else {
1076 rgb = colorSpace.toRGB(fdata);
1077 }
1078 return (int) (rgb[sample] * 255);
1079 }
1080 else {
1081 double[] ddata = (double[]) inData;
1082 norm = new float[numColorComponents];
1083 if (needAlpha) {
1084 double dalp = ddata[numColorComponents];
1085 if (dalp == 0.0) {
1086 return 0;
1087 }
1088 for (int i = 0; i < numColorComponents; i++) {
1089 norm[i] = (float) (ddata[i] / dalp);
1090 }
1091 rgb = colorSpace.toRGB(norm);
1092 }
1093 else {
1094 for (int i = 0; i < numColorComponents; i++) {
1095 norm[i] = (float) ddata[i];
1096 }
1097 rgb = colorSpace.toRGB(norm);
1098 }
1099 return (int) (rgb[sample] * 255);
1100 }
1101 }
1102
1103
1104 private final int clamp(float value) {
1105 // Ensure NaN maps to 0
1106 return (value >= 0.0F) ? ((value > 255.0F) ? 255 : (int) value) : 0;
1107 }
1108
1109
1110 private final int clamp(double value) {
1111 // Ensure NaN maps to 0
1112 return (value >= 0.0) ? ((value > 255.0) ? 255 : (int) value) : 0;
1113 }
1114}