-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdraw.go
More file actions
95 lines (78 loc) · 2.46 KB
/
draw.go
File metadata and controls
95 lines (78 loc) · 2.46 KB
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
package main
// adopted from https://github.com/nomad-software/meme/blob/ec8784f58dac72574b2742fa787ed0798a4dcc53/image/draw/draw.go
import (
_ "embed"
"image"
"math"
"strings"
"github.com/fogleman/gg"
"github.com/golang/freetype/truetype"
)
const (
fontBorderRadius = 3.0 // px
fontLeading = 1.4 // percentage
maxFontSize = 85.0 // pts
topTextDivisor = 5.0 // divisor
bottomTextDivisor = 3.75 // divisor
imageMargin = 18.0 // px
)
// NewContext creates a new context for the passed image
func NewContext(img image.Image) *gg.Context {
return gg.NewContextForImage(img)
}
// TopBanner draws the top text onto the meme.
func TopBanner(ctx *gg.Context, text string) {
x := float64(ctx.Width()) / 2
y := imageMargin
drawText(ctx, text, x, y, 0.5, 0.0, topTextDivisor)
}
// BottomBanner draws the bottom text onto the meme.
func BottomBanner(ctx *gg.Context, text string) {
x := float64(ctx.Width()) / 2
y := float64(ctx.Height()) - imageMargin
drawText(ctx, text, x, y, 0.5, 1.0, bottomTextDivisor)
}
// Draw text onto the meme.
func drawText(ctx *gg.Context, text string, x float64, y float64, ax float64, ay float64, divisor float64) {
text = strings.ToUpper(text)
width := float64(ctx.Width()) - (imageMargin * 2)
height := float64(ctx.Height()) / divisor
calculateFontSize(ctx, text, width, height)
// Draw the text border.
ctx.SetHexColor("#000")
for angle := 0.0; angle < (2 * math.Pi); angle += 0.35 {
bx := x + (math.Sin(angle) * fontBorderRadius)
by := y + (math.Cos(angle) * fontBorderRadius)
ctx.DrawStringWrapped(text, bx, by, ax, ay, width, fontLeading, gg.AlignCenter)
}
// Draw the text itself.
ctx.SetHexColor("#FFF")
ctx.DrawStringWrapped(text, x, y, ax, ay, width, fontLeading, gg.AlignCenter)
}
var tf *truetype.Font
//go:embed impact.ttf
var impact []byte
func init() {
tf, _ = truetype.Parse(impact)
}
// Dynamically calculate the correct size needed for text.
func calculateFontSize(ctx *gg.Context, text string, width float64, height float64) {
for size := maxFontSize; size > 20; size-- {
var rWidth, rHeight float64
var lWidth, lHeight float64
if err := ctx.LoadFontFace("impact.ttf", size); err != nil {
panic(err)
}
lines := ctx.WordWrap(text, width)
for _, line := range lines {
lWidth, lHeight = ctx.MeasureString(line)
if lWidth > rWidth {
rWidth = lWidth
}
}
rHeight = (lHeight * fontLeading) * float64(len(lines))
if rWidth <= width && rHeight <= height {
break
}
}
}