-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathnoise.go
135 lines (113 loc) · 2.77 KB
/
noise.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
package gocaptcha
import (
"image"
"image/draw"
"math/rand"
"time"
"github.com/golang/freetype"
"golang.org/x/image/font"
)
// NoiseDensity is the complexity of captcha
type NoiseDensity int
const (
NoiseDensityLower NoiseDensity = iota
NoiseDensityMedium
NoiseDensityHigh
)
// NoiseDrawer is a type that can make noise on an image
type NoiseDrawer interface {
// DrawNoise draws noise on the image
DrawNoise(img draw.Image, density NoiseDensity) error
}
type pointNoiseDrawer struct {
r *rand.Rand
}
// DrawNoise draws noise on the image
func (n pointNoiseDrawer) DrawNoise(img draw.Image, density NoiseDensity) error {
var densityNum int
switch density {
case NoiseDensityLower:
densityNum = 28
case NoiseDensityMedium:
densityNum = 18
case NoiseDensityHigh:
densityNum = 8
default:
densityNum = 18
}
maxSize := (img.Bounds().Dy() * img.Bounds().Dx()) / densityNum
bounds := img.Bounds()
width := bounds.Dx()
height := bounds.Dy()
for i := 0; i < maxSize; i++ {
rw := n.r.Intn(width)
rh := n.r.Intn(height)
img.Set(rw, rh, RandColor())
// 优化噪声点的生成逻辑,例如可以基于一定的概率决定是否绘制额外的点
if n.r.Intn(3) == 0 && rw+1 < width && rh+1 < height {
img.Set(rw+1, rh+1, RandColor())
}
}
return nil
}
// NewPointNoiseDrawer returns a NoiseDrawer that draws noise points
func NewPointNoiseDrawer() NoiseDrawer {
return &pointNoiseDrawer{
r: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
// textNoiseDrawer draws noise text
type textNoiseDrawer struct {
r *rand.Rand
dpi float64
}
// DrawNoise draws noise on the image
func (n textNoiseDrawer) DrawNoise(img draw.Image, density NoiseDensity) error {
var densityNum int
switch density {
case NoiseDensityLower:
densityNum = 2000
case NoiseDensityMedium:
densityNum = 1500
case NoiseDensityHigh:
densityNum = 1000
default:
densityNum = 1500 // 默认值
}
bounds := img.Bounds()
maxSize := (bounds.Dy() * bounds.Dx()) / densityNum
c := freetype.NewContext()
if n.dpi <= 0 {
n.dpi = 72
}
c.SetDPI(n.dpi)
c.SetClip(bounds)
c.SetDst(img)
c.SetHinting(font.HintingFull)
rawFontSize := float64(bounds.Dy()) / (1 + float64(n.r.Intn(7))/float64(10))
for i := 0; i < maxSize; i++ {
rw := n.r.Intn(bounds.Dx())
rh := n.r.Intn(bounds.Dy())
text := RandText(1)
fontSize := rawFontSize/2 + float64(n.r.Intn(5))
c.SetSrc(image.NewUniform(RandLightColor()))
c.SetFontSize(fontSize)
f, err := DefaultFontFamily.Random()
if err != nil {
return err
}
c.SetFont(f)
pt := freetype.Pt(rw, rh)
_, err = c.DrawString(text, pt)
if err != nil {
return err
}
}
return nil
}
func NewTextNoiseDrawer(dpi float64) NoiseDrawer {
return &textNoiseDrawer{
r: rand.New(rand.NewSource(time.Now().UnixNano())),
dpi: dpi,
}
}