Skip to content

Fix progressive grayscale decode with separate component scans - #124

Open
lpla wants to merge 1 commit into
bitbank2:masterfrom
lpla:agent/fix-progressive-grayscale-scans
Open

Fix progressive grayscale decode with separate component scans#124
lpla wants to merge 1 commit into
bitbank2:masterfrom
lpla:agent/fix-progressive-grayscale-scans

Conversation

@lpla

@lpla lpla commented Aug 8, 2026

Copy link
Copy Markdown

Summary

Progressive JPEGs may place the luminance DC coefficients in the first scan and defer both chroma components to a later scan. When decoding that first scan as EIGHT_BIT_GRAYSCALE, DecodeJPEG() currently calls JPEGDecodeMCU_P(..., MCU_SKIP, ...) for Cb and Cr even though neither component is present in the entropy stream.

Check each scan component's existing component_needed flag before consuming its entropy data. This avoids reading absent chroma data and lets the valid luminance-only scan produce the documented 1/8-scale progressive preview.

This adds no allocation and leaves baseline, single-component progressive, and color-output paths unchanged.

Reproduction

The failure can be reproduced without third-party image content by creating a 4:4:4 progressive JPEG with this libjpeg scan script:

0:   0-0,  0, 0;
1,2: 0-0,  0, 0;
0:   1-63, 0, 0;
1:   1-63, 0, 0;
2:   1-63, 0, 0;

Decode it using:

jpeg.setPixelType(EIGHT_BIT_GRAYSCALE);
jpeg.decode(0, 0, JPEG_SCALE_EIGHTH);

At current master (8628297), the decoder attempts the absent chroma blocks and crashes under the host harness. With this patch it returns success and invokes the draw callback for all eight output rows.

Validation

  • Synthetic 96x64 Y-only first progressive scan: baseline crashes; fixed decoder returns decode=1 error=0 draw_calls=8.
  • Real-world 600x900 Y-only first progressive scan: baseline crashes; fixed decoder returns decode=1 error=0 draw_calls=113.
  • Baseline color JPEG control: both return decode=1 error=0 draw_calls=8.
  • Single-component progressive grayscale control: both return decode=1 error=0 draw_calls=8.
  • Native-decoder CrossPoint emulator: baseline image is blank; fixed image renders and survives a cold cache reopen.

Emulator evidence

These screenshots are emulator-only evidence, not physical-device validation.

Baseline: valid cover decodes as blank Fixed: cover renders
Baseline emulator screenshot: blank cover Fixed emulator screenshot: rendered cover

Related, but distinct because it concerns components that are present in the scan: #119.

@lpla
lpla force-pushed the agent/fix-progressive-grayscale-scans branch from 4be2c05 to d62096b Compare August 8, 2026 11:17
@bitbank2

bitbank2 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Thank you for submitting this PR. Can you please send me the progressive JPEG used for testing so that I can verify the fix?

@lpla

lpla commented Aug 8, 2026

Copy link
Copy Markdown
Author

Here is a synthetic 96×64 reproducer with no third-party content: progressive-separated-component-scans.jpg (SHA-256 243e8e9387da6f81f77abc12dc2b5197fa3610dacbfde1ebc12a5f9edf75d9b6).

Its scans are: Y DC; Cb+Cr DC; Y AC; Cb AC; Cr AC. With EIGHT_BIT_GRAYSCALE and JPEG_SCALE_EIGHTH, current master crashes in the host harness; this PR returns success with 8 draw callbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants