// Copyright 2017 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package opentype implements a glyph rasterizer for TTF (TrueType Fonts) and// OTF (OpenType Fonts).//// This package provides a high-level API, centered on the NewFace function,// implementing the golang.org/x/image/font.Face interface.//// The sibling golang.org/x/image/font/sfnt package provides a low-level API.
package opentype // import "golang.org/x/image/font/opentype"import ()// ParseCollection parses an OpenType 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.func ( []byte) (*Collection, error) {returnsfnt.ParseCollection()}// ParseCollectionReaderAt parses an OpenType 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.func ( io.ReaderAt) (*Collection, error) {returnsfnt.ParseCollectionReaderAt()}// Collection is a collection of one or more fonts.//// All of the Collection methods are safe to call concurrently.typeCollection = sfnt.Collection// Parse parses an OpenType font, such as TTF or OTF data, from a []byte data// source.func ( []byte) (*Font, error) {returnsfnt.Parse()}// ParseReaderAt parses an OpenType font, such as TTF or OTF data, from an// io.ReaderAt data source.func ( io.ReaderAt) (*Font, error) {returnsfnt.ParseReaderAt()}// Font is an OpenType font, also known as an SFNT font.//// All of the Font methods are safe to call concurrently, as long as each call// has a different *sfnt.Buffer (or nil).//// The Font methods that don't take a *sfnt.Buffer argument are always safe to// call concurrently.typeFont = sfnt.Font// FaceOptions describes the possible options given to NewFace when// creating a new font.Face from a Font.typeFaceOptionsstruct { Size float64// Size is the font size in points DPI float64// DPI is the dots per inch resolution Hinting font.Hinting// Hinting selects how to quantize a vector font's glyph nodes}func defaultFaceOptions() *FaceOptions {return &FaceOptions{Size: 12,DPI: 72,Hinting: font.HintingNone, }}// Face implements the font.Face interface for Font values.//// A Face is not safe to use concurrently.typeFacestruct { f *Font hinting font.Hinting scale fixed.Int26_6 metrics font.Metrics metricsSet bool buf sfnt.Buffer rast vector.Rasterizer mask image.Alpha}// NewFace returns a new font.Face for the given Font.//// If opts is nil, sensible defaults will be used.func ( *Font, *FaceOptions) (font.Face, error) {if == nil { = defaultFaceOptions() } := &Face{f: ,hinting: .Hinting,scale: fixed.Int26_6(0.5 + (.Size * .DPI * 64 / 72)), }return , nil}// Close satisfies the font.Face interface.func ( *Face) () error {returnnil}// Metrics satisfies the font.Face interface.func ( *Face) () font.Metrics {if !.metricsSet {varerror .metrics, = .f.Metrics(&.buf, .scale, .hinting)if != nil { .metrics = font.Metrics{} } .metricsSet = true }return .metrics}// Kern satisfies the font.Face interface.func ( *Face) (, rune) fixed.Int26_6 { , := .f.GlyphIndex(&.buf, ) , := .f.GlyphIndex(&.buf, ) , := .f.Kern(&.buf, , , fixed.Int26_6(.f.UnitsPerEm()), .hinting)if != nil {return0 }return}// Glyph satisfies the font.Face interface.func ( *Face) ( fixed.Point26_6, rune) ( image.Rectangle, image.Image, image.Point, fixed.Int26_6, bool) { , := .f.GlyphIndex(&.buf, )if != nil {returnimage.Rectangle{}, nil, image.Point{}, 0, false }// Call f.f.GlyphAdvance before f.f.LoadGlyph because the LoadGlyph docs // say this about the &f.buf argument: the segments become invalid to use // once [the buffer] is re-used. , = .f.GlyphAdvance(&.buf, , .scale, .hinting)if != nil {returnimage.Rectangle{}, nil, image.Point{}, 0, false } , := .f.LoadGlyph(&.buf, , .scale, nil)if != nil {returnimage.Rectangle{}, nil, image.Point{}, 0, false }// Numerical notation used below: // - 2 is an integer, "two" // - 2:16 is a 26.6 fixed point number, "two and a quarter" // - 2.5 is a float32 number, "two and a half" // Using 26.6 fixed point numbers means that there are 64 sub-pixel units // in 1 integer pixel unit.// Translate the sub-pixel bounding box from glyph space (where the glyph // origin is at (0:00, 0:00)) to dst space (where the glyph origin is at // the dot). dst space is the coordinate space that contains both the dot // (a sub-pixel position) and dr (an integer-pixel rectangle). := .Bounds().Add()// Quantize the sub-pixel bounds (dBounds) to integer-pixel bounds (dr). .Min.X = .Min.X.Floor() .Min.Y = .Min.Y.Floor() .Max.X = .Max.X.Ceil() .Max.Y = .Max.Y.Ceil() := .Dx() := .Dy()if < 0 || < 0 {returnimage.Rectangle{}, nil, image.Point{}, 0, false }// Calculate the sub-pixel bias to convert from glyph space to rasterizer // space. In glyph space, the segments may be to the left or right and // above or below the glyph origin. In rasterizer space, the segments // should only be right and below (or equal to) the top-left corner (0.0, // 0.0). They should also be left and above (or equal to) the bottom-right // corner (width, height), as the rasterizer should enclose the glyph // bounding box. // // For example, suppose that dot.X was at the sub-pixel position 25:48, // three quarters of the way into the 26th pixel, and that bounds.Min.X was // 1:20. We then have dBounds.Min.X = 1:20 + 25:48 = 27:04, dr.Min.X = 27 // and biasX = 25:48 - 27:00 = -1:16. A vertical stroke at 1:20 in glyph // space becomes (1:20 + -1:16) = 0:04 in rasterizer space. 0:04 as a // fixed.Int26_6 value is float32(4)/64.0 = 0.0625 as a float32 value. := .X - fixed.Int26_6(.Min.X<<6) := .Y - fixed.Int26_6(.Min.Y<<6)// Configure the mask image, re-allocating its buffer if necessary. := * ifcap(.mask.Pix) < { .mask.Pix = make([]uint8, 2*) } .mask.Pix = .mask.Pix[:] .mask.Stride = .mask.Rect.Min.X = 0 .mask.Rect.Min.Y = 0 .mask.Rect.Max.X = .mask.Rect.Max.Y = // Rasterize the biased segments, converting from fixed.Int26_6 to float32. .rast.Reset(, ) .rast.DrawOp = draw.Srcfor , := range {switch .Op {casesfnt.SegmentOpMoveTo: .rast.MoveTo(float32(.Args[0].X+)/64,float32(.Args[0].Y+)/64, )casesfnt.SegmentOpLineTo: .rast.LineTo(float32(.Args[0].X+)/64,float32(.Args[0].Y+)/64, )casesfnt.SegmentOpQuadTo: .rast.QuadTo(float32(.Args[0].X+)/64,float32(.Args[0].Y+)/64,float32(.Args[1].X+)/64,float32(.Args[1].Y+)/64, )casesfnt.SegmentOpCubeTo: .rast.CubeTo(float32(.Args[0].X+)/64,float32(.Args[0].Y+)/64,float32(.Args[1].X+)/64,float32(.Args[1].Y+)/64,float32(.Args[2].X+)/64,float32(.Args[2].Y+)/64, ) } } .rast.Draw(&.mask, .mask.Bounds(), image.Opaque, image.Point{})return , &.mask, .mask.Rect.Min, , != 0}// GlyphBounds satisfies the font.Face interface.func ( *Face) ( rune) ( fixed.Rectangle26_6, fixed.Int26_6, bool) { , := .f.GlyphIndex(&.buf, ) , , := .f.GlyphBounds(&.buf, , .scale, .hinting)return , , ( == nil) && ( != 0)}// GlyphAdvance satisfies the font.Face interface.func ( *Face) ( rune) ( fixed.Int26_6, bool) { , := .f.GlyphIndex(&.buf, ) , := .f.GlyphAdvance(&.buf, , .scale, .hinting)return , ( == nil) && ( != 0)}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.