hbsubset

package module
v0.0.0-...-7d8dc5e Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 9 Imported by: 0

README

go-hbsubset

Go Reference Test Attest hbsubset build

Go bindings for HarfBuzz's font subsetter (hb-subset) without cgo.

This library wraps a WebAssembly build of HarfBuzz transpiled to Go using wasm2go.

[!WARNING]

These bindings are still experimental and are subject to change. They have not been tested extensively yet.

The wasm2go blob is fully reproducible and verified.

To have working IDE integration while working on the bindings, use bear -- make -C src distclean download all CXX=/path/to/wasi-sdk/bin/wasm32-wasip1-clang++ WASM_OPT=/path/to/binaryen/bin/wasm-opt to download the Harfbuzz source and generate the compile_commands.json.

Usage

To subset a single font:

import "github.com/pgaskin/go-hbsubset"

out, err := hbsubset.Subset(font, 0, &hbsubset.Options{
    Unicodes: []rune("some text"),
})

You can specify other options too:

import (
    "github.com/pgaskin/go-gfsubsets"
    "golang.org/x/text/unicode/rangetable"
)

out, err := hbsubset.Subset(data, 0, &hbsubset.Options{
    UnicodeRanges: rangetable.Merge(
        gfsubsets.Latin,
        &unicode.RangeTable{
            R16: []unicode.Range16{
                {Stride: 1, Lo: '\u2002', Hi: '\u201E'}, // spaces, smart punctuation
                {Stride: 1, Lo: '\u2022', Hi: '\u2022'}, // bullet
                {Stride: 1, Lo: '\u2026', Hi: '\u2026'}, // ellipsis
            },
        },
    ),
    PinAllAxesToDefault: true,
    AxisRanges: map[hbsubset.Tag]hbsubset.AxisRange{
        hbsubset.MakeTag("wght"): {Min: 100, Max: 900, Default: 400},
    },
    LayoutFeatures: []hbsubset.Tag{
        hbsubset.MakeTag("kern"),
        hbsubset.MakeTag("mkmk"),
        hbsubset.MakeTag("size"),
        hbsubset.MakeTag("liga"),
    },
    NameIDs: []hbsubset.NameID{
        hbsubset.NameUniqueID,
        hbsubset.NameCopyright,
        hbsubset.NameFontFamily,
        hbsubset.NameFontSubfamily,
        hbsubset.NameTypographicFamily,
        hbsubset.NameTypographicSubfamily,
        hbsubset.NameFullName,
        hbsubset.NameMacFullName,
        hbsubset.NamePostscriptName,
        hbsubset.NameManufacturer,
        hbsubset.NameDescription,
        hbsubset.NameVariationsPSPrefix,
    },
    LayoutScripts: []hbsubset.Tag{
        hbsubset.MakeTag("latn"), // latin
    },
    NameLanguages: []uint32{
        1033, // english
    },
})

You can reuse a font for multiple subsets (this also lets you access the font metadata):

face, err := hbsubset.NewFace(font, 0)
if err != nil {
    return err
}
face.Preprocess()

for _, page := range pages {
    out, err := face.Subset(&hbsubset.Options{Unicodes: page})
    // ...
}

You can use SubsetWithMapping to get the renumbered glyphs.

out, m, err := hbsubset.SubsetWithMapping(font, &hbsubset.Options{
    Unicodes: []rune("Hi"),
})

new, ok := m.NewGlyph(oldGID)

for old, new := range m.Glyphs() {
    // ...
}

There are also some helpers to get relevant info (names, axes, glyph mappings, etc) from the font before subsetting (see the docs and faceinfo.go).

Documentation

Index

Constants

View Source
const (
	FlagDefault                 = Flags(internal.HB_SUBSET_FLAGS_DEFAULT)                  // empty flags
	FlagNoHinting               = Flags(internal.HB_SUBSET_FLAGS_NO_HINTING)               // drop hinting instructions
	FlagRetainGIDs              = Flags(internal.HB_SUBSET_FLAGS_RETAIN_GIDS)              // make dropped glyphs empty instead of renumbering
	FlagDesubroutinize          = Flags(internal.HB_SUBSET_FLAGS_DESUBROUTINIZE)           // remove subroutines when subsetting a CFF font
	FlagNameLegacy              = Flags(internal.HB_SUBSET_FLAGS_NAME_LEGACY)              // retain non-unicode name records
	FlagSetOverlapsFlag         = Flags(internal.HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)        // set the OVERLAP_SIMPLE flag on each simple glyph
	FlagPassthroughUnrecognized = Flags(internal.HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) // don't drop unrecognized tables
	FlagNotdefOutline           = Flags(internal.HB_SUBSET_FLAGS_NOTDEF_OUTLINE)           // retain the outline of the .notdef glyph
	FlagGlyphNames              = Flags(internal.HB_SUBSET_FLAGS_GLYPH_NAMES)              // retain PostScript glyph names
	FlagNoPruneUnicodeRanges    = Flags(internal.HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)  // prevent OS/2 unicode ranges from being recalculated
	FlagNoLayoutClosure         = Flags(internal.HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)        // skip glyph closure over GSUB layout substitution rules
	FlagOptimizeIUPDeltas       = Flags(internal.HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS)      // perform IUP delta optimization on remaining gvar deltas
	FlagNoBidiClosure           = Flags(internal.HB_SUBSET_FLAGS_NO_BIDI_CLOSURE)          // do not pull mirrored versions of input codepoints into the subset
	FlagDowngradeCFF2           = Flags(internal.HB_SUBSET_FLAGS_DOWNGRADE_CFF2)           // convert an instanced CFF2 table to CFF1 for compatibility with older renderers
)
View Source
const (
	NameCopyright            = NameID(internal.HB_OT_NAME_ID_COPYRIGHT)
	NameFontFamily           = NameID(internal.HB_OT_NAME_ID_FONT_FAMILY)
	NameFontSubfamily        = NameID(internal.HB_OT_NAME_ID_FONT_SUBFAMILY)
	NameUniqueID             = NameID(internal.HB_OT_NAME_ID_UNIQUE_ID)
	NameFullName             = NameID(internal.HB_OT_NAME_ID_FULL_NAME)
	NameVersionString        = NameID(internal.HB_OT_NAME_ID_VERSION_STRING)
	NamePostscriptName       = NameID(internal.HB_OT_NAME_ID_POSTSCRIPT_NAME)
	NameTrademark            = NameID(internal.HB_OT_NAME_ID_TRADEMARK)
	NameManufacturer         = NameID(internal.HB_OT_NAME_ID_MANUFACTURER)
	NameDesigner             = NameID(internal.HB_OT_NAME_ID_DESIGNER)
	NameDescription          = NameID(internal.HB_OT_NAME_ID_DESCRIPTION)
	NameVendorURL            = NameID(internal.HB_OT_NAME_ID_VENDOR_URL)
	NameDesignerURL          = NameID(internal.HB_OT_NAME_ID_DESIGNER_URL)
	NameLicense              = NameID(internal.HB_OT_NAME_ID_LICENSE)
	NameLicenseURL           = NameID(internal.HB_OT_NAME_ID_LICENSE_URL)
	NameTypographicFamily    = NameID(internal.HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY)
	NameTypographicSubfamily = NameID(internal.HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY)
	NameMacFullName          = NameID(internal.HB_OT_NAME_ID_MAC_FULL_NAME)
	NameSampleText           = NameID(internal.HB_OT_NAME_ID_SAMPLE_TEXT)
	NameCidFindfontName      = NameID(internal.HB_OT_NAME_ID_CID_FINDFONT_NAME)
	NameWWSFamily            = NameID(internal.HB_OT_NAME_ID_WWS_FAMILY)
	NameWWSSubfamily         = NameID(internal.HB_OT_NAME_ID_WWS_SUBFAMILY)
	NameLightBackground      = NameID(internal.HB_OT_NAME_ID_LIGHT_BACKGROUND)
	NameDarkBackground       = NameID(internal.HB_OT_NAME_ID_DARK_BACKGROUND)
	NameVariationsPSPrefix   = NameID(internal.HB_OT_NAME_ID_VARIATIONS_PS_PREFIX)
)

Variables

This section is empty.

Functions

func FaceCount

func FaceCount(data []byte) (int, error)

FaceCount returns the number of faces in a font collection. If the font is not a collection, the count will be 1. If the data is not a font, the count will be 0. An error will only be returned if the wasm memory allocation fails.

func Subset

func Subset(font []byte, index int, opts *Options) ([]byte, error)

Subset is a helper to call NewFace and Face.Subset.

Types

type AxisRange

type AxisRange struct {
	Min, Max, Default float32
}

AxisRange partially instances a variable font by limiting a variation axis to [Min, Max] with the given Default.

type Face

type Face struct {
	// contains filtered or unexported fields
}

Face is a loaded Harfbuzz font. It is safe for concurrent use, but all methods lock a mutex.

func NewFace

func NewFace(data []byte, index int) (*Face, error)

NewFace loads an sfnt (TrueType/OpenType) font face from data. The index should be 0 unless data is a font collection (TTC/OTC).

func (*Face) GlyphCount

func (f *Face) GlyphCount() uint32

GlyphCount returns the number of glyphs in the face.

func (*Face) GlyphMapping

func (f *Face) GlyphMapping() map[rune]uint32

GlyphMapping returns the nominal cmap mapping from unicode codepoints to glyph indices.

func (*Face) Index

func (f *Face) Index() int

Index returns the face's index within its font collection.

func (*Face) Name

func (f *Face) Name(nameID uint32, language string) (string, bool)

Name returns a name-table entry as UTF-8. The language is a BCP 47 tag from [Face.NameIDs], or empty for English. It returns false if the face has no matching non-empty name.

func (*Face) Names

func (f *Face) Names() []NameEntry

Names returns the name-table entries of the face, in font order.

func (*Face) Preprocess

func (f *Face) Preprocess() error

Preprocess prepares the font to optimize repeated subset calls.

func (*Face) Subset

func (f *Face) Subset(opts *Options) ([]byte, error)

Subset subsets the face according to opts and returns the new sfnt.

func (*Face) SubsetWithMapping

func (f *Face) SubsetWithMapping(opts *Options) ([]byte, Mapping, error)

SubsetWithMapping is like Face.Subset but also returns the Mapping.

func (*Face) Table

func (f *Face) Table(tag Tag) ([]byte, error)

Table returns the raw bytes of a single sfnt table, or nil if the table does not exist.

func (*Face) Tables

func (f *Face) Tables() []Tag

Tables returns the sfnt table tags present in the face, in font order.

func (*Face) UnitsPerEm

func (f *Face) UnitsPerEm() int

UnitsPerEm returns the design units per em of the face.

func (*Face) VariationAxes

func (f *Face) VariationAxes() map[Tag]AxisRange

VariationAxes returns the fvar variation axes of the face and their value ranges.

func (*Face) VariationSelectors

func (f *Face) VariationSelectors() []rune

VariationSelectors returns the unicode variation selectors in the face's cmap, in ascending order. Note that variation selectors are a completely different concept from variation axes.

func (*Face) VariationUnicodes

func (f *Face) VariationUnicodes(selector rune) []rune

VariationUnicodes returns the unicode codepoints which the face's cmap maps to a variant glyph under the given variation selector, in ascending order.

type Flags

type Flags uint32

Flags is a bitmask of boolean options.

type Mapping

type Mapping struct {
	// contains filtered or unexported fields
}

Mapping describes renumbered glyphs.

func SubsetWithMapping

func SubsetWithMapping(font []byte, index int, opts *Options) ([]byte, Mapping, error)

SubsetWithMapping is like Subset but also returns the Mapping.

func (Mapping) Glyphs

func (m Mapping) Glyphs() iter.Seq2[uint32, uint32]

Glyphs iterates over the retained glyphs as (source glyph id, subset glyph id) pairs, in an arbitrary order.

func (Mapping) NewGlyph

func (m Mapping) NewGlyph(oldGID uint32) (uint32, bool)

NewGlyph returns the subset glyph id corresponding to a source glyph id, reporting whether that source glyph was retained.

func (Mapping) NumGlyphs

func (m Mapping) NumGlyphs() int

NumGlyphs returns the number of glyphs retained in the subset.

func (Mapping) OldGlyph

func (m Mapping) OldGlyph(newGID uint32) (uint32, bool)

OldGlyph returns the source glyph id corresponding to a subset glyph id, reporting whether such a glyph exists in the subset.

func (Mapping) RuneGlyph

func (m Mapping) RuneGlyph(r rune) (uint32, bool)

RuneGlyph returns the source glyph id that a unicode codepoint maps to, reporting whether the codepoint was retained. Combine it with Mapping.NewGlyph to obtain the codepoint's glyph id in the subset.

func (Mapping) Runes

func (m Mapping) Runes() iter.Seq2[rune, uint32]

Runes iterates over the retained unicode codepoints as (codepoint, source glyph id) pairs, in an arbitrary order.

type NameEntry

type NameEntry struct {
	// ID is the OpenType name ID (e.g. 1 is the font family name).
	ID NameID

	// Language is the BCP 47 language tag of the entry (e.g. "en"), for use
	// with [Face.Name].
	Language string

	// LanguageID is the raw name-record language ID of the entry, as used by
	// [Options.NameLanguages]. It is zero if the record could not be resolved.
	LanguageID uint32
}

NameEntry identifies a name-table entry by name ID and language.

type NameID

type NameID uint32

NameID is an OpenType name ID.

type Options

type Options struct {
	// ExcludeUnicodes makes [Options.Unicodes] and [Options.UnicodeRanges]
	// subtract from the full set instead of adding to it.
	ExcludeUnicodes bool

	// ExcludeGlyphs makes [Options.Glyphs] subtract from the full set instead
	// of adding to it.
	ExcludeGlyphs bool

	// Flags is a bitmask of boolean options.
	Flags Flags

	// Unicodes adds unicode codepoints to retain glyphs for.
	Unicodes []rune

	// UnicodesRanges adds unicode codepoints to retain glyphs for. You can make
	// these directly (LatinOffset is ignored) or use
	// golang.org/x/text/unicode/rangetable.
	UnicodeRanges *unicode.RangeTable

	// Glyphs are glyph indices to retain in addition to those reached from the
	// requested unicode codepoints.
	Glyphs []uint32

	// LayoutFeatures are the OpenType layout feature tags to retain.
	LayoutFeatures []Tag

	// LayoutScripts are the OpenType script tags to retain. It defaults to all
	// scripts when empty.
	LayoutScripts []Tag

	// NameIDs are the name-table name IDs to retain.
	NameIDs []NameID

	// NameLanguages are the raw name-table language IDs to retain (see
	// [NameID.LanguageID]).
	NameLanguages []uint32

	// NoSubsetTables are table tags to pass through unchanged rather than
	// subsetting.
	NoSubsetTables []Tag

	// DropTables are table tags to remove entirely.
	DropTables []Tag

	// GlyphMapping forces specific old-glyph-id to new-glyph-id assignments in
	// the subset. This is applied after [Options.Glyphs].
	GlyphMapping map[uint32]uint32

	// PinAllAxesToDefault pins every axis to its default, fully instancing a
	// variable font.
	PinAllAxesToDefault bool

	// PinAxesToDefault pins the named axes to their default value. This is
	// applied after [Options.PinAllAxesToDefault].
	PinAxesToDefault []Tag

	// PinAxes pins variation axes to specific values. This is applied after
	// [Options.PinAllAxesToDefault] and [Options.PinAxesToDefault].
	PinAxes map[Tag]float32

	// AxisRanges limits variation axes to sub-ranges, partially instancing a
	// variable font. This is applied after
	// [Options.PinAllAxesToDefault], [Options.PinAxesToDefault], and [Options.PinAxes].
	AxisRanges map[Tag]AxisRange
}

Options is the configuration for a subset plan.

The zero value retains only the minimal structure of the font.

type Tag

type Tag [4]byte

Tag is a four-byte identifier, for example, a sfnt table tag ("glyf"), a layout feature tag ("liga"), or a variation axis tag ("wght").

func MakeTag

func MakeTag(s string) Tag

MakeTag builds a Tag from a string. The string is truncated or space-padded to exactly four bytes, matching HB_TAG.

func (Tag) String

func (t Tag) String() string

String returns the trimmed tag.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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