-
Notifications
You must be signed in to change notification settings - Fork 27
/
drawer.go
80 lines (72 loc) · 2.06 KB
/
drawer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Package ggtext draws text on images.
// It is a modified copy of a portion of github.com/fogleman/gg by Michael Fogleman.
// See LICENSE.md for the original copyright notice.
package ggtext
import (
"image"
"image/color"
"golang.org/x/image/draw"
"golang.org/x/image/font"
"golang.org/x/image/math/f64"
"golang.org/x/image/math/fixed"
)
// Drawer is a font drawer
type Drawer struct {
Face font.Face
Color color.Color
}
func (td *Drawer) fontHeight() float64 {
return float64(td.Face.Metrics().Height) / 64
}
// Measure returns the rendered width and height of the specified text
// given the current font face.
func (td *Drawer) Measure(s string) (w, h float64) {
d := &font.Drawer{Face: td.Face}
a := d.MeasureString(s)
return float64(a >> 6), td.fontHeight()
}
// Draw draws the specified text at the specified point.
func (td *Drawer) Draw(img draw.Image, s string, x, y float64) {
td.DrawAnchored(img, s, x, y, 0, 0)
}
// DrawAnchored draws the specified text at the specified anchor point.
// The anchor point is x - w * ax, y - h * ay, where w, h is the size of the
// text. Use ax=0.5, ay=0.5 to center the text at the specified point.
func (td *Drawer) DrawAnchored(img draw.Image, s string, x, y, ax, ay float64) {
w, h := td.Measure(s)
x -= ax * w
y += ay * h
td.draw(img, s, x, y)
}
func (td *Drawer) draw(img draw.Image, s string, x, y float64) {
d := &font.Drawer{
Dst: img,
Src: image.NewUniform(td.Color),
Face: td.Face,
Dot: fixed.Point26_6{
X: fixed.Int26_6(x * 64),
Y: fixed.Int26_6(y * 64),
},
}
// based on Drawer.DrawString() in golang.org/x/image/font/font.go
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 {
continue
}
sr := dr.Sub(dr.Min)
transformer := draw.BiLinear
fx, fy := float64(dr.Min.X), float64(dr.Min.Y)
s2d := f64.Aff3{1, 0, fx, 0, 1, fy}
transformer.Transform(d.Dst, s2d, d.Src, sr, draw.Over, &draw.Options{
SrcMask: mask,
SrcMaskP: maskp,
})
d.Dot.X += advance
prevC = c
}
}