diff --git a/packages/python/src/epaper_dithering/__init__.py b/packages/python/src/epaper_dithering/__init__.py index b1a09e8..72b59c7 100644 --- a/packages/python/src/epaper_dithering/__init__.py +++ b/packages/python/src/epaper_dithering/__init__.py @@ -11,6 +11,7 @@ BWRY_4_2, HANSHOW_BWR, HANSHOW_BWY, + INKPLATE_6COLOR, MONO_4_26, SOLUM_BWR, SPECTRA_7_3_6COLOR, @@ -35,4 +36,5 @@ "SOLUM_BWR", "HANSHOW_BWR", "HANSHOW_BWY", + "INKPLATE_6COLOR", ] diff --git a/packages/python/src/epaper_dithering/palettes.py b/packages/python/src/epaper_dithering/palettes.py index 45f84e4..fea7dee 100644 --- a/packages/python/src/epaper_dithering/palettes.py +++ b/packages/python/src/epaper_dithering/palettes.py @@ -92,6 +92,24 @@ class ColorScheme(Enum): ), ) + # 7-color ACeP (e.g. Inkplate 6COLOR). Color order = panel native nibbles: + # black0 white1 green2 blue3 red4 yellow5 orange6. + BWGBRYO = ( + 8, + ColorPalette( + colors={ + "black": (0, 0, 0), + "white": (255, 255, 255), + "green": (0, 255, 0), + "blue": (0, 0, 255), + "red": (255, 0, 0), + "yellow": (255, 255, 0), + "orange": (255, 128, 0), + }, + accent="red", + ), + ) + GRAYSCALE_4 = ( 5, ColorPalette( @@ -223,3 +241,4 @@ def _load_measured_palettes() -> dict[str, "ColorPalette"]: SOLUM_BWR: ColorPalette = _MEASURED["SOLUM_BWR"] HANSHOW_BWR: ColorPalette = _MEASURED["HANSHOW_BWR"] HANSHOW_BWY: ColorPalette = _MEASURED["HANSHOW_BWY"] +INKPLATE_6COLOR: ColorPalette = _MEASURED["INKPLATE_6COLOR"] diff --git a/packages/rust/core/src/measured_palettes.rs b/packages/rust/core/src/measured_palettes.rs index 93530b0..fedd262 100644 --- a/packages/rust/core/src/measured_palettes.rs +++ b/packages/rust/core/src/measured_palettes.rs @@ -35,6 +35,12 @@ pub static CATALOG: &[MeasuredPaletteEntry] = &[ scheme: ColorScheme::Bwgbry, color_names: &["black", "white", "yellow", "red", "blue", "green"], }, + MeasuredPaletteEntry { + id: "INKPLATE_6COLOR", + palette: &INKPLATE_6COLOR, + scheme: ColorScheme::Bwgbryo, + color_names: &["black", "white", "green", "blue", "red", "yellow", "orange"], + }, MeasuredPaletteEntry { id: "MONO_4_26", palette: &MONO_4_26, @@ -103,6 +109,30 @@ pub static SPECTRA_7_3_6COLOR_V2: Palette = Palette { accent_idx: 3, // red }; +// ── Inkplate 6COLOR 7-color ACeP ───────────────────────────────────────────── + +/// Inkplate 6COLOR (600x448 7-color ACeP, EP585C / panel_ic_type 0x0043). +/// Color order = panel native nibbles: black0 white1 green2 blue3 red4 yellow5 orange6. +/// Hue-representative values tuned 2026-06-18 so source colors select the correct ink +/// (these drive matching only; the panel always renders its own ink for each nibble). +/// Derived from a forced-nibble calibration capture, then de-washed: the panel's raw +/// inks photograph very desaturated (esp. green, contaminated by ghosting), which makes +/// nearest-color matching send vivid greens->yellow and blues->black. Boosting saturation +/// toward each ink's true hue fixes ink selection. TODO: precise per-ink measurement on a +/// ghosting-cleared panel for tone-accurate values. +pub static INKPLATE_6COLOR: Palette = Palette { + colors: Cow::Borrowed(&[ + [ 45, 45, 70], // black (dark blue-gray) + [230, 230, 230], // white + [ 60, 150, 80], // green + [ 40, 70, 190], // blue + [200, 40, 40], // red + [235, 215, 90], // yellow + [225, 120, 40], // orange + ]), + accent_idx: 4, // red +}; + // ── Monochrome displays ─────────────────────────────────────────────────────── /// 4.26" Monochrome. TODO: measure actual display. diff --git a/packages/rust/core/src/palettes.rs b/packages/rust/core/src/palettes.rs index ef3ac09..a9d438d 100644 --- a/packages/rust/core/src/palettes.rs +++ b/packages/rust/core/src/palettes.rs @@ -49,6 +49,9 @@ pub enum ColorScheme { Grayscale16 = 6, /// Reserved: 8-level grayscale, pending firmware value assignment. Grayscale8 = 7, + /// 7-color ACeP (e.g. Inkplate 6COLOR). Color order matches the panel's + /// native nibble codes: black0 white1 green2 blue3 red4 yellow5 orange6. + Bwgbryo = 8, } // ── Palette data ───────────────────────────────────────────────────────────── @@ -76,6 +79,14 @@ static PALETTE_BWGBRY: Palette = Palette { ]), accent_idx: 3, }; +// 7-color ACeP. Order = panel native nibbles: black0 white1 green2 blue3 red4 yellow5 orange6. +static PALETTE_BWGBRYO: Palette = Palette { + colors: Cow::Borrowed(&[ + [0, 0, 0], [255, 255, 255], [0, 255, 0], [0, 0, 255], + [255, 0, 0], [255, 255, 0], [255, 128, 0], + ]), + accent_idx: 4, // red +}; static PALETTE_GRAYSCALE4: Palette = Palette { colors: Cow::Borrowed(&[[0, 0, 0], [85, 85, 85], [170, 170, 170], [255, 255, 255]]), accent_idx: 0, @@ -110,6 +121,7 @@ impl ColorScheme { ColorScheme::Grayscale4 => &PALETTE_GRAYSCALE4, ColorScheme::Grayscale16 => &PALETTE_GRAYSCALE16, ColorScheme::Grayscale8 => &PALETTE_GRAYSCALE8, + ColorScheme::Bwgbryo => &PALETTE_BWGBRYO, } } } @@ -135,6 +147,7 @@ impl TryFrom for ColorScheme { 5 => Ok(ColorScheme::Grayscale4), 6 => Ok(ColorScheme::Grayscale16), 7 => Ok(ColorScheme::Grayscale8), + 8 => Ok(ColorScheme::Bwgbryo), _ => Err(DitherError::UnknownColorScheme(v)), } } @@ -171,5 +184,27 @@ mod tests { assert_eq!(ColorScheme::Mono.palette().colors.len(), 2); assert_eq!(ColorScheme::Bwgbry.palette().colors.len(), 6); assert_eq!(ColorScheme::Grayscale16.palette().colors.len(), 16); + assert_eq!(ColorScheme::Bwgbryo.palette().colors.len(), 7); + } + + #[test] + fn bwgbryo_is_value_8() { + assert_eq!(u8::from(ColorScheme::Bwgbryo), 8); + assert_eq!(ColorScheme::try_from(8), Ok(ColorScheme::Bwgbryo)); + } + + #[test] + fn bwgbryo_order_matches_panel_native_nibbles() { + // The dither output index is the 4bpp nibble sent to the panel, so the + // palette order MUST match the Inkplate 6COLOR's native codes: + // black0 white1 green2 blue3 red4 yellow5 orange6. + let c = &ColorScheme::Bwgbryo.palette().colors; + assert_eq!(c[0], [0, 0, 0], "idx0 black"); + assert_eq!(c[1], [255, 255, 255], "idx1 white"); + assert_eq!(c[2], [0, 255, 0], "idx2 green"); + assert_eq!(c[3], [0, 0, 255], "idx3 blue"); + assert_eq!(c[4], [255, 0, 0], "idx4 red"); + assert_eq!(c[5], [255, 255, 0], "idx5 yellow"); + assert_eq!(c[6], [255, 128, 0], "idx6 orange"); } }