Browse Source

Numbers are now laid out correctly.

Next commits will introduce perturbations.
Dmitry Chestnykh 14 years ago
parent
commit
f1572d4d2c
3 changed files with 51 additions and 33 deletions
  1. 1 1
      captcha.go
  2. 1 1
      cmd/main.go
  3. 49 31
      image.go

+ 1 - 1
captcha.go

@@ -44,7 +44,7 @@ func init() {
 }
 
 func randomNumbers() []byte {
-	n := make([]byte, 3)
+	n := make([]byte, 6)
 	if _, err := io.ReadFull(crand.Reader, n); err != nil {
 		panic(err)
 	}

+ 1 - 1
cmd/main.go

@@ -6,6 +6,6 @@ import (
 )
 
 func main() {
-	img, _ := captcha.NewRandomImage(300, 80)
+	img, _ := captcha.NewRandomImage(230, 60)
 	img.PNGEncode(os.Stdout)
 }

+ 49 - 31
image.go

@@ -16,42 +16,60 @@ type CaptchaImage struct {
 	*image.NRGBA
 	primaryColor image.NRGBAColor
 	numberWidth  int
-	dotRadius    int
+	numberHeight int
+	dotSize    int
+}
+
+func (img *CaptchaImage) calculateSizes(width, height, ncount int) {
+	// Goal: fit all numbers into the image.
+	// Convert everything to floats for calculations.
+	w := float64(width)
+	h := float64(height)
+	// fontWidth includes 1-dot spacing between numbers
+	fw := float64(fontWidth) + 1
+	fh := float64(fontHeight)
+	nc := float64(ncount)
+	// Calculate width of a sigle number if we only take into
+	// account the width
+	nw := w / nc
+	// Calculate the number height from this width
+	nh := nw * fh / fw
+	// Number height too large?
+	if nh > h {
+		// Fit numbers based on height
+		nh = h
+		nw = fw/fh * nh
+	}
+	// Calculate dot size
+	img.dotSize = int(nh / fh)
+	// Save everything, making actual width smaller by 1 dot,
+	// to account for spacing between numbers
+	img.numberWidth = int(nw)
+	img.numberHeight = int(nh) - img.dotSize
 }
 
 func NewImage(numbers []byte, width, height int) *CaptchaImage {
 	img := new(CaptchaImage)
 	img.NRGBA = image.NewNRGBA(width, height)
 	img.primaryColor = image.NRGBAColor{uint8(rand.Intn(50)), uint8(rand.Intn(50)), uint8(rand.Intn(128)), 0xFF}
-	//width -= 30
-	//height -= 30
-	var border int = 0
-	// if width < height {
-	// 	border = width/4
-	// } else {
-	// 	border = height/4
-	// }
-	bwidth := width - border*2
-	bheight := height - border*2
-	//border := 15
-	//fullNumberWidth := int(float64(width/len(numbers)) *
-	//	float64(fontWidth) / float64(fontHeight))
-	var fullNumberWidth int
-	if float64(fontWidth)/float64(fontHeight) > float64(bwidth)/float64(bheight) {
-		fullNumberWidth	= bheight / fontHeight * fontWidth
+	// We need some space, so calculate border
+	var border int
+	if width > height {
+		border = height/5
 	} else {
-		fullNumberWidth = bwidth / len(numbers)
+		border = width/5
 	}
-	// add spacing
-	img.numberWidth = fullNumberWidth - fullNumberWidth/fontWidth
-	// center numbers in image
-	x := border
-	y := border
+	bwidth := width-border*2
+	bheight := height-border*2
+	img.calculateSizes(bwidth, bheight, len(numbers))
+	// Center numbers in image
+	x := width/2 - (img.numberWidth*len(numbers))/2 - img.dotSize
+	y := height/2 - img.numberHeight/2 + img.dotSize/2
 	setRandomBrightness(&img.primaryColor, 180)
 	for _, n := range numbers {
 		//y = rand.Intn(dotSize * 4)
 		img.drawNumber(font[n], x, y)
-		x += fullNumberWidth
+		x += img.numberWidth + img.dotSize
 	}
 	//img.strikeThrough(img.primaryColor)
 	return img
@@ -169,10 +187,10 @@ func (img *CaptchaImage) drawNumber(number []byte, x, y int) {
 	//if skf < 0 {
 	//	x -= skf * numberHeight
 	//}
-	d := img.numberWidth / fontWidth // number height is ignored
-	println(img.numberWidth)
-	srad := d/2             // standard (minumum) radius
-	mrad := d //srad + srad/2 // maximum radius
+	//d := img.numberWidth / fontWidth // number height is ignored
+	//println(img.numberWidth)
+	minr := img.dotSize/2 // minumum radius
+	maxr := img.dotSize // maximum radius
 	// x += srad
 	// y += srad
 	for yy := 0; yy < fontHeight; yy++ {
@@ -181,9 +199,9 @@ func (img *CaptchaImage) drawNumber(number []byte, x, y int) {
 				continue
 			}
 			// introduce random variations
-			or := srad            //rnd(srad, mrad)
-			ox := x + (xx * mrad) //+ rnd(0, or/2)
-			oy := y + (yy * mrad) //+ rnd(0, or/2)
+			or := rnd(minr, maxr)
+			ox := x + (xx * maxr) //+ rnd(0, or/2)
+			oy := y + (yy * maxr) //+ rnd(0, or/2)
 			img.drawCircle(img.primaryColor, ox, oy, or)
 		}
 		//x += skf