@@ -2,14 +2,16 @@ package captcha
2
2
3
3
import (
4
4
// "fmt"
5
+ "image"
6
+ "image/draw"
5
7
6
8
"embed"
7
9
// "fmt"
8
10
"github.com/golang/freetype"
9
11
"github.com/golang/freetype/truetype"
10
- "image"
12
+ // "image"
11
13
"image/color"
12
- // "math"
14
+ "math"
13
15
"math/rand"
14
16
"time"
15
17
)
@@ -33,6 +35,13 @@ type Canvas struct {
33
35
* image.NRGBA
34
36
Width int
35
37
Height int
38
+ Config Config
39
+ }
40
+
41
+ //DrawBackgroud 设置画板背景
42
+ func (c * Canvas ) DrawBackgroud () {
43
+ backgroupColor := image .NewUniform (c .Config .BackgroupColor )
44
+ draw .Draw (c , c .Bounds (), backgroupColor , image .ZP , draw .Over )
36
45
}
37
46
38
47
func (c * Canvas ) DrawLines (lineCount int ) {
@@ -51,12 +60,12 @@ func (c *Canvas) DrawLines(lineCount int) {
51
60
func (c * Canvas ) DrawLine (p1 , p2 Point , color color.Color ) {
52
61
53
62
var k float64 = 0
54
- b := p1 . Y
63
+ var b float64 = 0
55
64
if (p2 .X - p1 .X ) != 0 {
56
65
k = float64 (p2 .Y - p1 .Y ) / float64 (p2 .X - p1 .X )
57
66
}
58
67
59
- b = p1 .Y - int ( k * float64 (p1 .X ) )
68
+ b = float64 ( p1 .Y ) - k * float64 (p1 .X )
60
69
61
70
sx := 1
62
71
offsetX := p1 .X
@@ -65,9 +74,32 @@ func (c *Canvas) DrawLine(p1, p2 Point, color color.Color) {
65
74
sx = - 1
66
75
}
67
76
77
+ if k == 0 && p2 .X == p1 .X {
78
+
79
+ tmpY := p1 .Y
80
+
81
+ if p2 .Y < p1 .Y {
82
+ sx = - 1
83
+ }
84
+
85
+ for {
86
+
87
+ c .Set (offsetX , tmpY , color )
88
+
89
+ if tmpY == p2 .Y {
90
+ break
91
+ }
92
+
93
+ tmpY = tmpY + sx
94
+
95
+ }
96
+
97
+ return
98
+ }
99
+
68
100
for {
69
101
70
- offsetY := int (k * float64 (offsetX )) + b
102
+ offsetY := int (k * float64 (offsetX ) + b )
71
103
c .Set (offsetX , offsetY , color )
72
104
73
105
if offsetX == p2 .X {
@@ -78,32 +110,180 @@ func (c *Canvas) DrawLine(p1, p2 Point, color color.Color) {
78
110
}
79
111
}
80
112
113
+ //DrawBezierLines 画贝塞尔干扰线
114
+ func (c * Canvas ) DrawBezierLines (lineCount int ) {
115
+
116
+ for lineCount > 0 {
117
+
118
+ lineColor := randomColor ()
119
+
120
+ x1 := rand .Intn (c .Width / 4 )
121
+ y1 := randomInt (c .Height / 4 , int (float64 (c .Height )* 0.9 ))
122
+
123
+ x2 := randomInt (c .Width / 2 , int (float64 (c .Width )* 0.9 ))
124
+ y2 := randomInt (c .Height / 4 , int (float64 (c .Height )* 0.9 ))
125
+
126
+ cx := randomInt (c .Width / 4 , int (float64 (c .Width )* 0.7 ))
127
+ cy := randomInt (c .Height / 4 , int (float64 (c .Height )* 0.6 ))
128
+
129
+ // B(t) = (1-t)P0 + 2t(1-t)P1 + tP2, t∈[0,1]
130
+ // x = Math.pow(1-t, 2) * x1 + 2 * t * (1-t) * cx + Math.pow(t, 2) * x2
131
+ // y = Math.pow(1-t, 2) * y1 + 2 * t * (1-t) * cy + Math.pow(t, 2) * y2
132
+ var t float64
133
+ for t < 1 {
134
+
135
+ x := math .Pow (1 - t , 2.0 )* float64 (x1 ) + 2 * t * (1 - t )* float64 (cx ) + math .Pow (t , 2.0 )* float64 (x2 )
136
+ y := math .Pow (1 - t , 2 )* float64 (y1 ) + 2 * t * (1 - t )* float64 (cy ) + math .Pow (t , 2 )* float64 (y2 )
137
+
138
+ c .Set (int (x ), int (y ), lineColor )
139
+ t = t + 0.001
140
+ }
141
+
142
+ lineCount --
143
+ }
144
+
145
+ }
146
+
81
147
func (c * Canvas ) DrawString (text string ) {
82
148
149
+ var drawPos []DrawPos
83
150
for _ , ch := range text {
84
151
85
- dc := freetype .NewContext ()
86
- dc .SetDPI (float64 (72 ))
87
- dc .SetFont (defaultFont )
88
- dc .SetClip (c .Bounds ())
89
- dc .SetDst (c )
152
+ pos := c .randomFontPosition (56 )
90
153
91
- // 文字大小
92
- dc .SetFontSize (float64 (56 ))
154
+ fontImg , areaPoint := c .DrawFont (string (ch ), c .Config .FrontColors )
155
+
156
+ minX := areaPoint .MinX
157
+ maxX := areaPoint .MaxX
158
+ minY := areaPoint .MinY
159
+ maxY := areaPoint .MaxY
160
+ width := maxX - minX
161
+ height := maxY - minY
162
+ nW := fontImg .Bounds ().Max .X
163
+ nH := fontImg .Bounds ().Max .Y
164
+ for x := 0 ; x < nW ; x ++ {
165
+ for y := 0 ; y < nH ; y ++ {
166
+ co := fontImg .At (x , y )
167
+ if _ , _ , _ , a := co .RGBA (); a > 0 {
168
+ if x >= minX && x <= maxX && y >= minY && y <= maxY {
169
+ c .Set (pos .X + (x - minX ), pos .Y - height + (y - minY ), fontImg .At (x , y ))
170
+ }
171
+ }
172
+ }
173
+ }
93
174
94
- // 文字颜色
95
- fontColor := image .NewUniform (randomColor ())
96
- dc .SetSrc (fontColor )
175
+ var dp DrawPos
176
+ dp .X = minX + pos .X
177
+ dp .Y = pos .Y - height
178
+ dp .Width = width
179
+ dp .Height = height
97
180
98
- pos := c .randomFontPosition (56 )
99
- // 画文本
100
- pt := freetype .Pt (pos .X , pos .Y ) // 字出现的位置
101
- _ , err := dc .DrawString (string (ch ), pt )
102
- if err != nil {
103
- panic (err )
181
+ drawPos = append (drawPos , dp )
182
+
183
+ }
184
+
185
+ // lineColor := randomColor()
186
+
187
+ // for _, linePos := range drawPos {
188
+ // p1 := Point{X: linePos.X, Y: linePos.Y}
189
+ // p2 := Point{X: linePos.X + linePos.Width, Y: linePos.Y}
190
+
191
+ // p3 := Point{X: linePos.X, Y: linePos.Y + linePos.Height}
192
+ // p4 := Point{X: linePos.X + linePos.Width, Y: linePos.Y + linePos.Height}
193
+ // c.DrawLine(p1, p2, lineColor)
194
+ // c.DrawLine(p1, p3, lineColor)
195
+ // c.DrawLine(p3, p4, lineColor)
196
+ // c.DrawLine(p2, p4, lineColor)
197
+
198
+ // }
199
+ // fmt.Printf("drawpos %+v %s", drawPos, text)
200
+
201
+ }
202
+
203
+ //DrawFont 绘制验证码字
204
+ func (c * Canvas ) DrawFont (fontText string , fontColors []color.Color ) (* Palette , * AreaPoint ) {
205
+ fontSize := 56
206
+
207
+ rand .Seed (time .Now ().UnixNano ())
208
+
209
+ fntColorIndex := rand .Intn (len (fontColors ))
210
+
211
+ rColor := fontColors [fntColorIndex ]
212
+ p := []color.Color {
213
+ color.RGBA {R : 0xFF , G : 0xFF , B : 0xFF , A : 0x00 },
214
+ rColor ,
215
+ }
216
+
217
+ canvas := NewPalette (image .Rect (0 , 0 , fontSize , fontSize ), p )
218
+
219
+ dc := freetype .NewContext ()
220
+ dc .SetDPI (float64 (72 ))
221
+ dc .SetFont (defaultFont )
222
+ dc .SetClip (canvas .Bounds ())
223
+ dc .SetDst (canvas )
224
+
225
+ // 文字大小
226
+ dc .SetFontSize (float64 (56 ))
227
+
228
+ // 文字颜色
229
+ fontColor := image .NewUniform (rColor )
230
+ dc .SetSrc (fontColor )
231
+
232
+ // 画文本
233
+ pt := freetype .Pt (0 , fontSize ) // 字出现的位置
234
+ _ , err := dc .DrawString (string (fontText ), pt )
235
+
236
+ if err != nil {
237
+ panic (err )
238
+ }
239
+
240
+ //旋转角度
241
+ canvas .Rotate (randomInt (- 30 , 30 ))
242
+ ap := c .calcImageSpace (canvas )
243
+ return canvas , ap
244
+
245
+ }
246
+
247
+ func (c * Canvas ) calcImageSpace (pa * Palette ) * AreaPoint {
248
+ nW := pa .Bounds ().Max .X
249
+ nH := pa .Bounds ().Max .Y
250
+ // 计算裁剪的最小及最大的坐标
251
+ minX := nW
252
+ maxX := 0
253
+ minY := nH
254
+ maxY := 0
255
+ for x := 0 ; x < nW ; x ++ {
256
+ for y := 0 ; y < nH ; y ++ {
257
+ co := pa .At (x , y )
258
+ if _ , _ , _ , a := co .RGBA (); a > 0 {
259
+ if x < minX {
260
+ minX = x
261
+ }
262
+ if x > maxX {
263
+ maxX = x
264
+ }
265
+
266
+ if y < minY {
267
+ minY = y
268
+ }
269
+ if y > maxY {
270
+ maxY = y
271
+ }
272
+ }
104
273
}
105
274
}
106
275
276
+ minX = int (math .Max (0 , float64 (minX - 2 )))
277
+ maxX = int (math .Min (float64 (nW ), float64 (maxX + 2 )))
278
+ minY = int (math .Max (0 , float64 (minY - 2 )))
279
+ maxY = int (math .Min (float64 (nH ), float64 (maxY + 2 )))
280
+
281
+ return & AreaPoint {
282
+ minX ,
283
+ maxX ,
284
+ minY ,
285
+ maxY ,
286
+ }
107
287
}
108
288
109
289
func (c * Canvas ) randomFontPosition (fontSize int ) Point {
0 commit comments