OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / image / ComponentColorModel.java
1 /* ComponentColorModel.java --
2    Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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.color.ColorSpace;
45
46 public class ComponentColorModel extends ColorModel
47 {
48   private static int sum(int[] values)
49   {
50     int sum = 0;
51     for (int i=0; i<values.length; i++)
52       sum += values[i];
53     return sum;
54   }
55
56   public ComponentColorModel(ColorSpace colorSpace, int[] bits,
57                              boolean hasAlpha,
58                              boolean isAlphaPremultiplied,
59                              int transparency, int transferType)
60   {
61     super(sum(bits), bits, colorSpace, hasAlpha, isAlphaPremultiplied,
62           transparency, transferType);
63   }
64
65   /**
66    * Construct a new ComponentColorModel.
67    * 
68    * This constructor makes all bits of each sample significant, so for a
69    * transferType of DataBuffer.BYTE, the bits per sample is 8, etc.  If
70    * both hasAlpha and isAlphaPremultiplied are true, color samples are
71    * assumed to be premultiplied by the alpha component.  Transparency may be
72    * one of OPAQUE, BITMASK, or TRANSLUCENT. 
73    * 
74    * @param colorSpace The colorspace for this color model.
75    * @param hasAlpha True if there is an alpha component.
76    * @param isAlphaPremultiplied True if colors are already multiplied by
77    * alpha.
78    * @param transparency The type of alpha values.
79    * @param transferType Data type of pixel sample values.
80    * @since 1.4
81    */
82   public ComponentColorModel(ColorSpace colorSpace,
83                              boolean hasAlpha,
84                              boolean isAlphaPremultiplied,
85                              int transparency, int transferType)
86   {     
87     this(colorSpace, null, hasAlpha, isAlphaPremultiplied,
88          transparency, transferType);
89   }
90
91   public int getRed(int pixel)
92   {
93     if (getNumComponents()>1) throw new IllegalArgumentException();
94     return (int) getRGBFloat(pixel)[0];
95   }
96
97   public int getGreen(int pixel)
98   {
99     if (getNumComponents()>1) throw new IllegalArgumentException();
100     return (int) getRGBFloat(pixel)[0];
101   }
102   
103   public int getBlue(int pixel)
104   {
105     if (getNumComponents()>1) throw new IllegalArgumentException();
106     return (int) getRGBFloat(pixel)[0];
107   }
108
109   public int getAlpha(int pixel)
110   {
111     if (getNumComponents()>1) throw new IllegalArgumentException();
112     int shift = 8 - getComponentSize(getNumColorComponents());
113     if (shift >= 0) return pixel << shift;
114     return pixel >> (-shift);
115   }
116    
117   public int getRGB(int pixel)
118   {
119     float[] rgb = getRGBFloat(pixel);
120     int ret = getRGB(rgb);
121     if (hasAlpha()) ret |= getAlpha(pixel) << 24;
122     return ret;
123   }
124
125
126   /* Note, it's OK to pass a to large array to toRGB(). Extra
127      elements are ignored. */
128   
129   private float[] getRGBFloat(int pixel)
130   {
131     float[] data = { pixel };
132     return cspace.toRGB(data);
133   }
134
135   private float[] getRGBFloat(Object inData)
136   {
137     DataBuffer buffer =
138     Buffers.createBufferFromData(transferType, inData,
139                                  getNumComponents());
140     int colors = getNumColorComponents();
141     float[] data = new float[colors];
142     
143     // FIXME: unpremultiply data that is premultiplied
144     for (int i=0; i<colors; i++)
145       {
146         float maxValue = (1<<getComponentSize(i))-1;
147         data[i] = buffer.getElemFloat(i)/maxValue; 
148       }
149     float[] rgb = cspace.toRGB(data);
150     return rgb;
151   }
152   
153   public int getRed(Object inData)
154   {
155     return (int) getRGBFloat(inData)[0]*255;
156   }
157
158   public int getGreen(Object inData)
159   {
160     return (int) getRGBFloat(inData)[1]*255;
161   }
162
163   public int getBlue(Object inData)
164   {
165     return (int) getRGBFloat(inData)[2]*255;
166   }
167
168   public int getAlpha(Object inData)
169   {
170     DataBuffer buffer =
171       Buffers.createBufferFromData(transferType, inData,
172                                    getNumComponents());
173     int shift = 8 - getComponentSize(getNumColorComponents());
174     int alpha = buffer.getElem(getNumColorComponents());
175     if (shift >= 0) return alpha << shift;
176     return alpha >> (-shift);
177   }
178
179   private int getRGB(float[] rgb)
180   {
181     /* NOTE: We could cast to byte instead of int here. This would
182        avoid bits spilling over from one bit field to
183        another. But, if we assume that floats are in the [0.0,
184        1.0] range, this will never happen anyway. */
185     
186     /* Remember to multiply BEFORE casting to int, otherwise, decimal
187        point data will be lost. */
188     int ret =
189       (((int) (rgb[0]*255F)) << 16) |
190       (((int) (rgb[1]*255F)) <<  8) |
191       (((int) (rgb[2]*255F)) <<  0);
192     return ret;
193   }
194
195   /**
196    * @param inData pixel data of transferType, as returned by the
197    * getDataElements method in SampleModel.
198    */
199   public int getRGB(Object inData)
200   {
201     float[] rgb = getRGBFloat(inData);
202     int ret = getRGB(rgb);
203     if (hasAlpha()) ret |= getAlpha(inData) << 24;
204     return ret;
205   }
206
207   public Object getDataElements(int rgb, Object pixel)
208   {
209     // Convert rgb to [0.0, 1.0] sRGB values.
210     float[] rgbFloats = {
211       ((rgb >> 16)&0xff)/255.0F,
212       ((rgb >>  8)&0xff)/255.0F,
213       ((rgb >>  0)&0xff)/255.0F
214     };
215
216     // Convert from rgb to color space components.
217     float[] data = cspace.fromRGB(rgbFloats);
218     DataBuffer buffer = Buffers.createBuffer(transferType, pixel,
219                                              getNumComponents());
220     int numColors = getNumColorComponents();
221     
222     if (hasAlpha())
223       {
224         float alpha = ((rgb >> 24)&0xff)/255.0F;
225         
226         /* If color model has alpha and should be premultiplied, multiply
227            color space components with alpha value. */
228         if (isAlphaPremultiplied()) {
229           for (int i=0; i<numColors; i++)
230             data[i] *= alpha;
231         }
232         // Scale the alpha sample to the correct number of bits.
233         alpha *= (1<<(bits[numColors]-1));
234         // Arrange the alpha sample in the output array.
235         buffer.setElemFloat(numColors, alpha);
236       }
237     for (int i=0; i<numColors; i++)
238       {
239         // Scale the color samples to the correct number of bits.
240         float value = data[i]*(1<<(bits[i]-1));
241         // Arrange the color samples in the output array.
242         buffer.setElemFloat(i, value);
243       }
244     return Buffers.getData(buffer);
245   }
246
247   public int[] getComponents(int pixel, int[] components, int offset)
248   {
249     if (getNumComponents()>1) throw new IllegalArgumentException();
250     if (components == null)
251     components = new int[getNumComponents() + offset];
252     components[offset] = pixel;
253     return components;
254   }
255
256   public int[] getComponents(Object pixel, int[] components, int offset)
257   {
258     DataBuffer buffer = Buffers.createBuffer(transferType, pixel,
259                                              getNumComponents());
260     int numComponents = getNumComponents();
261
262     if (components == null)
263       components = new int[numComponents + offset];
264
265     for (int i=0; i<numComponents; i++)
266       components[offset++] = buffer.getElem(i);
267
268     return components;
269   }
270
271   public int getDataElement(int[] components, int offset)
272   {
273     if (getNumComponents()>1) throw new IllegalArgumentException();
274     return components[offset];
275   }
276
277   public Object getDataElements(int[] components, int offset, Object obj)
278   {
279     DataBuffer buffer = Buffers.createBuffer(transferType, obj,
280                                              getNumComponents());
281     int numComponents = getNumComponents();
282
283     for (int i=0; i<numComponents; i++)
284       buffer.setElem(i, components[offset++]);
285
286     return Buffers.getData(buffer);
287   }
288
289   public ColorModel coerceData(WritableRaster raster,
290                                boolean isAlphaPremultiplied) {
291     if (this.isAlphaPremultiplied == isAlphaPremultiplied)
292       return this;
293
294     /* TODO: provide better implementation based on the
295        assumptions we can make due to the specific type of the
296        color model. */
297     super.coerceData(raster, isAlphaPremultiplied);
298     
299     return new ComponentColorModel(cspace, bits, hasAlpha(),
300                                    isAlphaPremultiplied, // argument
301                                    transparency, transferType);
302   }
303
304   public boolean isCompatibleRaster(Raster raster)
305   {
306     return super.isCompatibleRaster(raster);
307     // FIXME: Should we test something more here? (Why override?)
308   }
309
310   public WritableRaster createCompatibleWritableRaster(int w, int h)
311   {
312     SampleModel sm = createCompatibleSampleModel(w, h);
313     Point origin = new Point(0, 0);
314     return Raster.createWritableRaster(sm, origin);
315   }
316
317
318   /**
319    * Creates a <code>SampleModel</code> whose arrangement of pixel
320    * data is compatible to this <code>ColorModel</code>.
321    *
322    * @param w the number of pixels in the horizontal direction.
323    * @param h the number of pixels in the vertical direction.
324    */
325   public SampleModel createCompatibleSampleModel(int w, int h)
326   {
327     int pixelStride, scanlineStride;
328     int[] bandOffsets;
329
330     pixelStride = getNumComponents();
331     scanlineStride = pixelStride * w;
332
333     /* We might be able to re-use the same bandOffsets array among
334      * multiple calls to this method. However, this optimization does
335      * not seem worthwile because setting up descriptive data
336      * structures (such as SampleModels) is neglectible in comparision
337      * to shuffling around masses of pixel data.
338      */
339     bandOffsets = new int[pixelStride];
340     for (int i = 0; i < pixelStride; i++)
341       bandOffsets[i] = i;
342
343     /* FIXME: Think about whether it would make sense to return the
344      * possibly more efficient PixelInterleavedSampleModel for other
345      * transferTypes as well. It seems unlikely that this would break
346      * any user applications, so the Mauve tests on this method
347      * might be too restrictive.
348      */
349     switch (transferType)
350       {
351       case DataBuffer.TYPE_BYTE:
352       case DataBuffer.TYPE_USHORT:
353         return new PixelInterleavedSampleModel(transferType, w, h,
354                                                pixelStride,
355                                                scanlineStride,
356                                                bandOffsets);
357
358       default:
359         return new ComponentSampleModel(transferType, w, h,
360                                         pixelStride,
361                                         scanlineStride,
362                                         bandOffsets);
363       }
364   }
365
366
367   public boolean isCompatibleSampleModel(SampleModel sm)
368   {
369     return 
370       (sm instanceof ComponentSampleModel) &&
371       super.isCompatibleSampleModel(sm);
372   }
373
374   public WritableRaster getAlphaRaster(WritableRaster raster)
375   {
376     if (!hasAlpha()) return null;
377     
378     SampleModel sm = raster.getSampleModel();
379     int[] alphaBand = { sm.getNumBands() - 1 };
380     SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
381     DataBuffer buffer = raster.getDataBuffer();
382     Point origin = new Point(0, 0);
383     return Raster.createWritableRaster(alphaModel, buffer, origin);
384   }
385     
386   public boolean equals(Object obj)
387   {
388     if (!(obj instanceof ComponentColorModel)) return false;
389     return super.equals(obj);
390   }
391 }