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