-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate.go
131 lines (115 loc) · 2.56 KB
/
generate.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
package rgbqrcode
import (
"bytes"
"encoding/base64"
"errors"
"image"
"image/color"
"image/draw"
"image/png"
_ "image/png"
"os"
"github.com/skip2/go-qrcode"
)
type (
GenerateParam struct {
// Image or logo file path
// Ex: "name.png"
LogoPath *os.File
// Value or data will encoded to QR CODE
QrValue string
// Size of QRCODE
// Default: 256
QrSize int
}
encodeQr struct {
imageLogo image.Image
value string
size int
}
ResultEncode struct {
Base64 string
PNG bytes.Buffer
}
)
func New(param GenerateParam) (encodeQr, error) {
imageLogo, _, err := image.Decode(param.LogoPath)
if err != nil {
return encodeQr{}, err
}
// validate logo size...
if validLogoSz := validateLogoSize(
imageLogo.Bounds().Dx(),
imageLogo.Bounds().Dy(),
); !validLogoSz {
return encodeQr{}, errors.New("Please use logo with size 50 X 50")
}
if param.QrSize == 0 {
param.QrSize = 256
}
return encodeQr{
imageLogo: imageLogo,
value: param.QrValue,
size: param.QrSize,
}, nil
}
// validateLogoSize
func validateLogoSize(x, y int) bool {
if x == 50 && y == 50 {
return true
}
return false
}
// Encode QR Code To base64 and byte
func (eq encodeQr) Encode() (ResultEncode, error) {
byteQR, err := qrcode.New(eq.value, qrcode.High)
if err != nil {
return ResultEncode{}, err
}
// RGBA Logo and QRCode
qrCodeImage := byteQR.Image(eq.size)
qrcodeRGBA := image.NewNRGBA(qrCodeImage.Bounds())
eq.overlayRGBLogo(qrCodeImage, eq.imageLogo, qrcodeRGBA)
// Result...
resPNG := eq.convertToPNG(qrcodeRGBA)
resBase64 := eq.convertToBase64(resPNG.Bytes())
return ResultEncode{
PNG: resPNG,
Base64: resBase64,
}, nil
}
// convertToPNG
func (eq encodeQr) convertToPNG(qrImage *image.NRGBA) bytes.Buffer {
var buf bytes.Buffer
// encode to png image
if err := png.Encode(&buf, qrImage); err != nil {
return bytes.Buffer{}
}
return buf
}
// convert to base64...
func (eq encodeQr) convertToBase64(data []byte) string {
return base64.RawStdEncoding.EncodeToString(data)
}
// overlayRGBLogo...
func (eq encodeQr) overlayRGBLogo(qrcode, logo image.Image, rgbQR draw.Image) {
draw.Draw(rgbQR, qrcode.Bounds(), qrcode, image.Point{}, draw.Over)
// offset logo
offset := qrcode.Bounds().Max.X/2 - logo.Bounds().Max.X/2
for x := 0; x < logo.Bounds().Max.X; x++ {
for y := 0; y < logo.Bounds().Max.Y; y++ {
r, g, b, a := logo.At(x, y).RGBA()
// set logo to qr code with RGBA
rgbQR.Set(
x+offset,
y+offset,
color.RGBA{
R: uint8(r),
G: uint8(g),
B: uint8(b),
A: uint8(a),
},
)
}
}
}