metadata-extractor
| Language | Java 8 or later, Android |
|---|---|
| License | Apache 2.0 |
| Repository | github.com/drewnoakes/metadata-extractor |
| Documentation | Javadoc, project wiki |
| Depends on | xmpcore (Adobe XMP library) |
| Read / write | metadata 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#
JpegMetadataReader.readMetadata(file)skips file type detection when you know it’s a JPEG.ImageMetadataReaderaccepts anInputStream, so you can read metadata from uploads without saving them.- On Android,
androidx.exifinterface.media.ExifInterfaceis a lighter alternative that can also write Exif.