package vision import ( "image/color" "math" "apigo.cc/go/rand" ) // CaptchaOption 定义验证码生成选项 type CaptchaOption struct { Text string Length int Width int Height int NoiseLevel int // 1-10 } // GenerateCaptcha 生成一个验证码画布 func GenerateCaptcha(opt *CaptchaOption) *Canvas { if opt == nil { opt = &CaptchaOption{} } if opt.Length == 0 { opt.Length = 4 } if opt.Width == 0 { opt.Width = 150 } if opt.Height == 0 { opt.Height = 50 } if opt.NoiseLevel == 0 { opt.NoiseLevel = 3 } if opt.Text == "" { chars := "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnpqrstwxyz2345678" text := make([]byte, opt.Length) for i := 0; i < opt.Length; i++ { text[i] = chars[rand.Int(0, len(chars)-1)] } opt.Text = string(text) } c := New(opt.Width, opt.Height, "#FFFFFF") c.RandBG(opt.NoiseLevel) // 计算字体大小 fontSize := math.Max(28, float64(opt.Height)*0.7) _ = c.SetFont(fontSize) // 绘制随机扭曲文本 c.RandText(opt.Text) return c } // RandText 绘制随机扭曲文本 (用于验证码) func (c *Canvas) RandText(text string) [][4]float64 { w, h := float64(c.Width()), float64(c.Height()) fullWidth, _ := c.dc.MeasureString(text) x := (w - fullWidth) / 2 y := h/2 + (c.dc.FontHeight()*0.7)/2 charPositions := make([][4]float64, 0, len(text)) for _, char := range text { charStr := string(char) charWidth, _ := c.dc.MeasureString(charStr) charHeight := c.dc.FontHeight() yOffset := rand.Float(0.0, 10.0) - 5 angle := rand.Float(0.0, 0.4) - 0.2 // ±11° charPositions = append(charPositions, [4]float64{x, y + yOffset - charHeight, charWidth, charHeight}) c.dc.Push() c.dc.RotateAbout(angle, x+charWidth/2, y+yOffset-charHeight/2) // 绘制阴影 c.dc.SetColor(color.Gray{Y: 100}) c.dc.DrawString(charStr, x+1, y+yOffset+1) // 绘制主体 c.dc.SetColor(ParseColor(RandColor())) c.dc.DrawString(charStr, x, y+yOffset) c.dc.Pop() x += charWidth + rand.Float(0.0, 5.0) } return charPositions }