all repos — captcha @ d88ce81917aa0fc9629bb41df9646ff90edd2250

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

image.go (view raw)

  1package captcha
  2
  3import (
  4	"image"
  5	"image/png"
  6	"io"
  7	"os"
  8	"rand"
  9)
 10
 11const (
 12	maxSkew = 3
 13)
 14
 15type CaptchaImage struct {
 16	*image.NRGBA
 17	primaryColor image.NRGBAColor
 18	numberWidth  int
 19	dotRadius    int
 20}
 21
 22func NewImage(numbers []byte, width, height int) *CaptchaImage {
 23	img := new(CaptchaImage)
 24	img.NRGBA = image.NewNRGBA(width, height)
 25	img.primaryColor = image.NRGBAColor{uint8(rand.Intn(50)), uint8(rand.Intn(50)), uint8(rand.Intn(128)), 0xFF}
 26	//width -= 30
 27	//height -= 30
 28	var border int = 0
 29	// if width < height {
 30	// 	border = width/4
 31	// } else {
 32	// 	border = height/4
 33	// }
 34	bwidth := width - border*2
 35	bheight := height - border*2
 36	//border := 15
 37	//fullNumberWidth := int(float64(width/len(numbers)) *
 38	//	float64(fontWidth) / float64(fontHeight))
 39	var fullNumberWidth int
 40	if float64(fontWidth)/float64(fontHeight) > float64(bwidth)/float64(bheight) {
 41		fullNumberWidth	= bheight / fontHeight * fontWidth
 42	} else {
 43		fullNumberWidth = bwidth / len(numbers)
 44	}
 45	// add spacing
 46	img.numberWidth = fullNumberWidth - fullNumberWidth/fontWidth
 47	// center numbers in image
 48	x := border
 49	y := border
 50	setRandomBrightness(&img.primaryColor, 180)
 51	for _, n := range numbers {
 52		//y = rand.Intn(dotSize * 4)
 53		img.drawNumber(font[n], x, y)
 54		x += fullNumberWidth
 55	}
 56	//img.strikeThrough(img.primaryColor)
 57	return img
 58}
 59
 60func NewRandomImage(width, height int) (img *CaptchaImage, numbers []byte) {
 61	numbers = randomNumbers()
 62	img = NewImage(numbers, width, height)
 63	return
 64}
 65
 66func (img *CaptchaImage) PNGEncode(w io.Writer) os.Error {
 67	return png.Encode(w, img)
 68}
 69
 70func (img *CaptchaImage) drawHorizLine(color image.Color, fromX, toX, y int) {
 71	for x := fromX; x <= toX; x++ {
 72		img.Set(x, y, color)
 73	}
 74}
 75
 76func (img *CaptchaImage) drawCircle(color image.Color, x, y, radius int) {
 77	f := 1 - radius
 78	dfx := 1
 79	dfy := -2 * radius
 80	xx := 0
 81	yy := radius
 82
 83	img.Set(x, y+radius, color)
 84	img.Set(x, y-radius, color)
 85	img.drawHorizLine(color, x-radius, x+radius, y)
 86
 87	for xx < yy {
 88		if f >= 0 {
 89			yy--
 90			dfy += 2
 91			f += dfy
 92		}
 93		xx++
 94		dfx += 2
 95		f += dfx
 96		img.drawHorizLine(color, x-xx, x+xx, y+yy)
 97		img.drawHorizLine(color, x-xx, x+xx, y-yy)
 98		img.drawHorizLine(color, x-yy, x+yy, y+xx)
 99		img.drawHorizLine(color, x-yy, x+yy, y-xx)
100	}
101}
102
103
104func min3(x, y, z uint8) (o uint8) {
105	o = x
106	if y < o {
107		o = y
108	}
109	if z < o {
110		o = z
111	}
112	return
113}
114
115func max3(x, y, z uint8) (o uint8) {
116	o = x
117	if y > o {
118		o = y
119	}
120	if z > o {
121		o = z
122	}
123	return
124}
125
126func setRandomBrightness(c *image.NRGBAColor, max uint8) {
127	minc := min3(c.R, c.G, c.B)
128	maxc := max3(c.R, c.G, c.B)
129	if maxc > max {
130		return
131	}
132	n := rand.Intn(int(max-maxc)) - int(minc)
133	c.R = uint8(int(c.R) + n)
134	c.G = uint8(int(c.G) + n)
135	c.B = uint8(int(c.B) + n)
136}
137
138func rnd(from, to int) int {
139	return rand.Intn(to+1-from) + from
140}
141
142func (img *CaptchaImage) fillWithCircles(color image.NRGBAColor, n, maxradius int) {
143	maxx := img.Bounds().Max.X
144	maxy := img.Bounds().Max.Y
145	for i := 0; i < n; i++ {
146		setRandomBrightness(&color, 255)
147		r := rnd(1, maxradius)
148		img.drawCircle(color, rnd(r, maxx), rnd(r, maxy), r)
149	}
150}
151
152// func (img *CaptchaImage) strikeThrough(color image.Color) {
153// 	r := 0
154// 	maxx := img.Bounds().Max.X
155// 	maxy := img.Bounds().Max.Y
156// 	y := rnd(maxy/3, maxy-maxy/3)
157// 	for x := 0; x < maxx; x += r {
158// 		r = rnd(1, dotSize/2-1)
159// 		y += rnd(-2, 2)
160// 		if y <= 0 || y >= maxy {
161// 			y = rnd(maxy/3, maxy-maxy/3)
162// 		}
163// 		img.drawCircle(color, x, y, r)
164// 	}
165// }
166
167func (img *CaptchaImage) drawNumber(number []byte, x, y int) {
168	//skf := rand.Intn(maxSkew) - maxSkew/2
169	//if skf < 0 {
170	//	x -= skf * numberHeight
171	//}
172	d := img.numberWidth / fontWidth // number height is ignored
173	println(img.numberWidth)
174	srad := d/2             // standard (minumum) radius
175	mrad := d //srad + srad/2 // maximum radius
176	// x += srad
177	// y += srad
178	for yy := 0; yy < fontHeight; yy++ {
179		for xx := 0; xx < fontWidth; xx++ {
180			if number[yy*fontWidth+xx] != 1 {
181				continue
182			}
183			// introduce random variations
184			or := srad            //rnd(srad, mrad)
185			ox := x + (xx * mrad) //+ rnd(0, or/2)
186			oy := y + (yy * mrad) //+ rnd(0, or/2)
187			img.drawCircle(img.primaryColor, ox, oy, or)
188		}
189		//x += skf
190	}
191}