All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.drew.imaging.ImageMetadataReader Maven / Gradle / Ivy

Go to download

Java library for extracting EXIF, IPTC, XMP, ICC and other metadata from image and video files.

There is a newer version: 2.19.0
Show newest version
/*
 * Copyright 2002-2019 Drew Noakes and contributors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 *
 * More information about this project is available at:
 *
 *    https://drewnoakes.com/code/exif/
 *    https://github.com/drewnoakes/metadata-extractor
 */
package com.drew.imaging;

import com.drew.imaging.avi.AviMetadataReader;
import com.drew.imaging.bmp.BmpMetadataReader;
import com.drew.imaging.eps.EpsMetadataReader;
import com.drew.imaging.gif.GifMetadataReader;
import com.drew.imaging.heif.HeifMetadataReader;
import com.drew.imaging.ico.IcoMetadataReader;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.mp3.Mp3MetadataReader;
import com.drew.imaging.mp4.Mp4MetadataReader;
import com.drew.imaging.quicktime.QuickTimeMetadataReader;
import com.drew.imaging.pcx.PcxMetadataReader;
import com.drew.imaging.png.PngMetadataReader;
import com.drew.imaging.psd.PsdMetadataReader;
import com.drew.imaging.raf.RafMetadataReader;
import com.drew.imaging.tiff.TiffMetadataReader;
import com.drew.imaging.wav.WavMetadataReader;
import com.drew.imaging.webp.WebpMetadataReader;
import com.drew.lang.RandomAccessStreamReader;
import com.drew.lang.StringUtil;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.file.FileSystemMetadataReader;
import com.drew.metadata.file.FileTypeDirectory;
import com.drew.metadata.xmp.XmpDirectory;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;

/**
 * Reads metadata from any supported file format.
 * 

* This class a lightweight wrapper around other, specific metadata processors. * During extraction, the file type is determined from the first few bytes of the file. * Parsing is then delegated to one of: * *

    *
  • {@link AviMetadataReader} for AVI files
  • *
  • {@link BmpMetadataReader} for BMP files
  • *
  • {@link FileSystemMetadataReader} for metadata from the file system when a {@link File} is provided
  • *
  • {@link GifMetadataReader} for GIF files
  • *
  • {@link IcoMetadataReader} for ICO files
  • *
  • {@link JpegMetadataReader} for JPEG files
  • *
  • {@link Mp4MetadataReader} for MPEG-4 files
  • *
  • {@link PcxMetadataReader} for PCX files
  • *
  • {@link PngMetadataReader} for PNG files
  • *
  • {@link PsdMetadataReader} for Photoshop files
  • *
  • {@link QuickTimeMetadataReader} for QuickTime files
  • *
  • {@link RafMetadataReader} for RAF files
  • *
  • {@link TiffMetadataReader} for TIFF and (most) RAW files
  • *
  • {@link WavMetadataReader} for WAV files
  • *
  • {@link WebpMetadataReader} for WebP files
  • *
* * If you know the file type you're working with, you may use one of the above processors directly. * For most scenarios it is simpler, more convenient and more robust to use this class. *

* {@link FileTypeDetector} is used to determine the provided image's file type, and therefore * the appropriate metadata reader to use. * * @author Drew Noakes https://drewnoakes.com */ public class ImageMetadataReader { /** * Reads metadata from an {@link InputStream}. * * @param inputStream a stream from which the file data may be read. The stream must be positioned at the * beginning of the file's data. * @return a populated {@link Metadata} object containing directories of tags with values and any processing errors. * @throws ImageProcessingException if the file type is unknown, or for general processing errors. */ @NotNull public static Metadata readMetadata(@NotNull final InputStream inputStream) throws ImageProcessingException, IOException { return readMetadata(inputStream, -1); } /** * Reads metadata from an {@link InputStream} of known length. * * @param inputStream a stream from which the file data may be read. The stream must be positioned at the * beginning of the file's data. * @param streamLength the length of the stream, if known, otherwise -1. * @return a populated {@link Metadata} object containing directories of tags with values and any processing errors. * @throws ImageProcessingException if the file type is unknown, or for general processing errors. */ @NotNull public static Metadata readMetadata(@NotNull final InputStream inputStream, final long streamLength) throws ImageProcessingException, IOException { BufferedInputStream bufferedInputStream = inputStream instanceof BufferedInputStream ? (BufferedInputStream)inputStream : new BufferedInputStream(inputStream); FileType fileType = FileTypeDetector.detectFileType(bufferedInputStream); Metadata metadata = readMetadata(bufferedInputStream, streamLength, fileType); metadata.addDirectory(new FileTypeDirectory(fileType)); return metadata; } /** * Reads metadata from an {@link InputStream} of known length and file type. * * @param inputStream a stream from which the file data may be read. The stream must be positioned at the * beginning of the file's data. * @param streamLength the length of the stream, if known, otherwise -1. * @param fileType the file type of the data stream. * @return a populated {@link Metadata} object containing directories of tags with values and any processing errors. * @throws ImageProcessingException if the file type is unknown, or for general processing errors. */ @NotNull public static Metadata readMetadata(@NotNull final InputStream inputStream, final long streamLength, final FileType fileType) throws IOException, ImageProcessingException { switch (fileType) { case Jpeg: return JpegMetadataReader.readMetadata(inputStream); case Tiff: case Arw: case Cr2: case Nef: case Orf: case Rw2: return TiffMetadataReader.readMetadata(new RandomAccessStreamReader(inputStream, RandomAccessStreamReader.DEFAULT_CHUNK_LENGTH, streamLength)); case Psd: return PsdMetadataReader.readMetadata(inputStream); case Png: return PngMetadataReader.readMetadata(inputStream); case Bmp: return BmpMetadataReader.readMetadata(inputStream); case Gif: return GifMetadataReader.readMetadata(inputStream); case Ico: return IcoMetadataReader.readMetadata(inputStream); case Pcx: return PcxMetadataReader.readMetadata(inputStream); case WebP: return WebpMetadataReader.readMetadata(inputStream); case Raf: return RafMetadataReader.readMetadata(inputStream); case Avi: return AviMetadataReader.readMetadata(inputStream); case Wav: return WavMetadataReader.readMetadata(inputStream); case QuickTime: return QuickTimeMetadataReader.readMetadata(inputStream); case Mp4: return Mp4MetadataReader.readMetadata(inputStream); case Mp3: return Mp3MetadataReader.readMetadata(inputStream); case Eps: return EpsMetadataReader.readMetadata(inputStream); case Heif: return HeifMetadataReader.readMetadata(inputStream); case Unknown: throw new ImageProcessingException("File format could not be determined"); default: return new Metadata(); } } /** * Reads {@link Metadata} from a {@link File} object. * * @param file a file from which the image data may be read. * @return a populated {@link Metadata} object containing directories of tags with values and any processing errors. * @throws ImageProcessingException for general processing errors. */ @NotNull public static Metadata readMetadata(@NotNull final File file) throws ImageProcessingException, IOException { InputStream inputStream = new FileInputStream(file); Metadata metadata; try { metadata = readMetadata(inputStream, file.length()); } finally { inputStream.close(); } new FileSystemMetadataReader().read(file, metadata); return metadata; } private ImageMetadataReader() throws Exception { throw new Exception("Not intended for instantiation"); } /** * An application entry point. Takes the name of one or more files as arguments and prints the contents of all * metadata directories to System.out. *

* If -thumb is passed, then any thumbnail data will be written to a file with name of the * input file having .thumb.jpg appended. *

* If -markdown is passed, then output will be in markdown format. *

* If -hex is passed, then the ID of each tag will be displayed in hexadecimal. * * @param args the command line arguments */ public static void main(@NotNull String[] args) { Collection argList = new ArrayList(Arrays.asList(args)); boolean markdownFormat = argList.remove("-markdown"); boolean showHex = argList.remove("-hex"); if (argList.size() < 1) { String version = ImageMetadataReader.class.getPackage().getImplementationVersion(); System.out.println("metadata-extractor version " + version); System.out.println(); System.out.println(String.format("Usage: java -jar metadata-extractor-%s.jar [] [-thumb] [-markdown] [-hex]", version == null ? "a.b.c" : version)); System.exit(1); } for (String filePath : argList) { long startTime = System.nanoTime(); File file = new File(filePath); if (!markdownFormat && argList.size()>1) System.out.printf("%n***** PROCESSING: %s%n%n", filePath); Metadata metadata = null; try { metadata = ImageMetadataReader.readMetadata(file); } catch (Exception e) { e.printStackTrace(System.err); System.exit(1); } long took = System.nanoTime() - startTime; if (!markdownFormat) System.out.printf("Processed %.3f MB file in %.2f ms%n%n", file.length() / (1024d * 1024), took / 1000000d); if (markdownFormat) { String fileName = file.getName(); String urlName = StringUtil.urlEncode(filePath); ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); String make = exifIFD0Directory == null ? "" : exifIFD0Directory.getString(ExifIFD0Directory.TAG_MAKE); String model = exifIFD0Directory == null ? "" : exifIFD0Directory.getString(ExifIFD0Directory.TAG_MODEL); System.out.println(); System.out.println("---"); System.out.println(); System.out.printf("# %s - %s%n", make, model); System.out.println(); System.out.printf("%n", urlName); System.out.printf("
%n", urlName); System.out.println(fileName); System.out.println("
"); System.out.println(); System.out.println("Directory | Tag Id | Tag Name | Extracted Value"); System.out.println(":--------:|-------:|----------|----------------"); } // iterate over the metadata and print to System.out for (Directory directory : metadata.getDirectories()) { String directoryName = directory.getName(); for (Tag tag : directory.getTags()) { String tagName = tag.getTagName(); String description = tag.getDescription(); // truncate the description if it's too long if (description != null && description.length() > 1024) { description = description.substring(0, 1024) + "..."; } if (markdownFormat) { System.out.printf("%s|0x%s|%s|%s%n", directoryName, Integer.toHexString(tag.getTagType()), tagName, description); } else { // simple formatting if (showHex) { System.out.printf("[%s - %s] %s = %s%n", directoryName, tag.getTagTypeHex(), tagName, description); } else { System.out.printf("[%s] %s = %s%n", directoryName, tagName, description); } } } if (directory instanceof XmpDirectory) { Map xmpProperties = ((XmpDirectory)directory).getXmpProperties(); for (Map.Entry property : xmpProperties.entrySet()) { String key = property.getKey(); String value = property.getValue(); if (value != null && value.length() > 1024) { value = value.substring(0, 1024) + "..."; } if (markdownFormat) { System.out.printf("%s||%s|%s%n", directoryName, key, value); } else { System.out.printf("[%s] %s = %s%n", directoryName, key, value); } } } // print out any errors for (String error : directory.getErrors()) System.err.println("ERROR: " + error); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy