1 /* ImageTypeSpecifier.java --
2    Copyright (C) 2004  Free Software Foundation, Inc.
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 javax.imageio;
40 
41 import java.awt.Transparency;
42 import java.awt.color.ColorSpace;
43 import java.awt.image.DataBuffer;
44 import java.awt.image.BandedSampleModel;
45 import java.awt.image.BufferedImage;
46 import java.awt.image.ColorModel;
47 import java.awt.image.ComponentColorModel;
48 import java.awt.image.DirectColorModel;
49 import java.awt.image.IndexColorModel;
50 import java.awt.image.MultiPixelPackedSampleModel;
51 import java.awt.image.PixelInterleavedSampleModel;
52 import java.awt.image.RenderedImage;
53 import java.awt.image.SampleModel;
54 
55 /**
56  * ImageTypeSpecifier store the color and sample models associated
57  * with an IIOImage.
58  */
59 public class ImageTypeSpecifier
60 {
61   /**
62    * The image's color model.
63    */
64   protected ColorModel colorModel;
65 
66   /**
67    * The image's sample model.
68    */
69   protected SampleModel sampleModel;
70 
71   /**
72    * Construct an image type specifier with the given models.
73    *
74    * @param colorModel the color model
75    * @param sampleModel the sample model
76    *
77    * @exception IllegalArgumentException if either model argument is
78    * null
79    * @exception IllegalArgumentException if the models are
80    * incompatible with one another
81    */
ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel)82   public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel)
83   {
84     if (colorModel == null)
85       throw new IllegalArgumentException("colorModel may not be null");
86 
87     if (sampleModel == null)
88       throw new IllegalArgumentException("sampleModel may not be null");
89 
90     if (!colorModel.isCompatibleSampleModel(sampleModel))
91       throw new IllegalArgumentException
92         ("sample Model not compatible with colorModel");
93 
94     this.colorModel = colorModel;
95     this.sampleModel = sampleModel;
96   }
97 
98   /**
99    * Construct an image type specifier that describes the given
100    * rendered image.
101    *
102    * @param image a rendered image
103    *
104    * @exception IllegalArgumentException if image is null
105    */
ImageTypeSpecifier(RenderedImage image)106   public ImageTypeSpecifier(RenderedImage image)
107   {
108     if (image == null)
109       throw new IllegalArgumentException("image may not be null");
110 
111     this.colorModel = image.getColorModel();
112     this.sampleModel = image.getSampleModel();
113   }
114 
115   /**
116    * Create an image type specifier for a banded image using a
117    * component color model and a banded sample model.
118    *
119    * @param colorSpace the color space
120    * @param bankIndices the bank indices at which each band will be
121    * stored
122    * @param bankOffsets the starting band offset for each band within
123    * its bank
124    * @param dataType the data type, a DataBuffer constant
125    * @param hasAlpha true if this image type specifier should have an
126    * alpha component, false otherwise
127    * @param isAlphaPremultiplied true if other color components should
128    * be premultiplied by the alpha component, false otherwise
129    *
130    * @return a banded image type specifier
131    *
132    * @exception IllegalArgumentException if any of colorSpace,
133    * bankIndices or bankOffsets is null
134    * @exception IllegalArgumentException if bankIndices and
135    * bankOffsets differ in length
136    * @excpetion IllegalArgumentException if the number of color space
137    * components, including the alpha component if requested, is
138    * different from bandOffsets.length
139    * @exception if dataType is not a valid DataBuffer constant
140    */
createBanded(ColorSpace colorSpace, int[] bankIndices, int[] bankOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied)141   public static ImageTypeSpecifier createBanded (ColorSpace colorSpace,
142                                                  int[] bankIndices,
143                                                  int[] bankOffsets,
144                                                  int dataType,
145                                                  boolean hasAlpha,
146                                                  boolean isAlphaPremultiplied)
147   {
148     if (colorSpace == null || bankIndices == null || bankOffsets == null)
149       throw new IllegalArgumentException ("null argument");
150 
151     if (bankIndices.length != bankOffsets.length)
152       throw new IllegalArgumentException ("array lengths differ");
153 
154     if (bankOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0)))
155       throw new IllegalArgumentException ("invalid bankOffsets length");
156 
157     return new ImageTypeSpecifier (new ComponentColorModel (colorSpace,
158                                                             hasAlpha,
159                                                             isAlphaPremultiplied,
160                                                             hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE,
161                                                             dataType),
162                                    new BandedSampleModel (dataType, 1, 1, 1,
163                                                           bankIndices,
164                                                           bankOffsets));
165   }
166 
167   /**
168    * Create a buffered image with the given dimensions using that has
169    * the characteristics specified by this image type specifier.
170    *
171    * @param width  width of the buffered image, in pixels
172    * @param height the height of the buffered image, in pixels
173    *
174    * @return a buffered image
175    *
176    * @exception IllegalArgumentException if either width or height is
177    * less than or equal to zero
178    * @exception IllegalArgumentException if width * height is greater
179    * than Integer.MAX_VALUE or if the storage required is greater than
180    * Integer.MAX_VALUE
181    */
createBufferedImage(int width, int height)182   public BufferedImage createBufferedImage (int width, int height)
183   {
184     if (width <= 0 || height <= 0)
185       throw new IllegalArgumentException ("dimension <= 0");
186 
187     // test for overflow
188     if (width * height < Math.min (width, height))
189       throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE");
190 
191     if (width * height * sampleModel.getNumBands() < Math.min (width, height))
192       throw new IllegalArgumentException ("storage required >"
193                                           + " Integer.MAX_VALUE");
194 
195     // FIXME: this is probably wrong:
196     return new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB);
197   }
198 
199   /**
200    * Create an image type specifier that describes the given buffered
201    * image type.
202    *
203    * @param bufferedImageType the buffered image type to represent
204    * with the returned image type specifier
205    *
206    * @return a new image type specifier
207    *
208    * @exception IllegalArgumentException if bufferedImageType is not a
209    * BufferedImage constant or is BufferedImage.TYPE_CUSTOM
210    */
createFromBufferedImageType(int bufferedImageType)211   public static ImageTypeSpecifier createFromBufferedImageType (int bufferedImageType)
212   {
213     if (bufferedImageType <= BufferedImage.TYPE_CUSTOM
214         || bufferedImageType > BufferedImage.TYPE_BYTE_INDEXED)
215       throw new IllegalArgumentException ("invalid buffered image type");
216 
217     return new ImageTypeSpecifier (new BufferedImage (1, 1, bufferedImageType));
218   }
219 
220   /**
221    * Create an image type specifier that describes the given rendered
222    * image's type.
223    *
224    * @param image the rendered image
225    *
226    * @return a new image type specifier
227    *
228    * @exception IllegalArgumentException if image is null
229    */
createFromRenderedImage(RenderedImage image)230   public static ImageTypeSpecifier createFromRenderedImage (RenderedImage image)
231   {
232     if (image == null)
233       throw new IllegalArgumentException ("image null");
234 
235     return new ImageTypeSpecifier (image);
236   }
237 
238   /**
239    * Create a grayscale image type specifier, given the number of
240    * bits, data type and whether or not the data is signed.
241    *
242    * @param bits the number of bits used to specify a greyscale value
243    * @param dataType a DataBuffer type constant
244    * @param isSigned true if this type specifier should support
245    * negative values, false otherwise
246    *
247    * @return a greyscal image type specifier
248    *
249    * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or 16
250    * @exception IllegalArgumentException if dataType is not
251    * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or
252    * DataBuffer.TYPE_USHORT
253    * @exception if bits is larger than the number of bits in the given
254    * data type
255    */
createGrayscale(int bits, int dataType, boolean isSigned)256   public static ImageTypeSpecifier createGrayscale (int bits, int dataType, boolean isSigned)
257   {
258     return createGrayscale (bits, dataType, isSigned, false);
259   }
260 
261   /**
262    * Create a grayscale image type specifier, given the number of
263    * bits, data type and whether or not the data is signed.
264    *
265    * @param bits the number of bits used to specify a greyscale value
266    * @param dataType a DataBuffer type constant
267    * @param isSigned true if this type specifier should support
268    * negative values, false otherwise
269    *
270    * @return a greyscal image type specifier
271    *
272    * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or
273    * 16
274    * @exception IllegalArgumentException if dataType is not
275    * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or
276    * DataBuffer.TYPE_USHORT
277    * @exception if bits is larger than the number of bits in the given
278    * data type
279    */
createGrayscale(int bits, int dataType, boolean isSigned, boolean isAlphaPremultiplied)280   public static ImageTypeSpecifier createGrayscale (int bits, int dataType,
281                                                     boolean isSigned,
282                                                     boolean isAlphaPremultiplied)
283   {
284     if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16)
285       throw new IllegalArgumentException ("invalid bit size");
286 
287     if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT
288         && dataType != DataBuffer.TYPE_USHORT)
289       throw new IllegalArgumentException ("invalid data type");
290 
291     if (dataType == DataBuffer.TYPE_BYTE && bits > 8)
292       throw new IllegalArgumentException ("number of bits too large for data type");
293 
294     // FIXME: this is probably wrong:
295     return new ImageTypeSpecifier (new DirectColorModel (bits, 0xff, 0x0,
296                                                          0x0, 0xff),
297                                    new MultiPixelPackedSampleModel (dataType,
298                                                                     1, 1,
299                                                                     bits));
300   }
301 
302   /**
303    * Return an image type specifier for an image that uses an indexed
304    * colour model where each colour value has the specified number of
305    * bits and type and where the colour tables are those given.
306    *
307    * @param redLUT the red index values
308    * @param greenLUT the green index values
309    * @param blueLUT the blue index values
310    * @param alphaLUT the alpha index values
311    * @param bits the number of bits per index value
312    * @param dataType the type of each index value
313    *
314    * @return an indexed image type specifier
315    *
316    * @exception IllegalArgumentException if any of the colour arrays,
317    * not including alphaLUT, is null
318    * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or
319    * 16
320    * @exception IllegalArgumentException if dataType is not
321    * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or
322    * DataBuffer.TYPE_USHORT
323    * @exception if bits is larger than the number of bits in the given
324    * data type
325    */
createIndexed(byte[] redLUT, byte[] greenLUT, byte[] blueLUT, byte[] alphaLUT, int bits, int dataType)326   public static ImageTypeSpecifier createIndexed (byte[] redLUT,
327                                                   byte[] greenLUT,
328                                                   byte[] blueLUT,
329                                                   byte[] alphaLUT,
330                                                   int bits,
331                                                   int dataType)
332   {
333     if (redLUT == null || greenLUT == null || blueLUT == null)
334       throw new IllegalArgumentException ("null colour table");
335 
336     if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16)
337       throw new IllegalArgumentException ("invalid bit size");
338 
339     if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT
340         && dataType != DataBuffer.TYPE_USHORT)
341       throw new IllegalArgumentException ("invalid data type");
342 
343     if (dataType == DataBuffer.TYPE_BYTE && bits > 8)
344       throw new IllegalArgumentException ("number of bits too large for data type");
345 
346     // FIXME: this is probably wrong:
347     return new ImageTypeSpecifier (new IndexColorModel (bits, redLUT.length,
348                                                         redLUT, greenLUT, blueLUT,
349                                                         alphaLUT),
350                                    new MultiPixelPackedSampleModel (dataType,
351                                                                     1, 1,
352                                                                     bits));
353   }
354 
355   /**
356    * Create an image type specifier that uses a component colour model
357    * and a pixel interleaved sample model.  Each pixel component will
358    * be stored in a separate value of the given data type.
359    *
360    * @param colorSpace the colour space used by the colour model
361    * @param bandOffsets the starting band offset for each band within
362    * its bank
363    * @param dataType the type of each pixel value
364    * @param hasAlpha true if an alpha channel should be specified,
365    * false otherwise
366    * @param isAlphaPremultiplied true if other colour channels should
367    * be premultiplied by the alpha value, false otherwise
368    *
369    * @return an interleaved image type specifier
370    *
371    * @exception IllegalArgumentException if either colorSpace or
372    * bandOffsets is null
373    * @excpetion IllegalArgumentException if the number of color space
374    * components, including the alpha component if requested, is
375    * different from bandOffsets.length
376    * @exception if dataType is not a valid DataBuffer constant
377    */
createInterleaved(ColorSpace colorSpace, int[] bandOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied)378   public static ImageTypeSpecifier createInterleaved (ColorSpace colorSpace,
379                                                       int[] bandOffsets,
380                                                       int dataType,
381                                                       boolean hasAlpha,
382                                                       boolean isAlphaPremultiplied)
383   {
384     if (colorSpace == null || bandOffsets == null)
385       throw new IllegalArgumentException ("null argument");
386 
387     if (bandOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0)))
388       throw new IllegalArgumentException ("invalid bankOffsets length");
389 
390     return new ImageTypeSpecifier (new ComponentColorModel (colorSpace,
391                                                             hasAlpha,
392                                                             isAlphaPremultiplied,
393                                                             hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE,
394                                                             dataType),
395                                    new PixelInterleavedSampleModel (dataType, 1, 1, 1, 1,
396                                                                     bandOffsets));
397   }
398 
399   /**
400    * Create an image type specifier using a direct color model and a
401    * packed sample model.  All pixel components will be packed into
402    * one value of the given data type.
403    *
404    * @param colorSpace the color space to use in the color model
405    * @param redMask the bitmask for the red bits
406    * @param greenMask the bitmask for the green bits
407    * @param blueMask the bitmask for the blue bits
408    * @param alphaMask the bitmask for the alpha bits
409    * @param transferType the data type used to store pixel values
410    * @param isAlphaPremultiplied true if other colour channels should
411    * be premultiplied by the alpha value, false otherwise
412    *
413    * @return a packed image type specifier
414    *
415    * @exception IllegalArgumentException if colorSpace is null
416    * @exception IllegalArgumentException if colorSpace does not have
417    * type ColorSpace.TYPE_RGB
418    * @exception IllegalArgumentException if all masks are 0
419    * @exception IllegalArgumentException if dataType is not
420    * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or
421    * DataBuffer.TYPE_INT
422    */
createPacked(ColorSpace colorSpace, int redMask, int greenMask, int blueMask, int alphaMask, int transferType, boolean isAlphaPremultiplied)423   public static ImageTypeSpecifier createPacked (ColorSpace colorSpace,
424                                                  int redMask,
425                                                  int greenMask,
426                                                  int blueMask,
427                                                  int alphaMask,
428                                                  int transferType,
429                                                  boolean isAlphaPremultiplied)
430   {
431     if (colorSpace == null)
432       throw new IllegalArgumentException ("null color space");
433 
434     if (colorSpace.getType() != ColorSpace.TYPE_RGB)
435       throw new IllegalArgumentException ("invalid color space type");
436 
437     if (redMask == 0 && greenMask == 0 && blueMask == 0 && alphaMask == 0)
438       throw new IllegalArgumentException ("no non-zero mask");
439 
440     if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT
441         && transferType != DataBuffer.TYPE_INT)
442       throw new IllegalArgumentException ("invalid data type");
443 
444     // Assume DataBuffer.TYPE_BYTE.
445     int numBits = 8;
446 
447     if (transferType == DataBuffer.TYPE_SHORT)
448       numBits = 16;
449     else if (transferType == DataBuffer.TYPE_INT)
450       numBits = 32;
451 
452     return new ImageTypeSpecifier (new DirectColorModel (colorSpace,
453                                                          numBits,
454                                                          redMask,
455                                                          greenMask,
456                                                          blueMask,
457                                                          alphaMask,
458                                                          isAlphaPremultiplied,
459                                                          transferType),
460                                    new MultiPixelPackedSampleModel (transferType,
461                                                                     1, 1, numBits));
462   }
463 
464   /**
465    * Get the number of bits per sample in the given band.
466    *
467    * @param band the band from which to get the number of bits
468    *
469    * @return the number of bits in the given band
470    *
471    * @exception IllegalArgumentException if band is out-of-bounds
472    */
getBitsPerBand(int band)473   public int getBitsPerBand (int band)
474   {
475     if (band < 0 || band > sampleModel.getNumBands())
476       throw new IllegalArgumentException ("band out-of-bounds");
477 
478     return sampleModel.getSampleSize (band);
479   }
480 
481   /**
482    * Get the buffered image constant specified by this image type
483    * specifier.
484    *
485    * @return a buffered image constant
486    */
getBufferedImageType()487   public int getBufferedImageType ()
488   {
489     // FIXME:
490     return BufferedImage.TYPE_INT_RGB;
491   }
492 
493   /**
494    * Create a sample model that is compatible with the one specified
495    * by this image type specifier, with the given dimensions.
496    *
497    * @param width the width of the returned sample model
498    * @param height the height of the returned sample model
499    *
500    * @return a sample model compatible with the one in this image type
501    * specifier, with the given dimensions
502    *
503    * @exception IllegalArgumentException if either width or height is
504    * less than or equal to 0
505    * @exception IllegalArgumentException if width * height is greater
506    * than Intere.MAX_VALUE
507    */
getSampleModel(int width, int height)508   public SampleModel getSampleModel (int width, int height)
509   {
510     if (width <= 0 || height <= 0)
511       throw new IllegalArgumentException ("invalid dimension");
512 
513     // test for overflow
514     if (width * height < Math.min (width, height))
515       throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE");
516 
517     return sampleModel.createCompatibleSampleModel (width, height);
518   }
519 
520   /**
521    * Get the color model specified by this image type specifier.
522    *
523    * @return the color model
524    */
getColorModel()525   public ColorModel getColorModel()
526   {
527     return colorModel;
528   }
529 
530   /**
531    * Get the number of bands specified by this image type specifier's
532    * sample model.
533    *
534    * @return the number of bands in the sample model
535    */
getNumBands()536   public int getNumBands()
537   {
538     return sampleModel.getNumBands();
539   }
540 
541   /**
542    * Get the number of components specified by this image type
543    * specifier's color model.
544    *
545    * @return the number of color components per pixel
546    */
getNumComponents()547   public int getNumComponents()
548   {
549     return colorModel.getNumComponents();
550   }
551 
552   /**
553    * Get the sample model specified by this image type specifier.
554    *
555    * @return the sample model
556    */
getSampleModel()557   public SampleModel getSampleModel()
558   {
559     return sampleModel;
560   }
561 }
562