OSDN Git Service

config:
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / image / ColorModel.java
1 /* Copyright (C) 2000  Free Software Foundation
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8
9 package java.awt.image;
10
11 import java.awt.Point;
12 import java.awt.Transparency;
13 import java.awt.color.ColorSpace;
14 import gnu.gcj.awt.Buffers;
15
16 /**
17  * A color model operates with colors in several formats:
18  *
19  * <ul>
20  * <li>normalized: component samples are in range [0.0, 1.0].</li>
21  *
22  * <li>color model pixel value: all the color component samples for a
23  * sigle pixel packed/encoded in a way natural for the color
24  * model.</li>
25  *
26  * <li>color model pixel int value: only makes sense if the natural
27  * encoding of a single pixel can fit in a single int value.</li>
28  *
29  * <li>array of transferType containing a single pixel: the pixel is
30  * encoded in the natural way of the color model, taking up as many
31  * array elements as needed.</li>
32  *
33  * <li>sRGB pixel int value: a pixel in sRGB color space, encoded in
34  * default 0xAARRGGBB format, assumed not alpha premultiplied.</li>
35  * 
36  * <li>single [0, 255] scaled int samples from default sRGB color
37  * space. These are always assumed to be alpha non-premultiplied.</li>
38  *
39  * <li>arrays of unnormalized component samples of single pixel: these
40  * samples are scaled and multiplied according to the color model, but
41  * is otherwise not packed or encoded. Each element of the array is one
42  * separate component sample. The color model only operate on the
43  * components from one pixel at a time, but using offsets, allows
44  * manipulation of arrays that contain the components of more than one
45  * pixel.</li>
46  *
47  * </ul>
48  *
49  * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
50  */
51
52 public abstract class ColorModel implements Transparency
53 {
54   protected int pixel_bits;
55   protected int transferType;
56
57   int[] bits;
58   ColorSpace cspace;
59   int transparency;
60   boolean hasAlpha;
61   boolean isAlphaPremultiplied;
62     
63   static int[] nArray(int value, int times)
64   {
65     int[] array = new int[times];
66     java.util.Arrays.fill(array, value);
67     return array;
68   }
69
70   static byte[] nArray(byte value, int times)
71   {
72     byte[] array = new byte[times];
73     java.util.Arrays.fill(array, value);
74     return array;
75   } 
76
77   public ColorModel(int bits)
78   {
79     this(bits * 4, // total bits, sRGB, four channels
80          nArray(bits, 4), // bits for each channel
81          null, // FIXME: should be sRGB
82          true, // has alpha
83          false, // not premultiplied
84          TRANSLUCENT,
85          Buffers.smallestAppropriateTransferType(bits * 4));
86   }
87
88   protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
89                        boolean hasAlpha, boolean isAlphaPremultiplied,
90                        int transparency, int transferType)
91   {
92     this.pixel_bits = pixel_bits;
93     this.bits = bits;
94     this.cspace = cspace;
95     this.hasAlpha = hasAlpha;
96     this.isAlphaPremultiplied = isAlphaPremultiplied;
97     this.transparency = transparency;
98     this.transferType = transferType;
99   }
100
101   public static ColorModel getRGBdefault()
102   {
103     return new DirectColorModel(8, 0xff0000, 0xff00, 0xff, 0xff000000);
104   }
105
106   public final boolean hasAlpha()
107   {
108     return hasAlpha;
109   }
110
111   public final boolean isAlphaPremultiplied()
112   {
113     return isAlphaPremultiplied;
114   }
115
116   public int getPixelSize()
117   {
118     return pixel_bits;
119   }
120     
121   public int getComponentSize(int componentIdx)
122   {
123     return bits[componentIdx];
124   }
125     
126   public int[] getComponentSize()
127   {
128     return bits;
129   }
130
131   public int getTransparency()
132   {
133     return transparency;
134   }
135
136   public int getNumComponents()
137   {
138     return getNumColorComponents() + (hasAlpha ? 1 : 0);
139   }
140
141   public int getNumColorComponents()
142   {
143     return cspace.getNumComponents();
144   }
145
146   /**
147    * Converts pixel value to sRGB and extract red int sample scaled
148    * to range [0, 255].
149    *
150    * @param pixel pixel value that will be interpreted according to
151    * the color model, (assumed alpha premultiplied if color model says
152    * so.)
153    *
154    * @return red sample scaled to range [0, 255], from default color
155    * space sRGB, alpha non-premultiplied.
156    */
157   public abstract int getRed(int pixel);
158
159   /**
160    * Converts pixel value to sRGB and extract green int sample
161    * scaled to range [0, 255].
162    *
163    * @see #getRed(int)
164    */
165     public abstract int getGreen(int pixel);
166     
167   /**
168    * Converts pixel value to sRGB and extract blue int sample
169    * scaled to range [0, 255].
170    *
171    * @see #getRed(int)
172    */
173   public abstract int getBlue(int pixel);
174
175   /**
176    * Extract alpha int sample from pixel value, scaled to [0, 255].
177    *
178    * @param pixel pixel value that will be interpreted according to
179    * the color model.
180    *
181    * @return alpha sample, scaled to range [0, 255].
182    */
183   public abstract int getAlpha(int pixel);
184
185   /**
186    * Converts a pixel int value of the color space of the color
187    * model to a sRGB pixel int value.
188    *
189    * This method is typically overriden in subclasses to provide a
190    * more efficient implementation.
191    * 
192    * @param pixel pixel value that will be interpreted according to
193    * the color model.
194    *
195    * @return a pixel in sRGB color space, encoded in default
196    * 0xAARRGGBB format.  */
197   public int getRGB(int pixel)
198   {
199     return 
200       ((getAlpha(pixel) & 0xff) << 24) |
201       ((  getRed(pixel) & 0xff) << 16) |
202       ((getGreen(pixel) & 0xff) <<  8) |
203       (( getBlue(pixel) & 0xff) <<  0);
204   }
205   
206
207   /**
208    * In this color model we know that the whole pixel value will
209    * always be contained within the first element of the pixel
210    * array.
211    */
212   final int getPixelFromArray(Object inData) {
213     DataBuffer data =
214       Buffers.createBufferFromData(transferType, inData, 1);
215     Object da = Buffers.getData(data);
216
217     return data.getElem(0);
218   }
219
220   /** 
221    * Converts pixel in the given array to sRGB and extract blue int
222    * sample scaled to range [0-255].
223    *
224    * This method is typically overriden in subclasses to provide a
225    * more efficient implementation.
226    * 
227    * @param array of transferType containing a single pixel.  The
228    * pixel should be encoded in the natural way of the color model.
229    */
230   public int getRed(Object inData)
231   {
232     return getRed(getPixelFromArray(inData));
233   }
234
235   /**
236    * @see #getRed(Object)
237    */
238   public int getGreen(Object inData)
239   {
240     return getGreen(getPixelFromArray(inData));
241   }
242
243   /**
244    * @see #getRed(Object)
245    */
246   public int getBlue(Object inData) {
247     return getBlue(getPixelFromArray(inData));
248   }
249
250   /**
251    * @see #getRed(Object)
252    */
253   public int getAlpha(Object inData) {
254     return getBlue(getPixelFromArray(inData));
255   }
256
257   /**
258    * Converts a pixel in the given array of the color space of the
259    * color model to an sRGB pixel int value.
260    *
261    * <p>This method performs the inverse function of
262    * <code>getDataElements(int rgb, Object pixel)</code>.
263    * I.e. <code>(rgb == cm.getRGB(cm.getDataElements(rgb,
264    * null)))</code>.
265    *
266    * @param inData array of transferType containing a single pixel. The
267    * pixel should be encoded in the natural way of the color model.
268    *
269    * @return a pixel in sRGB color space, encoded in default
270    * 0xAARRGGBB format.
271    *
272    * @see #getDataElements(int, Object)
273    */
274   public int getRGB(Object inData)
275   {
276     return 
277       ((getAlpha(inData) & 0xff) << 24) |
278       ((  getRed(inData) & 0xff) << 16) |
279       ((getGreen(inData) & 0xff) <<  8) |
280       (( getBlue(inData) & 0xff) <<  0);
281   }
282
283   /**
284    * Converts an sRGB pixel int value to an array containing a
285    * single pixel of the color space of the color model.
286    * 
287    * <p>This method performs the inverse function of
288    * <code>getRGB(Object inData)</code>.
289    *
290    * Outline of conversion process:
291    *
292    * <ol>
293    *
294    * <li>Convert rgb to normalized [0.0, 1.0] sRGB values.</li>
295    *
296    * <li>Convert to color space components using fromRGB in
297    * ColorSpace.</li>
298    *
299    * <li>If color model has alpha and should be premultiplied,
300    * multiply color space components with alpha value</li>
301    *
302    * <li>Scale the components to the correct number of bits.</li>
303    *
304    * <li>Arrange the components in the output array</li>
305    * 
306    * </ol>
307    *
308    * @param rgb The color to be converted to dataElements.  A pixel
309    * in sRGB color space, encoded in default 0xAARRGGBB format,
310    * assumed not alpha premultiplied.
311    *
312    * @param pixel to avoid needless creation of arrays, an array to
313    * use to return the pixel can be given. If null, a suitable array
314    * will be created.
315    *
316    * @return An array of transferType values representing the color,
317    * in the color model format. The color model defines whether the
318    *  
319    * @see #getRGB(Object)
320    */
321   public Object getDataElements(int rgb, Object pixel)
322   {
323     // FIXME: implement
324     throw new UnsupportedOperationException();
325   }
326
327   /**
328    * Fills an array with the unnormalized component samples from a
329    * pixel value. I.e. decompose the pixel, but not perform any
330    * color conversion. 
331    *
332    * This method is typically overriden in subclasses to provide a
333    * more efficient implementation.
334    * 
335    * @param pixel pixel value encoded according to the color model.
336    *
337    * @return arrays of unnormalized component samples of single
338    * pixel.  The scale and multiplication state of the samples are
339    * according to the color model. Each component sample is stored
340    * as a separate element in the array.
341    */
342   public int[] getComponents(int pixel, int[] components, int offset) {
343     // FIXME: implement
344     throw new UnsupportedOperationException();
345   }
346   
347   /**
348    * Fills an array with the unnormalized component samples from an
349    * array of transferType containing a single pixel. I.e. decompose
350    * the pixel, but not perform any color conversion.
351    *
352    * This method is typically overriden in subclasses to provide a
353    * more efficient implementation.
354    *
355    * @param array of transferType containing a single pixel.  The
356    * pixel should be encoded in the natural way of the color model.
357    * 
358    * @return arrays of unnormalized component samples of single
359    * pixel.  The scale and multiplication state of the samples are
360    * according to the color model. Each component sample is stored
361    * as a separate element in the array.
362    */
363   public int[] getComponents(Object pixel, int[] components, int offset)
364   {
365     throw new UnsupportedOperationException();
366   }
367
368   /**
369    * Convert normalized components to unnormalized components.
370    */
371   public int[] getUnnormalizedComponents(float[] normComponents,
372                                          int normOffset,
373                                          int[] components,
374                                          int offset)
375   {
376     int numComponents = getNumComponents();
377     if (components == null)
378     {
379       components = new int[offset + numComponents];
380     }
381     
382     for (int i=0; i<numComponents; i++)
383     {
384       float in = normComponents[normOffset++];
385       int out = (int) (in * ((2<<getComponentSize(i)) - 1));
386       components[offset++] = out;
387     }
388     return components;
389   }
390
391   /**
392    * Convert unnormalized components to normalized components.
393    */
394   public float[] getNormalizedComponents(int[] components,
395                                          int offset,
396                                          float[] normComponents,
397                                          int normOffset)
398   {
399     int numComponents = getNumComponents();
400     if (normComponents == null)
401     {
402       normComponents = new float[normOffset + numComponents];
403     }
404
405     for (int i=0; i<numComponents; i++)
406     {
407       float in = components[offset++];
408       float out = in / ((2<<getComponentSize(i)) - 1);
409       normComponents[normOffset++] = out;
410     }
411     return normComponents;
412   }
413
414   /**
415    * Converts the unnormalized component samples from an array to a
416    * pixel value. I.e. composes the pixel from component samples, but
417    * does not perform any color conversion or scaling of the samples.
418    * 
419    * This method performs the inverse function of
420    * <code>getComponents(int pixel, int[] components,
421    *                           int offset)</code>. I.e.
422    *
423    * <code>(pixel == cm.getDataElement(cm.getComponents(pixel, null,
424    * 0), 0))</code>.
425    *
426    * This method is typically overriden in subclasses to provide a
427    * more efficient implementation.
428    *
429    * @param arrays of unnormalized component samples of single
430    * pixel.  The scale and multiplication state of the samples are
431    * according to the color model. Each component sample is stored
432    * as a separate element in the array.
433    *
434    * @return pixel value encoded according to the color model.
435    */
436   public int getDataElement(int[] components, int offset)
437   {
438     throw new UnsupportedOperationException();
439   }
440
441   public Object getDataElements(int[] components, int offset, Object obj)
442   {
443     throw new UnsupportedOperationException();
444   }
445
446   public boolean equals(Object obj)
447   {
448     if (!(obj instanceof ColorModel)) return false;
449
450     ColorModel o = (ColorModel) obj;
451     return 
452       (pixel_bits == o.pixel_bits) &&
453       (transferType == o.transferType) &&
454       (transparency == o.transparency) &&
455       (hasAlpha == o.hasAlpha) &&
456       (isAlphaPremultiplied == isAlphaPremultiplied) &&
457       (bits.equals(o.bits)) &&
458       (cspace.equals(o.cspace));
459   }
460
461   public final ColorSpace getColorSpace()
462   {
463     return cspace;
464   }
465
466   // Typically overridden
467   public ColorModel coerceData(WritableRaster raster,
468                                boolean isAlphaPremultiplied)
469   {
470     if (this.isAlphaPremultiplied == isAlphaPremultiplied)
471       return this;
472
473     int w = raster.getWidth();
474     int h = raster.getHeight();
475     int x = raster.getMinX();
476     int y = raster.getMinY();
477     int size = w*h;
478     int numColors = getNumColorComponents();
479     int numComponents = getNumComponents();
480     int alphaScale = (1<<getComponentSize(numColors)) - 1;
481     double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
482
483     for (int i=0; i<size; i++)
484       {
485         double alpha = pixels[i*numComponents+numColors]*alphaScale;
486         for (int c=0; c<numColors; c++)
487           {
488             int offset = i*numComponents+c;
489             if (isAlphaPremultiplied)
490                 pixels[offset] = pixels[offset]/alpha;
491             else
492               pixels[offset] = pixels[offset]*alpha;
493           }
494       }
495     
496     raster.setPixels(0, 0, w, h, pixels);
497
498     // FIXME: what can we return?
499     return null;
500   }
501     
502   // Typically overridden
503   public boolean isCompatibleRaster(Raster raster)
504   {
505     SampleModel sampleModel = raster.getSampleModel();
506     return isCompatibleSampleModel(sampleModel);
507   }
508
509   // Typically overridden
510   public WritableRaster createCompatibleWritableRaster(int w, int h)
511   {
512     return new WritableRaster(createCompatibleSampleModel(w, h),
513                               new Point(0, 0));
514   }
515
516   // Typically overridden
517   public SampleModel createCompatibleSampleModel(int w, int h)
518   {
519     throw new UnsupportedOperationException();
520   }
521
522   // Typically overridden
523   public boolean isCompatibleSampleModel(SampleModel sm)
524   {
525     return sm.getTransferType() == transferType;
526   }
527
528   public void finalize() {
529   }
530
531   /**
532    * Subclasses must override this method if it is possible for the
533    * color model to have an alpha channel.
534    *
535    * @return null, as per JDK 1.3 doc. Subclasses will only return
536    * null if no alpha raster exists.
537    */
538   public WritableRaster getAlphaRaster(WritableRaster raster)
539   {
540     return null;
541     
542     /* It is a mystery to me why we couldn't use the following code...
543        
544        
545        if (!hasAlpha()) return null;
546        
547        SampleModel sm = raster.getSampleModel();
548        int[] alphaBand = { sm.getNumBands() - 1 };
549        SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
550        DataBuffer buffer = raster.getDataBuffer();
551        Point origin = new Point(0, 0);
552        return Raster.createWritableRaster(alphaModel, buffer, origin);
553        
554
555        ...here, and avoided overriding the method in subclasses,
556        but the Sun docs state that this method always will return
557        null, and that overriding is required. Oh, well.
558     */
559   }
560
561   String stringParam()
562   {
563     return "pixel_bits=" + pixel_bits +
564       ", cspace=" + cspace +
565       ", transferType=" + transferType +
566       ", transparency=" + transparency +
567       ", hasAlpha=" + hasAlpha +
568       ", isAlphaPremultiplied=" + isAlphaPremultiplied;
569   }
570
571   public String toString()
572   {
573     return getClass().getName() + "[" + stringParam() + "]";
574   }
575 }