Automating OpenType Features in FontForge with Python

Automating OpenType feature insertion is fully supported in FontForge through its native Python extension. By leveraging the fontforge Python module, type designers and developers can programmatically define layout tables, create lookups, bind feature tags, and map glyph substitutions or positionings. This workflow eliminates repetitive manual configuration in the FontForge graphical interface and enables seamless integration into automated font build pipelines.

Understanding the FontForge OpenType Architecture

In OpenType, features (such as liga for ligatures or kern for kerning) rely on lookups and subtables. FontForge mirrors this structure in Python:

  1. Lookups: Define the type of operation (e.g., substitution or positioning) and link to specific OpenType feature tags and script/language combinations.
  2. Subtables: Exist inside lookups and contain the actual glyph mapping rules.

Method 1: Using the Native Python API

You can programmatically construct lookups, add subtables, and assign glyph rules directly using FontForge's built-in methods.

Here is an example demonstrating how to automate a standard ligature (liga) feature:

import fontforge

# Open the font file
font = fontforge.open("MyFont.sfd")

# 1. Define lookup parameters
lookup_name = "Ligatures_lookup"
lookup_type = "gsub_ligature"
flags = ()  # Flags such as RightToLeft or IgnoreBaseGlyphs if needed
feature_tuple = (("liga", (("latn", ("dflt")),)),)

# 2. Add the lookup to the font
font.addLookup(lookup_name, lookup_type, flags, feature_tuple)

# 3. Add a subtable to the lookup
subtable_name = "Ligatures_subtable"
font.addLookupSubtable(lookup_name, subtable_name)

# 4. Map glyphs to the subtable
# Example: replace 'f' + 'i' with 'f_i'
if "f_i" in font:
    ligature_glyph = font["f_i"]
    ligature_glyph.addPosSub(subtable_name, ("f", "i"))

# Save and export
font.save("MyFont.sfd")
font.generate("MyFont.otf")

Method 2: Merging Adobe Feature Files (.fea)

While the native API provides fine-grained control, the most common and maintainable method for automating complex OpenType tables is importing an Adobe Feature File (.fea). FontForge can parse and merge external feature files directly into an existing font object.

import fontforge

font = fontforge.open("MyFont.sfd")

# Merge external OpenType feature definitions
font.mergeFeature("features.fea")

# Save the updated font
font.save("MyFont.sfd")
font.generate("MyFont.otf")

The accompanying features.fea file contains standard syntax:

feature liga {
    sub f i by f_i;
    sub f l by f_l;
} liga;

Choosing the Right Approach

  • Native Python API: Ideal when you need to dynamically calculate glyph relationships, kerning values, or component names on the fly based on font metadata.
  • Feature File Merging (mergeFeature): Ideal when your OpenType logic is already established, standardized across multiple font weights, or authored using standard OpenType syntax tools.