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 }