001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging;
018
019import java.awt.Dimension;
020import java.awt.image.BufferedImage;
021import java.io.File;
022import java.io.IOException;
023import java.io.OutputStream;
024import java.io.PrintWriter;
025import java.io.StringWriter;
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.List;
029import java.util.Locale;
030import java.util.logging.Level;
031import java.util.logging.Logger;
032
033import org.apache.commons.imaging.common.BinaryFileParser;
034import org.apache.commons.imaging.common.BufferedImageFactory;
035import org.apache.commons.imaging.common.ImageMetadata;
036import org.apache.commons.imaging.common.SimpleBufferedImageFactory;
037import org.apache.commons.imaging.common.bytesource.ByteSource;
038import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
039import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
040import org.apache.commons.imaging.formats.bmp.BmpImageParser;
041import org.apache.commons.imaging.formats.dcx.DcxImageParser;
042import org.apache.commons.imaging.formats.gif.GifImageParser;
043import org.apache.commons.imaging.formats.icns.IcnsImageParser;
044import org.apache.commons.imaging.formats.ico.IcoImageParser;
045import org.apache.commons.imaging.formats.jpeg.JpegImageParser;
046import org.apache.commons.imaging.formats.pcx.PcxImageParser;
047import org.apache.commons.imaging.formats.png.PngImageParser;
048import org.apache.commons.imaging.formats.pnm.PnmImageParser;
049import org.apache.commons.imaging.formats.psd.PsdImageParser;
050import org.apache.commons.imaging.formats.rgbe.RgbeImageParser;
051import org.apache.commons.imaging.formats.tiff.TiffImageParser;
052import org.apache.commons.imaging.formats.wbmp.WbmpImageParser;
053import org.apache.commons.imaging.formats.xbm.XbmImageParser;
054import org.apache.commons.imaging.formats.xpm.XpmImageParser;
055
056/**
057 * Provides the abstract base class for all image reading and writing
058 * utilities.  ImageParser implementations are expected to extend this
059 * class providing logic for identifying and processing data in their
060 * own specific format.   Specific implementations are found
061 * under the com.apache.commons.imaging.formats package.
062 *
063 * <h2>Application Notes</h2>
064 *
065 * <h3>Format support</h3>
066 *
067 * For the most recent information on format support for the
068 * Apache Commons Imaging package, refer to
069 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a>
070 * at the main project development web site.
071 *
072 * <h3>On the accuracy of this Javadoc</h3>
073 *
074 * The original authors of this class did not supply documentation.
075 * The Javadoc for this class is based on inspection of the
076 * source code.  In some cases, the purpose and usage for particular
077 * methods was deduced from the source and may not perfectly reflect
078 * the intentions of the original. Therefore, you should not assume
079 * that the documentation is perfect, especially in the more obscure
080 * and specialized areas of implementation.
081 *
082 * <h3>The "params" argument</h3>
083 *
084 * <p>Many of the methods specified by this class accept an argument of
085 * type {@code T} defining the parameters to be used when
086 * processing an image. For example, some of the output formats permit
087 * of different kinds of image compression or color models. Some of the
088 * reading methods permit the calling application to require strict
089 * format compliance.</p>
090 *
091 * @param <T> type of parameters used by this image parser
092 */
093public abstract class ImageParser<T extends ImagingParameters> extends BinaryFileParser {
094
095    private static final Logger LOGGER = Logger.getLogger(ImageParser.class.getName());
096
097    /**
098     * Gets an array of new instances of all image parsers.
099     *
100     * @return A valid array of image parsers
101     */
102    public static List<ImageParser<?>> getAllImageParsers() {
103        return Arrays.asList(
104                new BmpImageParser(),
105                new DcxImageParser(),
106                new GifImageParser(),
107                new IcnsImageParser(),
108                new IcoImageParser(),
109                new JpegImageParser(),
110                new PcxImageParser(),
111                new PngImageParser(),
112                new PnmImageParser(),
113                new PsdImageParser(),
114                new RgbeImageParser(),
115                new TiffImageParser(),
116                new WbmpImageParser(),
117                new XbmImageParser(),
118                new XpmImageParser()
119                // new JBig2ImageParser(),
120                // new TgaImageParser(),
121        );
122    }
123
124    /**
125     * Get a default parameters instance for this parser.
126     * @return default parameters instance
127     */
128    public abstract T getDefaultParameters();
129
130    /**
131     * Get image metadata from the specified byte source.  Format-specific
132     * ImageParser implementations are expected to return a valid
133     * IImageMetadata object or to throw an ImageReadException if unable
134     * to process the specified byte source.
135     *
136     * @param byteSource A valid byte source.
137     * @return A valid, potentially subject-matter-specific implementation of
138     *         the IImageMetadata interface describing the content extracted
139     *         from the source content.
140     * @throws ImageReadException In the event that the ByteSource
141     *                            content does not conform to the format of the specific parser
142     *                            implementation.
143     * @throws IOException        In the event of unsuccessful data read operation.
144     */
145    public final ImageMetadata getMetadata(final ByteSource byteSource) throws ImageReadException, IOException {
146        return getMetadata(byteSource, null);
147    }
148
149    /**
150     * Get image metadata from the specified byte source.  Format-specific
151     * ImageParser implementations are expected to return a valid
152     * IImageMetadata object or to throw an ImageReadException if unable
153     * to process the specified byte source.
154     *
155     * <p>The params argument provides a mechanism for individual
156     * implementations to pass optional information into the parser.
157     * Not all formats will require this capability.  Because the
158     * base class may call this method with a null params argument,
159     * implementations should <strong>always</strong> include logic
160     * for ignoring null input.
161     *
162     * @param byteSource A valid byte source.
163     * @param params     Optional instructions for special-handling or
164     *                   interpretation of the input data (null objects are permitted and
165     *                   must be supported by implementations).
166     * @return A valid, potentially subject-matter-specific implementation of
167     *         the IImageMetadata interface describing the content extracted
168     *         from the source content.
169     * @throws ImageReadException In the event that the ByteSource
170     *                            content does not conform to the format of the specific parser
171     *                            implementation.
172     * @throws IOException        In the event of unsuccessful data read operation.
173     */
174    public abstract ImageMetadata getMetadata(ByteSource byteSource, T params)
175            throws ImageReadException, IOException;
176
177    /**
178     * Get image metadata from the specified array of bytes.  Format-specific
179     * ImageParser implementations are expected to return a valid
180     * IImageMetadata object or to throw an ImageReadException if unable
181     * to process the specified data.
182     *
183     * @param bytes A valid array of bytes
184     * @return A valid, potentially subject-matter-specific implementation of
185     *         the IImageMetadata interface describing the content extracted
186     *         from the source content.
187     * @throws ImageReadException In the event that the specified content
188     *                            does not conform to the format of the specific
189     *                            parser implementation.
190     * @throws IOException        In the event of unsuccessful data read operation.
191     */
192    public final ImageMetadata getMetadata(final byte[] bytes) throws ImageReadException, IOException {
193        return getMetadata(bytes, null);
194    }
195
196    /**
197     * Get image metadata from the specified array of bytes.  Format-specific
198     * ImageParser implementations are expected to return a valid
199     * IImageMetadata object or to throw an ImageReadException if unable
200     * to process the specified data.
201     *
202     * <p>The params argument provides a mechanism for individual
203     * implementations to pass optional information into the parser.
204     * Not all formats will require this capability.  Because the
205     * base class may call this method with a null params argument,
206     * implementations should <strong>always</strong> include logic
207     * for ignoring null input.
208     *
209     * @param bytes  A valid array of bytes
210     * @param params Optional instructions for special-handling or
211     *               interpretation of the input data (null objects are permitted and
212     *               must be supported by implementations).
213     * @return A valid image metadata object describing the content extracted
214     *         from  the specified content.
215     * @throws ImageReadException In the event that the specified content
216     *                            does not conform to the format of the specific
217     *                            parser implementation.
218     * @throws IOException        In the event of unsuccessful data read operation.
219     */
220    public final ImageMetadata getMetadata(final byte[] bytes, final T params)
221            throws ImageReadException, IOException {
222        return getMetadata(new ByteSourceArray(bytes), params);
223    }
224
225    /**
226     * Get image metadata from the specified file.  Format-specific
227     * ImageParser implementations are expected to return a valid
228     * IImageMetadata object or to throw an ImageReadException if unable
229     * to process the specified data.
230     *
231     * @param file A valid reference to a file.
232     * @return A valid image metadata object describing the content extracted
233     *         from  the specified content.
234     * @throws ImageReadException In the event that the specified content
235     *                            does not conform to the format of the specific
236     *                            parser implementation.
237     * @throws IOException        In the event of unsuccessful file read or
238     *                            access operation.
239     */
240    public final ImageMetadata getMetadata(final File file) throws ImageReadException, IOException {
241        return getMetadata(file, null);
242    }
243
244    /**
245     * Get image metadata from the specified file.  Format-specific
246     * ImageParser implementations are expected to return a valid
247     * IImageMetadata object or to throw an ImageReadException if unable
248     * to process the specified data.
249     *
250     * <p>The params argument provides a mechanism for individual
251     * implementations to pass optional information into the parser.
252     * Not all formats will require this capability.  Because the
253     * base class may call this method with a null params argument,
254     * implementations should <strong>always</strong> include logic
255     * for ignoring null input.
256     *
257     * @param file   A valid reference to a file.
258     * @param params Optional instructions for special-handling or
259     *               interpretation of the input data (null objects are permitted and
260     *               must be supported by implementations).
261     * @return A valid image metadata object describing the content extracted
262     *         from  the specified content.
263     * @throws ImageReadException In the event that the specified content
264     *                            does not conform to the format of the specific
265     *                            parser implementation.
266     * @throws IOException        In the event of unsuccessful file read or
267     *                            access operation.
268     */
269    public final ImageMetadata getMetadata(final File file, final T params)
270            throws ImageReadException, IOException {
271        if (LOGGER.isLoggable(Level.FINEST)) {
272            LOGGER.finest(getName() + ".getMetadata" + ": " + file.getName());
273        }
274
275        if (!canAcceptExtension(file)) {
276            return null;
277        }
278
279        return getMetadata(new ByteSourceFile(file), params);
280    }
281
282    /**
283     * Get image information from the specified ByteSource. Format-specific
284     * ImageParser implementations are expected to return a valid
285     * ImageInfo object or to throw an ImageReadException if unable
286     * to process the specified data.
287     *
288     * <p>The params argument provides a mechanism for individual
289     * implementations to pass optional information into the parser.
290     * Not all formats will require this capability.  Because the
291     * base class may call this method with a null params argument,
292     * implementations should <strong>always</strong> include logic
293     * for ignoring null input.
294     *
295     * @param byteSource A valid ByteSource object
296     * @param params     Optional instructions for special-handling or interpretation
297     *                   of the input data (null objects are permitted and
298     *                   must be supported by implementations).
299     * @return A valid image information object describing the content extracted
300     *         from the specified data.
301     * @throws ImageReadException In the event that the specified content
302     *                            does not conform to the format of the specific
303     *                            parser implementation.
304     * @throws IOException        In the event of unsuccessful data access operation.
305     */
306    public abstract ImageInfo getImageInfo(ByteSource byteSource, T params)
307            throws ImageReadException, IOException;
308
309    /**
310     * Get image information from the specified ByteSource.  Format-specific
311     * ImageParser implementations are expected to return a valid
312     * ImageInfo object or to throw an ImageReadException if unable
313     * to process the specified data.
314     *
315     * @param byteSource A valid ByteSource object
316     * @return A valid image information object describing the content extracted
317     *         from the specified data.
318     * @throws ImageReadException In the event that the specified content
319     *                            does not conform to the format of the specific
320     *                            parser implementation.
321     * @throws IOException        In the event of unsuccessful data
322     *                            access operation.
323     */
324    public final ImageInfo getImageInfo(final ByteSource byteSource) throws ImageReadException, IOException {
325        return getImageInfo(byteSource, null);
326    }
327
328    /**
329     * Get image information from the specified array of bytes.  Format-specific
330     * ImageParser implementations are expected to return a valid
331     * ImageInfo object or to throw an ImageReadException if unable
332     * to process the specified data.
333     * <p>The params argument provides a mechanism for individual
334     * implementations to pass optional information into the parser.
335     * Not all formats will require this capability.  Because the
336     * base class may call this method with a null params argument,
337     * implementations should <strong>always</strong> include logic
338     * for ignoring null input.
339     *
340     * @param bytes  A valid array of bytes
341     * @param params Optional instructions for special-handling or
342     *               interpretation of the input data (null objects are permitted and
343     *               must be supported by implementations).
344     * @return A valid image information object describing the content extracted
345     *         from the specified data.
346     * @throws ImageReadException In the event that the specified content
347     *                            does not conform to the format of the specific
348     *                            parser implementation.
349     * @throws IOException        In the event of unsuccessful data
350     *                            access operation.
351     */
352    public final ImageInfo getImageInfo(final byte[] bytes, final T params)
353            throws ImageReadException, IOException {
354        return getImageInfo(new ByteSourceArray(bytes), params);
355    }
356
357    /**
358     * Get image information from the specified file  Format-specific
359     * ImageParser implementations are expected to return a valid
360     * ImageInfo object or to throw an ImageReadException if unable
361     * to process the specified data.
362     * <p>The params argument provides a mechanism for individual
363     * implementations to pass optional information into the parser.
364     * Not all formats will require this capability.  Because the
365     * base class may call this method with a null params argument,
366     * implementations should <strong>always</strong> include logic
367     * for ignoring null input.
368     *
369     * @param file   A valid File object
370     * @param params Optional instructions for special-handling or
371     *               interpretation of the input data (null objects are permitted and
372     *               must be supported by implementations).
373     * @return A valid image information object describing the content extracted
374     *         from the specified data.
375     * @throws ImageReadException In the event that the specified content
376     *                            does not conform to the format of the specific
377     *                            parser implementation.
378     * @throws IOException        In the event of unsuccessful file read or
379     *                            access operation.
380     */
381    public final ImageInfo getImageInfo(final File file, final T params)
382            throws ImageReadException, IOException {
383        if (!canAcceptExtension(file)) {
384            return null;
385        }
386
387        return getImageInfo(new ByteSourceFile(file), params);
388    }
389
390    /**
391     * Determines the format compliance of the content of the supplied byte
392     * source based on rules provided by a specific implementation.
393     *
394     * @param byteSource A valid instance of ByteSource
395     * @return true if the content is format-compliant; otherwise, false
396     * @throws ImageReadException may be thrown by sub-classes
397     * @throws IOException        may be thrown by sub-classes
398     */
399    public FormatCompliance getFormatCompliance(final ByteSource byteSource)
400            throws ImageReadException, IOException {
401        return null;
402    }
403
404    /**
405     * Determines the format compliance of the content of the supplied byte
406     * array based on rules provided by a specific implementation.
407     *
408     * @param bytes A valid byte array.
409     * @return A valid FormatCompliance object.
410     * @throws ImageReadException may be thrown by sub-classes
411     * @throws IOException        may be thrown by sub-classes
412     */
413    public final FormatCompliance getFormatCompliance(final byte[] bytes)
414            throws ImageReadException, IOException {
415        return getFormatCompliance(new ByteSourceArray(bytes));
416    }
417
418    /**
419     * Determines the format compliance of the specified file based on
420     * rules provided by a specific implementation.
421     *
422     * @param file A valid reference to a file.
423     * @return A valid format compliance object.
424     * @throws ImageReadException may be thrown by sub-classes
425     * @throws IOException        may be thrown by sub-classes
426     */
427    public final FormatCompliance getFormatCompliance(final File file)
428            throws ImageReadException, IOException {
429        if (!canAcceptExtension(file)) {
430            return null;
431        }
432
433        return getFormatCompliance(new ByteSourceFile(file));
434    }
435
436    /**
437     * Gets all images specified by the byte source (some
438     * formats may include multiple images within a single data source).
439     *
440     * @param byteSource A valid instance of ByteSource.
441     * @return A valid (potentially empty) list of BufferedImage objects.
442     * @throws ImageReadException In the event that the specified content
443     *                            does not conform to the format of the specific
444     *                            parser implementation.
445     * @throws IOException        In the event of unsuccessful read or access operation.
446     */
447    public List<BufferedImage> getAllBufferedImages(final ByteSource byteSource)
448            throws ImageReadException, IOException {
449        final BufferedImage bi = getBufferedImage(byteSource, null);
450
451        final List<BufferedImage> result = new ArrayList<>();
452
453        // FIXME this doesn't look like we're actually getting all images contained in the given ByteSource...
454        result.add(bi);
455
456        return result;
457    }
458
459    /**
460     * Gets all images specified by the byte array (some
461     * formats may include multiple images within a single data source).
462     *
463     * @param bytes A valid byte array
464     * @return A valid (potentially empty) list of BufferedImage objects.
465     * @throws ImageReadException In the event that the specified content
466     *                            does not conform to the format of the specific
467     *                            parser implementation.
468     * @throws IOException        In the event of unsuccessful read or access operation.
469     */
470    public final List<BufferedImage> getAllBufferedImages(final byte[] bytes)
471            throws ImageReadException, IOException {
472        return getAllBufferedImages(new ByteSourceArray(bytes));
473    }
474
475    /**
476     * Gets all images specified by indicated file (some
477     * formats may include multiple images within a single data source).
478     *
479     * @param file A valid reference to a file.
480     * @return A valid (potentially empty) list of BufferedImage objects.
481     * @throws ImageReadException In the event that the specified content
482     *                            does not conform to the format of the specific
483     *                            parser implementation.
484     * @throws IOException        In the event of unsuccessful read or access operation.
485     */
486    public final List<BufferedImage> getAllBufferedImages(final File file) throws ImageReadException, IOException {
487        if (!canAcceptExtension(file)) {
488            return null;
489        }
490
491        return getAllBufferedImages(new ByteSourceFile(file));
492    }
493
494    /**
495     * Gets a buffered image specified by the byte source (for
496     * sources that specify multiple images, choice of which image
497     * is returned is implementation dependent).
498     *
499     * @param byteSource A valid instance of ByteSource
500     * @param params     Optional instructions for special-handling or
501     *                   interpretation of the input data (null objects are permitted and
502     *                   must be supported by implementations).
503     * @return A valid instance of BufferedImage.
504     * @throws ImageReadException In the event that the specified content
505     *                            does not conform to the format of the specific
506     *                            parser implementation.
507     * @throws IOException        In the event of unsuccessful read or access operation.
508     */
509    public abstract BufferedImage getBufferedImage(ByteSource byteSource, T params)
510            throws ImageReadException, IOException;
511
512    /**
513     * Gets a buffered image specified by the byte array (for
514     * sources that specify multiple images, choice of which image
515     * is returned is implementation dependent).
516     *
517     * @param bytes  A valid byte array
518     * @param params Optional instructions for special-handling or
519     *               interpretation of the input data (null objects are permitted and
520     *               must be supported by implementations).
521     * @return A valid instance of BufferedImage.
522     * @throws ImageReadException In the event that the specified content
523     *                            does not conform to the format of the specific
524     *                            parser implementation.
525     * @throws IOException        In the event of unsuccessful read or access operation.
526     */
527    public final BufferedImage getBufferedImage(final byte[] bytes, final T params)
528            throws ImageReadException, IOException {
529        return getBufferedImage(new ByteSourceArray(bytes), params);
530    }
531
532    /**
533     * Gets a buffered image specified by the indicated file  (for
534     * sources that specify multiple images, choice of which image
535     * is returned is implementation dependent).
536     *
537     * @param file   A valid file reference.
538     * @param params Optional instructions for special-handling or
539     *               interpretation of the input data (null objects are permitted and
540     *               must be supported by implementations).
541     * @return A valid instance of BufferedImage.
542     * @throws ImageReadException In the event that the specified content
543     *                            does not conform to the format of the specific
544     *                            parser implementation.
545     * @throws IOException        In the event of unsuccessful read or access operation.
546     */
547    public final BufferedImage getBufferedImage(final File file, final T params)
548            throws ImageReadException, IOException {
549        if (!canAcceptExtension(file)) {
550            return null;
551        }
552
553        return getBufferedImage(new ByteSourceFile(file), params);
554    }
555
556
557    /**
558     * Writes the content of a BufferedImage to the specified output
559     * stream.
560     *
561     * <p>The params argument provides a mechanism for individual
562     * implementations to pass optional information into the parser.
563     * Not all formats will support this capability.  Currently,
564     * some of the parsers do not check for null arguments.</p>
565     *
566     * @param src    An image giving the source content for output
567     * @param os     A valid output stream for storing the formatted image
568     * @param params optional parameters, defining format-specific instructions for output
569     *               (such as selections for data compression, color models, etc.)
570     * @throws ImageWriteException In the event that the output format
571     *                             cannot handle the input image or invalid params are specified.
572     * @throws IOException         In the event of an write error from
573     *                             the output stream.
574     */
575    public void writeImage(final BufferedImage src, final OutputStream os, T params)
576            throws ImageWriteException, IOException {
577        os.close(); // we are obligated to close stream.
578
579        throw new ImageWriteException("This image format (" + getName() + ") cannot be written.");
580    }
581
582    /**
583     * Get the size of the image described by the specified byte array.
584     *
585     * @param bytes A valid byte array.
586     * @return A valid instance of Dimension.
587     * @throws ImageReadException In the event that the specified content
588     *                            does not conform to the format of the specific
589     *                            parser implementation.
590     * @throws IOException        In the event of unsuccessful read or access operation.
591     */
592    public final Dimension getImageSize(final byte[] bytes) throws ImageReadException, IOException {
593        return getImageSize(bytes, null);
594    }
595
596    /**
597     * Get the size of the image described by the specified byte array.
598     *
599     * @param bytes  A valid byte array.
600     * @param params Optional instructions for special-handling or
601     *               interpretation of the input data.
602     * @return A valid instance of Dimension.
603     * @throws ImageReadException In the event that the specified content
604     *                            does not conform to the format of the specific
605     *                            parser implementation.
606     * @throws IOException        In the event of unsuccessful read or access operation.
607     */
608    public final Dimension getImageSize(final byte[] bytes, final T params)
609            throws ImageReadException, IOException {
610        return getImageSize(new ByteSourceArray(bytes), params);
611    }
612
613    /**
614     * Get the size of the image described by the specified file.
615     *
616     * @param file A valid reference to a file.
617     * @return A valid instance of Dimension.
618     * @throws ImageReadException In the event that the specified content
619     *                            does not conform to the format of the specific
620     *                            parser implementation.
621     * @throws IOException        In the event of unsuccessful read or access operation.
622     */
623    public final Dimension getImageSize(final File file) throws ImageReadException, IOException {
624        return getImageSize(file, null);
625    }
626
627    /**
628     * Get the size of the image described by the specified file.
629     *
630     * @param file   A valid reference to a file.
631     * @param params Optional instructions for special-handling or
632     *               interpretation of the input data.
633     * @return A valid instance of Dimension.
634     * @throws ImageReadException In the event that the specified content
635     *                            does not conform to the format of the specific
636     *                            parser implementation.
637     * @throws IOException        In the event of unsuccessful read or access operation.
638     */
639    public final Dimension getImageSize(final File file, final T params)
640            throws ImageReadException, IOException {
641
642        if (!canAcceptExtension(file)) {
643            return null;
644        }
645
646        return getImageSize(new ByteSourceFile(file), params);
647    }
648
649    /**
650     * Get the size of the image described by the specified ByteSource.
651     *
652     * @param byteSource A valid reference to a ByteSource.
653     * @param params     Optional instructions for special-handling or
654     *                   interpretation of the input data.
655     * @return A valid instance of Dimension.
656     * @throws ImageReadException In the event that the specified content
657     *                            does not conform to the format of the specific
658     *                            parser implementation.
659     * @throws IOException        In the event of unsuccessful read or access operation.
660     */
661    public abstract Dimension getImageSize(ByteSource byteSource, T params)
662            throws ImageReadException, IOException;
663
664    /**
665     * Get an array of bytes describing the International Color Consortium (ICC)
666     * specification for the color space of the image contained in the
667     * input byte array. Not all formats support ICC profiles.
668     *
669     * @param bytes A valid array of bytes.
670     * @return If available, a valid array of bytes; otherwise, a null
671     * @throws ImageReadException In the event that the specified content
672     *                            does not conform to the format of the specific
673     *                            parser implementation.
674     * @throws IOException        In the event of unsuccessful read or access operation.
675     */
676    public final byte[] getICCProfileBytes(final byte[] bytes) throws ImageReadException, IOException {
677        return getICCProfileBytes(bytes, null);
678    }
679
680    /**
681     * Get an array of bytes describing the International Color Consortium (ICC)
682     * specification for the color space of the image contained in the
683     * input byte array. Not all formats support ICC profiles.
684     *
685     * @param bytes  A valid array of bytes.
686     * @param params Optional instructions for special-handling or
687     *               interpretation of the input data.
688     * @return If available, a valid array of bytes; otherwise, a null
689     * @throws ImageReadException In the event that the specified content
690     *                            does not conform to the format of the specific
691     *                            parser implementation.
692     * @throws IOException        In the event of unsuccessful read or access operation.
693     */
694    public final byte[] getICCProfileBytes(final byte[] bytes, final T params)
695            throws ImageReadException, IOException {
696        return getICCProfileBytes(new ByteSourceArray(bytes), params);
697    }
698
699    /**
700     * Get an array of bytes describing the International Color Consortium (ICC)
701     * specification for the color space of the image contained in the
702     * input file. Not all formats support ICC profiles.
703     *
704     * @param file A valid file reference.
705     * @return If available, a valid array of bytes; otherwise, a null
706     * @throws ImageReadException In the event that the specified content
707     *                            does not conform to the format of the specific
708     *                            parser implementation.
709     * @throws IOException        In the event of unsuccessful read or access operation.
710     */
711    public final byte[] getICCProfileBytes(final File file) throws ImageReadException, IOException {
712        return getICCProfileBytes(file, null);
713    }
714
715    /**
716     * Get an array of bytes describing the International Color Consortium (ICC)
717     * specification for the color space of the image contained in the
718     * input file. Not all formats support ICC profiles.
719     *
720     * @param file   A valid file reference.
721     * @param params Optional instructions for special-handling or
722     *               interpretation of the input data.
723     * @return If available, a valid array of bytes; otherwise, a null
724     * @throws ImageReadException In the event that the specified content
725     *                            does not conform to the format of the specific
726     *                            parser implementation.
727     * @throws IOException        In the event of unsuccessful read or access operation.
728     */
729    public final byte[] getICCProfileBytes(final File file, final T params)
730            throws ImageReadException, IOException {
731        if (!canAcceptExtension(file)) {
732            return null;
733        }
734
735        if (LOGGER.isLoggable(Level.FINEST)) {
736            LOGGER.finest(getName() + ": " + file.getName());
737        }
738
739        return getICCProfileBytes(new ByteSourceFile(file), params);
740    }
741
742    /**
743     * Get an array of bytes describing the International Color Consortium (ICC)
744     * specification for the color space of the image contained in the
745     * input byteSource. Not all formats support ICC profiles.
746     *
747     * @param byteSource A valid ByteSource.
748     * @param params     Optional instructions for special-handling or
749     *                   interpretation of the input data.
750     * @return If available, a valid array of bytes; otherwise, a null
751     * @throws ImageReadException In the event that the specified content
752     *                            does not conform to the format of the specific
753     *                            parser implementation.
754     * @throws IOException        In the event of unsuccessful read or access operation.
755     */
756    public abstract byte[] getICCProfileBytes(ByteSource byteSource, T params)
757            throws ImageReadException, IOException;
758
759    /**
760     * Write the ImageInfo and format-specific information for the image
761     * content of the specified byte array to a string.
762     *
763     * @param bytes A valid array of bytes.
764     * @return A valid string.
765     * @throws ImageReadException In the event that the specified content
766     *                            does not conform to the format of the specific
767     *                            parser implementation.
768     * @throws IOException        In the event of unsuccessful read or access operation.
769     */
770    public final String dumpImageFile(final byte[] bytes) throws ImageReadException, IOException {
771        return dumpImageFile(new ByteSourceArray(bytes));
772    }
773
774
775    /**
776     * Write the ImageInfo and format-specific information for the image
777     * content of the specified file to a string.
778     *
779     * @param file A valid file reference.
780     * @return A valid string.
781     * @throws ImageReadException In the event that the specified content
782     *                            does not conform to the format of the specific
783     *                            parser implementation.
784     * @throws IOException        In the event of unsuccessful read or access operation.
785     */
786    public final String dumpImageFile(final File file) throws ImageReadException, IOException {
787        if (!canAcceptExtension(file)) {
788            return null;
789        }
790
791        if (LOGGER.isLoggable(Level.FINEST)) {
792            LOGGER.finest(getName() + ": " + file.getName());
793        }
794
795        return dumpImageFile(new ByteSourceFile(file));
796    }
797
798    /**
799     * Write the ImageInfo and format-specific information for the image
800     * content of the specified byte source to a string.
801     *
802     * @param byteSource A valid byte source.
803     * @return A valid string.
804     * @throws ImageReadException In the event that the specified content
805     *                            does not conform to the format of the specific
806     *                            parser implementation.
807     * @throws IOException        In the event of unsuccessful read or access operation.
808     */
809    public final String dumpImageFile(final ByteSource byteSource)
810            throws ImageReadException, IOException {
811        final StringWriter sw = new StringWriter();
812        final PrintWriter pw = new PrintWriter(sw);
813
814        dumpImageFile(pw, byteSource);
815
816        pw.flush();
817
818        return sw.toString();
819    }
820
821    /**
822     * Write the ImageInfo and format-specific information for the image
823     * content of the specified byte source to a PrintWriter
824     *
825     * @param pw print writer used for writing the ImageInfo
826     * @param byteSource A valid byte source.
827     * @return A valid PrintWriter.
828     * @throws ImageReadException In the event that the specified content
829     *                            does not conform to the format of the specific
830     *                            parser implementation.
831     * @throws IOException        In the event of unsuccessful read or access operation.
832     */
833    public boolean dumpImageFile(final PrintWriter pw, final ByteSource byteSource)
834            throws ImageReadException, IOException {
835        return false;
836    }
837
838
839    /**
840     * Get a descriptive name for the implementation of an ImageParser.
841     *
842     * @return a valid, subject-matter-specific string.
843     */
844    public abstract String getName();
845
846    /**
847     * Get the default extension for the format specified by an implementation
848     * of ImageParser.  Some parsers can support more than one extension
849     * (i.e. .JPEG, .JPG;  .TIF, .TIFF, etc.).
850     *
851     * @return A valid string.
852     */
853    public abstract String getDefaultExtension();
854
855    /**
856     * Get an array of all accepted extensions
857     *
858     * @return A valid array of one or more elements.
859     */
860    protected abstract String[] getAcceptedExtensions();
861
862    /**
863     * Get an array of ImageFormat objects describing all accepted types
864     *
865     * @return A valid array of one or more elements.
866     */
867    protected abstract ImageFormat[] getAcceptedTypes();
868
869    /**
870     * Indicates whether the ImageParser implementation can accept
871     * the specified format
872     *
873     * @param type An instance of ImageFormat.
874     * @return If the parser can accept the format, true; otherwise, false.
875     */
876    public boolean canAcceptType(final ImageFormat type) {
877        final ImageFormat[] types = getAcceptedTypes();
878
879        for (final ImageFormat type2 : types) {
880            if (type2.equals(type)) {
881                return true;
882            }
883        }
884        return false;
885    }
886
887    /**
888     * Indicates whether the ImageParser implementation can accept
889     * the specified file based on its extension.
890     *
891     * @param file An valid file reference.
892     * @return If the parser can accept the format, true; otherwise, false.
893     */
894    public boolean canAcceptExtension(final File file) {
895        return canAcceptExtension(file.getName());
896    }
897
898    /**
899     * Indicates whether the ImageParser implementation can accept
900     * the specified file name based on its extension.
901     *
902     * @param fileName A valid string giving a file name or file path.
903     * @return If the parser can accept the format, true; otherwise, false.
904     */
905    public final boolean canAcceptExtension(final String fileName) {
906        final String[] extensions = getAcceptedExtensions();
907        if (extensions == null) {
908            return true;
909        }
910
911        final int index = fileName.lastIndexOf('.');
912        if (index >= 0) {
913            final String fileNameExtension = fileName.substring(index + 1).toLowerCase(Locale.ENGLISH);
914            for (final String extension : extensions) {
915                if (extension.equals(fileNameExtension)) {
916                    return true;
917                }
918            }
919        }
920        return false;
921    }
922
923    /**
924     * Get an instance of IBufferedImageFactory based on the presence
925     * of a specification for ImagingConstants.&#46;BUFFERED_IMAGE_FACTORY
926     * within the supplied params.
927     *
928     * @param params optional parameters.
929     * @return A valid instance of an implementation of a IBufferedImageFactory.
930     */
931    protected BufferedImageFactory getBufferedImageFactory(final T params) {
932        if (params == null) {
933            return new SimpleBufferedImageFactory();
934        }
935
936        final BufferedImageFactory result = params.getBufferedImageFactory();
937
938        if (null != result) {
939            return result;
940        }
941
942        return new SimpleBufferedImageFactory();
943    }
944}