/
font.go
112 lines (94 loc) · 2.19 KB
/
font.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// © 2013 the Ui Authors under the MIT license. See AUTHORS for the list of authors.
package ui
/*
#include "ui.h"
*/
import "C"
import (
"image"
"image/color"
"io/ioutil"
"os"
"code.google.com/p/freetype-go/freetype"
"code.google.com/p/freetype-go/freetype/truetype"
)
const (
// PxInch is the number of pixels in an inch.
// 72 seems to make font sizes consistent with SDL_ttf…
pxInch = 72.0
// PtInch is the number of Postscript points in an inch.
ptInch = 72.0
)
var fonts = make(map[string]font)
type font struct {
size int
path string
*truetype.Font
*freetype.Context
}
func getFont(path string, sizePts int) font {
sizePx := int(float64(sizePts)/ptInch*pxInch + 0.5)
if f, ok := fonts[path]; ok {
f.size = sizePx
return f
}
in, err := os.Open(path)
if err != nil {
panic(err)
}
defer in.Close()
fdata, err := ioutil.ReadAll(in)
if err != nil {
panic(err)
}
f := font{
path: path,
Context: freetype.NewContext(),
}
if f.Font, err = truetype.Parse(fdata); err != nil {
panic(err)
}
f.SetFont(f.Font)
f.SetDPI(pxInch)
fonts[path] = f
f.size = sizePx
return f
}
func (f *font) extents() (height, ascent, descent int) {
scale := f.scale()
bounds := f.Bounds(f.FUnitsPerEm())
ascent = int(float64(bounds.YMax)*scale + 0.5)
descent = int(float64(bounds.YMin)*scale - 0.5)
return ascent - descent, ascent, descent
}
func (f *font) width(s string) int {
em := f.FUnitsPerEm()
var width int32
prev, hasPrev := truetype.Index(0), false
for _, r := range s {
index := f.Index(r)
if hasPrev {
width += f.Kerning(em, prev, index)
}
width += f.HMetric(em, index).AdvanceWidth
prev, hasPrev = index, true
}
return int(float64(width)*f.scale() + 0.5)
}
func (f *font) scale() float64 {
em := f.FUnitsPerEm()
return (float64(f.size) / ptInch * pxInch) / float64(em)
}
func (f *font) draw(s string, col color.Color) *image.NRGBA {
width := f.width(s)
height, _, descent := f.extents()
img := image.NewNRGBA(image.Rect(0, 0, width, height))
f.SetFontSize(float64(f.size))
f.SetSrc(image.NewUniform(col))
f.SetClip(img.Bounds())
f.SetDst(img)
if _, err := f.DrawString(s, freetype.Pt(0, height+descent)); err != nil {
panic(err)
}
return img
}