-
Notifications
You must be signed in to change notification settings - Fork 3
/
image.go
129 lines (108 loc) · 2.79 KB
/
image.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
package image
import (
"bytes"
"image"
"image/draw"
"image/gif"
"image/jpeg"
"image/png"
"strings"
"golang.org/x/image/bmp"
"github.com/nfnt/resize"
)
const (
PNG = "png"
JPEG = "jpeg"
GIF = "gif"
BMP = "bmp"
)
const (
Center = "center"
AspectFill = "fill"
)
type Object interface {
Resize(width, height int, mode string) ([]byte, error)
}
type object struct {
img image.Image
format string
}
func New(format string, body []byte) (Object, error) {
img, _, err := image.Decode(bytes.NewReader(body))
if err != nil {
return nil, err
}
return &object{img: img, format: format}, err
}
func (o *object) Resize(width, height int, mode string) ([]byte, error) {
var img image.Image
switch mode {
case Center:
img = o.Center(width, height)
case AspectFill:
img = o.AspectFill(width, height)
}
return o.ImageToBytes(img)
}
func (o *object) Center(width, height int) image.Image {
// 创建目标图像
target := image.NewRGBA(image.Rect(0, 0, width, height))
// 计算裁剪位置
x, y := 0, 0
x = (o.img.Bounds().Dx() - width) / 2
y = (o.img.Bounds().Dy() - height) / 2
// 裁剪图像
draw.Draw(target, target.Bounds(), o.img, image.Point{X: x, Y: y}, draw.Src)
// 调整图像大小
return resize.Resize(uint(width), uint(height), target, resize.Lanczos3)
}
func (o *object) AspectFill(width, height int) image.Image {
// 获取原始图像的宽高
srcWidth := o.img.Bounds().Dx()
srcHeight := o.img.Bounds().Dy()
// 计算原始图像的宽高比和目标宽高比
srcAspectRatio := float64(srcWidth) / float64(srcHeight)
dstAspectRatio := float64(width) / float64(height)
// 计算裁剪区域的起始点和大小
var cropX, cropY, cropWidth, cropHeight int
if srcAspectRatio > dstAspectRatio {
// 原始图像更宽,裁剪高度
cropWidth = int(float64(srcHeight) * dstAspectRatio)
cropHeight = srcHeight
cropX = (srcWidth - cropWidth) / 2
cropY = 0
} else {
// 原始图像更高,裁剪宽度
cropWidth = srcWidth
cropHeight = int(float64(srcWidth) / dstAspectRatio)
cropX = 0
cropY = (srcHeight - cropHeight) / 2
}
// 创建裁剪后的图像
croppedImg := image.NewRGBA(image.Rect(0, 0, cropWidth, cropHeight))
draw.Draw(croppedImg, croppedImg.Bounds(), o.img, image.Point{X: cropX, Y: cropY}, draw.Over)
// 缩放图像
return resize.Resize(uint(width), uint(height), croppedImg, resize.Lanczos3)
}
func (o *object) ImageToBytes(img image.Image) ([]byte, error) {
var (
err error
buffer strings.Builder
)
switch o.format {
case PNG:
err = png.Encode(&buffer, img)
case JPEG:
err = jpeg.Encode(&buffer, img, nil)
case GIF:
err = gif.Encode(&buffer, img, nil)
case BMP:
err = bmp.Encode(&buffer, img)
default:
err = png.Encode(&buffer, img)
}
if err != nil {
return nil, err
}
return []byte(buffer.String()), nil
}