Go 语言做的几个验证码

时间:2023-03-10 04:18:23
Go 语言做的几个验证码

1、http://www.oschina.net/code/snippet_173630_12006

效果:

Go 语言做的几个验证码Go 语言做的几个验证码

Go 语言做的几个验证码Go 语言做的几个验证码Go 语言做的几个验证码

源代码:

   1: package main

   2:  

   3: import (

   4:     crand "crypto/rand"

   5:     "fmt"

   6:     "image"

   7:     "image/color"

   8:     "image/png"

   9:     "io"

  10:     "math/rand"

  11:     "net/http"

  12:     "strconv"

  13:     "time"

  14: )

  15:  

  16: const (

  17:     stdWidth  = 100

  18:     stdHeight = 40

  19:     maxSkew   = 2

  20: )

  21:  

  22: const (

  23:     fontWidth  = 5

  24:     fontHeight = 8

  25:     blackChar  = 1

  26: )

  27:  

  28: var font = [][]byte{

  29:     { // 0

  30:         0, 1, 1, 1, 0,

  31:         1, 0, 0, 0, 1,

  32:         1, 0, 0, 0, 1,

  33:         1, 0, 0, 0, 1,

  34:         1, 0, 0, 0, 1,

  35:         1, 0, 0, 0, 1,

  36:         1, 0, 0, 0, 1,

  37:         0, 1, 1, 1, 0},

  38:     { // 1

  39:         0, 0, 1, 0, 0,

  40:         0, 1, 1, 0, 0,

  41:         1, 0, 1, 0, 0,

  42:         0, 0, 1, 0, 0,

  43:         0, 0, 1, 0, 0,

  44:         0, 0, 1, 0, 0,

  45:         0, 0, 1, 0, 0,

  46:         1, 1, 1, 1, 1},

  47:     { // 2

  48:         0, 1, 1, 1, 0,

  49:         1, 0, 0, 0, 1,

  50:         0, 0, 0, 0, 1,

  51:         0, 0, 0, 1, 1,

  52:         0, 1, 1, 0, 0,

  53:         1, 0, 0, 0, 0,

  54:         1, 0, 0, 0, 0,

  55:         1, 1, 1, 1, 1},

  56:     { // 3

  57:         1, 1, 1, 1, 0,

  58:         0, 0, 0, 0, 1,

  59:         0, 0, 0, 1, 0,

  60:         0, 1, 1, 1, 0,

  61:         0, 0, 0, 1, 0,

  62:         0, 0, 0, 0, 1,

  63:         0, 0, 0, 0, 1,

  64:         1, 1, 1, 1, 0},

  65:     { // 4

  66:         1, 0, 0, 1, 0,

  67:         1, 0, 0, 1, 0,

  68:         1, 0, 0, 1, 0,

  69:         1, 0, 0, 1, 0,

  70:         1, 1, 1, 1, 1,

  71:         0, 0, 0, 1, 0,

  72:         0, 0, 0, 1, 0,

  73:         0, 0, 0, 1, 0},

  74:     { // 5

  75:         1, 1, 1, 1, 1,

  76:         1, 0, 0, 0, 0,

  77:         1, 0, 0, 0, 0,

  78:         1, 1, 1, 1, 0,

  79:         0, 0, 0, 0, 1,

  80:         0, 0, 0, 0, 1,

  81:         0, 0, 0, 0, 1,

  82:         1, 1, 1, 1, 0},

  83:     { // 6

  84:         0, 0, 1, 1, 1,

  85:         0, 1, 0, 0, 0,

  86:         1, 0, 0, 0, 0,

  87:         1, 1, 1, 1, 0,

  88:         1, 0, 0, 0, 1,

  89:         1, 0, 0, 0, 1,

  90:         1, 0, 0, 0, 1,

  91:         0, 1, 1, 1, 0},

  92:     { // 7

  93:         1, 1, 1, 1, 1,

  94:         0, 0, 0, 0, 1,

  95:         0, 0, 0, 0, 1,

  96:         0, 0, 0, 1, 0,

  97:         0, 0, 1, 0, 0,

  98:         0, 1, 0, 0, 0,

  99:         0, 1, 0, 0, 0,

 100:         0, 1, 0, 0, 0},

 101:     { // 8

 102:         0, 1, 1, 1, 0,

 103:         1, 0, 0, 0, 1,

 104:         1, 0, 0, 0, 1,

 105:         0, 1, 1, 1, 0,

 106:         1, 0, 0, 0, 1,

 107:         1, 0, 0, 0, 1,

 108:         1, 0, 0, 0, 1,

 109:         0, 1, 1, 1, 0},

 110:     { // 9

 111:         0, 1, 1, 1, 0,

 112:         1, 0, 0, 0, 1,

 113:         1, 0, 0, 0, 1,

 114:         1, 1, 0, 0, 1,

 115:         0, 1, 1, 1, 1,

 116:         0, 0, 0, 0, 1,

 117:         0, 0, 0, 0, 1,

 118:         1, 1, 1, 1, 0},

 119: }

 120:  

 121: type Image struct {

 122:     *image.NRGBA

 123:     color   *color.NRGBA

 124:     width   int //a digit width

 125:     height  int //a digit height

 126:     dotsize int

 127: }

 128:  

 129: func init() {

 130:     rand.Seed(int64(time.Second))

 131:  

 132: }

 133:  

 134: func NewImage(digits []byte, width, height int) *Image {

 135:     img := new(Image)

 136:     r := image.Rect(img.width, img.height, stdWidth, stdHeight)

 137:     img.NRGBA = image.NewNRGBA(r)

 138:     img.color = &color.NRGBA{

 139:         uint8(rand.Intn(129)),

 140:         uint8(rand.Intn(129)),

 141:         uint8(rand.Intn(129)),

 142:         0xFF}

 143:     // Draw background (10 random circles of random brightness)

 144:     img.calculateSizes(width, height, len(digits))

 145:     img.fillWithCircles(10, img.dotsize)

 146:     maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize

 147:     maxy := height - img.height - img.dotsize*2

 148:     x := rnd(img.dotsize*2, maxx)

 149:     y := rnd(img.dotsize*2, maxy)

 150:     // Draw digits.

 151:     for _, n := range digits {

 152:         img.drawDigit(font[n], x, y)

 153:         x += img.width + img.dotsize

 154:     }

 155:     // Draw strike-through line.

 156:     img.strikeThrough()

 157:     return img

 158:  

 159: }

 160:  

 161: func (img *Image) WriteTo(w io.Writer) (int64, error) {

 162:     return 0, png.Encode(w, img)

 163:  

 164: }

 165:  

 166: func (img *Image) calculateSizes(width, height, ncount int) {

 167:     // Goal: fit all digits inside the image.

 168:     var border int

 169:     if width > height {

 170:         border = height / 5

 171:     } else {

 172:         border = width / 5

 173:     }

 174:     // Convert everything to floats for calculations.

 175:     w := float64(width - border*2)  //268

 176:     h := float64(height - border*2) //48

 177:     // fw takes into account 1-dot spacing between digits.

 178:     fw := float64(fontWidth) + 1 //6

 179:     fh := float64(fontHeight)    //8

 180:     nc := float64(ncount)        //7

 181:     // Calculate the width of a single digit taking into account only the

 182:     // width of the image.

 183:     nw := w / nc //38

 184:     // Calculate the height of a digit from this width.

 185:     nh := nw * fh / fw //51

 186:     // Digit too high?

 187:     if nh > h {

 188:         // Fit digits based on height.

 189:         nh = h //nh = 44

 190:         nw = fw / fh * nh

 191:     }

 192:     // Calculate dot size.

 193:     img.dotsize = int(nh / fh)

 194:     // Save everything, making the actual width smaller by 1 dot to account

 195:     // for spacing between digits.

 196:     img.width = int(nw)

 197:     img.height = int(nh) - img.dotsize

 198:  

 199: }

 200:  

 201: func (img *Image) fillWithCircles(n, maxradius int) {

 202:     color := img.color

 203:     maxx := img.Bounds().Max.X

 204:     maxy := img.Bounds().Max.Y

 205:     for i := 0; i < n; i++ {

 206:         setRandomBrightness(color, 255)

 207:         r := rnd(1, maxradius)

 208:         img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)

 209:     }

 210:  

 211: }

 212:  

 213: func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {

 214:     for x := fromX; x <= toX; x++ {

 215:         img.Set(x, y, color)

 216:     }

 217:  

 218: }

 219:  

 220: func (img *Image) drawCircle(color color.Color, x, y, radius int) {

 221:     f := 1 - radius

 222:     dfx := 1

 223:     dfy := -2 * radius

 224:     xx := 0

 225:     yy := radius

 226:     img.Set(x, y+radius, color)

 227:     img.Set(x, y-radius, color)

 228:     img.drawHorizLine(color, x-radius, x+radius, y)

 229:     for xx < yy {

 230:         if f >= 0 {

 231:             yy--

 232:             dfy += 2

 233:             f += dfy

 234:         }

 235:         xx++

 236:         dfx += 2

 237:         f += dfx

 238:         img.drawHorizLine(color, x-xx, x+xx, y+yy)

 239:         img.drawHorizLine(color, x-xx, x+xx, y-yy)

 240:         img.drawHorizLine(color, x-yy, x+yy, y+xx)

 241:         img.drawHorizLine(color, x-yy, x+yy, y-xx)

 242:     }

 243:  

 244: }

 245:  

 246: func (img *Image) strikeThrough() {

 247:     r := 0

 248:     maxx := img.Bounds().Max.X

 249:     maxy := img.Bounds().Max.Y

 250:     y := rnd(maxy/3, maxy-maxy/3)

 251:     for x := 0; x < maxx; x += r {

 252:         r = rnd(1, img.dotsize/3)

 253:         y += rnd(-img.dotsize/2, img.dotsize/2)

 254:         if y <= 0 || y >= maxy {

 255:             y = rnd(maxy/3, maxy-maxy/3)

 256:         }

 257:         img.drawCircle(img.color, x, y, r)

 258:     }

 259:  

 260: }

 261:  

 262: func (img *Image) drawDigit(digit []byte, x, y int) {

 263:     skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))

 264:     xs := float64(x)

 265:     minr := img.dotsize / 2               // minumum radius

 266:     maxr := img.dotsize/2 + img.dotsize/4 // maximum radius

 267:     y += rnd(-minr, minr)

 268:     for yy := 0; yy < fontHeight; yy++ {

 269:         for xx := 0; xx < fontWidth; xx++ {

 270:             if digit[yy*fontWidth+xx] != blackChar {

 271:                 continue

 272:             }

 273:             // Introduce random variations.

 274:             or := rnd(minr, maxr)

 275:             ox := x + (xx * img.dotsize) + rnd(0, or/2)

 276:             oy := y + (yy * img.dotsize) + rnd(0, or/2)

 277:             img.drawCircle(img.color, ox, oy, or)

 278:         }

 279:         xs += skf

 280:         x = int(xs)

 281:     }

 282:  

 283: }

 284:  

 285: func setRandomBrightness(c *color.NRGBA, max uint8) {

 286:     minc := min3(c.R, c.G, c.B)

 287:     maxc := max3(c.R, c.G, c.B)

 288:     if maxc > max {

 289:         return

 290:     }

 291:     n := rand.Intn(int(max-maxc)) - int(minc)

 292:     c.R = uint8(int(c.R) + n)

 293:     c.G = uint8(int(c.G) + n)

 294:     c.B = uint8(int(c.B) + n)

 295:  

 296: }

 297:  

 298: func min3(x, y, z uint8) (o uint8) {

 299:     o = x

 300:     if y < o {

 301:         o = y

 302:     }

 303:     if z < o {

 304:         o = z

 305:     }

 306:     return

 307:  

 308: }

 309:  

 310: func max3(x, y, z uint8) (o uint8) {

 311:     o = x

 312:     if y > o {

 313:         o = y

 314:     }

 315:     if z > o {

 316:         o = z

 317:     }

 318:     return

 319:  

 320: }

 321:  

 322: // rnd returns a random number in range [from, to].

 323:  

 324: func rnd(from, to int) int {

 325:     //println(to+1-from)

 326:     return rand.Intn(to+1-from) + from

 327:  

 328: }

 329:  

 330: const (

 331:     // Standard length of uniuri string to achive ~95 bits of entropy.

 332:     StdLen = 16

 333:     // Length of uniurl string to achive ~119 bits of entropy, closest

 334:     // to what can be losslessly converted to UUIDv4 (122 bits).

 335:     UUIDLen = 20

 336: )

 337:  

 338: // Standard characters allowed in uniuri string.

 339:  

 340: var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")

 341:  

 342: // New returns a new random string of the standard length, consisting of

 343: // standard characters.

 344:  

 345: func New() string {

 346:     return NewLenChars(StdLen, StdChars)

 347:  

 348: }

 349:  

 350: // NewLen returns a new random string of the provided length, consisting of

 351: // standard characters.

 352:  

 353: func NewLen(length int) string {

 354:     return NewLenChars(length, StdChars)

 355:  

 356: }

 357:  

 358: // NewLenChars returns a new random string of the provided length, consisting

 359: // of the provided byte slice of allowed characters (maximum 256).

 360:  

 361: func NewLenChars(length int, chars []byte) string {

 362:     b := make([]byte, length)

 363:     r := make([]byte, length+(length/4)) // storage for random bytes.

 364:     clen := byte(len(chars))

 365:     maxrb := byte(256 - (256 % len(chars)))

 366:     i := 0

 367:     for {

 368:         if _, err := io.ReadFull(crand.Reader, r); err != nil {

 369:             panic("error reading from random source: " + err.Error())

 370:         }

 371:         for _, c := range r {

 372:             if c >= maxrb {

 373:                 // Skip this number to avoid modulo bias.

 374:                 continue

 375:             }

 376:             b[i] = chars[c%clen]

 377:             i++

 378:             if i == length {

 379:                 return string(b)

 380:             }

 381:         }

 382:     }

 383:     panic("unreachable")

 384:  

 385: }

 386:  

 387: func pic(w http.ResponseWriter, req *http.Request) {

 388:     d := make([]byte, 4)

 389:     s := NewLen(4)

 390:     ss := ""

 391:     d = []byte(s)

 392:     for v := range d {

 393:         d[v] %= 10

 394:         ss += strconv.FormatInt(int64(d[v]), 32)

 395:     }

 396:     w.Header().Set("Content-Type", "image/png")

 397:     NewImage(d, 100, 40).WriteTo(w)

 398:     fmt.Println(ss)

 399:  

 400: }

 401:  

 402: func index(w http.ResponseWriter, req *http.Request) {

 403:     str := "<meta charset=\"utf-8\"><h3>golang 图片验证码例子</h3><img border=\"1\" src=\"/pic\" alt=\"图片验证码\" onclick=\"this.src='/pic'\" />"

 404:     w.Header().Set("Content-Type", "text/html")

 405:     w.Write([]byte(str))

 406:  

 407: }

 408:  

 409: func main() {

 410:     http.HandleFunc("/pic", pic)

 411:     http.HandleFunc("/", index)

 412:     s := &http.Server{

 413:         Addr:           ":8080",

 414:         ReadTimeout:    30 * time.Second,

 415:         WriteTimeout:   30 * time.Second,

 416:         MaxHeaderBytes: 1 << 20}

 417:     s.ListenAndServe()

 418:  

 419: }

 

2、https://github.com/dchest/captcha 

它比较强大,可以生成图片的验证码或者音频验证码。

Go 语言做的几个验证码Go 语言做的几个验证码

Go 语言做的几个验证码Go 语言做的几个验证码Go 语言做的几个验证码