feat: add SD card font support with on-device download and web management
Add a complete SD card font subsystem that enables users to install and use custom fonts beyond the three built-in families. This combines the back-end firmware support (#1327) with the font configuration, build pipeline, CI distribution, and user-facing management UI (#1392). Core font system: - Custom .cpfont binary format (v4) with multi-style support (regular, bold, italic, bold-italic) packed into a single file per size - On-demand glyph loading from SD card with two-pass prewarm rendering to bulk-read glyphs per page, achieving near-flash performance for Latin text (~697ms vs ~681ms) and viable CJK rendering (~32% slower) - Persistent advance cache for layout measurement without SD I/O - Overflow ring buffer for glyph cache misses during rendering - Memory-conscious design: only advance tables kept in RAM; glyph bitmaps, kern tables, and ligatures loaded on demand from SD Font management: - On-device WiFi download from GitHub Releases with manifest-based discovery, install/update detection, and progress UI - Web interface font upload, listing, and deletion via /fonts page - Manual SD card copy to /fonts/ or /.fonts/ directories - Font selection integrated into Settings > Reader > Font Family Build pipeline: - Declarative YAML config (sd-fonts.yaml) as single source of truth for the 17-family font library (serif, sans, mono, accessibility) - Python converter (fontconvert_sdcard.py) for TTF/OTF to .cpfont with FreeType rasterization, class-based kerning, and ligature extraction - Parallel build orchestrator with variable font instance extraction - CI workflow publishing versioned + stable releases to a dedicated crosspoint-fonts repository with auto-incrementing revision tags - Centralized version constants (cpfont_version.py) shared across build tooling and CI, with firmware headers as manual sync points Additional fixes: - CJK characters no longer get hyphens inserted at line breaks - Advance table eliminates 30+ second stalls during CJK section indexing for paragraphs with >512 unique codepoints Closes #930 Co-authored-by: Zach Nelson <zach@zdnelson.com> Co-authored-by: Justin <itsthisjustin@users.noreply.github.com> Co-authored-by: jpirnay <jens@pirnay.com> Co-authored-by: mcrosson <kemonine@kemonine.info>
This commit is contained in:
committed by
Zach Nelson
co-authored by
Zach Nelson
Justin
jpirnay
mcrosson
parent
29fd29f537
commit
7993b2bb97
@@ -0,0 +1,106 @@
|
||||
name: Build & Publish SD Card Fonts
|
||||
|
||||
# Fonts change rarely — run manually when font sources or the conversion
|
||||
# pipeline are updated. Publishes .cpfont files + fonts.json manifest as
|
||||
# GitHub Release assets on the crosspoint-fonts repo so font releases don't
|
||||
# clutter the firmware releases page.
|
||||
#
|
||||
# Requires a repository secret FONTS_REPO_TOKEN — a fine-grained PAT (or
|
||||
# classic PAT) with contents:write permission on the target fonts repo.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
FONTS_REPO: crosspoint-reader/crosspoint-fonts
|
||||
|
||||
jobs:
|
||||
build-fonts:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.14'
|
||||
|
||||
- name: Install font tools
|
||||
run: pip install freetype-py fonttools pyyaml
|
||||
|
||||
- name: Install system dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libfreetype6-dev
|
||||
|
||||
- name: Read version constants
|
||||
id: versions
|
||||
run: |
|
||||
cd lib/EpdFont/scripts
|
||||
echo "binary=$(python3 -c 'from cpfont_version import CPFONT_VERSION; print(CPFONT_VERSION)')" >> "$GITHUB_OUTPUT"
|
||||
echo "metadata=$(python3 -c 'from cpfont_version import FONTS_MANIFEST_VERSION; print(FONTS_MANIFEST_VERSION)')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build SD card fonts
|
||||
run: python3 lib/EpdFont/scripts/build-sd-fonts.py --clean
|
||||
|
||||
- name: Flatten output for release assets
|
||||
run: |
|
||||
mkdir -p dist
|
||||
find lib/EpdFont/scripts/output -name '*.cpfont' -exec cp {} dist/ \;
|
||||
|
||||
- name: Compute release tags
|
||||
id: tags
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FONTS_REPO_TOKEN }}
|
||||
run: |
|
||||
BASE="sd-fonts-m${{ steps.versions.outputs.metadata }}-b${{ steps.versions.outputs.binary }}"
|
||||
echo "base=$BASE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Find the highest existing revision for this m/b pair
|
||||
LAST=$(gh release list --repo "${{ env.FONTS_REPO }}" \
|
||||
--json tagName --jq \
|
||||
'[.[] | select(.tagName | startswith("'"${BASE}-r"'")) | .tagName | split("-r")[1] | tonumber] | max // 0')
|
||||
NEXT=$((LAST + 1))
|
||||
echo "revision=$NEXT" >> "$GITHUB_OUTPUT"
|
||||
echo "versioned=${BASE}-r${NEXT}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Generate manifest
|
||||
run: |
|
||||
python3 scripts/generate-font-manifest.py \
|
||||
--input dist \
|
||||
--base-url "https://github.com/${{ env.FONTS_REPO }}/releases/download/${{ steps.tags.outputs.base }}/" \
|
||||
--output dist/fonts.json \
|
||||
--descriptions-from lib/EpdFont/scripts/sd-fonts.yaml
|
||||
|
||||
- name: Publish versioned release to fonts repo
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FONTS_REPO_TOKEN }}
|
||||
run: |
|
||||
VERSIONED="${{ steps.tags.outputs.versioned }}"
|
||||
TITLE="SD Card Fonts (${VERSIONED#sd-fonts-})"
|
||||
|
||||
gh release create "$VERSIONED" dist/* \
|
||||
--repo "${{ env.FONTS_REPO }}" \
|
||||
--title "$TITLE" \
|
||||
--notes "Pre-built \`.cpfont\` font files for CrossPoint Reader.
|
||||
|
||||
Download individual files or use **Settings > System > Download Fonts** on the device.
|
||||
|
||||
See [SD Card Fonts documentation](https://github.com/${{ github.repository }}/blob/main/docs/sd-card-fonts.md) for details."
|
||||
|
||||
- name: Update stable tag for device downloads
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FONTS_REPO_TOKEN }}
|
||||
run: |
|
||||
BASE="${{ steps.tags.outputs.base }}"
|
||||
|
||||
# Delete the old stable release for this m/b pair (the versioned releases are kept)
|
||||
gh release delete "$BASE" --repo "${{ env.FONTS_REPO }}" --yes 2>/dev/null || true
|
||||
|
||||
gh release create "$BASE" dist/* \
|
||||
--repo "${{ env.FONTS_REPO }}" \
|
||||
--title "SD Card Fonts (${BASE#sd-fonts-})" \
|
||||
--notes "Current font build for manifest v${{ steps.versions.outputs.metadata }}, binary format v${{ steps.versions.outputs.binary }}. Devices with this firmware version download from this release.
|
||||
|
||||
This is revision **${{ steps.tags.outputs.revision }}** — see [\`${{ steps.tags.outputs.versioned }}\`](https://github.com/${{ env.FONTS_REPO }}/releases/tag/${{ steps.tags.outputs.versioned }}) for the immutable copy.
|
||||
|
||||
Download individual files or use **Settings > System > Download Fonts** on the device."
|
||||
Reference in New Issue
Block a user