Commit Graph
49 Commits
Author SHA1 Message Date
NetterSilverandClaude Haiku 5.5 a3d00301cf Write ISOSpeed extension tag for ISO above 65534 in write_exif
Found while testing crates/meta/src/exif.rs:455 (write_exif)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 05:16:03 +00:00
Brandon Thomas dee8358c38 Merge PR #1838: Drop out-of-range GPS coordinates read from XMP 2026-10-18 09:20:40 -04:00
Brandon Thomas 70100a34c5 Merge PR #2144: Strip XML 1.0-forbidden characters from XMP sidecar output 2026-10-18 09:20:19 -04:00
NetterSilverandClaude Haiku 5.5 e0c02d5e89 Strip XML 1.0-forbidden characters from XMP sidecar output
Fixes #2131

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 13:12:52 +02:00
NetterSilverandClaude Haiku 5.5 0a9675c6d9 Ignore zero or negative ISO when importing XMP
Found while testing crates/meta/src/xmp.rs:509-512

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 14:54:06 +00:00
Brandon ThomasandClaude Opus 5.5 b5733c7649 Merge PR #1487
Resolved against rb-base-36: Scanned keeps the base's rewrite flag next to magic and tag; Exif keeps the Panasonic lens fallback; locale catalogs merged (one duplicate key dropped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:42:11 -04:00
NetterSilverandClaude Haiku 5.5 48d69bfae5 Drop out-of-range GPS coordinates read from XMP
Found while testing crates/meta/src/xmp.rs:364 (parse_gps_coord, used at xmp.rs:539-544)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 05:21:00 +02:00
Brandon Thomas bde5385a6f Merge PR #1590
# Conflicts:
#	crates/meta/src/exif.rs
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-14 22:32:44 -04:00
Brandon Thomas 75e0a6dd2a Merge PR #1835 2026-10-14 22:32:07 -04:00
MyrarcandOpenAI Codex cebaade144 CI-RUST195: keep strict Clippy clean on Rust 1.95
Move nested conditions into match guards and simplify equivalent Boolean
expressions without changing validation or short-circuit behavior. Keep
the explicit permitted Testkit dev-dependency arm in the layer checker.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-10-15 08:50:22 +07:00
Gert Pellin fbe3810aa8 Metadata: list the Panasonic lens name in All Metadata (#1671)
photo.allMetadata listed no lens for a RW2: Panasonic writes no Exif
LensModel, and the maker note that names the lens is in the Exif of
the embedded JpgFromRaw. List that maker note tag (LensType, 0x0051)
as a row of a Panasonic group, the same name photo.inspect shows, for
a RW2/RWL and for a JPEG with the note in its own Exif.

Checked on the CC0 sample DMC-G80 P1000403.RW2: Panasonic / Lens Type
= SIGMA 60mm F2.8 DN.
2026-10-14 17:42:09 +02:00
Michael Anderson 1acbf88661 LR-META-INFO: Show the lens for Nikon DSLR raws
They don't write a lens name, so read the range from the maker note's Lens tag.
2026-10-14 07:32:46 -05:00
Gert Pellin f9c97ab57b Metadata: read the Panasonic lens name from maker note tag 0x0051 (#1671)
Panasonic writes no Exif LensModel. The lens name is in its maker note
(LensType, 0x0051), and a RW2 or RWL keeps that maker note only in the
Exif of its embedded JpgFromRaw (IFD0 0x002E), not in the raw's own Exif
IFD. When LensModel is absent, read it from the maker note, and for a
raw from the JpgFromRaw's Exif.

Checked on the CC0 samples DC-GX9 gx9_1_1.RW2 (LUMIX G 25/F1.7) and
DC-S5 P1047510.RW2 (LUMIX S 85/F1.8), also through the sparse header
plan an import uses.
2026-10-14 11:09:25 +02:00
Jason Baldwin fdad5a4ad4 LR-VIEW-FOCUSPOINT: read focus points for photos already in the library, header-only in the background (#1480)
Photos imported before focus points were read got one only through Reload from Disk, which
hashes whole files on the UI thread. Now:

- lightcraft_meta::focus::read_header reads only what the decoder looks at: IFD0 (Make,
  Model), the Exif IFD, the maker note's IFD and the focus tags' values (a JPEG: its segments
  up to the Exif one), walked round by round and decoded with the whole-file code from a
  buffer of the file's length holding just those ranges. Bounded rounds, bytes (2 MB) and
  size (1 GB). One 32 KB read per α1 / A7S III ARW; on 109 real files (83 with a point)
  it gives the whole-file read's point for every one.
- A background job (crates/engine/src/focus_scan.rs) reads photos with no point from a
  supported body (by the stored camera; nothing else is opened), ARW or JPEG, one at a
  time in path order, with a "Reading focus points" activity row (Cancel::Flag). The UI's
  per-frame focus.pump gives it the face scan's pace (paused while dragging or typing) and
  starts it once per library opening. Commits every 200 photos or 3 s as system ops (no
  undo step, no sidecar write), only meta.focus, only on photos that still have none at the
  same path. "Looked, none" goes to focus-scanned.bin beside the library, headed by the
  decoder's tag so a decoder knowing more bodies starts afresh; unreadable files are retried
  at the next opening.
- photo.readFocusPoints {ids?, wait?} (Photo > Read Focus Points) runs it on demand.

Measured cold on a 5400 rpm USB drive: 200 α1 / A7S III ARWs in 1.9 s (~100 photos/s,
32 KB each), so 58,796 raws take about 10 minutes instead of re-reading 2.25 TB.
2026-10-13 16:06:06 +02:00
Jason Baldwin ac84cd31ee LR-VIEW-FOCUSPOINT: show the camera's focus point (Sony) and zoom to it (#1480)
Read the autofocus point from Sony maker notes (FocusLocation 0x2027, FocusFrameSize
0x2037, FocusMode 0x201b, AFAreaModeSetting 0x201c, AFTracking 0x2021 and the area mode
used from the enciphered 0x9402 block), for the ILCE-1 and ILCE-7SM3, whose layout was
checked against ExifTool's output on 333 real ARWs. Manual focus, centre-only Multi
reports and unchecked bodies give no point. The box is stored on the upright photo as
Meta.focus (omitted when unknown; no catalog format change), filled at import and by
Reload from Disk.

View > Show Focus Point (Alt+F) draws it in Detail, Compare and Survey through rotation
and crop; View > Zoom to Focus Point (on by default) makes Toggle Zoom centre on it; the
Info panel shows "AF-C · Wide · Animal Eye Tracking". photo.inspect returns meta.focus.
2026-10-13 13:14:24 +02:00
bflatastic d752076339 Batch 32: fixes for PRs merged together (#984 leap-year lint, #1344 ColorData field, #1187 preset panel builds) 2026-10-13 11:11:02 +07:00
bflatastic b297049e52 Merge PR #984 2026-10-13 11:02:37 +07:00
Nigel Ihza Firdausy e4f92df78c fix(meta): reject incomplete and mismatched GPX documents 2026-10-11 21:17:17 +07:00
Nigel Ihza Firdausy a77b0cc472 fix(meta): reject impossible Gregorian capture dates 2026-10-11 21:14:52 +07:00
Claude 7afbc3ecb3 Merge PR #687 2026-10-11 11:47:28 +00:00
Claude 63059a4303 Merge PR #961 2026-10-11 11:43:07 +00:00
Claude 69b90ee7c4 LR-META-EXIF-FULL: tags.rs back to LF line endings (#831 mixed in CRLF)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKWB9TCnvzJHV6xMLAj2J4
2026-10-11 11:40:41 +00:00
ingolfteetzandClaude Opus 5.5 bbd973f321 LRC-LIB-CATALOG-IMPORT: describe raws from their headers without reading pixel data
`lightcraft_raw::sparse::header_plan` says which byte ranges of a raw file the header
probe (`probe_info`, `lightcraft_meta::extract`) reads, given a buffer of the file's length
in which only some ranges are loaded: everything but the bulk sample data (large TIFF
strips/tiles minus the first chunk's coding headers, a CR3's image tracks minus the raw
track's CRX headers and QP maps, a RAF's CFA strip, an RW2's raw data). `preview_plan`
also reads what `embedded_preview` needs, for raws shown from their preview. NEF, ORF and
PEF (their header probe looks at samples) and anything else are read whole.

The corpus test checks, for every raw.pixls.us sample the plan describes, that probing the
partly loaded buffer gives exactly what the whole file gives, with the skipped bytes zero and
again 0xFF: CR3 2.7 %, DNG 2.4 %, CR2 3 %, RAF 6 %, RW2 7 %, ARW 8 % of their bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:25:57 +02:00
radialmonster 8f3f168802 LR-META-EXIF-FULL: raw sensor IFD Compression 7 reads Lossless JPEG (#830) 2026-10-10 17:59:11 -04:00
radialmonster 7ce13cfd07 LR-META-EXIF-FULL: All Metadata shows the raw image's Compression, NEFCompression in words (#830) 2026-10-10 17:51:27 -04:00
Brandon ThomasandClaude Opus 5.5 964d9338ba Progress docs: target-app parity, RAW coverage vs Adobe, gaps, alpha gate, readiness by audience (#788)
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, model-by-model RAW coverage against Adobe's camera list (docs/raw/), and format, hardware, UI and localization parity docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:25:15 -04:00
Ikki NishiharaandClaude Sonnet 5.5 87cd873d78 XMP merge: keep refusing repeated attributes, in linear time
quick-xml's own duplicate-attribute check is quadratic. Switch it off and
refuse a repeated name with a per-element set instead, so scan keeps its
behaviour on malformed packets without the quadratic cost.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 17:35:20 +09:00
Иван Лапочкин f96f732baa M11.1: add CR3 decoding
Decode lossless CRX and version 0x100/0x200 C-RAW in portable Rust,
including sensor geometry, timed white balance and black/white levels.
Verify all sensor samples against six independent M50/R100/R8 references.

Any CR3 decode error falls back to the embedded JPEG, as CR3 files did
before this decoder. The full sensor buffer is allocated only after the
first plane decodes, and plane buffers grow row by row. Tile planes
decode in parallel with a windowed bit reader (24 MP: 424 -> 89 ms
lossless, 519 -> 138 ms C-RAW on an M4).

Add guarded CR3 camera-JPEG colour fitting with independent framing
validation, relative white balance and cache invalidation.

Validation: cargo xtask ci.
2026-10-08 22:22:13 +03:00
Brandon ThomasandClaude Opus 5.5 3793e8fc33 LR-LIB-PEOPLE: clip XMP face regions to the photo, drop off-photo ones, read Rotation π
A region parsed from mwg-rs:Regions is now intersected with the 0..1 frame and dropped when it
misses the photo, so a hostile or stale sidecar (x=1e5, a 1e5-wide box) can't park a box far
outside the image. Lightroom's mwg-rs:Rotation of ±π (Exif orientation 3) is mapped to the upright
frame like the quarter turns; mirrored orientations can't be expressed in MWG and are taken as
written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:12:49 -04:00
Brandon Thomas 1b22a0e53b Merge origin/main into land-170 2026-10-07 06:09:24 -04:00
Maurice Rogers 13a3eff2e8 LR-IMP-FORMATS: CR3 full-size preview and metadata from the ISO-BMFF container
CR3 files imported as preview-only with the 1620x1080 PRVW JPEG and no metadata
(no camera, capture time, exposure, lens or GPS): nothing read the container.

- crates/meta/src/cr3.rs: bounded ISO base media box parser for CR3 (Canon uuid
  box with CMT1-4 and THMB, tracks with their sample entries, CMP1 coding header
  and sample location, XMP uuid box). Every size/offset checked; depth and box
  count bounded.
- Metadata: CMT1 (IFD0), CMT2 (Exif) and CMT4 (GPS) merged into one TIFF Exif
  block, so CR3 reads like any TIFF-based raw; XMP from its uuid box.
- Preview: the full-size JPEG track (6960x4640 on an EOS R6 Mark III) before
  PRVW/THMB; imports report the full image size.
- Tests: synthetic CR3 (boxes, tracks, merged Exif), truncation/corruption sweep,
  JPEG track preferred over PRVW with fallback.

Raw (CRX) data is still not decoded; CR3 stays preview-only.
2026-10-06 20:00:48 -06:00
Daniel VoshartandClaude Sonnet 5.5 9715c90413 Meta: map Lightroom's quarter-turn region Rotation to the upright frame
Lightroom Classic stores the box of a photo with Exif orientation 6 / 8 in
the sensor's own frame and records the orientation as mwg-rs:Rotation
(-pi/2 for 6, +pi/2 for 8, 0 for 1) while AppliedToDimensions names the
upright size. Ignoring Rotation put every portrait photo's face box in the
wrong place. Convert such regions into the upright frame, with a synthetic
regression test for -pi/2, +pi/2 and 0.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 19:42:32 -04:00
Daniel VoshartandClaude Sonnet 5 f29436a1f6 Meta: read MWG-RS face/pet/focus regions from XMP (read-only)
Adds Metadata::regions: Vec<Region>, populated by parse_xmp from mwg-rs:Regions
(MWG Region Guidelines v2.0) — the format Lightroom, digiKam and Picasa write
for face/pet/focus/barcode regions. Read-only: LightCraft does not write
regions yet (blocked on #92, which would otherwise clobber existing sidecars).

- Canonicalises the mwg-rs/stArea/stDim namespaces so any prefix a writer
  picks resolves consistently, reusing the existing generic struct/array XMP
  machinery (handles both the element and attribute encodings transparently).
- Area center-coordinates are converted to lightcraft_geom::Rect via
  Rect::from_center. Normalized units (the default, and the only unit we've
  seen in practice) need no AppliedToDimensions cross-reference; the rare
  pixel-unit region is converted when AppliedToDimensions is present, and
  dropped (not stored as a nonsense fraction) when it isn't.
- Hostile/malformed regions (missing Area, NaN/absurd/zero/negative extents)
  are skipped individually rather than failing the whole list or panicking.
- regions merges like keywords in fill_missing/overlay_user_fields, since it
  only ever comes from XMP today.

Not included: nothing yet reads Metadata::regions (no catalog field, no UI,
no command) — this is plumbing for a later PR, with no user-visible effect
and no docs/parity.md row to update.

cargo xtask ci passes (fmt, clippy -D warnings, test, parity, layers, assets,
wasm).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-06 19:42:31 -04:00
Brandon ThomasandClaude Opus 5.5 882a059fac Issue #92: XMP: merge into an existing sidecar instead of replacing it
Saving (Cmd+S or auto-write) now merges LightCraft's properties into an
existing sidecar (lightcraft_meta::merge_xmp): owned properties (rating,
label, dc/IPTC/rights fields, lc:*) are replaced or removed, capture time
and GPS only when LightCraft has a value; everything else (crs:,
xmpMM:History, unknown namespaces, packet wrapper) is kept byte for byte.
The result is re-parsed and checked before it is written (temp + fsync +
rename). A sidecar that isn't valid XMP is copied to .xmp.bak-<time>
(never overwriting) before it is replaced; one that can't be read at all
is left alone and the save fails.

Shared stems: when several catalogued files map to one stem sidecar
(IMG.CR3 + IMG.JPG), it belongs to the raw (else the first by name) and
the others write and read <file>.xmp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:08:18 -04:00
storybored379andOpenAI Codex 35e38661a7 Metadata: gracefully reject invalid Unicode timezone offsets
Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-10-04 21:11:55 -07:00
Brandon Thomas f7361a7d01 Merge main into feat/gpx-tracklog
# Conflicts:
#	docs/parity.md
#	docs/whats-new.md
2026-10-04 15:31:45 -04:00
storybored379andClaude Opus 5.5 1901a756bb LRC-MAP-TRACKLOG: Auto-Tag from Tracklog — GPS from a GPX track log by capture time
GPX 1.0/1.1 reader in lightcraft-meta (timed track points per segment; interpolation only within a
segment, nearest point within maxGap otherwise). Engine command photo.autoTagTracklog (path or gpx
text, camera time-zone offset, maxGap, replace, dryRun; one undo step) and Photo ▸ Auto-Tag from
Tracklog… with a time-zone prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 10:52:12 -07:00
storybored379andClaude Opus 5.5 18153682f2 LRC-LIB-METADATA: Copyright Status, Rights Usage Terms and Copyright Info URL
Catalog Meta gets copyright_status (unknown / copyrighted / publicDomain), usage_terms and
copyright_url, read and written as XMP Rights Management fields (xmpRights:Marked, UsageTerms,
WebStatement) on import, sidecars and exports (kept by "copyright only"). photo.setMeta,
copy/paste metadata, metadata presets, a Copyright Status smart-album rule and the Info panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:01:00 -07:00
Brandon ThomasandClaude Opus 5.5 def15b0346 LR-META-EXIF-FULL: All Metadata — every EXIF / GPS / XMP field of the file
lightcraft-meta gains tags.rs: every tag of IFD0 and the EXIF, GPS and interoperability IFDs
as (group, name, value) rows, named per the public TIFF / EXIF / DNG specifications, with
common values spelled out (exposure as 1/250 s, f/2.8, 35 mm, orientation, metering, flash,
compression…) and blobs summarised. photo.allMetadata adds the XMP fields (sidecar, else the
file's packet). Info ▸ All Metadata… opens a searchable dialog grouped by TIFF / EXIF / GPS /
XMP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:20:43 -04:00
Brandon ThomasandClaude Opus 5.5 b7d497d049 LR-IMP-PROFILES: carry masks over from presets, .lrtemplate and XMP sidecars
Local corrections stored as crs: structures (MaskGroupBasedCorrections and the older
gradient / circular gradient / paint containers) become our masks: linear and radial
gradients, brushes (dab runs → strokes), Subject / Sky, luminance and depth ranges, with
add / subtract / intersect and invert, and all local sliders. lightcraft-meta's XmpData gains
`values`, a structured view of every property (arrays of structs survive); .lrtemplate Lua
tables convert into the same shape.
Applying a preset adds its masks to the photo's own (once; Amount scales them); sidecar masks
replace them and radial masks are fitted to the photo's aspect. Unsupported components
(colour range, other AI selections) are reported as "Mask: <kind>".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:31:40 -04:00
Brandon ThomasandClaude Opus 5.5 096aefe698 LR-META-INFO: Info panel in Lightroom's layout with accessibility and place fields
- Metadata gains alt text, extended description, sublocation, city, state/province, country:
  catalog, photo.setMeta, copy/paste metadata, XMP read/write (Iptc4xmpCore AltText /
  ExtDescrAccessibility / Location, photoshop City / State / Country), sidecars and export
  (place fields dropped with "remove location").
- Info panel: camera card (camera, lens, size · file size, format badge, focal length,
  shutter, aperture, ISO), then title, caption, alt text, extended description, copyright,
  creator, file name (rename), file path (reveal), captured (edit), place fields, GPS.
- Text fields keep what is typed across frames and save on focus loss (they were rebound to
  the stored value every frame). New pencil icon (drawn in code); dates::display_time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 07:58:00 -04:00
Brandon Thomas 4dd57efcac Merge branch 'worktree-agent-af78b5603e6882a3f' 2026-10-01 01:06:29 -04:00
Brandon ThomasandClaude Opus 5.5 b6c9f66857 M10.8: keep lc:settings JSON readable in sidecars (escape only <, >, & in element content)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:04:00 -04:00
Brandon ThomasandClaude Opus 5.5 8af27c11b1 M10.8: XMP sidecars — save/read metadata + develop settings, auto-write, crs: interchange
- crates/engine/src/sidecar.rs: <stem>.xmp (default) or <file>.xmp next to originals with rating,
  label, title, caption, copyright, creator, keywords, capture time/GPS, pick flag + full develop
  settings in lc:settings; atomic writes; read on import (sidecar wins for metadata, edits restored)
  and via photo.readMetadataFromFile (one undo step); raw/DNG embedded XMP used without a sidecar.
- Commands: photo.saveMetadataToFile (Cmd+S), photo.readMetadataFromFile, library.xmpPreferences
  {autoWrite, naming}, library.toggleAutoWriteXmp; prefs persisted in the library's prefs.json.
  Auto-write rewrites sidecars after each committed change (not mid-drag; undo/redo too).
- crates/engine/src/crs.rs: crs: develop fields (PV2012 light, WB abs/incremental, presence, HSL,
  B&W mix, parametric + point curves, colour grading, sharpening, NR, vignette, grain, optics,
  geometry, crop) → partial settings; documented in docs/xmp-interop.md.
- meta: write_xmp_lc for extra lc: properties; crs namespace canonicalised on read (never written).
- Tests: packet round trip, crs mapping with hand-written snippets, save → delete library →
  re-import restores edits, auto-write + prefs persistence, foreign sidecar, DNG-embedded XMP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:36:19 -04:00
Brandon ThomasandClaude Opus 5.5 daa32c3e4a Merge main into raw formats branch (nrw/raf/orf/rw2/pef/cr3 in the open dialog, nrw import)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:31:23 -04:00
Brandon ThomasandClaude Opus 5.5 c6954d5bd9 M10.5: export metadata policy (all / all except camera / copyright / none, remove location) with EXIF + XMP embedding
New lightcraft_meta::write_exif (IFD0 + Exif + GPS IFDs; round-trip tested).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:03:38 -04:00
Brandon ThomasandClaude Opus 5.5 f7b502309c M11.2: Fujifilm RAF decoding (uncompressed Bayer and X-Trans)
RAF header/record parsing, raw IFD (0xf000) with 16-bit, 12-bit LSB and
32-bit-word MSB packings found by black-box analysis of CC0 samples,
X-Trans layout (reversed record, anchored at 0,0), crop, black levels,
WB_GRB levels, metadata and preview from the embedded JPEG. Compressed
RAF reports Unsupported. Colour uses the documented neutral fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:44:09 -04:00
Brandon ThomasandClaude Opus 5.5 cbe9d8989a M3.1: lightcraft-meta EXIF/XMP/IPTC
Metadata model; EXIF from TIFF/raw, JPEG APP1, PNG eXIf, WebP EXIF; XMP
read (namespace-canonicalised, arrays, structs) and write (dc/xmp/
photoshop/exif/exifEX/tiff/lr + lc:settings JSON); IPTC-IIM record 2;
container walkers for JPEG (incl. ICC and extended XMP), PNG, WebP.
Adds quick-xml and miniz_oxide to workspace deps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:08:42 -04:00
Brandon ThomasandClaude Opus 5.5 44d97a4104 M3.1: lightcraft-tiff reader/writer
Classic + BigTIFF, both byte orders, all field types, SubIFDs and Exif/GPS/
Interop pointer IFDs, strips/tiles layout, maker-note offset-base helpers,
IFD writer; hardened against malformed input (proptests). Placeholder
manifests for lightcraft-meta and lightcraft-raw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:00:48 -04:00