View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.imaging;
18  
19  import java.awt.Dimension;
20  import java.awt.image.BufferedImage;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.OutputStream;
24  import java.io.PrintWriter;
25  import java.io.StringWriter;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.List;
29  import java.util.Locale;
30  import java.util.logging.Level;
31  import java.util.logging.Logger;
32  
33  import org.apache.commons.imaging.common.BinaryFileParser;
34  import org.apache.commons.imaging.common.BufferedImageFactory;
35  import org.apache.commons.imaging.common.ImageMetadata;
36  import org.apache.commons.imaging.common.SimpleBufferedImageFactory;
37  import org.apache.commons.imaging.common.bytesource.ByteSource;
38  import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
39  import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
40  import org.apache.commons.imaging.formats.bmp.BmpImageParser;
41  import org.apache.commons.imaging.formats.dcx.DcxImageParser;
42  import org.apache.commons.imaging.formats.gif.GifImageParser;
43  import org.apache.commons.imaging.formats.icns.IcnsImageParser;
44  import org.apache.commons.imaging.formats.ico.IcoImageParser;
45  import org.apache.commons.imaging.formats.jpeg.JpegImageParser;
46  import org.apache.commons.imaging.formats.pcx.PcxImageParser;
47  import org.apache.commons.imaging.formats.png.PngImageParser;
48  import org.apache.commons.imaging.formats.pnm.PnmImageParser;
49  import org.apache.commons.imaging.formats.psd.PsdImageParser;
50  import org.apache.commons.imaging.formats.rgbe.RgbeImageParser;
51  import org.apache.commons.imaging.formats.tiff.TiffImageParser;
52  import org.apache.commons.imaging.formats.wbmp.WbmpImageParser;
53  import org.apache.commons.imaging.formats.xbm.XbmImageParser;
54  import org.apache.commons.imaging.formats.xpm.XpmImageParser;
55  
56  /**
57   * Provides the abstract base class for all image reading and writing
58   * utilities.  ImageParser implementations are expected to extend this
59   * class providing logic for identifying and processing data in their
60   * own specific format.   Specific implementations are found
61   * under the com.apache.commons.imaging.formats package.
62   *
63   * <h2>Application Notes</h2>
64   *
65   * <h3>Format support</h3>
66   *
67   * For the most recent information on format support for the
68   * Apache Commons Imaging package, refer to
69   * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a>
70   * at the main project development web site.
71   *
72   * <h3>On the accuracy of this Javadoc</h3>
73   *
74   * The original authors of this class did not supply documentation.
75   * The Javadoc for this class is based on inspection of the
76   * source code.  In some cases, the purpose and usage for particular
77   * methods was deduced from the source and may not perfectly reflect
78   * the intentions of the original. Therefore, you should not assume
79   * that the documentation is perfect, especially in the more obscure
80   * and specialized areas of implementation.
81   *
82   * <h3>The "params" argument</h3>
83   *
84   * <p>Many of the methods specified by this class accept an argument of
85   * type {@code T} defining the parameters to be used when
86   * processing an image. For example, some of the output formats permit
87   * of different kinds of image compression or color models. Some of the
88   * reading methods permit the calling application to require strict
89   * format compliance.</p>
90   *
91   * @param <T> type of parameters used by this image parser
92   */
93  public abstract class ImageParser<T extends ImagingParameters> extends BinaryFileParser {
94  
95      private static final Logger LOGGER = Logger.getLogger(ImageParser.class.getName());
96  
97      /**
98       * Gets an array of new instances of all image parsers.
99       *
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 }