Skip to content

Fix bitmaptools.dither() into 1-bit dest - #11455

Merged
dhalbert merged 2 commits into
adafruit:mainfrom
FoamyGuy:bitmaptools_fixes
Sep 24, 2026
Merged

dhalbert merged 2 commits into
adafruit:mainfrom
FoamyGuy:bitmaptools_fixes

Conversation

@FoamyGuy

Copy link
Copy Markdown
Collaborator

This change fixes an issue that causes a hard fault when attempting to dither into a 1-bit destination. Here is reproducer code:

import displayio
import bitmaptools


def check(width, height):
    src = displayio.Bitmap(width, height, 65536)
    # Horizontal luminance ramp: nontrivial dither pattern in every byte.
    for x in range(width):
        v = x * 255 // max(width - 1, 1)
        rgb565 = ((v >> 3) << 11) | ((v >> 2) << 5) | (v >> 3)
        for y in range(height):
            src[x, y] = rgb565

    ref = displayio.Bitmap(width, height, 65536)
    bitmaptools.dither(ref, src, displayio.Colorspace.RGB565,
                       bitmaptools.DitherAlgorithm.FloydStenberg)

    dst = displayio.Bitmap(width, height, 2)
    # Broken firmware dies on this call.
    bitmaptools.dither(dst, src, displayio.Colorspace.RGB565,
                       bitmaptools.DitherAlgorithm.FloydStenberg)

    mismatches = 0
    first = None
    for y in range(height):
        for x in range(width):
            if (ref[x, y] != 0) != (dst[x, y] != 0):
                mismatches += 1
                if first is None:
                    first = (x, y)
    if mismatches:
        return "FAIL: %d/%d pixels differ, first at %s" % (
            mismatches, width * height, first)
    return "PASS"


for size in ((320, 4), (64, 4), (50, 3), (17, 3), (8, 2), (1, 1)):
    print("%dx%d:" % size, check(*size))
print("done")

On a very recent main build from S3 it hard faults:

Adafruit CircuitPython 11.0.0-alpha.0-7-g8f94f74a7c on 2026-09-23; Adafruit Fruit Jam with rp2350b
>>> 
>>> import dither_issue

[16:16:35.130] Disconnected
[16:16:36.130] Connected
Auto-reload be off.
Runnin' in safe mode! Nay runnin' saved code.

You are in safe mode because:
CircuitPython core code crashed hard. Whoops!
Hard fault: memory access or instruction error.
Please file an issue with your program at github.com/adafruit/circuitpython/issues.
Press reset to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.

With this fix in place it runs successfully

>>> import dither_issue
320x4: PASS
64x4: PASS
50x3: PASS
17x3: PASS
8x2: PASS
1x1: PASS
done

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense - thanks!

@dhalbert
dhalbert merged commit d56a2f7 into adafruit:main Sep 24, 2026
583 of 584 checks passed
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