Skip to main content

Crate nom_exif

Crate nom_exif 

Source
Expand description

nom-exif is a pure Rust library for both image EXIF and video / audio track metadata through a single unified API.

§Highlights

  • Pure Rust — no FFmpeg, no libexif, no system deps; cross-compiles cleanly.
  • Image and video / audio in one crate — MediaParser dispatches to the right backend by detected MIME, no per-format wrappers.
  • RAW format support — Canon CR3, Fujifilm RAF, Phase One IIQ, alongside JPEG / HEIC / TIFF.
  • Three input modes — files, arbitrary Read / Read + Seek (network streams, pipes), or in-RAM bytes (WASM, mobile, HTTP proxies).
  • Sync and async unified under one MediaParser.
  • Eager (Exif, get-by-tag) or lazy (ExifIter, parse-on-demand) — per-entry errors surface in both modes (Exif::errors / per-iter Result), so one bad tag doesn’t poison the parse.
  • Allocation-frugal — parser buffer is recycled across calls; sub-IFDs share the same allocation (no deep copies).
  • Fuzz-tested with cargo-fuzz against malformed and adversarial input.

§Quick start

For a one-shot read, use the helpers:

use nom_exif::{read_exif, ExifTag};

let exif = read_exif("./testdata/exif.jpg")?;
let make = exif.get(ExifTag::Make).and_then(|v| v.as_str());
assert_eq!(make, Some("vivo"));

For batch processing, build a MediaParser once and reuse its buffer:

use nom_exif::{MediaKind, MediaParser, MediaSource};

let mut parser = MediaParser::new();
for path in ["./testdata/exif.jpg", "./testdata/meta.mov"] {
    let ms = MediaSource::open(path)?;
    match ms.kind() {
        MediaKind::Image => { let _ = parser.parse_exif(ms)?; }
        MediaKind::Track => { let _ = parser.parse_track(ms)?; }
    }
}

Async variants live behind feature = "tokio": read_exif_async, read_track_async, read_metadata_async, plus MediaParser::parse_exif_async / MediaParser::parse_track_async.

§Reading from in-memory bytes

When the payload is already in RAM (WASM, mobile, HTTP proxy, decoded response body), use the *_from_bytes helpers to skip the File / Read round-trip entirely. Memory mode is zero-copy: the underlying allocation is shared with the returned Exif / ExifIter / TrackInfo via bytes::Bytes reference counting.

use nom_exif::{read_exif_from_bytes, ExifTag};

let raw = std::fs::read("./testdata/exif.jpg")?;
let exif = read_exif_from_bytes(raw)?;
assert_eq!(exif.get(ExifTag::Make).and_then(|v| v.as_str()), Some("vivo"));

For batch processing of many in-memory payloads, build a MediaParser once and call MediaParser::parse_exif_from_bytes / MediaParser::parse_track_from_bytes per payload.

§API surface

See docs/MIGRATION.md for the v2 → v3 migration guide and docs/V3_API_DESIGN.md for the internal design contract.

§Cargo features

  • tokio — async API via tokio (AsyncMediaSource, read_*_async, MediaParser::parse_*_async).
  • serde — derives Serialize/Deserialize on the public types.

§Embedded media tracks

Some images embed a media track that parse_exif doesn’t surface — most commonly Pixel/Google Motion Photo JPEGs, which carry a short MP4 video appended after the JPEG image data. The Exif::has_embedded_track / ExifIter::has_embedded_track flags are set by parse_exif when it observes a concrete content signal (e.g. the GCamera:MotionPhoto="1" XMP attribute). When the flag is true, call MediaParser::parse_track on the same source to extract the embedded MP4’s metadata — parse_track automatically locates and parses the trailer.

use nom_exif::{MediaParser, MediaSource};
let mut parser = MediaParser::new();
let path = "PXL_20240101_120000000.MP.jpg";
let iter = parser.parse_exif(MediaSource::open(path)?)?;
if iter.has_embedded_track() {
    // Re-open: MediaSource is consumed by parse_exif.
    let track = parser.parse_track(MediaSource::open(path)?)?;
    // ...
}

Coverage: Pixel/Google Motion Photos and Samsung Galaxy Motion Photos that use the Adobe XMP Container directory format (modern Pixel including Ultra HDR, modern Galaxy JPEGs).

The pre-3.1 names (has_embedded_media) are #[deprecated] aliases that forward to the new methods.

Modules§

prelude
Convenient one-line import of the most common v3 symbols.

Structs§

AsyncMediaSource
Exif
Represents parsed Exif information, can be converted from an ExifIter like this: let exif: Exif = iter.into().
ExifEntry
Eager view into a single Exif entry. Yielded by crate::Exif::iter and designed to be cheap to copy: the value is a borrow into the parent crate::Exif.
ExifIter
An iterator version of Exif. Use ExifIterEntry as iterator items.
ExifIterEntry
Lazy yield from ExifIter. Carries a value xor error invariant — every entry holds exactly one of Self::value or Self::error.
GPSInfo
Parsed GPS information from the GPSInfo subIFD.
IfdIndex
Index of an IFD (Image File Directory) within an EXIF blob.
LatLng
Latitude or longitude expressed as degrees / minutes / seconds.
MediaParser
A MediaParser can parse media info from a MediaSource.
MediaSource
MediaSource represents a media data source that can be parsed by MediaParser.
Rational
Speed
EXIF GPS speed: unit + value paired so they cannot drift out of sync.
TrackInfo
Represents parsed track info.

Enums§

Altitude
Altitude relative to sea level.
ConvertError
Errors from conversions that are orthogonal to file parsing: parsing a tag name from a string, narrowing an IRational into a URational, building a LatLng from decimal degrees, parsing an ISO 6709 coordinate string.
EntryError
Errors that occur while decoding a single IFD entry.
EntryValue
Represent a parsed entry value.
Error
Top-level error returned by read_exif, MediaParser::parse_*, MediaSource::open, and any other public function that touches a file.
ExifDateTime
EXIF datetime value with timezone awareness preserved.
ExifTag
Defines recognized Exif tags. All tags can be parsed, no matter if it is defined here. This enum definition is just for ease of use.
LatRef
Latitude hemisphere reference.
LonRef
Longitude hemisphere reference.
MalformedKind
Categorizes the structural unit that produced a Error::Malformed.
MediaKind
Top-level classification of a media source.
Metadata
One-shot result of read_metadata: either Exif (image) or TrackInfo (video/audio). Closed enum — see spec §8.6 for why there’s no Both variant.
SpeedUnit
EXIF GPS speed reference unit (GPSSpeedRef).
TagOrCode
Either a recognized ExifTag or a raw u16 tag code that the parser did not recognize. Yielded by crate::ExifIterEntry::tag and by crate::ExifEntry::tag.
TrackInfoTag
Try to keep the tag name consistent with crate::ExifTag, and add some unique to video/audio, such as DurationMs.

Functions§

read_exif
Read EXIF metadata from a file in a single call.
read_exif_async
read_exif_from_bytes
Read EXIF metadata from an in-memory byte payload in a single call. Zero-copy: the underlying allocation is shared with the returned Exif via bytes::Bytes reference counting.
read_exif_iter
Read EXIF metadata from a file as a lazy iterator. Like read_exif but returns an ExifIter so per-entry errors can be inspected and values fetched without materializing the full Exif map.
read_exif_iter_async
read_exif_iter_from_bytes
Read EXIF metadata from an in-memory byte payload as a lazy iterator. Like read_exif_from_bytes but returns an ExifIter.
read_metadata
Read metadata from a file, dispatching by detected MediaKind: images return Metadata::Exif, video / audio containers return Metadata::Track.
read_metadata_async
read_metadata_from_bytes
Read metadata from an in-memory payload, dispatching by detected MediaKind: images return Metadata::Exif, video/audio containers return Metadata::Track.
read_track
Read track metadata from a video / audio file in a single call.
read_track_async
read_track_from_bytes
Read track metadata from an in-memory video/audio payload.

Type Aliases§

IRational
Result
Crate-wide convenience alias for std::result::Result<T, Error>.
URational