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