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 static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_FILENAME;
020import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_FORMAT;
021
022import java.awt.Dimension;
023import java.awt.color.ICC_Profile;
024import java.awt.image.BufferedImage;
025import java.io.BufferedOutputStream;
026import java.io.ByteArrayOutputStream;
027import java.io.File;
028import java.io.FileOutputStream;
029import java.io.IOException;
030import java.io.InputStream;
031import java.io.OutputStream;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Locale;
035import java.util.Map;
036
037import org.apache.commons.imaging.common.ImageMetadata;
038import org.apache.commons.imaging.common.bytesource.ByteSource;
039import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
040import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
041import org.apache.commons.imaging.common.bytesource.ByteSourceInputStream;
042import org.apache.commons.imaging.icc.IccProfileInfo;
043import org.apache.commons.imaging.icc.IccProfileParser;
044
045/**
046 * The primary application programming interface (API) to the Imaging library.
047 *
048 * <h3>Application Notes</h3>
049 *
050 * <h4>Using this class</h4>
051 *
052 * <p>
053 * Almost all of the Apache Commons Imaging library's core functionality can
054 * be accessed through the methods provided by this class.
055 * The use of the Imaging class is similar to the Java API's ImageIO class,
056 * though Imaging supports formats and options not included in the standard
057 * Java API.
058 * </p>
059 *
060 * <p>
061 * All of methods provided by the Imaging class are declared static.
062 * </p>
063 *
064 * <p>
065 * The Apache Commons Imaging package is a pure Java implementation.
066 * </p>
067 *
068 * <h4>Format support</h4>
069 *
070 * <p>
071 * While the Apache Commons Imaging package handles a number of different
072 * graphics formats, support for some formats is not yet complete.
073 * For the most recent information on support for specific formats, refer to
074 * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
075 * at the main project development web site.
076 * </p>
077 *
078 * <h4>Optional parameters for image reading and writing</h4>
079 *
080 * <p>
081 * Some of the methods provided by this class accept an optional
082 * <strong>params</strong> argument that permits the application to specify
083 * elements for special handling.  If these specifications are not required by
084 * the application, the params argument may be omitted (as appropriate) or
085 * a null argument may be provided. In image-writing operations, the option
086 * parameters may include options such as data-compression type (if any),
087 * color model, or other format-specific data representations.   The parameters
088 * map may also be used to provide EXIF Tags and other metadata to those
089 * formats that support them. In image-reading operations,
090 * the parameters may include information about special handling in reading
091 * the image data.
092 * </p>
093 *
094 * <p>
095 * Optional parameters are specified using a Map object (typically,
096 * a Java HashMap) to specify a set of keys and values for input.
097 * The specification for support keys is provided by the ImagingConstants
098 * interface as well as by format-specific interfaces such as
099 * JpegContants or TiffConstants.
100 * </p>
101 *
102 * <h4>Example code</h4>
103 *
104 * <p>
105 * See the source of the SampleUsage class and other classes in the
106 * org.apache.commons.imaging.examples package for examples.
107 * </p>
108 *
109 * @see <a
110 *      href="https://svn.apache.org/repos/asf/commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/SampleUsage.java">org.apache.commons.imaging.examples.SampleUsage</a>
111 * @see <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
112 */
113public final class Imaging {
114
115    private static final int[] MAGIC_NUMBERS_GIF = { 0x47, 0x49, };
116    private static final int[] MAGIC_NUMBERS_PNG = { 0x89, 0x50, };
117    private static final int[] MAGIC_NUMBERS_JPEG = { 0xff, 0xd8, };
118    private static final int[] MAGIC_NUMBERS_BMP = { 0x42, 0x4d, };
119    private static final int[] MAGIC_NUMBERS_TIFF_MOTOROLA = { 0x4D, 0x4D, };
120    private static final int[] MAGIC_NUMBERS_TIFF_INTEL = { 0x49, 0x49, };
121    private static final int[] MAGIC_NUMBERS_PAM = { 0x50, 0x37, };
122    private static final int[] MAGIC_NUMBERS_PSD = { 0x38, 0x42, };
123    private static final int[] MAGIC_NUMBERS_PBM_A = { 0x50, 0x31, };
124    private static final int[] MAGIC_NUMBERS_PBM_B = { 0x50, 0x34, };
125    private static final int[] MAGIC_NUMBERS_PGM_A = { 0x50, 0x32, };
126    private static final int[] MAGIC_NUMBERS_PGM_B = { 0x50, 0x35, };
127    private static final int[] MAGIC_NUMBERS_PPM_A = { 0x50, 0x33, };
128    private static final int[] MAGIC_NUMBERS_PPM_B = { 0x50, 0x36, };
129    private static final int[] MAGIC_NUMBERS_JBIG2_1 = { 0x97, 0x4A, };
130    private static final int[] MAGIC_NUMBERS_JBIG2_2 = { 0x42, 0x32, };
131    private static final int[] MAGIC_NUMBERS_ICNS = { 0x69, 0x63, };
132    private static final int[] MAGIC_NUMBERS_DCX = { 0xB1, 0x68, };
133    private static final int[] MAGIC_NUMBERS_RGBE = { 0x23, 0x3F, };
134
135    private Imaging() {
136        // Instances can not be created
137    }
138
139    /**
140     * Attempts to determine if a file contains an image recorded in
141     * a supported graphics format based on its file-name extension
142     * (for example "&#46jpg", "&#46;gif", "&#46;png", etc&#46;).
143     *
144     * @param file A valid File object providing a reference to
145     * a file that may contain an image.
146     * @return true if the file-name includes a supported image
147     * format file extension; otherwise, false.
148     */
149    public static boolean hasImageFileExtension(final File file) {
150        if (file == null || !file.isFile()) {
151            return false;
152        }
153        return hasImageFileExtension(file.getName());
154    }
155
156    /**
157     * Attempts to determine if a file contains an image recorded in
158     * a supported graphics format based on its file-name extension
159     * (for example "&#46jpg", "&#46;gif", "&#46;png", etc&#46;).
160     *
161     * @param filename  A valid string representing name of file
162     * which may contain an image.
163     * @return true if the filename has an image format file extension.
164     */
165    public static boolean hasImageFileExtension(final String filename) {
166        if (filename == null) {
167            return false;
168        }
169
170        final String normalizedFilename = filename.toLowerCase(Locale.ENGLISH);
171
172        for (final ImageParser imageParser : ImageParser.getAllImageParsers()) {
173            for (final String extension : imageParser.getAcceptedExtensions()) {
174                if (normalizedFilename.endsWith(extension.toLowerCase(Locale.ENGLISH))) {
175                    return true;
176                }
177            }
178        }
179
180        return false;
181    }
182
183    /**
184     * Attempts to determine the image format of a file based on its
185     * "magic numbers," the first bytes of the data.
186     * <p>Many graphics format specify identifying byte
187     * values that appear at the beginning of the data file.  This method
188     * checks for such identifying elements and returns a ImageFormat
189     * enumeration indicating what it detects. Note that this
190     * method can return "false positives" in cases where non-image files
191     * begin with the specified byte values.
192     *
193     * @param bytes  Byte array containing an image file.
194     * @return An ImageFormat, such as ImageFormat.IMAGE_FORMAT_JPEG. Returns
195     *         ImageFormat.IMAGE_FORMAT_UNKNOWN if the image type cannot be
196     *         determined.
197     */
198    public static ImageFormat guessFormat(final byte[] bytes)
199            throws ImageReadException, IOException {
200        return guessFormat(new ByteSourceArray(bytes));
201    }
202
203    /**
204     * Attempts to determine the image format of a file based on its
205     * "magic numbers," the first bytes of the data.
206     * <p>Many graphics formats specify identifying byte
207     * values that appear at the beginning of the data file.  This method
208     * checks for such identifying elements and returns a ImageFormat
209     * enumeration indicating what it detects. Note that this
210     * method can return "false positives" in cases where non-image files
211     * begin with the specified byte values.
212     *
213     * @param file  File containing image data.
214     * @return An ImageFormat, such as ImageFormat.IMAGE_FORMAT_JPEG. Returns
215     *         ImageFormat.IMAGE_FORMAT_UNKNOWN if the image type cannot be
216     *         determined.
217     */
218    public static ImageFormat guessFormat(final File file) throws ImageReadException,
219            IOException {
220        return guessFormat(new ByteSourceFile(file));
221    }
222
223    private static boolean compareBytePair(final int[] a, final int[] b) {
224        if (a.length != 2 && b.length != 2) {
225            throw new RuntimeException("Invalid Byte Pair.");
226        }
227        return (a[0] == b[0]) && (a[1] == b[1]);
228    }
229
230
231    /**
232     * Attempts to determine the image format of a file based on its
233     * "magic numbers," the first bytes of the data.
234     * <p>Many graphics formats specify identifying byte
235     * values that appear at the beginning of the data file.  This method
236     * checks for such identifying elements and returns a ImageFormat
237     * enumeration indicating what it detects. Note that this
238     * method can return "false positives" in cases where non-image files
239     * begin with the specified byte values.
240     *
241     * @param byteSource a valid ByteSource object potentially supplying
242     * data for an image.
243     * @return An ImageFormat, such as ImageFormat.IMAGE_FORMAT_JPEG. Returns
244     *         ImageFormat.IMAGE_FORMAT_UNKNOWN if the image type cannot be
245     *         determined.
246     * @throws ImageReadException in the event of an unsuccessful
247     * attempt to read the image data
248     * @throws IOException in the event of an unrecoverable I/O condition.
249     */
250    public static ImageFormat guessFormat(final ByteSource byteSource)
251            throws ImageReadException, IOException {
252
253        if (byteSource == null) {
254            return ImageFormats.UNKNOWN;
255        }
256
257        try (InputStream is = byteSource.getInputStream()) {
258            final int i1 = is.read();
259            final int i2 = is.read();
260            if ((i1 < 0) || (i2 < 0)) {
261                throw new ImageReadException(
262                        "Couldn't read magic numbers to guess format.");
263            }
264
265            final int b1 = i1 & 0xff;
266            final int b2 = i2 & 0xff;
267            final int[] bytePair = { b1, b2, };
268
269            if (compareBytePair(MAGIC_NUMBERS_GIF, bytePair)) {
270                return ImageFormats.GIF;
271            // } else if (b1 == 0x00 && b2 == 0x00) // too similar to TGA
272            // {
273            // return ImageFormat.IMAGE_FORMAT_ICO;
274            } else if (compareBytePair(MAGIC_NUMBERS_PNG, bytePair)) {
275                return ImageFormats.PNG;
276            } else if (compareBytePair(MAGIC_NUMBERS_JPEG, bytePair)) {
277                return ImageFormats.JPEG;
278            } else if (compareBytePair(MAGIC_NUMBERS_BMP, bytePair)) {
279                return ImageFormats.BMP;
280            } else if (compareBytePair(MAGIC_NUMBERS_TIFF_MOTOROLA, bytePair)) {
281                return ImageFormats.TIFF;
282            } else if (compareBytePair(MAGIC_NUMBERS_TIFF_INTEL, bytePair)) {
283                return ImageFormats.TIFF;
284            } else if (compareBytePair(MAGIC_NUMBERS_PSD, bytePair)) {
285                return ImageFormats.PSD;
286            } else if (compareBytePair(MAGIC_NUMBERS_PAM, bytePair)) {
287                return ImageFormats.PAM;
288            } else if (compareBytePair(MAGIC_NUMBERS_PBM_A, bytePair)) {
289                return ImageFormats.PBM;
290            } else if (compareBytePair(MAGIC_NUMBERS_PBM_B, bytePair)) {
291                return ImageFormats.PBM;
292            } else if (compareBytePair(MAGIC_NUMBERS_PGM_A, bytePair)) {
293                return ImageFormats.PGM;
294            } else if (compareBytePair(MAGIC_NUMBERS_PGM_B, bytePair)) {
295                return ImageFormats.PGM;
296            } else if (compareBytePair(MAGIC_NUMBERS_PPM_A, bytePair)) {
297                return ImageFormats.PPM;
298            } else if (compareBytePair(MAGIC_NUMBERS_PPM_B, bytePair)) {
299                return ImageFormats.PPM;
300            } else if (compareBytePair(MAGIC_NUMBERS_JBIG2_1, bytePair)) {
301                final int i3 = is.read();
302                final int i4 = is.read();
303                if ((i3 < 0) || (i4 < 0)) {
304                    throw new ImageReadException(
305                            "Couldn't read magic numbers to guess format.");
306                }
307
308                final int b3 = i3 & 0xff;
309                final int b4 = i4 & 0xff;
310                final int[] bytePair2 = { b3, b4, };
311                if (compareBytePair(MAGIC_NUMBERS_JBIG2_2, bytePair2)) {
312                    return ImageFormats.JBIG2;
313                }
314            } else if (compareBytePair(MAGIC_NUMBERS_ICNS, bytePair)) {
315                return ImageFormats.ICNS;
316            } else if (compareBytePair(MAGIC_NUMBERS_DCX, bytePair)) {
317                return ImageFormats.DCX;
318            } else if (compareBytePair(MAGIC_NUMBERS_RGBE, bytePair)) {
319                return ImageFormats.RGBE;
320            }
321            return ImageFormats.UNKNOWN;
322        }
323    }
324
325    /**
326     * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and
327     * TIFF images.
328     * <p>
329     *
330     * @param bytes
331     *            Byte array containing an image file.
332     * @return An instance of ICC_Profile or null if the image contains no ICC
333     *         profile.
334     */
335    public static ICC_Profile getICCProfile(final byte[] bytes)
336            throws ImageReadException, IOException {
337        return getICCProfile(bytes, null);
338    }
339
340    /**
341     * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and
342     * TIFF images.
343     * <p>
344     *
345     * @param bytes
346     *            Byte array containing an image file.
347     * @param params
348     *            Map of optional parameters, defined in ImagingConstants.
349     * @return An instance of ICC_Profile or null if the image contains no ICC
350     *         profile..
351     */
352    public static ICC_Profile getICCProfile(final byte[] bytes, final Map<String, Object> params)
353            throws ImageReadException, IOException {
354        return getICCProfile(new ByteSourceArray(bytes), params);
355    }
356
357    /**
358     * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and
359     * TIFF images.
360     * <p>
361     *
362     * @param is
363     *            InputStream from which to read image data.
364     * @param filename
365     *            Filename associated with image data (optional).
366     * @return An instance of ICC_Profile or null if the image contains no ICC
367     *         profile..
368     */
369    public static ICC_Profile getICCProfile(final InputStream is, final String filename)
370            throws ImageReadException, IOException {
371        return getICCProfile(is, filename, null);
372    }
373
374    /**
375     * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and
376     * TIFF images.
377     * <p>
378     *
379     * @param is
380     *            InputStream from which to read image data.
381     * @param filename
382     *            Filename associated with image data (optional).
383     * @param params
384     *            Map of optional parameters, defined in ImagingConstants.
385     * @return An instance of ICC_Profile or null if the image contains no ICC
386     *         profile..
387     */
388    public static ICC_Profile getICCProfile(final InputStream is, final String filename,
389            final Map<String, Object> params) throws ImageReadException, IOException {
390        return getICCProfile(new ByteSourceInputStream(is, filename), params);
391    }
392
393    /**
394     * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and
395     * TIFF images.
396     * <p>
397     *
398     * @param file
399     *            File containing image data.
400     * @return An instance of ICC_Profile or null if the image contains no ICC
401     *         profile..
402     */
403    public static ICC_Profile getICCProfile(final File file)
404            throws ImageReadException, IOException {
405        return getICCProfile(file, null);
406    }
407
408    /**
409     * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and
410     * TIFF images.
411     * <p>
412     *
413     * @param file
414     *            File containing image data.
415     * @param params
416     *            Map of optional parameters, defined in ImagingConstants.
417     * @return An instance of ICC_Profile or null if the image contains no ICC
418     *         profile..
419     */
420    public static ICC_Profile getICCProfile(final File file, final Map<String, Object> params)
421            throws ImageReadException, IOException {
422        return getICCProfile(new ByteSourceFile(file), params);
423    }
424
425    protected static ICC_Profile getICCProfile(final ByteSource byteSource, final Map<String, Object> params)
426            throws ImageReadException, IOException {
427        final byte[] bytes = getICCProfileBytes(byteSource, params);
428        if (bytes == null) {
429            return null;
430        }
431
432        final IccProfileParser parser = new IccProfileParser();
433        final IccProfileInfo info = parser.getICCProfileInfo(bytes);
434        if (info == null) {
435            return null;
436        }
437        if (info.issRGB()) {
438            return null;
439        }
440
441        return ICC_Profile.getInstance(bytes);
442    }
443
444    /**
445     * Extracts the raw bytes of an ICC Profile (if present) from JPEG, PNG, PSD
446     * (Photoshop) and TIFF images.
447     * <p>
448     * To parse the result use IccProfileParser or
449     * ICC_Profile.getInstance(bytes).
450     * <p>
451     *
452     * @param bytes
453     *            Byte array containing an image file.
454     * @return A byte array.
455     * @see IccProfileParser
456     * @see ICC_Profile
457     */
458    public static byte[] getICCProfileBytes(final byte[] bytes)
459            throws ImageReadException, IOException {
460        return getICCProfileBytes(bytes, null);
461    }
462
463    /**
464     * Extracts the raw bytes of an ICC Profile (if present) from JPEG, PNG, PSD
465     * (Photoshop) and TIFF images.
466     * <p>
467     * To parse the result use IccProfileParser or
468     * ICC_Profile.getInstance(bytes).
469     * <p>
470     *
471     * @param bytes
472     *            Byte array containing an image file.
473     * @param params
474     *            Map of optional parameters, defined in ImagingConstants.
475     * @return A byte array.
476     * @see IccProfileParser
477     * @see ICC_Profile
478     */
479    public static byte[] getICCProfileBytes(final byte[] bytes, final Map<String, Object> params)
480            throws ImageReadException, IOException {
481        return getICCProfileBytes(new ByteSourceArray(bytes), params);
482    }
483
484    /**
485     * Extracts the raw bytes of an ICC Profile (if present) from JPEG, PNG, PSD
486     * (Photoshop) and TIFF images.
487     * <p>
488     * To parse the result use IccProfileParser or
489     * ICC_Profile.getInstance(bytes).
490     * <p>
491     *
492     * @param file
493     *            File containing image data.
494     * @return A byte array.
495     * @see IccProfileParser
496     * @see ICC_Profile
497     */
498    public static byte[] getICCProfileBytes(final File file)
499            throws ImageReadException, IOException {
500        return getICCProfileBytes(file, null);
501    }
502
503    /**
504     * Extracts the raw bytes of an ICC Profile (if present) from JPEG, PNG, PSD
505     * (Photoshop) and TIFF images.
506     * <p>
507     * To parse the result use IccProfileParser or
508     * ICC_Profile.getInstance(bytes).
509     * <p>
510     *
511     * @param file
512     *            File containing image data.
513     * @param params
514     *            Map of optional parameters, defined in ImagingConstants.
515     * @return A byte array.
516     * @see IccProfileParser
517     * @see ICC_Profile
518     */
519    public static byte[] getICCProfileBytes(final File file, final Map<String, Object> params)
520            throws ImageReadException, IOException {
521        return getICCProfileBytes(new ByteSourceFile(file), params);
522    }
523
524    private static byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
525            throws ImageReadException, IOException {
526        final ImageParser imageParser = getImageParser(byteSource);
527
528        return imageParser.getICCProfileBytes(byteSource, params);
529    }
530
531    /**
532     * Parses the "image info" of an image.
533     * <p>
534     * "Image info" is a summary of basic information about the image such as:
535     * width, height, file format, bit depth, color type, etc.
536     * <p>
537     * Not to be confused with "image metadata."
538     * <p>
539     *
540     * @param filename
541     *            String.
542     * @param bytes
543     *            Byte array containing an image file.
544     * @param params
545     *            Map of optional parameters, defined in ImagingConstants.
546     * @return An instance of ImageInfo.
547     * @see ImageInfo
548     */
549    public static ImageInfo getImageInfo(final String filename, final byte[] bytes,
550            final Map<String, Object> params) throws ImageReadException, IOException {
551        return getImageInfo(new ByteSourceArray(filename, bytes), params);
552    }
553
554    /**
555     * Parses the "image info" of an image.
556     * <p>
557     * "Image info" is a summary of basic information about the image such as:
558     * width, height, file format, bit depth, color type, etc.
559     * <p>
560     * Not to be confused with "image metadata."
561     * <p>
562     *
563     * @param filename
564     *            String.
565     * @param bytes
566     *            Byte array containing an image file.
567     * @return An instance of ImageInfo.
568     * @see ImageInfo
569     */
570    public static ImageInfo getImageInfo(final String filename, final byte[] bytes)
571            throws ImageReadException, IOException {
572        return getImageInfo(new ByteSourceArray(filename, bytes), null);
573    }
574
575    /**
576     * Parses the "image info" of an image.
577     * <p>
578     * "Image info" is a summary of basic information about the image such as:
579     * width, height, file format, bit depth, color type, etc.
580     * <p>
581     * Not to be confused with "image metadata."
582     * <p>
583     *
584     * @param is
585     *            InputStream from which to read image data.
586     * @param filename
587     *            Filename associated with image data (optional).
588     * @return An instance of ImageInfo.
589     * @see ImageInfo
590     */
591    public static ImageInfo getImageInfo(final InputStream is, final String filename)
592            throws ImageReadException, IOException {
593        return getImageInfo(new ByteSourceInputStream(is, filename), null);
594    }
595
596    /**
597     * Parses the "image info" of an image.
598     * <p>
599     * "Image info" is a summary of basic information about the image such as:
600     * width, height, file format, bit depth, color type, etc.
601     * <p>
602     * Not to be confused with "image metadata."
603     * <p>
604     *
605     * @param is
606     *            InputStream from which to read image data.
607     * @param filename
608     *            Filename associated with image data (optional).
609     * @param params
610     *            Map of optional parameters, defined in ImagingConstants.
611     * @return An instance of ImageInfo.
612     * @see ImageInfo
613     */
614    public static ImageInfo getImageInfo(final InputStream is, final String filename,
615            final Map<String, Object> params) throws ImageReadException, IOException {
616        return getImageInfo(new ByteSourceInputStream(is, filename), params);
617    }
618
619    /**
620     * Parses the "image info" of an image.
621     * <p>
622     * "Image info" is a summary of basic information about the image such as:
623     * width, height, file format, bit depth, color type, etc.
624     * <p>
625     * Not to be confused with "image metadata."
626     * <p>
627     *
628     * @param bytes
629     *            Byte array containing an image file.
630     * @return An instance of ImageInfo.
631     * @see ImageInfo
632     */
633    public static ImageInfo getImageInfo(final byte[] bytes)
634            throws ImageReadException, IOException {
635        return getImageInfo(new ByteSourceArray(bytes), null);
636    }
637
638    /**
639     * Parses the "image info" of an image.
640     * <p>
641     * "Image info" is a summary of basic information about the image such as:
642     * width, height, file format, bit depth, color type, etc.
643     * <p>
644     * Not to be confused with "image metadata."
645     * <p>
646     *
647     * @param bytes
648     *            Byte array containing an image file.
649     * @param params
650     *            Map of optional parameters, defined in ImagingConstants.
651     * @return An instance of ImageInfo.
652     * @see ImageInfo
653     */
654    public static ImageInfo getImageInfo(final byte[] bytes, final Map<String, Object> params)
655            throws ImageReadException, IOException {
656        return getImageInfo(new ByteSourceArray(bytes), params);
657    }
658
659    /**
660     * Parses the "image info" of an image file.
661     * <p>
662     * "Image info" is a summary of basic information about the image such as:
663     * width, height, file format, bit depth, color type, etc.
664     * <p>
665     * Not to be confused with "image metadata."
666     * <p>
667     *
668     * @param file
669     *            File containing image data.
670     * @param params
671     *            Map of optional parameters, defined in ImagingConstants.
672     * @return An instance of ImageInfo.
673     * @see ImageInfo
674     */
675    public static ImageInfo getImageInfo(final File file, final Map<String, Object> params)
676            throws ImageReadException, IOException {
677        return getImageInfo(new ByteSourceFile(file), params);
678    }
679
680    /**
681     * Parses the "image info" of an image file.
682     * <p>
683     * "Image info" is a summary of basic information about the image such as:
684     * width, height, file format, bit depth, color type, etc.
685     * <p>
686     * Not to be confused with "image metadata."
687     * <p>
688     *
689     * @param file
690     *            File containing image data.
691     * @return An instance of ImageInfo.
692     * @see ImageInfo
693     */
694    public static ImageInfo getImageInfo(final File file) throws ImageReadException,
695            IOException {
696        return getImageInfo(file, null);
697    }
698
699    private static ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
700            throws ImageReadException, IOException {
701        return getImageParser(byteSource).getImageInfo(byteSource, params);
702    }
703
704    private static ImageParser getImageParser(final ByteSource byteSource)
705            throws ImageReadException, IOException {
706        final ImageFormat format = guessFormat(byteSource);
707        if (!format.equals(ImageFormats.UNKNOWN)) {
708
709            final ImageParser[] imageParsers = ImageParser.getAllImageParsers();
710
711            for (final ImageParser imageParser : imageParsers) {
712                if (imageParser.canAcceptType(format)) {
713                    return imageParser;
714                }
715            }
716        }
717
718        final String filename = byteSource.getFilename();
719        if (filename != null) {
720            final ImageParser[] imageParsers = ImageParser.getAllImageParsers();
721
722            for (final ImageParser imageParser : imageParsers) {
723                if (imageParser.canAcceptExtension(filename)) {
724                    return imageParser;
725                }
726            }
727        }
728
729        throw new ImageReadException("Can't parse this format.");
730    }
731
732    /**
733     * Determines the width and height of an image.
734     * <p>
735     *
736     * @param is
737     *            InputStream from which to read image data.
738     * @param filename
739     *            Filename associated with image data (optional).
740     * @return The width and height of the image.
741     */
742    public static Dimension getImageSize(final InputStream is, final String filename)
743            throws ImageReadException, IOException {
744        return getImageSize(is, filename, null);
745    }
746
747    /**
748     * Determines the width and height of an image.
749     * <p>
750     *
751     * @param is
752     *            InputStream from which to read image data.
753     * @param filename
754     *            Filename associated with image data (optional).
755     * @param params
756     *            Map of optional parameters, defined in ImagingConstants.
757     * @return The width and height of the image.
758     */
759    public static Dimension getImageSize(final InputStream is, final String filename,
760            final Map<String, Object> params) throws ImageReadException, IOException {
761        return getImageSize(new ByteSourceInputStream(is, filename), params);
762    }
763
764    /**
765     * Determines the width and height of an image.
766     * <p>
767     *
768     * @param bytes
769     *            Byte array containing an image file.
770     * @return The width and height of the image.
771     */
772    public static Dimension getImageSize(final byte[] bytes)
773            throws ImageReadException, IOException {
774        return getImageSize(bytes, null);
775    }
776
777    /**
778     * Determines the width and height of an image.
779     * <p>
780     *
781     * @param bytes
782     *            Byte array containing an image file.
783     * @param params
784     *            Map of optional parameters, defined in ImagingConstants.
785     * @return The width and height of the image.
786     */
787    public static Dimension getImageSize(final byte[] bytes, final Map<String, Object> params)
788            throws ImageReadException, IOException {
789        return getImageSize(new ByteSourceArray(bytes), params);
790    }
791
792    /**
793     * Determines the width and height of an image file.
794     * <p>
795     *
796     * @param file
797     *            File containing image data.
798     * @return The width and height of the image.
799     */
800    public static Dimension getImageSize(final File file) throws ImageReadException,
801            IOException {
802        return getImageSize(file, null);
803    }
804
805    /**
806     * Determines the width and height of an image file.
807     * <p>
808     *
809     * @param file
810     *            File containing image data.
811     * @param params
812     *            Map of optional parameters, defined in ImagingConstants.
813     * @return The width and height of the image.
814     */
815    public static Dimension getImageSize(final File file, final Map<String, Object> params)
816            throws ImageReadException, IOException {
817        return getImageSize(new ByteSourceFile(file), params);
818    }
819
820    public static Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
821            throws ImageReadException, IOException {
822        final ImageParser imageParser = getImageParser(byteSource);
823
824        return imageParser.getImageSize(byteSource, params);
825    }
826
827    /**
828     * Extracts the embedded XML metadata as an XML string.
829     * <p>
830     *
831     * @param is
832     *            InputStream from which to read image data.
833     * @param filename
834     *            Filename associated with image data (optional).
835     * @return Xmp Xml as String, if present. Otherwise, returns null.
836     */
837    public static String getXmpXml(final InputStream is, final String filename)
838            throws ImageReadException, IOException {
839        return getXmpXml(is, filename, null);
840    }
841
842    /**
843     * Extracts the embedded XML metadata as an XML string.
844     * <p>
845     *
846     * @param is
847     *            InputStream from which to read image data.
848     * @param filename
849     *            Filename associated with image data (optional).
850     * @param params
851     *            Map of optional parameters, defined in ImagingConstants.
852     * @return Xmp Xml as String, if present. Otherwise, returns null.
853     */
854    public static String getXmpXml(final InputStream is, final String filename, final Map<String, Object> params)
855            throws ImageReadException, IOException {
856        return getXmpXml(new ByteSourceInputStream(is, filename), params);
857    }
858
859    /**
860     * Extracts the embedded XML metadata as an XML string.
861     * <p>
862     *
863     * @param bytes
864     *            Byte array containing an image file.
865     * @return Xmp Xml as String, if present. Otherwise, returns null.
866     */
867    public static String getXmpXml(final byte[] bytes) throws ImageReadException,
868            IOException {
869        return getXmpXml(bytes, null);
870    }
871
872    /**
873     * Extracts the embedded XML metadata as an XML string.
874     * <p>
875     *
876     * @param bytes
877     *            Byte array containing an image file.
878     * @param params
879     *            Map of optional parameters, defined in ImagingConstants.
880     * @return Xmp Xml as String, if present. Otherwise, returns null.
881     */
882    public static String getXmpXml(final byte[] bytes, final Map<String, Object> params)
883            throws ImageReadException, IOException {
884        return getXmpXml(new ByteSourceArray(bytes), params);
885    }
886
887    /**
888     * Extracts the embedded XML metadata as an XML string.
889     * <p>
890     *
891     * @param file
892     *            File containing image data.
893     * @return Xmp Xml as String, if present. Otherwise, returns null.
894     */
895    public static String getXmpXml(final File file) throws ImageReadException,
896            IOException {
897        return getXmpXml(file, null);
898    }
899
900    /**
901     * Extracts the embedded XML metadata as an XML string.
902     * <p>
903     *
904     * @param file
905     *            File containing image data.
906     * @param params
907     *            Map of optional parameters, defined in ImagingConstants.
908     * @return Xmp Xml as String, if present. Otherwise, returns null.
909     */
910    public static String getXmpXml(final File file, final Map<String, Object> params)
911            throws ImageReadException, IOException {
912        return getXmpXml(new ByteSourceFile(file), params);
913    }
914
915    /**
916     * Extracts the embedded XML metadata as an XML string.
917     * <p>
918     *
919     * @param byteSource
920     *            File containing image data.
921     * @param params
922     *            Map of optional parameters, defined in ImagingConstants.
923     * @return Xmp Xml as String, if present. Otherwise, returns null.
924     */
925    public static String getXmpXml(final ByteSource byteSource, final Map<String, Object> params)
926            throws ImageReadException, IOException {
927        final ImageParser imageParser = getImageParser(byteSource);
928
929        return imageParser.getXmpXml(byteSource, params);
930    }
931
932    /**
933     * Parses the metadata of an image. This metadata depends on the format of
934     * the image.
935     * <p>
936     * JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may
937     * contain comments. TIFF files may contain metadata.
938     * <p>
939     * The instance of IImageMetadata returned by getMetadata() should be upcast
940     * (depending on image format).
941     * <p>
942     * Not to be confused with "image info."
943     * <p>
944     *
945     * @param bytes
946     *            Byte array containing an image file.
947     * @return An instance of IImageMetadata.
948     * @see org.apache.commons.imaging.common.ImageMetadata
949     */
950    public static ImageMetadata getMetadata(final byte[] bytes)
951            throws ImageReadException, IOException {
952        return getMetadata(bytes, null);
953    }
954
955    /**
956     * Parses the metadata of an image. This metadata depends on the format of
957     * the image.
958     * <p>
959     * JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may
960     * contain comments. TIFF files may contain metadata.
961     * <p>
962     * The instance of IImageMetadata returned by getMetadata() should be upcast
963     * (depending on image format).
964     * <p>
965     * Not to be confused with "image info."
966     * <p>
967     *
968     * @param bytes
969     *            Byte array containing an image file.
970     * @param params
971     *            Map of optional parameters, defined in ImagingConstants.
972     * @return An instance of IImageMetadata.
973     * @see org.apache.commons.imaging.common.ImageMetadata
974     */
975    public static ImageMetadata getMetadata(final byte[] bytes, final Map<String, Object> params)
976            throws ImageReadException, IOException {
977        return getMetadata(new ByteSourceArray(bytes), params);
978    }
979
980    /**
981     * Parses the metadata of an image file. This metadata depends on the format
982     * of the image.
983     * <p>
984     * JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may
985     * contain comments. TIFF files may contain metadata.
986     * <p>
987     * The instance of IImageMetadata returned by getMetadata() should be upcast
988     * (depending on image format).
989     * <p>
990     * Not to be confused with "image info."
991     * <p>
992     *
993     * @param is
994     *            InputStream from which to read image data.
995     * @param filename
996     *            Filename associated with image data (optional).
997     * @return An instance of IImageMetadata.
998     * @see org.apache.commons.imaging.common.ImageMetadata
999     */
1000    public static ImageMetadata getMetadata(final InputStream is, final String filename)
1001            throws ImageReadException, IOException {
1002        return getMetadata(is, filename, null);
1003    }
1004
1005    /**
1006     * Parses the metadata of an image file. This metadata depends on the format
1007     * of the image.
1008     * <p>
1009     * JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may
1010     * contain comments. TIFF files may contain metadata.
1011     * <p>
1012     * The instance of IImageMetadata returned by getMetadata() should be upcast
1013     * (depending on image format).
1014     * <p>
1015     * Not to be confused with "image info."
1016     * <p>
1017     *
1018     * @param is
1019     *            InputStream from which to read image data.
1020     * @param filename
1021     *            Filename associated with image data (optional).
1022     * @param params
1023     *            Map of optional parameters, defined in ImagingConstants.
1024     * @return An instance of IImageMetadata.
1025     * @see org.apache.commons.imaging.common.ImageMetadata
1026     */
1027    public static ImageMetadata getMetadata(final InputStream is, final String filename,
1028            final Map<String, Object> params) throws ImageReadException, IOException {
1029        return getMetadata(new ByteSourceInputStream(is, filename), params);
1030    }
1031
1032    /**
1033     * Parses the metadata of an image file. This metadata depends on the format
1034     * of the image.
1035     * <p>
1036     * JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may
1037     * contain comments. TIFF files may contain metadata.
1038     * <p>
1039     * The instance of IImageMetadata returned by getMetadata() should be upcast
1040     * (depending on image format).
1041     * <p>
1042     * Not to be confused with "image info."
1043     * <p>
1044     *
1045     * @param file
1046     *            File containing image data.
1047     * @return An instance of IImageMetadata.
1048     * @see org.apache.commons.imaging.common.ImageMetadata
1049     */
1050    public static ImageMetadata getMetadata(final File file)
1051            throws ImageReadException, IOException {
1052        return getMetadata(file, null);
1053    }
1054
1055    /**
1056     * Parses the metadata of an image file. This metadata depends on the format
1057     * of the image.
1058     * <p>
1059     * JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may
1060     * contain comments. TIFF files may contain metadata.
1061     * <p>
1062     * The instance of IImageMetadata returned by getMetadata() should be upcast
1063     * (depending on image format).
1064     * <p>
1065     * Not to be confused with "image info."
1066     * <p>
1067     *
1068     * @param file
1069     *            File containing image data.
1070     * @param params
1071     *            Map of optional parameters, defined in ImagingConstants.
1072     * @return An instance of IImageMetadata.
1073     * @see org.apache.commons.imaging.common.ImageMetadata
1074     */
1075    public static ImageMetadata getMetadata(final File file, final Map<String, Object> params)
1076            throws ImageReadException, IOException {
1077        return getMetadata(new ByteSourceFile(file), params);
1078    }
1079
1080    private static ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
1081            throws ImageReadException, IOException {
1082        final ImageParser imageParser = getImageParser(byteSource);
1083
1084        return imageParser.getMetadata(byteSource, params);
1085    }
1086
1087    /**
1088     * Write the ImageInfo and format-specific information for the image
1089     * content of the specified byte array to a string.
1090     * @param bytes A valid array of bytes.
1091     * @return A valid string.
1092     * @throws ImageReadException In the event that the specified
1093     * content does not conform to the format of the specific parser
1094     * implementation.
1095     * @throws IOException In the event of unsuccessful read or
1096     * access operation.
1097     */
1098    public static String dumpImageFile(final byte[] bytes) throws ImageReadException,
1099            IOException {
1100        return dumpImageFile(new ByteSourceArray(bytes));
1101    }
1102
1103    /**
1104     * Write the ImageInfo and format-specific information for the image
1105     * content of the specified file to a string.
1106     * @param file A valid file reference.
1107     * @return A valid string.
1108     * @throws ImageReadException In the event that the specified
1109     * content does not conform to the format of the specific parser
1110     * implementation.
1111     * @throws IOException In the event of unsuccessful read or
1112     * access operation.
1113     */
1114    public static String dumpImageFile(final File file) throws ImageReadException,
1115            IOException {
1116        return dumpImageFile(new ByteSourceFile(file));
1117    }
1118
1119    private static String dumpImageFile(final ByteSource byteSource)
1120            throws ImageReadException, IOException {
1121        final ImageParser imageParser = getImageParser(byteSource);
1122
1123        return imageParser.dumpImageFile(byteSource);
1124    }
1125
1126    /**
1127     * Attempts to determine the image format of the specified data and
1128     * evaluates its format compliance.   This method
1129     * returns a FormatCompliance object which includes information
1130     * about the data's compliance to a specific format.
1131     * @param bytes a valid array of bytes containing image data.
1132     * @return if successful, a valid FormatCompliance object.
1133     * @throws ImageReadException in the event of unreadable data.
1134     * @throws IOException in the event of an unrecoverable I/O condition.
1135     */
1136    public static FormatCompliance getFormatCompliance(final byte[] bytes)
1137            throws ImageReadException, IOException {
1138        return getFormatCompliance(new ByteSourceArray(bytes));
1139    }
1140
1141    /**
1142     * Attempts to determine the image format of the specified data and
1143     * evaluates its format compliance.   This method
1144     * returns a FormatCompliance object which includes information
1145     * about the data's compliance to a specific format.
1146     * @param file valid file containing image data
1147     * @return if successful, a valid FormatCompliance object.
1148     * @throws ImageReadException in the event of unreadable data.
1149     * @throws IOException in the event of an unrecoverable I/O condition.
1150     */
1151    public static FormatCompliance getFormatCompliance(final File file)
1152            throws ImageReadException, IOException {
1153        return getFormatCompliance(new ByteSourceFile(file));
1154    }
1155
1156    private static FormatCompliance getFormatCompliance(final ByteSource byteSource)
1157            throws ImageReadException, IOException {
1158        final ImageParser imageParser = getImageParser(byteSource);
1159
1160        return imageParser.getFormatCompliance(byteSource);
1161    }
1162
1163    /**
1164     * Gets all images specified by the InputStream  (some
1165     * formats may include multiple images within a single data source).
1166     * @param is A valid InputStream
1167     * @return A valid (potentially empty) list of BufferedImage objects.
1168     * @throws ImageReadException In the event that the specified
1169     * content does not conform to the format of the specific parser
1170     * implementation.
1171     * @throws IOException In the event of unsuccessful read or
1172     * access operation.
1173     */
1174    public static List<BufferedImage> getAllBufferedImages(final InputStream is,
1175            final String filename) throws ImageReadException, IOException {
1176        return getAllBufferedImages(new ByteSourceInputStream(is, filename));
1177    }
1178
1179    /**
1180     * Gets all images specified by the byte array (some
1181     * formats may include multiple images within a single data source).
1182     * @param bytes a valid array of bytes
1183     * @return A valid (potentially empty) list of BufferedImage objects.
1184     * @throws ImageReadException In the event that the specified
1185     * content does not conform to the format of the specific parser
1186     * implementation.
1187     * @throws IOException In the event of unsuccessful read or
1188     * access operation.
1189     */
1190    public static List<BufferedImage> getAllBufferedImages(final byte[] bytes)
1191            throws ImageReadException, IOException {
1192        return getAllBufferedImages(new ByteSourceArray(bytes));
1193    }
1194
1195   /**
1196     * Gets all images specified by the file (some
1197     * formats may include multiple images within a single data source).
1198     * @param file A reference to a valid data file.
1199     * @return A valid (potentially empty) list of BufferedImage objects.
1200     * @throws ImageReadException In the event that the specified
1201     * content does not conform to the format of the specific parser
1202     * implementation.
1203     * @throws IOException In the event of unsuccessful read or
1204     * access operation.
1205     */
1206    public static List<BufferedImage> getAllBufferedImages(final File file)
1207            throws ImageReadException, IOException {
1208        return getAllBufferedImages(new ByteSourceFile(file));
1209    }
1210
1211
1212    private static List<BufferedImage> getAllBufferedImages(
1213            final ByteSource byteSource) throws ImageReadException, IOException {
1214        final ImageParser imageParser = getImageParser(byteSource);
1215
1216        return imageParser.getAllBufferedImages(byteSource);
1217    }
1218
1219
1220    /**
1221     * Reads the first image from an InputStream.
1222     * <p>
1223     * For the most recent information on support for specific formats, refer to
1224     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1225     * at the main project development web site.   While the Apache Commons
1226     * Imaging package does not fully support all formats, it  can read
1227     * image info, metadata and ICC profiles from all image formats that
1228     * provide this data.
1229     * @param is a valid ImageStream from which to read data.
1230     * @return if successful, a valid buffered image
1231     * @throws ImageReadException in the event of a processing error
1232     * while reading an image (i.e. a format violation, etc.).
1233     * @throws IOException  in the event of an unrecoverable I/O exception.
1234     */
1235
1236    public static BufferedImage getBufferedImage(final InputStream is)
1237            throws ImageReadException, IOException {
1238        return getBufferedImage(is, null);
1239    }
1240
1241
1242
1243    /**
1244     * Reads the first image from an InputStream
1245     * using data-processing options specified through a parameters
1246     * map.  Options may be configured using the ImagingContants
1247     * interface or the various format-specific implementations provided
1248     * by this package.
1249     * <p>
1250     * For the most recent information on support for specific formats, refer to
1251     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1252     * at the main project development web site.   While the Apache Commons
1253     * Imaging package does not fully support all formats, it  can read
1254     * image info, metadata and ICC profiles from all image formats that
1255     * provide this data.
1256     * @param is a valid ImageStream from which to read data.
1257     * @param params an optional parameters map specifying options
1258     * @return if successful, a valid buffered image
1259     * @throws ImageReadException in the event of a processing error
1260     * while reading an image (i.e. a format violation, etc.).
1261     * @throws IOException  in the event of an unrecoverable I/O exception.
1262     */
1263    public static BufferedImage getBufferedImage(final InputStream is, final Map<String, Object> params)
1264            throws ImageReadException, IOException {
1265        String filename = null;
1266        if (params != null && params.containsKey(PARAM_KEY_FILENAME)) {
1267            filename = (String) params.get(PARAM_KEY_FILENAME);
1268        }
1269        return getBufferedImage(new ByteSourceInputStream(is, filename), params);
1270    }
1271
1272    /**
1273     * Reads the first image from a byte array.
1274     * <p>
1275     * For the most recent information on support for specific formats, refer to
1276     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1277     * at the main project development web site.   While the Apache Commons
1278     * Imaging package does not fully support all formats, it  can read
1279     * image info, metadata and ICC profiles from all image formats that
1280     * provide this data.
1281     * @param bytes a valid array of bytes from which to read data.
1282     * @return if successful, a valid buffered image
1283     * @throws ImageReadException in the event of a processing error
1284     * while reading an image (i.e. a format violation, etc.).
1285     * @throws IOException  in the event of an unrecoverable I/O exception.
1286     */
1287    public static BufferedImage getBufferedImage(final byte[] bytes)
1288            throws ImageReadException, IOException {
1289        return getBufferedImage(new ByteSourceArray(bytes), null);
1290    }
1291
1292
1293    /**
1294     * Reads the first image from a byte array
1295     * using data-processing options specified through a parameters
1296     * map.  Options may be configured using the ImagingContants
1297     * interface or the various format-specific implementations provided
1298     * by this package.
1299     * <p>
1300     * For the most recent information on support for specific formats, refer to
1301     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1302     * at the main project development web site.   While the Apache Commons
1303     * Imaging package does not fully support all formats, it  can read
1304     * image info, metadata and ICC profiles from all image formats that
1305     * provide this data.
1306     * @param bytes a valid array of bytes from which to read data.
1307     * @param params an optional parameters map specifying options.
1308     * @return if successful, a valid buffered image
1309     * @throws ImageReadException in the event of a processing error
1310     * while reading an image (i.e. a format violation, etc.).
1311     * @throws IOException  in the event of an unrecoverable I/O exception.
1312     */
1313    public static BufferedImage getBufferedImage(final byte[] bytes, final Map<String, Object> params)
1314            throws ImageReadException, IOException {
1315        return getBufferedImage(new ByteSourceArray(bytes), params);
1316    }
1317
1318
1319
1320
1321    /**
1322     * Reads the first image from a file.
1323     * <p>
1324     * For the most recent information on support for specific formats, refer to
1325     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1326     * at the main project development web site.   While the Apache Commons
1327     * Imaging package does not fully support all formats, it  can read
1328     * image info, metadata and ICC profiles from all image formats that
1329     * provide this data.
1330     * @param file a valid reference to a file containing image data.
1331     * @return if successful, a valid buffered image
1332     * @throws ImageReadException in the event of a processing error
1333     * while reading an image (i.e. a format violation, etc.).
1334     * @throws IOException  in the event of an unrecoverable I/O exception.
1335     */
1336    public static BufferedImage getBufferedImage(final File file)
1337            throws ImageReadException, IOException {
1338        return getBufferedImage(new ByteSourceFile(file), null);
1339    }
1340
1341
1342    /**
1343     * Reads the first image from a file
1344     * using data-processing options specified through a parameters
1345     * map.  Options may be configured using the ImagingContants
1346     * interface or the various format-specific implementations provided
1347     * by this package.
1348     * <p>
1349     * For the most recent information on support for specific formats, refer to
1350     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1351     * at the main project development web site.   While the Apache Commons
1352     * Imaging package does not fully support all formats, it  can read
1353     * image info, metadata and ICC profiles from all image formats that
1354     * provide this data.
1355     * @param file a valid reference to a file containing image data.
1356     * @return if successful, a valid buffered image
1357     * @throws ImageReadException in the event of a processing error
1358     * while reading an image (i.e. a format violation, etc.).
1359     * @throws IOException  in the event of an unrecoverable I/O exception.
1360     */
1361    public static BufferedImage getBufferedImage(final File file, final Map<String, Object> params)
1362            throws ImageReadException, IOException {
1363        return getBufferedImage(new ByteSourceFile(file), params);
1364    }
1365
1366
1367
1368    private static BufferedImage getBufferedImage(final ByteSource byteSource,
1369            Map<String, Object> params) throws ImageReadException, IOException {
1370        final ImageParser imageParser = getImageParser(byteSource);
1371        if (null == params) {
1372            params = new HashMap<>();
1373        }
1374
1375        return imageParser.getBufferedImage(byteSource, params);
1376    }
1377
1378     /**
1379     * Writes the content of a BufferedImage to a file using the specified
1380     * image format.  Specifications for storing the file (such as data compression,
1381     * color models, metadata tags, etc.) may be specified using an optional
1382     * parameters map. These specifications are defined in the ImagingConstants
1383     * interface or in various format-specific implementations.
1384     * <p>
1385     * Image writing is not supported for all graphics formats.
1386     * For the most recent information on support for specific formats, refer to
1387     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1388     * at the main project development web site.   While the Apache Commons
1389     * Imaging package does not fully support all formats, it  can read
1390     * image info, metadata and ICC profiles from all image formats that
1391     * provide this data.
1392     * @param src a valid BufferedImage object
1393     * @param file the file to which the output image is to be written
1394     * @param format the format in which the output image is to be written
1395     * @param params an optional parameters map (nulls permitted)
1396     * @throws ImageWriteException in the event of a format violation,
1397     * unsupported image format, etc.
1398     * @throws IOException in the event of an unrecoverable I/O exception.
1399     * @see ImagingConstants
1400     */
1401    public static void writeImage(final BufferedImage src, final File file,
1402            final ImageFormat format, final Map<String, Object> params) throws ImageWriteException,
1403            IOException {
1404        try (FileOutputStream fos = new FileOutputStream(file);
1405                BufferedOutputStream os = new BufferedOutputStream(fos)) {
1406            writeImage(src, os, format, params);
1407        }
1408    }
1409
1410
1411    /**
1412     * Writes the content of a BufferedImage to a byte array using the specified
1413     * image format.  Specifications for storing the file (such as data compression,
1414     * color models, metadata tags, etc.) may be specified using an optional
1415     * parameters map. These specifications are defined in the ImagingConstants
1416     * interface or in various format-specific implementations.
1417     * <p>
1418     * Image writing is not supported for all graphics formats.
1419     * For the most recent information on support for specific formats, refer to
1420     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1421     * at the main project development web site.   While the Apache Commons
1422     * Imaging package does not fully support all formats, it  can read
1423     * image info, metadata and ICC profiles from all image formats that
1424     * provide this data.
1425     * @param src a valid BufferedImage object
1426     * @param format the format in which the output image is to be written
1427     * @param params an optional parameters map (nulls permitted)
1428     * @return if successful, a valid array of bytes.
1429     * @throws ImageWriteException in the event of a format violation,
1430     * unsupported image format, etc.
1431     * @throws IOException in the event of an unrecoverable I/O exception.
1432     * @see ImagingConstants
1433     */
1434    public static byte[] writeImageToBytes(final BufferedImage src,
1435            final ImageFormat format, final Map<String, Object> params) throws ImageWriteException,
1436            IOException {
1437        final ByteArrayOutputStream os = new ByteArrayOutputStream();
1438
1439        writeImage(src, os, format, params);
1440
1441        return os.toByteArray();
1442    }
1443
1444
1445     /**
1446     * Writes the content of a BufferedImage to an OutputStream using the specified
1447     * image format.  Specifications for storing the file (such as data compression,
1448     * color models, metadata tags, etc.) may be specified using an optional
1449     * parameters map. These specifications are defined in the ImagingConstants
1450     * interface or in various format-specific implementations.
1451     * <p>
1452     * Image writing is not supported for all graphics formats.
1453     * For the most recent information on support for specific formats, refer to
1454     * <a href="http://commons.apache.org/imaging/formatsupport.html">Format Support</a>
1455     * at the main project development web site.   While the Apache Commons
1456     * Imaging package does not fully support all formats, it  can read
1457     * image info, metadata and ICC profiles from all image formats that
1458     * provide this data.
1459     * @param src a valid BufferedImage object
1460     * @param os the OutputStream to which the output image is to be written
1461     * @param format the format in which the output image is to be written
1462     * @param params an optional parameters map (nulls permitted)
1463     * @throws ImageWriteException in the event of a format violation,
1464     * unsupported image format, etc.
1465     * @throws IOException in the event of an unrecoverable I/O exception.
1466     * @see ImagingConstants
1467     */
1468    public static void writeImage(final BufferedImage src, final OutputStream os,
1469            final ImageFormat format, Map<String, Object> params) throws ImageWriteException,
1470            IOException {
1471        final ImageParser[] imageParsers = ImageParser.getAllImageParsers();
1472
1473        // make sure params are non-null
1474        if (params == null) {
1475            params = new HashMap<>();
1476        }
1477
1478        params.put(PARAM_KEY_FORMAT, format);
1479
1480        ImageParser imageParser = null;
1481        for (final ImageParser imageParser2 : imageParsers) {
1482            if (imageParser2.canAcceptType(format)) {
1483                imageParser = imageParser2;
1484                break;
1485            }
1486        }
1487        if (imageParser != null) {
1488            imageParser.writeImage(src, os, params);
1489        } else {
1490            throw new ImageWriteException("Unknown Format: " + format);
1491        }
1492    }
1493
1494}