install fontforge and python
sudo apt install fontforge python3-fontforge
sudo apt install python3 python3-pip python3-venv -y
export.py
#!/usr/bin/env python3
import fontforge
import os
import sys
# Usage check
if len(sys.argv) < 2:
print("Usage: python3 export.py <fontfile.ttf> [output_dir]")
sys.exit(1)
# Path to font file
font_path = sys.argv[1]
# Output directory (default = ./svg)
output_dir = sys.argv[2] if len(sys.argv) > 2 else "./svg"
os.makedirs(output_dir, exist_ok=True)
# Open the font
font = fontforge.open(font_path)
# Export glyphs
for glyph in font.glyphs():
if glyph.isWorthOutputting():
export_path = os.path.join(output_dir, f"{glyph.glyphname}.svg")
glyph.export(export_path)
print(f"Exported: {export_path}")
font.close()
print("✅ All glyphs exported successfully.")
import.py
#!/usr/bin/env fontforge
import fontforge
import os
import sys
# Usage check
if len(sys.argv) < 4:
print("Usage: fontforge -script export.py <fontfile.ttf> <svg_dir> <output_file.(ttf|sfd)>")
sys.exit(1)
# Dynamic paths from command line
font_path = sys.argv[1]
svg_dir = sys.argv[2]
output_file = sys.argv[3]
try:
# Open the base font
font = fontforge.open(font_path)
print("✓ Font opened successfully")
print("Font name:", font.fontname)
# Collect all SVG files
svg_files = [f for f in os.listdir(svg_dir) if f.endswith(".svg")]
if not svg_files:
print("✗ No SVG files found in", svg_dir)
# Process each SVG
for svg_file in svg_files:
test_svg = os.path.join(svg_dir, svg_file)
print(f"\nImporting {svg_file}...")
if not os.path.exists(test_svg):
print(f"✗ File not found: {test_svg}")
continue
expected_glyph_name = svg_file[:-4]
if not expected_glyph_name.strip():
print(f"✗ Invalid glyph name from file: {svg_file}")
continue
print(f"Looking for glyph: {expected_glyph_name}")
glyph = None
if expected_glyph_name.startswith("uni"):
parts = expected_glyph_name.split('_')
try:
if len(parts) == 1 and '.' not in expected_glyph_name:
codepoint = int(parts[0][3:], 16)
glyph = font[codepoint]
print(f"✓ Found base glyph: {glyph.glyphname} (U+{glyph.unicode:04X})")
else:
if expected_glyph_name not in [g.glyphname for g in font.glyphs()]:
glyph = font.createChar(-1, expected_glyph_name)
print(f"✓ Created new glyph: {expected_glyph_name}")
else:
glyph = font[expected_glyph_name]
print(f"✓ Found existing glyph: {expected_glyph_name}")
except Exception:
pass
else:
try:
glyph = font[expected_glyph_name]
except Exception:
pass
if glyph is None:
print(f"✗ Glyph '{expected_glyph_name}' not found or created")
continue
print(" Before import bounding box:", glyph.boundingBox())
# Save metrics
original_width = glyph.width
original_left_bearing = glyph.left_side_bearing
original_right_bearing = glyph.right_side_bearing
glyph.clear()
try:
glyph.importOutlines(test_svg)
glyph.round()
# Restore metrics
glyph.width = original_width
glyph.left_side_bearing = original_left_bearing
glyph.right_side_bearing = original_right_bearing
print(" After import bounding box:", glyph.boundingBox())
print("✓ SVG import completed with spacing preserved")
except Exception as e:
print(f"✗ Error importing {svg_file}: {e}")
# Generate output font (TTF or SFD depending on extension)
print(f"\nGenerating font: {output_file}")
if output_file.lower().endswith(".ttf"):
font.generate(output_file, flags=("opentype", "dummy-dsig"))
elif output_file.lower().endswith(".sfd"):
font.save(output_file)
else:
print("✗ Unsupported output format. Use .ttf or .sfd")
sys.exit(1)
print("✓ Font saved as:", output_file)
if os.path.exists(output_file):
size = os.path.getsize(output_file)
print(f"✓ Output file exists, size: {size} bytes")
else:
print("✗ Output file was not created!")
font.close()
except Exception as e:
print("Error:", e)
import traceback
traceback.print_exc()
print("✅ All glyphs import successfully.")
feature.py
#!/usr/bin/env python3
import fontforge
import os
import sys
def import_features(font_path, fea_path, output_file):
try:
# Normalize output path (absolute)
output_file = os.path.abspath(output_file)
output_dir = os.path.dirname(output_file)
# Ensure output directory exists
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
print(f"✓ Created directory: {output_dir}")
# Open font
font = fontforge.open(font_path)
print(f"✓ Opened font: {font.fontname}")
# Import features
font.mergeFeature(fea_path)
print(f"✓ Features merged from {fea_path}")
# Save
if output_file.lower().endswith(".ttf"):
font.generate(output_file, flags=("opentype", "dummy-dsig"))
elif output_file.lower().endswith(".sfd"):
font.save(output_file)
else:
print("✗ Unsupported output format. Use .ttf or .sfd")
return
print(f"✓ New font generated: {output_file}")
font.close()
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
if len(sys.argv) < 4:
print("Usage: python3 feature.py <fontfile.ttf|sfd> <features.fea> <outputfile.ttf|sfd>")
sys.exit(1)
font_path = sys.argv[1]
fea_path = sys.argv[2]
output_file = sys.argv[3]
import_features(font_path, fea_path, output_file)
print("✅ All glyphs feature export successfully.")
.sfd to .ttf
fontforge -lang=ff -c 'Open("name.sfd"); Generate("name.ttf");'