https://github.com/mtraver/matrixfont
Easily make BDF fonts from an easy-to-edit, visual text-based format
https://github.com/mtraver/matrixfont
adafruit bdf circuitpython font fonts golang led-matrix led-matrix-display led-matrix-displays
Last synced: 12 days ago
JSON representation
Easily make BDF fonts from an easy-to-edit, visual text-based format
- Host: GitHub
- URL: https://github.com/mtraver/matrixfont
- Owner: mtraver
- License: mit
- Created: 2026-05-08T06:39:26.000Z (27 days ago)
- Default Branch: main
- Last Pushed: 2026-05-17T00:08:42.000Z (18 days ago)
- Last Synced: 2026-05-17T02:34:28.161Z (18 days ago)
- Topics: adafruit, bdf, circuitpython, font, fonts, golang, led-matrix, led-matrix-display, led-matrix-displays
- Language: Go
- Homepage:
- Size: 44.9 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Easily create and edit fonts for LED matrices
Create a font via an easy-to-edit, visual, text-based format.
Define your font like this:
```text
CHAR 'A'
.###..
#...#.
#...#.
#####.
#...#.
#...#.
#...#.
```
That's all you need to create a fully-functional font! It will contain the single glyph 'A'.
Create a .bdf file from it like this:
```sh
go run ./cmd/matf2bdf my_font.matf my_font.bdf
```
Load `my_font.bdf` onto your Adafruit Matrix Portal or whatever and off you go!
## Advanced usage
Here's a .matf font file that demonstrates all the features of the format:
```text
// These optional key-value pairs define font metadata used
// to generate an XLFD font name string for the BDF file.
FOUNDRY mtraver
FAMILY ledmatrix
WEIGHT Light
SLANT R // Roman (upright)
WIDTH Normal
STYLE Sans Serif
SPACING P // Proportional
CHARSET_REGISTRY ISO8859
CHARSET_ENCODING 1
// DPI is used in the XLFD font name and also used to calculate the font's
// size. If not given a default value of 75 will be used.
DPI 6 // The DPI of a 4mm pitch LED matrix is 6.4.
// Glyphs are defined by a CHAR line containing the codepoint
// specified as one of:
// - A hex value with 0x prefix (e.g. 0x41)
// - A hex value with U+ prefix (e.g. U+0041)
// - A decimal value (e.g. 65)
// - The character itself in single quotes (e.g. 'A')
//
// The CHAR line is followed by a grid of '#' and '.'
// characters representing the glyph's bitmap, where
// '#' indicates a lit/activated pixel.
CHAR 0x41 // 'A'
.###..
#...#.
#...#.
#####.
#...#.
#...#.
#...#.
// Glyph specified as decimal.
CHAR 66 // 'B'
####..
#...#.
#...#.
####..
#...#.
#...#.
####..
// Glyph specified as single-quoted character.
CHAR 'C'
.###..
#...#.
#.....
#.....
#.....
#...#.
.###..
// XOFF and YOFF can be used to shift the glyph left/right (XOFF)
// and up/down (YOFF). In this case they're used to move the comma
// left toward the preceding glyph and down two pixels below the
// baseline.
CHAR 0x2c // ","
XOFF -1
YOFF -2
...
...
...
...
.#.
.#.
#..
// ADVANCE specifies how far the cursor is moved after rendering
// the glyph. The default is to advance the cursor the width of
// the glyph and as such ADVANCE usually doesn't need to be given
// (note above how 'A', 'B', and 'C' include an empty column on the
// right, allowing the default advance to provide space between glyphs).
//
// In this example we implement the space glyph by simply specifying
// ADVANCE 2. There's no ink in a space; it's just an advance of the
// cursor.
//
// This is also a special case: the only time that a glyph is
// allowed to be empty (i.e., no grid of '#' and '.') is when a
// non-zero ADVANCE is given.
CHAR 0x20 // " "
ADVANCE 2
```
## Modify an existing font
Want to start from `terminalio.FONT` or a font that you've converted from .ttf to .bdf/.pcf and modify it? You can do that! First you'll need to export it in matrixfont format from your CircuitPython device. Copy `font_utils.py` onto your device and use it like this:
```python
import terminalio
import font_utils
# Export the terminalio default font.
print("======= START FONT =======")
font_utils.print_glyphs(terminalio.FONT)
print("======= END FONT =======")
# Export any font file.
print("======= START FONT =======")
font_utils.print_glyphs("lib/font_free_mono_12/font.pcf")
print("======= END FONT =======")
```
Save the output between the START FONT and END FONT lines to a file, edit the glyphs as you please, and convert it to .bdf using `matf2bdf` as described above.
## Background
When building my first LED matrix project (using [a matrix from Adafruit](https://www.adafruit.com/category/327)) I started off using CircuitPython's built-in `terminalio.FONT`. It looks good on an LED matrix but it's taller than it needs to be. Given the very low DPI of LED matrices (a 4mm pitch LED matrix has a DPI of 6.4), I wanted a more compact but still readable font. Space is at a premium!
Aside from `terminalio.FONT`, the easy and well-documented font options are:
1. The pre-made fonts from Adafruit (download one of the releases, which contain .pcf files): https://github.com/adafruit/circuitpython-fonts
2. Using `otf2bdf` to convert any .ttf file to [BDF](https://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format) format, which CircuitPython supports. The .bdf can then then be converted to .pcf if you like.
I was unsatisfied with these options. The core issue is that taking a modern, detailed font and displaying it on an exceptionally low DPI LED matrix will either 1) require a huge number of pixels (perhaps 15 pixels tall, which on a 64x32 matrix means _at most_ two lines of text in landscape orientation) or 2) downsampling to the point of illegibility. For example, FreeMono 8, 10, and 12, all included in the Adafruit font bundle, look quite bad. Capitals in FreeMono 12 are 7 pixels tall and with 7 pixels it's possible to achieve attractive, legible text on an LED matrix. I wanted to make that happen!
Given all this I set out to create my own fonts specifically designed for LED matrices and thus this tool was born. I hope it proves useful to someone else!