Custom Validation Checks with FontForge Python

FontForge provides a robust Python scripting interface that allows type designers and font developers to automate testing and build custom validation checks. By querying glyph geometry, font metrics, metadata, and OpenType tables directly through the fontforge Python module, you can programmatically detect design flaws, enforce style standards, and catch technical errors across entire font families before production.

Built-In Validation via Python

FontForge includes a native validation suite that can be executed directly from Python. The glyph.validate() method runs standard technical checks on individual glyphs, assessing outline validity, path direction, self-intersections, and point placement.

import fontforge

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

for glyph in font.glyphs():
    state = glyph.validate()
    if state != 0:
        print(f"Validation warning on {glyph.glyphname}: code {state}")

The returned integer is a bitmask representing specific errors, such as missing extrema, open contours, or self-intersecting paths.

Writing Custom Geometric Checks

You are not limited to built-in rules; you can inspect the raw coordinates of contours and points to enforce proprietary geometric constraints.

1. Detecting Extrema Violations

Glyph curves generally require on-curve control points at their horizontal and vertical extrema for proper rasterization and hinting. You can iterate through a glyph's layers and contours to inspect control points:

def check_extrema(glyph):
    layer = glyph.layers[glyph.active_layer]
    for contour in layer:
        for point in contour:
            # Analyze on-curve and off-curve coordinates
            if point.on_curve:
                # Custom logic for bounding limits
                pass

2. Checking Minimum Distance Between Points

Coincident or nearly overlapping points can cause rendering artifacts. You can compute the Euclidean distance between sequential points along a contour to ensure they meet a minimum threshold:

import math

def check_minimum_distance(glyph, min_dist=1.0):
    layer = glyph.layers[glyph.active_layer]
    for contour in layer:
        for i in range(len(contour)):
            p1 = contour[i]
            p2 = contour[(i + 1) % len(contour)]
            dist = math.hypot(p2.x - p1.x, p2.y - p1.y)
            if dist < min_dist:
                print(f"{glyph.glyphname}: Points too close ({dist:.2f} units)")

Validating Metrics and Spacing

Custom scripts can evaluate spacing rules across the font to ensure uniform appearance:

  • Bounding Box Checks: Verify that glyph paths do not exceed the font's ascent or descent limits unexpectedly.
  • Sidebearing Consistency: Check that left sidebearings (LSB) and right sidebearings (RSB) meet minimum margins or adhere to spacing tables.
  • Monospace Uniformity: If building a monospaced font, assert that glyph.width is identical for every character.
def validate_monospace(font, expected_width=600):
    for glyph in font.glyphs():
        if glyph.width != expected_width:
            print(f"Width error: {glyph.glyphname} has width {glyph.width}")

Verifying Metadata and Encodings

FontForge Python scripts can inspect font-level properties, OpenType features, and Unicode mappings to ensure delivery compliance:

  • Required Glyphs: Verify the existence of essential glyphs such as .notdef, space, and standard punctuation.
  • Unicode Coverage: Ensure specific blocks (such as Basic Latin or accented sets) contain no unmapped gaps.
  • Naming Consistency: Check that the PostScript name, family name, and weight strings in font.sfnt_names follow the required naming conventions and do not contain illegal characters.

Automating Validation in Build Pipelines

Because FontForge can be run headless from the command line using fontforge -script validator.py, you can integrate custom validation scripts directly into continuous integration (CI) workflows. By configuring your script to exit with a non-zero status code (sys.exit(1)) when a test fails, you prevent faulty font binaries from being generated and released.