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

Quick Search    Search Deep

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}