// 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) { return sfnt.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) { return sfnt.ParseCollectionReaderAt() } // Collection is a collection of one or more fonts. // // All of the Collection methods are safe to call concurrently. type Collection = sfnt.Collection // Parse parses an OpenType font, such as TTF or OTF data, from a []byte data // source. func ( []byte) (*Font, error) { return sfnt.Parse() } // ParseReaderAt parses an OpenType font, such as TTF or OTF data, from an // io.ReaderAt data source. func ( io.ReaderAt) (*Font, error) { return sfnt.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. type Font = sfnt.Font // FaceOptions describes the possible options given to NewFace when // creating a new font.Face from a Font. type FaceOptions struct { 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. type Face struct { 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 { return nil } // Metrics satisfies the font.Face interface. func ( *Face) () font.Metrics { if !.metricsSet { var error .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 { return 0 } 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 { return image.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 { return image.Rectangle{}, nil, image.Point{}, 0, false } , := .f.LoadGlyph(&.buf, , .scale, nil) if != nil { return image.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 { return image.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. := * if cap(.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.Src for , := range { switch .Op { case sfnt.SegmentOpMoveTo: .rast.MoveTo( float32(.Args[0].X+)/64, float32(.Args[0].Y+)/64, ) case sfnt.SegmentOpLineTo: .rast.LineTo( float32(.Args[0].X+)/64, float32(.Args[0].Y+)/64, ) case sfnt.SegmentOpQuadTo: .rast.QuadTo( float32(.Args[0].X+)/64, float32(.Args[0].Y+)/64, float32(.Args[1].X+)/64, float32(.Args[1].Y+)/64, ) case sfnt.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) }