aboutsummaryrefslogtreecommitdiffstats
path: root/examples/imageviewer/util.go
blob: 94f25fb420224525190e58a36fbc84ee7e8be0ab (plain) (blame)
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
package main

import (
	"image"
	"image/color"
	"image/draw"
	"sync"

	"github.com/golang/freetype/truetype"

	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

type concurrentFace struct {
	mu   sync.Mutex
	face font.Face
}

func (cf *concurrentFace) Close() error {
	cf.mu.Lock()
	defer cf.mu.Unlock()
	return cf.face.Close()
}

func (cf *concurrentFace) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
	cf.mu.Lock()
	defer cf.mu.Unlock()
	return cf.face.Glyph(dot, r)
}

func (cf *concurrentFace) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
	cf.mu.Lock()
	defer cf.mu.Unlock()
	return cf.face.GlyphBounds(r)
}

func (cf *concurrentFace) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
	cf.mu.Lock()
	defer cf.mu.Unlock()
	return cf.face.GlyphAdvance(r)
}

func (cf *concurrentFace) Kern(r0, r1 rune) fixed.Int26_6 {
	cf.mu.Lock()
	defer cf.mu.Unlock()
	return cf.face.Kern(r0, r1)
}

func (cf *concurrentFace) Metrics() font.Metrics {
	cf.mu.Lock()
	defer cf.mu.Unlock()
	return cf.face.Metrics()
}

func TTFToFace(ttf []byte, size float64) (font.Face, error) {
	font, err := truetype.Parse(ttf)
	if err != nil {
		return nil, err
	}
	return &concurrentFace{face: truetype.NewFace(font, &truetype.Options{
		Size: size,
	})}, nil
}

func DrawText(text string, face font.Face, clr color.Color) image.Image {
	drawer := &font.Drawer{
		Src:  &image.Uniform{clr},
		Face: face,
		Dot:  fixed.P(0, 0),
	}
	b26_6, _ := drawer.BoundString(text)
	bounds := image.Rect(
		b26_6.Min.X.Floor(),
		b26_6.Min.Y.Floor(),
		b26_6.Max.X.Ceil(),
		b26_6.Max.Y.Ceil(),
	)
	drawer.Dst = image.NewRGBA(bounds)
	drawer.DrawString(text)
	return drawer.Dst
}

func DrawCentered(dst draw.Image, r image.Rectangle, src image.Image, op draw.Op) {
	if src == nil {
		return
	}
	bounds := src.Bounds()
	center := bounds.Min.Add(bounds.Max).Div(2)
	target := r.Min.Add(r.Max).Div(2)
	delta := target.Sub(center)
	draw.Draw(dst, bounds.Add(delta).Intersect(r), src, bounds.Min, op)
}

func DrawLeftCentered(dst draw.Image, r image.Rectangle, src image.Image, op draw.Op) {
	if src == nil {
		return
	}
	bounds := src.Bounds()
	leftCenter := image.Pt(bounds.Min.X, (bounds.Min.Y+bounds.Max.Y)/2)
	target := image.Pt(r.Min.X, (r.Min.Y+r.Max.Y)/2)
	delta := target.Sub(leftCenter)
	draw.Draw(dst, bounds.Add(delta).Intersect(r), src, bounds.Min, op)
}