opentype

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: BSD-3-Clause Imports: 9 Imported by: 0

README

go-ruby-opentype

CI Go Reference Go Report Card

The pure-Go, Ruby-runtime-independent core of the Ruby opentype gem — a complete text stack (font parsing, sized faces, complex-script shaping, the Unicode Bidirectional Algorithm and a registry of legible fonts) — shaped so that go-embedded-ruby (rbgo) can bind it as require "opentype".

It is a thin adapter over the typed libraries of the go-opentype stack:

Library Role
go-opentype/opentype TrueType/OpenType parser + anti-aliased rasteriser.
go-opentype/shape HarfBuzz-lite complex-text shaper (Arabic, Indic, USE, ...).
go-opentype/bidi The Unicode Bidirectional Algorithm (UAX #9).
go-opentype/fonts A registry of legible, permissively-licensed families.

It exposes them through Ruby-facing handles — Module, Font, Face — whose methods return Ruby-shaped values: a Hash (map[string]any), an Array ([]any) or a scalar. A single dynamic entry point, Call, dispatches a Ruby-style snake_case method name to the matching handle method and coerces the arguments, which is exactly what an rbgo binding drives from method_missing. Nothing here depends on the Ruby runtime, so it is equally usable as a standalone Go library — a sibling of go-ruby-regexp/regexp, go-ruby-erb/erb and go-ruby-dimail/dimail.

  • CGO-free, builds and tests identically on amd64, arm64, riscv64, loong64, ppc64le, s390x, plus js/wasm.
  • 100 % test coverage, race-clean, enforced in CI.

The Ruby-facing surface

Module — the package-level receiver (the Opentype module under rbgo):

Method Returns
open_font(ttf) / parse(ttf) a Font handle
most_legible the bytes of the bundled Atkinson Hyperlegible family
default_font a Font of the most-legible family
load(name) the bytes of a bundled family, or the most-legible default
families Array of Hashes {name, kind, license, import_path}
visual_order(text, base) the String reordered to visual order
resolve_levels(text, base) Array of the bidi embedding level of each rune
shape(face, text, opts) Array of glyph Hashes (see below)

Font — a parsed font: num_glyphs, glyph_index(rune) (an Int or nil), axes, named_instances, and face(px).

Face — a sized font: measure(text), advance(rune), kern(a, b), metrics, glyph_info(rune, x, y) (a GlyphMask-style Hash), set_hinting(on) and set_variation(coords).

shape returns an Array of Hashes, each:

{ "gid"=>, "cluster"=>, "x_advance"=>, "y_advance"=>,
  "x_offset"=>, "y_offset"=>, "scale"=> }

and its opts Hash carries "direction" ("ltr"/"rtl"/"auto"), "script" (e.g. "arab"), "features" (an Array of tags) and "vertical".

Usage from Ruby

Under rbgo, require "opentype" gives an Opentype module whose snake_case methods are these operations, returning Ruby Hashes, Arrays and scalars:

require "opentype"

font  = Opentype.open_font(Opentype.most_legible)
puts font.num_glyphs                     # => Integer

face  = font.face(24)
puts face.measure("Hello")               # => Integer

Opentype.shape(face, "بيت").each do |g|  # => Array<Hash>
  # draw glyph g["gid"]; advance the pen by g["x_advance"], etc.
end

puts Opentype.visual_order("aب1", "auto")   # reordered String

The require "opentype" binding lives in rbgo (a thin method_missing shim over Call); it is pending in that repo.

Install (Go)

go get github.com/go-ruby-opentype/opentype

Usage from Go

package main

import (
	"fmt"
	"log"

	"github.com/go-ruby-opentype/opentype"
)

func main() {
	m := opentype.NewModule()

	font, err := m.OpenFont(m.MostLegible())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("glyphs:", font.NumGlyphs())

	face := font.Face(24)
	fmt.Println("width:", face.Measure("Hello"))

	// A shaped run comes back as an Array of Hashes.
	for _, g := range m.Shape(face, "AV", nil) {
		h := g.(map[string]any)
		fmt.Println(h["gid"], h["x_advance"])
	}

	// Mixed-direction text reordered to visual order.
	fmt.Println(m.VisualOrder("aب1", "auto"))
}

Methods(recv) lists every snake_case name Call accepts for a handle, and Call(recv, name, args...) is the uniform dynamic entry point rbgo binds.

License

BSD-3-Clause. See LICENSE. Each bundled font keeps its own upstream license (see go-opentype/fonts); this repository's Go code is BSD-3-Clause.

Documentation

Overview

Package opentype is the pure-Go, Ruby-runtime-independent core of the Ruby `opentype` gem: a text stack — font parsing, sized faces, complex-script shaping, the Unicode Bidirectional Algorithm and a registry of legible fonts — shaped so that github.com/go-embedded-ruby/ruby (rbgo) can bind it as `require "opentype"`.

It is a thin adapter over the typed libraries of the go-opentype stack — github.com/go-opentype/opentype (parse + raster), .../shape (HarfBuzz-lite shaper), .../bidi (UAX #9) and .../fonts (bundled families). It exposes them through Ruby-facing handles (Module, Font, Face) whose methods return Ruby-shaped values: a Hash (map[string]any), an Array ([]any) or a scalar. A single dynamic entry point, Call, dispatches a Ruby-style snake_case method name to the matching handle method and coerces the arguments, which is exactly what an rbgo binding drives from method_missing. Nothing here imports the Ruby runtime, so the package is equally usable as a standalone Go library — a sibling of go-ruby-regexp/regexp, go-ruby-erb/erb and go-ruby-dimail/dimail.

Handles

  • Module is the package-level receiver: OpenFont/Parse a font, Load a bundled family, list Families, run VisualOrder/ResolveLevels over text and Shape a run against a Face.
  • Font is a parsed font: NumGlyphs, GlyphIndex, Axes, NamedInstances and Face(px) to size it.
  • Face is a sized font: Measure, Advance, Kern, Metrics, GlyphInfo (a GlyphMask-style Hash), SetHinting and SetVariation.

Usage from Go

m := opentype.NewModule()
font, err := m.OpenFont(opentype.MostLegible())
if err != nil {
	return err
}
face := font.Face(24)
adv := face.Measure("Hello")               // an Int
run := m.Shape(face, "بيت", nil)            // an Array of Hashes
order := m.VisualOrder("aب1", "auto")      // reordered String

Usage from Ruby

Under rbgo, `require "opentype"` gives an Opentype module whose snake_case methods are these operations, returning Ruby Hashes, Arrays and scalars:

require "opentype"

font  = Opentype.open_font(Opentype.most_legible)
face  = font.face(24)
face.measure("Hello")                      # => Integer
Opentype.shape(face, "بيت")                # => Array<Hash>
Opentype.visual_order("aب1", "auto")       # => String

The `require "opentype"` binding lives in rbgo (a thin method_missing shim over Call); it is pending in that repo.

Example

Example mirrors the README: parse the bundled most-legible font, size it, measure a string, shape a run and reorder mixed-direction text — every result a Ruby-shaped value.

package main

import (
	"fmt"
	"log"

	"github.com/go-ruby-opentype/opentype"
)

func main() {
	m := opentype.NewModule()

	font, err := m.OpenFont(m.MostLegible())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("glyphs:", font.NumGlyphs())

	face := font.Face(24)
	fmt.Println("width:", face.Measure("Hello"))

	run := m.Shape(face, "AV", nil) // an Array of Hashes
	fmt.Println("shaped:", len(run))

	fmt.Println("order:", m.VisualOrder("abc", "ltr"))

}
Output:
glyphs: 369
width: 55
shaped: 2
order: abc

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Call

func Call(recv any, method string, args ...any) (any, error)

Call dispatches a Ruby-style snake_case method name to the matching exported method of recv (a *Module, *Font or *Face), coercing each Ruby-supplied argument to the Go parameter type. Trailing arguments may be omitted; they default to nil. The result is the method's Ruby-shaped return value (or nil for a method that returns nothing); a trailing error return is unwrapped into Call's own error. This is the single entry point an rbgo binding drives.

func Families

func Families() []any

Families lists every bundled family as an Array of Hashes.

func Load

func Load(name string) []byte

Load returns the bytes of a bundled family by name (see Module.Load).

func Methods

func Methods(recv any) []string

Methods lists, sorted, the Ruby-style snake_case names Call accepts for recv.

func MostLegible

func MostLegible() []byte

MostLegible returns the bytes of the bundled Atkinson Hyperlegible family.

func ResolveLevels

func ResolveLevels(text, base string) []any

ResolveLevels returns the bidi embedding levels of text as an Array.

func Shape

func Shape(face *Face, text string, opts map[string]any) []any

Shape turns text into a positioned glyph run against face (see Module.Shape).

func VisualOrder

func VisualOrder(text, base string) string

VisualOrder reorders text to visual order under base ("ltr"/"rtl"/"auto").

Types

type Face

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

Face is a Ruby-facing handle over a sized github.com/go-opentype/opentype face. Like the underlying face it caches rasterised glyphs and is not safe for concurrent use.

func (*Face) Advance

func (fc *Face) Advance(r rune) int

Advance returns the advance width of a single rune in whole pixels.

func (*Face) GlyphInfo

func (fc *Face) GlyphInfo(r rune, x, y int) map[string]any

GlyphInfo returns a GlyphMask-style Hash for rune r placed at pen (x, y): "found" (a Bool), "advance", the "bounds" of the placed glyph (a Hash with "min_x"/"min_y"/"max_x"/"max_y"/"width"/"height"), the mask "origin" (a Hash with "x"/"y"), and, when found, the 8-bit alpha coverage "mask" as a Hash with "width"/"height"/"stride"/"pix" (the raw coverage bytes). It wraps Face.GlyphMask.

func (*Face) Kern

func (fc *Face) Kern(prev, r rune) int

Kern returns the kerning adjustment, in pixels, between two adjacent runes.

func (*Face) Measure

func (fc *Face) Measure(text string) int

Measure returns the advance width of text in whole pixels, ignoring kerning.

func (*Face) Metrics

func (fc *Face) Metrics() map[string]any

Metrics returns the face's vertical metrics as a Hash with "ascent", "descent", "height" and "scale".

func (*Face) SetHinting

func (fc *Face) SetHinting(on bool)

SetHinting turns the face's grid-fitting hinting on or off.

func (*Face) SetVariation

func (fc *Face) SetVariation(coords map[string]any) map[string]any

SetVariation moves the face along its variation axes. coords is a Hash of axis tag to a numeric user coordinate (e.g. {"wght" => 700}); non-numeric values are ignored. It returns the normalised coordinates as a Ruby Hash and wraps Face.SetVariation.

type Font

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

Font is a Ruby-facing handle over a parsed github.com/go-opentype/opentype font. It is immutable and safe for concurrent use.

func DefaultFont

func DefaultFont() (*Font, error)

DefaultFont parses MostLegible into a Font handle.

func OpenFont

func OpenFont(ttf []byte) (*Font, error)

OpenFont parses a font blob into a Font handle.

func Parse

func Parse(ttf []byte) (*Font, error)

Parse is an alias for OpenFont.

func (*Font) Axes

func (f *Font) Axes() []any

Axes lists the font's variation axes as an Array of Hashes, each with "tag", "min", "default", "max", "flags" and "name_id". A non-variable font yields an empty Array.

func (*Font) Face

func (f *Font) Face(px int) *Face

Face sizes the font at px pixels, returning a Face handle. It wraps Font.NewFace.

func (*Font) GlyphIndex

func (f *Font) GlyphIndex(r rune) any

GlyphIndex maps a rune to its glyph id (an Int), or nil when the font has no glyph for it.

func (*Font) NamedInstances

func (f *Font) NamedInstances() []any

NamedInstances lists the font's named variation instances as an Array of Hashes, each with "subfamily_name_id", "flags", "coordinates" (a Hash of axis tag to coordinate) and "post_script_name_id".

func (*Font) NumGlyphs

func (f *Font) NumGlyphs() int

NumGlyphs reports how many glyphs the font contains.

type Module

type Module struct{}

Module is the package-level Ruby receiver: the `Opentype` module under rbgo. Its methods parse fonts, load bundled families, run the Unicode Bidirectional Algorithm and shape text, all returning Ruby-shaped values. A Module is stateless and safe for concurrent use.

func NewModule

func NewModule() *Module

NewModule returns the package-level receiver. The package-level convenience functions (OpenFont, Parse, Load, Families, VisualOrder, ResolveLevels and Shape) delegate to it.

func (*Module) DefaultFont

func (m *Module) DefaultFont() (*Font, error)

DefaultFont parses MostLegible into a ready Font handle.

func (*Module) Families

func (m *Module) Families() []any

Families lists every bundled family as an Array of Hashes, each with "name", "kind", "license" and "import_path". It wraps fonts.All (metadata only — no bytes are linked).

func (*Module) Load

func (m *Module) Load(name string) []byte

Load returns the bytes of a bundled family by name. Only the registry's embedded default (MostLegible) carries bytes in this package — every other family lives in its own subpackage and must be loaded by importing it — so Load returns those default bytes when name is empty or names the default family (case-insensitively), and nil otherwise.

func (*Module) MostLegible

func (m *Module) MostLegible() []byte

MostLegible returns the bytes of the one family embedded directly in the fonts registry — Atkinson Hyperlegible, designed for maximum legibility.

func (*Module) OpenFont

func (m *Module) OpenFont(ttf []byte) (*Font, error)

OpenFont parses a TrueType/OpenType blob into a Font handle. It wraps opentype.Parse.

func (*Module) Parse

func (m *Module) Parse(ttf []byte) (*Font, error)

Parse is an alias for OpenFont, mirroring fonts.Parse.

func (*Module) ResolveLevels

func (m *Module) ResolveLevels(text, base string) []any

ResolveLevels runs the Unicode Bidirectional Algorithm over text and returns an Array of the resolved embedding level (an Int) of every rune, under the given base direction ("ltr", "rtl" or "auto"). It wraps bidi.ResolveLevels.

func (*Module) Shape

func (m *Module) Shape(face *Face, text string, opts map[string]any) []any

Shape turns text into a positioned glyph run against face, returning an Array of Hashes, each with "gid", "cluster", "x_advance", "y_advance", "x_offset", "y_offset" and "scale". It wraps shape.Shape. The opts Hash carries "direction" ("ltr"/"rtl"/"auto"), "script" (e.g. "arab"), "features" (an Array of feature tags) and "vertical" (a Bool). A nil face yields an empty Array.

func (*Module) VisualOrder

func (m *Module) VisualOrder(text, base string) string

VisualOrder resolves and reorders text to visual (left-to-right) order under the given base direction ("ltr", "rtl" or "auto"; empty means auto). It wraps bidi.VisualOrder and returns a String.

Jump to

Keyboard shortcuts

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