374 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			374 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2015 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 font defines an interface for font faces, for drawing text on an
 | |
| // image.
 | |
| //
 | |
| // Other packages provide font face implementations. For example, a truetype
 | |
| // package would provide one based on .ttf font files.
 | |
| package font // import "golang.org/x/image/font"
 | |
| 
 | |
| import (
 | |
| 	"image"
 | |
| 	"image/draw"
 | |
| 	"io"
 | |
| 	"unicode/utf8"
 | |
| 
 | |
| 	"golang.org/x/image/math/fixed"
 | |
| )
 | |
| 
 | |
| // TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
 | |
| // The Drawer or the Face?
 | |
| 
 | |
| // Face is a font face. Its glyphs are often derived from a font file, such as
 | |
| // "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
 | |
| // hinting. For example, the 12pt and 18pt versions of Comic Sans are two
 | |
| // different faces, even if derived from the same font file.
 | |
| //
 | |
| // A Face is not safe for concurrent use by multiple goroutines, as its methods
 | |
| // may re-use implementation-specific caches and mask image buffers.
 | |
| //
 | |
| // To create a Face, look to other packages that implement specific font file
 | |
| // formats.
 | |
| type Face interface {
 | |
| 	io.Closer
 | |
| 
 | |
| 	// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
 | |
| 	// glyph at the sub-pixel destination location dot, and that glyph's
 | |
| 	// advance width.
 | |
| 	//
 | |
| 	// It returns !ok if the face does not contain a glyph for r.
 | |
| 	//
 | |
| 	// The contents of the mask image returned by one Glyph call may change
 | |
| 	// after the next Glyph call. Callers that want to cache the mask must make
 | |
| 	// a copy.
 | |
| 	Glyph(dot fixed.Point26_6, r rune) (
 | |
| 		dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)
 | |
| 
 | |
| 	// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
 | |
| 	// to the origin, and that glyph's advance width.
 | |
| 	//
 | |
| 	// It returns !ok if the face does not contain a glyph for r.
 | |
| 	//
 | |
| 	// 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
 | |
| 	GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)
 | |
| 
 | |
| 	// GlyphAdvance returns the advance width of r's glyph.
 | |
| 	//
 | |
| 	// It returns !ok if the face does not contain a glyph for r.
 | |
| 	GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)
 | |
| 
 | |
| 	// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
 | |
| 	// positive kern means to move the glyphs further apart.
 | |
| 	Kern(r0, r1 rune) fixed.Int26_6
 | |
| 
 | |
| 	// Metrics returns the metrics for this Face.
 | |
| 	Metrics() Metrics
 | |
| 
 | |
| 	// TODO: ColoredGlyph for various emoji?
 | |
| 	// TODO: Ligatures? Shaping?
 | |
| }
 | |
| 
 | |
| // Metrics holds the metrics for a Face. A visual depiction is at
 | |
| // https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
 | |
| type Metrics struct {
 | |
| 	// Height is the recommended amount of vertical space between two lines of
 | |
| 	// text.
 | |
| 	Height fixed.Int26_6
 | |
| 
 | |
| 	// Ascent is the distance from the top of a line to its baseline.
 | |
| 	Ascent fixed.Int26_6
 | |
| 
 | |
| 	// Descent is the distance from the bottom of a line to its baseline. The
 | |
| 	// value is typically positive, even though a descender goes below the
 | |
| 	// baseline.
 | |
| 	Descent fixed.Int26_6
 | |
| 
 | |
| 	// XHeight is the distance from the top of non-ascending lowercase letters
 | |
| 	// to the baseline.
 | |
| 	XHeight fixed.Int26_6
 | |
| 
 | |
| 	// CapHeight is the distance from the top of uppercase letters to the
 | |
| 	// baseline.
 | |
| 	CapHeight fixed.Int26_6
 | |
| 
 | |
| 	// CaretSlope is the slope of a caret as a vector with the Y axis pointing up.
 | |
| 	// The slope {0, 1} is the vertical caret.
 | |
| 	CaretSlope image.Point
 | |
| }
 | |
| 
 | |
| // Drawer draws text on a destination image.
 | |
| //
 | |
| // A Drawer is not safe for concurrent use by multiple goroutines, since its
 | |
| // Face is not.
 | |
| type Drawer struct {
 | |
| 	// Dst is the destination image.
 | |
| 	Dst draw.Image
 | |
| 	// Src is the source image.
 | |
| 	Src image.Image
 | |
| 	// Face provides the glyph mask images.
 | |
| 	Face Face
 | |
| 	// Dot is the baseline location to draw the next glyph. The majority of the
 | |
| 	// affected pixels will be above and to the right of the dot, but some may
 | |
| 	// be below or to the left. For example, drawing a 'j' in an italic face
 | |
| 	// may affect pixels below and to the left of the dot.
 | |
| 	Dot fixed.Point26_6
 | |
| 
 | |
| 	// TODO: Clip image.Image?
 | |
| 	// TODO: SrcP image.Point for Src images other than *image.Uniform? How
 | |
| 	// does it get updated during DrawString?
 | |
| }
 | |
| 
 | |
| // TODO: should DrawString return the last rune drawn, so the next DrawString
 | |
| // call can kern beforehand? Or should that be the responsibility of the caller
 | |
| // if they really want to do that, since they have to explicitly shift d.Dot
 | |
| // anyway? What if ligatures span more than two runes? What if grapheme
 | |
| // clusters span multiple runes?
 | |
| //
 | |
| // TODO: do we assume that the input is in any particular Unicode Normalization
 | |
| // Form?
 | |
| //
 | |
| // TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
 | |
| // io.RuneReader, we can't assume that we can rewind the stream.
 | |
| //
 | |
| // TODO: how does this work with line breaking: drawing text up until a
 | |
| // vertical line? Should DrawString return the number of runes drawn?
 | |
| 
 | |
| // DrawBytes draws s at the dot and advances the dot's location.
 | |
| //
 | |
| // It is equivalent to DrawString(string(s)) but may be more efficient.
 | |
| func (d *Drawer) DrawBytes(s []byte) {
 | |
| 	prevC := rune(-1)
 | |
| 	for len(s) > 0 {
 | |
| 		c, size := utf8.DecodeRune(s)
 | |
| 		s = s[size:]
 | |
| 		if prevC >= 0 {
 | |
| 			d.Dot.X += d.Face.Kern(prevC, c)
 | |
| 		}
 | |
| 		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
 | |
| 		if !ok {
 | |
| 			// TODO: is falling back on the U+FFFD glyph the responsibility of
 | |
| 			// the Drawer or the Face?
 | |
| 			// TODO: set prevC = '\ufffd'?
 | |
| 			continue
 | |
| 		}
 | |
| 		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
 | |
| 		d.Dot.X += advance
 | |
| 		prevC = c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // DrawString draws s at the dot and advances the dot's location.
 | |
| func (d *Drawer) DrawString(s string) {
 | |
| 	prevC := rune(-1)
 | |
| 	for _, c := range s {
 | |
| 		if prevC >= 0 {
 | |
| 			d.Dot.X += d.Face.Kern(prevC, c)
 | |
| 		}
 | |
| 		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
 | |
| 		if !ok {
 | |
| 			// TODO: is falling back on the U+FFFD glyph the responsibility of
 | |
| 			// the Drawer or the Face?
 | |
| 			// TODO: set prevC = '\ufffd'?
 | |
| 			continue
 | |
| 		}
 | |
| 		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
 | |
| 		d.Dot.X += advance
 | |
| 		prevC = c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
 | |
| // the advance.
 | |
| //
 | |
| // It is equivalent to BoundBytes(string(s)) but may be more efficient.
 | |
| func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
 | |
| 	bounds, advance = BoundBytes(d.Face, s)
 | |
| 	bounds.Min = bounds.Min.Add(d.Dot)
 | |
| 	bounds.Max = bounds.Max.Add(d.Dot)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // BoundString returns the bounding box of s, drawn at the drawer dot, as well
 | |
| // as the advance.
 | |
| func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
 | |
| 	bounds, advance = BoundString(d.Face, s)
 | |
| 	bounds.Min = bounds.Min.Add(d.Dot)
 | |
| 	bounds.Max = bounds.Max.Add(d.Dot)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // MeasureBytes returns how far dot would advance by drawing s.
 | |
| //
 | |
| // It is equivalent to MeasureString(string(s)) but may be more efficient.
 | |
| func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
 | |
| 	return MeasureBytes(d.Face, s)
 | |
| }
 | |
| 
 | |
| // MeasureString returns how far dot would advance by drawing s.
 | |
| func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
 | |
| 	return MeasureString(d.Face, s)
 | |
| }
 | |
| 
 | |
| // BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
 | |
| // origin, as well as the advance.
 | |
| //
 | |
| // It is equivalent to BoundString(string(s)) but may be more efficient.
 | |
| func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
 | |
| 	prevC := rune(-1)
 | |
| 	for len(s) > 0 {
 | |
| 		c, size := utf8.DecodeRune(s)
 | |
| 		s = s[size:]
 | |
| 		if prevC >= 0 {
 | |
| 			advance += f.Kern(prevC, c)
 | |
| 		}
 | |
| 		b, a, ok := f.GlyphBounds(c)
 | |
| 		if !ok {
 | |
| 			// TODO: is falling back on the U+FFFD glyph the responsibility of
 | |
| 			// the Drawer or the Face?
 | |
| 			// TODO: set prevC = '\ufffd'?
 | |
| 			continue
 | |
| 		}
 | |
| 		b.Min.X += advance
 | |
| 		b.Max.X += advance
 | |
| 		bounds = bounds.Union(b)
 | |
| 		advance += a
 | |
| 		prevC = c
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // BoundString returns the bounding box of s with f, drawn at a dot equal to the
 | |
| // origin, as well as the advance.
 | |
| func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
 | |
| 	prevC := rune(-1)
 | |
| 	for _, c := range s {
 | |
| 		if prevC >= 0 {
 | |
| 			advance += f.Kern(prevC, c)
 | |
| 		}
 | |
| 		b, a, ok := f.GlyphBounds(c)
 | |
| 		if !ok {
 | |
| 			// TODO: is falling back on the U+FFFD glyph the responsibility of
 | |
| 			// the Drawer or the Face?
 | |
| 			// TODO: set prevC = '\ufffd'?
 | |
| 			continue
 | |
| 		}
 | |
| 		b.Min.X += advance
 | |
| 		b.Max.X += advance
 | |
| 		bounds = bounds.Union(b)
 | |
| 		advance += a
 | |
| 		prevC = c
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // MeasureBytes returns how far dot would advance by drawing s with f.
 | |
| //
 | |
| // It is equivalent to MeasureString(string(s)) but may be more efficient.
 | |
| func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
 | |
| 	prevC := rune(-1)
 | |
| 	for len(s) > 0 {
 | |
| 		c, size := utf8.DecodeRune(s)
 | |
| 		s = s[size:]
 | |
| 		if prevC >= 0 {
 | |
| 			advance += f.Kern(prevC, c)
 | |
| 		}
 | |
| 		a, ok := f.GlyphAdvance(c)
 | |
| 		if !ok {
 | |
| 			// TODO: is falling back on the U+FFFD glyph the responsibility of
 | |
| 			// the Drawer or the Face?
 | |
| 			// TODO: set prevC = '\ufffd'?
 | |
| 			continue
 | |
| 		}
 | |
| 		advance += a
 | |
| 		prevC = c
 | |
| 	}
 | |
| 	return advance
 | |
| }
 | |
| 
 | |
| // MeasureString returns how far dot would advance by drawing s with f.
 | |
| func MeasureString(f Face, s string) (advance fixed.Int26_6) {
 | |
| 	prevC := rune(-1)
 | |
| 	for _, c := range s {
 | |
| 		if prevC >= 0 {
 | |
| 			advance += f.Kern(prevC, c)
 | |
| 		}
 | |
| 		a, ok := f.GlyphAdvance(c)
 | |
| 		if !ok {
 | |
| 			// TODO: is falling back on the U+FFFD glyph the responsibility of
 | |
| 			// the Drawer or the Face?
 | |
| 			// TODO: set prevC = '\ufffd'?
 | |
| 			continue
 | |
| 		}
 | |
| 		advance += a
 | |
| 		prevC = c
 | |
| 	}
 | |
| 	return advance
 | |
| }
 | |
| 
 | |
| // Hinting selects how to quantize a vector font's glyph nodes.
 | |
| //
 | |
| // Not all fonts support hinting.
 | |
| type Hinting int
 | |
| 
 | |
| const (
 | |
| 	HintingNone Hinting = iota
 | |
| 	HintingVertical
 | |
| 	HintingFull
 | |
| )
 | |
| 
 | |
| // Stretch selects a normal, condensed, or expanded face.
 | |
| //
 | |
| // Not all fonts support stretches.
 | |
| type Stretch int
 | |
| 
 | |
| const (
 | |
| 	StretchUltraCondensed Stretch = -4
 | |
| 	StretchExtraCondensed Stretch = -3
 | |
| 	StretchCondensed      Stretch = -2
 | |
| 	StretchSemiCondensed  Stretch = -1
 | |
| 	StretchNormal         Stretch = +0
 | |
| 	StretchSemiExpanded   Stretch = +1
 | |
| 	StretchExpanded       Stretch = +2
 | |
| 	StretchExtraExpanded  Stretch = +3
 | |
| 	StretchUltraExpanded  Stretch = +4
 | |
| )
 | |
| 
 | |
| // Style selects a normal, italic, or oblique face.
 | |
| //
 | |
| // Not all fonts support styles.
 | |
| type Style int
 | |
| 
 | |
| const (
 | |
| 	StyleNormal Style = iota
 | |
| 	StyleItalic
 | |
| 	StyleOblique
 | |
| )
 | |
| 
 | |
| // Weight selects a normal, light or bold face.
 | |
| //
 | |
| // Not all fonts support weights.
 | |
| //
 | |
| // The named Weight constants (e.g. WeightBold) correspond to CSS' common
 | |
| // weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
 | |
| // the zero value means to use a normal weight. For the CSS names and values,
 | |
| // see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
 | |
| type Weight int
 | |
| 
 | |
| const (
 | |
| 	WeightThin       Weight = -3 // CSS font-weight value 100.
 | |
| 	WeightExtraLight Weight = -2 // CSS font-weight value 200.
 | |
| 	WeightLight      Weight = -1 // CSS font-weight value 300.
 | |
| 	WeightNormal     Weight = +0 // CSS font-weight value 400.
 | |
| 	WeightMedium     Weight = +1 // CSS font-weight value 500.
 | |
| 	WeightSemiBold   Weight = +2 // CSS font-weight value 600.
 | |
| 	WeightBold       Weight = +3 // CSS font-weight value 700.
 | |
| 	WeightExtraBold  Weight = +4 // CSS font-weight value 800.
 | |
| 	WeightBlack      Weight = +5 // CSS font-weight value 900.
 | |
| )
 |