DitherInk

4.2" e-paper image converter

4.2-inch e-paper panels have a resolution of 400×300 pixels. They are available as black & white, 4-level grayscale, 3-color (black/white/red). Pick the resolution and colors that match your panel, upload a photo and DitherInk will crop it, dither it with its tuned Atkinson algorithm and give you a file your firmware can use directly.

4.2" 400×300

Native resolution400 × 300 (120,000 pixels, 4:3)
Portrait image size300 × 400
Landscape image size400 × 300
ColorsBuffer format.bin size
Black & Whitemono_1bpp15,000 bytes (14.6 KB)
4-level Grayscalegray_2bpp30,000 bytes (29.3 KB)
3-color (Black/White/Red)tri_2plane30,000 bytes (29.3 KB)

Convert an image for 4.2" 400×300 →

Portrait or landscape?

The panel always receives its buffer in its native 400×300 layout. If your frame stands upright, choose Portrait: you crop a 300×400 image and DitherInk rotates the buffer 90° counterclockwise before writing the file. If your driver expects a different rotation, change it under Advanced output options.

Which file should I download?

  • .h: a C array you can #include in an Arduino or ESP-IDF project. Easiest for a single fixed image.
  • .bin: the raw frame buffer. Store it on an SD card or in flash and stream it to the panel. Best when images change.
  • .png: an indexed PNG whose pixel values are the color codes. Handy for Python on a Raspberry Pi.
  • .bmp: an indexed bitmap for photo frames and tools that read BMP files.
Ad

Tips for black & white

High-contrast images, line art and text work best. For photos, Auto mode lifts the shadows a little so dark areas do not collapse into solid black.

Example code (400×300, Black & White)

Arduino / ESP-IDF with the .h file

#include "my_image.h"  // downloaded from DitherInk

// MY_IMAGE_WIDTH x MY_IMAGE_HEIGHT = 400 x 300, mono_1bpp
// Color codes: black=0, white=1
// The buffer is already in the panel's native orientation.

void showImage() {
  epd_write_frame(my_image, MY_IMAGE_SIZE);  // your driver's full-frame write
  epd_refresh();
}

Replace epd_write_frame and epd_refresh with the functions your display driver provides. Most drivers have a function that takes a full frame buffer.

ESP32 loading the .bin file from flash

#include <LittleFS.h>

constexpr size_t FRAME_BYTES = 15000;
static uint8_t frame[FRAME_BYTES];

bool loadFrame(const char* path) {
  File f = LittleFS.open(path, "r");
  if (!f || f.size() != FRAME_BYTES) return false;  // wrong size = wrong panel settings
  f.read(frame, FRAME_BYTES);
  f.close();
  return true;
}

Python (Raspberry Pi) reading the .bin file

import numpy as np

data = np.fromfile("my_image.bin", dtype=np.uint8)
assert data.size == 15000
bits = np.unpackbits(data).reshape(300, -1)[:, :400]  # 1 = white, 0 = black

Not sure about your panel's details? See how e-paper frame buffers are laid out.