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