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 / PNG / TIFF.
  • Motion Photo support — Pixel and Samsung Motion Photos (JPEG with an embedded MP4) are detected automatically; parse_track extracts the embedded video’s track metadata.
  • 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.

§Motion Photos (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).

§Reading from in-memory bytes

When the payload is already in RAM (WASM, mobile, HTTP proxy, decoded response body), use MediaSource::from_memory 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::{MediaSource, MediaParser, ExifTag};

let raw = std::fs::read("./testdata/exif.jpg")?;
let ms = MediaSource::from_memory(raw)?;
let mut parser = MediaParser::new();
let iter = parser.parse_exif(ms)?;
let exif: nom_exif::Exif = iter.into();
assert_eq!(exif.get(ExifTag::Make).and_then(|v| v.as_str()), Some("vivo"));

§Image metadata beyond EXIF

Some image formats carry metadata that does not fit the EXIF / IFD model. PNG’s tEXt chunks are the headline example: arbitrary Latin-1 key/value pairs (Title, Author, Comment, …). For PNG-aware (or future GIF / WebP / JXL extras-aware) callers, use MediaParser::parse_image_metadata:

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

let mut parser = MediaParser::new();
let ms = MediaSource::open("./testdata/exif.png")?;
let img = parser.parse_image_metadata(ms)?;

if let Some(ImageFormatMetadata::Png(text_chunks)) = img.format {
    let _title = text_chunks.get("Title");
}

Returns ImageMetadata<ExifIter> (lazy form); convert to the eager ImageMetadata<Exif> via .into() if needed. Top-level read_image_metadata helpers are deferred to v4 alongside the Metadata enum redesign.

§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.

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.
ImageMetadata
Structured image-metadata view: EXIF (if any) plus format-specific metadata (if any).
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.
PngTextChunks
PNG tEXt chunks, decoded as Latin-1 (key, value) pairs in file order.
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.
ImageFormatMetadata
Format-specific image metadata. One variant per format that has metadata not expressible as EXIF tags.
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.

Traits§

ExifRepr
Marker trait for the two valid “EXIF representations” held by ImageMetadata: Exif (eager) and ExifIter (lazy). Sealed — users cannot add their own implementations.

Functions§

read_exif
Read EXIF metadata from a file in a single call.
read_exif_async
read_exif_from_bytesDeprecated
Deprecated since v3.3.0: use read_exif with MediaSource::from_memory directly.
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_bytesDeprecated
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_bytesDeprecated
read_track
Read track metadata from a video / audio file in a single call.
read_track_async
read_track_from_bytesDeprecated

Type Aliases§

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