Skip to content
GadgetoidPublic

About

PPF font support for MicroPython's framebuf module.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

fbppf - Framebuf PPF

Pure-MicroPython loader and renderer for Picovector PPF (pixel) fonts, drawing onto any framebuf.FrameBuffer. Optional per-format viper blitters accelerate the common linear buffer layouts.

Get some cool icon fonts from here: https://gadgetoid.github.io/iconfont-ppf/

Or steal some from Badgeware: https://github.com/pimoroni/tufty2350/tree/main/romfs/fonts (preview them under pixel fonts here: https://try.badgewa.re/fonts.html).

petme128, MicroPython's built-in 8x8 font converted to PPF

Manticore, a Badgeware display font

Boardgames, from iconfont-ppf

Above: the bundled petme128, the Badgeware Manticore font, and the boardgames icon font from iconfont-ppf, all rendered by this library.

Install

With mpremote:

mpremote mip install github:gadgetoid/fbppf

Or freeze it into a firmware build by adding this to a board manifest:

include("/path/to/fbppf/manifest.py")

ppf and ppf_viper install to the device's library path; import ppf then works directly.

Usage

import framebuf
from ppf import PPFFont, Canvas

font = PPFFont("ark.ppf")

# Any framebuf.FrameBuffer works (portable path, every pixel format):
fb = framebuf.FrameBuffer(buf, 240, 135, framebuf.RGB565)
font.text(fb, "Hello", 4, 4, 0xFFFF)          # col, then optional scale
font.text(fb, "Big", 4, 20, 0xF800, scale=2)
w, h = font.measure("Hello", scale=2)

# A Canvas carries the buffer geometry viper needs. On a build with a native
# emitter and a supported format it renders through the viper fast path;
# otherwise it transparently falls back to the portable path.
canvas = Canvas(240, 135, framebuf.RGB565)
font.text(canvas, "Fast", 4, 4, 0xFFFF)
# canvas.fb is the FrameBuffer; canvas.buffer is the backing bytearray.

text() returns the x cursor after the last glyph. \n returns to the start column and drops one line; \r is ignored. The space glyph advances width // 3 pixels (times scale), matching the reference renderer.

Fast path coverage

Viper blitters exist for RGB565, GS8 and MONO_VLSB — the linear formats where a pixel address is a cheap function of (x, y). Other formats (GS4_HMSB, MONO_HLSB, ...) use the portable path, which coalesces horizontal runs into fill_rect calls and clips via framebuf. The portable path is always used on desktop MicroPython (no native emitter for x86-64 / aarch64) and whenever a plain FrameBuffer is passed.

PPF format

All multi-byte fields are big-endian.

Offset Type Field
0 char[4] "ppf!" marker
4 u16 flags (unused)
6 u32 glyph count
10 u16 width (maximum glyph width; sets the bitmap row stride)
12 u16 height
14 char[32] name, nul-padded
46 glyph table glyph count records of u32 codepoint, u16 width, sorted by codepoint
... bitmaps glyph count bitmaps, each ((width + 7) // 8) * height bytes

Each bitmap is packed row-major, MSB-first, at the font's maximum-width stride; a glyph uses only its own width columns. Glyphs are looked up by codepoint with a binary search.

Tests

cd tests
micropython test_ppf.py [font.ppf]
micropython test_viper_algo.py [font.ppf]

The viper blitters cannot execute on a desktop build (no aarch64/x86-64 native emitter), so test_viper_algo.py validates their index math and unsigned clip logic against the portable renderer. Compilation for real targets is checked with mpy-cross:

mpy-cross -march=armv6m   ppf_viper.py   # RP2040
mpy-cross -march=armv7emsp ppf_viper.py  # RP2350 (Arm)
mpy-cross -march=rv32imc  ppf_viper.py   # RP2350 (RISC-V)

License

MIT; see LICENSE. examples/petme128.ppf is generated by tools/petme128_to_ppf.py from MicroPython's built-in font_petme128_8x8.h and remains under its MIT license.

About

PPF font support for MicroPython's framebuf module.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages