fix(deps): update rust crate nom-exif to v3#3
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
2.7.0→3.0.0Release Notes
mindeng/nom-exif (nom-exif)
v3.6.1Compare Source
Fixed
pnotormdatheaders —early consumer cameras (Nikon COOLPIX S5/P5000, Casio EX-Z50, Fujifilm
FinePix, etc., ca. 2003-2008) produce MOV files that start with a
pnot(preview) atom or a huge leading
mdatinstead offtyp/wide. Thesefiles were previously rejected as
UnsupportedFormatbecause MIMEdetection required an
ftypbox within the first 128 bytes. Now:pnotis recognized as unambiguously QuickTime;mdatfalls through toextract_moov_body_from_buf, whichalready skips arbitrarily large
mdatbodies and findsmoovat EOF.creation_timeand other track metadata now parse correctly for theselegacy files, matching ExifTool output.
#59
v3.6.0Compare Source
Changed
tokiofeature intotokioandtokio-fs— thetokiofeature now only pulls in
tokio/io-util, enabling the asyncstreaming API (
AsyncMediaSource::seekable/unseekable/from_memory,MediaParser::parse_*_async) onwasm32-unknown-unknown. Path-basedhelpers (
read_exif_async,read_track_async,read_metadata_async,AsyncMediaSource::open) moved to the newtokio-fsfeature (impliestokio). Users who previously usedfeatures = ["tokio"]withread_exif_asyncetc. should switch tofeatures = ["tokio-fs"].#53
Fixed
extract_attr_value()against byte-string literals now uses explicit&b"..."[..]coercion, fixing a compile error when a crate like rkyvis present in the dependency graph. #58
v3.5.1Compare Source
Fixed
extract_attr_value()against byte-string literals now uses explicit&b"..."[..]coercion, fixing a compile error when a crate like rkyvis present in the dependency graph. #58
v3.5.0Compare Source
Added
CameraSerialNumberEXIF tag (0xa431). Standard EXIF tag for thecamera body serial number. #56
LensSerialNumberEXIF tag (0xa435). Standard EXIF tag for thelens serial number. #57
v3.4.2Compare Source
Fixed
real-world PNG (i.e. anything beyond a stripped-down test fixture)
surfaced
malformed iso-bmff box: PNG: bad signaturefromparse_exif/parse_image_metadata. Root cause was a two-partbug in the chunk walker: (a)
ClearAndSkip(total - remaining)under-requested the skip distance by exactly
cursor + remainingbytes — semantically the caller should advance the parser's
logical position by
cursor + total, not just past the buffer'send — leaving the parser stranded mid-IDAT; (b) on the resumed call
extract_chunksalways re-validatedbuf[..8]against the PNGsignature, but the resumed buffer started mid-stream and the check
failed. Fixed both: skip request is now
cursor + total, and a newParsingState::PngPastSignaturetells the resumed call to skip thesignature check. In-memory mode (
from_memory) was unaffectedbecause the full file is buffered at once and
ClearAndSkipneverfires. Fixes #55.
Fixed (behaviour)
Error::Malformed.kindcorrectly identifies the failingstructural unit. Previously every parse failure that flowed
through
From<ParsedError> for ErrororFrom<nom::Err<...>> for Errorwas hard-coded asMalformedKind::IsoBmffBox/MalformedKind::TiffHeaderrespectively — misleading for PNG / JPEG / EBML inputs. The
MalformedKindis now threaded throughParsingError::Failed,ParsedError::Failed, andLoopAction::Failed, and surfacedunchanged at the
Errorboundary. Downstream code that(incorrectly) matched on
kind == IsoBmffBoxto catch anyparse failure will need updating; conformant code that uses a
_ =>arm (required by#[non_exhaustive]) is unaffected.Added
MalformedKind::PngChunkvariant.MalformedKindis#[non_exhaustive], so adding a variant is non-breaking.v3.4.1Compare Source
Fixed
GPSVersionID first) —
IfdIter::parse_tag_entryshort-circuitedon
tag == 0as a defensive guard against zero-padded malformedIFDs. But tag 0 is also the legitimate GPSVersionID — the
spec-defined first entry of the GPS sub-IFD. Aborting iteration
there caused the whole sub-IFD to be dropped, silently losing every
GPS field. Now gated on
!self.is_gps_subifd()so the defensesurvives in non-GPS contexts while GPSVersionID parses normally.
Fixes #50.
v3.4.0Compare Source
Changed (BREAKING for
serdefeature)SerializeforEntryValue. The previous implstringified everything via
Display, which meant numeric arraysand
Undefinedbyte blobs were truncated with...after 8 / 9elements — JSON consumers silently lost data, and rationals came
out as opaque strings like
"175/100 (1.7500)". The new shape:Text/DateTime/NaiveDateTime→ strings (formatsunchanged).
URational/IRational→{"numerator", "denominator"}objects (uses the existing
Rational<T>Serializederive).URationalArray/IRationalArray→ JSON arrays of thoseobjects, never truncated.
Undefined(Vec<u8>)→ continuous lowercase hex string(e.g.
"30323230"), never truncated.U8Array/U16Array/U32Array→ JSON arrays of numbers.Changed (BREAKING for
Display/to_string)Displayno longer truncates arrays. The 8-element ellipsis capon
Undefined,U8Array,U16Array,U32Array, and the 3-elementcap on
URationalArray/IRationalArrayare gone.to_string()now emits every element. Callers that need a length cap should
impose it at their layer (rexiftool already does this).
EntryValue::Undefinedrendering redesigned. When all bytes areprintable ASCII (
0x20..=0x7E), it now displays as a quoted string(e.g.
ExifVersion→"0220",GPSProcessingMethod→"CELLID").Otherwise it displays as a continuous lowercase hex string prefixed
with
0x(e.g.ComponentsConfiguration→0x01020300). TheUndefined[0xNN, 0xNN, ...]wrapper is gone.U8Array/U16Array/U32Arraykeep theirName[...]form.v3.3.0Compare Source
Added
read_exif("foo.png")and friends now workfor PNG files, covering standard
eXIfchunks and legacyhex-encoded EXIF in
Raw profile type exif/Raw profile type APP1tEXtchunks (ImageMagick / Photoshop pattern). Legacyhex-encoded EXIF is transparently merged into
Exif::get(...).MediaParser::parse_image_metadata— new entry point thatreturns
ImageMetadata { exif, format }, surfacing PNGtEXtchunks via
ImageFormatMetadata::Png(PngTextChunks). Singlemethod handles file/stream/memory inputs (no
_from_bytessibling). Async variant under the
tokiofeature.MediaSource::from_memory— replacesMediaSource::<()>::from_bytes.Returns
MediaSource<std::io::Empty>soparse_exif<R: Read>,parse_track<R: Read>, andparse_image_metadata<R: Read>canall accept memory-mode sources directly.
AsyncMediaSource::from_memory(tokio feature) — asynccounterpart, returns
AsyncMediaSource<tokio::io::Empty>. Thethree
parse_*_asyncmethods all accept memory-mode sourcesdirectly with the same zero-copy
bytes::Bytesstory as sync.ImageMetadata<E: ExifRepr = Exif>,ImageFormatMetadata(#[non_exhaustive]),PngTextChunks,ExifReprsealed trait.examples/rexiftoolprints PNGtEXtchunks under a-- Format Metadata --section (and_formatJSON key); add--no-formatto suppress.Deprecated
MediaSource::<()>::from_bytes— useMediaSource::from_memory.MediaParser::parse_exif_from_bytes— useparse_exifdirectlywith a
MediaSource::from_memorysource.MediaParser::parse_track_from_bytes— analogous.read_exif_from_bytes,read_exif_iter_from_bytes,read_track_from_bytes,read_metadata_from_bytes— analogous.tests in v3.x. Removal scheduled for v4.
Notes
read_image_metadatahelpers are deferred to v4alongside the planned
Metadataenum redesign (a singleread_metadatareturningMetadata::Image(ImageMetadata)).Mixed-content batch users on v3.3 still match on
MediaSource::kind()to dispatch betweenparse_image_metadataand
parse_track.iTXtandzTXtchunks are not yet supported (would requirea
flate2dependency foriTXt's optional zlib-compressedvariant). Their addition is non-breaking —
PngTextChunksisshaped to extend.
v3.2.0Compare Source
Added
AVIF (AV1 Image File Format) support. Files with
ftypmajor orcompatible brands
avif,avis, oravioare now recognized androuted through the existing HEIF Exif extractor — AVIF reuses the
ISO BMFF
meta/Exifitem layout from ISO/IEC 23008-12, so nonew parser was needed. New
MediaMimeImage::Avifvariant.AVIF detection runs before the HEIF compatible-brand check because
AVIF files commonly include
mif1/miafin their compatible-brandlist. Closes #45.
New test fixture
testdata/exif.avif(12 KB; transcoded fromtestdata/exif.heicvia ImageMagick with Exif preserved).v3.1.1Compare Source
Fixed
cargo fmtto long-line breaks introduced in 3.1.0(
src/exif/exif_exif.rs,src/jpeg.rs,src/parser.rs). Pureformatting; no functional changes. The 3.1.0 release passed every CI
job except
cargo fmt --check; 3.1.1 closes that gap. Users on3.1.0 should upgrade only if their build pipeline runs
cargo fmt --checkagainst the published source.v3.1.0Compare Source
Added
Motion Photo extraction for JPEG.
parse_exifnow content-detectsthree XMP layouts during its APP-marker walk and sets
[
Exif::has_embedded_track] / [ExifIter::has_embedded_track] totruewhen any is present:<Container:Directory>witha
Container:Itementry whoseItem:Mime="video/mp4"andItem:Semantic="MotionPhoto". Used by modern Pixel cameras(including Pixel 9 Pro XL Ultra HDR Motion Photos) and Samsung
Galaxy Motion Photos.
GCamera:MotionPhotoOffset="N"attribute (mid-era PixelPXL_*.MP.jpg).GCamera:MicroVideoOffset="N"attribute (pre-2018 PixelMVIMG_*.jpg).When the flag is
true,MediaParser::parse_trackon the samesource locates the trailing MP4 (computing the offset from the
Container directory or attribute) and returns its
TrackInfo—previously it returned
Error::TrackNotFoundfor any image MIME.Samsung's
Item:Paddingsemantics ("padding bytes between this itemand the next") are honored: for the final item the padding is
ignored (no bytes after it).
Detection is demand-driven:
parse_exifonly reads bytes past theEXIF segment when the XMP scanner reports it ran out mid-walk
(capped at 256 KB extra to bound malformed inputs). Plain JPEGs and
the common case where XMP fits inside the EXIF-fill pay zero extra
I/O.
rexiftool --no-trackflag. When the source is an image with anembedded track, the example tool now extracts the track too: under
an
-- Embedded Track --separator in text mode, or a nested_embedded_trackobject in--jsonmode. Pass--no-tracktosuppress.
New synthetic test fixture
testdata/motion_photo_pixel_synth.jpgbuilt from existing repo files via
testdata/scripts/build_motion_photo_fixture.py(no third-partycontent; legally clean).
Renamed
Exif::has_embedded_media()→Exif::has_embedded_track()ExifIter::has_embedded_media()→ExifIter::has_embedded_track()The original names implied "any embedded media" but the actual
semantics target a paired media track. Old names remain as
#[deprecated]aliases that forward to the new methods.Deprecated (no replacement)
TrackInfo::has_embedded_media()is now deprecated and alwaysreturns
false. The 3.0.0 method was reserved for "track sourcecarries another embedded track" detection (e.g. mka with both
audio and video) but the detection was never wired up. Without a
concrete use case there is no symmetric
TrackInfo::has_embedded_track()in v3.1; the deprecated methodstays as a no-op for source compatibility.
Changed
has_embedded_trackis now content-detected, not MIME-guessed.In 3.0.0 this flag was
truefor any HEIC/HEIF/RAF source whetheror not a track actually existed; in 3.1.0 it returns
trueonlywhen a real Motion Photo signal is observed in the JPEG's XMP.
Plain HEIC, plain JPEG, and RAF correctly return
false.Fixed
MediaMimeImage::Rafno longer flipshas_embedded_track()totrue— RAF's preview is a still JPEG, not a media track.v3.0.0Compare Source
Breaking release. The public API has been reshaped end-to-end. The
canonical migration guide is
docs/MIGRATION.md;internal design rationale lives in
docs/V3_API_DESIGN.md.Highlights
read_exif,read_exif_iter,read_track,read_metadata(and_asyncvariants underfeature = "tokio").MediaSource::<()>::from_bytes(impl Into<bytes::Bytes>)constructor +MediaParser::parse_exif_from_bytes/MediaParser::parse_track_from_bytesmethods + one-shotread_exif_from_bytes/read_exif_iter_from_bytes/read_track_from_bytes/read_metadata_from_byteshelpers. AcceptsVec<u8>,&'static [u8],Bytes, andBytes::from_owner(...); returnedExifIter/ sub-IFDs / CR3 CMT blocks share the user's allocation viabytes::Bytesrefcount.MediaParser(no separateAsyncMediaParser);MediaSource::open(path)replacesMediaSource::file_path(path).Error::Malformed { kind, message }/Error::UnexpectedEof/Error::UnsupportedFormatreplace the v2ParseFailed(Box<dyn Error>).Exifgainsiter()/gps_info()/errors()/has_embedded_media()/get_in()/get_by_code().ExifItergainsclone_rewound()/parse_gps()/has_embedded_media();ParsedExifEntryis renamedExifIterEntrywith private fields andinto_result()(consumesself).ExifEntry<'a>(eager view overExif::iter).IfdIndexnewtype (withMAIN/THUMBNAILconstants);TagOrCodereplacesExifTagCode.Rational<T>fields private; access vianumerator()/denominator()/to_f64().LatRef/LonRef/Altitude/Speed/SpeedUnitenums replacechar/u8GPS fields.LatLngnamed fields;LatLng::try_from_decimal_degreesreplaces panickyFrom<f64>.preludemodule for common imports.async→tokio,json_dump→serde.Migration Table (excerpt — full guide in
docs/MIGRATION.md)MediaSource::file_path(p)MediaSource::open(p)orread_exif(p)MediaSource::tcp_stream(s)MediaSource::unseekable(s)ms.has_exif()/ms.has_track()ms.kind() == MediaKind::Image/Trackparser.parse::<_,_,ExifIter>(ms)parser.parse_exif(ms)parser.parse::<_,_,TrackInfo>(ms)parser.parse_track(ms)Error::ParseFailed(Box)Error::Malformed { kind, message }(orUnexpectedEof/UnsupportedFormat)Error::IOError(e)Error::Io(e)From<&str> for Errorvalue.as_time_components()value.as_datetime()value.as_u8array()/value.to_u8array()value.as_u8_slice()ExifTag::try_from(0x010f)ExifTag::from_code(0x010f)<&str as From<ExifTag>>::from(t)t.name()ort.to_string()exif.get_gps_info()exif.gps_info() -> Option<&GPSInfo>exif.get_by_ifd_tag_code(0, 0x0110)exif.get_by_code(IfdIndex::MAIN, 0x0110)exif.get_by_ifd_tag_code(ifd, t.code())exif.get_in(IfdIndex::new(ifd), t)ParsedExifEntryExifIterEntryentry.tag()+entry.tag_code()entry.tag() -> TagOrCodeentry.take_value()/take_result()entry.into_result()iter.clone_and_rewind()iter.clone_rewound()iter.parse_gps_info()iter.parse_gps()info.get_gps_info()info.gps_info() -> Option<&GPSInfo>TrackInfoTag::ImageWidth/ImageHeightTrackInfoTag::Width/Height(Track context only;ExifTag::ImageWidth/ImageHeightunchanged)g.latitude_ref == 'N'matches!(g.latitude_ref, LatRef::North)URational(1, 2)URational::new(1, 2);.to_f64()?LatLng::from(f64)(panicky)LatLng::try_from_decimal_degrees(f64)?features = ["async"]features = ["tokio"]features = ["json_dump"]features = ["serde"]AsyncMediaParserMediaParser(single type, async methods feature-gated)AsyncMediaSource::file_path(p).awaitAsyncMediaSource::open(p).awaitparser.parse(ms).await(async)parser.parse_exif_async(ms).await/parser.parse_track_async(ms).awaitRemoved
MediaSource::tcp_stream(was an alias forunseekable).MediaSource::has_exif/has_track(usekind()).Error::ParseFailed(Box<dyn Error>),From<&str> for Error,From<String> for Error.AsyncMediaParser(merged intoMediaParser).EntryValue::as_time_components/as_u8array/to_u8array.ParsedExifEntry::take_result/take_value/tag_code/get_result/get_value/has_value.ExifIter::clone_and_rewind/parse_gps_info.Exif::get_by_ifd_tag_code/get_gps_info(Result-wrapped).TrackInfo::get_gps_info,From<BTreeMap<TrackInfoTag, EntryValue>> for TrackInfo,IntoIterator for TrackInfo,From<TrackInfoTag> for &str,TryFrom<&str> for TrackInfoTag,UnknownTrackInfoTagerror type.LatLng::from<f64>,URational(u32, u32)tuple-struct field access (nownumerator()/denominator()).Internal (no API impact)
BufParser/AsyncBufParsertraits (P2).PartialVec/AssociatedInputdeleted; all internal byte-views unified onbytes::Bytes(P4.5).Option<Bytes>cache +Bytes::try_into_mutrecycle;MediaParser::new()is now zero-alloc (P4.5).BufferedParserStategains a memory mode (no public surface change); streaming parse path is untouched (P7).v2.8.0Compare Source
Added
Changed
unreachable!()panics in HEIF/TIFF state machines with proper error returnspartial_vec.rsLoadvsBufParsermigration path in source commentsTryFromBytesimplementations, reducing repetitive boilerplateConfiguration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.