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.py

The 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 via target_font.em = source_font.em.