sfnt

package
v0.0.0-...-11403fe Latest Latest
Warning

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

Go to latest
Published: Mar 31, 2021 License: BSD-3-Clause Imports: 10 Imported by: 0

Documentation

Overview

Package sfnt implements a decoder for TTF (TrueType Fonts) and OTF (OpenType Fonts). Such fonts are also known as SFNT fonts.

This package provides a low-level API and does not depend on vector rasterization packages. Glyphs are represented as vectors, not pixels.

The sibling github.com/elwhite321/image/font/opentype package provides a high-level API, including glyph rasterization.

This package provides a decoder in that it produces a TTF's glyphs (and other metadata such as advance width and kerning pairs): give me the 'A' from times_new_roman.ttf.

Unlike the image.Image decoder functions (gif.Decode, jpeg.Decode and png.Decode) in Go's standard library, an sfnt.Font needs ongoing access to the TTF data (as a []byte or io.ReaderAt) after the sfnt.ParseXxx functions return. If parsing a []byte, its elements are assumed immutable while the sfnt.Font remains in use. If parsing an *os.File, you should not close the file until after you're done with the sfnt.Font.

The []byte or io.ReaderAt data given to ParseXxx can be re-written to another io.Writer, copying the underlying TTF file, but this package does not provide an encoder. Specifically, there is no API to build a different TTF file, whether 'from scratch' or by modifying an existing one.

Example (RasterizeGlyph)
package main

import (
	"image"
	"image/draw"
	"log"
	"os"

	"github.com/elwhite321/image/font/gofont/goregular"
	"github.com/elwhite321/image/font/sfnt"
	"github.com/elwhite321/image/math/fixed"
	"github.com/elwhite321/image/vector"
)

func main() {
	const (
		ppem    = 32
		width   = 24
		height  = 36
		originX = 0
		originY = 32
	)

	f, err := sfnt.Parse(goregular.TTF)
	if err != nil {
		log.Fatalf("Parse: %v", err)
	}
	var b sfnt.Buffer
	x, err := f.GlyphIndex(&b, 'Ġ')
	if err != nil {
		log.Fatalf("GlyphIndex: %v", err)
	}
	if x == 0 {
		log.Fatalf("GlyphIndex: no glyph index found for the rune 'Ġ'")
	}
	segments, err := f.LoadGlyph(&b, x, fixed.I(ppem), nil)
	if err != nil {
		log.Fatalf("LoadGlyph: %v", err)
	}

	r := vector.NewRasterizer(width, height)
	r.DrawOp = draw.Src
	for _, seg := range segments {
		// The divisions by 64 below is because the seg.Args values have type
		// fixed.Int26_6, a 26.6 fixed point number, and 1<<6 == 64.
		switch seg.Op {
		case sfnt.SegmentOpMoveTo:
			r.MoveTo(
				originX+float32(seg.Args[0].X)/64,
				originY+float32(seg.Args[0].Y)/64,
			)
		case sfnt.SegmentOpLineTo:
			r.LineTo(
				originX+float32(seg.Args[0].X)/64,
				originY+float32(seg.Args[0].Y)/64,
			)
		case sfnt.SegmentOpQuadTo:
			r.QuadTo(
				originX+float32(seg.Args[0].X)/64,
				originY+float32(seg.Args[0].Y)/64,
				originX+float32(seg.Args[1].X)/64,
				originY+float32(seg.Args[1].Y)/64,
			)
		case sfnt.SegmentOpCubeTo:
			r.CubeTo(
				originX+float32(seg.Args[0].X)/64,
				originY+float32(seg.Args[0].Y)/64,
				originX+float32(seg.Args[1].X)/64,
				originY+float32(seg.Args[1].Y)/64,
				originX+float32(seg.Args[2].X)/64,
				originY+float32(seg.Args[2].Y)/64,
			)
		}
	}

	dst := image.NewAlpha(image.Rect(0, 0, width, height))
	r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})

	const asciiArt = ".++8"
	buf := make([]byte, 0, height*(width+1))
	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			a := dst.AlphaAt(x, y).A
			buf = append(buf, asciiArt[a>>6])
		}
		buf = append(buf, '\n')
	}
	os.Stdout.Write(buf)

}
Output:

........................
........................
........................
............888.........
............888.........
............888.........
............+++.........
........................
..........+++++++++.....
.......+8888888888888+..
......8888888888888888..
....+8888+........++88..
....8888................
...8888.................
..+888+.................
..+888..................
..888+..................
.+888+..................
.+888...................
.+888...................
.+888...................
.+888..........+++++++..
.+888..........8888888..
.+888+.........+++8888..
..888+............+888..
..8888............+888..
..+888+...........+888..
...8888+..........+888..
...+8888+.........+888..
....+88888+.......+888..
.....+8888888888888888..
.......+888888888888++..
..........++++++++......
........................
........................
........................

Index

Examples

Constants

View Source
const (
	NameIDCopyright                  NameID = 0
	NameIDFamily                            = 1
	NameIDSubfamily                         = 2
	NameIDUniqueIdentifier                  = 3
	NameIDFull                              = 4
	NameIDVersion                           = 5
	NameIDPostScript                        = 6
	NameIDTrademark                         = 7
	NameIDManufacturer                      = 8
	NameIDDesigner                          = 9
	NameIDDescription                       = 10
	NameIDVendorURL                         = 11
	NameIDDesignerURL                       = 12
	NameIDLicense                           = 13
	NameIDLicenseURL                        = 14
	NameIDTypographicFamily                 = 16
	NameIDTypographicSubfamily              = 17
	NameIDCompatibleFull                    = 18
	NameIDSampleText                        = 19
	NameIDPostScriptCID                     = 20
	NameIDWWSFamily                         = 21
	NameIDWWSSubfamily                      = 22
	NameIDLightBackgroundPalette            = 23
	NameIDDarkBackgroundPalette             = 24
	NameIDVariationsPostScriptPrefix        = 25
)

Variables

View Source
var (
	// ErrColoredGlyph indicates that the requested glyph is not a monochrome
	// vector glyph, such as a colored (bitmap or vector) emoji glyph.
	ErrColoredGlyph = errors.New("sfnt: colored glyph")
	// ErrNotFound indicates that the requested value was not found.
	ErrNotFound = errors.New("sfnt: not found")
)

Functions

This section is empty.

Types

type Buffer

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

Buffer holds re-usable buffers that can reduce the total memory allocation of repeated Font method calls.

See the Font type's documentation comment for more details.

type Collection

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

Collection is a collection of one or more fonts.

All of the Collection methods are safe to call concurrently.

func ParseCollection

func ParseCollection(src []byte) (*Collection, error)

ParseCollection parses an SFNT font collection, such as TTC or OTC data, from a []byte data source.

If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it will return a collection containing 1 font.

The caller should not modify src while the Collection or its Fonts remain in use. See the package documentation for details.

func ParseCollectionReaderAt

func ParseCollectionReaderAt(src io.ReaderAt) (*Collection, error)

ParseCollectionReaderAt parses an SFNT collection, such as TTC or OTC data, from an io.ReaderAt data source.

If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it will return a collection containing 1 font.

The caller should not modify or close src while the Collection or its Fonts remain in use. See the package documentation for details.

func (*Collection) Font

func (c *Collection) Font(i int) (*Font, error)

Font returns the i'th font in the collection.

func (*Collection) NumFonts

func (c *Collection) NumFonts() int

NumFonts returns the number of fonts in the collection.

type Font

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

Font is an SFNT font.

Many of its methods take a *Buffer argument, as re-using buffers can reduce the total memory allocation of repeated Font method calls, such as measuring and rasterizing every unique glyph in a string of text. If efficiency is not a concern, passing a nil *Buffer is valid, and implies using a temporary buffer for a single call.

It is valid to re-use a *Buffer with multiple Font method calls, even with different *Font receivers, as long as they are not concurrent calls.

All of the Font methods are safe to call concurrently, as long as each call has a different *Buffer (or nil).

The Font methods that don't take a *Buffer argument are always safe to call concurrently.

Some methods provide lengths or coordinates, e.g. bounds, font metrics and control points. All of these methods take a ppem parameter, which is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For example, if 1 em is 10 pixels then ppem is fixed.I(10), which equals fixed.Int26_6(10 << 6).

To get those lengths or coordinates in terms of font units instead of pixels, use ppem = fixed.Int26_6(f.UnitsPerEm()) and if those methods take a font.Hinting parameter, use font.HintingNone. The return values will have type fixed.Int26_6, but those numbers can be converted back to Units with no further scaling necessary.

func Parse

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

Parse parses an SFNT font, such as TTF or OTF data, from a []byte data source.

The caller should not modify src while the Font remains in use. See the package documentation for details.

func ParseReaderAt

func ParseReaderAt(src io.ReaderAt) (*Font, error)

ParseReaderAt parses an SFNT font, such as TTF or OTF data, from an io.ReaderAt data source.

The caller should not modify or close src while the Font remains in use. See the package documentation for details.

func (*Font) Bounds

func (f *Font) Bounds(b *Buffer, ppem fixed.Int26_6, h font.Hinting) (fixed.Rectangle26_6, error)

Bounds returns the union of a Font's glyphs' bounds.

In the returned Rectangle26_6's (x, y) coordinates, the Y axis increases down.

func (*Font) GlyphAdvance

func (f *Font) GlyphAdvance(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error)

GlyphAdvance returns the advance width for the x'th glyph. ppem is the number of pixels in 1 em.

It returns ErrNotFound if the glyph index is out of range.

func (*Font) GlyphBounds

func (f *Font) GlyphBounds(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, err error)

GlyphBounds returns the bounding box of the x'th glyph, drawn at a dot equal to the origin, and that glyph's advance width. ppem is the number of pixels in 1 em.

It returns ErrNotFound if the glyph index is out of range.

The glyph's ascent and descent are equal to -bounds.Min.Y and +bounds.Max.Y. The glyph's left-side and right-side bearings are equal to bounds.Min.X and advance-bounds.Max.X. A visual depiction of what these metrics are is at https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyphterms_2x.png

func (*Font) GlyphIndex

func (f *Font) GlyphIndex(b *Buffer, r rune) (GlyphIndex, error)

GlyphIndex returns the glyph index for the given rune.

It returns (0, nil) if there is no glyph for r. https://www.microsoft.com/typography/OTSPEC/cmap.htm says that "Character codes that do not correspond to any glyph in the font should be mapped to glyph index 0. The glyph at this location must be a special glyph representing a missing character, commonly known as .notdef."

func (*Font) GlyphName

func (f *Font) GlyphName(b *Buffer, x GlyphIndex) (string, error)

GlyphName returns the name of the x'th glyph.

Not every font contains glyph names. If not present, GlyphName will return ("", nil).

If present, the glyph name, provided by the font, is assumed to follow the Adobe Glyph List Specification: https://github.com/adobe-type-tools/agl-specification/blob/master/README.md

This is also known as the "Adobe Glyph Naming convention", the "Adobe document [for] Unicode and Glyph Names" or "PostScript glyph names".

It returns ErrNotFound if the glyph index is out of range.

func (*Font) Kern

func (f *Font) Kern(b *Buffer, x0, x1 GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error)

Kern returns the horizontal adjustment for the kerning pair (x0, x1). A positive kern means to move the glyphs further apart. ppem is the number of pixels in 1 em.

It returns ErrNotFound if either glyph index is out of range.

func (*Font) LoadGlyph

func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) (Segments, error)

LoadGlyph returns the vector segments for the x'th glyph. ppem is the number of pixels in 1 em.

If b is non-nil, the segments become invalid to use once b is re-used.

In the returned Segments' (x, y) coordinates, the Y axis increases down.

It returns ErrNotFound if the glyph index is out of range. It returns ErrColoredGlyph if the glyph is not a monochrome vector glyph, such as a colored (bitmap or vector) emoji glyph.

func (*Font) Metrics

func (f *Font) Metrics(b *Buffer, ppem fixed.Int26_6, h font.Hinting) (font.Metrics, error)

Metrics returns the metrics of this font.

func (*Font) Name

func (f *Font) Name(b *Buffer, id NameID) (string, error)

Name returns the name value keyed by the given NameID.

It returns ErrNotFound if there is no value for that key.

func (*Font) NumGlyphs

func (f *Font) NumGlyphs() int

NumGlyphs returns the number of glyphs in f.

func (*Font) PostTable

func (f *Font) PostTable() *PostTable

PostTable returns the information from the font's "post" table. It can return nil, if the font doesn't have such a table.

See https://docs.microsoft.com/en-us/typography/opentype/spec/post

func (*Font) UnitsPerEm

func (f *Font) UnitsPerEm() Units

UnitsPerEm returns the number of units per em for f.

func (*Font) WriteSourceTo

func (f *Font) WriteSourceTo(b *Buffer, w io.Writer) (int64, error)

WriteSourceTo writes the source data (the []byte or io.ReaderAt passed to Parse or ParseReaderAt) to w.

It returns the number of bytes written. On success, this is the final offset of the furthest SFNT table in the source. This may be less than the length of the []byte or io.ReaderAt originally passed.

type GlyphIndex

type GlyphIndex uint16

GlyphIndex is a glyph index in a Font.

type LoadGlyphOptions

type LoadGlyphOptions struct {
}

LoadGlyphOptions are the options to the Font.LoadGlyph method.

type NameID

type NameID uint16

NameID identifies a name table entry.

See the "Name IDs" section of https://www.microsoft.com/typography/otspec/name.htm

type PostTable

type PostTable struct {
	// Version of the version tag of the "post" table.
	Version uint32
	// ItalicAngle in counter-clockwise degrees from the vertical. Zero for
	// upright text, negative for text that leans to the right (forward).
	ItalicAngle float64
	// UnderlinePosition is the suggested distance of the top of the
	// underline from the baseline (negative values indicate below baseline).
	UnderlinePosition int16
	// Suggested values for the underline thickness.
	UnderlineThickness int16
	// IsFixedPitch indicates that the font is not proportionally spaced
	// (i.e. monospaced).
	IsFixedPitch bool
}

PostTable represents an information stored in the PostScript font section.

type Segment

type Segment struct {
	// Op is the operator.
	Op SegmentOp
	// Args is up to three (x, y) coordinates. The Y axis increases down.
	Args [3]fixed.Point26_6
}

Segment is a segment of a vector path.

type SegmentOp

type SegmentOp uint32

SegmentOp is a vector path segment's operator.

const (
	SegmentOpMoveTo SegmentOp = iota
	SegmentOpLineTo
	SegmentOpQuadTo
	SegmentOpCubeTo
)

type Segments

type Segments []Segment

Segments is a slice of Segment.

func (Segments) Bounds

func (s Segments) Bounds() (bounds fixed.Rectangle26_6)

Bounds returns s' bounding box. It returns an empty rectangle if s is empty.

type Units

type Units int32

Units are an integral number of abstract, scalable "font units". The em square is typically 1000 or 2048 "font units". This would map to a certain number (e.g. 30 pixels) of physical pixels, depending on things like the display resolution (DPI) and font size (e.g. a 12 point font).

Jump to

Keyboard shortcuts

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