thirdculture-docker/scripts/fonts.py
2026-11-07 19:26:19 -05:00

61 lines
2.7 KiB
Python
Executable file

#!/usr/bin/env -S uv run -q --script
# /// script
# dependencies = ["fonttools==4.68.0", "brotli==1.2.1", "lxml==6.1.3"]
# ///
# ./scripts/fonts.py fonts/fonts.txt (family weight style file) → werc/pub/style/fonts/*.woff2 + fonts.css
import pathlib, shutil
from fontTools import subset
from fontTools.ttLib import TTFont
root = pathlib.Path(__file__).resolve().parent.parent
src, out, css = root / 'fonts', root / 'werc/pub/style/fonts', root / 'werc/pub/style/fonts.css'
CORE = [(0x20, 0x7e), (0xa0, 0x17f), (0x2000, 0x206f), (0x20ac, 0x20ac), (0x2122, 0x2122),
(0x2190, 0x21ff), (0x2212, 0x2212), (0x2500, 0x25ff)]
SPLIT = 64 # more extra glyphs than this → separate .ext file, fetched only by pages that use them
def in_core(c): return any(a <= c <= b for a, b in CORE)
def rng(a, b): return f'U+{a:X}' if a == b else f'U+{a:X}-{b:X}'
core_range = ', '.join(rng(a, b) for a, b in CORE)
ext_range, prev = [], -1
for a, b in CORE + [(0x110000, 0x110000)]:
if a > prev + 1: ext_range.append(rng(prev + 1, a - 1))
prev = b
ext_range = ', '.join(ext_range)
opts = subset.Options()
opts.flavor, opts.layout_features, opts.name_IDs, opts.notdef_outline = 'woff2', ['*'], ['*'], True
opts.drop_tables += ['FFTM']
def build(path, name, cps):
font = subset.load_font(str(path), opts)
s = subset.Subsetter(opts)
s.populate(unicodes=cps)
s.subset(font)
subset.save_font(font, str(out / name), opts)
shutil.rmtree(out, ignore_errors=True)
out.mkdir()
files, faces = {}, []
for line in (src / 'fonts.txt').read_text().splitlines():
if not line.strip(): continue
*family, weight, style, file = line.split()
if file not in files:
slug = pathlib.Path(file).stem.lower().replace('_', '-')
cps = set(TTFont(src / file, lazy=True).getBestCmap())
core, ext = {c for c in cps if in_core(c)}, {c for c in cps if not in_core(c)}
if len(ext) > SPLIT:
build(src / file, f'{slug}.woff2', core)
build(src / file, f'{slug}.ext.woff2', ext)
files[file] = [(f'{slug}.woff2', core_range), (f'{slug}.ext.woff2', ext_range)]
else:
build(src / file, f'{slug}.woff2', cps)
files[file] = [(f'{slug}.woff2', None)]
for name, ur in files[file]:
faces.append(f"@font-face {{ font-family: '{' '.join(family)}'; src: url('fonts/{name}') format('woff2'); "
f"font-weight: {weight}; font-style: {style}; font-display: swap;"
+ (f' unicode-range: {ur};' if ur else '') + ' }')
css.write_text('\n'.join(faces) + '\n')
before = sum((src / f).stat().st_size for f in files)
after = sum(p.stat().st_size for p in out.iterdir())
print(f'{len(faces)} faces, {len(files)} sources {before // 1024} KB → {after // 1024} KB')