Skip to content

Repository files navigation

epaper-dithering

PyPInpmPython TestsJS TestsRuff

Dithering algorithms for e-paper/e-ink displays. Rust core with Python and JavaScript/TypeScript bindings.

Examples

Frankfurt at night — original vs Spectra 6-color with auto tone + gamut compression

Dithering algorithms (Spectra 6-color, Marienplatz U-Bahn station):

All dithering algorithms compared

Color schemes (Burkes, river scene):

All color schemes compared

Packages

Python (packages/python/)

Published to PyPI as epaper-dithering.

pip install epaper-dithering
fromPILimportImagefromepaper_ditheringimportdither_image, ColorScheme, DitherMode, SPECTRA_7_3_6COLOR_V2img=Image.open("photo.jpg")
# Idealized palettedithered=dither_image(img, ColorScheme.BWR, mode=DitherMode.FLOYD_STEINBERG)
# Measured palette — calibrated color matchingdithered=dither_image(img, SPECTRA_7_3_6COLOR_V2)
# Opt in to automatic tone + gamut compression for photosdithered=dither_image(img, SPECTRA_7_3_6COLOR_V2, tone="auto", gamut="auto")

See packages/python/README.md for full documentation.

JavaScript/TypeScript (packages/javascript/)

Published to npm as @opendisplay/epaper-dithering.

npm install @opendisplay/epaper-dithering
import{ditherImage,ColorScheme,DitherMode,SPECTRA_7_3_6COLOR_V2}from'@opendisplay/epaper-dithering';// ImageBuffer from Canvas API or Node.js (sharp, etc.)constdithered=ditherImage(imageBuffer,ColorScheme.BWR,{mode: DitherMode.BURKES});// Measured palette — calibrated color matchingconstdithered=ditherImage(imageBuffer,SPECTRA_7_3_6COLOR_V2);// Opt in to automatic tone + gamut compression for photosconstcompressed=ditherImage(imageBuffer,SPECTRA_7_3_6COLOR_V2,{tone: 'auto',gamut: 'auto'});

See packages/javascript/README.md for full documentation.

Features

  • Rust Core: All dithering logic in packages/rust/core/ — shared by both packages
  • 10 Dithering Algorithms: NONE, ORDERED, BURKES, FLOYD_STEINBERG, ATKINSON, STUCKI, SIERRA, SIERRA_LITE, JARVIS_JUDICE_NINKE, DIZZY
  • 10 Color Schemes: MONO, BWR, BWY, BWRY, BWGBRY (Spectra 6), GRAYSCALE_4, GRAYSCALE_16, SEVEN_COLOR (Spectra/ACeP 7), BWGBRY_SPLIT, GRAYSCALE_8 (library-local, e.g. Inkplate 10 — not a firmware wire value)
  • Measured Palettes: Calibrated RGB values for real displays, linked to their canonical firmware palette
  • OKLab Color Matching: Weighted Cartesian OKLab — preserves hue without the achromatic-attractor bug of LCH-weighted approaches
  • Pre-dither Knobs: Per-image exposure, saturation, shadows, highlights, and gamut compression — all orthogonal

Repository Structure

epaper-dithering/
├── packages/
│ ├── rust/
│ │ ├── core/ # Shared Rust algorithms (OKLab, dithering, tone/gamut)
│ │ └── wasm/ # wasm-bindgen bindings for JavaScript
│ ├── python/ # PyO3/maturin extension + Python wrapper
│ └── javascript/ # TypeScript wrapper + bundled WASM
├── docs/ # Calibration and color science documentation
└── .github/workflows/ # CI for all packages

Development

# Python (requires Rust toolchain: https://rustup.rs)cd packages/python
uv sync --all-extras
uv run maturin develop --release
uv run pytest tests/ -v
# JavaScriptcd packages/javascript
bun install
bun run test# Rustcd packages/rust
cargo test --workspace

Related Projects

Releases

Packages

Contributors

Languages