C-RAW is quantised wavelet coding: next to clipped highlights its reconstruction overshoots the sensor range by a few quantisation steps. On 17 CC0 CR3 files (SX70 HS, G5 X Mark II, M6 Mark II, EOS R, RP, 90D, M200, R5 Mark II, R6 Mark II, R6 Mark III, R8) samples reached 16384 to 16419 at 14 bits, never below 0, and decoding failed with "decoded sample outside its bit depth". Lossless files of the same bodies clip at exactly 16383. Wavelet samples are now clamped to the CMP1 bit depth; lossless samples outside it are still corrupt data. The other 93 CR3 files have no sample outside the range and render pixel-identically. Render cache version 13 -> 14.
4.9 KiB
Canon CR3 decoding
The CR3 adapter reads the CRX Bayer track, CMP1 compression descriptor,
CDI1/IAD1 sensor geometry and timed CTMD maker notes. White balance,
black/white levels and the default crop come from the file. A Dual Pixel delta
track is never substituted for the primary Bayer track.
The decoder is independent Rust code shared by desktop, CLI and WebAssembly;
it has no operating-system imaging dependency or external decoder. Its sources
are the public prose descriptions and patents cited in
crates/raw/src/vendor/crx.rs. Unsupported coding variants retain the existing
embedded-JPEG fallback and its visible warning when a JPEG is present. So does
any other CR3 decode error (a corrupt file, or a body whose CRX stream the
decoder misreads): every CR3 opened from its embedded JPEG before this decoder,
and only three bodies are verified, so a CR3 never fails to import or load
where a preview exists. HEVC-only preview tracks are recognized but are not
decoded.
Verified sensor decoding
CRX version 0x100, four Bayer planes and ff01/ff02/ff03 marker headers
support lossless RAW and three-level C-RAW with horizontal tiles. Uniform
quantization values 4–43 are independently verified. Version 0x200 C-RAW
supports the ff11/ff12/ff13 marker family, a single 14-bit Bayer tile and
its adaptive quantization map. C-RAW is quantized, so next to clipped highlights
its reconstruction can overshoot the sensor range by a few quantization steps
(up to 36 codes above 16383 in 17 CC0 files); those samples are clamped to the
CMP1 bit depth. A lossless sample outside the bit depth is still corrupt data.
Other unverified coding variants return explicit unsupported errors. Header probing validates the same coding variants and
tile/plane layout as full decoding.
crates/raw/tests/cr3_corpus.rs checks every full-sensor sample against a
black-box reference, before cropping or colour processing. Public CC0 files
are downloaded by cargo xtask corpus --download and kept outside version
control. The exact inputs and reference hashes are:
| File | Input SHA-256 | Sensor FNV-1a (u16 little-endian) |
|---|---|---|
| Canon M50 RAW, raw.pixls.us 4657 | 1ba9ad6b51b315b88820eb0fe5fd7f52bc136ba37b1a5ca76825ebfe25b18058 |
62261f0ba81cfcd2 |
| Canon M50 C-RAW, raw.pixls.us 2663 | 15384b775867ec4c42b11882837f1e368cedc0561832ffab271221e6bb80be4c |
9aacbfe66f505e1b |
| Canon R100 RAW, raw.pixls.us 7896 | 6d83217d58a5e6d2dabcf470430e91a16676b60531c025b81fa7453fc74b0521 |
cbe5299ab9c52630 |
| Canon R100 C-RAW, raw.pixls.us 7897 | 0b66842b2fe00329ebc05fe8ab9357ddbbe1a0a2d2e69a2893102de7fdf5c942 |
341c706b37c38bbf |
| Canon R8 RAW, raw.pixls.us 6585 | 7d5c6dbb11ff7e6ee58715d90a20f5d801e8b103f4711ff6ea329ceafcef254c |
63c1c6d8d1eb2312 |
| Canon R8 C-RAW, raw.pixls.us 6587 | df33cf394573645ce03dea1b2e9f0b5cc2b7734e9e3391ee7114151414cf2812 |
f836a663a795a375 |
Reference pixels were observed from the DNGLab 0.8.0 macOS arm64 release
binary; no decoder source was read or copied, and it is not shipped or linked.
The release ZIP SHA-256 was
ee70805cb60f18d5ed62548c4e595f6cee0a33407e15358eb1766a46afc1c16e.
All six sensor comparisons pass. R8 HEVC preview tracks are distinguished from
the primary Bayer RAW; the HEVC preview itself is not decoded. Missing corpus
files are reported as skipped by the tests.
The version 0x200 QP predictor and entropy framing were checked independently.
Controlled input mutations establish floor averaging of paired QP rows before
the nonlinear integer table, then multiplication, division by eight, addition
of the subband base and a minimum step of one. QP values 131–167 are verified;
unmeasured values and an odd QP-map height are rejected. Partial-subband and
rounded-plane coding, vertical C-RAW tiling and adaptive low-frequency gains
remain unsupported. The decoder bounds image dimensions, sample count,
tile count, marker headers and temporary allocations. The full sensor buffer is
allocated only after the first plane decodes, and plane buffers grow row by row,
so a small crafted file fails before reserving memory for the image it claims.
Colour limits
CR3 carries as-shot white balance but no measured camera matrix is imported
here. The existing guarded embedded-JPEG fitting path now includes CR3, with
both proxies oriented identically before gathering training pairs. A bounded
crop/translation registration of the JPEG is confirmed on held-out edge
directions before fitting colour; the existing held-out colour acceptance gates
are unchanged. No lens distortion correction is applied (LightCraft has no lens
profiles of its own yet), so lenses whose camera JPEG is strongly
distortion-corrected may fail the gates and keep the neutral matrix. Render
cache version 13 invalidates earlier thumbnails. All developed pixels still come
from the RAW sensor; a rejected colour fit retains the documented neutral
matrix fallback. See camera-preview-colour.md for the limits of this estimate.