This e-paper image converter turns any image into the byte buffers a Waveshare or Good Display e-ink panel needs — including proper 3-color black/white/red output with a separate red layer. Drop in a PNG or JPG, pick your panel, and copy a const unsigned char buffer (or two, for tri-color) ready for display.Display(). Everything runs in your browser, so it works offline and never uploads your art. It is purpose-built for e-paper, unlike the OLED-focused image2cpp converter.
Why e-paper is different from OLED
E-paper (e-ink) displays are bistable: once an image is drawn, the panel holds it with zero power, which is why they are perfect for battery shelf labels, weather dashboards and name badges. But that physics changes how you feed them images. Refreshes are slow (seconds, not milliseconds), and many panels render more than two colors by stacking pigment layers. A three-color Waveshare panel can show black, white and red — but only by accepting two separate 1-bit buffers, one per non-white color.
How 3-color (black/white/red) buffers work
For a tri-color panel you send two bitmaps of identical dimensions:
- The black buffer — a bit controls whether each pixel is black.
- The red buffer — a bit controls whether each pixel is red.
A pixel that is black in neither buffer stays white (the panel's background). This converter analyses your source image: strongly red pixels are routed to the red layer, dark non-red pixels become black, and everything else is left white. That means you can design a poster in any image editor — red headline, black body text — and get both layers generated automatically. Most Waveshare panels treat a 0 bit as the colored pixel (black or red) and a 1 bit as white; this tool follows that convention. If your panel is reversed, toggle Invert.
Wiring a Waveshare e-paper module (SPI)
Waveshare e-paper HATs and bare panels talk SPI. A common ESP32 wiring:
- VCC → 3.3V GND → GND
- DIN (MOSI) → GPIO23 CLK (SCK) → GPIO18
- CS → GPIO5 DC → GPIO17 RST → GPIO16 BUSY → GPIO4
Install the Waveshare e-Paper library (download it from Waveshare's GitHub for your exact model — the class name encodes the size and color, e.g. Epd in the epd2in9b folder for a 2.9" tri-color panel).
Full Arduino example — 3-color panel
Generate your buffers above (named poster here), then:
#include "epd2in9b_V3.h" // 2.9" black/white/red
Epd epd;
// <-- paste poster_black[] and poster_red[] here -->
void setup() {
if (epd.Init() != 0) return;
epd.Display(poster_black, poster_red);
epd.Sleep(); // ALWAYS sleep e-ink after a refresh
}
void loop() {}
For a plain black/white panel the call is simply epd.Display(poster); with the single buffer this tool generates in B/W mode. Calling Sleep() after every refresh is important — leaving an e-ink panel powered in its active state can damage it over time.
Getting a clean e-ink result
E-paper has no grayscale on a 2-color panel, so photos need dithering just like an OLED — Floyd-Steinberg and Atkinson both work well. For tri-color posters, keep your reds saturated and pure in the source image so the red-detection routing is unambiguous. Text and line art look sharpest with the Binary threshold mode and no dithering.
Power, refresh and longevity tips
Because e-ink holds its image without power, the ideal pattern is: wake the MCU, draw one frame, then deep-sleep both the panel and the microcontroller. Avoid full refreshes more often than the datasheet allows — rapid repeated refreshing causes ghosting and shortens panel life. Many modules support a faster partial refresh for small regions (a clock digit, a sensor value) while reserving the slow full-screen refresh for a periodic clean-up pass. The full-frame buffer this converter produces is exactly what you load before either kind of refresh, so it fits both workflows.
Need monochrome OLED output instead? Use the u8g2 converter or the classic image2cpp tool. Building a touchscreen GUI? See the LVGL converter.