A C++23 library for controlling Waveshare e-paper displays on Raspberry Pi, featuring transparent sleep/wake management and a fluent builder API.
[
](LICENSE)
See docs for complete documentation.
β¨ Quick Example
int main() {
auto display = create_display<EPD27, MonoFramebuffer>(device, DisplayMode::BlackWhite,
Orientation::Landscape90).value();
display->clear(Color::White);
display->draw(
display->text("Hello, libepaper!")
.at(20, 70)
.font(&Font::font24())
.foreground(Color::Black)
.background(Color::White)
.build()
);
display->refresh();
return 0;
}
Definition device.hpp:158
auto init() -> std::expected< void, Error >
Initialize the GPIO (libgpiod) and SPI (SPIdev) interfaces.
Definition device.cpp:152
Bitmap font rendering for e-paper displays.
π See examples/ for complete applications.
π― Features
- Multiple Display Modes: Black/white, 4-level grayscale, and color displays (BWR, BWY, Spectra 6-color)
- Complete Drawing API: Points, lines, rectangles, circles, text rendering with multiple font sizes
- Image Support: Load and display PNG/JPEG images with automatic color conversion and dithering
- Flexible Orientation: Rotate display 0Β°, 90Β°, 180Β°, 270Β° with automatic coordinate transformation
- Transparent Power Management: Auto-sleep prevents burn-in, auto-wake on refreshβzero manual intervention
- Hardware Abstraction: Compile-time driver selection with MockDriver for testing without physical hardware
- Multiple Framebuffer Types: Single-plane (mono/grayscale) and multi-plane (color) with automatic color mapping
- Builder Pattern API: Fluent, chainable drawing commands with sensible defaults
- Comprehensive Error Handling: Type-safe error propagation with
std::expected (no exceptions)
- C++23: Built with concepts,
std::span, ranges, and zero-cost abstractions
Driver Selection
All drivers are compiled into the library. To use a driver:
- Include the driver header for your display:
- Use the driver class in
create_display<>(): auto display = create_display<EPD27, MonoFramebuffer>(device, DisplayMode::BlackWhite,
Orientation::Landscape90).value();
Available Drivers
| Driver | Hardware | Dimensions | Color Support |
| EPD27 | Waveshare 2.7" | 176Γ264 | B/W, Grayscale4 |
| **MockDriver** | Software only | Configurable | B/W (outputs PNG) |
π See Doxygen documentation for detailed driver API specifications
π Quick Start
Use as a dependency in your CMake project
Link the libepaper target via CMake FetchContent:
include(FetchContent)
FetchContent_Declare(
epaper
GIT_REPOSITORY https://github.com/johanns/libepaper
GIT_TAG main
)
FetchContent_MakeAvailable(epaper)
add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE libepaper)
Then build your project as usual (Debug or Release mode).
Run examples from the repository
Install dependencies and set up the system:
Build the library (Release by default, use --type Debug for debug builds):
./bin/build
# ./bin/build --type Debug
Run an example:
./build/examples/crypto_dashboard/crypto_dashboard
π§© Alternative Integration Options
For other integration methods:
Option A β Vendored submodule with add_subdirectory
git submodule add https://github.com/johanns/libepaper external/libepaper
git submodule update --init --recursive
add_subdirectory(external/libepaper)
add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE libepaper)
Option B β System-wide installation
cd libepaper
./bin/setup
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
sudo cmake --install build
find_path(EPAPER_INCLUDE_DIR epaper/display.hpp PATH_SUFFIXES epaper)
find_library(EPAPER_LIBRARY NAMES epaper)
add_executable(my_app src/main.cpp)
target_include_directories(my_app PRIVATE ${EPAPER_INCLUDE_DIR})
target_link_libraries(my_app PRIVATE ${EPAPER_LIBRARY} gpiod m)
βοΈ Build Configuration
Build with Release (default) or Debug optimization:
Using our script:
./bin/build # Release (default, EPD27 driver)
./bin/build --type Debug # Debug build
./bin/build --driver Mock tests # Build tests with MockDriver (no hardware)
./bin/build examples --type Release
Using raw CMake:
# Standard build
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
# Build with MockDriver for testing without hardware
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DLIBEPAPER_DRIVER=Mock
cmake --build build -j
./build/tests/test_drawing_primitives # Outputs PNG to mock_output/
π Documentation
The library provides multiple documentation resources:
π API Documentation
π Guides
| Document | Description |
| Examples | Tutorials and working examples |
| Contributing Guide | Commit format and PR process |
π‘ Quick Reference
Core Concepts:
- Display: Unified interface coordinating driver and framebuffer (epaper::Display)
- Driver: Hardware abstraction (SPI/GPIO communication) (Driver concept)
- Framebuffer: Pixel buffer with color encoding (MonoFramebuffer)
- Builder API: Fluent drawing commands (Builders)
Essential Headers:
Image loading/saving utilities using stb_image library.
Common Patterns:
auto display = create_display<EPD27>(device, DisplayMode::BlackWhite).value();
display->clear(Color::White);
display->line({0, 0}, {100, 100}).color(Color::Black).draw();
display->rectangle({10, 10}, {50, 50}).fill(DrawFill::Full).draw();
display->refresh();
display->sleep();
display->wake();
π€ Contributing
We welcome contributions! Please see CONTRIBUTING.md for our commit format and PR process.
ποΈ Adding New Display Support
The abstract driver interface makes adding new displays straightforward:
- Implement the
Driver concept (see driver_concepts.hpp)
- Create driver-specific pin configuration struct
- Implement display protocol (init, refresh, sleep/wake)
- Add comprehensive Doxygen documentation
Reference Implementation: See EPD27 driver for a complete example.
Driver Interface Requirements:
- Satisfy
Driver concept constraints (width(), height(), init(), display(), etc.)
- Define
driver_traits specialization for capability advertisement
- Use
std::expected<T, Error> for all fallible operations
- Follow RAII patterns for resource management
Testing: Use MockDriver for development without hardware.
π§ Development
Requirements
- Raspberry Pi OS, Debian 12 (Bookworm), or Ubuntu 24.04 (Jammy Jellyfish)
- C++23 capable compiler (GCC 14+ or Clang 18+)
- CMake 3.25+
- libgpiod library (user-space GPIO access)
- Raspberry Pi with SPI enabled
- User in
gpio and spi groups (no sudo required)
π License
MIT License - see [LICENSE](LICENSE) file for details. Copyright (c) 2021 - 2026 Johanns Gregorian (https://github.com/johanns)