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:
- Lookups: Define the type of operation (e.g., substitution or positioning) and link to specific OpenType feature tags and script/language combinations.
- 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.