OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / image / DirectColorModel.java
1 /* DirectColorModel.java --
2    Copyright (C) 1999, 2000, 2002, 2004  Free Software Foundation
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package java.awt.image;
40
41 import gnu.java.awt.Buffers;
42
43 import java.awt.Point;
44 import java.awt.Transparency;
45 import java.awt.color.ColorSpace;
46
47 /**
48  * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
49  * @author C. Brian Jones (cbj@gnu.org)
50  * @author Mark Benvenuto (mcb54@columbia.edu)
51  */
52 public class DirectColorModel extends PackedColorModel
53 {
54   /**
55    * For the color model created with this constructor the pixels
56    * will have fully opaque alpha components with a value of 255.
57    * Each mask should describe a fully contiguous set of bits in the
58    * most likely order of alpha, red, green, blue from the most significant
59    * byte to the least significant byte.
60    * 
61    * @param pixelBits the number of bits wide used for bit size of pixel values
62    * @param rmask the bits describing the red component of a pixel
63    * @param gmask the bits describing the green component of a pixel
64    * @param bmask the bits describing the blue component of a pixel 
65    */
66   public DirectColorModel(int pixelBits, int rmask, int gmask, int bmask)
67   {
68     this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits,
69          rmask, gmask, bmask, 0, 
70          false, // not alpha premultiplied
71          Buffers.smallestAppropriateTransferType(pixelBits) // find type
72          );
73   }
74
75   /**
76    * For the color model created with this constructor the pixels
77    * will have fully opaque alpha components with a value of 255.
78    * Each mask should describe a fully contiguous set of bits in the
79    * most likely order of red, green, blue from the most significant
80    * byte to the least significant byte.
81    * 
82    * @param pixelBits the number of bits wide used for bit size of pixel values
83    * @param rmask the bits describing the red component of a pixel
84    * @param gmask the bits describing the green component of a pixel
85    * @param bmask the bits describing the blue component of a pixel 
86    * @param amask the bits describing the alpha component of a pixel 
87    */
88   public DirectColorModel(int pixelBits,
89                           int rmask, int gmask, int bmask, int amask)
90   {
91     this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits,
92          rmask, gmask, bmask, amask,
93          false, // not alpha premultiplied
94          Buffers.smallestAppropriateTransferType(pixelBits) // find type
95          );
96   }
97
98   public DirectColorModel(ColorSpace cspace, int pixelBits,
99                           int rmask, int gmask, int bmask, int amask,
100                           boolean isAlphaPremultiplied,
101                           int transferType)
102   {
103     super(cspace, pixelBits,
104           rmask, gmask, bmask, amask, isAlphaPremultiplied,
105           ((amask == 0) ? Transparency.OPAQUE : Transparency.TRANSLUCENT),
106           transferType);
107   }
108     
109   public final int getRedMask()
110   {
111     return getMask(0);
112   }
113
114   public final int getGreenMask()
115   {
116     return getMask(1);
117   }
118
119   public final int getBlueMask()
120   {
121     return getMask(2);
122   }
123
124   public final int getAlphaMask()
125   {
126     return hasAlpha() ? getMask(3) : 0;
127   }
128
129   /**
130    * Get the red component of the given pixel.
131    * <br>
132    */
133   public final int getRed(int pixel)
134   {
135     return extractAndNormalizeSample(pixel, 0);
136   }
137
138   /**
139    * Get the green component of the given pixel.
140    * <br>
141    */
142   public final int getGreen(int pixel)
143   {
144     return extractAndNormalizeSample(pixel, 1);
145   }
146   
147   /**
148    * Get the blue component of the given pixel.
149    * <br>
150    */
151   public final int getBlue(int pixel)
152   {
153     return extractAndNormalizeSample(pixel, 2);
154   }
155
156   /**
157    * Get the alpha component of the given pixel.
158    * <br>
159    */
160   public final int getAlpha(int pixel)
161   {
162     if (!hasAlpha())
163       return 255;
164     return extractAndScaleSample(pixel, 3);
165   }
166
167   private int extractAndNormalizeSample(int pixel, int component)
168   {
169     int value = extractAndScaleSample(pixel, component);
170     if (hasAlpha() && isAlphaPremultiplied() && getAlpha(pixel) != 0)
171       value = value*255/getAlpha(pixel);
172     return value;
173   }
174
175   private int extractAndScaleSample(int pixel, int component)
176   {
177     int field = pixel & getMask(component);
178     int to8BitShift =
179       8 - shifts[component] - getComponentSize(component);
180     return (to8BitShift>0) ?
181       (field << to8BitShift) :
182       (field >>> (-to8BitShift));
183   }
184
185   /**
186    * Get the RGB color value of the given pixel using the default
187    * RGB color model. 
188    * <br>
189    *
190    * @param pixel a pixel value
191    */
192   public final int getRGB(int pixel) 
193   {
194     /* FIXME: The Sun docs show that this method is overridden, but I
195        don't see any way to improve on the superclass
196        implementation. */
197     return super.getRGB(pixel);
198   }
199
200   public int getRed(Object inData)
201   {
202     return getRed(getPixelFromArray(inData));
203   }
204
205   public int getGreen(Object inData)
206   {
207     return getGreen(getPixelFromArray(inData));
208   }
209
210   public int getBlue(Object inData)
211   {
212     return getBlue(getPixelFromArray(inData));
213   }
214     
215   public int getAlpha(Object inData)
216   {
217     return getAlpha(getPixelFromArray(inData));
218   }
219
220   public int getRGB(Object inData)
221   {
222     return getRGB(getPixelFromArray(inData));
223   }
224     
225   /**
226    * Converts a normalized pixel int value in the sRGB color
227    * space to an array containing a single pixel of the color space
228    * of the color model.
229    *
230    * <p>This method performs the inverse function of
231    * <code>getRGB(Object inData)</code>.
232    *
233    * @param rgb pixel as a normalized sRGB, 0xAARRGGBB value.
234    *  
235    * @param pixel to avoid needless creation of arrays, an array to
236    * use to return the pixel can be given. If null, a suitable array
237    * will be created.
238    *
239    * @return array of transferType containing a single pixel. The
240    * pixel should be encoded in the natural way of the color model.
241    *
242    * @see #getRGB(Object)
243    */
244   public Object getDataElements(int rgb, Object pixel)
245   {
246     // FIXME: handle alpha multiply
247     
248     int pixelValue = 0;
249     int a = 0;
250     if (hasAlpha()) {
251       a = (rgb >>> 24) & 0xff;
252       pixelValue = valueToField(a, 3, 8);
253     }
254         
255     if (hasAlpha() && isAlphaPremultiplied())
256       {
257         int r, g, b;
258         /* if r=0xff and a=0xff, then resulting
259            value will be (r*a)>>>8 == 0xfe... This seems wrong.
260            We should divide by 255 rather than shifting >>>8 after
261            multiplying.
262            
263            Too bad, shifting is probably less expensive.
264            r = ((rgb >>> 16) & 0xff)*a;
265            g = ((rgb >>>  8) & 0xff)*a;
266            b = ((rgb >>> 0) & 0xff)*a; */
267         /* The r, g, b values we calculate are 16 bit. This allows
268            us to avoid discarding the lower 8 bits obtained if
269            multiplying with the alpha band. */
270         
271         // using 16 bit values
272         r = ((rgb >>> 8) & 0xff00)*a/255;
273         g = ((rgb >>> 0) & 0xff00)*a/255;
274         b = ((rgb <<  8) & 0xff00)*a/255;
275         pixelValue |= 
276           valueToField(r, 0, 16) |  // Red
277           valueToField(g, 1, 16) |  // Green
278           valueToField(b, 2, 16);   // Blue
279       }
280     else
281       {
282         int r, g, b;
283         // using 8 bit values
284         r = (rgb >>> 16) & 0xff;
285         g = (rgb >>>  8) & 0xff;
286         b = (rgb >>>  0) & 0xff;
287         
288         pixelValue |= 
289           valueToField(r, 0, 8) |  // Red
290           valueToField(g, 1, 8) |  // Green
291           valueToField(b, 2, 8);   // Blue
292       }
293     
294     /* In this color model, the whole pixel fits in the first element
295        of the array. */
296     DataBuffer buffer = Buffers.createBuffer(transferType, pixel, 1);
297     buffer.setElem(0, pixelValue);
298     return Buffers.getData(buffer);
299   }
300     
301   /**
302    * Converts a value to the correct field bits based on the
303    * information derived from the field masks.
304    *
305    * @param highBit the position of the most significant bit in the
306    * val parameter.
307    */
308   private int valueToField(int val, int component, int highBit)
309   {
310     int toFieldShift = 
311       getComponentSize(component) + shifts[component] - highBit;
312     int ret = (toFieldShift>0) ?
313       (val << toFieldShift) :
314       (val >>> (-toFieldShift));
315     return ret & getMask(component);
316   }  
317
318   /**
319    * Converts a 16 bit value to the correct field bits based on the
320    * information derived from the field masks.
321    */
322   private int value16ToField(int val, int component)
323   {
324     int toFieldShift = getComponentSize(component) + shifts[component] - 16;
325     return (toFieldShift>0) ?
326       (val << toFieldShift) :
327       (val >>> (-toFieldShift));
328   }
329
330   /**
331    * Fills an array with the unnormalized component samples from a
332    * pixel value. I.e. decompose the pixel, but not perform any
333    * color conversion.
334    */
335   public final int[] getComponents(int pixel, int[] components, int offset)
336   {
337     int numComponents = getNumComponents();
338     if (components == null) components = new int[offset + numComponents];
339     
340     for (int b=0; b<numComponents; b++)
341       components[offset++] = (pixel&getMask(b)) >>> shifts[b];
342         
343     return components;
344   }
345
346   public final int[] getComponents(Object pixel, int[] components,
347                                    int offset)
348   {
349     return getComponents(getPixelFromArray(pixel), components, offset);
350   }
351
352   /**
353    * Creates a <code>WriteableRaster</code> that has a <code>SampleModel</code>
354    * that is compatible with this <code>ColorModel</code>.
355    *
356    * @param w the width of the writeable raster to create
357    * @param h the height of the writeable raster to create
358    *
359    * @throws IllegalArgumentException if <code>w</code> or <code>h</code>
360    *         is less than or equal to zero
361    */
362   public final WritableRaster createCompatibleWritableRaster(int w, int h)
363   {
364     // Sun also makes this check here.
365     if(w <= 0 || h <= 0)
366       throw new IllegalArgumentException("width (=" + w + ") and height (="
367                                          + h + ") must be > 0");
368
369     SampleModel sm = createCompatibleSampleModel(w, h);
370     Point origin = new Point(0, 0);
371     return Raster.createWritableRaster(sm, origin);     
372   }
373
374   public int getDataElement(int[] components, int offset)
375   {
376     int numComponents = getNumComponents();
377     int pixelValue = 0;
378     
379     for (int c=0; c<numComponents; c++)
380       pixelValue |= (components[offset++] << shifts[c]) & getMask(c);
381
382     return pixelValue;
383   }  
384
385   public Object getDataElements(int[] components, int offset, Object obj)
386   {
387     /* In this color model, the whole pixel fits in the first element
388        of the array. */
389     int pixelValue = getDataElement(components, offset);
390
391     DataBuffer buffer = Buffers.createBuffer(transferType, obj, 1);
392     buffer.setElem(0, pixelValue);
393     return Buffers.getData(buffer);
394   }
395     
396   public final ColorModel coerceData (WritableRaster raster,
397                                       boolean isAlphaPremultiplied)
398   {
399     if (this.isAlphaPremultiplied == isAlphaPremultiplied || !hasAlpha())
400       return this;
401         
402     /* TODO: provide better implementation based on the
403        assumptions we can make due to the specific type of the
404        color model. */
405     coerceDataWorker(raster, isAlphaPremultiplied);
406     
407     return new DirectColorModel(cspace, pixel_bits, getRedMask(),
408                                 getGreenMask(), getBlueMask(), getAlphaMask(),
409                                 isAlphaPremultiplied, transferType);
410   } 
411
412   public boolean isCompatibleRaster(Raster raster)
413   {
414     /* FIXME: the Sun docs say this method is overridden here, 
415        but I don't see any way to improve upon the implementation
416        in ColorModel. */
417     return super.isCompatibleRaster(raster);
418   }
419
420   String stringParam()
421   {
422     return super.stringParam() +
423       ", redMask=" + Integer.toHexString(getRedMask()) +
424       ", greenMask=" + Integer.toHexString(getGreenMask()) +
425       ", blueMask=" + Integer.toHexString(getBlueMask()) +
426       ", alphaMask=" + Integer.toHexString(getAlphaMask());
427   }
428
429   public String toString()
430   {
431     /* FIXME: Again, docs say override, but how do we improve upon the
432        superclass implementation? */
433     return super.toString();
434   }
435 }
436