Skip to content

JPEG Lossless restart boundaries not applied during predictor reconstruction #286

@TidalPaladin

Description

@TidalPaladin

Summary

JPEG Lossless images with restart intervals (DRI + RSTn) can decode to visibly corrupted output (banding/striping) while decoding succeeds without error.

Suspected root cause

In decode_scan_lossless (src/decoder/lossless.rs), restart handling is tracked during entropy decoding, but reconstruction later does not reliably apply restart resets at the same sample boundaries.

In practice this means the restart flag used by prediction can be wrong during reconstruction because restart-boundary context is no longer aligned with sample index when reconstructing the differences buffer.

Notes

  • This is reproducible on valid JPEG Lossless streams using restart markers.
  • A fix should ensure restart resets are derived from absolute sample position (or equivalent preserved state) during reconstruction.

Proposed patch (minimal)

The core change is to derive restart boundaries from absolute sample index during reconstruction, instead of reusing transient decoder loop state.

diff --git a/src/decoder/lossless.rs b/src/decoder/lossless.rs
@@
- let prediction = predict(..., self.restart_interval > 0
-     && mcus_left_until_restart == self.restart_interval - 1);
+ let pixel_index = mcu_y * width + mcu_x;
+ let prediction = predict(..., self.restart_interval > 0
+     && pixel_index > 0
+     && pixel_index % self.restart_interval as usize == 0);

And in the Predictor::Ra branch, apply the same restart condition (pixel_index % restart_interval == 0) when selecting the reset predictor at restart boundaries.

Examples (Before / After)

Image Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions