KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > imageio > ImageTypeSpecifier


1 /*
2  * @(#)ImageTypeSpecifier.java 1.34 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.imageio;
9
10 import java.awt.Point JavaDoc;
11 import java.awt.Transparency JavaDoc;
12 import java.awt.image.BandedSampleModel JavaDoc;
13 import java.awt.image.BufferedImage JavaDoc;
14 import java.awt.image.ColorModel JavaDoc;
15 import java.awt.color.ColorSpace JavaDoc;
16 import java.awt.image.IndexColorModel JavaDoc;
17 import java.awt.image.ComponentColorModel JavaDoc;
18 import java.awt.image.DataBuffer JavaDoc;
19 import java.awt.image.DirectColorModel JavaDoc;
20 import java.awt.image.MultiPixelPackedSampleModel JavaDoc;
21 import java.awt.image.PixelInterleavedSampleModel JavaDoc;
22 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
23 import java.awt.image.Raster JavaDoc;
24 import java.awt.image.RenderedImage JavaDoc;
25 import java.awt.image.SampleModel JavaDoc;
26 import java.awt.image.WritableRaster JavaDoc;
27 import java.util.Hashtable JavaDoc;
28
29 /**
30  * A class that allows the format of an image (in particular, its
31  * <code>SampleModel</code> and <code>ColorModel</code>) to be
32  * specified in a convenient manner.
33  *
34  * @version 0.5
35  */

36 public class ImageTypeSpecifier {
37
38     /**
39      * The <code>ColorModel</code> to be used as a prototype.
40      */

41     protected ColorModel JavaDoc colorModel;
42
43     /**
44      * A <code>SampleModel</code> to be used as a prototype.
45      */

46     protected SampleModel JavaDoc sampleModel;
47
48     /**
49      * Cached specifiers for all of the standard
50      * <code>BufferedImage</code> types.
51      */

52     private static ImageTypeSpecifier JavaDoc[] BISpecifier;
53
54     // Initialize the standard specifiers
55
static {
56         ColorSpace JavaDoc sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
57         
58         BISpecifier =
59             new ImageTypeSpecifier JavaDoc[BufferedImage.TYPE_BYTE_INDEXED + 1];
60
61         BISpecifier[BufferedImage.TYPE_CUSTOM] = null;
62
63         BISpecifier[BufferedImage.TYPE_INT_RGB] =
64             createPacked(sRGB,
65                          0x00ff0000,
66                          0x0000ff00,
67                          0x000000ff,
68                          0x0,
69                          DataBuffer.TYPE_INT,
70                          false);
71
72         BISpecifier[BufferedImage.TYPE_INT_ARGB] =
73             createPacked(sRGB,
74                          0x00ff0000,
75                          0x0000ff00,
76                          0x000000ff,
77                          0xff000000,
78                          DataBuffer.TYPE_INT,
79                          false);
80
81         BISpecifier[BufferedImage.TYPE_INT_ARGB_PRE] =
82             createPacked(sRGB,
83                          0x00ff0000,
84                          0x0000ff00,
85                          0x000000ff,
86                          0xff000000,
87                          DataBuffer.TYPE_INT,
88                          true);
89
90         BISpecifier[BufferedImage.TYPE_INT_BGR] =
91             createPacked(sRGB,
92                          0x000000ff,
93                          0x0000ff00,
94                          0x00ff0000,
95                          0x0,
96                          DataBuffer.TYPE_INT,
97                          false);
98
99         int[] bOffsRGB = { 2, 1, 0 };
100         BISpecifier[BufferedImage.TYPE_3BYTE_BGR] =
101             createInterleaved(sRGB,
102                               bOffsRGB,
103                               DataBuffer.TYPE_BYTE,
104                               false,
105                               false);
106
107         int[] bOffsABGR = { 3, 2, 1, 0 };
108         BISpecifier[BufferedImage.TYPE_4BYTE_ABGR] =
109             createInterleaved(sRGB,
110                               bOffsABGR,
111                               DataBuffer.TYPE_BYTE,
112                               true,
113                               false);
114         
115         BISpecifier[BufferedImage.TYPE_4BYTE_ABGR_PRE] =
116             createInterleaved(sRGB,
117                               bOffsABGR,
118                               DataBuffer.TYPE_BYTE,
119                               true,
120                               true);
121
122         BISpecifier[BufferedImage.TYPE_USHORT_565_RGB] =
123             createPacked(sRGB,
124                          0xF800,
125                          0x07E0,
126                          0x001F,
127                          0x0,
128                          DataBuffer.TYPE_USHORT,
129                          false);
130
131         BISpecifier[BufferedImage.TYPE_USHORT_555_RGB] =
132             createPacked(sRGB,
133                          0x7C00,
134                          0x03E0,
135                          0x001F,
136                          0x0,
137                          DataBuffer.TYPE_USHORT,
138                          false);
139
140         BISpecifier[BufferedImage.TYPE_BYTE_GRAY] =
141             createGrayscale(8,
142                             DataBuffer.TYPE_BYTE,
143                             false);
144         
145         BISpecifier[BufferedImage.TYPE_USHORT_GRAY] =
146             createGrayscale(16,
147                             DataBuffer.TYPE_USHORT,
148                             false);
149
150         BISpecifier[BufferedImage.TYPE_BYTE_BINARY] =
151             createGrayscale(1,
152                             DataBuffer.TYPE_BYTE,
153                             false);
154
155         BufferedImage JavaDoc bi =
156             new BufferedImage JavaDoc(1, 1, BufferedImage.TYPE_BYTE_INDEXED);
157         IndexColorModel JavaDoc icm = (IndexColorModel JavaDoc)bi.getColorModel();
158         int mapSize = icm.getMapSize();
159         byte[] redLUT = new byte[mapSize];
160         byte[] greenLUT = new byte[mapSize];
161         byte[] blueLUT = new byte[mapSize];
162         byte[] alphaLUT = new byte[mapSize];
163
164         icm.getReds(redLUT);
165         icm.getGreens(greenLUT);
166         icm.getBlues(blueLUT);
167         icm.getAlphas(alphaLUT);
168
169         BISpecifier[BufferedImage.TYPE_BYTE_INDEXED] =
170             createIndexed(redLUT, greenLUT, blueLUT, alphaLUT,
171                           8,
172                           DataBuffer.TYPE_BYTE);
173     }
174
175     /**
176      * A constructor to be used by inner subclasses only.
177      */

178     private ImageTypeSpecifier() {}
179
180     /**
181      * Constructs an <code>ImageTypeSpecifier</code> directly
182      * from a <code>ColorModel</code> and a <code>SampleModel</code>.
183      * It is the caller's responsibility to supply compatible
184      * parameters.
185      *
186      * @param colorModel a <code>ColorModel</code>.
187      * @param sampleModel a <code>SampleModel</code>.
188      *
189      * @exception IllegalArgumentException if either parameter is
190      * <code>null</code>.
191      * @exception IllegalArgumentException if <code>sampleModel</code>
192      * is not compatible with <code>colorModel</code>.
193      */

194     public ImageTypeSpecifier(ColorModel JavaDoc colorModel, SampleModel JavaDoc sampleModel) {
195         if (colorModel == null) {
196             throw new IllegalArgumentException JavaDoc("colorModel == null!");
197         }
198         if (sampleModel == null) {
199             throw new IllegalArgumentException JavaDoc("sampleModel == null!");
200         }
201         if (!colorModel.isCompatibleSampleModel(sampleModel)) {
202             throw new IllegalArgumentException JavaDoc
203                 ("sampleModel is incompatible with colorModel!");
204         }
205         this.colorModel = colorModel;
206         this.sampleModel = sampleModel;
207     }
208
209     /**
210      * Constructs an <code>ImageTypeSpecifier</code> from a
211      * <code>RenderedImage</code>. If a <code>BufferedImage</code> is
212      * being used, one of the factory methods
213      * <code>createFromRenderedImage</code> or
214      * <code>createFromBufferedImageType</code> should be used instead in
215      * order to get a more accurate result.
216      *
217      * @param image a <code>RenderedImage</code>.
218      *
219      * @exception IllegalArgumentException if the argument is
220      * <code>null</code>.
221      */

222     public ImageTypeSpecifier(RenderedImage JavaDoc image) {
223         if (image == null) {
224             throw new IllegalArgumentException JavaDoc("image == null!");
225         }
226         colorModel = image.getColorModel();
227         sampleModel = image.getSampleModel();
228     }
229
230     // Packed
231

232     static class Packed extends ImageTypeSpecifier JavaDoc {
233         ColorSpace JavaDoc colorSpace;
234         int redMask;
235         int greenMask;
236         int blueMask;
237         int alphaMask;
238         int transferType;
239         boolean isAlphaPremultiplied;
240
241         public Packed(ColorSpace JavaDoc colorSpace,
242                       int redMask,
243                       int greenMask,
244                       int blueMask,
245                       int alphaMask, // 0 if no alpha
246
int transferType,
247                       boolean isAlphaPremultiplied) {
248             if (colorSpace == null) {
249                 throw new IllegalArgumentException JavaDoc("colorSpace == null!");
250             }
251             if (colorSpace.getType() != ColorSpace.TYPE_RGB) {
252                 throw new IllegalArgumentException JavaDoc
253                     ("colorSpace is not of type TYPE_RGB!");
254             }
255             if (transferType != DataBuffer.TYPE_BYTE &&
256                 transferType != DataBuffer.TYPE_USHORT &&
257                 transferType != DataBuffer.TYPE_INT) {
258                 throw new IllegalArgumentException JavaDoc
259                     ("Bad value for transferType!");
260             }
261             if (redMask == 0 && greenMask == 0 &&
262                 blueMask == 0 && alphaMask == 0) {
263                 throw new IllegalArgumentException JavaDoc
264                     ("No mask has at least 1 bit set!");
265             }
266             this.colorSpace = colorSpace;
267             this.redMask = redMask;
268             this.greenMask = greenMask;
269             this.blueMask = blueMask;
270             this.alphaMask = alphaMask;
271             this.transferType = transferType;
272             this.isAlphaPremultiplied = isAlphaPremultiplied;
273
274             int bits = 32;
275             this.colorModel =
276                 new DirectColorModel JavaDoc(colorSpace,
277                                      bits,
278                                      redMask, greenMask, blueMask,
279                                      alphaMask, isAlphaPremultiplied,
280                                      transferType);
281             this.sampleModel = colorModel.createCompatibleSampleModel(1, 1);
282         }
283     }
284
285     /**
286      * Returns a specifier for a packed image format that will use a
287      * <code>DirectColorModel</code> and a packed
288      * <code>SampleModel</code> to store each pixel packed into in a
289      * single byte, short, or int.
290      *
291      * @param colorSpace the desired <code>ColorSpace</code>.
292      * @param redMask a contiguous mask indicated the position of the
293      * red channel.
294      * @param greenMask a contiguous mask indicated the position of the
295      * green channel.
296      * @param blueMask a contiguous mask indicated the position of the
297      * blue channel.
298      * @param alphaMask a contiguous mask indicated the position of the
299      * alpha channel.
300      * @param transferType the desired <code>SampleModel</code> transfer type.
301      * @param isAlphaPremultiplied <code>true</code> if the color channels
302      * will be premultipled by the alpha channel.
303      *
304      * @return an <code>ImageTypeSpecifier</code> with the desired
305      * characteristics.
306      *
307      * @exception IllegalArgumentException if <code>colorSpace</code>
308      * is <code>null</code>.
309      * @exception IllegalArgumentException if <code>colorSpace</code>
310      * is not of type <code>TYPE_RGB</code>.
311      * @exception IllegalArgumentException if no mask has at least 1
312      * bit set.
313      * @exception IllegalArgumentException if
314      * <code>transferType</code> if not one of
315      * <code>DataBuffer.TYPE_BYTE</code>,
316      * <code>DataBuffer.TYPE_USHORT</code>, or
317      * <code>DataBuffer.TYPE_INT</code>.
318      */

319     public static ImageTypeSpecifier JavaDoc
320         createPacked(ColorSpace JavaDoc colorSpace,
321                      int redMask,
322                      int greenMask,
323                      int blueMask,
324                      int alphaMask, // 0 if no alpha
325
int transferType,
326                      boolean isAlphaPremultiplied) {
327         return new ImageTypeSpecifier.Packed JavaDoc(colorSpace,
328                                              redMask,
329                                              greenMask,
330                                              blueMask,
331                                              alphaMask, // 0 if no alpha
332
transferType,
333                                              isAlphaPremultiplied);
334     }
335
336     static ColorModel JavaDoc createComponentCM(ColorSpace JavaDoc colorSpace,
337                                         int numBands,
338                                         int dataType,
339                                         boolean hasAlpha,
340                                         boolean isAlphaPremultiplied) {
341         int transparency =
342             hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
343         
344         int[] numBits = new int[numBands];
345         int bits = DataBuffer.getDataTypeSize(dataType);
346
347         for (int i = 0; i < numBands; i++) {
348             numBits[i] = bits;
349         }
350         
351         return new ComponentColorModel JavaDoc(colorSpace,
352                                        numBits,
353                                        hasAlpha,
354                                        isAlphaPremultiplied,
355                                        transparency,
356                                        dataType);
357     }
358
359     // Interleaved
360

361     static class Interleaved extends ImageTypeSpecifier JavaDoc {
362         ColorSpace JavaDoc colorSpace;
363         int[] bandOffsets;
364         int dataType;
365         boolean hasAlpha;
366         boolean isAlphaPremultiplied;
367
368         public Interleaved(ColorSpace JavaDoc colorSpace,
369                            int[] bandOffsets,
370                            int dataType,
371                            boolean hasAlpha,
372                            boolean isAlphaPremultiplied) {
373             if (colorSpace == null) {
374                 throw new IllegalArgumentException JavaDoc("colorSpace == null!");
375             }
376             if (bandOffsets == null) {
377                 throw new IllegalArgumentException JavaDoc("bandOffsets == null!");
378             }
379             int numBands = colorSpace.getNumComponents() +
380                 (hasAlpha ? 1 : 0);
381             if (bandOffsets.length != numBands) {
382                 throw new IllegalArgumentException JavaDoc
383                     ("bandOffsets.length is wrong!");
384             }
385             if (dataType != DataBuffer.TYPE_BYTE &&
386                 dataType != DataBuffer.TYPE_SHORT &&
387                 dataType != DataBuffer.TYPE_USHORT &&
388                 dataType != DataBuffer.TYPE_INT &&
389                 dataType != DataBuffer.TYPE_FLOAT &&
390                 dataType != DataBuffer.TYPE_DOUBLE) {
391                 throw new IllegalArgumentException JavaDoc
392                     ("Bad value for dataType!");
393             }
394             this.colorSpace = colorSpace;
395             this.bandOffsets = (int[])bandOffsets.clone();
396             this.dataType = dataType;
397             this.hasAlpha = hasAlpha;
398             this.isAlphaPremultiplied = isAlphaPremultiplied;
399
400             this.colorModel =
401                 ImageTypeSpecifier.createComponentCM(colorSpace,
402                                                      bandOffsets.length,
403                                                      dataType,
404                                                      hasAlpha,
405                                                      isAlphaPremultiplied);
406             
407             int minBandOffset = bandOffsets[0];
408             int maxBandOffset = minBandOffset;
409             for (int i = 0; i < bandOffsets.length; i++) {
410                 int offset = bandOffsets[i];
411                 minBandOffset = Math.min(offset, minBandOffset);
412                 maxBandOffset = Math.max(offset, maxBandOffset);
413             }
414             int pixelStride = maxBandOffset - minBandOffset + 1;
415             
416             int w = 1;
417             int h = 1;
418             this.sampleModel =
419                 new PixelInterleavedSampleModel JavaDoc(dataType,
420                                                 w, h,
421                                                 pixelStride,
422                                                 w*pixelStride,
423                                                 bandOffsets);
424         }
425
426         public boolean equals(Object JavaDoc o) {
427             if ((o == null) ||
428                 !(o instanceof ImageTypeSpecifier.Interleaved JavaDoc)) {
429                 return false;
430             }
431
432             ImageTypeSpecifier.Interleaved JavaDoc that =
433                 (ImageTypeSpecifier.Interleaved JavaDoc)o;
434
435             if ((!(this.colorSpace.equals(that.colorSpace))) ||
436                 (this.dataType != that.dataType) ||
437                 (this.hasAlpha != that.hasAlpha) ||
438                 (this.isAlphaPremultiplied != that.isAlphaPremultiplied) ||
439                 (this.bandOffsets.length != that.bandOffsets.length)) {
440                 return false;
441             }
442
443             for (int i = 0; i < bandOffsets.length; i++) {
444                 if (this.bandOffsets[i] != that.bandOffsets[i]) {
445                     return false;
446                 }
447             }
448
449             return true;
450         }
451
452         public int hashCode() {
453             return (super.hashCode() +
454                     (4 * bandOffsets.length) +
455                     (25 * dataType) +
456                     (hasAlpha ? 17 : 18));
457         }
458     }
459
460     /**
461      * Returns a specifier for an interleaved image format that will
462      * use a <code>ComponentColorModel</code> and a
463      * <code>PixelInterleavedSampleModel</code> to store each pixel
464      * component in a separate byte, short, or int.
465      *
466      * @param colorSpace the desired <code>ColorSpace</code>.
467      * @param bandOffsets an array of <code>int</code>s indicating the
468      * offsets for each band.
469      * @param dataType the desired data type, as one of the enumerations
470      * from the <code>DataBuffer</code> class.
471      * @param hasAlpha <code>true</code> if an alpha channel is desired.
472      * @param isAlphaPremultiplied <code>true</code> if the color channels
473      * will be premultipled by the alpha channel.
474      *
475      * @return an <code>ImageTypeSpecifier</code> with the desired
476      * characteristics.
477      *
478      * @exception IllegalArgumentException if <code>colorSpace</code>
479      * is <code>null</code>.
480      * @exception IllegalArgumentException if <code>bandOffsets</code>
481      * is <code>null</code>.
482      * @exception IllegalArgumentException if <code>dataType</code> is
483      * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
484      * @exception IllegalArgumentException if
485      * <code>bandOffsets.length</code> does not equal the number of
486      * color space components, plus 1 if <code>hasAlpha</code> is
487      * <code>true</code>.
488      */

489     public static ImageTypeSpecifier JavaDoc
490         createInterleaved(ColorSpace JavaDoc colorSpace,
491                           int[] bandOffsets,
492                           int dataType,
493                           boolean hasAlpha,
494                           boolean isAlphaPremultiplied) {
495         return new ImageTypeSpecifier.Interleaved JavaDoc(colorSpace,
496                                                   bandOffsets,
497                                                   dataType,
498                                                   hasAlpha,
499                                                   isAlphaPremultiplied);
500     }
501
502     // Banded
503

504     static class Banded extends ImageTypeSpecifier JavaDoc {
505         ColorSpace JavaDoc colorSpace;
506         int[] bankIndices;
507         int[] bandOffsets;
508         int dataType;
509         boolean hasAlpha;
510         boolean isAlphaPremultiplied;
511
512         public Banded(ColorSpace JavaDoc colorSpace,
513                       int[] bankIndices,
514                       int[] bandOffsets,
515                       int dataType,
516                       boolean hasAlpha,
517                       boolean isAlphaPremultiplied) {
518             if (colorSpace == null) {
519                 throw new IllegalArgumentException JavaDoc("colorSpace == null!");
520             }
521             if (bankIndices == null) {
522                 throw new IllegalArgumentException JavaDoc("bankIndices == null!");
523             }
524             if (bandOffsets == null) {
525                 throw new IllegalArgumentException JavaDoc("bandOffsets == null!");
526             }
527             if (bankIndices.length != bandOffsets.length) {
528                 throw new IllegalArgumentException JavaDoc
529                     ("bankIndices.length != bandOffsets.length!");
530             }
531             if (dataType != DataBuffer.TYPE_BYTE &&
532                 dataType != DataBuffer.TYPE_SHORT &&
533                 dataType != DataBuffer.TYPE_USHORT &&
534                 dataType != DataBuffer.TYPE_INT &&
535                 dataType != DataBuffer.TYPE_FLOAT &&
536                 dataType != DataBuffer.TYPE_DOUBLE) {
537                 throw new IllegalArgumentException JavaDoc
538                     ("Bad value for dataType!");
539             }
540             int numBands = colorSpace.getNumComponents() +
541                 (hasAlpha ? 1 : 0);
542             if (bandOffsets.length != numBands) {
543                 throw new IllegalArgumentException JavaDoc
544                     ("bandOffsets.length is wrong!");
545             }
546            
547             this.colorSpace = colorSpace;
548             this.bankIndices = (int[])bankIndices.clone();
549             this.bandOffsets = (int[])bandOffsets.clone();
550             this.dataType = dataType;
551             this.hasAlpha = hasAlpha;
552             this.isAlphaPremultiplied = isAlphaPremultiplied;
553
554             this.colorModel =
555                 ImageTypeSpecifier.createComponentCM(colorSpace,
556                                                      bankIndices.length,
557                                                      dataType,
558                                                      hasAlpha,
559                                                      isAlphaPremultiplied);
560
561             int w = 1;
562             int h = 1;
563             this.sampleModel = new BandedSampleModel JavaDoc(dataType,
564                                                      w, h,
565                                                      w,
566                                                      bankIndices,
567                                                      bandOffsets);
568         }
569
570         public boolean equals(Object JavaDoc o) {
571             if ((o == null) ||
572                 !(o instanceof ImageTypeSpecifier.Banded JavaDoc)) {
573                 return false;
574             }
575
576             ImageTypeSpecifier.Banded JavaDoc that =
577                 (ImageTypeSpecifier.Banded JavaDoc)o;
578
579             if ((!(this.colorSpace.equals(that.colorSpace))) ||
580                 (this.dataType != that.dataType) ||
581                 (this.hasAlpha != that.hasAlpha) ||
582                 (this.isAlphaPremultiplied != that.isAlphaPremultiplied) ||
583                 (this.bankIndices.length != that.bankIndices.length) ||
584                 (this.bandOffsets.length != that.bandOffsets.length)) {
585                 return false;
586             }
587
588             for (int i = 0; i < bankIndices.length; i++) {
589                 if (this.bankIndices[i] != that.bankIndices[i]) {
590                     return false;
591                 }
592             }
593
594             for (int i = 0; i < bandOffsets.length; i++) {
595                 if (this.bandOffsets[i] != that.bandOffsets[i]) {
596                     return false;
597                 }
598             }
599
600             return true;
601         }
602
603         public int hashCode() {
604             return (super.hashCode() +
605                     (3 * bandOffsets.length) +
606                     (7 * bankIndices.length) +
607                     (21 * dataType) +
608                     (hasAlpha ? 19 : 29));
609         }
610     }
611
612     /**
613      * Returns a specifier for a banded image format that will use a
614      * <code>ComponentColorModel</code> and a
615      * <code>BandedSampleModel</code> to store each channel in a
616      * separate array.
617      *
618      * @param colorSpace the desired <code>ColorSpace</code>.
619      * @param bankIndices an array of <code>int</code>s indicating the
620      * bank in which each band will be stored.
621      * @param bandOffsets an array of <code>int</code>s indicating the
622      * starting offset of each band within its bank.
623      * @param dataType the desired data type, as one of the enumerations
624      * from the <code>DataBuffer</code> class.
625      * @param hasAlpha <code>true</code> if an alpha channel is desired.
626      * @param isAlphaPremultiplied <code>true</code> if the color channels
627      * will be premultipled by the alpha channel.
628      *
629      * @return an <code>ImageTypeSpecifier</code> with the desired
630      * characteristics.
631      *
632      * @exception IllegalArgumentException if <code>colorSpace</code>
633      * is <code>null</code>.
634      * @exception IllegalArgumentException if <code>bankIndices</code>
635      * is <code>null</code>.
636      * @exception IllegalArgumentException if <code>bandOffsets</code>
637      * is <code>null</code>.
638      * @exception IllegalArgumentException if the lengths of
639      * <code>bankIndices</code> and <code>bandOffsets</code> differ.
640      * @exception IllegalArgumentException if
641      * <code>bandOffsets.length</code> does not equal the number of
642      * color space components, plus 1 if <code>hasAlpha</code> is
643      * <code>true</code>.
644      * @exception IllegalArgumentException if <code>dataType</code> is
645      * not one of the legal <code>DataBuffer.TYPE_*</code> constants.
646      */

647     public static ImageTypeSpecifier JavaDoc
648         createBanded(ColorSpace JavaDoc colorSpace,
649                      int[] bankIndices,
650                      int[] bandOffsets,
651                      int dataType,
652                      boolean hasAlpha,
653                      boolean isAlphaPremultiplied) {
654         return new ImageTypeSpecifier.Banded JavaDoc(colorSpace,
655                                              bankIndices,
656                                              bandOffsets,
657                                              dataType,
658                                              hasAlpha,
659                                              isAlphaPremultiplied);
660     }
661
662     // Grayscale
663

664     static class Grayscale extends ImageTypeSpecifier JavaDoc {
665         int bits;
666         int dataType;
667         boolean isSigned;
668         boolean hasAlpha;
669         boolean isAlphaPremultiplied;
670
671         public Grayscale(int bits,
672                          int dataType,
673                          boolean isSigned,
674                          boolean hasAlpha,
675                          boolean isAlphaPremultiplied)
676         {
677             if (bits != 1 && bits != 2 && bits != 4 &&
678                 bits != 8 && bits != 16)
679             {
680                 throw new IllegalArgumentException JavaDoc("Bad value for bits!");
681             }
682             if (dataType != DataBuffer.TYPE_BYTE &&
683                 dataType != DataBuffer.TYPE_SHORT &&
684                 dataType != DataBuffer.TYPE_USHORT)
685             {
686                 throw new IllegalArgumentException JavaDoc
687                     ("Bad value for dataType!");
688             }
689             if (bits > 8 && dataType == DataBuffer.TYPE_BYTE) {
690                 throw new IllegalArgumentException JavaDoc
691                     ("Too many bits for dataType!");
692             }
693
694             this.bits = bits;
695             this.dataType = dataType;
696             this.isSigned = isSigned;
697             this.hasAlpha = hasAlpha;
698             this.isAlphaPremultiplied = isAlphaPremultiplied;
699
700             ColorSpace JavaDoc colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
701
702             if ((bits == 8 && dataType == DataBuffer.TYPE_BYTE) ||
703                 (bits == 16 &&
704                  (dataType == DataBuffer.TYPE_SHORT ||
705                   dataType == DataBuffer.TYPE_USHORT))) {
706                 // Use component color model & sample model
707

708                 int numBands = hasAlpha ? 2 : 1;
709                 int transparency =
710                     hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
711                 
712
713                 int[] nBits = new int[numBands];
714                 nBits[0] = bits;
715                 if (numBands == 2) {
716                     nBits[1] = bits;
717                 }
718                 this.colorModel =
719                     new ComponentColorModel JavaDoc(colorSpace,
720                                             nBits,
721                                             hasAlpha,
722                                             isAlphaPremultiplied,
723                                             transparency,
724                                             dataType);
725
726                 int[] bandOffsets = new int[numBands];
727                 bandOffsets[0] = 0;
728                 if (numBands == 2) {
729                     bandOffsets[1] = 1;
730                 }
731
732                 int w = 1;
733                 int h = 1;
734                 this.sampleModel =
735                     new PixelInterleavedSampleModel JavaDoc(dataType,
736                                                     w, h,
737                                                     numBands, w*numBands,
738                                                     bandOffsets);
739             } else {
740                 int numEntries = 1 << bits;
741                 byte[] arr = new byte[numEntries];
742                 for (int i = 0; i < numEntries; i++) {
743                     arr[i] = (byte)(i*255/(numEntries - 1));
744                 }
745                 this.colorModel =
746                     new IndexColorModel JavaDoc(bits, numEntries, arr, arr, arr);
747                 
748                 this.sampleModel =
749                     new MultiPixelPackedSampleModel JavaDoc(dataType, 1, 1, bits);
750             }
751         }
752     }
753
754     /**
755      * Returns a specifier for a grayscale image format that will pack
756      * pixels of the given bit depth into array elements of
757      * the specified data type.
758      *
759      * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
760      * @param dataType the desired data type, as one of the enumerations
761      * from the <code>DataBuffer</code> class.
762      * @param isSigned <code>true</code> if negative values are to
763      * be represented.
764      *
765      * @return an <code>ImageTypeSpecifier</code> with the desired
766      * characteristics.
767      *
768      * @exception IllegalArgumentException if <code>bits</code> is
769      * not one of 1, 2, 4, 8, or 16.
770      * @exception IllegalArgumentException if <code>dataType</code> is
771      * not one of <code>DataBuffer.TYPE_BYTE</code>,
772      * <code>DataBuffer.TYPE_SHORT</code>, or
773      * <code>DataBuffer.TYPE_USHORT</code>.
774      * @exception IllegalArgumentException if <code>bits</code> is
775      * larger than the bit size of the given <code>dataType</code>.
776      */

777     public static ImageTypeSpecifier JavaDoc
778         createGrayscale(int bits,
779                         int dataType,
780                         boolean isSigned) {
781         return new ImageTypeSpecifier.Grayscale JavaDoc(bits,
782                                                 dataType,
783                                                 isSigned,
784                                                 false,
785                                                 false);
786     }
787
788     /**
789      * Returns a specifier for a grayscale plus alpha image format
790      * that will pack pixels of the given bit depth into array
791      * elements of the specified data type.
792      *
793      * @param bits the number of bits per gray value (1, 2, 4, 8, or 16).
794      * @param dataType the desired data type, as one of the enumerations
795      * from the <code>DataBuffer</code> class.
796      * @param isSigned <code>true</code> if negative values are to
797      * be represented.
798      * @param isAlphaPremultiplied <code>true</code> if the luminance channel
799      * will be premultipled by the alpha channel.
800      *
801      * @return an <code>ImageTypeSpecifier</code> with the desired
802      * characteristics.
803      *
804      * @exception IllegalArgumentException if <code>bits</code> is
805      * not one of 1, 2, 4, 8, or 16.
806      * @exception IllegalArgumentException if <code>dataType</code> is
807      * not one of <code>DataBuffer.TYPE_BYTE</code>,
808      * <code>DataBuffer.TYPE_SHORT</code>, or
809      * <code>DataBuffer.TYPE_USHORT</code>.
810      * @exception IllegalArgumentException if <code>bits</code> is
811      * larger than the bit size of the given <code>dataType</code>.
812      */

813     public static ImageTypeSpecifier JavaDoc
814         createGrayscale(int bits,
815                         int dataType,
816                         boolean isSigned,
817                         boolean isAlphaPremultiplied) {
818         return new ImageTypeSpecifier.Grayscale JavaDoc(bits,
819                                                 dataType,
820                                                 isSigned,
821                                                 true,
822                                                 isAlphaPremultiplied);
823     }
824
825     // Indexed
826

827     static class Indexed extends ImageTypeSpecifier JavaDoc {
828         byte[] redLUT;
829         byte[] greenLUT;
830         byte[] blueLUT;
831         byte[] alphaLUT = null;
832         int bits;
833         int dataType;
834
835         public Indexed(byte[] redLUT,
836                        byte[] greenLUT,
837                        byte[] blueLUT,
838                        byte[] alphaLUT,
839                        int bits,
840                        int dataType) {
841             if (redLUT == null || greenLUT == null || blueLUT == null) {
842                 throw new IllegalArgumentException JavaDoc("LUT is null!");
843             }
844             if (bits != 1 && bits != 2 && bits != 4 &&
845                 bits != 8 && bits != 16) {
846                 throw new IllegalArgumentException JavaDoc("Bad value for bits!");
847             }
848             if (dataType != DataBuffer.TYPE_BYTE &&
849                 dataType != DataBuffer.TYPE_SHORT &&
850                 dataType != DataBuffer.TYPE_USHORT &&
851                 dataType != DataBuffer.TYPE_INT) {
852                 throw new IllegalArgumentException JavaDoc
853                     ("Bad value for dataType!");
854             }
855             if ((bits > 8 && dataType == DataBuffer.TYPE_BYTE) ||
856                 (bits > 16 && dataType != DataBuffer.TYPE_INT)) {
857                 throw new IllegalArgumentException JavaDoc
858                     ("Too many bits for dataType!");
859             }
860                 
861             int len = 1 << bits;
862             if (redLUT.length != len ||
863                 greenLUT.length != len ||
864                 blueLUT.length != len ||
865                 (alphaLUT != null && alphaLUT.length != len)) {
866                 throw new IllegalArgumentException JavaDoc("LUT has improper length!");
867             }
868             this.redLUT = (byte[])redLUT.clone();
869             this.greenLUT = (byte[])greenLUT.clone();
870             this.blueLUT = (byte[])blueLUT.clone();
871             if (alphaLUT != null) {
872                 this.alphaLUT = (byte[])alphaLUT.clone();
873             }
874             this.bits = bits;
875             this.dataType = dataType;
876             
877             if (alphaLUT == null) {
878                 this.colorModel = new IndexColorModel JavaDoc(bits,
879                                                       redLUT.length,
880                                                       redLUT,
881                                                       greenLUT,
882                                                       blueLUT);
883             } else {
884                 this.colorModel = new IndexColorModel JavaDoc(bits,
885                                                       redLUT.length,
886                                                       redLUT,
887                                                       greenLUT,
888                                                       blueLUT,
889                                                       alphaLUT);
890             }
891             
892             if ((bits == 8 && dataType == DataBuffer.TYPE_BYTE) ||
893                 (bits == 16 &&
894                  (dataType == DataBuffer.TYPE_SHORT ||
895                   dataType == DataBuffer.TYPE_USHORT))) {
896                 int[] bandOffsets = { 0 };
897                 this.sampleModel =
898                     new PixelInterleavedSampleModel JavaDoc(dataType,
899                                                     1, 1, 1, 1,
900                                                     bandOffsets);
901             } else {
902                 this.sampleModel =
903                     new MultiPixelPackedSampleModel JavaDoc(dataType, 1, 1, bits);
904             }
905         }
906     }
907
908     /**
909      * Returns a specifier for an indexed-color image format that will pack
910      * index values of the given bit depth into array elements of
911      * the specified data type.
912      *
913      * @param redLUT an array of <code>byte</code>s containing
914      * the red values for each index.
915      * @param greenLUT an array of <code>byte</code>s containing * the
916      * green values for each index.
917      * @param blueLUT an array of <code>byte</code>s containing the
918      * blue values for each index.
919      * @param alphaLUT an array of <code>byte</code>s containing the
920      * alpha values for each index, or <code>null</code> to create a
921      * fully opaque LUT.
922      * @param bits the number of bits in each index.
923      * @param dataType the desired output type, as one of the enumerations
924      * from the <code>DataBuffer</code> class.
925      *
926      * @return an <code>ImageTypeSpecifier</code> with the desired
927      * characteristics.
928      *
929      * @exception IllegalArgumentException if <code>redLUT</code> is
930      * <code>null</code>.
931      * @exception IllegalArgumentException if <code>greenLUT</code> is
932      * <code>null</code>.
933      * @exception IllegalArgumentException if <code>blueLUT</code> is
934      * <code>null</code>.
935      * @exception IllegalArgumentException if <code>bits</code> is
936      * not one of 1, 2, 4, 8, or 16.
937      * @exception IllegalArgumentException if the
938      * non-<code>null</code> LUT parameters do not have lengths of
939      * exactly <code>1 << bits</code>.
940      * @exception IllegalArgumentException if <code>dataType</code> is
941      * not one of <code>DataBuffer.TYPE_BYTE</code>,
942      * <code>DataBuffer.TYPE_SHORT</code>,
943      * <code>DataBuffer.TYPE_USHORT</code>,
944      * or <code>DataBuffer.TYPE_INT</code>.
945      * @exception IllegalArgumentException if <code>bits</code> is
946      * larger than the bit size of the given <code>dataType</code>.
947      */

948     public static ImageTypeSpecifier JavaDoc
949         createIndexed(byte[] redLUT,
950                       byte[] greenLUT,
951                       byte[] blueLUT,
952                       byte[] alphaLUT,
953                       int bits,
954                       int dataType) {
955         return new ImageTypeSpecifier.Indexed JavaDoc(redLUT,
956                                               greenLUT,
957                                               blueLUT,
958                                               alphaLUT,
959                                               bits,
960                                               dataType);
961     }
962
963     /**
964      * Returns an <code>ImageTypeSpecifier</code> that encodes
965      * one of the standard <code>BufferedImage</code> types
966      * (other than <code>TYPE_CUSTOM</code>).
967      *
968      * @param bufferedImageType an int representing one of the standard
969      * <code>BufferedImage</code> types.
970      *
971      * @return an <code>ImageTypeSpecifier</code> with the desired
972      * characteristics.
973      *
974      * @exception IllegalArgumentException if
975      * <code>bufferedImageType</code> is not one of the standard
976      * types, or is equal to <code>TYPE_CUSTOM</code>.
977      *
978      * @see java.awt.image.BufferedImage
979      * @see java.awt.image.BufferedImage#TYPE_INT_RGB
980      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
981      * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
982      * @see java.awt.image.BufferedImage#TYPE_INT_BGR
983      * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
984      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
985      * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
986      * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
987      * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
988      * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
989      * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
990      * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
991      * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
992      */

993     public static
994         ImageTypeSpecifier JavaDoc createFromBufferedImageType(int bufferedImageType) {
995         if (bufferedImageType >= BufferedImage.TYPE_INT_RGB &&
996             bufferedImageType <= BufferedImage.TYPE_BYTE_INDEXED) {
997             return BISpecifier[bufferedImageType];
998         } else if (bufferedImageType == BufferedImage.TYPE_CUSTOM) {
999             throw new IllegalArgumentException JavaDoc("Cannot create from TYPE_CUSTOM!");
1000        } else {
1001            throw new IllegalArgumentException JavaDoc("Invalid BufferedImage type!");
1002        }
1003    }
1004
1005    /**
1006     * Returns an <code>ImageTypeSpecifier</code> that encodes the
1007     * layout of a <code>RenderedImage</code> (which may be a
1008     * <code>BufferedImage</code>).
1009     *
1010     * @param image a <code>RenderedImage</code>.
1011     *
1012     * @return an <code>ImageTypeSpecifier</code> with the desired
1013     * characteristics.
1014     *
1015     * @exception IllegalArgumentException if <code>image</code> is
1016     * <code>null</code>.
1017     */

1018    public static
1019        ImageTypeSpecifier JavaDoc createFromRenderedImage(RenderedImage JavaDoc image) {
1020        if (image == null) {
1021            throw new IllegalArgumentException JavaDoc("image == null!");
1022        }
1023
1024        if (image instanceof BufferedImage JavaDoc) {
1025            int bufferedImageType = ((BufferedImage JavaDoc)image).getType();
1026            if (bufferedImageType != BufferedImage.TYPE_CUSTOM) {
1027                return BISpecifier[bufferedImageType];
1028            }
1029        }
1030        
1031        return new ImageTypeSpecifier JavaDoc(image);
1032    }
1033
1034    /**
1035     * Returns an int containing one of the enumerated constant values
1036     * describing image formats from <code>BufferedImage</code>.
1037     *
1038     * @return an <code>int</code> representing a
1039     * <code>BufferedImage</code> type.
1040     *
1041     * @see java.awt.image.BufferedImage
1042     * @see java.awt.image.BufferedImage#TYPE_CUSTOM
1043     * @see java.awt.image.BufferedImage#TYPE_INT_RGB
1044     * @see java.awt.image.BufferedImage#TYPE_INT_ARGB
1045     * @see java.awt.image.BufferedImage#TYPE_INT_ARGB_PRE
1046     * @see java.awt.image.BufferedImage#TYPE_INT_BGR
1047     * @see java.awt.image.BufferedImage#TYPE_3BYTE_BGR
1048     * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR
1049     * @see java.awt.image.BufferedImage#TYPE_4BYTE_ABGR_PRE
1050     * @see java.awt.image.BufferedImage#TYPE_USHORT_565_RGB
1051     * @see java.awt.image.BufferedImage#TYPE_USHORT_555_RGB
1052     * @see java.awt.image.BufferedImage#TYPE_BYTE_GRAY
1053     * @see java.awt.image.BufferedImage#TYPE_USHORT_GRAY
1054     * @see java.awt.image.BufferedImage#TYPE_BYTE_BINARY
1055     * @see java.awt.image.BufferedImage#TYPE_BYTE_INDEXED
1056     */

1057    public int getBufferedImageType() {
1058        BufferedImage JavaDoc bi = createBufferedImage(1, 1);
1059        return bi.getType();
1060    }
1061
1062    /**
1063     * Return the number of color components
1064     * specified by this object. This is the same value as returned by
1065     * <code>ColorModel.getNumComponents</code>
1066     *
1067     * @return the number of components in the image.
1068     */

1069    public int getNumComponents() {
1070        return colorModel.getNumComponents();
1071    }
1072
1073    /**
1074     * Return the number of bands
1075     * specified by this object. This is the same value as returned by
1076     * <code>SampleModel.getNumBands</code>
1077     *
1078     * @return the number of bands in the image.
1079     */

1080    public int getNumBands() {
1081        return sampleModel.getNumBands();
1082    }
1083
1084    /**
1085     * Return the number of bits used to represent samples of the given band.
1086     *
1087     * @param band the index of the band to be queried, as an
1088     * int.
1089     *
1090     * @return an int specifying a number of bits.
1091     *
1092     * @exception IllegalArgumentException if <code>band</code> is
1093     * negative or greater than the largest band index.
1094     */

1095    public int getBitsPerBand(int band) {
1096        if (band < 0 | band >= getNumBands()) {
1097            throw new IllegalArgumentException JavaDoc("band out of range!");
1098        }
1099        return sampleModel.getSampleSize(band);
1100    }
1101
1102    /**
1103     * Returns a <code>SampleModel</code> based on the settings
1104     * encapsulated within this object. The width and height of the
1105     * <code>SampleModel</code> will be set to arbitrary values.
1106     *
1107     * @return a <code>SampleModel</code> with arbitrary dimensions.
1108     */

1109    public SampleModel JavaDoc getSampleModel() {
1110        return sampleModel;
1111    }
1112
1113    /**
1114     * Returns a <code>SampleModel</code> based on the settings
1115     * encapsulated within this object. The width and height of the
1116     * <code>SampleModel</code> will be set to the supplied values.
1117     *
1118     * @param width the desired width of the returned <code>SampleModel</code>.
1119     * @param height the desired height of the returned
1120     * <code>SampleModel</code>.
1121     *
1122     * @return a <code>SampleModel</code> with the given dimensions.
1123     *
1124     * @exception IllegalArgumentException if either <code>width</code> or
1125     * <code>height</code> are negative or zero.
1126     * @exception IllegalArgumentException if the product of
1127     * <code>width</code> and <code>height</code> is greater than
1128     * <code>Integer.MAX_VALUE</code>
1129     */

1130    public SampleModel JavaDoc getSampleModel(int width, int height) {
1131        if ((long)width*height > Integer.MAX_VALUE) {
1132            throw new IllegalArgumentException JavaDoc
1133                ("width*height > Integer.MAX_VALUE!");
1134        }
1135        return sampleModel.createCompatibleSampleModel(width, height);
1136    }
1137
1138    /**
1139     * Returns the <code>ColorModel</code> specified by this object.
1140     *
1141     * @return a <code>ColorModel</code>.
1142     */

1143    public ColorModel JavaDoc getColorModel() {
1144        return colorModel;
1145    }
1146
1147    /**
1148     * Creates a <code>BufferedImage</code> with a given width and
1149     * height according to the specification embodied in this object.
1150     *
1151     * @param width the desired width of the returned
1152     * <code>BufferedImage</code>.
1153     * @param height the desired height of the returned
1154     * <code>BufferedImage</code>.
1155     *
1156     * @return a new <code>BufferedImage</code>
1157     *
1158     * @exception IllegalArgumentException if either <code>width</code> or
1159     * <code>height</code> are negative or zero.
1160     * @exception IllegalArgumentException if the product of
1161     * <code>width</code> and <code>height</code> is greater than
1162     * <code>Integer.MAX_VALUE</code>, or if the number of array
1163     * elements needed to store the image is greater than
1164     * <code>Integer.MAX_VALUE</code>.
1165     */

1166    public BufferedImage JavaDoc createBufferedImage(int width, int height) {
1167        try {
1168            SampleModel JavaDoc sampleModel = getSampleModel(width, height);
1169            WritableRaster JavaDoc raster =
1170                Raster.createWritableRaster(sampleModel,
1171                                            new Point JavaDoc(0, 0));
1172            return new BufferedImage JavaDoc(colorModel, raster,
1173                                     colorModel.isAlphaPremultiplied(),
1174                                     new Hashtable JavaDoc());
1175        } catch (NegativeArraySizeException JavaDoc e) {
1176            // Exception most likely thrown from a DataBuffer constructor
1177
throw new IllegalArgumentException JavaDoc
1178                ("Array size > Integer.MAX_VALUE!");
1179        }
1180    }
1181
1182    /**
1183     * Returns <code>true</code> if the given <code>Object</code> is
1184     * an <code>ImageTypeSpecifier</code> and has a
1185     * <code>SampleModel</code> and <code>ColorModel</code> that are
1186     * equal to those of this object.
1187     *
1188     * @param o the <code>Object</code> to be compared for equality.
1189     *
1190     * @return <code>true</code> if the given object is an equivalent
1191     * <code>ImageTypeSpecifier</code>.
1192     */

1193    public boolean equals(Object JavaDoc o) {
1194        if ((o == null) || !(o instanceof ImageTypeSpecifier JavaDoc)) {
1195            return false;
1196        }
1197
1198        ImageTypeSpecifier JavaDoc that = (ImageTypeSpecifier JavaDoc)o;
1199        return (colorModel.equals(that.colorModel)) &&
1200            (sampleModel.equals(that.sampleModel));
1201    }
1202
1203    /**
1204     * Returns the hash code for this ImageTypeSpecifier.
1205     *
1206     * @return a hash code for this ImageTypeSpecifier
1207     */

1208    public int hashCode() {
1209        return (9 * colorModel.hashCode()) + (14 * sampleModel.hashCode());
1210    }
1211}
1212
Popular Tags