Glyph Outlines

Glyph Outlines

Glyph outlines give you the actual vector path of a glyph — the Bezier curves that define its shape. This is useful for rendering text as filled paths (e.g., in SVG or MetaPost), hit testing, computing exact bounding boxes, or any scenario where you need the geometry of a character, not just its advance width.

Extracting an Outline

Call GlyphOutline on a Face with a glyph ID. Glyph IDs come from shaping (via buf.Info[i].GlyphID) or from a cmap lookup.

face, _ := ot.NewFace(font)

// Look up glyph ID for 'A'
cmap := face.Cmap()
gid, ok := cmap.Lookup(ot.Codepoint('A'))
if !ok {
    log.Fatal("no glyph for 'A'")
}

outline, ok := face.GlyphOutline(gid)
if !ok {
    // Empty glyph (e.g. space)
    return
}

for _, seg := range outline.Segments {
    switch seg.Op {
    case ot.SegmentMoveTo:
        fmt.Printf("M %.1f,%.1f\n", seg.Args[0].X, seg.Args[0].Y)
    case ot.SegmentLineTo:
        fmt.Printf("L %.1f,%.1f\n", seg.Args[0].X, seg.Args[0].Y)
    case ot.SegmentQuadTo:
        fmt.Printf("Q %.1f,%.1f %.1f,%.1f\n",
            seg.Args[0].X, seg.Args[0].Y,
            seg.Args[1].X, seg.Args[1].Y)
    case ot.SegmentCubeTo:
        fmt.Printf("C %.1f,%.1f %.1f,%.1f %.1f,%.1f\n",
            seg.Args[0].X, seg.Args[0].Y,
            seg.Args[1].X, seg.Args[1].Y,
            seg.Args[2].X, seg.Args[2].Y)
    }
}

Combining Shaping and Outlines

A typical workflow shapes text first, then extracts outlines for each glyph and positions them using the shaping output:

font, _ := ot.ParseFont(fontData, 0)
face, _ := ot.NewFace(font)
shaper, _ := ot.NewShaperFromFace(face)

buf := ot.NewBuffer()
buf.AddString("Hello")
buf.GuessSegmentProperties()
shaper.Shape(buf, nil)

upem := float64(face.Upem())
fontSize := 12.0
scale := fontSize / upem
curX := 0.0

for i := range buf.Info {
    gid := buf.Info[i].GlyphID
    pos := buf.Pos[i]

    outline, ok := face.GlyphOutline(gid)
    if ok {
        ox := curX + float64(pos.XOffset)*scale
        oy := float64(pos.YOffset) * scale
        for _, seg := range outline.Segments {
            // Scale and translate each point by (ox, oy, scale)
            x := float64(seg.Args[0].X)*scale + ox
            y := float64(seg.Args[0].Y)*scale + oy
            _ = x
            _ = y
            // ... render segment
        }
    }

    curX += float64(pos.XAdvance) * scale
}

Segment Types

Each segment in a GlyphOutline has an operation and up to three argument points:

Op Name Args used Description
SegmentMoveTo Move [0] Start a new contour at this point
SegmentLineTo Line [0] Straight line to endpoint
SegmentQuadTo Quad [0], [1] Quadratic Bezier: control point, endpoint
SegmentCubeTo Cubic [0], [1], [2] Cubic Bezier: control 1, control 2, endpoint

TrueType fonts use quadratic Bezier curves (SegmentQuadTo). CFF/OpenType fonts (.otf) use cubic curves (SegmentCubeTo). Both formats are fully supported.

All coordinates are in font units. Scale by fontSize / upem to convert to points or pixels.

Composite Glyphs

Some glyphs are built from other glyphs — for example, “e” (U+00E9) may combine the base “e” glyph with an acute accent component. GlyphOutline resolves composite glyphs recursively and applies the affine transform (translation, scale, rotation) of each component. The returned segments are the fully flattened outline — you don’t need to handle composition yourself.

Empty Glyphs

GlyphOutline returns false (second return value) for empty glyphs like space or .notdef that have no outline data.

Converting Quadratic to Cubic Curves

If your rendering pipeline only supports cubic Bezier curves (common in PDF and PostScript), convert quadratic segments with the standard degree elevation formula:

// Quadratic control point and endpoint
qx, qy := seg.Args[0].X, seg.Args[0].Y
ex, ey := seg.Args[1].X, seg.Args[1].Y

// Previous point (start of this segment)
sx, sy := lastX, lastY

// Cubic control points
c1x := sx + 2.0/3.0*(qx-sx)
c1y := sy + 2.0/3.0*(qy-sy)
c2x := ex + 2.0/3.0*(qx-ex)
c2y := ey + 2.0/3.0*(qy-ey)

This is an exact conversion — no approximation error.