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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// 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 sfnt_test
import (
"image"
"image/draw"
"log"
"os"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
"golang.org/x/image/vector"
)
func ExampleRasterizeGlyph() {
const (
ppem = 32
width = 24
height = 32
originX = 0
originY = 28
)
f, err := sfnt.Parse(goregular.TTF)
if err != nil {
log.Fatalf("Parse: %v", err)
}
var b sfnt.Buffer
x, err := f.GlyphIndex(&b, 'G')
if err != nil {
log.Fatalf("GlyphIndex: %v", err)
}
if x == 0 {
log.Fatalf("GlyphIndex: no glyph index found for the rune 'G'")
}
segments, err := f.LoadGlyph(&b, x, fixed.I(ppem), nil)
if err != nil {
log.Fatalf("LoadGlyph: %v", err)
}
r := vector.NewRasterizer(width, height)
r.DrawOp = draw.Src
for _, seg := range segments {
// The divisions by 64 below is because the seg.Args values have type
// fixed.Int26_6, a 26.6 fixed point number, and 1<<6 == 64.
switch seg.Op {
case sfnt.SegmentOpMoveTo:
r.MoveTo(
originX+float32(seg.Args[0])/64,
originY-float32(seg.Args[1])/64,
)
case sfnt.SegmentOpLineTo:
r.LineTo(
originX+float32(seg.Args[0])/64,
originY-float32(seg.Args[1])/64,
)
case sfnt.SegmentOpQuadTo:
r.QuadTo(
originX+float32(seg.Args[0])/64,
originY-float32(seg.Args[1])/64,
originX+float32(seg.Args[2])/64,
originY-float32(seg.Args[3])/64,
)
case sfnt.SegmentOpCubeTo:
r.CubeTo(
originX+float32(seg.Args[0])/64,
originY-float32(seg.Args[1])/64,
originX+float32(seg.Args[2])/64,
originY-float32(seg.Args[3])/64,
originX+float32(seg.Args[4])/64,
originY-float32(seg.Args[5])/64,
)
}
}
// TODO: call ClosePath? Once overall or once per contour (i.e. MoveTo)?
dst := image.NewAlpha(image.Rect(0, 0, width, height))
r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
const asciiArt = ".++8"
buf := make([]byte, 0, height*(width+1))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
a := dst.AlphaAt(x, y).A
buf = append(buf, asciiArt[a>>6])
}
buf = append(buf, '\n')
}
os.Stdout.Write(buf)
// Output:
// ........................
// ........................
// ........................
// ........................
// ..........+++++++++.....
// .......+8888888888888+..
// ......8888888888888888..
// ....+8888+........++88..
// ....8888................
// ...8888.................
// ..+888+.................
// ..+888..................
// ..888+..................
// .+888+..................
// .+888...................
// .+888...................
// .+888...................
// .+888..........+++++++..
// .+888..........8888888..
// .+888+.........+++8888..
// ..888+............+888..
// ..8888............+888..
// ..+888+...........+888..
// ...8888+..........+888..
// ...+8888+.........+888..
// ....+88888+.......+888..
// .....+8888888888888888..
// .......+888888888888++..
// ..........++++++++......
// ........................
// ........................
// ........................
}
|