Convert TrueType/OpenType fonts to C bitmap arrays for e-paper displays
Automatic batch processing tool for generating Arduino/ESP32 compatible bitmap fonts from TTF/OTF files. Designed for Waveshare e-paper displays and GUI_Paint library.
- β
Automatic batch processing - Drop fonts in
input/, run one command - β Standard sizes - Generates 12, 14, 16, 18, 20, 24, 28, 32px automatically
- β Organized output - Each font in its own subdirectory
- β Descender support - Properly handles lowercase g, j, p, q, y characters
- β Visual debugging - Comments show character bitmaps in hex
- β Zero configuration - Works out of the box
- β Cross-platform - Windows, macOS, Linux
pip install -r requirements.txtOr manually:
pip install PillowPlace .ttf or .otf files in the input/ directory:
input/
βββ Monocraft.ttf
βββ IBMPlexMono-Regular.ttf
βββ Roboto-Regular.ttf
python generate_all.pyFind generated files in output/ organized by font:
output/
βββ Monocraft/
β βββ Monocraft12.cpp
β βββ Monocraft12.h
β βββ Monocraft14.cpp
β βββ Monocraft14.h
β βββ ...
β βββ Monocraft32.h
βββ IBMPlexMono/
β βββ IBMPlexMono12.cpp
β βββ ...
βββ Roboto/
βββ ...
Copy desired .cpp and .h files to your Arduino project:
cp output/Monocraft/Monocraft16.* YourProject/Add extern declarations to your fonts.h:
// Custom fonts
#ifdef FONT_ENABLE_MONOCRAFT16
extern sFONT Monocraft16;
#endif
#ifdef FONT_ENABLE_MONOCRAFT24
extern sFONT Monocraft24;
#endif// Define BEFORE #include "fonts.h"
#define FONT_ENABLE_MONOCRAFT16
#define FONT_ENABLE_MONOCRAFT24
#include "fonts.h"Paint_DrawString_EN(x, y, "Hello World", &Monocraft16, BLACK, WHITE);
Paint_DrawString_EN(x, y, "Larger Text", &Monocraft24, BLACK, WHITE);See examples/arduino_example.ino for complete code.
| Size | Use Case | Typical Usage |
|---|---|---|
| 12px | Tiny labels | Metadata, timestamps, fine print |
| 14px | Small text | Secondary information, captions |
| 16px | Body text | UI labels, descriptions, main text |
| 18px | Emphasized | Important labels, highlighted info |
| 20px | Subheaders | Section titles, categories |
| 24px | Headers | Screen titles, primary headings |
| 28px | Large headers | Main titles, emphasis |
| 32px | Display text | Time display, large numbers |
Edit STANDARD_SIZES in generate_all.py:
STANDARD_SIZES = [10, 15, 22, 30] # Your custom sizesPerfect for aligned layouts, tables, numeric displays:
- Monocraft - Pixel art aesthetic, gaming/retro projects
- IBM Plex Mono - Professional, clean, corporate
- JetBrains Mono - Developer-friendly, code displays
- Roboto Mono - Material Design, modern
- Courier New - Classic, universally available
Better for readability in longer text:
- Roboto - Modern, geometric, Android standard
- Open Sans - Friendly, readable, web-optimized
- Inter - UI-optimized, excellent small sizes
For visual impact:
- Roboto Bold - Strong emphasis, same family as Roboto
- Bebas Neue - Tall, condensed, impactful headers
- Google Fonts - Free, open-source
- Font Squirrel - Commercial-use fonts
- IBM Plex - Professional fonts
- JetBrains Mono - Code font
Typical memory per font (95 ASCII characters):
| Size | Memory | ESP32 % (8MB) |
|---|---|---|
| 12px | ~1.5 KB | 0.02% |
| 16px | ~3 KB | 0.04% |
| 24px | ~7 KB | 0.09% |
| 32px | ~12 KB | 0.15% |
Example: 4 fonts Γ 3 sizes each = ~50 KB total (0.6% of ESP32 flash)
Memory is negligible for most projects. Generate all sizes you might need.
python .\tools\analyze_font.py '.\input\YourFont.ttf'Shows natural height at each size to verify fit.
Default: ASCII 0x20-0x7E (printable characters: space through tilde)
To modify, edit generate_font_bitmap() in generate_all.py:
for ascii_code in range(0x20, 0xFF): # Extended ASCII
for ascii_code in range(0x30, 0x3A): # Only digits 0-9python font_generator.py input/Font.ttf 18 CustomName18Creates output/CustomName18.cpp and .h
Problem: input/ directory is empty
Solution: Place .ttf or .otf files in input/ directory
Problem: Font natural height exceeds target size
Solution:
- Run
python analyze_font.py input/YourFont.ttf - Check "natural_height" in output
- Use larger size (e.g., 18px instead of 16px)
Problem: Natural height > target cell height
Solution: Increase generation size by 2-4px
Problems:
- "sFONT was not declared"
- "Undefined reference to FontName"
Solutions:
- Verify
fonts.hhasextern sFONT FontName;declaration - Check
#define FONT_ENABLE_Xis BEFORE#include "fonts.h" - Ensure both
.cppand.hare in project directory - Verify files compiled (check Arduino IDE output)
Problem: Alignment or spacing issues
Solution:
- Check natural_height in generated
.cppheader comments - Verify you're using correct font size
- Test with different sizes to find optimal
E-Paper-Font-Generator/
βββ README.md β This file
βββ LICENSE β MIT License
βββ requirements.txt β Python dependencies
βββ .gitignore β Git ignore rules
β
βββ generate_all.py β Main batch generator
βββ font_generator.py β Single font generator
βββ analyze_font.py β Font analysis tool
βββ setup.py β Initial setup helper
β
βββ input/ β Place your TTF/OTF files here
β βββ (your fonts)
β
βββ output/ β Generated files (auto-created)
β βββ FontName/
β βββ FontName12.cpp
β βββ FontName12.h
β βββ FontName14.cpp
β βββ ...
β
βββ examples/ β Example code
β βββ arduino_example.ino β Complete Arduino example
β βββ (jupyter notebooks)
β
βββ docs/ β Additional documentation
β βββ FONT_LIBRARY_GUIDE.md β Font recommendations
β βββ (development notes)
β
βββ tools/ β Development versions
βββ (generator iterations)
- Font Loading - Uses PIL (Pillow) to load TTF/OTF files
- Rasterization - Renders each character at target pixel size
- Measurement - Calculates natural character bounds (handles descenders)
- Centering - Positions characters vertically within target cell
- Bitmap Conversion - Converts to 1-bit monochrome bitmap
- C Array Generation - Creates byte arrays with visual comments
- sFONT Wrapping - Packages in Waveshare-compatible structure
Tested With:
- Waveshare 4.2" e-paper display (400Γ300px)
- ESP32-S3 DevKit C-1
- Arduino IDE 2.x
- GUI_Paint library
Should Work With:
- All Waveshare e-paper displays (any size)
- Arduino Uno, Mega, Due
- ESP8266, ESP32 (all variants)
- STM32 (Blue Pill, Nucleo)
- Any microcontroller using GUI_Paint library
MIT License - Free for personal and commercial use
See LICENSE for full text.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
- Font Rendering: Pillow (PIL Fork)
- Compatible With: Waveshare e-paper libraries
- Inspired By: Pixel font community and bitmap font tools
- Created For: The Watcher Project - ESP32-S3 e-ink clock
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: See
docs/directory
- GUI interface for font selection
- Preview mode before generating
- Support for non-Latin character sets
- Font subsetting (reduce memory)
- Anti-aliasing option for grayscale displays
- Direct integration with PlatformIO
See CHANGELOG.md for version history.
Made with β€οΈ for embedded developers
If this tool helped your project, please give it a β on GitHub!