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_ROWceil(WIDTH / 8), bytes per pixel row (row-major layouts only).
  • BYTES_PER_GLYPH — total bytes per glyph (BYTES_PER_ROW × HEIGHT for row-major).
  • FIRST_CHAR — codepoint of codePoints[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_SIZEGLYPH_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 into BYTES_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 as ceil(HEIGHT/8) vertical pages of WIDTH bytes 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 a PAGE_COUNT macro replaces BYTES_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 OptionsEnvelope 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 where const data already lands in flash/ROM.
  • AVR / Arduino (avr-arduino) — prologue defines PROGMEM / pgm_read_byte with 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 places const data 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 that const data 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_BYTE expression.

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.

Open Font Tool →