Generated header format reference
This page documents every part of the .h file produced by
/font. The examples below are real output for JetBrains Mono Bold at
24×22 px with the character set trimmed to space, digits, and colon (12 glyphs).
Array name and identifiers
The base name used for the array, macros, and (optionally) the C++ wrapper class comes
from Array name in Header Options, or — if left blank — is derived
automatically from the font name and dimensions via
Identifiers.BuildDefaultArrayName(fontName, frameHeight, frameWidth):
"JetBrains Mono Bold", height=24, width=22 -> font_jetbrains_mono_bold_24x22
Both the automatic name and any custom name typed into Array name are passed
through Identifiers.Sanitize(...), which lowercases the input, keeps only
[a-z0-9_], collapses repeated underscores, trims leading/trailing underscores, and
prefixes f_ if the result would start with a digit — guaranteeing a valid C
identifier. This base name is used for:
- the glyph table:
{name}[] - the sparse code table (if any):
{name}_codes[] - every metadata macro:
FONT_{NAME_UPPER}_* - the reference renderer functions:
{name}_draw_char/{name}_draw_str - the optional C++ wrapper class:
{name}_font
Metadata #defines
For the 12-glyph example above, /font generates:
#define FONT_JETBRAINS_MONO_BOLD_24X22_WIDTH 22
#define FONT_JETBRAINS_MONO_BOLD_24X22_HEIGHT 24
#define FONT_JETBRAINS_MONO_BOLD_24X22_BYTES_PER_ROW 3
#define FONT_JETBRAINS_MONO_BOLD_24X22_BYTES_PER_GLYPH 72
#define FONT_JETBRAINS_MONO_BOLD_24X22_FIRST_CHAR 32
#define FONT_JETBRAINS_MONO_BOLD_24X22_GLYPH_COUNT 12
#define FONT_JETBRAINS_MONO_BOLD_24X22_TABLE_SIZE 864
#define FONT_JETBRAINS_MONO_BOLD_24X22_HAS_CODE_TABLE 1
// Byte layout: Row-major, MSB first
#define FONT_JETBRAINS_MONO_BOLD_24X22_LAYOUT_ROW_MAJOR_MSB 1
WIDTH/HEIGHT— glyph cell dimensions in pixels.BYTES_PER_ROW—ceil(WIDTH / 8), bytes per pixel row (row-major layouts only).BYTES_PER_GLYPH— total bytes per glyph (BYTES_PER_ROW × HEIGHTfor row-major).FIRST_CHAR— codepoint ofcodePoints[0]. Only meaningful for contiguous sets (used as the offset base for direct indexing); still emitted for sparse sets but unused by the sparse renderer.GLYPH_COUNT— number of glyphs in the table (codePoints.Count).TABLE_SIZE—GLYPH_COUNT × BYTES_PER_GLYPH, the size in bytes of the glyph table array (does not include the_codes[]table, if present).HAS_CODE_TABLE— only emitted when the character set is non-contiguous; signals that{name}_codes[]is present and must be used for lookups.LAYOUT_*— one macro identifying the active byte layout, also used by the reference renderer's#if defined(...)branches.
FONT_READ_BYTE(p)
Every read of the glyph table goes through this macro, so the table can live somewhere other than normal addressable RAM (e.g. AVR flash) without changing the reference renderer:
// Generic C99, PIC XC8, ARM GCC presets:
#define FONT_READ_BYTE(p) (*(p))
// AVR / Arduino preset:
#define FONT_READ_BYTE(p) pgm_read_byte(p)
On AVR, const uint8_t[] arrays are placed in flash via PROGMEM but
can't be dereferenced directly — pgm_read_byte(p) issues the special
instruction needed to read flash memory. The AVR/Arduino envelope's prologue defines a
host-compiler fallback for pgm_read_byte/PROGMEM when
__AVR__ is not defined, so the same header also compiles on a desktop simulator.
Byte layouts
Byte layout in Header Options controls how glyph pixels are packed into the
bytes of the table, and which #if defined(FONT_{NAME}_LAYOUT_*) branch the
reference renderer takes:
- Row-major, MSB first (
LAYOUT_ROW_MAJOR_MSB, the default) — each row is packed intoBYTES_PER_ROW = ceil(WIDTH/8)bytes, bit 7 of the first byte is the leftmost pixel of the row. The renderer walks the glyph row by row. Matches most framebuffer/SPI display drivers. - Row-major, LSB first (
LAYOUT_ROW_MAJOR_LSB) — same row/byte grouping as MSB-first, but bit 0 of the first byte is the leftmost pixel. Use this if your display driver expects LSB-first bit order; the renderer's only difference is(bits & (1 << bit))instead of(bits & (1 << (7 - bit))). - Column-major pages (SSD1306), LSB-top (
LAYOUT_COLUMN_PAGES) — SSD1306/SH1106-style page addressing: the glyph is stored asceil(HEIGHT/8)vertical pages ofWIDTHbytes each, bit 0 of a column's byte is its topmost pixel in that page. The renderer walks the glyph page by page, column by column, instead of row by row, and aPAGE_COUNTmacro replacesBYTES_PER_ROW.
All three layouts work with put_pixel(x, y, on) via the reference renderer —
column-major is an optional optimisation for drivers that write whole pages directly, not a
requirement. See the SSD1306 guide.
Contiguous vs. sparse character sets
CharacterSet.IsContiguous(codePoints) checks whether the selected codepoints form
a gap-free range (last - first + 1 == count). Full ASCII and presets like
Digits 0-9 are contiguous; mixing ranges (e.g. digits + space + colon) is not.
For a contiguous set, a character's glyph index is a direct offset:
int index = (c - FONT_{NAME}_FIRST_CHAR) * FONT_{NAME}_BYTES_PER_GLYPH;
For a sparse (non-contiguous) set, an extra array lists the included
codepoints in ascending order, and HAS_CODE_TABLE is defined:
// Sparse character set: this font does not cover a contiguous codepoint range.
// font_jetbrains_mono_bold_24x22_codes[] lists the included codepoints in ascending order; a
// character's glyph index is its position in that array (see the reference
// renderer below).
static const uint8_t font_jetbrains_mono_bold_24x22_codes[] = {
0x20, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A
};
The sparse reference renderer ({name}_lookup_index(char c)) does a linear search
over {name}_codes[] and returns -1 (silently skipping the draw) if
c isn't found. Prefer a contiguous set (e.g. Full ASCII) when you need every
character in a range and don't mind the larger table; prefer a sparse set (e.g. digits +
a few symbols) when you only need a handful of characters and want the smallest possible
table — see the minimal font guide for real byte
counts.
Platform envelopes
Header Options → Envelope preset fills in a
Prologue / Array declaration / Epilogue / FONT_READ_BYTE combination for a target
toolchain. Editing any of the three text fields directly switches the preset to
custom for full manual control.
- Generic C99 (
generic-c99, the default) — no prologue or epilogue,const uint8_t {name}[],FONT_READ_BYTE(p) (*(p)). A safe default for desktop builds, simulators, and any toolchain whereconstdata already lands in flash/ROM. - AVR / Arduino (
avr-arduino) — prologue definesPROGMEM/pgm_read_bytewith a host-compiler fallback when__AVR__is undefined;const uint8_t {name}[] PROGMEM;FONT_READ_BYTE(p) pgm_read_byte(p). - PIC (XC8) (
pic-xc8) — a comment noting that XC8 placesconstdata in program memory automatically;const uint8_t {name}[];FONT_READ_BYTE(p) (*(p)). - ARM GCC (STM32, ESP32, nRF, ...) (
esp-idf-arm-gcc) — a comment noting thatconstdata is placed in flash via the linker script;const uint8_t {name}[];FONT_READ_BYTE(p) (*(p)). - Custom (
custom) — manually edited Prologue / Array declaration template (must contain{name}) / Epilogue /FONT_READ_BYTEexpression.
AVR/Arduino's prologue and array declaration, verbatim:
#ifdef __AVR__
#include <avr/pgmspace.h>
#else
#define PROGMEM
#define pgm_read_byte(p) (*(const uint8_t*)(p))
#endif
...
const uint8_t font_jetbrains_mono_bold_24x22[] PROGMEM = {
Reference renderer
"Include reference renderer as live code" (Header Options) controls whether
{name}_draw_char / {name}_draw_str are emitted as compilable code
(plus #include <stdbool.h> and an extern void put_pixel(...)
declaration) or as a /* ... */ comment block you can copy into your own source
file. Either way, the renderer's contract is a single function you implement:
extern void put_pixel(int x, int y, bool on);
{name}_draw_char(x, y, c) reads BYTES_PER_GLYPH bytes via
FONT_READ_BYTE (direct offset for contiguous sets, {name}_codes[]
lookup for sparse sets) and calls put_pixel once per pixel, honoring the active
byte layout. {name}_draw_str(x, y, s) calls draw_char for each
character, advancing x by WIDTH each time. See the
SSD1306 guide for the full live-code renderer and a compiling
example.
C++ wrapper
Enabling "Generate C++ class wrapper (header-only, C++14)" in Header Options downloads an
additional {name}_wrapper.hpp alongside the .h file. It declares a
{name}_font class with Width/Height/BytesPerRow
(or PageCount for column-major layouts)/BytesPerGlyph constants, plus
contains(char) and glyph(char). glyph(char) returns a
pointer to the real glyph bytes for characters in the set, or a
BytesPerGlyph-byte fallback glyph otherwise — Blank (all
zero), Hollow box (border outline, shown below), or
Use character (copies another glyph from the table). The wrapper has no
exceptions, no RTTI, and no dynamic allocation — compiles with
-std=c++14 -Wall -Werror -fno-exceptions -fno-rtti.
Real output for the 12-glyph example, with the "Hollow box" fallback:
// Header-only C++14 wrapper for font_jetbrains_mono_bold_24x22.
// Requires font_jetbrains_mono_bold_24x22.h to be included first (declares the FONT_JETBRAINS_MONO_BOLD_24X22_*
// macros and the font_jetbrains_mono_bold_24x22[] glyph table).
//
// No exceptions, no RTTI, no dynamic allocation โ safe for
// -fno-exceptions -fno-rtti embedded builds.
#pragma once
#include <stdint.h>
class font_jetbrains_mono_bold_24x22_font
{
public:
static constexpr int Width = FONT_JETBRAINS_MONO_BOLD_24X22_WIDTH;
static constexpr int Height = FONT_JETBRAINS_MONO_BOLD_24X22_HEIGHT;
#if defined(FONT_JETBRAINS_MONO_BOLD_24X22_LAYOUT_COLUMN_PAGES)
static constexpr int PageCount = FONT_JETBRAINS_MONO_BOLD_24X22_PAGE_COUNT;
#else
static constexpr int BytesPerRow = FONT_JETBRAINS_MONO_BOLD_24X22_BYTES_PER_ROW;
#endif
static constexpr int BytesPerGlyph = FONT_JETBRAINS_MONO_BOLD_24X22_BYTES_PER_GLYPH;
// Returns true if `c` has a glyph in this font's character set.
static constexpr bool contains(char c)
{
for (int i = 0; i < FONT_JETBRAINS_MONO_BOLD_24X22_GLYPH_COUNT; i++)
if (font_jetbrains_mono_bold_24x22_codes[i] == (unsigned char)c) return true;
return false;
}
// Returns a pointer to the BytesPerGlyph-byte glyph for `c`, or the
// configured fallback glyph if `c` is not in this font's character set.
static const uint8_t* glyph(char c)
{
static const uint8_t kFallback[BytesPerGlyph] = { 0xFF, 0xFF, 0xFC, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0x80, 0x00, 0x04, 0xFF, 0xFF, 0xFC };
if (!contains(c))
return kFallback;
for (int i = 0; i < FONT_JETBRAINS_MONO_BOLD_24X22_GLYPH_COUNT; i++)
if (font_jetbrains_mono_bold_24x22_codes[i] == (unsigned char)c) return &font_jetbrains_mono_bold_24x22[i * BytesPerGlyph];
return kFallback;
}
};
For a contiguous character set, contains and glyph use a range check
and direct offset instead of the {name}_codes[] linear search shown above.