Modify Outline Contours with FontForge Python
Yes, you can modify outline contours programmatically using FontForge's built-in Python module. The scripting interface provides granular access to font structures, allowing you to traverse glyph layers, manipulate existing contour points, generate new vector paths from scratch, and execute geometric transformations. This capability is essential for automated font mastering, batch path corrections, algorithmic glyph generation, and variable font manipulation.
Accessing Glyph Layers and Contours
FontForge stores vector outlines within layers. By default, the visible glyph outline is located on the foreground layer. To inspect or modify contours, you load the font, select the desired glyph, and extract its foreground layer:
import fontforge
# Open the font file
font = fontforge.open("MyFont.sfd")
# Access a specific glyph
glyph = font["A"]
# Extract the foreground layer containing contours
layer = glyph.foregroundA layer acts as an iterable collection of
fontforge.contour objects, and each contour acts as an
iterable collection of fontforge.point objects.
Inspecting and Modifying Points
Each point object on a contour contains spatial
coordinates and curve metadata:
xandy: The Cartesian coordinates of the node.on_curve: A boolean value indicating whether the point is an on-curve anchor point (True) or an off-curve Bézier control handle (False).selected: A boolean flag for selection state in the GUI.
To modify existing coordinates, you can iterate through the contours and update point positions directly:
for contour in layer:
for point in contour:
# Move all points 10 units right and 5 units up
point.x += 10
point.y += 5
# Crucial step: Reassign the modified layer back to the glyph
glyph.foreground = layerIn FontForge's Python API, changes made to a layer's contours are not
applied to the glyph automatically. You must explicitly reassign the
layer variable back to glyph.foreground to commit the
modifications.
Creating and Appending New Contours
You can construct contours programmatically and add them to existing
glyphs using the fontforge.contour class:
# Create an empty contour
new_contour = fontforge.contour()
# Add points: moveTo, lineTo, or curveTo
new_contour.moveTo(100, 100)
new_contour.lineTo(200, 100)
new_contour.lineTo(200, 200)
new_contour.lineTo(100, 200)
new_contour.closed = True
# Append to the layer and save to the glyph
layer += new_contour
glyph.foreground = layerFor cubic Bézier curves, use
new_contour.cubicTo((cp1_x, cp1_y), (cp2_x, cp2_y), (end_x, end_y)).
Transformations and Contour Utilities
FontForge includes utility methods that apply directly to contour objects:
Transformations: Apply affine transformations using the
psMatmodule.import psMat matrix = psMat.scale(1.2) for contour in layer: contour.transform(matrix) glyph.foreground = layerDirection and Winding: Correct path orientation (clockwise vs. counter-clockwise) using
contour.direction = "clockwise"orglyph.correctDirection().Simplification: Merge redundant points along paths using
contour.simplify()to optimize file size and clean up generated vectors.