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)