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