From 536ccb2e4520df3806cf4bfbc7e651721333f1ae Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 6 Jul 2026 02:22:11 -0400 Subject: [PATCH] docs: clarify DitherMode::None is for pre-quantized graphics, not photos DitherMode::None does a direct nearest-color map with no error diffusion, so on limited palettes (especially BWR) continuous-tone or large flat mid-tone areas can map to an unexpected ink (e.g. a mid-gray region rendering as solid red). Document this in the Rust/Python/JS enum docs and the package READMEs, and steer users toward an error-diffusion mode for photographic input. Docs only; no logic or metric changes. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR --- packages/javascript/README.md | 2 +- packages/javascript/src/enums.ts | 7 +++++++ packages/python/README.md | 2 +- packages/python/src/epaper_dithering/enums.py | 5 +++++ packages/rust/core/README.md | 2 +- packages/rust/core/src/enums.rs | 5 +++++ 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/javascript/README.md b/packages/javascript/README.md index 745c43a..0e11e60 100644 --- a/packages/javascript/README.md +++ b/packages/javascript/README.md @@ -127,7 +127,7 @@ ditherImage(image: ImageBuffer, palette: ColorScheme | ColorPalette, options?: D Pre-processing pipeline: `exposure → saturation → shadows/highlights → tone → gamut → dither`. Each step is a no-op at its identity value. -`DitherMode.NONE` performs direct nearest-color mapping without error diffusion or ordered dithering. Built-in measured palettes carry their canonical firmware `scheme`, so pure display colors map to the corresponding firmware palette index even when measured RGB values are used for matching. +`DitherMode.NONE` performs direct nearest-color mapping without error diffusion or ordered dithering. It is intended for already-quantized graphics, not continuous-tone photos: because there is no error diffusion, on limited palettes (especially BWR) a continuous-tone image or a large flat mid-tone area can map to an unexpected ink — for example, a solid mid-gray region can render as solid red. Use an error-diffusion mode (e.g. `FLOYD_STEINBERG`, `BURKES`) for photographic input. Built-in measured palettes carry their canonical firmware `scheme`, so pure display colors map to the corresponding firmware palette index even when measured RGB values are used for matching. For built-in measured palettes, exact canonical display colors are also protected in ordered and error-diffusion modes when pre-processing is off: an image made entirely of display colors is returned as a direct palette-index map, and exact display-color pixels inside a mixed image keep their canonical index instead of being rematched to the measured RGB palette. Pre-processing runs before that exact-pixel check, so explicit `tone: 'auto'`, `gamut: 'auto'`, or other adjustments may intentionally alter those pixels first. diff --git a/packages/javascript/src/enums.ts b/packages/javascript/src/enums.ts index f33a82d..951e8c7 100644 --- a/packages/javascript/src/enums.ts +++ b/packages/javascript/src/enums.ts @@ -3,6 +3,13 @@ * Values match firmware conventions (0-8) */ export enum DitherMode { + /** + * Direct nearest-color mapping with no error diffusion. Intended for + * already-quantized graphics only. On limited palettes (especially BWR), + * continuous-tone photos or large flat mid-tone areas can map to an + * unexpected ink (e.g. a mid-gray region rendered as solid red); use an + * error-diffusion mode (e.g. FLOYD_STEINBERG, BURKES) for photographic input. + */ NONE = 0, BURKES = 1, ORDERED = 2, diff --git a/packages/python/README.md b/packages/python/README.md index b06e350..6e871ca 100644 --- a/packages/python/README.md +++ b/packages/python/README.md @@ -182,7 +182,7 @@ result = dither_image(img, SPECTRA_7_3_6COLOR, mode=DitherMode.BURKES, gamut="of Note: `gamut` also has no effect for theoretical `ColorScheme` palettes. -`DitherMode.NONE` performs direct nearest-color mapping without error diffusion or ordered dithering. For built-in measured palettes, pure canonical display colors such as `(255, 0, 0)` map directly to the corresponding firmware palette index even though matching uses measured display RGB values. +`DitherMode.NONE` performs direct nearest-color mapping without error diffusion or ordered dithering. It is intended for already-quantized graphics, not continuous-tone photos: because there is no error diffusion, on limited palettes (especially BWR) a continuous-tone image or a large flat mid-tone area can map to an unexpected ink — for example, a solid mid-gray region can render as solid red. Use an error-diffusion mode (e.g. `FLOYD_STEINBERG`, `BURKES`) for photographic input. For built-in measured palettes, pure canonical display colors such as `(255, 0, 0)` map directly to the corresponding firmware palette index even though matching uses measured display RGB values. For built-in measured palettes, exact canonical display colors are also protected in ordered and error-diffusion modes when pre-processing is off: an image made entirely of display colors is returned as a direct palette-index map, and exact display-color pixels inside a mixed image keep their canonical index instead of being rematched to the measured RGB palette. Pre-processing runs before that exact-pixel check, so explicit `tone="auto"`/`gamut="auto"` or other adjustments may intentionally alter those pixels first. diff --git a/packages/python/src/epaper_dithering/enums.py b/packages/python/src/epaper_dithering/enums.py index a8a6548..6d170ff 100644 --- a/packages/python/src/epaper_dithering/enums.py +++ b/packages/python/src/epaper_dithering/enums.py @@ -11,6 +11,11 @@ class DitherMode(IntEnum): Values are compatible with OpenDisplay firmware conventions. """ + #: Direct nearest-color mapping with no error diffusion. Intended for + #: already-quantized graphics only. On limited palettes (especially BWR), + #: continuous-tone photos or large flat mid-tone areas can map to an + #: unexpected ink (e.g. a mid-gray region rendered as solid red); use an + #: error-diffusion mode (e.g. FLOYD_STEINBERG, BURKES) for photographic input. NONE = 0 BURKES = 1 ORDERED = 2 diff --git a/packages/rust/core/README.md b/packages/rust/core/README.md index c5ee40e..41d42cd 100644 --- a/packages/rust/core/README.md +++ b/packages/rust/core/README.md @@ -57,7 +57,7 @@ let indices = dither(&img, &SPECTRA_7_3_6COLOR, DitherConfig { Pipeline order: `exposure → saturation → shadows/highlights → tone → gamut → dither`. -`DitherMode::None` performs direct nearest-color mapping without error diffusion or ordered dithering. `dither_with_canonical` lets measured palettes use calibrated RGB values for matching while preserving the canonical display palette for exact-color bypass and firmware indices. +`DitherMode::None` performs direct nearest-color mapping without error diffusion or ordered dithering. It is intended for already-quantized graphics, not continuous-tone photos: with no error diffusion, on limited palettes (especially BWR) a continuous-tone image or a large flat mid-tone area can map to an unexpected ink — for example, a solid mid-gray region can render as solid red. Use an error-diffusion mode (e.g. `FloydSteinberg`, `Burkes`) for photographic input. `dither_with_canonical` lets measured palettes use calibrated RGB values for matching while preserving the canonical display palette for exact-color bypass and firmware indices. With `dither_with_canonical`, exact canonical display colors are also protected in ordered and error-diffusion modes when pre-processing is off: an image made entirely of display colors is returned as a direct palette-index map, and exact display-color pixels inside a mixed image keep their canonical index instead of being rematched to the measured RGB palette. Pre-processing runs before that exact-pixel check, so explicit tone/gamut compression or other adjustments may intentionally alter those pixels first. diff --git a/packages/rust/core/src/enums.rs b/packages/rust/core/src/enums.rs index b09cc20..b17ce2a 100644 --- a/packages/rust/core/src/enums.rs +++ b/packages/rust/core/src/enums.rs @@ -9,6 +9,11 @@ use crate::tone_map; #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum DitherMode { + /// Direct nearest-color mapping with no error diffusion. Intended for + /// already-quantized graphics only. On limited palettes (especially BWR), + /// continuous-tone photos or large flat mid-tone areas can map to an + /// unexpected ink (e.g. a mid-gray region rendered as solid red); use an + /// error-diffusion mode (e.g. `FloydSteinberg`, `Burkes`) for photographic input. None = 0, #[default] Burkes = 1,