Add Anchor Points with FontForge Python
This article explains how to programmatically define and assign
OpenType anchor points to glyphs using the FontForge Python module
(fontforge). You will learn the required prerequisites,
including setting up GPOS lookups and anchor classes, followed by the
exact syntax and code required to place anchor points on base and mark
glyphs.
Prerequisites: GPOS Lookup and Anchor Classes
In FontForge, an anchor point cannot exist in isolation; it must belong to an Anchor Class, which in turn belongs to an OpenType GPOS subtable (such as Mark-to-Base, Mark-to-Mark, or Cursive attachment).
Before attaching points to glyphs, you must ensure the corresponding GPOS lookup and anchor class exist in the font.
Step 1: Create the Lookup and Subtable
If your font does not already have an appropriate GPOS lookup, create
one using font.addLookup() and
font.addLookupSubtable():
import fontforge
font = fontforge.open("MyFont.sfd")
lookup_name = "mark_to_base_lookup"
subtable_name = "mark_to_base_subtable"
# Create a Mark-to-Base GPOS lookup
font.addLookup(lookup_name, "gpos_mark2base", (), (("latn", ("dflt",)),))
# Add a subtable to the lookup
font.addLookupSubtable(lookup_name, subtable_name)Step 2: Define the Anchor Class
Once the subtable is defined, bind an anchor class (e.g.,
"top", "bottom") to that subtable using
font.addAnchorClass():
anchor_class_name = "top"
# Associate the anchor class with the subtable
font.addAnchorClass(subtable_name, anchor_class_name)Step 3: Add Anchor Points to Glyphs
Anchor points are placed using the
glyph.addAnchorPoint() method.
Method signature:
glyph.addAnchorPoint(anchor_class_name, anchor_type, x, y, [lig_index])anchor_class_name(str): The exact name of the anchor class defined in Step 2.anchor_type(str): The point's role. Common values include:"base": Used for standard base glyphs."mark": Used for combining diacritics."ligature": Used for composite glyphs requiring multiple attachment sites."basemark": Used when a mark acts as a base for another mark."entry"/"exit": Used for cursive script connections.
x(int/float): The horizontal coordinate of the point.y(int/float): The vertical coordinate of the point.lig_index(int, optional): Specifies which component of a ligature the anchor belongs to (0-indexed).
Complete Code Example
The following script sets up a lookup, defines an anchor class named
"top", and positions coordinates on a base glyph
(a) and a combining mark (acutecomb):
import fontforge
# Open font
font = fontforge.open("MyFont.sfd")
# 1. Create Lookup and Subtable
font.addLookup("m2b_lookup", "gpos_mark2base", (), (("latn", ("dflt",)),))
font.addLookupSubtable("m2b_lookup", "m2b_subtable")
# 2. Create Anchor Class
font.addAnchorClass("m2b_subtable", "top")
# 3. Add Base Anchor to glyph 'a'
base_glyph = font["a"]
base_glyph.addAnchorPoint("top", "base", 260, 480)
# 4. Add Mark Anchor to combining acute
mark_glyph = font["acutecomb"]
mark_glyph.addAnchorPoint("top", "mark", 0, 480)
# Save changes
font.save("MyFont.sfd")
font.close()Managing Existing Anchor Points
To inspect or remove existing points programmatically:
Inspect points: Access
glyph.anchorPoints, which returns a tuple of tuples containing point data:for pt in glyph.anchorPoints: name, pt_type, x, y, lig_index = pt print(name, pt_type, x, y)Clear points: Assign an empty tuple to remove all anchor points from a glyph:
glyph.anchorPoints = ()