LCDGFX LCD display driver  1.2.0
Lightweight graphics library for SSD1306, SSD1325, SSD1327, SSD1331, SSD1351, SH1106, SH1107, IL9163, ST7735, ST7789, ILI9341, PCD8544 displays over I2C/SPI
Fonts: generating and format reference

lcdgfx renders text from font tables stored in PROGMEM. You can use the fonts that ship with the library, or generate your own from any TTF (or a GLCD-exported .c file) with the tools/fontgenerator.py script.

This page covers:

Generating a font

fontgenerator.py needs freetype-py (pip install freetype-py). The generated C array is written to stdout, so redirect it into a header/source file.

# Variable-width font (recommended): each glyph keeps its natural width
./fontgenerator.py --ttf consola.ttf -s 8 -g 0 127 -f new > my_font.cpp
# Fixed-width font: every glyph padded to the width of the widest one
./fontgenerator.py --ttf consola.ttf -s 8 -fw -g 0 127 -f new > my_font.cpp
# Preview the result in the console while generating (-d = demo text)
./fontgenerator.py --ttf consola.ttf -s 8 -g 0 127 -f new -d -t "Hello 12:45"

-g <first> <count> selects a block of characters. <first> is a symbol, a decimal code, or a 0x.. hex code; <count> is *(number of chars − 1)*. Repeat -g to pack several blocks (e.g. digits + Latin + Cyrillic) into one font while skipping the gaps in between:

./fontgenerator.py --ttf consola.ttf -s 10 \
-g 48 9 -g 65 25 -g 97 25 -f new > alnum_font.cpp

Use the font in your sketch:

display.setFixedFont(my_font); // fixed font (type 0/1)
display.setFreeFont(free_my_font8x13); // free / variable font (type 2)

The generated array name encodes the size, e.g. free_consola6x13. Look at the extern const uint8_t ... line at the top of the output for the exact symbol to pass to setFreeFont().


Per-group exact width

*(New format only — the recommended fix for uneven spacing.)*

A variable-width font keeps every glyph at its natural width, which is usually what you want — but some characters are drawn very narrow. A space or colon may be only 1–2 px wide, so a string like Cookies 325 12 mins looks cramped even with getFont().setSpacing(1). Forcing the whole font to fixed width (-fw) over-corrects: now every glyph is as wide as W, wasting space.

The optional 3rd argument of -g solves this per block:

-g <first> <count> <width>

It forces every char in that group to an exact pixel width, keeping the glyph centered — narrow chars are padded with blank columns on both sides, wider chars are cropped equally from both sides. The width is stored per char in the jump table, so it costs nothing at runtime and combines cleanly with setSpacing().

# space -> 5 px, colon -> 3 px, underscore -> 5 px, everything else natural
./fontgenerator.py --ttf consolas.ttf -s 10 \
-g 32 0 5 \
-g 58 0 3 \
-g 95 0 5 \
-g 48 9 -g 65 25 -g 97 25 \
-f new > consolas_10.cpp

Notes:

  • Padding is split as evenly as possible; an odd remainder puts the extra column on the right.
  • Cropping to a width narrower than the glyph's ink prints a warning on stderr (char U+XXXX cropped ...) — the glyph may lose pixels.
  • Do not combine a per-group width with -fw. -fw forces one global width onto every char and would override the per-group values.

Command-line options

Option Meaning
--ttf <file> Use a TTF file as the source.
--glcd <file> Use a GLCD-exported .c file as the source.
-s <N> Font size (point size, not pixels).
-SB <N> Limit glyph height to N pixels (bottom pixels are cut).
-fh Fixed height (pad all glyphs to the tallest).
-fw Fixed width (pad all glyphs to the widest).
-g <S> <E> [W] Add a char block: first char S, count-minus-1 E, optional exact width W (new format only).
-f old Old fixed format (1.7.6 and below).
-f new New free/variable format (1.7.8 and above).
-d Print demo text to the console.
-t <text> Text to use for the -d demo.
--demo-only Print demo text and exit (no font emitted).
--output-file <file> Write the font to a file directly (instead of stdout).

Binary format reference

For people writing tools that emit or parse lcdgfx fonts. Every field is one byte unless noted.

Fixed font format (TYPE 0 or 1)

TYPE | WIDTH | HEIGHT | FIRSTCHAR
FIRSTUNICODE(MSB) | FIRSTUNICODE(LSB) | COUNT // type 1 only
--- FONT DATA: COUNT * WIDTH * ceil(HEIGHT/8) bytes
  • TYPE 0 — ASCII 0–127 plus extended 128–255. Generated by the standalone LCD font generator GUI only.
  • TYPE 1 — fixed cell size, but supports Unicode blocks. Generate with:
    ./fontgenerator.py --ttf consola.ttf -s 8 -g 0 127 -f old -d > output.cpp
  • WIDTH / HEIGHT — fixed cell size of each glyph.
  • FIRSTCHAR — meaningful only for TYPE 0 (first ASCII code in the table).

Free / variable font format (TYPE 2)

TYPE | WIDTH | HEIGHT | FIRSTCHAR
FIRSTUNICODE(MSB) | FIRSTUNICODE(LSB) | COUNT
--- JUMP TABLE (one entry per char):
OFFSET(MSB) | OFFSET(LSB) | WIDTH | HEIGHT
--- FONT DATA
  • TYPE — always 2.
  • WIDTH (header) — unused for type 2.
  • HEIGHT (header) — max glyph height of the font.
  • FIRSTCHAR (header) — unused for type 2.
  • JUMP TABLE WIDTH / HEIGHT — the per-char dimensions. This is where a per-group exact width ends up, which is why it is free at render time.

Squix format (reference)

WIDTH | HEIGHT | FIRSTCHAR | COUNT
--- JUMP TABLE:
OFFSET(MSB) | OFFSET(LSB) | BYTES | WIDTH
--- FONT DATA