mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
LR-IMP-PREVIEW-READ: stand-ins and raw thumbnails decode the smallest embedded JPEG that covers them
`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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
b3d392b499
commit
14e0d12813
@@ -108,17 +108,36 @@ Measured on the real folder: idle for a minute, the app read 12 previews (**26.9
|
||||
**zero** raws for thumbnails, against 638 MB of whole-file reads for the same 12 photos before. The
|
||||
render queue stayed empty.
|
||||
|
||||
## The smallest JPEG that covers the box
|
||||
|
||||
Many TIFF-based raws keep more than one embedded JPEG. A Sony A7R VI ARW holds a 1616 × 1080 one
|
||||
(0.3 MB) beside the 9984 × 6656 one (5.6 MB), and Nikon NEF and Panasonic RW2 files have mid-sized
|
||||
copies too. The loupe stand-in and the grid thumbnail (`embedded_preview_srgb`) decode the smallest
|
||||
JPEG whose long edge is at least the size asked for (`lightcraft_raw::embedded_preview_covering`).
|
||||
They take the largest one when no other JPEG is big enough. The plan route picks the same way
|
||||
(`preview_window` takes the size asked for), so a raw read through the plan gets the JPEG the whole
|
||||
file would give. A smaller JPEG only counts as a copy of the picture when its aspect ratio is within
|
||||
1 % of the largest one's and it has the same number of colour components. That rules out letterboxed
|
||||
thumbnails of another shape and the grey masks an iPhone ProRAW DNG keeps at the picture's shape.
|
||||
Sources for editing (an unsupported raw's JPEG, `load_embedded_preview`) and the camera-look fit still
|
||||
use the largest JPEG, so their geometry and colour do not depend on the size level.
|
||||
|
||||
## Tests
|
||||
|
||||
- `crates/raw/src/preview.rs`: the header-only range matches `embedded_preview` byte for byte; a
|
||||
clamped prefix, a padded extent, a late pointer, a lying pointer and a non-JPEG window are all
|
||||
covered.
|
||||
covered. `a_stand_in_takes_the_smallest_covering_jpeg_of_the_same_shape` covers the picker: a
|
||||
smaller JPEG that covers the box is taken, the largest when none does, and a thumbnail of another
|
||||
shape or a grey mask never is.
|
||||
- `crates/engine/src/files.rs`: on a synthetic RAF with a 200 KB tail, the quick path and the
|
||||
whole-file path produce identical pixels, and the read stays under half the file. On a synthetic
|
||||
TIFF/DNG whose preview only its tags locate — the plan path — the same identity holds and the CFA
|
||||
strip is not read; the same structure without the tag that makes it a raw declines instead of
|
||||
guessing, and the caller keeps reading it whole. So do a file whose own orientation or Adobe RGB
|
||||
colour space only the whole-file path can show, while one that states sRGB stays on the fast path.
|
||||
A synthetic DNG with a full-size and a half-size JPEG gets, on the plan path, the half-size one for
|
||||
a box it covers and the full-size one otherwise, with the same pixels as the whole-file path
|
||||
(`preview_loading_plans_the_smallest_covering_jpeg`).
|
||||
- `crates/raw/tests/sparse_corpus.rs`: `preview_plan` is asked for **every** corpus file, not only
|
||||
the ones whose header plan is `Ready`, and the preview it yields must equal the whole file's with
|
||||
the skipped bytes `0` and `0xFF`. The test prints what each format reads.
|
||||
|
||||
Reference in New Issue
Block a user