Krux uses a custom fork of the Terminus font for its glyphs that includes Vietnamese characters, the Bitcoin currency symbol (₿) and custom icons.
To rebuild the font for all devices, run:
poetry run python bdftokff.py True
If the True
argument was passed, the Python script will automatically overwrite the contents of the font.c
file in each of the projects ../MaixPy/projects/*/compile/overrides/components/micropython/port/src/omv/img/font.c
, otherwise the script will produce 3 files: m5stickv_font.c
, amigo_font.c
and bit_dock_yahboom_font.c
. Use these files to manually replace the contents of the font.c
file in each of your projects.
Krux uses bitmap fonts that are custom-built for each device it runs on. The format that the firmware expects fonts to be in is a custom format referred to as "krux font format," or .kff
.
Krux font format is a sparse bitmap font format that is intended to minimize the amount of memory used to store a subset of unicode glyphs. In this format, all glyphs are encoded as a 2-byte header integer containing their unicode codepoint followed by a fixed-size array of bytes describing how to draw the glyph. These glyphs are stored contiguously in a one-dimensional byte array sorted by codepoint. The header of this array is a 2-byte integer containing the total number of glyphs in the file. At runtime, each glyph is looked up using binary search.
To create a .kff
file, you first need to find a font in .bdf
format. You can edit and generate a .bdf
file using FontForge
From there, you can run the bdftohex.py
script which converts the bdf file to an intermediary .hex
format mapping each character's unicode codepoint to a series of hex digits describing how to draw it.
From there, you can run the hexfill.py
script which takes in a .hex
file and font width and height and post-processes the file to fill in any gaps in the codepoint sequence, adding zero'd lines for missing glyphs. If the specified font size is larger than the hex for a glyph, leading zero padding will be added to the glyph to make it the right size, and if the hex for a glyph is larger than the font size it will be zero'd out.
The hexmerge.py
script takes a list of .hex
font files and merges them into one combined .hex
file sorted by unicode codepoint. If multiple files refer to the same character, the earliest non-zero glyph will be used.
Finally, the hextokff.py
script takes a .hex
font file and font width and height and converts it into the 1D sparse bitmap array format that Krux needs. Importantly, this script scans the i18n/translations
folder and builds the set of unique codepoints used across all translations to drastically reduce the number of glyphs stored.
To simplify this process, a bdftokff.sh
bash script has been added that invokes the aforementioned scripts as needed to compile one .kff
file given a list of fonts.
To rebuild the font for all devices, run:
./bdftokff.sh ter-u14n 8 14 > m5stickv.kff
./bdftokff.sh ter-u16n 8 16 > bit_dock_yahboom.kff
./bdftokff.sh ter-u24b 12 24 > amigo.kff
Once you have .kff
files, for each project that you want to use the updated fonts, edit ../MaixPy/projects/*/compile/overrides/components/micropython/port/src/omv/img/font.c
(substituting maixpy_amigo
for *
if only for an amigo) and replace the array contents in the unicode
variable with the byte array found within the appropriate .kff
file, then rebuild the firmware.