Files
warp/script/patch_font_with_warp_glyph
2026-04-28 08:43:33 -05:00

114 lines
3.2 KiB
Plaintext
Executable File

#!/usr/bin/env -S fontforge -script
# Script that patches a given font to include the Warp logo as a glyph in the font,
# using a unicode codepoint in the private use area.
import os
import sys
import fontforge
import psMat
# Default values match what we used when initially patching Roboto.
SCRIPT_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
DEFAULT_SVG_PATH = os.path.join(SCRIPT_DIR, "warp.svg")
DEFAULT_CODEPOINT = 0xE500 # Private Use Area
DEFAULT_GLYPH_NAME = "warpLogo"
def usage(exit_code: int) -> None:
prog = os.path.basename(sys.argv[0])
print(
"\n".join(
[
f"Usage: {prog} <font.ttf> [--svg <icon.svg>] [--codepoint <hex>] [--name <glyph_name>]",
"",
"Patches the given font by importing an SVG icon as a new glyph.",
"Defaults:",
f" --svg {DEFAULT_SVG_PATH}",
f" --codepoint 0x{DEFAULT_CODEPOINT:04X}",
f" --name {DEFAULT_GLYPH_NAME}",
]
)
)
raise SystemExit(exit_code)
def parse_args(argv):
if len(argv) < 2 or argv[1] in ("-h", "--help"):
usage(0 if len(argv) >= 2 else 2)
font_path = argv[1]
svg_path = DEFAULT_SVG_PATH
codepoint = DEFAULT_CODEPOINT
glyph_name = DEFAULT_GLYPH_NAME
i = 2
while i < len(argv):
arg = argv[i]
if arg == "--svg":
i += 1
if i >= len(argv):
usage(2)
svg_path = argv[i]
elif arg == "--codepoint":
i += 1
if i >= len(argv):
usage(2)
v = argv[i]
# Accept 0xE500, E500, or decimal.
codepoint = int(v, 16) if (v.startswith("0x") or any(c in v.lower() for c in "abcdef")) else int(v)
elif arg == "--name":
i += 1
if i >= len(argv):
usage(2)
glyph_name = argv[i]
else:
print(f"Unknown argument: {arg}")
usage(2)
i += 1
return font_path, svg_path, codepoint, glyph_name
def patch_font(font_path: str, svg_path: str, codepoint: int, glyph_name: str) -> None:
if not os.path.exists(font_path):
raise SystemExit(f"Font not found: {font_path}")
if not os.path.exists(svg_path):
raise SystemExit(f"SVG not found: {svg_path}")
font = fontforge.open(font_path)
# Create or replace the glyph.
g = font.createChar(codepoint, glyph_name)
g.clear()
# Import the outlines.
g.importOutlines(svg_path)
# Clean up and make it robust for rasterization.
g.removeOverlap()
g.simplify()
g.correctDirection()
# Keep the logo from looking low: align the bottom of the imported outline to the baseline.
# (This is the same adjustment we ended up applying after the initial patch.)
xmin, ymin, xmax, ymax = g.boundingBox()
if ymin != 0:
g.transform(psMat.translate(0, -ymin))
g.round()
font.generate(font_path)
font.close()
def main():
font_path, svg_path, codepoint, glyph_name = parse_args(sys.argv)
patch_font(font_path, svg_path, codepoint, glyph_name)
print(f"Patched {font_path} with U+{codepoint:04X} ({glyph_name})")
if __name__ == "__main__":
main()