Batch Update Font Metadata Using FontForge
Yes, you can automate metadata updates across multiple font files using FontForge's built-in Python scripting engine. This guide explains how to programmatically batch-process font files to update key metadata fields—such as family names, copyright notices, version strings, and designer credits—without manually opening each file in the FontForge graphical user interface.
How Automation Works in FontForge
FontForge includes a powerful Python extension that provides access
to its core font-manipulation engine. When you install FontForge, it
typically provides a standalone command-line interpreter executable via
fontforge -script <your_script.py>. This allows you
to iterate over directories of TrueType (.ttf), OpenType
(.otf), or Web Open Font Format
(.woff/.woff2) files, apply metadata updates,
and re-export the files automatically.
Writing the Batch Metadata Update Script
Below is a complete, minimal Python script that traverses a directory of fonts, modifies their naming and metadata attributes, and generates updated files.
Save the following code as update_metadata.py:
import os
import sys
import fontforge
# Directory containing the fonts to update
INPUT_DIR = "./fonts"
OUTPUT_DIR = "./fonts_updated"
# New metadata values to apply
NEW_COPYRIGHT = "Copyright (c) 2026 Example Foundry. All rights reserved."
NEW_DESIGNER = "Jane Doe"
NEW_VERSION = "2.000"
FAMILY_PREFIX = "Custom "
def process_fonts():
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
for filename in os.listdir(INPUT_DIR):
if filename.lower().endswith((".ttf", ".otf")):
input_path = os.path.join(INPUT_DIR, filename)
output_path = os.path.join(OUTPUT_DIR, filename)
print(f"Processing: {filename}")
# Open the font file
font = fontforge.open(input_path)
# Update primary metadata properties
font.copyright = NEW_COPYRIGHT
font.version = NEW_VERSION
# Update naming records
font.familyname = FAMILY_PREFIX + font.familyname
font.fontname = FAMILY_PREFIX.replace(" ", "") + font.fontname
font.fullname = FAMILY_PREFIX + font.fullname
# Update OpenType (SFNT) Name Table values
# Language ID 0x409 represents English (US)
# Name ID 9 = Designer, Name ID 0 = Copyright
font.appendSFNTName("English (US)", "Designer", NEW_DESIGNER)
font.appendSFNTName("English (US)", "Copyright", NEW_COPYRIGHT)
font.appendSFNTName("English (US)", "Version", f"Version {NEW_VERSION}")
# Generate the new font file
font.generate(output_path)
font.close()
print("Batch processing complete.")
if __name__ == "__main__":
process_fonts()Essential FontForge Metadata Properties
When modifying font records in Python, FontForge exposes several core attributes directly on the font object:
font.fontname: The PostScript name of the font. It should contain no spaces.font.familyname: The family name displayed in font menus (e.g., "Helvetica").font.fullname: The full display name (e.g., "Helvetica Bold").font.weight: The weight description (e.g., "Regular", "Bold", "Light").font.version: The font version string.font.copyright: The high-level copyright declaration.
For deeper OpenType table modifications, use the
appendSFNTName(language, string_type, value) method. This
handles specific standard table fields such as Manufacturer (Name ID 8),
Designer (Name ID 9), URL Vendor (Name ID 11), and License Description
(Name ID 13).
Running the Automation Script
Execute the script using the FontForge command-line interface:
fontforge -script update_metadata.pyIf your system's default Python environment has the
fontforge module properly linked or compiled, you can also
run the script directly using standard Python:
python3 update_metadata.pyBest Practices
- Always work on copies: Never run metadata batch scripts directly on your original source files. Output the modified fonts to a dedicated folder to avoid irreversible corruption.
- Validate the PostScript name: Ensure that
font.fontnamedoes not contain spaces or non-ASCII characters, as invalid PostScript names can cause operating systems or PDF generators to reject the font. - Preserve font features: Using
font.generate()retains existing hinting, kerning, and OpenType layout features by default, but you should verify your exported fonts in a font validator to ensure all tables remain intact after processing.