123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- package captcha
- import (
- "bytes"
- "github.com/fogleman/gg"
- "github.com/golang/freetype/truetype"
- "golang.org/x/image/font"
- "math/rand"
- "time"
- )
- type Captcha struct {
- }
- const Chars = "ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789"
- // GetRandStr 生成验证码字符串(可存入redis或者放入其他缓存中)
- func (Captcha) GetRandStr(n int) (randStr string) {
- charsLen := len(Chars)
- if n > 10 {
- n = 10
- }
- rand.Seed(time.Now().UnixNano())
- for i := 0; i < n; i++ {
- randIndex := rand.Intn(charsLen)
- randStr += Chars[randIndex : randIndex+1]
- }
- return randStr
- }
- // ImgText 生成图片byte数据可以生成base64数据或者生成img图片文件
- func (Captcha) ImgText(width, height int, text string) (b []byte) {
- textLen := len(text)
- dc := gg.NewContext(width, height)
- bgR, bgG, bgB, bgA := getRandColorRange(240, 255)
- dc.SetRGBA255(bgR, bgG, bgB, bgA)
- dc.Clear()
- // 干扰线
- for i := 0; i < 10; i++ {
- x1, y1 := getRandPos(width, height)
- x2, y2 := getRandPos(width, height)
- r, g, b, a := getRandColor(255)
- w := float64(rand.Intn(3) + 1)
- dc.SetRGBA255(r, g, b, a)
- dc.SetLineWidth(w)
- dc.DrawLine(x1, y1, x2, y2)
- dc.Stroke()
- }
- fontSize := float64(height/2) + 5
- face := loadFontFace(fontSize)
- dc.SetFontFace(face)
- for i := 0; i < len(text); i++ {
- r, g, b, _ := getRandColor(100)
- dc.SetRGBA255(r, g, b, 255)
- fontPosX := float64(width/textLen*i) + fontSize*0.6
- writeText(dc, text[i:i+1], float64(fontPosX), float64(height/2))
- }
- buffer := bytes.NewBuffer(nil)
- dc.EncodePNG(buffer)
- b = buffer.Bytes()
- return
- }
- // 渲染文字
- func writeText(dc *gg.Context, text string, x, y float64) {
- xfload := 5 - rand.Float64()*10 + x
- yfload := 5 - rand.Float64()*10 + y
- radians := 40 - rand.Float64()*80
- dc.RotateAbout(gg.Radians(radians), x, y)
- dc.DrawStringAnchored(text, xfload, yfload, 0.2, 0.5)
- dc.RotateAbout(-1*gg.Radians(radians), x, y)
- dc.Stroke()
- }
- // 随机坐标
- func getRandPos(width, height int) (x float64, y float64) {
- x = rand.Float64() * float64(width)
- y = rand.Float64() * float64(height)
- return x, y
- }
- // 随机颜色
- func getRandColor(maxColor int) (r, g, b, a int) {
- r = int(uint8(rand.Intn(maxColor)))
- g = int(uint8(rand.Intn(maxColor)))
- b = int(uint8(rand.Intn(maxColor)))
- a = int(uint8(rand.Intn(255)))
- return r, g, b, a
- }
- // 随机颜色范围
- func getRandColorRange(miniColor, maxColor int) (r, g, b, a int) {
- if miniColor > maxColor {
- miniColor = 0
- maxColor = 255
- }
- r = int(uint8(rand.Intn(maxColor-miniColor) + miniColor))
- g = int(uint8(rand.Intn(maxColor-miniColor) + miniColor))
- b = int(uint8(rand.Intn(maxColor-miniColor) + miniColor))
- a = int(uint8(rand.Intn(maxColor-miniColor) + miniColor))
- return r, g, b, a
- }
- // 加载字体
- func loadFontFace(points float64) font.Face {
- // 这里是将字体TTF文件转换成了 byte 数据保存成了一个 go 文件
- // 通过truetype.Parse可以将 byte 类型的数据转换成TTF字体类型
- f, err := truetype.Parse(COMICSAN)
- if err != nil {
- panic(err)
- }
- face := truetype.NewFace(f, &truetype.Options{
- Size: points,
- })
- return face
- }
|