Skip to content

Commit 078c393

Browse files
committed
optimize the rotation captcha
1 parent a73f44c commit 078c393

File tree

6 files changed

+128
-37
lines changed

6 files changed

+128
-37
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- Angular Package:[https://github.com/wenlng/go-captcha-angular](https://github.com/wenlng/go-captcha-angular)
3636
- Svelte Package:[https://github.com/wenlng/go-captcha-svelte](https://github.com/wenlng/go-captcha-svelte)
3737
- Solid Package:[https://github.com/wenlng/go-captcha-solid](https://github.com/wenlng/go-captcha-solid)
38+
- UniApp Module:[https://github.com/wenlng/go-captcha-uni](https://github.com/wenlng/go-captcha-uni)
3839
- ...
3940

4041
<br/>
@@ -508,8 +509,9 @@ builder.SetResources(rotate.WithXxx(), ...)
508509
- [x] Angular
509510
- [x] Svelte
510511
- [x] Solid
511-
- [ ] MinProgram
512-
- [ ] UniApp
512+
- [x] UniApp
513+
- [ ] WX-Applet
514+
- [ ] React Native App
513515
- [ ] Flutter App
514516
- [ ] Android App
515517
- [ ] IOS App

README_zh.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
- Angular Package:[https://github.com/wenlng/go-captcha-angular](https://github.com/wenlng/go-captcha-angular)
4242
- Svelte Package:[https://github.com/wenlng/go-captcha-svelte](https://github.com/wenlng/go-captcha-svelte)
4343
- Solid Package:[https://github.com/wenlng/go-captcha-solid](https://github.com/wenlng/go-captcha-solid)
44+
- UniApp Module:[https://github.com/wenlng/go-captcha-uni](https://github.com/wenlng/go-captcha-uni)
4445
- ...
4546

4647
<br/>
@@ -375,7 +376,7 @@ func loadPng(p string) (image.Image, error) {
375376
### 验证码数据
376377
- GetData() *Block 获取当前校验的信息
377378
- GetMasterImage() imagedata.JPEGImageData 获取主图
378-
- GetTitleImage() imagedata.PNGImageData 获取缩略图
379+
- GetTileImage() imagedata.PNGImageData 获取缩略图
379380

380381

381382
<br />
@@ -490,7 +491,6 @@ func loadPng(p string) (image.Image, error) {
490491
- GetMasterImage() imagedata.PNGImageData 获取主图
491492
- GetThumbImage() imagedata.PNGImageData 获取缩略图
492493

493-
494494
<br/>
495495

496496
## 验证码图像
@@ -514,19 +514,28 @@ func loadPng(p string) (image.Image, error) {
514514

515515
<br/>
516516

517-
## 验证模块
518-
- 文字点选式
519-
- 图形点选式
520-
- 滑动式
521-
- 拖拽式
522-
- 旋转式
517+
## 验证模式
518+
- [x] 文字点选
519+
- [x] 图形点选
520+
- [x] 滑动
521+
- [x] 拖拽
522+
- [x] 旋转
523+
- [ ] 抛物线
524+
- [ ] 物品辨认
525+
- [ ] ...
523526

524-
<br />
527+
## 扩展&增强
528+
- [x] 基本验证
529+
- [ ] 行为轨迹验证增强
530+
- [ ] 其他因素增强
531+
- [ ] 多任务生成模式
532+
- [ ] ...
525533

526534
## 语言支持
527535
- [x] Golang
528536
- [ ] NodeJs
529537
- [ ] Rust
538+
- [ ] ...
530539

531540
## 前端安装包
532541
- [x] JavaScript
@@ -535,8 +544,9 @@ func loadPng(p string) (image.Image, error) {
535544
- [x] Angular
536545
- [x] Svelte
537546
- [x] Solid
538-
- [ ] MinProgram
539-
- [ ] UniApp
547+
- [x] UniApp
548+
- [ ] WX-Applet
549+
- [ ] React Native App
540550
- [ ] Flutter App
541551
- [ ] Android App
542552
- [ ] IOS App

v2/base/canvas/helper.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package canvas
88

99
import (
10+
"image"
1011
"math"
1112
)
1213

@@ -42,3 +43,27 @@ func RotatedSize(w, h int, angle float64) (int, int) {
4243

4344
return int(width), int(height)
4445
}
46+
47+
func CalcResizedRect(src image.Rectangle, width int, height int, centerAlign bool) image.Rectangle {
48+
var dst image.Rectangle
49+
if width*src.Dy() < height*src.Dx() {
50+
ratio := float64(width) / float64(src.Dx())
51+
52+
tH := int(float64(src.Dy()) * ratio)
53+
pad := 0
54+
if centerAlign {
55+
pad = (height - tH) / 2
56+
}
57+
dst = image.Rect(0, pad, width, pad+tH)
58+
} else {
59+
ratio := float64(height) / float64(src.Dy())
60+
tW := int(float64(src.Dx()) * ratio)
61+
pad := 0
62+
if centerAlign {
63+
pad = (width - tW) / 2
64+
}
65+
dst = image.Rect(pad, 0, pad+tW, height)
66+
}
67+
68+
return dst
69+
}

v2/base/canvas/nrgba.go

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ type NRGBA interface {
2525
DrawImage(img Palette, dotRect *PositionRect, posRect *AreaRect)
2626
DrawString(params *DrawStringParams, pt fixed.Point26_6) error
2727
CalcMarginBlankArea() *AreaRect
28-
Rotate(angle int)
29-
CropCircle(x, y, radius, zoom int)
28+
Rotate(angle int, overCrop bool)
29+
Scale(zoomSize int, keepRatio, centerAlign bool)
30+
CropCircle(x, y, radius int)
31+
CropScaleCircle(x, y, radius int, zoomSize int)
3032
SubImage(r image.Rectangle)
3133
}
3234

@@ -150,15 +152,17 @@ func (n *nRGBA) CalcMarginBlankArea() *AreaRect {
150152
}
151153

152154
// Rotate is to rotation at any Angle
153-
func (n *nRGBA) Rotate(a int) {
155+
func (n *nRGBA) Rotate(a int, overCrop bool) {
154156
if a == 0 {
155157
return
156158
}
157159

158160
angle := float64(a) * math.Pi / 180
159161

160-
w, h := RotatedSize(n.Bounds().Dx(), n.Bounds().Dy(), float64(a))
161-
im := image.NewNRGBA(image.Rect(0, 0, w, h))
162+
sW := n.Get().Bounds().Dx()
163+
sH := n.Get().Bounds().Dy()
164+
w, h := RotatedSize(sW, sH, float64(a))
165+
img := image.NewNRGBA(image.Rect(0, 0, w, h))
162166

163167
centerX := float64(w) / 2
164168
centerY := float64(h) / 2
@@ -172,21 +176,49 @@ func (n *nRGBA) Rotate(a int) {
172176
matrix = matrix.Rotate(angle)
173177
matrix = matrix.Translate(-centerX, -centerY)
174178

175-
x := (w - n.Bounds().Dx()) / 2
176-
y := (h - n.Bounds().Dy()) / 2
179+
x := (w - n.Get().Bounds().Dx()) / 2
180+
y := (h - n.Get().Bounds().Dy()) / 2
177181
fx, fy := float64(x), float64(y)
178182

179183
m := matrix.Translate(fx, fy)
180184
s2d := f64.Aff3{m.XX, m.XY, m.X0, m.YX, m.YY, m.Y0}
181185

182-
draw.BiLinear.Transform(im, s2d, n, n.Bounds(), draw.Over, nil)
183-
n.NRGBA = im
186+
draw.BiLinear.Transform(img, s2d, n.Get(), n.Get().Bounds(), draw.Over, nil)
187+
n.NRGBA = img
188+
189+
if overCrop {
190+
xx := w - sW
191+
yy := h - sH
192+
dx := xx / 2
193+
dy := yy / 2
194+
n.SubImage(image.Rect(dx, dy, sW+dx, sH+dy))
195+
}
184196
}
185197

186198
// CropCircle is to cut the circle
187-
func (n *nRGBA) CropCircle(x, y, radius, zoom int) {
188-
bounds := n.Bounds()
199+
func (n *nRGBA) CropCircle(x, y, radius int) {
200+
bounds := n.Get().Bounds()
201+
mask := image.NewNRGBA(bounds)
202+
for py := bounds.Min.Y; py < bounds.Max.Y; py++ {
203+
for px := bounds.Min.X; px < bounds.Max.X; px++ {
204+
dist := math.Hypot(float64(px-x), float64(py-y))
205+
if dist <= float64(radius) {
206+
mask.Set(px, py, color.White)
207+
} else {
208+
mask.Set(px, py, color.Transparent)
209+
}
210+
}
211+
}
212+
213+
draw.DrawMask(mask, mask.Bounds(), n.Get(), image.Point{X: 0, Y: 0}, mask, image.Point{}, draw.Over)
214+
n.NRGBA = mask
215+
}
216+
217+
// CropScaleCircle is to scale and crop the circle
218+
func (n *nRGBA) CropScaleCircle(x, y, radius int, zoomSize int) {
219+
bounds := n.Get().Bounds()
189220
mask := image.NewNRGBA(bounds)
221+
190222
for py := bounds.Min.Y; py < bounds.Max.Y; py++ {
191223
for px := bounds.Min.X; px < bounds.Max.X; px++ {
192224
dist := math.Hypot(float64(px-x), float64(py-y))
@@ -198,17 +230,39 @@ func (n *nRGBA) CropCircle(x, y, radius, zoom int) {
198230
}
199231
}
200232

201-
if zoom > 0 {
202-
subtract := zoom * 2
233+
if zoomSize > 0 {
234+
subtract := zoomSize * 2
203235
scaleMask := image.NewNRGBA(image.Rect(0, 0, n.Bounds().Dx()-subtract, n.Bounds().Dy()-subtract))
204236
draw.BiLinear.Scale(scaleMask, scaleMask.Bounds(), mask, mask.Bounds(), draw.Over, nil)
205237
mask = scaleMask
206238
}
207239

208-
draw.DrawMask(mask, mask.Bounds(), n.Get(), image.Point{X: zoom, Y: zoom}, mask, image.Point{}, draw.Over)
240+
draw.DrawMask(mask, mask.Bounds(), n.Get(), image.Point{X: zoomSize, Y: zoomSize}, mask, image.Point{}, draw.Over)
209241
n.NRGBA = mask
210242
}
211243

244+
// Scale is to scale the image
245+
func (n *nRGBA) Scale(zoomSize int, keepRatio, centerAlign bool) {
246+
img := n.NRGBA
247+
if zoomSize > 0 {
248+
subtract := zoomSize * 2
249+
newW := n.Get().Bounds().Dx() - subtract
250+
newH := n.Get().Bounds().Dy() - subtract
251+
outImg := image.NewNRGBA(image.Rect(0, 0, newW, newH))
252+
253+
if !keepRatio {
254+
draw.BiLinear.Scale(outImg, outImg.Bounds(), n.Get(), n.Get().Bounds(), draw.Over, nil)
255+
} else {
256+
dst := CalcResizedRect(n.Get().Bounds(), newW, newH, centerAlign)
257+
draw.ApproxBiLinear.Scale(outImg, dst.Bounds(), n.Get(), n.Get().Bounds(), draw.Over, nil)
258+
}
259+
260+
img = outImg
261+
}
262+
263+
n.NRGBA = img
264+
}
265+
212266
// SubImage is to capture the image
213267
func (n *nRGBA) SubImage(r image.Rectangle) {
214268
n.NRGBA = n.Get().SubImage(r).(*image.NRGBA)

v2/click/draw.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func (d *drawImage) DrawWithPalette(params *DrawImageParams, tColors []color.Col
136136
return nil, err
137137
}
138138

139-
dotImage.Rotate(dot.Angle)
139+
dotImage.Rotate(dot.Angle, false)
140140
bgBounds := cvs.Get().Bounds()
141141
dotBounds := dotImage.Bounds()
142142
drawAt := image.Point{X: bgBounds.Dx() - dotBounds.Dx(), Y: bgBounds.Dy() - dotBounds.Dy()}
@@ -230,7 +230,7 @@ func (d *drawImage) DrawWithNRGBA2(params *DrawImageParams, tColors []color.Colo
230230
return nil, err
231231
}
232232

233-
dotImage.Rotate(dot.Angle)
233+
dotImage.Rotate(dot.Angle, false)
234234

235235
bgBounds := ccvs.Get().Bounds()
236236
dotBounds := dotImage.Bounds()
@@ -242,7 +242,7 @@ func (d *drawImage) DrawWithNRGBA2(params *DrawImageParams, tColors []color.Colo
242242
if err != nil {
243243
return nil, err
244244
}
245-
cImage.Rotate(dot.Angle)
245+
cImage.Rotate(dot.Angle, false)
246246

247247
areaPoint := cImage.CalcMarginBlankArea()
248248
minX := areaPoint.MinX
@@ -343,7 +343,7 @@ func (d *drawImage) DrawDotImage(dot *DrawDot, params *DrawImageParams) (canvas.
343343
draw.Draw(cvs.Get(), shadowImg.Bounds(), shadowImg, image.Point{X: pointX, Y: pointY}, draw.Over)
344344
}
345345
draw.Draw(cvs.Get(), cImage.Bounds(), cImage, image.Point{}, draw.Over)
346-
cvs.Rotate(dot.Angle)
346+
cvs.Rotate(dot.Angle, false)
347347

348348
ap := cvs.CalcMarginBlankArea()
349349

@@ -383,7 +383,7 @@ func (d *drawImage) DrawShapeImage(dot *DrawDot, cColor color.Color) (canvas.NRG
383383
var colorArr = []color.RGBA{
384384
{R: uint8(cr), G: uint8(cg), B: uint8(cb), A: uint8(ca)},
385385
}
386-
386+
387387
ncvs := canvas.CreateNRGBACanvas(dot.Width+10, dot.Height+10, true)
388388
var bounds image.Rectangle
389389
var img image.Image

v2/rotate/draw.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func (d *drawImage) DrawWithCropCircle(params *DrawCropCircleImageParams) (image
5555
bgBounds := bgImage.Bounds()
5656
cvs := canvas.CreateNRGBACanvas(bgImage.Bounds().Dx(), bgImage.Bounds().Dy(), true)
5757
draw.Draw(cvs.Get(), bgImage.Bounds(), bgImage, image.Point{}, draw.Over)
58-
cvs.CropCircle(bgImage.Bounds().Dx()/2, bgImage.Bounds().Dy()/2, bgImage.Bounds().Dy()/2, params.ScaleRatioSize)
59-
cvs.Rotate(params.Rotate)
58+
cvs.CropScaleCircle(bgImage.Bounds().Dx()/2, bgImage.Bounds().Dy()/2, bgImage.Bounds().Dy()/2, params.ScaleRatioSize)
59+
cvs.Rotate(params.Rotate, true)
6060

6161
cvBounds := cvs.Bounds()
6262
if cvBounds.Dy() > bgBounds.Dy() || cvBounds.Dx() > bgBounds.Dx() {
@@ -65,7 +65,7 @@ func (d *drawImage) DrawWithCropCircle(params *DrawCropCircleImageParams) (image
6565
cvs = newCvs
6666
}
6767

68-
return cvs, nil
68+
return cvs.Get(), nil
6969
}
7070

7171
// DrawWithNRGBA is to draw with a NRGBA
@@ -81,6 +81,6 @@ func (d *drawImage) DrawWithNRGBA(params *DrawImageParams) (img image.Image, err
8181
draw.Draw(rcm.Get(), rcm.Bounds(), rc.Get(), image.Point{}, draw.Over)
8282
}
8383

84-
rcm.CropCircle(rcm.Bounds().Dx()/2, rcm.Bounds().Dy()/2, rcm.Bounds().Dy()/2, 0)
85-
return rcm, nil
84+
rcm.CropCircle(rcm.Bounds().Dx()/2, rcm.Bounds().Dy()/2, rcm.Bounds().Dy()/2)
85+
return rcm.Get(), nil
8686
}

0 commit comments

Comments
 (0)