all repos — captcha @ 69b50fb6730cbea5fb4d367f1817415a215e7a9a

Go package captcha implements generation and verification of image and audio CAPTCHAs.

captcha.go (view raw)

  1package main
  2
  3import (
  4	"image"
  5	"image/png"
  6	"os"
  7	"rand"
  8	"time"
  9	crand "crypto/rand"
 10	"io"
 11)
 12
 13var numbers = [][]byte{
 14	{
 15		0, 1, 1, 1, 0,
 16		1, 0, 0, 0, 1,
 17		1, 0, 0, 0, 1,
 18		1, 0, 0, 0, 1,
 19		1, 0, 0, 0, 1,
 20		1, 0, 0, 0, 1,
 21		1, 0, 0, 0, 1,
 22		0, 1, 1, 1, 0,
 23	},
 24	{
 25		0, 0, 1, 0, 0,
 26		0, 1, 1, 0, 0,
 27		1, 0, 1, 0, 0,
 28		0, 0, 1, 0, 0,
 29		0, 0, 1, 0, 0,
 30		0, 0, 1, 0, 0,
 31		0, 0, 1, 0, 0,
 32		1, 1, 1, 1, 1,
 33	},
 34	{
 35		0, 1, 1, 1, 0,
 36		1, 0, 0, 0, 1,
 37		0, 0, 0, 0, 1,
 38		0, 0, 0, 1, 1,
 39		0, 1, 1, 0, 0,
 40		1, 0, 0, 0, 0,
 41		1, 0, 0, 0, 0,
 42		1, 1, 1, 1, 1,
 43	},
 44	{
 45		1, 1, 1, 1, 1,
 46		0, 0, 0, 0, 1,
 47		0, 0, 0, 1, 1,
 48		0, 1, 1, 0, 0,
 49		0, 0, 0, 1, 0,
 50		0, 0, 0, 0, 1,
 51		0, 0, 0, 0, 1,
 52		1, 1, 1, 1, 0,
 53	},
 54	{
 55		1, 0, 0, 1, 0,
 56		1, 0, 0, 1, 0,
 57		1, 0, 0, 1, 0,
 58		1, 0, 0, 1, 0,
 59		1, 1, 1, 1, 1,
 60		0, 0, 0, 1, 0,
 61		0, 0, 0, 1, 0,
 62		0, 0, 0, 1, 0,
 63	},
 64	{
 65		1, 1, 1, 1, 1,
 66		1, 0, 0, 0, 0,
 67		1, 0, 0, 0, 0,
 68		1, 1, 1, 1, 0,
 69		0, 0, 0, 1, 1,
 70		0, 0, 0, 0, 1,
 71		0, 0, 0, 1, 1,
 72		1, 1, 1, 1, 0,
 73	},
 74	{
 75		0, 0, 1, 1, 1,
 76		0, 1, 0, 0, 0,
 77		1, 0, 0, 0, 0,
 78		1, 1, 1, 1, 0,
 79		1, 1, 0, 0, 1,
 80		1, 0, 0, 0, 1,
 81		1, 1, 0, 0, 1,
 82		0, 1, 1, 1, 0,
 83	},
 84	{
 85		1, 1, 1, 1, 1,
 86		0, 0, 0, 0, 1,
 87		0, 0, 0, 0, 1,
 88		0, 0, 0, 1, 0,
 89		0, 0, 1, 0, 0,
 90		0, 1, 0, 0, 0,
 91		0, 1, 0, 0, 0,
 92		0, 1, 0, 0, 0,
 93	},
 94	{
 95		0, 1, 1, 1, 0,
 96		1, 0, 0, 0, 1,
 97		1, 1, 0, 1, 1,
 98		0, 1, 1, 1, 0,
 99		1, 1, 0, 1, 1,
100		1, 0, 0, 0, 1,
101		1, 1, 0, 1, 1,
102		0, 1, 1, 1, 0,
103	},
104	{
105		0, 1, 1, 1, 0,
106		1, 0, 0, 1, 1,
107		1, 0, 0, 0, 1,
108		1, 1, 0, 0, 1,
109		0, 1, 1, 1, 1,
110		0, 0, 0, 0, 1,
111		0, 0, 0, 0, 1,
112		1, 1, 1, 1, 0,
113	},
114}
115
116const (
117	NumberWidth  = 5
118	NumberHeight = 8
119	DotSize = 6
120	SkewFactor = 3
121)
122
123func drawHorizLine(img *image.NRGBA, color image.Color, fromX, toX, y int) {
124	for x := fromX; x <= toX; x++ {
125		img.Set(x, y, color)
126	}
127}
128
129func drawCircle(img *image.NRGBA, color image.Color, x0, y0, radius int) {
130	f := 1 - radius
131	ddF_x := 1
132	ddF_y := -2 * radius
133	x := 0
134	y := radius
135
136	img.Set(x0, y0+radius, color)
137	img.Set(x0, y0-radius, color)
138	//img.Set(x0+radius, y0, color)
139	//img.Set(x0-radius, y0, color)
140	drawHorizLine(img, color, x0-radius, x0+radius, y0)
141
142	for x < y {
143		// ddF_x == 2 * x + 1;
144		// ddF_y == -2 * y;
145		// f == x*x + y*y - radius*radius + 2*x - y + 1;
146		if f >= 0 {
147			y--
148			ddF_y += 2
149			f += ddF_y
150		}
151		x++
152		ddF_x += 2
153		f += ddF_x
154		//img.Set(x0+x, y0+y, color)
155		//img.Set(x0-x, y0+y, color)
156		drawHorizLine(img, color, x0-x, x0+x, y0+y)
157		//img.Set(x0+x, y0-y, color)
158		//img.Set(x0-x, y0-y, color)
159		drawHorizLine(img, color, x0-x, x0+x, y0-y)
160		//img.Set(x0+y, y0+x, color)
161		//img.Set(x0-y, y0+x, color)
162		drawHorizLine(img, color, x0-y, x0+y, y0+x)
163		//img.Set(x0+y, y0-x, color)
164		//img.Set(x0-y, y0-x, color)
165		drawHorizLine(img, color, x0-y, x0+y, y0-x)
166	}
167}
168
169func min3(x, y, z uint8) (o uint8) {
170	o = x
171	if y < o {
172		o = y
173	}
174	if z < o {
175		o = z
176	}
177	return
178}
179
180func max3(x, y, z uint8) (o uint8) {
181	o = x
182	if y > o {
183		o = y
184	}
185	if z > o {
186		o = z
187	}
188	return
189}
190
191func setRandomBrightness(c *image.NRGBAColor, max uint8) {
192	minc := min3(c.R, c.G, c.B)
193	maxc := max3(c.R, c.G, c.B)
194	if maxc > max {
195		return
196	}
197	n := rand.Intn(int(max-maxc)) - int(minc)
198	c.R = uint8(int(c.R) + n)
199	c.G = uint8(int(c.G) + n)
200	c.B = uint8(int(c.B) + n)
201}
202
203func fillWithCircles(img *image.NRGBA, n, maxradius int) {
204	maxx := img.Bounds().Max.X
205	maxy := img.Bounds().Max.Y
206	color := image.NRGBAColor{0, 0, 0x80, 0xFF}
207	for i := 0; i < n; i++ {
208		setRandomBrightness(&color, 255)
209		r := rand.Intn(maxradius-1)+1 
210		drawCircle(img, color, rand.Intn(maxx-r*2)+r, rand.Intn(maxy-r*2)+r, r)
211	}
212}
213
214func drawNumber(img *image.NRGBA, number []byte, x, y int, color image.NRGBAColor) {
215	skf := rand.Intn(SkewFactor)-SkewFactor/2
216	if skf < 0 {
217		x -= skf * NumberHeight
218	}
219	for y0 := 0; y0 < NumberHeight; y0++ {
220		for x0 := 0; x0 < NumberWidth; x0++ {
221			radius := rand.Intn(DotSize/2)+DotSize/2
222			addx := rand.Intn(radius/2)
223			addy := rand.Intn(radius/2)
224			if number[y0*NumberWidth+x0] == 1 {
225				drawCircle(img, color, x+x0*DotSize+DotSize+addx, y+y0*DotSize+DotSize+addy, radius)
226			}
227		}
228		x += skf
229	}
230}
231
232func drawNumbersToImage(ns []byte) {
233	img := image.NewNRGBA(NumberWidth*(DotSize+2)*len(ns)+DotSize, NumberHeight*DotSize+(DotSize*6))
234	for y := 0; y < img.Bounds().Max.Y; y++ {
235		for x := 0; x < img.Bounds().Max.X; x++ {
236			img.Set(x, y, image.NRGBAColor{0xFF, 0xFF, 0xFF, 0xFF})
237		}
238	}
239	fillWithCircles(img, 60, 3)
240	x := rand.Intn(DotSize)
241	y := 0
242	color := image.NRGBAColor{0, 0, 0x80, 0xFF}
243	setRandomBrightness(&color, 180)
244	for _, n := range ns {
245		y = rand.Intn(DotSize*4)
246		drawNumber(img, numbers[n], x, y, color)
247		x += DotSize * NumberWidth + rand.Intn(SkewFactor)+3 
248	}
249	f, err := os.Create("captcha.png")
250	if err != nil {
251		panic(err)
252	}
253	defer f.Close()
254	png.Encode(f, img)
255}
256
257func main() {
258	rand.Seed(time.Seconds())
259	n := make([]byte, 6)
260	if _, err := io.ReadFull(crand.Reader, n); err != nil {
261		panic(err)
262	}
263	for i := range n {
264		n[i] %= 10
265	}
266	drawNumbersToImage(n)
267}
268