ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
font_to_c.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# SPDX-License-Identifier: MIT
3# Copyright (c) 2026 Brighton Sikarskie
4"""Emit a C source file embedding a binary font blob as a byte array.
5
6Dependency-free (stdlib only) so it runs at build time on any host without a
7venv. The generated .c is written to the build directory and is NOT committed,
8which keeps the large hex array out of the QC gates (magic-numbers / format).
9
10Usage:
11 font_to_c.py <input-font> <output.c> <symbol_name> <header_name>
12
13The output defines, against the declarations in <header_name> (one header per
14baked font, named after the font -- e.g. literata_latin1.h):
15 const unsigned char <symbol_name>[] = { ... };
16 const unsigned int <symbol_name>_len = <N>;
17
18The Latin-1 subset checked in at libs/ra8_fonts/literata_latin1.ttf was produced
19with fonttools (in a throwaway venv) from libs/ra8_fonts/Literata-Regular.ttf
20(Literata Regular, SIL OFL 1.1, googlefonts/literata):
21 pyftsubset Literata-Regular.ttf \
22 --unicodes='0020-00FF,2013,2014,2018,2019,201C,201D,2026' \
23 --output-file=literata_latin1.ttf \
24 --no-hinting --desubroutinize --glyph-names --notdef-outline
25
26Copyright (c) 2026 Brighton Sikarskie
27SPDX-License-Identifier: MIT
28"""
29
30import pathlib
31import sys
32
33# Expected number of CLI arguments: script + 4 positional args.
34EXPECTED_ARGC = 5
35
36
37def main() -> int:
38 """Convert a font file to a C array, or exit 2 on a usage error.
39
40 Rejects an EMPTY input rather than emitting a zero-length array: a
41 zero-length font links cleanly and fails only at render time, where the
42 cause is far from the effect.
43
44 Returns 0 on success, 2 on wrong argument count.
45 """
46 if len(sys.argv) != EXPECTED_ARGC:
47 sys.stderr.write(
48 "usage: font_to_c.py <input-font> <output.c> <symbol_name> <header_name>\n"
49 )
50 return 2
51 src, dst, name, header = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
52 data = pathlib.Path(src).read_bytes()
53 if not data:
54 sys.stderr.write(f"font_to_c.py: empty input {src}\n")
55 return 1
56
57 out = []
58 out.append("/* GENERATED by scripts/gen/font_to_c.py -- do not edit. */")
59 out.append(f"/* Source: {pathlib.Path(src).name} ({len(data)} bytes). */")
60 out.append(f'#include "{header}"')
61 out.append("")
62 out.append(f"const unsigned char {name}[] = {{")
63 # 16 bytes per line keeps the file readable; it is build-only, not committed.
64 for i in range(0, len(data), 16):
65 chunk = data[i : i + 16]
66 out.append(" " + "".join(f"0x{b:02X}, " for b in chunk).rstrip())
67 out.append("};")
68 out.append(f"const unsigned int {name}_len = {len(data)}U;")
69 out.append("")
70
71 pathlib.Path(dst).write_text("\n".join(out))
72 return 0
73
74
75if __name__ == "__main__":
76 raise SystemExit(main())
void main(void)
The application entry point Reset_Handler hands control to.
Definition main.c:298