All formats

metadata-extractor

LanguageJava 8 or later, Android
LicenseApache 2.0
Repositorygithub.com/drewnoakes/metadata-extractor
DocumentationJavadoc, project wiki
Depends onxmpcore (Adobe XMP library)
Read / writemetadata only / no

metadata-extractor reads metadata from JPEG files without decoding the image: Exif (IFD0, SubIFD, GPS, thumbnail), maker notes of most camera brands, XMP, IPTC, ICC profiles, JFIF, Photoshop resources and the JPEG frame header. Each block is a Directory with typed getters and human-readable descriptions of every tag. It also handles PNG, GIF, HEIF, WebP, TIFF, camera raw, MP4 and QuickTime files.

It’s read-only. To change Exif in Java, use Apache Commons Imaging (ExifRewriter) or call ExifTool. A .NET port exists: MetadataExtractor.

Installation#

Maven:

XML
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.22.0</version>
</dependency>

Gradle:

implementation("com.drewnoakes:metadata-extractor:2.22.0")

Basic usage: print all metadata of a JPEG#

Java
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import java.io.File;
import java.io.IOException;

public class DumpMetadata {
    public static void main(String[] args) throws ImageProcessingException, IOException {
        Metadata metadata = ImageMetadataReader.readMetadata(new File("photo.jpg"));
        for (Directory directory : metadata.getDirectories()) {
            for (Tag tag : directory.getTags()) {
                System.out.println("[" + directory.getName() + "] " + tag.getTagName() + " = " + tag.getDescription());
            }
            for (String error : directory.getErrors()) {
                System.err.println("ERROR: " + error);
            }
        }
    }
}

How to get the camera model and the date a photo was taken#

Java
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import java.util.Date;

ExifIFD0Directory ifd0 = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (ifd0 != null) {
    System.out.println(ifd0.getString(ExifIFD0Directory.TAG_MAKE) + " " + ifd0.getString(ExifIFD0Directory.TAG_MODEL));
}
ExifSubIFDDirectory sub = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
if (sub != null) {
    Date taken = sub.getDateOriginal();   // interpreted as UTC; pass a TimeZone for local time
    System.out.println("Taken: " + taken);
}

How to read the GPS location of a photo#

Java
import com.drew.lang.GeoLocation;
import com.drew.metadata.exif.GpsDirectory;

GpsDirectory gps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
if (gps != null) {
    GeoLocation location = gps.getGeoLocation();
    if (location != null && !location.isZero()) {
        System.out.println(location.getLatitude() + ", " + location.getLongitude());
    }
}

How to read the Exif orientation#

Java
import com.drew.metadata.exif.ExifIFD0Directory;

int orientation = 1;
ExifIFD0Directory ifd0 = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (ifd0 != null && ifd0.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
    orientation = ifd0.getInteger(ExifIFD0Directory.TAG_ORIENTATION);
}
// 1 = normal, 3 = 180°, 6 = rotate 90° clockwise, 8 = rotate 90° counter-clockwise

How to get JPEG dimensions and compression type#

Java
import com.drew.metadata.MetadataException;
import com.drew.metadata.jpeg.JpegDirectory;

JpegDirectory jpeg = metadata.getFirstDirectoryOfType(JpegDirectory.class);
if (jpeg != null) {
    try {
        System.out.println(jpeg.getImageWidth() + " x " + jpeg.getImageHeight());
    } catch (MetadataException e) {
        System.err.println("no size in SOF marker");
    }
    System.out.println(jpeg.getDescription(JpegDirectory.TAG_COMPRESSION_TYPE));  // "Baseline", "Progressive, Huffman"
}

Tips#