`embedded_preview_srgb` (the loupe stand-in and the grid thumbnail of an unedited raw) decoded the
largest embedded JPEG whatever the size asked for: a 512 px thumbnail of a Sony A7R VI ARW decoded
its 9984 x 6656 JPEG (5.6 MB) although the file holds a 1616 x 1080 one (0.3 MB).
`lightcraft_raw::embedded_preview_covering(bytes, min_edge)` returns the smallest of a TIFF-based
raw's JPEGs whose long edge is at least `min_edge` and that is a copy of the largest one: aspect
ratio within 1 % (not a letterboxed thumbnail of another shape) and the same number of components
(not the grey semantic masks of an iPhone ProRAW DNG); else the largest, as `embedded_preview`.
The colour-space handling stays in `decode_raw_preview` (a `covering` argument); an unsupported
raw's editing source and the camera-look fit keep the largest JPEG, so a source never depends on
its size level.
On 120 raws of every make in the corpus at 256 / 512 / 1600 px: wherever the largest JPEG is still
chosen the output is identical byte for byte; where a smaller one is (Sony, Nikon, Panasonic,
Adobe DNG) orientation matches, the size is equal or 1-2 px off, mean difference <= 4.7 / 255.
- Rebased onto #1020: its plan route (`preview_window` -> `planned_preview`) now takes the box size and picks
with `embedded_preview_covering` too, so a TIFF raw read through the sparse plan gets the whole file's JPEG.
Co-Authored-By: Claude <[email protected]>
A windowed render dehazes with the whole frame's airlight, estimated on a 384 px proxy of the frame
(`local::frame_airlight`). Every window asked for that proxy again, so every pan of a 1:1 view and every
slider step while zoomed sampled the whole original down to it on the CPU: ~200 ms of CPU on a 64 MP raw.
The proxy (taken before white balance) is now kept for the last 4 (source fingerprint, frame, size); white
balance, the dark channel and the percentile still run on it every time. Same pixels: the GPU window of
`render_bench` is byte-identical.
`optics::fingerprint` indexed the first pixel of an empty image; it now hashes only the dimensions then.
render_bench ONLY=window GPU_ONLY=1 on a 64 MP Sony ILCE-7RM6 raw (RTX 4070 Ti SUPER, 4-CPU quota), CPU time:
pan 208-212 -> 9-11 ms, exposure change 200-204 -> 4 ms, NR change 211-217 -> 13 ms.
Co-Authored-By: Claude <[email protected]>
In Compare a filmstrip click goes to `compare.set` (#747), so the grid's
modifier clicks never reached `library.select` and multi-select from the
filmstrip was impossible there (#187 follow-up). A ⌘/Ctrl-click now toggles
the photo and a Shift-click extends from the active photo, as in the grid;
the two photos shown stay selected and the active photo is unchanged, so a
rating key still acts on a photo that is on screen. A plain click still
replaces the active side.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NH3itd85jPuM6wNjgcGfEH
The grid queues no render behind an unedited raw's quick thumbnail, since the embedded JPEG is
meant to be the thumbnail. But whether that JPEG can be read is only known when the quick job
runs, and `quick_thumb_job` had no fallback: when the preview loader returned nothing the job
failed with "no quick preview", the failure was remembered for that key, and the cell stayed
empty until an edit changed it. The quick job now carries the real thumbnail job as its last
resort, as `quick_view_job` already does for the loupe.
As in PhotoCraft: when portable.txt (or LightCraft.portable) sits next to the
executable, config_dir() is <exe dir>/LightCraftData, so settings, logs and
models stay with a portable copy instead of %APPDATA%. LIGHTCRAFT_CONFIG_DIR
still wins and is used without probing beside the executable. A portable
folder that can't be written logs a warning and the platform folder is used.
The check runs once per process.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts: crates/engine/src/tests_merge.rs (#1123's test landed where this branch's is; both kept),
docs/parity-checklist.md (the LR-MERGE-HDR row: both notes) and docs/whats-new.md (both entries).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015gRtdWF1E9358FfzhzYqCS