Quantize with a measured Spectra 6 palette and OKLab-space ordered dithering
Build and push server image / test (push) Successful in 58s
Build and push server image / build-and-push (push) Successful in 2m44s
Build and push server image / deploy (push) Successful in 53s

DEFAULT_PALETTE_RGB was a guessed approximation of the panel's ink
colors (pure sRGB primaries); swap in epdoptimize's measured spectra6
palette instead, which is far more muted/darker, matching how these
inks actually look.

_quantize now matches against the palette in OKLab space (perceptual
distance) instead of PIL's raw-RGB quantize(), with lightness weighted
down relative to hue/chroma when selecting the nearest color -- this
palette's inks are lit so differently from their sRGB namesakes
(muted dark red, bright yellow) that unweighted distance let lightness
dominate and mismatch hue (pure red nearest "yellow").

Dithering switched from Floyd-Steinberg error diffusion to a Bayer
ordered dither: true error diffusion is an inherently serial per-pixel
loop, and doing that in pure Python for a full 800x480 panel took
~1s, blowing past the render-latency budget the "render widgets
concurrently" fix (previous commit) exists to protect. The ordered
dither finds each pixel's true nearest and second-nearest palette
color and mixes between them (via projection onto that segment, not
distance ratio) using a tiled Bayer threshold -- fully vectorized, no
Python-level pixel loop.
This commit is contained in:
2026-07-28 04:20:25 +00:00
parent a48c84ed4a
commit 05b417a29b
3 changed files with 185 additions and 34 deletions
+2 -2
View File
@@ -135,7 +135,7 @@ def test_solid_border_draws_the_configured_palette_color(client, db_session):
assert resp.status_code == 200, resp.text
img = _preview_pixels(client)
assert img.getpixel((0, 0)) == (207, 0, 15) # DEFAULT_PALETTE_RGB[3], top-left corner of the stroke
assert img.getpixel((0, 0)) == (98, 32, 30) # DEFAULT_PALETTE_RGB[3], top-left corner of the stroke
def test_no_border_leaves_the_edge_unmarked(client, db_session):
@@ -146,4 +146,4 @@ def test_no_border_leaves_the_edge_unmarked(client, db_session):
render path already painting it that color."""
client.post("/setup", data={"username": "alice", "password": "hunter22"})
img = _preview_pixels(client)
assert img.getpixel((0, 0)) != (207, 0, 15)
assert img.getpixel((0, 0)) != (98, 32, 30)