Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/ydp/jai/ImageCodec.java


1   /*
2    * The contents of this file are subject to the  JAVA ADVANCED IMAGING
3    * SAMPLE INPUT-OUTPUT CODECS AND WIDGET HANDLING SOURCE CODE  License
4    * Version 1.0 (the "License"); You may not use this file except in
5    * compliance with the License. You may obtain a copy of the License at
6    * http://www.sun.com/software/imaging/JAI/index.html
7    *
8    * Software distributed under the License is distributed on an "AS IS"
9    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
10   * the License for the specific language governing rights and limitations
11   * under the License. 
12   *
13   * The Original Code is JAVA ADVANCED IMAGING SAMPLE INPUT-OUTPUT CODECS
14   * AND WIDGET HANDLING SOURCE CODE. 
15   * The Initial Developer of the Original Code is: Sun Microsystems, Inc..
16   * Portions created by: _______________________________________
17   * are Copyright (C): _______________________________________
18   * All Rights Reserved.
19   * Contributor(s): _______________________________________
20   */
21  
22  package org.ydp.jai;
23  
24  import java.awt.Transparency;
25  import java.awt.color.ColorSpace;
26  import java.awt.image.ColorModel;
27  import java.awt.image.DataBuffer;
28  import java.awt.image.ComponentColorModel;
29  import java.awt.image.IndexColorModel;
30  import java.awt.image.RenderedImage;
31  import java.awt.image.SampleModel;
32  import java.io.File;
33  import java.io.InputStream;
34  import java.io.IOException;
35  import java.io.OutputStream;
36  import java.util.Enumeration;
37  import java.util.Hashtable;
38  import java.util.Vector;
39  
40  /**
41   * An abstract class allowing the creation of image decoders and
42   * encoders.  Instances of <code>ImageCodec</code> may be registered.
43   * Once a codec has been registered, the format name associated with
44   * it may be used as the <code>name</code> parameter in the
45   * <code>createImageEncoder()</code> and <code>createImageDecoder()</code>
46   * methods.
47   *
48   * <p> Additionally, subclasses of <code>ImageCodec</code> 
49   * are able to perform recognition of their particular format,
50   * wither by inspection of a fixed-length file header or by
51   * arbitrary access to the source data stream.
52   *
53   * <p> Format recognition is performed by two variants of the
54   * <code>isFormatRecognized()</code> method.  Which variant should be
55   * called is determined by the output of the codec's
56   * <codec>getNumHeaderBytes()</code> method, which returns 0 if
57   * arbitrary access to the stream is required, and otherwise returns
58   * the number of header bytes required to recognize the format.
59   * Each subclass of <code>ImageCodec</code> needs to implement only
60   * one of the two variants.
61   *
62   * <p><b> This class is not a committed part of the JAI API.  It may
63   * be removed or changed in future releases of JAI.</b>
64   */
65  public abstract class ImageCodec {
66  
67      private static Hashtable codecs = new Hashtable();
68  
69      /** Allow only subclasses to instantiate this class. */
70      protected ImageCodec() {}
71  
72      /**
73       * Load all the codecs.
74       */
75      static {
76          registerCodec(new BMPCodec());
77          registerCodec(new GIFCodec());
78          registerCodec(new FPXCodec());
79          registerCodec(new JPEGCodec());
80          registerCodec(new PNGCodec());
81          registerCodec(new TIFFCodec());
82      }
83  
84      /**
85       * Returns the <code>ImageCodec</code> associated with the given
86       * name.  <code>null</code> is returned if no codec is registered
87       * with the given name.  Case is not significant.
88       *
89       * @param name The name associated with the codec.
90       * @return The associated <code>ImageCodec</code>, or <code>null</code>.
91       */
92      public static ImageCodec getCodec(String name) {
93          return (ImageCodec)codecs.get(name.toLowerCase());
94      }
95  
96      /**
97       * Associates an <code>ImageCodec</code> with its format name, as
98       * determined by its <code>getFormatName()</code> method.  Case is
99       * not significant.  Any codec previously associated with the name
100      * is discarded.
101      *
102      * @param codec The <code>ImageCodec</code> object to be registered.
103      */
104     public static void registerCodec(ImageCodec codec) {
105         codecs.put(codec.getFormatName().toLowerCase(), codec);
106     }
107 
108     /**
109      * Unregisters the <code>ImageCodec</code> object currently
110      * responsible for handling the named format.  Case is not
111      * significant.
112      *
113      * @param name The name associated with the codec to be removed.
114      */
115     public static void unregisterCodec(String name) {
116         codecs.remove(name.toLowerCase());
117     }
118 
119     /**
120      * Returns an <code>Enumeration</code> of all regstered 
121      * <code>ImageCodec</code> objects.
122      */
123     public static Enumeration getCodecs() {
124         return codecs.elements();
125     }
126 
127     /**
128      * Returns an <code>ImageEncoder</code> object suitable for
129      * encoding to the supplied <code>OutputStream</code>, using the
130      * supplied <code>ImageEncoderParam</code> object.
131      *
132      * @param name The name associated with the codec.
133      * @param dst An <code>OutputStream</code> to write to.
134      * @param param An instance of <code>ImageEncoderParam</code> suitable
135      *        for use with the named codec, or <code>null</code>.
136      * @return An instance of <code>ImageEncoder</code>, or <code>null</code>.
137      */
138     public static ImageEncoder createImageEncoder(String name,
139                                                   OutputStream dst,
140                                                   ImageEncodeParam param) {
141         ImageCodec codec = getCodec(name);
142         if (codec == null) {
143             return null;
144         }
145         return codec.createImageEncoder(dst, param);
146     }
147 
148     /**
149      * Returns an <code>ImageDecoder</code> object suitable for
150      * decoding from the supplied <code>InputStream</code>, using the
151      * supplied <code>ImageDecodeParam</code> object.
152      *
153      * @param name The name associated with the codec.
154      * @param src An <code>InputStream</code> to read from.
155      * @param param An instance of <code>ImageDecodeParam</code> suitable
156      *        for use with the named codec, or <code>null</code>.
157      * @return An instance of <code>ImageDecoder</code>, or <code>null</code>.
158      */
159     public static ImageDecoder createImageDecoder(String name,
160                                                   InputStream src,
161                                                   ImageDecodeParam param) {
162         ImageCodec codec = getCodec(name);
163         if (codec == null) {
164             return null;
165         }
166         return codec.createImageDecoder(src, param);
167     }
168 
169     /**
170      * Returns an <code>ImageDecoder</code> object suitable for
171      * decoding from the supplied <code>File</code>, using the
172      * supplied <code>ImageDecodeParam</code> object.
173      *
174      * @param name The name associated with the codec.
175      * @param src A <code>File</code> to read from.
176      * @param param An instance of <code>ImageDecodeParam</code> suitable
177      *        for use with the named codec, or <code>null</code>.
178      * @return An instance of <code>ImageDecoder</code>, or <code>null</code>.
179      */
180     public static ImageDecoder createImageDecoder(String name,
181                                                   File src,
182                                                   ImageDecodeParam param)
183         throws IOException {
184         ImageCodec codec = getCodec(name);
185         if (codec == null) {
186             return null;
187         }
188         return codec.createImageDecoder(src, param);
189     }
190 
191     /**
192      * Returns an <code>ImageDecoder</code> object suitable for
193      * decoding from the supplied <code>SeekableStream</code>, using the
194      * supplied <code>ImageDecodeParam</code> object.
195      *
196      * @param name The name associated with the codec.
197      * @param src A <code>SeekableStream</code> to read from.
198      * @param param An instance of <code>ImageDecodeParam</code> suitable
199      *        for use with the named codec, or <code>null</code>.
200      * @return An instance of <code>ImageDecoder</code>, or <code>null</code>.
201      */
202     public static ImageDecoder createImageDecoder(String name,
203                                                   SeekableStream src,
204                                                   ImageDecodeParam param) {
205         ImageCodec codec = getCodec(name);
206         if (codec == null) {
207             return null;
208         }
209         return codec.createImageDecoder(src, param);
210     }
211 
212     private static String[] vectorToStrings(Vector nameVec) {
213         int count = nameVec.size();
214         String[] names = new String[count];
215         for (int i = 0; i < count; i++) {
216             names[i] = (String)nameVec.elementAt(i);
217         }
218         return names;
219     }
220 
221     /**
222      * Returns an array of <code>String</code>s indicating the names
223      * of registered <code>ImageCodec</code>s that may be appropriate
224      * for reading the given <code>SeekableStream</code>.
225      *
226      * <p> If the <code>src</code> <code>SeekableStream</code> does
227      * not support seeking backwards (that is, its
228      * <code>canSeekBackwards()</code> method returns
229      * <code>false</code>) then only <code>FormatRecognizer</code>s
230      * that require only a fixed-length header will be checked.
231      *
232      * <p> If the <code>src</code> stream does not support seeking
233      * backwards, it must support marking, as determined by its 
234      * <code>markSupported()</code> method.
235      *
236      * @param src A <code>SeekableStream</code> which optionally supports
237      *        seeking backwards.
238      * @return An array of <code>String</code>s.
239      *
240      * @throws IllegalArgumentException if <code>src</code> supports
241      *         neither seeking backwards nor marking.
242      */
243     public static String[] getDecoderNames(SeekableStream src) {
244         if (!src.canSeekBackwards() && !src.markSupported()) {
245             throw new IllegalArgumentException(JaiI18N.getString("ImageCodec2"));
246         }
247         
248         Enumeration enum = codecs.elements();
249         Vector nameVec = new Vector();
250 
251         String opName = null;
252         while (enum.hasMoreElements()) {
253             ImageCodec codec = (ImageCodec)enum.nextElement();
254 
255             int bytesNeeded = codec.getNumHeaderBytes();
256             if ((bytesNeeded == 0) && !src.canSeekBackwards()) {
257                 continue;
258             }
259 
260             try {
261                 if (bytesNeeded > 0) {
262                     src.mark(bytesNeeded);
263                     byte[] header = new byte[bytesNeeded];
264                     src.readFully(header);
265                     src.reset();
266 
267                     if (codec.isFormatRecognized(header)) {
268                         nameVec.add(codec.getFormatName());
269                     }
270                 } else {
271                     long pointer = src.getFilePointer();
272                     src.seek(0L);
273                     if (codec.isFormatRecognized(src)) {
274                         nameVec.add(codec.getFormatName());
275                     }
276                     src.seek(pointer);
277                 }
278             } catch (IOException e) {
279                 e.printStackTrace();
280             }
281         }
282 
283         return vectorToStrings(nameVec);
284     }
285 
286     /**
287      * Returns an array of <code>String</code>s indicating the names
288      * of registered <code>ImageCodec</code>s that may be appropriate
289      * for writing the given <code>RenderedImage</code>, using the
290      * optional <code>ImageEncodeParam</code>, which may be
291      * <code>null</code>.
292      *
293      * @param im A <code>RenderedImage</code> to be encodec.
294      * @param param An <code>ImageEncodeParam</code>, or null.
295      * @return An array of <code>String</code>s.
296      */
297     public static String[] getEncoderNames(RenderedImage im,
298                                            ImageEncodeParam param) {
299         Enumeration enum = codecs.elements();
300         Vector nameVec = new Vector();
301 
302         String opName = null;
303         while (enum.hasMoreElements()) {
304             ImageCodec codec = (ImageCodec)enum.nextElement();
305 
306             if (codec.canEncodeImage(im, param)) {
307                 nameVec.add(codec.getFormatName());
308             }
309         }
310 
311         return vectorToStrings(nameVec);
312     }
313 
314     /**
315      * Returns the name of this image format.
316      *
317      * @return A <code>String</code> containing the name of the
318      *         image format supported by this codec.
319      */
320     public abstract String getFormatName();
321 
322     /** 
323      * Returns the number of bytes of header needed to recognize the
324      * format, or 0 if an arbitrary number of bytes may be needed.
325      * The default implementation returns 0.
326      *
327      * <p> The return value must be a constant for all instances of
328      * each particular subclass of <code>ImageCodec</code>.
329      *
330      * <p> Although it is legal to always return 0, in some cases
331      * processing may be more efficient if the number of bytes needed
332      * is known in advance.
333      */
334     public int getNumHeaderBytes() {
335         return 0;
336     }
337 
338     /**
339      * Returns <code>true</code> if the format is recognized in the
340      * initial portion of a stream.  The header will be passed in as a
341      * <code>byte</code> array of length <code>getNumHeaderBytes()</code>.
342      * This method should be called only if <code>getNumHeaderBytes()</code>
343      * returns a value greater than 0.
344      *
345      * <p> The default implementation throws an exception to indicate
346      * that it should never be called.
347      *
348      * @param header An array of <code>byte</code>s containing the input
349      *        stream header.
350      * @return <code>true</code> if the format is recognized.
351      */
352     public boolean isFormatRecognized(byte[] header) {
353         throw new RuntimeException(JaiI18N.getString("ImageCodec0"));
354     }
355 
356     /**
357      * Returns <code>true</code> if the format is recognized in the
358      * input data stream.  This method should be called only if
359      * <code>getNumHeaderBytesNeeded()</code> returns 0.
360      *
361      * <p> The source <code>SeekableStream</code> is guaranteed to
362      * support seeking backwards, and should be seeked to 0 prior
363      * to calling this method.
364      *
365      * <p> The default implementation throws an exception to indicate
366      * that it should never be called.
367      *
368      * @param src A <code>SeekableStream</code> containing the input
369      *        data.
370      * @return <code>true</code> if the format is recognized.
371      */
372     public boolean isFormatRecognized(SeekableStream src) throws IOException {
373         throw new RuntimeException(JaiI18N.getString("ImageCodec1"));
374     }
375 
376     /**
377      * Returns a <code>Class</code> object indicating the proper
378      * subclass of <code>ImageEncodeParam</code> to be used with this
379      * <code>ImageCodec</code>.  If encoding is not supported by this
380      * codec, <code>null</code> is returned.  If encoding is
381      * supported, but a parameter object is not used during encoding,
382      * Object.class is returned to signal this fact.
383      */
384     protected abstract Class getEncodeParamClass();
385 
386     /**
387      * Returns a <code>Class</code> object indicating the proper
388      * subclass of <code>ImageDecodeParam</code> to be used with this
389      * <code>ImageCodec</code>.  If encoding is not supported by this
390      * codec, <code>null</code> is returned.  If decoding is
391      * supported, but a parameter object is not used during decoding,
392      * Object.class is returned to signal this fact.
393      */
394     protected abstract Class getDecodeParamClass();
395 
396     /**
397      * In a concrete subclass of <code>ImageCodec</code>, returns an
398      * implementation of the <code>ImageEncoder</code> interface
399      * appropriate for that codec.
400      *
401      * @param dst An <code>OutputStream</code> to write to.
402      * @param param An instance of <code>ImageEncoderParam</code>
403      *        suitable for use with the <code>ImageCodec</code>
404      *        subclass, or <code>null</code>.
405      * @return An instance of <code>ImageEncoder</code>.
406      */
407     protected abstract ImageEncoder createImageEncoder(OutputStream dst,
408                                                        ImageEncodeParam param);
409     
410     /**
411      * Returns <code>true</code> if the given image and encoder param
412      * object are suitable for encoding by this <code>ImageCodec</code>.
413      * For example, some codecs may only deal with images with a certain
414      * number of bands; an attempt to encode an image with an unsupported
415      * number of bands will fail.
416      *
417      * @param im a RenderedImage whose ability to be encoded is to be
418      *        determined.
419      * @param param a suitable <code>ImageEncodeParam</code> object,
420      *        or <code>null</code>.
421      */
422     public abstract boolean canEncodeImage(RenderedImage im,
423                                            ImageEncodeParam param);
424 
425     /**
426      * Returns an implementation of the <code>ImageDecoder</code>
427      * interface appropriate for that codec.  Subclasses of
428      * <code>ImageCodec</code> may override this method if they wish
429      * to accept data directly from an <code>InputStream</code>;
430      * otherwise, this method will convert the source into a
431      * backwards-seekable <code>SeekableStream</code> and call the
432      * appropriate version of <code>createImageDecoder</code> for that
433      * data type.
434      *
435      * <p> Instances of <code>ImageCodec</code> that do not require
436      * the ability to seek backwards in their source
437      * <code>SeekableStream</code> should override this method in
438      * order to avoid the default call to
439      * <code>SeekableStream.wrapInputStream(src, true)</code>.
440      *
441      * @param dst An <code>InputStream</code> to read from.
442      * @param param An instance of <code>ImageDecodeParam</code>
443      *        suitable for use with the <code>ImageCodec</code>
444      *        subclass, or <code>null</code>.
445      * @return An instance of <code>ImageDecoder</code>.
446      */
447     protected ImageDecoder createImageDecoder(InputStream src,
448                                               ImageDecodeParam param) {
449         SeekableStream stream = SeekableStream.wrapInputStream(src, true);
450         return createImageDecoder(stream, param);
451     }
452 
453     /**
454      * Returns an implementation of the <code>ImageDecoder</code>
455      * interface appropriate for that codec.  Subclasses of 
456      * <code>ImageCodec</code> may override this method if they wish
457      * to accept data directly from a <code>File</code>;
458      * otherwise, this method will convert the source into a
459      * <code>SeekableStream</code> and call the appropriate
460      * version of <code>createImageDecoder</code> for that data type.
461      *
462      * @param dst A <code>File</code> to read from.
463      * @param param An instance of <code>ImageDecodeParam</code>
464      *        suitable for use with the <code>ImageCodec</code>
465      *        subclass, or <code>null</code>.
466      * @return An instance of <code>ImageDecoder</code>.
467      */
468     protected ImageDecoder createImageDecoder(File src,
469                                               ImageDecodeParam param) 
470         throws IOException {
471         return createImageDecoder(new FileSeekableStream(src), param);
472     }
473 
474     /**
475      * In a concrete subclass of <code>ImageCodec</code>, returns an
476      * implementation of the <code>ImageDecoder</code> interface
477      * appropriate for that codec.
478      *
479      * @param dst A <code>SeekableStream</code> to read from.
480      * @param param An instance of <code>ImageDecodeParam</code>
481      *        suitable for use with the <code>ImageCodec</code>
482      *        subclass, or <code>null</code>.
483      * @return An instance of <code>ImageDecoder</code>.
484      */
485     protected abstract ImageDecoder createImageDecoder(SeekableStream src,
486                                                        ImageDecodeParam param);
487 
488     // ColorModel utility functions
489 
490     private static final byte[][] grayIndexCmaps = {
491         null,
492         // 1 bit
493         { (byte)0x00, (byte)0xff },
494         // 2 bits
495         { (byte)0x00, (byte)0x55, (byte)0xaa, (byte)0xff },
496         null,
497         // 4 bits
498         { (byte)0x00, (byte)0x11, (byte)0x22, (byte)0x33,
499           (byte)0x44, (byte)0x55, (byte)0x66, (byte)0x77,
500           (byte)0x88, (byte)0x99, (byte)0xaa, (byte)0xbb,
501           (byte)0xcc, (byte)0xdd, (byte)0xee, (byte)0xff }
502     };
503 
504     /**
505      * A convenience methods to create an instance of
506      * <code>IndexColorModel</code> suitable for the given 1-banded
507      * <code>SampleModel</code>.
508      *
509      * @param sm a 1-banded <code>SampleModel</code>.
510      * @param blackIsZero <code>true</code> if the gray ramp should
511      *        go from black to white, <code>false</code>otherwise.
512      */
513     public static ColorModel createGrayIndexColorModel(SampleModel sm,
514                                                        boolean blackIsZero) {
515         if (sm.getNumBands() != 1) {
516             throw new IllegalArgumentException();
517         }
518         int sampleSize = sm.getSampleSize(0);
519 
520         byte[] cmap = null;
521         if (sampleSize < 8) {
522             cmap = grayIndexCmaps[sampleSize];
523             if (!blackIsZero) {
524                 int length = cmap.length;
525                 byte[] newCmap = new byte[length];
526                 for (int i = 0; i < length; i++) {
527                     newCmap[i] = cmap[length - i - 1];
528                 }
529                 cmap = newCmap;
530             }
531         } else {
532             cmap = new byte[256];
533             if (!blackIsZero) {
534                 for (int i = 0; i < 256; i++) {
535                     cmap[i] = (byte)i;
536                 }
537             } else {
538                 for (int i = 0; i < 256; i++) {
539                     cmap[i] = (byte)(255 - i);
540                 }
541             }
542         }
543 
544         return new IndexColorModel(sampleSize, cmap.length,
545                                    cmap, cmap, cmap);
546     }
547 
548     private static final int[] GrayBits8 = { 8 };
549     private static final ComponentColorModel colorModelGray8 =
550         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
551                                 GrayBits8, false, false,
552                                 Transparency.OPAQUE,
553                                 DataBuffer.TYPE_BYTE);
554 
555     private static final int[] GrayAlphaBits8 = { 8, 8 };
556     private static final ComponentColorModel colorModelGrayAlpha8 =
557         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
558                                 GrayAlphaBits8, true, false,
559                                 Transparency.TRANSLUCENT,
560                                 DataBuffer.TYPE_BYTE);
561 
562     private static final int[] GrayBits16 = { 16 };
563     private static final ComponentColorModel colorModelGray16 =
564         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
565                                 GrayBits16, false, false,
566                                 Transparency.OPAQUE,
567                                 DataBuffer.TYPE_USHORT);
568 
569     private static final int[] GrayAlphaBits16 = { 16, 16 };
570     private static final ComponentColorModel colorModelGrayAlpha16 =
571         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
572                                 GrayAlphaBits16, true, false,
573                                 Transparency.TRANSLUCENT,
574                                 DataBuffer.TYPE_USHORT);
575 
576     private static final int[] GrayBits32 = { 32 };
577     private static final ComponentColorModel colorModelGray32 =
578         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
579                                 GrayBits32, false, false,
580                                 Transparency.OPAQUE,
581                                 DataBuffer.TYPE_INT);
582 
583     private static final int[] GrayAlphaBits32 = { 32, 32 };
584     private static final ComponentColorModel colorModelGrayAlpha32 =
585         new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
586                                 GrayAlphaBits32, true, false,
587                                 Transparency.TRANSLUCENT,
588                                 DataBuffer.TYPE_INT);
589 
590     private static final int[] RGBBits8 = { 8, 8, 8 };
591     private static final ComponentColorModel colorModelRGB8 =
592       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
593                               RGBBits8, false, false,
594                               Transparency.OPAQUE,
595                               DataBuffer.TYPE_BYTE);
596 
597     private static final int[] RGBABits8 = { 8, 8, 8, 8 };
598     private static final ComponentColorModel colorModelRGBA8 =
599       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
600                               RGBABits8, true, false,
601                               Transparency.TRANSLUCENT,
602                               DataBuffer.TYPE_BYTE);
603 
604     private static final int[] RGBBits16 = { 16, 16, 16 };
605     private static final ComponentColorModel colorModelRGB16 =
606       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
607                               RGBBits16, false, false,
608                               Transparency.OPAQUE,
609                               DataBuffer.TYPE_USHORT);
610 
611     private static final int[] RGBABits16 = { 16, 16, 16, 16 };
612     private static final ComponentColorModel colorModelRGBA16 =
613       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
614                               RGBABits16, true, false,
615                               Transparency.TRANSLUCENT,
616                               DataBuffer.TYPE_USHORT);
617 
618     private static final int[] RGBBits32 = { 32, 32, 32 };
619     private static final ComponentColorModel colorModelRGB32 =
620       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
621                               RGBBits32, false, false,
622                               Transparency.OPAQUE,
623                               DataBuffer.TYPE_INT);
624 
625     private static final int[] RGBABits32 = { 32, 32, 32, 32 };
626     private static final ComponentColorModel colorModelRGBA32 =
627       new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
628                               RGBABits32, true, false,
629                               Transparency.TRANSLUCENT,
630                               DataBuffer.TYPE_INT);
631 
632     /**
633      * A convenience method to create an instance of
634      * <code>ComponentColorModel</code> suitable for use with the
635      * given <code>SampleModel</code>.  The <code>SampleModel</code>
636      * should have a data type of <code>DataBuffer.TYPE_BYTE</code>,
637      * <code>TYPE_USHORT</code>, or <code>TYPE_INT</code> and between
638      * 1 and 4 bands.  Depending on the number of bands of the
639      * <code>SampleModel</code>, either a gray, gray+alpha, rgb, or
640      * rgb+alpha <code>ColorModel</code> is returned.
641      */
642     public static ColorModel createComponentColorModel(SampleModel sm) {
643         int type = sm.getDataType();
644         int bands = sm.getNumBands();
645         ComponentColorModel cm = null;
646 
647         if (type == DataBuffer.TYPE_BYTE) {
648             switch (bands) {
649             case 1:
650                 cm = colorModelGray8;
651                 break;
652             case 2:
653                 cm = colorModelGrayAlpha8;
654                 break;
655             case 3:
656                 cm = colorModelRGB8;
657                 break;
658             case 4:
659                 cm = colorModelRGBA8;
660                 break;
661             }
662         } else if (type == DataBuffer.TYPE_USHORT) {
663             switch (bands) {
664             case 1:
665                 cm = colorModelGray16;
666                 break;
667             case 2:
668                 cm = colorModelGrayAlpha16;
669                 break;
670             case 3:
671                 cm = colorModelRGB16;
672                 break;
673             case 4:
674                 cm = colorModelRGBA16;
675                 break;
676             }
677         } else if (type == DataBuffer.TYPE_INT) {
678             switch (bands) {
679             case 1:
680                 cm = colorModelGray32;
681                 break;
682             case 2:
683                 cm = colorModelGrayAlpha32;
684                 break;
685             case 3:
686                 cm = colorModelRGB32;
687                 break;
688             case 4:
689                 cm = colorModelRGBA32;
690                 break;
691             }
692         }
693 
694         return cm;
695     }
696 }