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 org.apache.commons.imaging.common.ImageMetadata; 020import org.apache.commons.imaging.common.XmpEmbeddable; 021import org.apache.commons.imaging.common.bytesource.ByteSource; 022import org.apache.commons.imaging.common.bytesource.ByteSourceArray; 023import org.apache.commons.imaging.common.bytesource.ByteSourceFile; 024import org.apache.commons.imaging.common.bytesource.ByteSourceInputStream; 025import org.apache.commons.imaging.icc.IccProfileInfo; 026import org.apache.commons.imaging.icc.IccProfileParser; 027import org.apache.commons.imaging.internal.Util; 028 029import java.awt.Dimension; 030import java.awt.color.ICC_Profile; 031import java.awt.image.BufferedImage; 032import java.io.BufferedOutputStream; 033import java.io.ByteArrayOutputStream; 034import java.io.File; 035import java.io.FileOutputStream; 036import java.io.IOException; 037import java.io.InputStream; 038import java.io.OutputStream; 039import java.util.List; 040import java.util.Locale; 041import java.util.Objects; 042import java.util.stream.Stream; 043 044/** 045 * The primary application programming interface (API) to the Imaging library. 046 * 047 * <h2>Application Notes</h2> 048 * 049 * <h3>Using this class</h3> 050 * 051 * <p>Almost all of the Apache Commons Imaging library's core functionality can 052 * be accessed through the methods provided by this class. 053 * The use of the Imaging class is similar to the Java API's ImageIO class, 054 * though Imaging supports formats not included in the standard Java API.</p> 055 * 056 * <p>All of methods provided by the Imaging class are declared static.</p> 057 * 058 * <p>The Apache Commons Imaging package is a pure Java implementation.</p> 059 * 060 * <h3>Format support</h3> 061 * 062 * <p>While the Apache Commons Imaging package handles a number of different 063 * graphics formats, support for some formats is not yet complete. 064 * For the most recent information on support for specific formats, refer to 065 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 066 * at the main project development web site.</p> 067 * 068 * <h3>Optional parameters for image reading and writing</h3> 069 * 070 * <p>Many of the operations provided in this class as static calls can be accessed directly 071 * using format-specific {@link ImageParser} instances. These static methods are provided 072 * for convenience in simple use cases.</p> 073 * 074 * <h3>Example code</h3> 075 * 076 * <p>See the source of the SampleUsage class and other classes in the 077 * org.apache.commons.imaging.examples package for examples.</p> 078 * 079 * @see <a 080 * 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> 081 * @see <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 082 */ 083public final class Imaging { 084 085 private static final int[] MAGIC_NUMBERS_GIF = { 0x47, 0x49, }; 086 private static final int[] MAGIC_NUMBERS_PNG = { 0x89, 0x50, }; 087 private static final int[] MAGIC_NUMBERS_JPEG = { 0xff, 0xd8, }; 088 private static final int[] MAGIC_NUMBERS_BMP = { 0x42, 0x4d, }; 089 private static final int[] MAGIC_NUMBERS_TIFF_MOTOROLA = { 0x4D, 0x4D, }; 090 private static final int[] MAGIC_NUMBERS_TIFF_INTEL = { 0x49, 0x49, }; 091 private static final int[] MAGIC_NUMBERS_PAM = { 0x50, 0x37, }; 092 private static final int[] MAGIC_NUMBERS_PSD = { 0x38, 0x42, }; 093 private static final int[] MAGIC_NUMBERS_PBM_A = { 0x50, 0x31, }; 094 private static final int[] MAGIC_NUMBERS_PBM_B = { 0x50, 0x34, }; 095 private static final int[] MAGIC_NUMBERS_PGM_A = { 0x50, 0x32, }; 096 private static final int[] MAGIC_NUMBERS_PGM_B = { 0x50, 0x35, }; 097 private static final int[] MAGIC_NUMBERS_PPM_A = { 0x50, 0x33, }; 098 private static final int[] MAGIC_NUMBERS_PPM_B = { 0x50, 0x36, }; 099 private static final int[] MAGIC_NUMBERS_JBIG2_1 = { 0x97, 0x4A, }; 100 private static final int[] MAGIC_NUMBERS_JBIG2_2 = { 0x42, 0x32, }; 101 private static final int[] MAGIC_NUMBERS_ICNS = { 0x69, 0x63, }; 102 private static final int[] MAGIC_NUMBERS_DCX = { 0xB1, 0x68, }; 103 private static final int[] MAGIC_NUMBERS_RGBE = { 0x23, 0x3F, }; 104 105 private Imaging() { 106 // Instances can not be created 107 } 108 109 /** 110 * Attempts to determine if a file contains an image recorded in 111 * a supported graphics format based on its file-name extension 112 * (for example ".jpg", ".gif", ".png", etc.). 113 * 114 * @param file A valid File object providing a reference to a file that may contain an image. 115 * @return true if the file-name includes a supported image format file extension; otherwise, false. 116 */ 117 public static boolean hasImageFileExtension(final File file) { 118 if (file == null || !file.isFile()) { 119 return false; 120 } 121 return hasImageFileExtension(file.getName()); 122 } 123 124 /** 125 * Attempts to determine if a file contains an image recorded in 126 * a supported graphics format based on its file-name extension 127 * (for example ".jpg", ".gif", ".png", etc.). 128 * 129 * @param fileName A valid string representing name of file which may contain an image. 130 * @return true if the file name has an image format file extension. 131 */ 132 public static boolean hasImageFileExtension(final String fileName) { 133 if (fileName == null) { 134 return false; 135 } 136 137 final String normalizedFilename = fileName.toLowerCase(Locale.ENGLISH); 138 139 for (final ImageParser<?> imageParser : ImageParser.getAllImageParsers()) { 140 for (final String extension : imageParser.getAcceptedExtensions()) { 141 if (normalizedFilename.endsWith(extension.toLowerCase(Locale.ENGLISH))) { 142 return true; 143 } 144 } 145 } 146 147 return false; 148 } 149 150 /** 151 * Attempts to determine the image format of a file based on its "magic numbers," the first bytes of the data. 152 * 153 * <p>Many graphics format specify identifying byte 154 * values that appear at the beginning of the data file. This method 155 * checks for such identifying elements and returns a ImageFormat 156 * enumeration indicating what it detects. Note that this 157 * method can return "false positives" in cases where non-image files 158 * begin with the specified byte values.</p> 159 * 160 * @param bytes Byte array containing an image file. 161 * @return An ImageFormat, such as ImageFormat.IMAGE_FORMAT_JPEG. Returns ImageFormat.IMAGE_FORMAT_UNKNOWN if the image type cannot be determined. 162 * @throws IOException in the event of an unrecoverable I/O condition. 163 */ 164 public static ImageFormat guessFormat(final byte[] bytes) throws IOException { 165 return guessFormat(new ByteSourceArray(bytes)); 166 } 167 168 /** 169 * Attempts to determine the image format of a file based on its "magic numbers," the first bytes of the data. 170 * 171 * <p>Many graphics formats specify identifying byte 172 * values that appear at the beginning of the data file. This method 173 * checks for such identifying elements and returns a ImageFormat 174 * enumeration indicating what it detects. Note that this 175 * method can return "false positives" in cases where non-image files 176 * begin with the specified byte values.</p> 177 * 178 * @param file File containing image data. 179 * @return An ImageFormat, such as ImageFormat.IMAGE_FORMAT_JPEG. Returns ImageFormat.IMAGE_FORMAT_UNKNOWN if the image type cannot be determined. 180 * @throws IOException in the event of an unrecoverable I/O condition. 181 */ 182 public static ImageFormat guessFormat(final File file) throws IOException { 183 return guessFormat(new ByteSourceFile(file)); 184 } 185 186 private static boolean compareBytePair(final int[] a, final int[] b) { 187 if (a.length != 2 && b.length != 2) { 188 throw new IllegalArgumentException("Invalid Byte Pair."); 189 } 190 return (a[0] == b[0]) && (a[1] == b[1]); 191 } 192 193 /** 194 * Attempts to determine the image format of a file based on its "magic numbers," the first bytes of the data. 195 * 196 * <p>Many graphics formats specify identifying byte 197 * values that appear at the beginning of the data file. This method 198 * checks for such identifying elements and returns a ImageFormat 199 * enumeration indicating what it detects. Note that this 200 * method can return "false positives" in cases where non-image files 201 * begin with the specified byte values.</p> 202 * 203 * @param byteSource a valid ByteSource object potentially supplying data for an image. 204 * @return An ImageFormat, such as ImageFormat.IMAGE_FORMAT_JPEG. Returns ImageFormat.IMAGE_FORMAT_UNKNOWN if the image type cannot be determined. 205 * @throws IllegalArgumentException in the event of an unsuccessful attempt to read the image data 206 * @throws IOException in the event of an unrecoverable I/O condition. 207 */ 208 public static ImageFormat guessFormat(final ByteSource byteSource) throws IOException { 209 if (byteSource == null) { 210 return ImageFormats.UNKNOWN; 211 } 212 213 try (InputStream is = byteSource.getInputStream()) { 214 final int i1 = is.read(); 215 final int i2 = is.read(); 216 if ((i1 < 0) || (i2 < 0)) { 217 throw new IllegalArgumentException("Couldn't read magic numbers to guess format."); 218 } 219 220 final int b1 = i1 & 0xff; 221 final int b2 = i2 & 0xff; 222 final int[] bytePair = { b1, b2, }; 223 224 if (compareBytePair(MAGIC_NUMBERS_GIF, bytePair)) { 225 return ImageFormats.GIF; 226 // } else if (b1 == 0x00 && b2 == 0x00) // too similar to TGA 227 // { 228 // return ImageFormat.IMAGE_FORMAT_ICO; 229 } 230 if (compareBytePair(MAGIC_NUMBERS_PNG, bytePair)) { 231 return ImageFormats.PNG; 232 } 233 if (compareBytePair(MAGIC_NUMBERS_JPEG, bytePair)) { 234 return ImageFormats.JPEG; 235 } 236 if (compareBytePair(MAGIC_NUMBERS_BMP, bytePair)) { 237 return ImageFormats.BMP; 238 } 239 if (compareBytePair(MAGIC_NUMBERS_TIFF_MOTOROLA, bytePair)) { 240 return ImageFormats.TIFF; 241 } 242 if (compareBytePair(MAGIC_NUMBERS_TIFF_INTEL, bytePair)) { 243 return ImageFormats.TIFF; 244 } 245 if (compareBytePair(MAGIC_NUMBERS_PSD, bytePair)) { 246 return ImageFormats.PSD; 247 } 248 if (compareBytePair(MAGIC_NUMBERS_PAM, bytePair)) { 249 return ImageFormats.PAM; 250 } 251 if (compareBytePair(MAGIC_NUMBERS_PBM_A, bytePair)) { 252 return ImageFormats.PBM; 253 } 254 if (compareBytePair(MAGIC_NUMBERS_PBM_B, bytePair)) { 255 return ImageFormats.PBM; 256 } 257 if (compareBytePair(MAGIC_NUMBERS_PGM_A, bytePair)) { 258 return ImageFormats.PGM; 259 } 260 if (compareBytePair(MAGIC_NUMBERS_PGM_B, bytePair)) { 261 return ImageFormats.PGM; 262 } 263 if (compareBytePair(MAGIC_NUMBERS_PPM_A, bytePair)) { 264 return ImageFormats.PPM; 265 } 266 if (compareBytePair(MAGIC_NUMBERS_PPM_B, bytePair)) { 267 return ImageFormats.PPM; 268 } 269 if (compareBytePair(MAGIC_NUMBERS_JBIG2_1, bytePair)) { 270 final int i3 = is.read(); 271 final int i4 = is.read(); 272 if ((i3 < 0) || (i4 < 0)) { 273 throw new IllegalArgumentException("Couldn't read magic numbers to guess format."); 274 } 275 276 final int b3 = i3 & 0xff; 277 final int b4 = i4 & 0xff; 278 final int[] bytePair2 = { b3, b4, }; 279 if (compareBytePair(MAGIC_NUMBERS_JBIG2_2, bytePair2)) { 280 return ImageFormats.JBIG2; 281 } 282 } else if (compareBytePair(MAGIC_NUMBERS_ICNS, bytePair)) { 283 return ImageFormats.ICNS; 284 } else if (compareBytePair(MAGIC_NUMBERS_DCX, bytePair)) { 285 return ImageFormats.DCX; 286 } else if (compareBytePair(MAGIC_NUMBERS_RGBE, bytePair)) { 287 return ImageFormats.RGBE; 288 } 289 return Stream 290 .of(ImageFormats.values()) 291 .filter((imageFormat) -> Stream 292 .of(imageFormat.getExtensions()) 293 .anyMatch((extension) -> { 294 final String fileName = byteSource.getFileName(); 295 if (fileName == null || fileName.trim().length() == 0) { 296 return false; 297 } 298 final String fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1); 299 return extension != null 300 && extension.trim().length() > 0 301 && fileExtension.equalsIgnoreCase(extension); 302 })) 303 .findFirst() 304 .orElse(ImageFormats.UNKNOWN) 305 ; 306 } 307 } 308 309 /** 310 * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and TIFF images. 311 * 312 * @param bytes Byte array containing an image file. 313 * @return An instance of ICC_Profile or null if the image contains no ICC profile. 314 * @throws ImageReadException if it fails to parse the image 315 * @throws IOException if it fails to read the image data 316 */ 317 public static ICC_Profile getICCProfile(final byte[] bytes) throws ImageReadException, IOException { 318 return getICCProfile(new ByteSourceArray(bytes)); 319 } 320 321 /** 322 * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and TIFF images. 323 * 324 * @param is InputStream from which to read image data. 325 * @param fileName Filename associated with image data (optional). 326 * @return An instance of ICC_Profile or null if the image contains no ICC profile. 327 * @throws ImageReadException if it fails to parse the image 328 * @throws IOException if it fails to read the image data 329 */ 330 public static ICC_Profile getICCProfile(final InputStream is, final String fileName) throws ImageReadException, IOException { 331 return getICCProfile(new ByteSourceInputStream(is, fileName)); 332 } 333 334 /** 335 * Extracts an ICC Profile (if present) from JPEG, PNG, PSD (Photoshop) and TIFF images. 336 * 337 * @param file File containing image data. 338 * @return An instance of ICC_Profile or null if the image contains no ICC profile. 339 * @throws ImageReadException if it fails to parse the image 340 * @throws IOException if it fails to read the image data 341 */ 342 public static ICC_Profile getICCProfile(final File file) throws ImageReadException, IOException { 343 return getICCProfile(new ByteSourceFile(file)); 344 } 345 346 protected static ICC_Profile getICCProfile(final ByteSource byteSource) throws ImageReadException, IOException { 347 final byte[] bytes = getICCProfileBytes(byteSource); 348 if (bytes == null) { 349 return null; 350 } 351 352 final IccProfileParser parser = new IccProfileParser(); 353 final IccProfileInfo info = parser.getICCProfileInfo(bytes); 354 if (info == null) { 355 return null; 356 } 357 if (info.issRGB()) { 358 return null; 359 } 360 361 return ICC_Profile.getInstance(bytes); 362 } 363 364 /** 365 * Extracts the raw bytes of an ICC Profile (if present) from JPEG, PNG, PSD 366 * (Photoshop) and TIFF images. 367 * 368 * <p>To parse the result use IccProfileParser or 369 * ICC_Profile.getInstance(bytes).</p> 370 * 371 * @param bytes 372 * Byte array containing an image file. 373 * @return A byte array. 374 * @see IccProfileParser 375 * @see ICC_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 byte[] getICCProfileBytes(final byte[] bytes) throws ImageReadException, IOException { 380 return getICCProfileBytes(new ByteSourceArray(bytes)); 381 } 382 383 /** 384 * Extracts the raw bytes of an ICC Profile (if present) from JPEG, PNG, PSD 385 * (Photoshop) and TIFF images. 386 * 387 * <p>To parse the result use IccProfileParser or 388 * ICC_Profile.getInstance(bytes).</p> 389 * 390 * @param file 391 * File containing image data. 392 * @return A byte array. 393 * @see IccProfileParser 394 * @see ICC_Profile 395 * @throws ImageReadException if it fails to parse the image 396 * @throws IOException if it fails to read the image data 397 */ 398 public static byte[] getICCProfileBytes(final File file) throws ImageReadException, IOException { 399 return getICCProfileBytes(new ByteSourceFile(file)); 400 } 401 402 private static byte[] getICCProfileBytes(final ByteSource byteSource) throws ImageReadException, IOException { 403 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 404 return imageParser.getICCProfileBytes(byteSource, null); 405 } 406 407 /** 408 * Parses the "image info" of an image. 409 * 410 * <p>"Image info" is a summary of basic information about the image such as: 411 * width, height, file format, bit depth, color type, etc.</p> 412 * 413 * <p>Not to be confused with "image metadata."</p> 414 * 415 * @param fileName String. 416 * @param bytes Byte array containing an image file. 417 * @return An instance of ImageInfo. 418 * @see ImageInfo 419 * @throws ImageReadException if it fails to parse the image 420 * @throws IOException if it fails to read the image data 421 */ 422 public static ImageInfo getImageInfo(final String fileName, final byte[] bytes) throws ImageReadException, IOException { 423 return getImageInfo(new ByteSourceArray(fileName, bytes)); 424 } 425 426 /** 427 * Parses the "image info" of an image. 428 * 429 * <p>"Image info" is a summary of basic information about the image such as: 430 * width, height, file format, bit depth, color type, etc.</p> 431 * 432 * <p>Not to be confused with "image metadata."</p> 433 * 434 * @param is InputStream from which to read image data. 435 * @param fileName Filename associated with image data (optional). 436 * @return An instance of ImageInfo. 437 * @see ImageInfo 438 * @throws ImageReadException if it fails to parse the image 439 * @throws IOException if it fails to read the image data 440 */ 441 public static ImageInfo getImageInfo(final InputStream is, final String fileName) throws ImageReadException, IOException { 442 return getImageInfo(new ByteSourceInputStream(is, fileName)); 443 } 444 445 /** 446 * Parses the "image info" of an image. 447 * 448 * <p>"Image info" is a summary of basic information about the image such as: 449 * width, height, file format, bit depth, color type, etc.</p> 450 * 451 * <p>Not to be confused with "image metadata."</p> 452 * 453 * @param bytes Byte array containing an image file. 454 * @return An instance of ImageInfo. 455 * @see ImageInfo 456 * @throws ImageReadException if it fails to parse the image 457 * @throws IOException if it fails to read the image data 458 */ 459 public static ImageInfo getImageInfo(final byte[] bytes) throws ImageReadException, IOException { 460 return getImageInfo(new ByteSourceArray(bytes)); 461 } 462 463 /** 464 * Parses the "image info" of an image file. 465 * 466 * <p>"Image info" is a summary of basic information about the image such as: 467 * width, height, file format, bit depth, color type, etc.</p> 468 * 469 * <p>Not to be confused with "image metadata."</p> 470 * 471 * @param file File containing image data. 472 * @return An instance of ImageInfo. 473 * @see ImageInfo 474 * @throws ImageReadException if it fails to parse the image 475 * @throws IOException if it fails to read the image data 476 */ 477 public static ImageInfo getImageInfo(final File file) throws ImageReadException, IOException { 478 return getImageInfo(new ByteSourceFile(file)); 479 } 480 481 private static ImageInfo getImageInfo(final ByteSource byteSource) throws ImageReadException, IOException { 482 return Util.getImageParser(byteSource).getImageInfo(byteSource, null); 483 } 484 485 /** 486 * Determines the width and height of an image. 487 * 488 * @param is InputStream from which to read image data. 489 * @param fileName Filename associated with image data (optional). 490 * @return The width and height of the image. 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 Dimension getImageSize(final InputStream is, final String fileName) throws ImageReadException, IOException { 495 return getImageSize(new ByteSourceInputStream(is, fileName)); 496 } 497 498 /** 499 * Determines the width and height of an image. 500 * 501 * @param bytes Byte array containing an image file. 502 * @return The width and height of the image. 503 * @throws ImageReadException if it fails to parse the image 504 * @throws IOException if it fails to read the image data 505 */ 506 public static Dimension getImageSize(final byte[] bytes) throws ImageReadException, IOException { 507 return getImageSize(new ByteSourceArray(bytes)); 508 } 509 510 /** 511 * Determines the width and height of an image file. 512 * 513 * @param file File containing image data. 514 * @return The width and height of the image. 515 * @throws ImageReadException if it fails to parse the image 516 * @throws IOException if it fails to read the image data 517 */ 518 public static Dimension getImageSize(final File file) throws ImageReadException, IOException { 519 return getImageSize(new ByteSourceFile(file)); 520 } 521 522 /** 523 * Determines the width and height of an image byte source. 524 * 525 * @param byteSource Byte source data. 526 * @return The width and height of the image. 527 * @throws ImageReadException if it fails to parse the image 528 * @throws IOException if it fails to read the image data 529 */ 530 public static Dimension getImageSize(final ByteSource byteSource) throws ImageReadException, IOException { 531 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 532 return imageParser.getImageSize(byteSource, null); 533 } 534 535 /** 536 * Extracts the embedded XML metadata as an XML string. 537 * 538 * @param is InputStream from which to read image data. 539 * @param fileName Filename associated with image data (optional). 540 * @return Xmp Xml as String, if present. Otherwise, returns null. 541 * @throws ImageReadException if it fails to parse the image 542 * @throws IOException if it fails to read the image data 543 */ 544 public static String getXmpXml(final InputStream is, final String fileName) throws ImageReadException, IOException { 545 return getXmpXml(new ByteSourceInputStream(is, fileName)); 546 } 547 548 /** 549 * Extracts the embedded XML metadata as an XML string. 550 * 551 * @param bytes Byte array containing an image file. 552 * @return Xmp Xml as String, if present. Otherwise, returns null. 553 * @throws ImageReadException if it fails to parse the image 554 * @throws IOException if it fails to read the image data 555 */ 556 public static String getXmpXml(final byte[] bytes) throws ImageReadException, IOException { 557 return getXmpXml(new ByteSourceArray(bytes)); 558 } 559 560 /** 561 * Extracts the embedded XML metadata as an XML string. 562 * 563 * @param file File containing image data. 564 * @return Xmp Xml as String, if present. Otherwise, returns null. 565 * @throws ImageReadException if it fails to parse the image 566 * @throws IOException if it fails to read the image data 567 */ 568 public static String getXmpXml(final File file) throws ImageReadException, IOException { 569 return getXmpXml(new ByteSourceFile(file)); 570 } 571 572 /** 573 * Extracts the embedded XML metadata as an XML string. 574 * 575 * @param byteSource File containing image data. 576 * @return Xmp Xml as String, if present. Otherwise, returns null. 577 * @throws ImageReadException if it fails to parse the image 578 * @throws IOException if it fails to read the image data 579 */ 580 public static String getXmpXml(final ByteSource byteSource) throws ImageReadException, IOException { 581 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 582 if (imageParser instanceof XmpEmbeddable) { 583 return ((XmpEmbeddable) imageParser).getXmpXml(byteSource, null); 584 } 585 return null; 586 } 587 588 /** 589 * Parses the metadata of an image. This metadata depends on the format of the image. 590 * 591 * <p>JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may 592 * contain comments. TIFF files may contain metadata.</p> 593 * 594 * <p>The instance of IImageMetadata returned by getMetadata() should be upcast 595 * (depending on image format).</p> 596 * 597 * <p>Not to be confused with "image info."</p> 598 * 599 * @param bytes Byte array containing an image file. 600 * @return An instance of ImageMetadata. 601 * @see org.apache.commons.imaging.common.ImageMetadata 602 * @throws ImageReadException if it fails to read the image metadata 603 * @throws IOException if it fails to read the image data 604 */ 605 public static ImageMetadata getMetadata(final byte[] bytes) throws ImageReadException, IOException { 606 return getMetadata(new ByteSourceArray(bytes)); 607 } 608 609 /** 610 * Parses the metadata of an image file. This metadata depends on the format of the image. 611 * 612 * <p>JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may 613 * contain comments. TIFF files may contain metadata.</p> 614 * 615 * <p>The instance of IImageMetadata returned by getMetadata() should be upcast (depending on image format).</p> 616 * 617 * <p>Not to be confused with "image info."</p> 618 * 619 * @param is InputStream from which to read image data. 620 * @param fileName Filename associated with image data (optional). 621 * @return An instance of IImageMetadata. 622 * @see org.apache.commons.imaging.common.ImageMetadata 623 * @throws ImageReadException if it fails to read the image metadata 624 * @throws IOException if it fails to read the image data 625 */ 626 public static ImageMetadata getMetadata(final InputStream is, final String fileName) throws ImageReadException, IOException { 627 return getMetadata(new ByteSourceInputStream(is, fileName)); 628 } 629 630 /** 631 * Parses the metadata of an image file. This metadata depends on the format of the image. 632 * 633 * <p>JPEG/JFIF files may contain EXIF and/or IPTC metadata. PNG files may 634 * contain comments. TIFF files may contain metadata.</p> 635 * 636 * <p>The instance of IImageMetadata returned by getMetadata() should be upcast 637 * (depending on image format).</p> 638 * 639 * <p>Not to be confused with "image info."</p> 640 * 641 * @param file File containing image data. 642 * @return An instance of IImageMetadata. 643 * @see org.apache.commons.imaging.common.ImageMetadata 644 * @throws ImageReadException if it fails to read the image metadata 645 * @throws IOException if it fails to read the image data 646 */ 647 public static ImageMetadata getMetadata(final File file) throws ImageReadException, IOException { 648 return getMetadata(new ByteSourceFile(file)); 649 } 650 651 private static ImageMetadata getMetadata(final ByteSource byteSource) throws ImageReadException, IOException { 652 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 653 return imageParser.getMetadata(byteSource, null); 654 } 655 656 /** 657 * Write the ImageInfo and format-specific information for the image content of the specified byte array to a string. 658 * 659 * @param bytes A valid array of bytes. 660 * @return A valid string. 661 * @throws ImageReadException In the event that the specified content does not conform to the format of the specific parser implementation. 662 * @throws IOException In the event of unsuccessful read or access operation. 663 */ 664 public static String dumpImageFile(final byte[] bytes) throws ImageReadException, IOException { 665 return dumpImageFile(new ByteSourceArray(bytes)); 666 } 667 668 /** 669 * Write the ImageInfo and format-specific information for the image content of the specified file to a string. 670 * 671 * @param file A valid file reference. 672 * @return A valid string. 673 * @throws ImageReadException In the event that the specified content does not conform to the format of the specific parser implementation. 674 * @throws IOException In the event of unsuccessful read or access operation. 675 */ 676 public static String dumpImageFile(final File file) throws ImageReadException, IOException { 677 return dumpImageFile(new ByteSourceFile(file)); 678 } 679 680 private static String dumpImageFile(final ByteSource byteSource) throws ImageReadException, IOException { 681 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 682 return imageParser.dumpImageFile(byteSource); 683 } 684 685 /** 686 * Attempts to determine the image format of the specified data and evaluates its format compliance. 687 * 688 * <p>This method returns a FormatCompliance object which includes information about the data's compliance to a specific format.</p> 689 * 690 * @param bytes a valid array of bytes containing image data. 691 * @return if successful, a valid FormatCompliance object. 692 * @throws ImageReadException in the event of unreadable data. 693 * @throws IOException in the event of an unrecoverable I/O condition. 694 */ 695 public static FormatCompliance getFormatCompliance(final byte[] bytes) throws ImageReadException, IOException { 696 return getFormatCompliance(new ByteSourceArray(bytes)); 697 } 698 699 /** 700 * Attempts to determine the image format of the specified data and 701 * evaluates its format compliance. This method 702 * returns a FormatCompliance object which includes information 703 * about the data's compliance to a specific format. 704 * 705 * @param file valid file containing image data 706 * @return if successful, a valid FormatCompliance object. 707 * @throws ImageReadException in the event of unreadable data. 708 * @throws IOException in the event of an unrecoverable I/O condition. 709 */ 710 public static FormatCompliance getFormatCompliance(final File file) throws ImageReadException, IOException { 711 return getFormatCompliance(new ByteSourceFile(file)); 712 } 713 714 private static FormatCompliance getFormatCompliance(final ByteSource byteSource) throws ImageReadException, IOException { 715 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 716 return imageParser.getFormatCompliance(byteSource); 717 } 718 719 /** 720 * Gets all images specified by the InputStream (some formats may include multiple images within a single data source). 721 * 722 * @param is A valid InputStream 723 * @param fileName Filename associated with image data (optional). 724 * @return A valid (potentially empty) list of BufferedImage objects. 725 * @throws ImageReadException In the event that the specified content does not conform to the format of the specific parser implementation. 726 * @throws IOException In the event of unsuccessful read or access operation. 727 */ 728 public static List<BufferedImage> getAllBufferedImages(final InputStream is, final String fileName) throws ImageReadException, IOException { 729 return getAllBufferedImages(new ByteSourceInputStream(is, fileName)); 730 } 731 732 /** 733 * Gets all images specified by the byte array (some formats may include multiple images within a single data source). 734 * 735 * @param bytes a valid array of bytes 736 * @return A valid (potentially empty) list of BufferedImage objects. 737 * @throws ImageReadException In the event that the specified content does not conform to the format of the specific parser implementation. 738 * @throws IOException In the event of unsuccessful read or access operation. 739 */ 740 public static List<BufferedImage> getAllBufferedImages(final byte[] bytes) throws ImageReadException, IOException { 741 return getAllBufferedImages(new ByteSourceArray(bytes)); 742 } 743 744 /** 745 * Gets all images specified by the file (some formats may include multiple images within a single data source). 746 * 747 * @param file A reference to a valid data file. 748 * @return A valid (potentially empty) list of BufferedImage objects. 749 * @throws ImageReadException In the event that the specified content does not conform to the format of the specific parser implementation. 750 * @throws IOException In the event of unsuccessful read or access operation. 751 */ 752 public static List<BufferedImage> getAllBufferedImages(final File file) throws ImageReadException, IOException { 753 return getAllBufferedImages(new ByteSourceFile(file)); 754 } 755 756 private static List<BufferedImage> getAllBufferedImages(final ByteSource byteSource) throws ImageReadException, IOException { 757 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 758 return imageParser.getAllBufferedImages(byteSource); 759 } 760 761 /** 762 * Reads the first image from an InputStream. 763 * 764 * <p>For the most recent information on support for specific formats, refer to 765 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 766 * at the main project development web site. While the Apache Commons 767 * Imaging package does not fully support all formats, it can read 768 * image info, metadata and ICC profiles from all image formats that 769 * provide this data.</p> 770 * 771 * @param is a valid ImageStream from which to read data. 772 * @return if successful, a valid buffered image 773 * @throws ImageReadException in the event of a processing errorfileName while reading an image (i.e. a format violation, etc.). 774 * @throws IOException in the event of an unrecoverable I/O exception. 775 */ 776 public static BufferedImage getBufferedImage(final InputStream is) throws ImageReadException, IOException { 777 return getBufferedImage(is, null); 778 } 779 780 /** 781 * Reads the first image from an InputStream. 782 * 783 * <p>For the most recent information on support for specific formats, refer to 784 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 785 * at the main project development web site. While the Apache Commons 786 * Imaging package does not fully support all formats, it can read 787 * image info, metadata and ICC profiles from all image formats that 788 * provide this data.</p> 789 * 790 * @param is a valid ImageStream from which to read data. 791 * @param fileName the image file name. 792 * @return if successful, a valid buffered image 793 * @throws ImageReadException in the event of a processing error while reading an image (i.e. a format violation, etc.). 794 * @throws IOException in the event of an unrecoverable I/O exception. 795 */ 796 public static BufferedImage getBufferedImage(final InputStream is, String fileName) throws ImageReadException, IOException { 797 return getBufferedImage(new ByteSourceInputStream(is, fileName)); 798 } 799 800 /** 801 * Reads the first image from a byte array. 802 * 803 * <p>For the most recent information on support for specific formats, refer to 804 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 805 * at the main project development web site. While the Apache Commons 806 * Imaging package does not fully support all formats, it can read 807 * image info, metadata and ICC profiles from all image formats that 808 * provide this data.</p> 809 * 810 * @param bytes a valid array of bytes from which to read data. 811 * @return if successful, a valid buffered image 812 * @throws ImageReadException in the event of a processing error while reading an image (i.e. a format violation, etc.). 813 * @throws IOException in the event of an unrecoverable I/O exception. 814 */ 815 public static BufferedImage getBufferedImage(final byte[] bytes) throws ImageReadException, IOException { 816 return getBufferedImage(new ByteSourceArray(bytes)); 817 } 818 819 /** 820 * Reads the first image from a file. 821 * 822 * <p>For the most recent information on support for specific formats, refer to 823 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 824 * at the main project development web site. While the Apache Commons 825 * Imaging package does not fully support all formats, it can read 826 * image info, metadata and ICC profiles from all image formats that 827 * provide this data.</p> 828 * 829 * @param file a valid reference to a file containing image data. 830 * @return if successful, a valid buffered image 831 * @throws ImageReadException in the event of a processing error while reading an image (i.e. a format violation, etc.). 832 * @throws IOException in the event of an unrecoverable I/O exception. 833 */ 834 public static BufferedImage getBufferedImage(final File file) throws ImageReadException, IOException { 835 return getBufferedImage(new ByteSourceFile(file)); 836 } 837 838 private static BufferedImage getBufferedImage(final ByteSource byteSource) throws ImageReadException, IOException { 839 final ImageParser<?> imageParser = Util.getImageParser(byteSource); 840 return imageParser.getBufferedImage(byteSource, null); 841 } 842 843 /** 844 * Writes the content of a BufferedImage to a file using the specified image format. 845 * 846 * <p>Image writing is not supported for all graphics formats. 847 * For the most recent information on support for specific formats, refer to 848 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 849 * at the main project development web site. While the Apache Commons 850 * Imaging package does not fully support all formats, it can read 851 * image info, metadata and ICC profiles from all image formats that 852 * provide this data.</p> 853 * 854 * @param src a valid BufferedImage object 855 * @param file the file to which the output image is to be written 856 * @param format the format in which the output image is to be written 857 * @throws ImageWriteException in the event of a format violation, unsupported image format, etc. 858 * @throws IOException in the event of an unrecoverable I/O exception. 859 * @see ImagingConstants 860 */ 861 public static void writeImage(final BufferedImage src, final File file, final ImageFormat format) throws ImageWriteException, IOException { 862 try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream os = new BufferedOutputStream(fos)) { 863 writeImage(src, os, format); 864 } 865 } 866 867 /** 868 * Writes the content of a BufferedImage to a byte array using the specified image format. 869 * 870 * <p>Image writing is not supported for all graphics formats. 871 * For the most recent information on support for specific formats, refer to 872 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 873 * at the main project development web site. While the Apache Commons 874 * Imaging package does not fully support all formats, it can read 875 * image info, metadata and ICC profiles from all image formats that 876 * provide this data.</p> 877 * 878 * @param src a valid BufferedImage object 879 * @param format the format in which the output image is to be written 880 * @return if successful, a valid array of bytes. 881 * @throws ImageWriteException in the event of a format violation, unsupported image format, etc. 882 * @throws IOException in the event of an unrecoverable I/O exception. 883 * @see ImagingConstants 884 */ 885 public static byte[] writeImageToBytes(final BufferedImage src, final ImageFormat format) throws ImageWriteException, IOException { 886 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { 887 writeImage(src, os, format); 888 return os.toByteArray(); 889 } 890 } 891 892 /** 893 * Writes the content of a BufferedImage to an OutputStream using the specified image format. 894 * 895 * <p>Image writing is not supported for all graphics formats. 896 * For the most recent information on support for specific formats, refer to 897 * <a href="https://commons.apache.org/imaging/formatsupport.html">Format Support</a> 898 * at the main project development web site. While the Apache Commons 899 * Imaging package does not fully support all formats, it can read 900 * image info, metadata and ICC profiles from all image formats that 901 * provide this data.</p> 902 * 903 * @param src a valid BufferedImage object 904 * @param os the OutputStream to which the output image is to be written 905 * @param format the format in which the output image is to be written 906 * @throws ImageWriteException in the event of a format violation, unsupported image format, etc. 907 * @throws IOException in the event of an unrecoverable I/O exception. 908 * @see ImagingConstants 909 */ 910 public static void writeImage(final BufferedImage src, final OutputStream os, final ImageFormat format) throws ImageWriteException, IOException { 911 Objects.requireNonNull(src, "src must not be null"); 912 Objects.requireNonNull(os, "os must not be null"); 913 Objects.requireNonNull(format, "format must not be null"); 914 915 ImageParser<?> imageParser = Util.getImageParser(format); 916 imageParser.writeImage(src, os, null); 917 } 918}