Copy Glyphs Between Fonts Using FontForge Python
This guide explains how to programmatically transfer glyph outlines, metrics, and references between distinct font files using FontForge's Python module. By leveraging the internal clipboard mechanism or manipulating glyph layers directly, you can automate batch migrations, merge font styles, or replace specific characters with consistent results across multiple formats like TTF, OTF, and SFD.
Prerequisites
To execute FontForge Python scripts, ensure you run your code via the
FontForge binary using the -script flag, or within an
environment where the native fontforge extension is
installed.
fontforge -script copy_glyphs.pyThe Standard Clipboard Method
The most reliable way to copy complete glyph data—including contours, components, and hints—is using FontForge's selection and clipboard APIs.
import fontforge
# Open the source and destination font files
source_font = fontforge.open("SourceFont.otf")
target_font = fontforge.open("TargetFont.otf")
# Define the glyphs you want to copy (by glyph name)
glyphs_to_copy = ["A", "B", "ampersand", "copyright"]
for glyph_name in glyphs_to_copy:
if glyph_name in source_font:
# Create the glyph in the target font if it does not already exist
if glyph_name not in target_font:
target_font.createChar(-1, glyph_name)
# Select and copy the glyph from the source font
source_font.selection.select(glyph_name)
source_font.copy()
# Select and paste into the target font
target_font.selection.select(glyph_name)
target_font.paste()
# Explicitly match the advance width
target_font[glyph_name].width = source_font[glyph_name].width
# Generate the updated font file
target_font.generate("TargetFont_Updated.otf")
# Clean up resources
source_font.close()
target_font.close()Direct Layer Copying (Advanced Method)
If you only want vector outlines without overwriting existing metadata, unicode mappings, or kerning classes, assign the foreground layer directly between glyph objects.
import fontforge
source_font = fontforge.open("SourceFont.otf")
target_font = fontforge.open("TargetFont.otf")
glyph_name = "C"
# Retrieve glyph references
src_glyph = source_font[glyph_name]
dst_glyph = target_font.createChar(src_glyph.unicode, glyph_name)
# Copy the foreground layer containing the outlines
dst_glyph.layers["Fore"] = src_glyph.layers["Fore"]
# Match horizontal metrics
dst_glyph.width = src_glyph.width
dst_glyph.vwidth = src_glyph.vwidth
target_font.generate("TargetFont_Updated.otf")
source_font.close()
target_font.close()Batch Copying All Glyphs
To merge or overwrite an entire font, iterate through the source font's glyph dictionary:
import fontforge
source_font = fontforge.open("SourceFont.ttf")
target_font = fontforge.open("TargetFont.ttf")
for glyph in source_font.glyphs():
name = glyph.glyphname
if name not in target_font:
target_font.createChar(glyph.unicode, name)
source_font.selection.select(name)
source_font.copy()
target_font.selection.select(name)
target_font.paste()
target_font[name].width = glyph.width
target_font.generate("MergedFont.ttf")
source_font.close()
target_font.close()Key Considerations
- References and Components: Composite glyphs (such
as accented characters) depend on base glyphs. When copying composite
glyphs, ensure the component glyphs are copied first, or use
glyph.unlinkRef()before copying to flatten components into standalone vector paths. - Em Square Matching: If the source and target fonts
use different units per em (UPM), scale the contours using
glyph.transform(psMat.scale(target_upm / source_upm))before pasting, or match the target font's UPM viatarget_font.em = source_font.em.