Expand description
Extract the largest embedded JPEG preview from a TIFF-based RAW.
TIFF-based RAW formats (NEF, CR2, CR3, ARW, DNG, ORF, RW2, PEF, RWL, SRW, …) all pack one or more full-decoded JPEGs at known offsets inside the file. Cameras embed these for the rear-screen preview — they’re exactly what every consumer photo-viewer shows when it claims to “open a RAW”. The image is the manufacturer’s intended rendering: correct white balance, correct colours, correct sharpening. Better than anything an open-source debayer pipeline produces without the camera’s proprietary DCP profiles.
§Why a hand-rolled walker
rawloader and rawler give you Bayer sensor data, not embedded
JPEGs. libraw would work but is a native C dep we don’t want to
ship per-platform. kamadak-exif (already a dep) walks IFD0,
IFD1, plus the EXIF / GPS / Interop SubIFDs — but the preview
JPEGs in NEF / CR2 / ARW / DNG / ORF live in a TIFF “SubIFD”
chain referenced by tag 0x014A, which kamadak doesn’t traverse.
So we walk the TIFF directly. ~150 lines of well-defined byte pushing. No deps. Covers every TIFF-based RAW in one shot.
§Algorithm
- Read the 8-byte TIFF header. Confirm
II*\0(little-endian) orMM\0*(big-endian). Note the offset of IFD0. - Recursively walk every IFD reachable from IFD0:
- IFD chain via the NextIFD offset (last 4 bytes of each IFD)
- SubIFD chain via tag 0x014A
- EXIF / GPS / Interop SubIFDs via tags 0x8769 / 0x8825 / 0xA005 Each visit short-circuits if we’ve already seen that offset, so a malformed file with a cycle can’t hang us.
- For each IFD, look for two embedded-JPEG idioms:
a.
JPEGInterchangeFormat(0x0201) + length (0x0202) b.StripOffsets(0x0111) + byte counts (0x0117) whereCompression(0x0103) is 6 (old-style JPEG) or 7 (new). - Sanity-bound each candidate against the file size, then return the bytes of the largest one (or None if no candidate found).
§What this doesn’t do
- RAF (Fujifilm) — custom container, not TIFF. Falls through to
the
image::openpath which fails; the user gets a clear error. ~100 LOC of standalone parser would add it; do that when a Fuji user actually asks. - Full Bayer demosaic — out of scope; that’s a separate path that would need DCP colour profiles and per-camera tuning.
Functions§
- extract_
largest_ preview - Bytes of the largest embedded JPEG in this TIFF-based RAW, or
Noneif the file doesn’t contain a recognisable embedded preview.