001    /* ColorModel.java --
002       Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006  Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt.image;
040    
041    import gnu.java.awt.Buffers;
042    
043    import java.awt.Point;
044    import java.awt.Transparency;
045    import java.awt.color.ColorSpace;
046    import java.util.Arrays;
047    
048    /**
049     * A color model operates with colors in several formats:
050     *
051     * <ul>
052     * <li>normalized: component samples are in range [0.0, 1.0].</li>
053     *
054     * <li>color model pixel value: all the color component samples for a
055     * sigle pixel packed/encoded in a way natural for the color
056     * model.</li>
057     *
058     * <li>color model pixel int value: only makes sense if the natural
059     * encoding of a single pixel can fit in a single int value.</li>
060     *
061     * <li>array of transferType containing a single pixel: the pixel is
062     * encoded in the natural way of the color model, taking up as many
063     * array elements as needed.</li>
064     *
065     * <li>sRGB pixel int value: a pixel in sRGB color space, encoded in
066     * default 0xAARRGGBB format, assumed not alpha premultiplied.</li>
067     *
068     * <li>single [0, 255] scaled int samples from default sRGB color
069     * space. These are always assumed to be alpha non-premultiplied.</li>
070     *
071     * <li>arrays of unnormalized component samples of single pixel: these
072     * samples are scaled and multiplied according to the color model, but
073     * is otherwise not packed or encoded. Each element of the array is one
074     * separate component sample. The color model only operate on the
075     * components from one pixel at a time, but using offsets, allows
076     * manipulation of arrays that contain the components of more than one
077     * pixel.</li>
078     *
079     * </ul>
080     *
081     * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
082     * @author C. Brian Jones (cbj@gnu.org)
083     */
084    public abstract class ColorModel implements Transparency
085    {
086      protected int pixel_bits;
087      protected int transferType;
088    
089      int[] bits;
090      ColorSpace cspace;
091      int transparency;
092      boolean hasAlpha;
093      boolean isAlphaPremultiplied;
094    
095      /**
096       * The standard color model for the common sRGB.
097       */
098      private static final ColorModel S_RGB_MODEL = new SRGBColorModel();
099    
100      static int[] nArray(int value, int times)
101      {
102        int[] array = new int[times];
103        java.util.Arrays.fill(array, value);
104        return array;
105      }
106    
107      static byte[] nArray(byte value, int times)
108      {
109        byte[] array = new byte[times];
110        java.util.Arrays.fill(array, value);
111        return array;
112      }
113    
114      /**
115       * Constructs the default color model.  The default color model
116       * can be obtained by calling <code>getRGBdefault</code> of this
117       * class.
118       * @param bits the number of bits wide used for bit size of pixel values
119       */
120      public ColorModel(int bits)
121      {
122        this(bits * 4, // total bits, sRGB, four channels
123             nArray(bits, 4), // bits for each channel
124             ColorSpace.getInstance(ColorSpace.CS_sRGB), // sRGB
125             true, // has alpha
126             false, // not premultiplied
127             TRANSLUCENT,
128             Buffers.smallestAppropriateTransferType(bits * 4));
129      }
130    
131      /**
132       * Constructs a ColorModel that translates pixel values to
133       * color/alpha components.
134       *
135       * @exception IllegalArgumentException If the length of the bit array is less
136       * than the number of color or alpha components in this ColorModel, or if the
137       * transparency is not a valid value, or if the sum of the number of bits in
138       * bits is less than 1 or if any of the elements in bits is less than 0.
139       */
140      protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
141                           boolean hasAlpha, boolean isAlphaPremultiplied,
142                           int transparency, int transferType)
143      {
144        int bits_sum = 0;
145        for (int i = 0; i < bits.length; i++)
146          {
147            if (bits [i] < 0)
148              throw new IllegalArgumentException ();
149    
150            bits_sum |= bits [i];
151          }
152    
153        if ((bits.length < cspace.getNumComponents())
154            || (bits_sum < 1))
155          throw new IllegalArgumentException ();
156    
157        this.pixel_bits = pixel_bits;
158        this.bits = bits;
159        this.cspace = cspace;
160        this.hasAlpha = hasAlpha;
161        this.isAlphaPremultiplied = isAlphaPremultiplied;
162        this.transparency = transparency;
163        this.transferType = transferType;
164      }
165    
166      public void finalize()
167      {
168        // Do nothing here.
169      }
170    
171      /**
172       * Returns the default color model which in Sun's case is an instance
173       * of <code>DirectColorModel</code>.
174       */
175      public static ColorModel getRGBdefault()
176      {
177        return S_RGB_MODEL;
178      }
179    
180      public final boolean hasAlpha()
181      {
182        return hasAlpha;
183      }
184    
185      public final boolean isAlphaPremultiplied()
186      {
187        return isAlphaPremultiplied;
188      }
189    
190      /**
191       * Get get number of bits wide used for the bit size of pixel values
192       */
193      public int getPixelSize()
194      {
195        return pixel_bits;
196      }
197    
198      public int getComponentSize(int componentIdx)
199      {
200        return bits[componentIdx];
201      }
202    
203      public int[] getComponentSize()
204      {
205        return bits;
206      }
207    
208      public int getTransparency()
209      {
210        return transparency;
211      }
212    
213      public int getNumComponents()
214      {
215        return getNumColorComponents() + (hasAlpha ? 1 : 0);
216      }
217    
218      public int getNumColorComponents()
219      {
220        return cspace.getNumComponents();
221      }
222    
223      /**
224       * Converts pixel value to sRGB and extract red int sample scaled
225       * to range [0, 255].
226       *
227       * @param pixel pixel value that will be interpreted according to
228       * the color model, (assumed alpha premultiplied if color model says
229       * so.)
230       *
231       * @return red sample scaled to range [0, 255], from default color
232       * space sRGB, alpha non-premultiplied.
233       */
234      public abstract int getRed(int pixel);
235    
236      /**
237       * Converts pixel value to sRGB and extract green int sample
238       * scaled to range [0, 255].
239       *
240       * @see #getRed(int)
241       */
242      public abstract int getGreen(int pixel);
243    
244      /**
245       * Converts pixel value to sRGB and extract blue int sample
246       * scaled to range [0, 255].
247       *
248       * @see #getRed(int)
249       */
250      public abstract int getBlue(int pixel);
251    
252      /**
253       * Extract alpha int sample from pixel value, scaled to [0, 255].
254       *
255       * @param pixel pixel value that will be interpreted according to
256       * the color model.
257       *
258       * @return alpha sample, scaled to range [0, 255].
259       */
260      public abstract int getAlpha(int pixel);
261    
262      /**
263       * Converts a pixel int value of the color space of the color
264       * model to a sRGB pixel int value.
265       *
266       * This method is typically overriden in subclasses to provide a
267       * more efficient implementation.
268       *
269       * @param pixel pixel value that will be interpreted according to
270       * the color model.
271       *
272       * @return a pixel in sRGB color space, encoded in default
273       * 0xAARRGGBB format.  */
274      public int getRGB(int pixel)
275      {
276        return
277          ((getAlpha(pixel) & 0xff) << 24) |
278          ((  getRed(pixel) & 0xff) << 16) |
279          ((getGreen(pixel) & 0xff) <<  8) |
280          (( getBlue(pixel) & 0xff) <<  0);
281      }
282    
283    
284      /**
285       * In this color model we know that the whole pixel value will
286       * always be contained within the first element of the pixel
287       * array.
288       */
289      final int getPixelFromArray(Object inData) {
290        DataBuffer data =
291          Buffers.createBufferFromData(transferType, inData, 1);
292        Object da = Buffers.getData(data);
293    
294        return data.getElem(0);
295      }
296    
297      /**
298       * Converts pixel in the given array to sRGB and extract blue int
299       * sample scaled to range [0-255].
300       *
301       * This method is typically overriden in subclasses to provide a
302       * more efficient implementation.
303       *
304       * @param inData array of transferType containing a single pixel.  The
305       * pixel should be encoded in the natural way of the color model.
306       */
307      public int getRed(Object inData)
308      {
309        return getRed(getPixelFromArray(inData));
310      }
311    
312      /**
313       * @see #getRed(Object)
314       */
315      public int getGreen(Object inData)
316      {
317        return getGreen(getPixelFromArray(inData));
318      }
319    
320      /**
321       * @see #getRed(Object)
322       */
323      public int getBlue(Object inData) {
324        return getBlue(getPixelFromArray(inData));
325      }
326    
327      /**
328       * @see #getRed(Object)
329       */
330      public int getAlpha(Object inData) {
331        return getAlpha(getPixelFromArray(inData));
332      }
333    
334      /**
335       * Converts a pixel in the given array of the color space of the
336       * color model to an sRGB pixel int value.
337       *
338       * <p>This method performs the inverse function of
339       * <code>getDataElements(int rgb, Object pixel)</code>.
340       * I.e. <code>(rgb == cm.getRGB(cm.getDataElements(rgb,
341       * null)))</code>.
342       *
343       * @param inData array of transferType containing a single pixel. The
344       * pixel should be encoded in the natural way of the color model.
345       *
346       * @return a pixel in sRGB color space, encoded in default
347       * 0xAARRGGBB format.
348       *
349       * @see #getDataElements(int, Object)
350       */
351      public int getRGB(Object inData)
352      {
353        return
354          ((getAlpha(inData) & 0xff) << 24) |
355          ((  getRed(inData) & 0xff) << 16) |
356          ((getGreen(inData) & 0xff) <<  8) |
357          (( getBlue(inData) & 0xff) <<  0);
358      }
359    
360      /**
361       * Converts an sRGB pixel int value to an array containing a
362       * single pixel of the color space of the color model.
363       *
364       * <p>This method performs the inverse function of
365       * <code>getRGB(Object inData)</code>.
366       *
367       * Outline of conversion process:
368       *
369       * <ol>
370       *
371       * <li>Convert rgb to normalized [0.0, 1.0] sRGB values.</li>
372       *
373       * <li>Convert to color space components using fromRGB in
374       * ColorSpace.</li>
375       *
376       * <li>If color model has alpha and should be premultiplied,
377       * multiply color space components with alpha value</li>
378       *
379       * <li>Scale the components to the correct number of bits.</li>
380       *
381       * <li>Arrange the components in the output array</li>
382       *
383       * </ol>
384       *
385       * @param rgb The color to be converted to dataElements.  A pixel
386       * in sRGB color space, encoded in default 0xAARRGGBB format,
387       * assumed not alpha premultiplied.
388       *
389       * @param pixel to avoid needless creation of arrays, an array to
390       * use to return the pixel can be given. If null, a suitable array
391       * will be created.
392       *
393       * @return An array of transferType values representing the color,
394       * in the color model format. The color model defines whether the
395       *
396       * @see #getRGB(Object)
397       */
398      public Object getDataElements(int rgb, Object pixel)
399      {
400        // subclasses has to implement this method.
401        throw new UnsupportedOperationException();
402      }
403    
404      /**
405       * Fills an array with the unnormalized component samples from a
406       * pixel value. I.e. decompose the pixel, but not perform any
407       * color conversion.
408       *
409       * This method is typically overriden in subclasses to provide a
410       * more efficient implementation.
411       *
412       * @param pixel pixel value encoded according to the color model.
413       *
414       * @return arrays of unnormalized component samples of single
415       * pixel.  The scale and multiplication state of the samples are
416       * according to the color model. Each component sample is stored
417       * as a separate element in the array.
418       */
419      public int[] getComponents(int pixel, int[] components, int offset)
420      {
421        // subclasses has to implement this method.
422        throw new UnsupportedOperationException();
423      }
424    
425      /**
426       * Fills an array with the unnormalized component samples from an
427       * array of transferType containing a single pixel. I.e. decompose
428       * the pixel, but not perform any color conversion.
429       *
430       * This method is typically overriden in subclasses to provide a
431       * more efficient implementation.
432       *
433       * @param pixel an array of transferType containing a single pixel.  The
434       * pixel should be encoded in the natural way of the color model.  If
435       * this argument is not an array, as expected, a {@link ClassCastException}
436       * will be thrown.
437       * @param components an array that will be filled with the color component
438       * of the pixel.  If this is null, a new array will be allocated
439       * @param offset index into the components array at which the result
440       * will be stored
441       *
442       * @return arrays of unnormalized component samples of single
443       * pixel.  The scale and multiplication state of the samples are
444       * according to the color model. Each component sample is stored
445       * as a separate element in the array.
446       */
447      public int[] getComponents(Object pixel, int[] components, int offset)
448      {
449        // subclasses has to implement this method.
450        throw new UnsupportedOperationException();
451      }
452    
453      /**
454       * Convert normalized components to unnormalized components.
455       */
456      public int[] getUnnormalizedComponents(float[] normComponents,
457                                             int normOffset,
458                                             int[] components,
459                                             int offset)
460      {
461        int numComponents = getNumComponents();
462        if (components == null)
463        {
464          components = new int[offset + numComponents];
465        }
466    
467        for (int i=0; i<numComponents; i++)
468        {
469          float in = normComponents[normOffset++];
470          int out = (int) (in * ((1<<getComponentSize(i)) - 1));
471          components[offset++] = out;
472        }
473        return components;
474      }
475    
476      /**
477       * Convert unnormalized components to normalized components.
478       */
479      public float[] getNormalizedComponents(int[] components,
480                                             int offset,
481                                             float[] normComponents,
482                                             int normOffset)
483      {
484        int numComponents = getNumComponents();
485        if (normComponents == null)
486        {
487          normComponents = new float[normOffset + numComponents];
488        }
489    
490        for (int i=0; i<numComponents; i++)
491        {
492          float in = components[offset++];
493          float out = in / ((1<<getComponentSize(i)) - 1);
494          normComponents[normOffset++] = out;
495        }
496        return normComponents;
497      }
498    
499      /**
500       * Convert unnormalized components to normalized components.
501       *
502       * @since 1.4
503       */
504      public float[] getNormalizedComponents (Object pixel,
505                                              float[] normComponents,
506                                              int normOffset)
507      {
508        int[] components = getComponents(pixel, null, 0);
509        return getNormalizedComponents(components, 0, normComponents, normOffset);
510      }
511    
512      /**
513       * Converts the unnormalized component samples from an array to a
514       * pixel value. I.e. composes the pixel from component samples, but
515       * does not perform any color conversion or scaling of the samples.
516       *
517       * This method performs the inverse function of
518       * <code>getComponents(int pixel, int[] components,
519       *                           int offset)</code>. I.e.
520       *
521       * <code>(pixel == cm.getDataElement(cm.getComponents(pixel, null,
522       * 0), 0))</code>.
523       *
524       * This method is overriden in subclasses since this abstract class throws
525       * UnsupportedOperationException().
526       *
527       * @param components Array of unnormalized component samples of single
528       * pixel.  The scale and multiplication state of the samples are according
529       * to the color model. Each component sample is stored as a separate element
530       * in the array.
531       * @param offset Position of the first value of the pixel in components.
532       *
533       * @return pixel value encoded according to the color model.
534       */
535      public int getDataElement(int[] components, int offset)
536      {
537        // subclasses have to implement this method.
538        throw new UnsupportedOperationException();
539      }
540    
541      /**
542       * Converts the normalized component samples from an array to a pixel
543       * value. I.e. composes the pixel from component samples, but does not
544       * perform any color conversion or scaling of the samples.
545       *
546       * This method is typically overriden in subclasses to provide a
547       * more efficient implementation.  The method provided by this abstract
548       * class converts the components to unnormalized form and returns
549       * getDataElement(int[], int).
550       *
551       * @param components Array of normalized component samples of single pixel.
552       * The scale and multiplication state of the samples are according to the
553       * color model. Each component sample is stored as a separate element in the
554       * array.
555       * @param offset Position of the first value of the pixel in components.
556       *
557       * @return pixel value encoded according to the color model.
558       * @since 1.4
559       */
560      public int getDataElement (float[] components, int offset)
561      {
562        return
563          getDataElement(getUnnormalizedComponents(components, offset, null, 0),
564                         0);
565      }
566    
567      public Object getDataElements(int[] components, int offset, Object obj)
568      {
569        // subclasses have to implement this method.
570        throw new UnsupportedOperationException();
571      }
572    
573      /**
574       * Converts the normalized component samples from an array to an array of
575       * TransferType values. I.e. composes the pixel from component samples, but
576       * does not perform any color conversion or scaling of the samples.
577       *
578       * If obj is null, a new array of TransferType is allocated and returned.
579       * Otherwise the results are stored in obj and obj is returned.  If obj is
580       * not long enough, ArrayIndexOutOfBounds is thrown.  If obj is not an array
581       * of primitives, ClassCastException is thrown.
582       *
583       * This method is typically overriden in subclasses to provide a
584       * more efficient implementation.  The method provided by this abstract
585       * class converts the components to unnormalized form and returns
586       * getDataElement(int[], int, Object).
587       *
588       * @param components Array of normalized component samples of single pixel.
589       * The scale and multiplication state of the samples are according to the
590       * color model. Each component sample is stored as a separate element in the
591       * array.
592       * @param offset Position of the first value of the pixel in components.
593       * @param obj Array of TransferType or null.
594       *
595       * @return pixel value encoded according to the color model.
596       * @throws ArrayIndexOutOfBoundsException
597       * @throws ClassCastException
598       * @since 1.4
599       */
600      public Object getDataElements(float[] components, int offset, Object obj)
601      {
602        return
603          getDataElements(getUnnormalizedComponents(components, offset, null, 0),
604                          0, obj);
605      }
606    
607      public boolean equals(Object obj)
608      {
609        if (!(obj instanceof ColorModel)) return false;
610    
611        ColorModel o = (ColorModel) obj;
612        return
613          (pixel_bits == o.pixel_bits) &&
614          (transferType == o.transferType) &&
615          (transparency == o.transparency) &&
616          (hasAlpha == o.hasAlpha) &&
617          (isAlphaPremultiplied == o.isAlphaPremultiplied) &&
618          Arrays.equals(bits, o.bits) &&
619          (cspace.equals(o.cspace));
620      }
621    
622      public final ColorSpace getColorSpace()
623      {
624        return cspace;
625      }
626    
627      public ColorModel coerceData(WritableRaster raster,
628                                   boolean isAlphaPremultiplied)
629      {
630        // This method should always be overridden, but is not abstract.
631        throw new UnsupportedOperationException();
632      }
633    
634      void coerceDataWorker(WritableRaster raster,
635                            boolean isAlphaPremultiplied)
636      {
637        int w = raster.getWidth();
638        int h = raster.getHeight();
639        int x = raster.getMinX();
640        int y = raster.getMinY();
641        int size = w * h;
642        int numColors = getNumColorComponents();
643        int numComponents = getNumComponents();
644        int alphaScale = (1 << getComponentSize(numColors)) - 1;
645        double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
646    
647        for (int i = 0; i < size; i++)
648          {
649            double alpha = pixels[i * numComponents + numColors] / alphaScale;
650            for (int c = 0; c < numColors; c++)
651              {
652                int offset = i * numComponents + c;
653                if (isAlphaPremultiplied)
654                  pixels[offset] = Math.round(pixels[offset] * alpha);
655                else
656                  pixels[offset] = Math.round(pixels[offset] / alpha);
657              }
658          }
659    
660        raster.setPixels(0, 0, w, h, pixels);
661      }
662    
663      /**
664       * Checks if the given raster has a compatible data-layout (SampleModel).
665       * @param raster The Raster to test.
666       * @return true if raster is compatible.
667       */
668      public boolean isCompatibleRaster(Raster raster)
669      {
670        SampleModel sampleModel = raster.getSampleModel();
671        return isCompatibleSampleModel(sampleModel);
672      }
673    
674      // Typically overridden
675      public WritableRaster createCompatibleWritableRaster(int w, int h)
676      {
677        return new WritableRaster(createCompatibleSampleModel(w, h),
678                                  new Point(0, 0));
679      }
680    
681      // Typically overridden
682      public SampleModel createCompatibleSampleModel(int w, int h)
683      {
684        throw new UnsupportedOperationException();
685      }
686    
687      // Typically overridden
688      public boolean isCompatibleSampleModel(SampleModel sm)
689      {
690        return sm.getTransferType() == transferType;
691      }
692    
693      public final int getTransferType ()
694      {
695        return transferType;
696      }
697    
698      /**
699       * Subclasses must override this method if it is possible for the
700       * color model to have an alpha channel.
701       *
702       * @return null, as per JDK 1.3 doc. Subclasses will only return
703       * null if no alpha raster exists.
704       */
705      public WritableRaster getAlphaRaster(WritableRaster raster)
706      {
707        return null;
708    
709        /* It is a mystery to me why we couldn't use the following code...
710    
711    
712           if (!hasAlpha()) return null;
713    
714           SampleModel sm = raster.getSampleModel();
715           int[] alphaBand = { sm.getNumBands() - 1 };
716           SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
717           DataBuffer buffer = raster.getDataBuffer();
718           Point origin = new Point(0, 0);
719           return Raster.createWritableRaster(alphaModel, buffer, origin);
720    
721    
722           ...here, and avoided overriding the method in subclasses,
723           but the Sun docs state that this method always will return
724           null, and that overriding is required. Oh, well.
725        */
726      }
727    
728      String stringParam()
729      {
730        return "pixel_bits=" + pixel_bits +
731          ", cspace=" + cspace +
732          ", transferType=" + transferType +
733          ", transparency=" + transparency +
734          ", hasAlpha=" + hasAlpha +
735          ", isAlphaPremultiplied=" + isAlphaPremultiplied;
736      }
737    
738      public String toString()
739      {
740        return getClass().getName() + "[" + stringParam() + "]";
741      }
742    
743      /**
744       * A color model optimized for standard sRGB.
745       */
746      private static class SRGBColorModel
747        extends DirectColorModel
748      {
749    
750        SRGBColorModel()
751        {
752          super(32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
753        }
754    
755        public int getAlpha(Object inData)
756        {
757          return ((((int[]) inData)[0]) >> 24) & 0xFF;
758        }
759    
760        public int getBlue(Object inData)
761        {
762          return ((((int[]) inData)[0])) & 0xFF;
763        }
764    
765        public int getGreen(Object inData)
766        {
767          return ((((int[]) inData)[0]) >>  8) & 0xFF;
768        }
769    
770        public int getRed(Object inData)
771        {
772          return ((((int[]) inData)[0]) >> 16) & 0xFF;
773        }
774    
775        public int getRGB(Object inData)
776        {
777          return ((int[]) inData)[0];
778        }
779    
780        public Object getDataElements(int rgb, Object pixel)
781        {
782          if(pixel == null)
783            {
784              pixel = new int[]{rgb};
785            }
786          else
787            {
788              ((int[]) pixel)[0] = rgb;
789            }
790    
791          return pixel;
792        }
793      }
794    }