All formats

MetadataExtractor

LanguageC# (.NET Standard 2.0 and 2.1, so .NET Framework and all modern .NET)
LicenseApache 2.0
Repositorygithub.com/drewnoakes/metadata-extractor-dotnet
DocumentationREADME, format notes
Depends onXmpCore (for XMP)
Read / writemetadata only / no

MetadataExtractor reads the metadata segments of a JPEG without decoding pixels: Exif (IFD0, Exif SubIFD, GPS, thumbnail), camera maker notes (Canon, Nikon, Sony, Fujifilm, Olympus, Panasonic and others), XMP, IPTC, ICC profiles, JFIF, Photoshop resources and the frame header (size, components, subsampling). It returns each block as a Directory of tags with both raw values and human-readable descriptions.

It also reads PNG, GIF, HEIC, AVIF, WebP, TIFF, camera raw files and video containers. It doesn’t write metadata; use Magick.NET or ExifTool for that. It’s the .NET port of the Java metadata-extractor.

Installation#

Shell
dotnet add package MetadataExtractor

Basic usage: print all metadata#

C#
using MetadataExtractor;

var directories = ImageMetadataReader.ReadMetadata("photo.jpg");
foreach (var directory in directories)
{
    foreach (var tag in directory.Tags)
        Console.WriteLine($"[{directory.Name}] {tag.Name} = {tag.Description}");

    foreach (var error in directory.Errors)
        Console.Error.WriteLine($"ERROR: {error}");
}

Output looks like [Exif IFD0] Model = Canon EOS R6, [Exif SubIFD] Exposure Time = 1/250 sec, [GPS] GPS Latitude = 52° 13' 47.9".

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

C#
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;

var directories = ImageMetadataReader.ReadMetadata("photo.jpg");

var ifd0 = directories.OfType<ExifIfd0Directory>().FirstOrDefault();
string? make = ifd0?.GetDescription(ExifDirectoryBase.TagMake);
string? model = ifd0?.GetDescription(ExifDirectoryBase.TagModel);

var subIfd = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
if (subIfd != null && subIfd.TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out DateTime taken))
    Console.WriteLine($"{make} {model}, taken {taken:yyyy-MM-dd HH:mm}");

How to read the GPS location of a photo#

C#
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;

var gps = ImageMetadataReader.ReadMetadata("photo.jpg").OfType<GpsDirectory>().FirstOrDefault();
if (gps != null && gps.TryGetGeoLocation(out GeoLocation location))
    Console.WriteLine($"{location.Latitude}, {location.Longitude}");  // decimal degrees

How to read the Exif orientation#

C#
var ifd0 = ImageMetadataReader.ReadMetadata("photo.jpg").OfType<ExifIfd0Directory>().FirstOrDefault();
int orientation = 1;
if (ifd0 != null && ifd0.TryGetInt32(ExifDirectoryBase.TagOrientation, out int value))
    orientation = value;   // 1 normal, 3 = 180°, 6 = 90° clockwise, 8 = 90° counter-clockwise

How to get JPEG dimensions and encoding#

The JpegDirectory comes from the SOF marker:

C#
using MetadataExtractor;
using MetadataExtractor.Formats.Jpeg;

var jpeg = ImageMetadataReader.ReadMetadata("photo.jpg").OfType<JpegDirectory>().FirstOrDefault();
if (jpeg != null)
{
    Console.WriteLine($"{jpeg.GetImageWidth()} x {jpeg.GetImageHeight()}");
    Console.WriteLine(jpeg.GetDescription(JpegDirectory.TagCompressionType));  // "Baseline" or "Progressive, Huffman"
}

Tips#