textshape

module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2026 License: MIT

README

textshape

A pure Go implementation of text shaping, inspired by HarfBuzz.

Features

  • OpenType Shaping: GSUB (substitution) and GPOS (positioning)
  • Ligatures: Standard ligatures (fi, fl, ffi, ffl, etc.)
  • Kerning: Pair adjustment positioning
  • Mark positioning: Base-to-mark, mark-to-mark attachment
  • Font Subsetting: Create minimal fonts for PDF embedding
  • CFF Support: OpenType/CFF font subsetting with subroutine optimization
  • HarfBuzz-compatible API: Similar concepts and data structures

Installation

go get github.com/boxesandglue/textshape

Quick Start

package main

import (
    "fmt"
    "os"

    "github.com/boxesandglue/textshape/ot"
)

func main() {
    // Load font
    data, _ := os.ReadFile("Roboto-Regular.ttf")
    font, _ := ot.ParseFont(data, 0)

    // Create shaper
    shaper, _ := ot.NewShaper(font)

    // Shape text
    buf := ot.NewBuffer()
    buf.AddString("office")
    buf.GuessSegmentProperties()
    shaper.Shape(buf, nil) // nil = default features

    // Read results
    for i, info := range buf.Info {
        fmt.Printf("glyph=%d advance=%d\n", info.GlyphID, buf.Pos[i].XAdvance)
    }
}

API Overview

Buffer
buf := ot.NewBuffer()
buf.AddString("Hello")           // Add text
buf.AddCodepoints([]Codepoint{}) // Or add codepoints directly
buf.GuessSegmentProperties()     // Auto-detect direction/script
buf.SetDirection(ot.DirectionRTL)
buf.Flags = ot.BufferFlagRemoveDefaultIgnorables
Shaper
shaper, err := ot.NewShaper(font)
shaper.Shape(buf, nil)           // Use default features
shaper.Shape(buf, features)      // Use specific features
shaper.ShapeString("text")       // Convenience method
Features
// Create features programmatically
features := []ot.Feature{
    ot.NewFeatureOn(ot.TagLiga),   // Enable ligatures
    ot.NewFeatureOff(ot.TagKern),  // Disable kerning
    ot.NewFeature(ot.TagAalt, 2),  // Alternate #2
}

// Or parse from string (HarfBuzz-compatible syntax)
f, ok := ot.FeatureFromString("kern")      // kern=1
f, ok := ot.FeatureFromString("-liga")     // liga=0
f, ok := ot.FeatureFromString("aalt=2")    // aalt=2
f, ok := ot.FeatureFromString("kern[3:5]") // kern for clusters 3-5

// Parse comma-separated list
features := ot.ParseFeatures("liga,kern,-smcp")
Convenience Function
// One-liner (caches shapers internally)
err := ot.Shape(font, buf, features)
Font Subsetting
import "github.com/boxesandglue/textshape/subset"

// Simple subsetting
result, err := subset.SubsetString(font, "Hello World")

// With options
input := subset.NewInput()
input.AddString("Hello World")
input.Flags = subset.FlagDropLayoutTables // For PDF embedding

plan, _ := subset.CreatePlan(font, input)
result, _ := plan.Execute()

Supported OpenType Features

GSUB (Glyph Substitution)
Type Name Status
1 Single Substitution
2 Multiple Substitution
3 Alternate Substitution
4 Ligature Substitution
5 Context Substitution
6 Chaining Context
7 Extension
8 Reverse Chaining
GPOS (Glyph Positioning)
Type Name Status
1 Single Adjustment
2 Pair Adjustment (Kerning)
3 Cursive Attachment
4 Mark-to-Base
5 Mark-to-Ligature
6 Mark-to-Mark
7 Context Positioning
8 Chaining Context
9 Extension

Comparison with HarfBuzz

go-hb produces identical results to HarfBuzz for Latin scripts:

Text      HarfBuzz                    go-hb
-----     --------                    -----
Hello     [44 73 80 80 83]           [44 73 80 80 83]    ✓
office    [83 446 71 73]             [83 446 71 73]      ✓
fi        [444]                       [444]               ✓
AV        [37+1249 58+1303]          [37+1249 58+1303]   ✓

Limitations

  • Complex scripts: Arabic, Indic, Thai shapers not yet implemented
  • Variable fonts: Not yet supported
  • Graphite: Not supported

For complex scripts, consider using the full HarfBuzz via cgo or the textlayout package.

License

MIT License - see LICENSE

Acknowledgments

  • HarfBuzz - The original text shaping engine
  • textlayout - Go port that inspired this implementation

Directories

Path Synopsis
internal
testutil
Package testutil provides utilities for testing.
Package testutil provides utilities for testing.
Package ot provides OpenType font table parsing.
Package ot provides OpenType font table parsing.
Package subset provides font subsetting functionality.
Package subset provides font subsetting functionality.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL