forked from fogleman/gg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
225 lines (201 loc) · 5.1 KB
/
util.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package gg
import (
"bufio"
"fmt"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"math"
"os"
"strings"
"github.com/fumiama/imgsz"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// 弧度
func Radians(degrees float64) float64 {
return degrees * math.Pi / 180
}
// 角度
func Degrees(radians float64) float64 {
return radians * 180 / math.Pi
}
// 加载指定路径的图像
func LoadImage(path string) (image.Image, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
im, _, err := image.Decode(bufio.NewReader(file))
return im, err
}
// 加载指定路径的 JPG 图像
func LoadJPG(path string) (image.Image, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
return jpeg.Decode(bufio.NewReader(file))
}
// 保存 JPG 图像
func SaveJPG(path string, im image.Image, quality int) error {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
return jpeg.Encode(file, im, &jpeg.Options{
Quality: quality, // 质量百分比
})
}
// 加载指定路径的 PNG 图像
func LoadPNG(path string) (image.Image, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
return png.Decode(bufio.NewReader(file))
}
// 保存 PNG 图像
func SavePNG(path string, im image.Image) error {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
return png.Encode(file, im)
}
// image.Image 转为 image.RGBA
func ImageToRGBA(src image.Image) *image.RGBA {
return imageToRGBA(src)
}
// image.Image 转为 image.RGBA
func imageToRGBA(src image.Image) *image.RGBA {
bounds := src.Bounds()
dst := image.NewRGBA(bounds)
draw.Draw(dst, bounds, src, bounds.Min, draw.Src)
return dst
}
// image.Image 转为 image.RGBA64
func ImageToRGBA64(src image.Image) *image.RGBA64 {
bounds := src.Bounds()
dst := image.NewRGBA64(bounds)
draw.Draw(dst, bounds, src, bounds.Min, draw.Src)
return dst
}
// image.Image 转为 image.NRGBA
func ImageToNRGBA(src image.Image) *image.NRGBA {
bounds := src.Bounds()
dst := image.NewNRGBA(bounds)
draw.Draw(dst, bounds, src, bounds.Min, draw.Src)
return dst
}
// image.Image 转为 *image.NRGBA64
func ImageToNRGBA64(src image.Image) *image.NRGBA64 {
bounds := src.Bounds()
dst := image.NewNRGBA64(bounds)
draw.Draw(dst, bounds, src, bounds.Min, draw.Src)
return dst
}
// 解析图片的宽高信息
func GetWH(path string) (int, int, error) {
f, err := os.Open(path)
if err != nil {
return 0, 0, err
}
defer f.Close()
sz, _, err := imgsz.DecodeSize(f)
return sz.Width, sz.Height, err
}
// 解析十六进制颜色
func ParseHexColor(x string) (r, g, b, a int) {
return parseHexColor(x)
}
// 解析十六进制颜色
func parseHexColor(x string) (r, g, b, a int) {
x = strings.TrimPrefix(x, "#")
a = 255
switch len(x) {
case 3:
format := "%1x%1x%1x"
fmt.Sscanf(x, format, &r, &g, &b)
r |= r << 4
g |= g << 4
b |= b << 4
case 6:
format := "%02x%02x%02x"
fmt.Sscanf(x, format, &r, &g, &b)
case 8:
format := "%02x%02x%02x%02x"
fmt.Sscanf(x, format, &r, &g, &b, &a)
}
return
}
func fixp(x, y float64) fixed.Point26_6 {
return fixed.Point26_6{
X: fix(x),
Y: fix(y),
}
}
func fix(x float64) fixed.Int26_6 {
return fixed.Int26_6(math.Round(x * 64))
}
func unfix(x fixed.Int26_6) float64 {
const shift, mask = 6, 1<<6 - 1
if x >= 0 {
return float64(x>>shift) + float64(x&mask)/64
}
x = -x
if x >= 0 {
return -(float64(x>>shift) + float64(x&mask)/64)
}
return 0
}
// LoadFontFace is a helper function to load the specified font file with
// the specified point size. Note that the returned `font.Face` objects
// are not thread safe and cannot be used in parallel across goroutines.
// You can usually just use the Context.LoadFontFace function instead of
// this package-level function.
//
// LoadFontFace 是一个辅助函数,用于加载指定点大小的指定字体文件。
// 请注意,返回的 `font.Face` 对象不是线程安全的,不能跨 goroutine 并行使用。
// 您通常可以只使用 Context.LoadFontFace 函数而不是这个包级函数。
func LoadFontFace(path string, points float64) (face font.Face, err error) {
fontBytes, err := os.ReadFile(path)
if err != nil {
return
}
f, err := truetype.Parse(fontBytes)
if err != nil {
return
}
face = truetype.NewFace(f, &truetype.Options{
Size: points,
// Hinting: font.HintingFull,
})
return
}
// ParseFontFace 是一个辅助函数,用于加载指定点大小的指定字体文件。
// 请注意,返回的 `font.Face` 对象不是线程安全的,不能跨 goroutine 并行使用。
// 您通常可以只使用 Context.LoadFontFace 函数而不是这个包级函数。
func ParseFontFace(b []byte, points float64) (face font.Face, err error) {
f, err := truetype.Parse(b)
if err != nil {
return
}
face = truetype.NewFace(f, &truetype.Options{
Size: points,
// Hinting: font.HintingFull,
})
return
}
// Takecolor 实现基于k-means算法的图像取色算法
func TakeColor(img image.Image, k int) []color.RGBA {
return takecolor(img, k)
}