JXL DNG: honor Row/ColumnInterleaveFactor, add F32 path#1
Merged
Conversation
DNG 1.7 CFA files may store the Bayer mosaic as RowInterleaveFactor x ColumnInterleaveFactor stacked color-plane "fields" (each a smooth half-res subimage that compresses far better under lossy JPEG XL), signalled by tags 0xC71F / 0xCD43. rawspeed assembled the tiles but never wove the fields back together, emitting a scrambled mosaic (four quadrant planes stacked instead of RGGB). Add a whole-frame de-interleave post-pass in decodeData(), run after slices.decompress() and before handleMetadata() applies ActiveArea / DefaultCropOrigin. It operates on the uncropped assembled buffer, one whole pixel (getBpp() bytes) at a time, so it is type-generic over UINT16 and F32. A single JXL tile can straddle a field boundary, so this cannot be done per-tile. The stored->final index math (dngDeinterleaveFieldMap) follows the Adobe DNG 1.7.1.0 spec and the dng_sdk dng_read_image.cpp reference: field f's rows scatter to final rows f, f+R, f+2R, ...; non-divisible sizes let earlier fields absorb the remainder. Factored into a small pure header (DngDeinterleave.h) so the index mapping is unit-testable. R==1 && C==1 fast-paths to a no-op. Also adds the missing COLUMNINTERLEAVEFACTOR (0xCD43) tag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Unit-test dngDeinterleaveFieldMap, including the verified 4x4 R=C=2 worked example (quadrant-constant stored buffer must de-interleave to the RGGB-phase mosaic), the per-pixel stored->final map, the factor-1 identity fast path, and the non-divisible remainder rule from dng_sdk (total=5,factor=2 and total=7,factor=3). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The decompressor unconditionally wrote the decoded tile through mRaw->getU16DataAsUncroppedArray2DRef() and requested JXL_TYPE_UINT16, which asserts (dataType == RawImageType::UINT16) and fails to decode for float (F32) JPEG XL DNGs such as Adobe's 02_jxl_linear_raw_float.dng. Pick the JxlPixelFormat sample type from mRaw->getDataType(): request JXL_TYPE_FLOAT and write via getF32DataAsUncroppedArray2DRef() for F32 images, keeping the JXL_TYPE_UINT16 path for integer images. The decoded tile now lands in a type-agnostic byte buffer (libjxl reports the size in bytes) and a templated copyTile() shares the interleaved copy loop. Verified both 01_jxl_linear_raw_integer.dng and 02_jxl_linear_raw_float.dng decode without crashing via rstest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on top of darktable-org#971 (base branch
jpegxl-dng17). Three correctness fixes for the JPEG XL DNG decoder, found while verifying the feature against Adobe's DNG SDK sample files and a real interleaved-CFA capture.1. Honor RowInterleaveFactor / ColumnInterleaveFactor (DNG 1.7)
DNG 1.7 lets a CFA mosaic be stored as
RxCstacked half-res color-plane subimages (each plane is spatially smooth, so it compresses far better under lossy JXL). The decoder ignoredRowInterleaveFactor(0xC71F, was defined but never read) andColumnInterleaveFactor(0xCD43, was not defined), so any 2x2-interleaved CFA JXL DNG decoded scrambled: the four quadrant planes were left stacked instead of woven back into the Bayer mosaic.COLUMNINTERLEAVEFACTOR = 0xCD43toTiffTag.h.DngDeinterleave.h: pure, unit-testabledngDeinterleaveFieldMap(total, factor).DngDecoder::deinterleaveFields(): a whole-frame post-pass afterslices.decompress(), beforeActiveArea/DefaultCropOrigin. Type-generic (UINT16 + F32) viagetByteDataAsUncroppedArray2DRef().Why whole-frame, not per-tile: Adobe's
03_jxl_bayer_raw_integer.dngis 10240x7168 with 1280x1440 tiles and R=C=2; the row-field boundary (3584) is not a multiple of 1440, so a single JXL tile straddles two color planes. Per-tile de-interleave is geometrically impossible. The index mapping (fy = within_field_row * R + field_row_index, symmetric for columns; non-divisible fields let earlier fields absorb the remainder) matches the DNG 1.7.1.0 spec anddng_sdk'sdng_row_interleaved_image::MapRow.2. Unit test for the de-interleave math
googletest covering factor-1 identity, non-divisible field sizing, and the spec's 4x4 / R=C=2 quadrant worked example (verifies the exact RGGB-phase mosaic).
3. F32 output path for float JXL DNGs
The decoder unconditionally requested
JXL_TYPE_UINT16and wrote throughgetU16DataAsUncroppedArray2DRef(), which asserts on float (F32) images, so float LinearRaw JXL DNGs (02_jxl_linear_raw_float.dng) failed to decode. Now theJxlPixelFormatsample type and output accessor are picked frommRaw->getDataType()(JXL_TYPE_FLOAT+ F32 accessor for float, UINT16 path otherwise) via a templatedcopyTile().Verification (libjxl 0.11.2, standalone build)
DngDeinterleaveTest6/6.rstest -cdecodes01_jxl_linear_raw_integer,02_jxl_linear_raw_float,03_jxl_bayer_raw_integerwith no crash/assertion.02confirms the UINT16 assertion is gone.03mosaic de-scrambled: mid-line vs interior mean-abs-diff ratio 1.3x (a scrambled 4-quadrant layout shows 5-20x).Test files: the Adobe DNG SDK sample set (
adobe-dng-sdksample_files),03_jxl_bayer_raw_integer.dngbeing the canonical 2x2-interleaved CFA vector.🤖 Generated with Claude Code