dist: Added scripts for pre-processing future icon fonts

This commit is contained in:
WerWolv
2025-07-25 23:04:53 +02:00
parent c1545b57c9
commit 94527345b9
3 changed files with 130 additions and 0 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
/.idea/
/.kdev4/
/.vs/
.venv/
/cmake-build-*/
/build*/

69
dist/fonts/move_private_use_area.py vendored Normal file
View File

@@ -0,0 +1,69 @@
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables._c_m_a_p import CmapSubtable
import argparse
# Default PUAs
SOURCE_PUA_START = 0xEA00
SOURCE_PUA_END = 0x100F2
TARGET_PUA_START = 0xF0000
def move_pua_glyphs(input_font_path, output_font_path):
font = TTFont(input_font_path)
cmap_table = font['cmap']
glyph_set = font.getGlyphSet()
# Track moved glyphs
moved = 0
new_mapping = {}
# Collect original mappings in the PUA
for cmap in cmap_table.tables:
if cmap.isUnicode():
for codepoint, glyph_name in cmap.cmap.items():
if SOURCE_PUA_START <= codepoint <= SOURCE_PUA_END:
offset = codepoint - SOURCE_PUA_START
new_codepoint = TARGET_PUA_START + offset
new_mapping[new_codepoint] = glyph_name
moved += 1
if moved == 0:
print("No glyphs found in the source Private Use Area.")
return
# Remove old PUA entries from existing cmap subtables
for cmap in cmap_table.tables:
if cmap.isUnicode():
cmap.cmap = {
cp: gn for cp, gn in cmap.cmap.items()
if not (SOURCE_PUA_START <= cp <= SOURCE_PUA_END)
}
# Create or update a format 12 cmap subtable
found_format12 = False
for cmap in cmap_table.tables:
if cmap.format == 12 and cmap.platformID == 3 and cmap.platEncID in (10, 1):
cmap.cmap.update(new_mapping)
found_format12 = True
break
if not found_format12:
# Create a new format 12 subtable
cmap12 = CmapSubtable.newSubtable(12)
cmap12.platformID = 3
cmap12.platEncID = 10 # UCS-4
cmap12.language = 0
cmap12.cmap = new_mapping
cmap_table.tables.append(cmap12)
print(f"Moved {moved} glyphs from U+{SOURCE_PUA_START:X}U+{SOURCE_PUA_END:X} to U+{TARGET_PUA_START:X}+")
font.save(output_font_path)
print(f"Saved modified font to {output_font_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Move PUA glyphs in a TTF file to another Unicode range.")
parser.add_argument("input", help="Input TTF file path")
parser.add_argument("output", help="Output TTF file path")
args = parser.parse_args()
move_pua_glyphs(args.input, args.output)

60
dist/fonts/ttf_to_header_file.py vendored Normal file
View File

@@ -0,0 +1,60 @@
import argparse
from fontTools.ttLib import TTFont
import os
def unicode_to_utf8_escape(codepoint):
return ''.join([f'\\x{b:02x}' for b in chr(codepoint).encode('utf-8')])
def format_macro_name(prefix, glyph_name):
# Convert names like 'repo-forked' -> 'ICON_VS_REPO_FORKED'
return "ICON_" + prefix + "_" + glyph_name.upper().replace('-', '_')
def generate_font_header(font_path, output_path, font_macro_name, font_file_macro):
font = TTFont(font_path)
# Use cmap to get Unicode to glyph mapping
codepoint_to_names = {}
for table in font["cmap"].tables:
if table.isUnicode():
for codepoint, glyph_name in table.cmap.items():
codepoint_to_names.setdefault(codepoint, []).append(glyph_name)
if not codepoint_to_names:
print("No Unicode-mapped glyphs found in the font.")
return
# Remove any glyph that is lower than 0xFF
codepoint_to_names = {cp: names for cp, names in codepoint_to_names.items() if cp >= 0xFF}
min_cp = min(codepoint_to_names)
max_cp = max(codepoint_to_names)
with open(output_path, "w", encoding="utf-8") as out:
out.write("#pragma once\n\n")
out.write(f'#define FONT_ICON_FILE_NAME_{font_macro_name} "{font_file_macro}"\n\n')
out.write(f"#define ICON_MIN_{font_macro_name} 0x{min_cp:04x}\n")
out.write(f"#define ICON_MAX_16_{font_macro_name} 0x{max_cp:04x}\n")
out.write(f"#define ICON_MAX_{font_macro_name} 0x{max_cp:04x}\n")
written = set()
for codepoint in sorted(codepoint_to_names):
utf8 = unicode_to_utf8_escape(codepoint)
comment = f"// U+{codepoint:04X}"
glyph_names = sorted(set(codepoint_to_names[codepoint]))
for i, glyph_name in enumerate(glyph_names):
macro = format_macro_name(font_macro_name, glyph_name)
if macro in written:
continue
out.write(f"#define {macro} \"{utf8}\"\t{comment}\n")
written.add(macro)
print(f"Header generated at {output_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate C header file from TTF glyphs.")
parser.add_argument("font", help="Input .ttf font file")
parser.add_argument("output", help="Output .h file")
parser.add_argument("macro_name", help="Macro prefix")
args = parser.parse_args()
generate_font_header(args.font, args.output, args.macro_name, os.path.basename(args.font))