Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/ydp/jai/FloatDoubleColorModel.java


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