-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
151 lines (136 loc) · 3.54 KB
/
main.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"image"
"image/color"
"image/draw"
"image/jpeg"
"io/ioutil"
"os"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
func loadImage(filename string) image.Image {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
pic, err := jpeg.Decode(file)
if err != nil {
panic(err)
}
return pic
}
func saveImage(filename string, im image.Image) {
file, err := os.Create(filename)
if err != nil {
panic(err)
}
defer file.Close()
jpeg.Encode(file, im, &jpeg.Options{Quality: 100})
}
func newCanvas(w, h int) *image.RGBA {
rect := image.Rect(0, 0, w, h)
canvas := image.NewRGBA(rect)
for i := range canvas.Pix {
if i%250 == 0 {
canvas.Pix[i] = 0
} else {
canvas.Pix[i] = 255
}
}
return canvas
}
func fontFace(filename string, size float64) font.Face {
b, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
f, err := freetype.ParseFont(b)
if err != nil {
panic(err)
}
return truetype.NewFace(f, &truetype.Options{Size: size})
}
func drawBackground(canvas draw.Image, rect image.Rectangle) {
bg := image.NewUniform(color.RGBA{0, 0, 0, 100})
draw.Draw(canvas, rect, bg, image.ZP, draw.Over)
}
func paragraphHeight(text []string, ff font.Face, lineSpacing int) int {
return ff.Metrics().Ascent.Floor() +
(ff.Metrics().Height.Floor()+lineSpacing)*len(text) - lineSpacing
}
func wordWrap(text string, width int, ff font.Face) []string {
lineWidth := fixed.I(0)
rs := []rune(text)
line := ""
lines := make([]string, 0)
for i := 0; i < len(rs); i++ {
r := rs[i]
advance, ok := ff.GlyphAdvance(r)
if !ok {
// skipping unknown character
continue
}
if lineWidth+advance < fixed.I(width) {
line += string(r)
lineWidth += advance
if r == '\n' { // handle line breakers
line = line[:len(line)-1]
lines = append(lines, line)
line = ""
lineWidth = fixed.I(0)
}
if i == len(rs)-1 { // last loop
lines = append(lines, line)
}
} else {
lines = append(lines, line)
line = ""
lineWidth = fixed.I(0)
i--
}
}
return lines
}
func drawTextWordWrap(canvas draw.Image, lines []string,
ff font.Face, lineSpacing, x, y int) {
point := fixed.Point26_6{
// X offset
X: fixed.I(x),
// Y offset of glyph
// This value is accepted by font.Drawer as the Y value of baseline,
// so Ascent value must be added
Y: ff.Metrics().Ascent + fixed.I(y),
}
drawer := &font.Drawer{
Src: image.NewUniform(color.Black),
Dst: canvas,
// Note that this is the baseline location
Dot: point,
Face: ff,
}
for _, line := range lines {
drawer.DrawString(line)
point.Y += ff.Metrics().Height
point.Y += fixed.I(lineSpacing)
drawer.Dot = point
}
}
func main() {
const w, h = 500, 500
const spacing = 2
const leftMargin, rightMargin = 10, 10
const text = `瓦亚格岛
瓦亚格岛是印度尼西亚西巴布亚省拉贾安帕特群岛的一部分。这些无人居住的小岛很受潜水者和浮潜者的欢迎,他们渴望探索周围巨大而多样的珊瑚礁系统。
瓦亚格岛是珊瑚礁三角区的一部分,虽然它只覆盖了地球上1.6%的海洋区域,但却包含了地球上所有已知的珊瑚物种的76%。`
ff := fontFace("C:/Windows/Fonts/simsun.ttc", 24)
canvas := newCanvas(w, h)
lines := wordWrap(text, w/2, ff)
drawBackground(canvas, image.Rect(leftMargin, rightMargin, w/2,
paragraphHeight(lines, ff, spacing)))
drawTextWordWrap(canvas, lines, ff, spacing, leftMargin, rightMargin)
saveImage("output.jpg", canvas)
}