OSDN Git Service

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