Files
ttf_to_binary_font/font_to_binary.py

88 lines
3.0 KiB
Python

import sys
from PIL import Image, ImageDraw, ImageFont
FONT_SIZE = 16 # 16x16 pixels
def render_glyph(font, char):
"""Render a single character into a 16x16 monochrome bitmap."""
img = Image.new('1', (FONT_SIZE, FONT_SIZE), 0)
draw = ImageDraw.Draw(img)
# Get bounding box
bbox = draw.textbbox((0, 0), char, font=font)
w = bbox[2] - bbox[0]
h = bbox[3] - bbox[1]
# Draw character centered
draw.text(
((FONT_SIZE - w) // 2 - bbox[0], (FONT_SIZE - h) // 2 - bbox[1]),
char,
fill=1,
font=font
)
# Convert to 16x16 bitmap (list of 0/1)
bitmap = [[img.getpixel((x, y)) for x in range(FONT_SIZE)] for y in range(FONT_SIZE)]
return bitmap
def bitmap_to_c_array(char, bitmap):
"""Convert 16x16 bitmap to a C-style uint8_t array with binary literals."""
lines = []
for row in bitmap:
high = row[:8]
low = row[8:]
high_val = "0b" + "".join(str(b) for b in high)
low_val = "0b" + "".join(str(b) for b in low)
lines.append(f"{high_val}, {low_val}, // " + "".join("*" if b else " " for b in row))
# Use ASCII code for special characters to avoid invalid variable names
if char.isalnum():
array_name = f"letter_{char}_16x16"
else:
array_name = f"letter_{ord(char)}_16x16"
c_code = f"static const uint8_t {array_name}[32] = {{\n " + "\n ".join(lines) + "\n};"
return array_name, c_code
def main(ttf_path, output_file):
font = ImageFont.truetype(ttf_path, FONT_SIZE)
# Characters to include
letters_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
letters_lower = "abcdefghijklmnopqrstuvwxyz"
digits = "0123456789"
specials = "!@#$%^&*()-_=+[]{};:'\",.<>/?\\|`~ "
all_chars = letters_upper + letters_lower + digits + specials
array_names = []
with open(output_file, "w") as f:
for char in all_chars:
bitmap = render_glyph(font, char)
array_name, c_array = bitmap_to_c_array(char, bitmap)
array_names.append(array_name)
f.write(f"// Character '{char}' (ASCII {ord(char)})\n")
f.write(c_array + "\n\n")
# Generate pointer array
f.write("// Font bitmaps array\n")
f.write(f"static const uint8_t *font_bitmaps_16x16[{len(array_names)}] = {{\n ")
f.write(", ".join(array_names))
f.write("\n};\n\n")
# Generate FontPack structure
f.write("// Font pack structure\n")
f.write("typedef struct {\n const uint8_t **bitmaps;\n} FontPack;\n\n")
f.write("const FontPack basic_font_pack = {\n")
f.write(" .bitmaps = {\n " + ", ".join(array_names) + "\n }\n};\n")
print(f"C arrays and FontPack structure written to {output_file}")
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python font_to_binary.py path/to/font.ttf output_file")
sys.exit(1)
ttf_path = sys.argv[1]
output_file = sys.argv[2]
main(ttf_path, output_file)