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

Quick Search    Search Deep

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 }