Image Display on E-Ink
Image Display on E-Ink
Overview
Section titled “Overview”This section covers displaying bitmap images on e-paper displays, including converting graphics to the required format, embedding them in the sketch, and combining images with text for professional-looking dashboards. After completing this section, you will be able to:
- Convert PNG/JPG images to XBM byte arrays for e-paper display
- Embed bitmap data in an Arduino sketch
- Display images on the e-paper screen
- Overlay text on top of background images
Prerequisites
Section titled “Prerequisites”Before starting this section, please ensure:
- GxEPD2 library is installed and working (see 02-03)
- Text rendering basics are understood (see 02-04)
- Basic image editing skills
Key Concepts
Section titled “Key Concepts”XBM Image Format
Section titled “XBM Image Format”The e-paper display requires images in XBM (X BitMap) format — a monochrome bitmap format where each pixel is represented by a single bit (0 = white, 1 = black).
How XBM Works:
Original Image (250×122 pixels)↓Conversion to XBM↓Each pixel → 1 bit (0=white, 1=black)250 × 122 = 30,500 bits = 3,813 bytes↓C byte array:
const unsigned char image_name[] = { 0xFF, 0x00, 0xFF, ... // Row 1 0x00, 0xFF, 0x00, ... // Row 2 ...};Key Points:
- XBM is purely black and white (no grayscale)
- Data is stored row by row, left to right
- Each byte represents 8 horizontal pixels
- Bytes are formatted as hexadecimal values
Image Size Constraints
Section titled “Image Size Constraints”The image must match the display resolution exactly:
| Display Size | Resolution | Max Image Dimensions |
|---|---|---|
| 1.54” | 200×200 | 200×200 pixels |
| 2.13” | 250×122 | 250×122 pixels |
| 2.9” | 296×128 | 296×128 pixels |
| 4.2” | 400×300 | 400×300 pixels |
| 7.5” | 800×480 | 800×480 pixels |
Implementation Steps
Section titled “Implementation Steps”Step 1: Prepare Your Image
Section titled “Step 1: Prepare Your Image”- Create or resize your image to match the display resolution
- Convert to black and white (no grayscale, no color)
- Save as PNG or BMP
Image Preparation Tips:
- Use high-contrast designs (pure black on pure white)
- Avoid thin lines (less than 2 pixels wide)
- Keep text in images large enough to be readable
- Solid areas work better than complex patterns
Step 2: Convert to XBM Using Online Tool
Section titled “Step 2: Convert to XBM Using Online Tool”Use an online converter to generate the XBM data:
- Go to image.online-convert.com/convert-to-xbm
- Upload your image
- Ensure settings:
- Format: XBM (X BitMap)
- Monochrome: Yes
- Size: Match display resolution
- Click Convert
- Download the
.xbmfile
Alternative: Use image2cpp (http://javl.github.io/image2cpp/):
- Upload image
- Set output format: Plain C array
- Brightness threshold: 128 (adjust as needed)
- Check Draw mode: Black on white
- Click Generate code
- Copy the generated byte array
Step 3: Create Header File
Section titled “Step 3: Create Header File”Create a new file called background.h in your sketch folder:
// Factory dashboard background image for 2.13" e-paper display (250×122)
#ifndef BACKGROUND_H#define BACKGROUND_H
const unsigned char background_image [] = { // Paste the converted XBM data here 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ... (full data omitted for brevity — include all bytes for your display size) 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif // BACKGROUND_HStep 4: Display the Image
Section titled “Step 4: Display the Image”#include <GxEPD2_BW.h>#include "background.h" // Include the bitmap header
#define EPD_CS 5#define EPD_DC 17#define EPD_RST 16#define EPD_BUSY 4
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display( GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));
void setup() { Serial.begin(115200); display.init(115200); display.setRotation(1);
// Clear screen display.fillScreen(GxEPD_WHITE);
// Draw bitmap at position (0,0) — full screen display.drawInvertedBitmap( 0, // X position 0, // Y position background_image, // Bitmap data display.width(), // Width display.height(), // Height GxEPD_BLACK // Color );
display.display(); Serial.println("Image displayed!");}
void loop() {}Note:
drawInvertedBitmap()is used because XBM format treats 0 as black and 1 as white, while the e-paper library expects the opposite.
Alternative: If your XBM uses standard encoding, use drawBitmap() instead:
display.drawBitmap(0, 0, background_image, display.width(), display.height(), GxEPD_BLACK);Step 5: Combine Image with Text Overlay
Section titled “Step 5: Combine Image with Text Overlay”This is the most practical use case — display a background design with dynamic text on top:
#include <GxEPD2_BW.h>#include "background.h"
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display( GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));
void setup() { display.init(115200); display.setRotation(1);
// Step 1: Draw background display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, background_image, display.width(), display.height(), GxEPD_BLACK);
// Step 2: Overlay text on top of the background display.setFont(&FreeMonoBold18pt7b); display.setCursor(90, 55); display.setTextColor(GxEPD_BLACK); display.print("25.5");
display.setFont(&FreeMono9pt7b); display.setCursor(95, 80); display.print("Celsius");
display.setCursor(85, 105); display.print("Humidity: 60%");
display.display();}
void loop() {}Step 6: Display Weather Icons
Section titled “Step 6: Display Weather Icons”For weather forecast dashboards, you can embed small icons:
const unsigned char sun_icon[] = { 0x00, 0x18, 0x00, // Binary icon data for sun symbol (16×16) 0x00, 0x3C, 0x00, // ... (16×16 = 32 bytes)};
const unsigned char cloud_icon[] = { // Cloud icon data};
const unsigned char rain_icon[] = { // Rain icon data};
void displayWeatherIcon(int x, int y, const char* condition) { if (strcmp(condition, "sunny") == 0) { display.drawInvertedBitmap(x, y, sun_icon, 16, 16, GxEPD_BLACK); } else if (strcmp(condition, "cloudy") == 0) { display.drawInvertedBitmap(x, y, cloud_icon, 16, 16, GxEPD_BLACK); } else if (strcmp(condition, "rainy") == 0) { display.drawInvertedBitmap(x, y, rain_icon, 16, 16, GxEPD_BLACK); }}Memory Considerations
Section titled “Memory Considerations”Bitmap images consume significant flash memory:
| Display Size | Resolution | XBM Size (bytes) |
|---|---|---|
| 1.54” | 200×200 | ~5,000 bytes |
| 2.13” | 250×122 | ~3,813 bytes |
| 2.9” | 296×128 | ~4,736 bytes |
| 4.2” | 400×300 | ~15,000 bytes |
| 7.5” | 800×480 | ~48,000 bytes |
Note: ESP32 typically has 4MB flash, so even a full-screen 7.5” image only uses ~1.2% of available flash. However, PROGMEM storage may be needed for very large images.
For ESP32, XBM data is stored in flash automatically by the compiler. No special PROGMEM handling is needed (unlike AVR-based Arduino boards).
Verification
Section titled “Verification”- Image displays at correct position and size
- No distortion or pixel shifting
- Text overlay appears at correct position on top of image
- Icons (if used) display clearly
- Contrast is good (clear black/white separation)
Troubleshooting
Section titled “Troubleshooting”Issue 1: Image Appears Distorted
Section titled “Issue 1: Image Appears Distorted”Symptom:
- Image is stretched, squished, or shifted
Solution:
- Verify image dimensions match display resolution exactly
- Check that width and height parameters in
drawInvertedBitmap()are correct - Ensure rotation is set before drawing the image
Issue 2: Image Appears Inverted (Colors Reversed)
Section titled “Issue 2: Image Appears Inverted (Colors Reversed)”Symptom:
- White areas appear black and vice versa
Solution:
// Option 1: Use the other bitmap functiondisplay.drawBitmap(0, 0, image_data, width, height, GxEPD_BLACK);
// Option 2: Invert the data using drawInvertedBitmapdisplay.drawInvertedBitmap(0, 0, image_data, width, height, GxEPD_BLACK);Issue 3: Compilation Error — “Image too large”
Section titled “Issue 3: Compilation Error — “Image too large””Symptom:
- Compiler error about array size
Solution:
- Split large images into multiple smaller sections
- Use lower resolution images
- Consider using a background with fewer details
Best Practices
Section titled “Best Practices”- ✅ Prefer simple, high-contrast designs — They look better on e-paper
- ✅ Use
drawInvertedBitmap()to handle XBM byte ordering - ✅ Keep image files as separate .h files — Improves code organization
- ❌ Avoid thin horizontal lines (< 2px) — They may not render clearly
- ❌ Don’t use gradients — E-paper cannot display shades of gray
- ❌ Avoid updating background image with every refresh — Draw it once and overlay text changes when possible
Summary
Section titled “Summary”- Images must be in XBM format — Monochrome bitmaps with 1-bit per pixel
- Image dimensions must match display resolution exactly
- Use
drawInvertedBitmap()ordrawBitmap()depending on XBM encoding - Text can be overlaid on images — Draw the background first, then add dynamic text
- Organize bitmap data in separate .h files for maintainability
References
Section titled “References”Target Audience: Alibaba.com IoT Pre-sales Engineers
Status: ✅ Completed