# 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. 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.