lightcraft-meta at 5b61ce1e, as one crate with a module per format: exif (read, write, maker-note lens, focus point, tag listing), iptc, xmp (parse, write, merge), gpx, and the JPEG, PNG, WebP, TIFF, RAF and CR3 containers. They share Metadata, DateTime, Gps and Orientation. Changed in the move: - TIFF comes from craft-tiff; Point, Rect and Orientation are the crate's own. - The app namespace is a parameter: parse_xmp_with, write_xmp_with and MergeRules::namespaces take it, and XmpData no longer has lc_settings. - The HEIF, PSD and MRW readers stay out, since craft-heif, craft-psd and craft-raw read those containers; from_embedded takes the blocks they find.
craft-metadata
Photo metadata: EXIF, IPTC-IIM, XMP packets and GPX track logs, the blocks that carry them in image
files, and one Metadata model they all read into. From LightCraft (lightcraft-meta). TIFF
structure comes from craft-tiff.
One module per format; they share Metadata, DateTime, Gps and Orientation, which is why they
are one crate.
| Function | Purpose |
|---|---|
read_exif(&[u8]) -> Metadata |
A TIFF-structured Exif block: a whole TIFF/DNG/raw file, or a JPEG APP1 payload with or without Exif\0\0. try_read_exif reports header errors, try_read_exif_with takes craft_tiff::ParseOptions. |
from_tiff(&Tiff) -> Metadata |
The same from an already parsed stream. |
write_exif(&Metadata) -> Vec<u8> |
An Exif block for an exported file. |
tags::tag_rows, tags::file_tag_rows |
Every tag with its name and value as text, maker notes included. |
focus::read, focus::read_header |
Where the camera focused, from the maker note (Sony), on the upright photo. read_header reads only the first kilobytes of a file through a callback. |
parse_iptc(&[u8]) -> Metadata |
IIM record 2: title (2:5), keywords (2:25), by-line (2:80), copyright (2:116), caption (2:120), date and time created (2:55, 2:60). |
parse_xmp(&str) -> Result<XmpData> |
Metadata, every property (prefix:name, structs flattened as a:b/c:d) and the structured values. parse_xmp_with also canonicalises the caller's own namespaces. |
write_xmp(&Metadata) -> String |
A complete <?xpacket?> packet. write_xmp_with sets the toolkit name and adds simple properties in the caller's namespace. |
merge_xmp(existing, fresh, MergeRules) |
Updates a packet another program wrote: owned properties are replaced, everything else stays byte for byte. |
parse_gpx(&str) -> Result<Tracklog> |
GPX track points; Tracklog::locate gives the position at a capture time. |
embedded(&[u8]) -> Embedded |
Sniffs JPEG, PNG, WebP, TIFF-based files, Fujifilm RAF and Canon CR3 and returns the Exif, XMP (and extended XMP), ICC and IPTC blocks. jpeg_segments, png_chunks, webp_chunks are the walkers. |
cr3::parse_cr3 |
The Canon CR3 container: CMT1…CMT4, the XMP uuid box, the thumbnail, the tracks. |
extract(&[u8]) -> Metadata |
All of it for a whole file. Precedence: EXIF, then IPTC fills gaps, then XMP overrides the user fields (rating, label, title, caption, artist, copyright, keywords, GPS) and fills the rest. from_embedded does the same for blocks already located. |
HEIF, PSD and MRW files are read by craft-heif, craft-psd and craft-raw. Put the blocks they
return into an Embedded and call from_embedded.
Capture time
EXIF candidates are tried in order: DateTimeOriginal, DateTimeDigitized, then IFD0 DateTime. A clock
with more than three colon-separated components is rejected as a whole, so the next candidate or the
XMP supplies the time. ISO 8601 times in XMP need a complete clock. Calendar checks go through
chrono. Invalid GPX point times count as untimed.
XMP namespaces
Written: dc, xmp, xmpRights, photoshop, exif, exifEX, tiff, aux, lr,
Iptc4xmpCore, and the one namespace the caller passes. Read as well: crs, mwg-rs regions
(stArea, stDim). Reading canonicalises prefixes by namespace URI and handles attribute and element
forms, rdf:Seq/Bag/Alt (x-default first), rdf:parseType="Resource" and nested-description
structs, predefined and numeric entities.
A foreign namespace that uses a recognised prefix cannot supply recognised properties. Its keys are
Q{hex-encoded namespace URI}local. Merging keeps the original foreign XML.
Limits
XMP: 64 levels, 200 000 nodes, 1 MiB of flattened keys and 8 MiB of opaque names per packet
(XmpError::TooComplex). GPX: 64 levels, 5 000 000 points. CR3: 4096 boxes. JPEG ICC is returned only when its APP2 chunks form a
complete, consistent, uniquely numbered sequence. TIFF limits are craft-tiff's. No input panics:
proptests feed random bytes to every container walker and random text to the XMP parser, and a sample
JPEG is cut at every byte.
Sources
CIPA DC-008 (Exif 2.32), TIFF 6.0, Adobe DNG 1.7 (tag numbers), ISO 16684-1 and the Adobe XMP
Specification Parts 1 to 3, IPTC-IIM 4.2 and the IPTC Photo Metadata Standard, the MWG Region
Guidelines, ITU-T T.81 (JPEG markers), ICC.1 (APP2 embedding), the PNG Specification 3rd ed. (eXIf,
iTXt), the WebP RIFF container specification, ISO/IEC 14496-12 (box structure), GPX 1.1. XML parsing:
quick-xml (MIT). No third-party metadata code was consulted.