Skip to content

CircuitPython's own jpegio -> displayio.Bitmap mis-strides the right-edge MCU block of odd-width images (upstream bug; test carries a workaround) #11

Description

@bdbarnett

Found while running tests/test_lvgl_jpeg_decode.py on the aggregator's CircuitPython 10.2.1 unix coverage build (2026-09-03). The LVGL path (our shim on CP's lib/tjpgd) matches jpegio's goldens on every frame; CP's built-in jpegio.JpegDecoder.decode(bitmap) does not, on odd widths.

Where: shared-module/jpegio/JpegDecoder.c in bitmap_output(), line 136 at 10.2.1:

int src_width = rect->right - rect->left + 1, src_pixel_stride = src_width /* in units of pixels! */, ...
    .stride = src_pixel_stride / 2, /* in units of uint32_t */

For the right-edge MCU block of a 37-px-wide image the block is 5 px wide; 5 / 2 gives a stride of 2 words (4 px), so every row after the first in that block starts one pixel early. On odd_size_37x29.jpg 104 pixels differ, all in columns 32..36, rows 1..28. Even widths are unaffected (the last block is a whole number of words).

Workaround in this repo: the Bitmap witness in tests/test_lvgl_jpeg_decode.py (lines ~225-232) compares only left of the last block for odd widths and requires the difference to stay inside it; README notes it beside the test.

Upstream: this is a CircuitPython core bug, a one-line fix ((src_pixel_stride + 1) / 2, i.e. round up, since the source rows are already word-padded by TJpgDec's output). Candidate for the upstream-emissary when Brad wants a CP PR prepared; the fix would also need the same rounding wherever src_pixel_stride feeds common_hal_displayio_bitmap_blit. Not a blocker for jpegio Phase 2 (the LVGL path is correct).

Activity

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

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