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.List;
28  import java.util.Locale;
29  import java.util.Map;
30  
31  import org.apache.commons.imaging.common.BinaryFileParser;
32  import org.apache.commons.imaging.common.BufferedImageFactory;
33  import org.apache.commons.imaging.common.ImageMetadata;
34  import org.apache.commons.imaging.common.SimpleBufferedImageFactory;
35  import org.apache.commons.imaging.common.bytesource.ByteSource;
36  import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
37  import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
38  import org.apache.commons.imaging.formats.bmp.BmpImageParser;
39  import org.apache.commons.imaging.formats.dcx.DcxImageParser;
40  import org.apache.commons.imaging.formats.gif.GifImageParser;
41  import org.apache.commons.imaging.formats.icns.IcnsImageParser;
42  import org.apache.commons.imaging.formats.ico.IcoImageParser;
43  import org.apache.commons.imaging.formats.jpeg.JpegImageParser;
44  import org.apache.commons.imaging.formats.pcx.PcxImageParser;
45  import org.apache.commons.imaging.formats.png.PngImageParser;
46  import org.apache.commons.imaging.formats.pnm.PnmImageParser;
47  import org.apache.commons.imaging.formats.psd.PsdImageParser;
48  import org.apache.commons.imaging.formats.rgbe.RgbeImageParser;
49  import org.apache.commons.imaging.formats.tiff.TiffImageParser;
50  import org.apache.commons.imaging.formats.wbmp.WbmpImageParser;
51  import org.apache.commons.imaging.formats.xbm.XbmImageParser;
52  import org.apache.commons.imaging.formats.xpm.XpmImageParser;
53  
54  /**
55   * Provides the abstract base class for all image reading and writing
56   * utilities.  ImageParser implementations are expected to extend this
57   * class providing logic for identifying and processing data in their
58   * own specific format.   Specific implementations are found
59   * under the com.apache.commons.imaging.formats package.
60   * 
61   * <h3>Application Notes</h3>
62   * 
63   * <h4>Format support</h4>
64   * 
65   * For the most recent information on format support for the
66   * Apache Commons Imaging package, refer to
67   * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
68   * at the main project development web site.
69   * 
70   * <h4>On the accuracy of this Javadoc</h4>
71   * 
72   * The original authors of this class did not supply documentation.
73   * The Javadoc for this class is based on inspection of the
74   * source code.  In some cases, the purpose and usage for particular
75   * methods was deduced from the source and may not perfectly reflect
76   * the intentions of the original. Therefore, you should not assume
77   * that the documentation is perfect, especially in the more obscure
78   * and specialized areas of implementation.
79   * 
80   * <h4>The "Map params" argument</h4>
81   * 
82   * Many of the methods specified by this class accept an argument of
83   * type Map giving a list of parameters to be used when processing an
84   * image. For example, some of the output formats permit the specification
85   * of different kinds of image compression or color models. Some of the
86   * reading methods permit the calling application to require strict
87   * format compliance.   In many cases, however, an application will not
88   * require the use of this argument.  While some of the ImageParser
89   * implementations check for (and ignore) null arguments for this parameter,
90   * not all of them do (at least not at the time these notes were written).
91   * Therefore, a prudent programmer will always supply an valid, though
92   * empty instance of a Map implementation when calling such methods.
93   * Generally, the java HashMap class is useful for this purpose.
94   * 
95   * <p>Additionally, developers creating or enhancing classes derived
96   * from ImageParser are encouraged to include such checks in their code.
97   */
98  public abstract class ImageParser extends BinaryFileParser {
99  
100     /**
101      * Gets an array of new instances of all image parsers.
102      *
103      * @return A valid array of image parsers
104      */
105     public static ImageParser[] getAllImageParsers() {
106 
107         return new ImageParser[]{
108                 new BmpImageParser(),
109                 new DcxImageParser(),
110                 new GifImageParser(),
111                 new IcnsImageParser(),
112                 new IcoImageParser(),
113                 new JpegImageParser(),
114                 new PcxImageParser(),
115                 new PngImageParser(),
116                 new PnmImageParser(),
117                 new PsdImageParser(),
118                 new RgbeImageParser(),
119                 new TiffImageParser(),
120                 new WbmpImageParser(),
121                 new XbmImageParser(),
122                 new XpmImageParser(),
123                 // new JBig2ImageParser(),
124                 // new TgaImageParser(),
125         };
126     }
127 
128     /**
129      * Get image metadata from the specified byte source.  Format-specific
130      * ImageParser implementations are expected to return a valid
131      * IImageMetadata object or to throw an ImageReadException if unable
132      * to process the specified byte source.
133      *
134      * @param byteSource A valid byte source.
135      * @return A valid, potentially subject-matter-specific implementation of
136      *         the IImageMetadata interface describing the content extracted
137      *         from the source content.
138      * @throws ImageReadException In the event that the the ByteSource
139      *                            content does not conform to the format of the specific parser
140      *                            implementation.
141      * @throws IOException        In the event of unsuccessful data read operation.
142      */
143     public final ImageMetadata getMetadata(final ByteSource byteSource) throws ImageReadException, IOException {
144         return getMetadata(byteSource, null);
145     }
146 
147     /**
148      * Get image metadata from the specified byte source.  Format-specific
149      * ImageParser implementations are expected to return a valid
150      * IImageMetadata object or to throw an ImageReadException if unable
151      * to process the specified byte source.
152      * 
153      * <p>The params argument provides a mechanism for individual
154      * implementations to pass optional information into the parser.
155      * Not all formats will require this capability.  Because the
156      * base class may call this method with a null params argument,
157      * implementations should <strong>always</strong> include logic
158      * for ignoring null input.
159      *
160      * @param byteSource A valid byte source.
161      * @param params     Optional instructions for special-handling or
162      *                   interpretation of the input data (null objects are permitted and
163      *                   must be supported by implementations).
164      * @return A valid, potentially subject-matter-specific implementation of
165      *         the IImageMetadata interface describing the content extracted
166      *         from the source content.
167      * @throws ImageReadException In the event that the the ByteSource
168      *                            content does not conform to the format of the specific parser
169      *                            implementation.
170      * @throws IOException        In the event of unsuccessful data read operation.
171      */
172     public abstract ImageMetadata getMetadata(ByteSource byteSource, Map<String, Object> params)
173             throws ImageReadException, IOException;
174 
175     /**
176      * Get image metadata from the specified array of bytes.  Format-specific
177      * ImageParser implementations are expected to return a valid
178      * IImageMetadata object or to throw an ImageReadException if unable
179      * to process the specified data.
180      *
181      * @param bytes A valid array of bytes
182      * @return A valid, potentially subject-matter-specific implementation of
183      *         the IImageMetadata interface describing the content extracted
184      *         from the source content.
185      * @throws ImageReadException In the event that the the specified content
186      *                            does not conform to the format of the specific
187      *                            parser implementation.
188      * @throws IOException        In the event of unsuccessful data read operation.
189      */
190     public final ImageMetadata getMetadata(final byte[] bytes) throws ImageReadException, IOException {
191         return getMetadata(bytes, null);
192     }
193 
194     /**
195      * Get image metadata from the specified array of bytes.  Format-specific
196      * ImageParser implementations are expected to return a valid
197      * IImageMetadata object or to throw an ImageReadException if unable
198      * to process the specified data.
199      * 
200      * <p>The params argument provides a mechanism for individual
201      * implementations to pass optional information into the parser.
202      * Not all formats will require this capability.  Because the
203      * base class may call this method with a null params argument,
204      * implementations should <strong>always</strong> include logic
205      * for ignoring null input.
206      *
207      * @param bytes  A valid array of bytes
208      * @param params Optional instructions for special-handling or
209      *               interpretation of the input data (null objects are permitted and
210      *               must be supported by implementations).
211      * @return A valid image metadata object describing the content extracted
212      *         from  the specified content.
213      * @throws ImageReadException In the event that the the specified content
214      *                            does not conform to the format of the specific
215      *                            parser implementation.
216      * @throws IOException        In the event of unsuccessful data read operation.
217      */
218     public final ImageMetadata getMetadata(final byte[] bytes, final Map<String, Object> params)
219             throws ImageReadException, IOException {
220         return getMetadata(new ByteSourceArray(bytes), params);
221     }
222 
223     /**
224      * Get image metadata from the specified file.  Format-specific
225      * ImageParser implementations are expected to return a valid
226      * IImageMetadata object or to throw an ImageReadException if unable
227      * to process the specified data.
228      *
229      * @param file A valid reference to a file.
230      * @return A valid image metadata object describing the content extracted
231      *         from  the specified content.
232      * @throws ImageReadException In the event that the the specified content
233      *                            does not conform to the format of the specific
234      *                            parser implementation.
235      * @throws IOException        In the event of unsuccessful file read or
236      *                            access operation.
237      */
238     public final ImageMetadata getMetadata(final File file) throws ImageReadException, IOException {
239         return getMetadata(file, null);
240     }
241 
242     /**
243      * Get image metadata from the specified file.  Format-specific
244      * ImageParser implementations are expected to return a valid
245      * IImageMetadata object or to throw an ImageReadException if unable
246      * to process the specified data.
247      * 
248      * <p>The params argument provides a mechanism for individual
249      * implementations to pass optional information into the parser.
250      * Not all formats will require this capability.  Because the
251      * base class may call this method with a null params argument,
252      * implementations should <strong>always</strong> include logic
253      * for ignoring null input.
254      *
255      * @param file   A valid reference to a file.
256      * @param params Optional instructions for special-handling or
257      *               interpretation of the input data (null objects are permitted and
258      *               must be supported by implementations).
259      * @return A valid image metadata object describing the content extracted
260      *         from  the specified content.
261      * @throws ImageReadException In the event that the the specified content
262      *                            does not conform to the format of the specific
263      *                            parser implementation.
264      * @throws IOException        In the event of unsuccessful file read or
265      *                            access operation.
266      */
267     public final ImageMetadata getMetadata(final File file, final Map<String, Object> params)
268             throws ImageReadException, IOException {
269         if (getDebug()) {
270             System.out.println(getName() + ".getMetadata" + ": "
271                     + file.getName());
272         }
273 
274         if (!canAcceptExtension(file)) {
275             return null;
276         }
277 
278         return getMetadata(new ByteSourceFile(file), params);
279     }
280 
281     /**
282      * Get image information from the specified ByteSource. Format-specific
283      * ImageParser implementations are expected to return a valid
284      * ImageInfo object or to throw an ImageReadException if unable
285      * to process the specified data.
286      * 
287      * <p>The params argument provides a mechanism for individual
288      * implementations to pass optional information into the parser.
289      * Not all formats will require this capability.  Because the
290      * base class may call this method with a null params argument,
291      * implementations should <strong>always</strong> include logic
292      * for ignoring null input.
293      *
294      * @param byteSource A valid ByteSource object
295      * @param params     Optional instructions for special-handling or interpretation
296      *                   of the input data (null objects are permitted and
297      *                   must be supported by implementations).
298      * @return A valid image information object describing the content extracted
299      *         from the specified data.
300      * @throws ImageReadException In the event that the the specified content
301      *                            does not conform to the format of the specific
302      *                            parser implementation.
303      * @throws IOException        In the event of unsuccessful data access operation.
304      */
305     public abstract ImageInfo getImageInfo(ByteSource byteSource, Map<String, Object> params)
306             throws ImageReadException, IOException;
307 
308     /**
309      * Get image information from the specified ByteSource.  Format-specific
310      * ImageParser implementations are expected to return a valid
311      * ImageInfo object or to throw an ImageReadException if unable
312      * to process the specified data.
313      *
314      * @param byteSource A valid ByteSource object
315      * @return A valid image information object describing the content extracted
316      *         from the specified data.
317      * @throws ImageReadException In the event that the the specified content
318      *                            does not conform to the format of the specific
319      *                            parser implementation.
320      * @throws IOException        In the event of unsuccessful data
321      *                            access operation.
322      */
323     public final ImageInfo getImageInfo(final ByteSource byteSource) throws ImageReadException, IOException {
324         return getImageInfo(byteSource, null);
325     }
326 
327     /**
328      * Get image information from the specified array of bytes.  Format-specific
329      * ImageParser implementations are expected to return a valid
330      * ImageInfo object or to throw an ImageReadException if unable
331      * to process the specified data.
332      * <p>The params argument provides a mechanism for individual
333      * implementations to pass optional information into the parser.
334      * Not all formats will require this capability.  Because the
335      * base class may call this method with a null params argument,
336      * implementations should <strong>always</strong> include logic
337      * for ignoring null input.
338      *
339      * @param bytes  A valid array of bytes
340      * @param params Optional instructions for special-handling or
341      *               interpretation of the input data (null objects are permitted and
342      *               must be supported by implementations).
343      * @return A valid image information object describing the content extracted
344      *         from the specified data.
345      * @throws ImageReadException In the event that the the specified content
346      *                            does not conform to the format of the specific
347      *                            parser implementation.
348      * @throws IOException        In the event of unsuccessful data
349      *                            access operation.
350      */
351     public final ImageInfo getImageInfo(final byte[] bytes, final Map<String, Object> params)
352             throws ImageReadException, IOException {
353         return getImageInfo(new ByteSourceArray(bytes), params);
354     }
355 
356     /**
357      * Get image information from the specified file  Format-specific
358      * ImageParser implementations are expected to return a valid
359      * ImageInfo object or to throw an ImageReadException if unable
360      * to process the specified data.
361      * <p>The params argument provides a mechanism for individual
362      * implementations to pass optional information into the parser.
363      * Not all formats will require this capability.  Because the
364      * base class may call this method with a null params argument,
365      * implementations should <strong>always</strong> include logic
366      * for ignoring null input.
367      *
368      * @param file   A valid File object
369      * @param params Optional instructions for special-handling or
370      *               interpretation of the input data (null objects are permitted and
371      *               must be supported by implementations).
372      * @return A valid image information object describing the content extracted
373      *         from the specified data.
374      * @throws ImageReadException In the event that the the specified content
375      *                            does not conform to the format of the specific
376      *                            parser implementation.
377      * @throws IOException        In the event of unsuccessful file read or
378      *                            access operation.
379      */
380     public final ImageInfo getImageInfo(final File file, final Map<String, Object> params)
381             throws ImageReadException, IOException {
382         if (!canAcceptExtension(file)) {
383             return null;
384         }
385 
386         return getImageInfo(new ByteSourceFile(file), params);
387     }
388 
389     /**
390      * Determines the format compliance of the content of the supplied byte
391      * source based on rules provided by a specific implementation.
392      *
393      * @param byteSource A valid instance of ByteSource
394      * @return true if the content is format-compliant; otherwise, false
395      * @throws ImageReadException may be thrown by sub-classes
396      * @throws IOException        may be thrown by sub-classes
397      */
398     public FormatCompliance getFormatCompliance(final ByteSource byteSource)
399             throws ImageReadException, IOException {
400         return null;
401     }
402 
403     /**
404      * Determines the format compliance of the content of the supplied byte
405      * array based on rules provided by a specific implementation.
406      *
407      * @param bytes A valid byte array.
408      * @return A valid FormatCompliance object.
409      * @throws ImageReadException may be thrown by sub-classes
410      * @throws IOException        may be thrown by sub-classes
411      */
412     public final FormatCompliance getFormatCompliance(final byte[] bytes)
413             throws ImageReadException, IOException {
414         return getFormatCompliance(new ByteSourceArray(bytes));
415     }
416 
417     /**
418      * Determines the format compliance of the specified file based on
419      * rules provided by a specific implementation.
420      *
421      * @param file A valid reference to a file.
422      * @return A valid format compliance object.
423      * @throws ImageReadException may be thrown by sub-classes
424      * @throws IOException        may be thrown by sub-classes
425      */
426     public final FormatCompliance getFormatCompliance(final File file)
427             throws ImageReadException, IOException {
428         if (!canAcceptExtension(file)) {
429             return null;
430         }
431 
432         return getFormatCompliance(new ByteSourceFile(file));
433     }
434 
435     /**
436      * Gets all images specified by the byte source (some
437      * formats may include multiple images within a single data source).
438      *
439      * @param byteSource A valid instance of ByteSource.
440      * @return A valid (potentially empty) list of BufferedImage objects.
441      * @throws ImageReadException In the event that the the specified content
442      *                            does not conform to the format of the specific
443      *                            parser implementation.
444      * @throws IOException        In the event of unsuccessful read or access operation.
445      */
446     public List<BufferedImage> getAllBufferedImages(final ByteSource byteSource)
447             throws ImageReadException, IOException {
448         final BufferedImage bi = getBufferedImage(byteSource, null);
449 
450         final List<BufferedImage> result = new ArrayList<>();
451 
452         // FIXME this doesn't look like we're actually getting all images contained in the given ByteSource...
453         result.add(bi);
454 
455         return result;
456     }
457 
458     /**
459      * Gets all images specified by the byte array (some
460      * formats may include multiple images within a single data source).
461      *
462      * @param bytes A valid byte array
463      * @return A valid (potentially empty) list of BufferedImage objects.
464      * @throws ImageReadException In the event that the the specified content
465      *                            does not conform to the format of the specific
466      *                            parser implementation.
467      * @throws IOException        In the event of unsuccessful read or access operation.
468      */
469     public final List<BufferedImage> getAllBufferedImages(final byte[] bytes)
470             throws ImageReadException, IOException {
471         return getAllBufferedImages(new ByteSourceArray(bytes));
472     }
473 
474     /**
475      * Gets all images specified by indicated file (some
476      * formats may include multiple images within a single data source).
477      *
478      * @param file A valid reference to a file.
479      * @return A valid (potentially empty) list of BufferedImage objects.
480      * @throws ImageReadException In the event that the the specified content
481      *                            does not conform to the format of the specific
482      *                            parser implementation.
483      * @throws IOException        In the event of unsuccessful read or access operation.
484      */
485     public final List<BufferedImage> getAllBufferedImages(final File file) throws ImageReadException, IOException {
486         if (!canAcceptExtension(file)) {
487             return null;
488         }
489 
490         return getAllBufferedImages(new ByteSourceFile(file));
491     }
492 
493     /**
494      * Gets a buffered image specified by the byte source (for
495      * sources that specify multiple images, choice of which image
496      * is returned is implementation dependent).
497      *
498      * @param byteSource A valid instance of ByteSource
499      * @param params     Optional instructions for special-handling or
500      *                   interpretation of the input data (null objects are permitted and
501      *                   must be supported by implementations).
502      * @return A valid instance of BufferedImage.
503      * @throws ImageReadException In the event that the the specified content
504      *                            does not conform to the format of the specific
505      *                            parser implementation.
506      * @throws IOException        In the event of unsuccessful read or access operation.
507      */
508     public abstract BufferedImage getBufferedImage(ByteSource byteSource, Map<String, Object> params)
509             throws ImageReadException, IOException;
510 
511     /**
512      * Gets a buffered image specified by the byte array (for
513      * sources that specify multiple images, choice of which image
514      * is returned is implementation dependent).
515      *
516      * @param bytes  A valid byte array
517      * @param params Optional instructions for special-handling or
518      *               interpretation of the input data (null objects are permitted and
519      *               must be supported by implementations).
520      * @return A valid instance of BufferedImage.
521      * @throws ImageReadException In the event that the the specified content
522      *                            does not conform to the format of the specific
523      *                            parser implementation.
524      * @throws IOException        In the event of unsuccessful read or access operation.
525      */
526     public final BufferedImage getBufferedImage(final byte[] bytes, final Map<String, Object> params)
527             throws ImageReadException, IOException {
528         return getBufferedImage(new ByteSourceArray(bytes), params);
529     }
530 
531     /**
532      * Gets a buffered image specified by the indicated file  (for
533      * sources that specify multiple images, choice of which image
534      * is returned is implementation dependent).
535      *
536      * @param file   A valid file reference.
537      * @param params Optional instructions for special-handling or
538      *               interpretation of the input data (null objects are permitted and
539      *               must be supported by implementations).
540      * @return A valid instance of BufferedImage.
541      * @throws ImageReadException In the event that the the specified content
542      *                            does not conform to the format of the specific
543      *                            parser implementation.
544      * @throws IOException        In the event of unsuccessful read or access operation.
545      */
546     public final BufferedImage getBufferedImage(final File file, final Map<String, Object> params)
547             throws ImageReadException, IOException {
548         if (!canAcceptExtension(file)) {
549             return null;
550         }
551 
552         return getBufferedImage(new ByteSourceFile(file), params);
553     }
554 
555 
556     /**
557      * Writes the content of a BufferedImage to the specified output
558      * stream.
559      * 
560      * <p>The params argument provides a mechanism for individual
561      * implementations to pass optional information into the parser.
562      * Not all formats will support this capability.  Currently,
563      * some of the parsers do not check for null arguments. So in cases
564      * where no optional specifications are supported, application
565      * code should pass in an empty instance of an implementation of
566      * the map interface (i.e. an empty HashMap).
567      *
568      * @param src    An image giving the source content for output
569      * @param os     A valid output stream for storing the formatted image
570      * @param params A non-null Map implementation supplying optional,
571      *               format-specific instructions for output
572      *               (such as selections for data compression, color models, etc.)
573      * @throws ImageWriteException In the event that the output format
574      *                             cannot handle the input image or invalid params are specified.
575      * @throws IOException         In the event of an write error from
576      *                             the output stream.
577      */
578     public void writeImage(final BufferedImage src, final OutputStream os, final Map<String, Object> params)
579             throws ImageWriteException, IOException {
580         os.close(); // we are obligated to close stream.
581 
582         throw new ImageWriteException("This image format (" + getName()
583                 + ") cannot be written.");
584     }
585 
586     /**
587      * Get the size of the image described by the specified byte array.
588      *
589      * @param bytes A valid byte array.
590      * @return A valid instance of Dimension.
591      * @throws ImageReadException In the event that the the specified content
592      *                            does not conform to the format of the specific
593      *                            parser implementation.
594      * @throws IOException        In the event of unsuccessful read or access operation.
595      */
596     public final Dimension getImageSize(final byte[] bytes) throws ImageReadException, IOException {
597         return getImageSize(bytes, null);
598     }
599 
600     /**
601      * Get the size of the image described by the specified byte array.
602      *
603      * @param bytes  A valid byte array.
604      * @param params Optional instructions for special-handling or
605      *               interpretation of the input data.
606      * @return A valid instance of Dimension.
607      * @throws ImageReadException In the event that the the specified content
608      *                            does not conform to the format of the specific
609      *                            parser implementation.
610      * @throws IOException        In the event of unsuccessful read or access operation.
611      */
612     public final Dimension getImageSize(final byte[] bytes, final Map<String, Object> params)
613             throws ImageReadException, IOException {
614         return getImageSize(new ByteSourceArray(bytes), params);
615     }
616 
617     /**
618      * Get the size of the image described by the specified file.
619      *
620      * @param file A valid reference to a file.
621      * @return A valid instance of Dimension.
622      * @throws ImageReadException In the event that the the specified content
623      *                            does not conform to the format of the specific
624      *                            parser implementation.
625      * @throws IOException        In the event of unsuccessful read or access operation.
626      */
627     public final Dimension getImageSize(final File file) throws ImageReadException, IOException {
628         return getImageSize(file, null);
629     }
630 
631     /**
632      * Get the size of the image described by the specified file.
633      *
634      * @param file   A valid reference to a file.
635      * @param params Optional instructions for special-handling or
636      *               interpretation of the input data.
637      * @return A valid instance of Dimension.
638      * @throws ImageReadException In the event that the the specified content
639      *                            does not conform to the format of the specific
640      *                            parser implementation.
641      * @throws IOException        In the event of unsuccessful read or access operation.
642      */
643     public final Dimension getImageSize(final File file, final Map<String, Object> params)
644             throws ImageReadException, IOException {
645 
646         if (!canAcceptExtension(file)) {
647             return null;
648         }
649 
650         return getImageSize(new ByteSourceFile(file), params);
651     }
652 
653     /**
654      * Get the size of the image described by the specified ByteSource.
655      *
656      * @param byteSource A valid reference to a ByteSource.
657      * @param params     Optional instructions for special-handling or
658      *                   interpretation of the input data.
659      * @return A valid instance of Dimension.
660      * @throws ImageReadException In the event that the the specified content
661      *                            does not conform to the format of the specific
662      *                            parser implementation.
663      * @throws IOException        In the event of unsuccessful read or access operation.
664      */
665     public abstract Dimension getImageSize(ByteSource byteSource, Map<String, Object> params)
666             throws ImageReadException, IOException;
667 
668     /**
669      * Get a string containing XML-formatted text conforming to the Extensible
670      * Metadata  Platform (EXP) standard for representing information about
671      * image content.  Not all image formats support EXP infomation and
672      * even for those that do, there is no guarantee that such information
673      * will be present in an image.
674      *
675      * @param byteSource A valid reference to a ByteSource.
676      * @param params     Optional instructions for special-handling or
677      *                   interpretation of the input data.
678      * @return If XMP metadata is present, a valid string;
679      *         if it is not present, a null.
680      * @throws ImageReadException In the event that the the specified content
681      *                            does not conform to the format of the specific
682      *                            parser implementation.
683      * @throws IOException        In the event of unsuccessful read or access operation.
684      */
685     public abstract String getXmpXml(ByteSource byteSource, Map<String, Object> params)
686             throws ImageReadException, IOException;
687 
688     /**
689      * Get an array of bytes describing the International Color Consortium (ICC)
690      * specification for the color space of the image contained in the
691      * input byte array. Not all formats support ICC profiles.
692      *
693      * @param bytes A valid array of bytes.
694      * @return If available, a valid array of bytes; otherwise, a null
695      * @throws ImageReadException In the event that the the specified content
696      *                            does not conform to the format of the specific
697      *                            parser implementation.
698      * @throws IOException        In the event of unsuccessful read or access operation.
699      */
700     public final byte[] getICCProfileBytes(final byte[] bytes) throws ImageReadException, IOException {
701         return getICCProfileBytes(bytes, null);
702     }
703 
704     /**
705      * Get an array of bytes describing the International Color Consortium (ICC)
706      * specification for the color space of the image contained in the
707      * input byte array. Not all formats support ICC profiles.
708      *
709      * @param bytes  A valid array of bytes.
710      * @param params Optional instructions for special-handling or
711      *               interpretation of the input data.
712      * @return If available, a valid array of bytes; otherwise, a null
713      * @throws ImageReadException In the event that the the specified content
714      *                            does not conform to the format of the specific
715      *                            parser implementation.
716      * @throws IOException        In the event of unsuccessful read or access operation.
717      */
718     public final byte[] getICCProfileBytes(final byte[] bytes, final Map<String, Object> params)
719             throws ImageReadException, IOException {
720         return getICCProfileBytes(new ByteSourceArray(bytes), params);
721     }
722 
723     /**
724      * Get an array of bytes describing the International Color Consortium (ICC)
725      * specification for the color space of the image contained in the
726      * input file. Not all formats support ICC profiles.
727      *
728      * @param file A valid file reference.
729      * @return If available, a valid array of bytes; otherwise, a null
730      * @throws ImageReadException In the event that the the specified content
731      *                            does not conform to the format of the specific
732      *                            parser implementation.
733      * @throws IOException        In the event of unsuccessful read or access operation.
734      */
735     public final byte[] getICCProfileBytes(final File file) throws ImageReadException, IOException {
736         return getICCProfileBytes(file, null);
737     }
738 
739     /**
740      * Get an array of bytes describing the International Color Consortium (ICC)
741      * specification for the color space of the image contained in the
742      * input file. Not all formats support ICC profiles.
743      *
744      * @param file   A valid file reference.
745      * @param params Optional instructions for special-handling or
746      *               interpretation of the input data.
747      * @return If available, a valid array of bytes; otherwise, a null
748      * @throws ImageReadException In the event that the the specified content
749      *                            does not conform to the format of the specific
750      *                            parser implementation.
751      * @throws IOException        In the event of unsuccessful read or access operation.
752      */
753     public final byte[] getICCProfileBytes(final File file, final Map<String, Object> params)
754             throws ImageReadException, IOException {
755         if (!canAcceptExtension(file)) {
756             return null;
757         }
758 
759         if (getDebug()) {
760             System.out.println(getName() + ": " + file.getName());
761         }
762 
763         return getICCProfileBytes(new ByteSourceFile(file), params);
764     }
765 
766     /**
767      * Get an array of bytes describing the International Color Consortium (ICC)
768      * specification for the color space of the image contained in the
769      * input byteSoruce. Not all formats support ICC profiles.
770      *
771      * @param byteSource A valid ByteSource.
772      * @param params     Optional instructions for special-handling or
773      *                   interpretation of the input data.
774      * @return If available, a valid array of bytes; otherwise, a null
775      * @throws ImageReadException In the event that the the specified content
776      *                            does not conform to the format of the specific
777      *                            parser implementation.
778      * @throws IOException        In the event of unsuccessful read or access operation.
779      */
780     public abstract byte[] getICCProfileBytes(ByteSource byteSource, Map<String, Object> params)
781             throws ImageReadException, IOException;
782 
783     /**
784      * Write the ImageInfo and format-specific information for the image
785      * content of the specified byte array to a string.
786      *
787      * @param bytes A valid array of bytes.
788      * @return A valid string.
789      * @throws ImageReadException In the event that the the specified content
790      *                            does not conform to the format of the specific
791      *                            parser implementation.
792      * @throws IOException        In the event of unsuccessful read or access operation.
793      */
794     public final String dumpImageFile(final byte[] bytes) throws ImageReadException, IOException {
795         return dumpImageFile(new ByteSourceArray(bytes));
796     }
797 
798 
799     /**
800      * Write the ImageInfo and format-specific information for the image
801      * content of the specified file to a string.
802      *
803      * @param file A valid file reference.
804      * @return A valid string.
805      * @throws ImageReadException In the event that the the specified content
806      *                            does not conform to the format of the specific
807      *                            parser implementation.
808      * @throws IOException        In the event of unsuccessful read or access operation.
809      */
810     public final String dumpImageFile(final File file) throws ImageReadException, IOException {
811         if (!canAcceptExtension(file)) {
812             return null;
813         }
814 
815         if (getDebug()) {
816             System.out.println(getName() + ": " + file.getName());
817         }
818 
819         return dumpImageFile(new ByteSourceFile(file));
820     }
821 
822     /**
823      * Write the ImageInfo and format-specific information for the image
824      * content of the specified byte source to a string.
825      *
826      * @param byteSource A valid byte source.
827      * @return A valid string.
828      * @throws ImageReadException In the event that the 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 final String dumpImageFile(final ByteSource byteSource)
834             throws ImageReadException, IOException {
835         final StringWriter sw = new StringWriter();
836         final PrintWriter pw = new PrintWriter(sw);
837 
838         dumpImageFile(pw, byteSource);
839 
840         pw.flush();
841 
842         return sw.toString();
843     }
844 
845     /**
846      * Write the ImageInfo and format-specific information for the image
847      * content of the specified byte source to a PrintWriter
848      *
849      * @param byteSource A valid byte source.
850      * @return A valid PrintWriter.
851      * @throws ImageReadException In the event that the the specified content
852      *                            does not conform to the format of the specific
853      *                            parser implementation.
854      * @throws IOException        In the event of unsuccessful read or access operation.
855      */
856     public boolean dumpImageFile(final PrintWriter pw, final ByteSource byteSource)
857             throws ImageReadException, IOException {
858         return false;
859     }
860 
861 
862     /**
863      * Get a descriptive name for the implementation of an ImageParser.
864      *
865      * @return a valid, subject-matter-specific string.
866      */
867     public abstract String getName();
868 
869     /**
870      * Get the default extension for the format specified by an implementation
871      * of ImageParser.  Some parsers can support more than one extension
872      * (i.e. .JPEG, .JPG;  .TIF, .TIFF, etc.).
873      *
874      * @return A valid string.
875      */
876     public abstract String getDefaultExtension();
877 
878     /**
879      * Get an array of all accepted extensions
880      *
881      * @return A valid array of one or more elements.
882      */
883     protected abstract String[] getAcceptedExtensions();
884 
885     /**
886      * Get an array of ImageFormat objects describing all accepted types
887      *
888      * @return A valid array of one or more elements.
889      */
890     protected abstract ImageFormat[] getAcceptedTypes();
891 
892     /**
893      * Indicates whether the ImageParser implementation can accept
894      * the specified format
895      *
896      * @param type An instance of ImageFormat.
897      * @return If the parser can accept the format, true; otherwise, false.
898      */
899     public boolean canAcceptType(final ImageFormat type) {
900         final ImageFormat[] types = getAcceptedTypes();
901 
902         for (final ImageFormat type2 : types) {
903             if (type2.equals(type)) {
904                 return true;
905             }
906         }
907         return false;
908     }
909 
910     /**
911      * Indicates whether the ImageParser implementation can accept
912      * the specified file based on its extension.
913      *
914      * @param file An valid file reference.
915      * @return If the parser can accept the format, true; otherwise, false.
916      */
917     protected final boolean canAcceptExtension(final File file) {
918         return canAcceptExtension(file.getName());
919     }
920 
921     /**
922      * Indicates whether the ImageParser implementation can accept
923      * the specified file name based on its extension.
924      *
925      * @param filename An valid string giving a file name or file path.
926      * @return If the parser can accept the format, true; otherwise, false.
927      */
928     protected final boolean canAcceptExtension(final String filename) {
929         final String[] exts = getAcceptedExtensions();
930         if (exts == null) {
931             return true;
932         }
933 
934         final int index = filename.lastIndexOf('.');
935         if (index >= 0) {
936             String ext = filename.substring(index);
937             ext = ext.toLowerCase(Locale.ENGLISH);
938 
939             for (final String ext2 : exts) {
940                 final String ext2Lower = ext2.toLowerCase(Locale.ENGLISH);
941                 if (ext2Lower.equals(ext)) {
942                     return true;
943                 }
944             }
945         }
946         return false;
947     }
948 
949     /**
950      * Get an instance of IBufferedImageFactory based on the presence
951      * of a specification for ImagingConstants.&#46;BUFFERED_IMAGE_FACTORY
952      * within the supplied params.
953      *
954      * @param params A valid Map object, or a null.
955      * @return A valid instance of an implementation of a IBufferedImageFactory.
956      */
957     protected BufferedImageFactory getBufferedImageFactory(final Map<String, Object> params) {
958         if (params == null) {
959             return new SimpleBufferedImageFactory();
960         }
961 
962         final BufferedImageFactory result = (BufferedImageFactory) params.get(
963                 ImagingConstants.BUFFERED_IMAGE_FACTORY);
964 
965         if (null != result) {
966             return result;
967         }
968 
969         return new SimpleBufferedImageFactory();
970     }
971 
972     /**
973      * A utility method to search a params specification and determine
974      * whether it contains the ImagingConstants&#46;PARAM_KEY_STRICT
975      * specification. Intended
976      * for internal use by ImageParser implementations.
977      *
978      * @param params A valid Map object (or a null).
979      * @return If the params specify strict format compliance, true;
980      *         otherwise, false.
981      */
982     public static boolean isStrict(final Map<String, Object> params) {
983         if (params == null || !params.containsKey(ImagingConstants.PARAM_KEY_STRICT)) {
984             return false;
985         }
986         return ((Boolean) params.get(ImagingConstants.PARAM_KEY_STRICT)).booleanValue();
987     }
988 }