Go 语言做的几个验证码

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

效果:

image image

image image image

源代码:

  

 

 

 

 

 

 

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

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

image image

 

[mw_shl_code=erlang,true]package main
import (
        "image"
        "image/color"
        "image/png"
        "io"
        "net/http"
        "math/rand"
        crand "crypto/rand"
        "time"
        "fmt"
        "strconv"
)
const (
        stdWidth = 100
        stdHeight = 40
        maxSkew = 2
)

const (
        fontWidth  = 5
        fontHeight = 8
        blackChar  = 1
)

var font = [][]byte{
        { // 0
                0, 1, 1, 1, 0,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                0, 1, 1, 1, 0,
        },
        { // 1
                0, 0, 1, 0, 0,
                0, 1, 1, 0, 0,
                1, 0, 1, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 1, 0, 0,
                1, 1, 1, 1, 1,
        },
        { // 2
                0, 1, 1, 1, 0,
                1, 0, 0, 0, 1,
                0, 0, 0, 0, 1,
                0, 0, 0, 1, 1,
                0, 1, 1, 0, 0,
                1, 0, 0, 0, 0,
                1, 0, 0, 0, 0,
                1, 1, 1, 1, 1,
        },
        { // 3
                1, 1, 1, 1, 0,
                0, 0, 0, 0, 1,
                0, 0, 0, 1, 0,
                0, 1, 1, 1, 0,
                0, 0, 0, 1, 0,
                0, 0, 0, 0, 1,
                0, 0, 0, 0, 1,
                1, 1, 1, 1, 0,
        },
        { // 4
                1, 0, 0, 1, 0,
                1, 0, 0, 1, 0,
                1, 0, 0, 1, 0,
                1, 0, 0, 1, 0,
                1, 1, 1, 1, 1,
                0, 0, 0, 1, 0,
                0, 0, 0, 1, 0,
                0, 0, 0, 1, 0,
        },
        { // 5
                1, 1, 1, 1, 1,
                1, 0, 0, 0, 0,
                1, 0, 0, 0, 0,
                1, 1, 1, 1, 0,
                0, 0, 0, 0, 1,
                0, 0, 0, 0, 1,
                0, 0, 0, 0, 1,
                1, 1, 1, 1, 0,
        },
        { // 6
                0, 0, 1, 1, 1,
                0, 1, 0, 0, 0,
                1, 0, 0, 0, 0,
                1, 1, 1, 1, 0,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                0, 1, 1, 1, 0,
        },
        { // 7
                1, 1, 1, 1, 1,
                0, 0, 0, 0, 1,
                0, 0, 0, 0, 1,
                0, 0, 0, 1, 0,
                0, 0, 1, 0, 0,
                0, 1, 0, 0, 0,
                0, 1, 0, 0, 0,
                0, 1, 0, 0, 0,
        },
        { // 8
                0, 1, 1, 1, 0,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                0, 1, 1, 1, 0,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                0, 1, 1, 1, 0,
        },
        { // 9
                0, 1, 1, 1, 0,
                1, 0, 0, 0, 1,
                1, 0, 0, 0, 1,
                1, 1, 0, 0, 1,
                0, 1, 1, 1, 1,
                0, 0, 0, 0, 1,
                0, 0, 0, 0, 1,
                1, 1, 1, 1, 0,
        },
}

type Image struct {
        *image.NRGBA
        color         *color.NRGBA
        width         int  //a digit width
        height         int  //a digit height
        dotsize int
}
func init(){
        rand.Seed(int64(time.Second))
}

func NewImage(digits []byte, width, height int) *Image {
        img := new(Image)
        r := image.Rect(img.width, img.height, stdWidth, stdHeight)
        img.NRGBA = image.NewNRGBA(r)
        
        img.color = &color.NRGBA{
                uint8(rand.Intn(129)),
                uint8(rand.Intn(129)),
                uint8(rand.Intn(129)),
                0xFF,
        }
        // Draw background (10 random circles of random brightness)
        img.calculateSizes(width, height, len(digits))
        img.fillWithCircles(10, img.dotsize)

        maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
        maxy := height - img.height - img.dotsize*2

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

        // Draw digits.
        for _, n := range digits {
                img.drawDigit(font[n], x, y)
                x += img.width + img.dotsize
        }

        // Draw strike-through line.
        img.strikeThrough()
        return img
}

func (img *Image) WriteTo(w io.Writer) (int64, error) {
        return 0, png.Encode(w, img)
}

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

        // Goal: fit all digits inside the image.
        var border int
        if width > height {
                border = height / 5
        } else {
                border = width / 5
        }
        // Convert everything to floats for calculations.
        w := float64(width - border*2) //268
        h := float64(height - border*2) //48
        // fw takes into account 1-dot spacing between digits.

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

        fh := float64(fontHeight)  //8
        nc := float64(ncount)  //7

        // Calculate the width of a single digit taking into account only the
        // width of the image.
        nw := w / nc //38
        // Calculate the height of a digit from this width.
        nh := nw * fh / fw //51

        // Digit too high?

        if nh > h {
                // Fit digits based on height.
                nh = h //nh = 44
                nw = fw / fh * nh
        }
        // Calculate dot size.
        img.dotsize = int(nh / fh)
        // Save everything, making the actual width smaller by 1 dot to account
        // for spacing between digits.
        img.width = int(nw)
        img.height = int(nh) - img.dotsize
}

func (img *Image) fillWithCircles(n, maxradius int) {
        color := img.color
        maxx := img.Bounds().Max.X
        maxy := img.Bounds().Max.Y
        for i := 0; i < n; i++ {
                setRandomBrightness(color, 255)
                r := rnd(1, maxradius)
                img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
        }
}

func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {
        for x := fromX; x <= toX; x++ {
                img.Set(x, y, color)
        }
}

func (img *Image) drawCircle(color color.Color, x, y, radius int) {
        f := 1 - radius
        dfx := 1
        dfy := -2 * radius
        xx := 0
        yy := radius

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

        for xx < yy {
                if f >= 0 {
                        yy--
                        dfy += 2
                        f += dfy
                }
                xx++
                dfx += 2
                f += dfx
                img.drawHorizLine(color, x-xx, x+xx, y+yy)
                img.drawHorizLine(color, x-xx, x+xx, y-yy)
                img.drawHorizLine(color, x-yy, x+yy, y+xx)
                img.drawHorizLine(color, x-yy, x+yy, y-xx)
        }
}

func (img *Image) strikeThrough() {
        r := 0
        maxx := img.Bounds().Max.X
        maxy := img.Bounds().Max.Y
        y := rnd(maxy/3, maxy-maxy/3)
        for x := 0; x < maxx; x += r {
                r = rnd(1, img.dotsize/3)
                y += rnd(-img.dotsize/2, img.dotsize/2)
                if y <= 0 || y >= maxy {
                        y = rnd(maxy/3, maxy-maxy/3)
                }
                img.drawCircle(img.color, x, y, r)
        }
}

func (img *Image) drawDigit(digit []byte, x, y int) {
        skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
        xs := float64(x)
        minr := img.dotsize / 2               // minumum radius
        maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
        y += rnd(-minr, minr)
        for yy := 0; yy < fontHeight; yy++ {
                for xx := 0; xx < fontWidth; xx++ {
                        if digit[yy*fontWidth+xx] != blackChar {
                                continue
                        }
                        // Introduce random variations.
                        or := rnd(minr, maxr)
                        ox := x + (xx * img.dotsize) + rnd(0, or/2)
                        oy := y + (yy * img.dotsize) + rnd(0, or/2)

                        img.drawCircle(img.color, ox, oy, or)
                }
                xs += skf
                x = int(xs)
        }
}

func setRandomBrightness(c *color.NRGBA, max uint8) {
        minc := min3(c.R, c.G, c.B)
        maxc := max3(c.R, c.G, c.B)
        if maxc > max {
                return
        }
        n := rand.Intn(int(max-maxc)) - int(minc)
        c.R = uint8(int(c.R) + n)
        c.G = uint8(int(c.G) + n)
        c.B = uint8(int(c.B) + n)
}

func min3(x, y, z uint8) (o uint8) {
        o = x
        if y < o {
                o = y
        }
        if z < o {
                o = z
        }
        return
}

func max3(x, y, z uint8) (o uint8) {
        o = x
        if y > o {
                o = y
        }
        if z > o {
                o = z
        }
        return
}

// rnd returns a random number in range [from, to].
func rnd(from, to int) int {
        //println(to+1-from)
        return rand.Intn(to+1-from) + from
}

const (
        // Standard length of uniuri string to achive ~95 bits of entropy.
        StdLen = 16
        // Length of uniurl string to achive ~119 bits of entropy, closest
        // to what can be losslessly converted to UUIDv4 (122 bits).
        UUIDLen = 20
)

// Standard characters allowed in uniuri string.
var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")

// New returns a new random string of the standard length, consisting of
// standard characters.
func New() string {
        return NewLenChars(StdLen, StdChars)
}

// NewLen returns a new random string of the provided length, consisting of
// standard characters.
func NewLen(length int) string {
        return NewLenChars(length, StdChars)
}

// NewLenChars returns a new random string of the provided length, consisting
// of the provided byte slice of allowed characters (maximum 256).
func NewLenChars(length int, chars []byte) string {
        b := make([]byte, length)
        r := make([]byte, length+(length/4)) // storage for random bytes.
        clen := byte(len(chars))
        maxrb := byte(256 - (256 % len(chars)))
        i := 0
        for {
                if _, err := io.ReadFull(crand.Reader, r); err != nil {
                        panic("error reading from random source: " + err.Error())
                }
                for _, c := range r {
                        if c >= maxrb {
                                // Skip this number to avoid modulo bias.
                                continue
                        }
                        b = chars[c%clen]
                        i++
                        if i == length {
                                return string(b)
                        }
                }
        }
        panic("unreachable")
}

func pic(w http.ResponseWriter, req *http.Request) {
        d := make([]byte, 4)
        s := NewLen(4)
        ss := ""
        d = []byte(s)
        for v := range d {
                d[v] %= 10
                ss += strconv.FormatInt(int64(d[v]), 32)
        }
        w.Header().Set("Content-Type", "image/png")
        NewImage(d, 100, 40).WriteTo(w)
        fmt.Println(ss)
}

func index(w http.ResponseWriter, req *http.Request) {
        str := "<meta charset=\"utf-8\"><h3>golang 图片验证码例子</h3><img border=\"1\" src=\"/pic\" alt=\"图片验证码\" onclick=\"this.src='/pic'\" />"
        w.Header().Set("Content-Type", "text/html")
        w.Write([]byte(str))
}

func main() {
        http.HandleFunc("/pic", pic)
        http.HandleFunc("/", index)
        s := &http.Server{
                Addr:                          ":8080",
                ReadTimeout:         30*time.Second,
                WriteTimeout:         30*time.Second,
                MaxHeaderBytes: 1 << 20,
        }
        s.ListenAndServe()
}[/mw_shl_code]

 

 

image image image

posted @ 2014-08-12 18:01  开心编码源  阅读(1213)  评论(0编辑  收藏  举报