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 —
MediaParserdispatches 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_trackextracts 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-iterResult), 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-fuzzagainst 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
- One-shot helpers:
read_exif,read_exif_iter,read_track,read_metadata. - Reusable parser:
MediaParser+MediaSource(orAsyncMediaSource)MediaKind. UseMediaSource::from_memoryfor in-RAM bytes.
- Image metadata:
Exif(eager, get-by-tag) orExifIter(lazy iterator with per-entry errors). Convert:let exif: Exif = iter.into();. - Track metadata:
TrackInfo(audio/video container metadata). - Discriminated union:
Metadatareturned byread_metadata. - Errors:
Errorfor parse-level,EntryErrorfor per-entry IFD errors,ConvertErrorfor type-conversion peer errors. - Convenience:
preludere-exports the symbols you most often need.
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— derivesSerialize/Deserializeon the public types.
Modules§
- prelude
- Convenient one-line import of the most common v3 symbols.
Structs§
- Async
Media Source - Exif
- Represents parsed Exif information, can be converted from an
ExifIterlike this:let exif: Exif = iter.into(). - Exif
Entry - Eager view into a single Exif entry. Yielded by
crate::Exif::iterand designed to be cheap to copy: thevalueis a borrow into the parentcrate::Exif. - Exif
Iter - An iterator version of
Exif. UseExifIterEntryas iterator items. - Exif
Iter Entry - Lazy yield from
ExifIter. Carries a value xor error invariant — every entry holds exactly one ofSelf::valueorSelf::error. - GPSInfo
- Parsed GPS information from the GPSInfo subIFD.
- IfdIndex
- Index of an IFD (Image File Directory) within an EXIF blob.
- Image
Metadata - Structured image-metadata view: EXIF (if any) plus format-specific metadata (if any).
- LatLng
- Latitude or longitude expressed as degrees / minutes / seconds.
- Media
Parser - A
MediaParsercan parse media info from aMediaSource. - Media
Source MediaSourcerepresents a media data source that can be parsed byMediaParser.- PngText
Chunks - PNG
tEXtchunks, 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.
- Track
Info - Represents parsed track info.
Enums§
- Altitude
- Altitude relative to sea level.
- Convert
Error - Errors from conversions that are orthogonal to file parsing: parsing a tag
name from a string, narrowing an
IRationalinto aURational, building aLatLngfrom decimal degrees, parsing an ISO 6709 coordinate string. - Entry
Error - Errors that occur while decoding a single IFD entry.
- Entry
Value - 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. - Exif
Date Time - 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.
- Image
Format Metadata - Format-specific image metadata. One variant per format that has metadata not expressible as EXIF tags.
- LatRef
- Latitude hemisphere reference.
- LonRef
- Longitude hemisphere reference.
- Malformed
Kind - Categorizes the structural unit that produced a
Error::Malformed. - Media
Kind - 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 noBothvariant. - Speed
Unit - EXIF GPS speed reference unit (
GPSSpeedRef). - TagOr
Code - Either a recognized
ExifTagor a rawu16tag code that the parser did not recognize. Yielded bycrate::ExifIterEntry::tagand bycrate::ExifEntry::tag. - Track
Info Tag - Try to keep the tag name consistent with
crate::ExifTag, and add some unique to video/audio, such asDurationMs.
Traits§
- Exif
Repr - Marker trait for the two valid “EXIF representations” held by
ImageMetadata:Exif(eager) andExifIter(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_ bytes Deprecated - Deprecated since v3.3.0: use
read_exifwithMediaSource::from_memorydirectly. - read_
exif_ iter - Read EXIF metadata from a file as a lazy iterator. Like
read_exifbut returns anExifIterso per-entry errors can be inspected and values fetched without materializing the fullExifmap. - read_
exif_ iter_ async - read_
exif_ iter_ from_ bytes Deprecated - read_
metadata - Read metadata from a file, dispatching by detected
MediaKind: images returnMetadata::Exif, video / audio containers returnMetadata::Track. - read_
metadata_ async - read_
metadata_ from_ bytes Deprecated - read_
track - Read track metadata from a video / audio file in a single call.
- read_
track_ async - read_
track_ from_ bytes Deprecated