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