diff --git a/README.md b/README.md index 8ae867e..96b6bc1 100644 --- a/README.md +++ b/README.md @@ -438,17 +438,20 @@ builder.SetResources(rotate.WithXxx(), ...) ## Captcha Image Data ### JPEGImageData object method - Get() image.Image -- ToBytes() []byte -- ToBytesWithQuality(imageQuality int) []byte -- ToBase64() string -- ToBase64WithQuality(imageQuality int) string +- ToBytes() ([]byte, error) +- ToBytesWithQuality(imageQuality int) ([]byte, error) +- ToBase64() (string, error) +- ToBase64Data() (string, error) +- ToBase64WithQuality(imageQuality int) (string, error) +- ToBase64DataWithQuality(imageQuality int) (string, error) - SaveToFile(filepath string, quality int) error ### PNGImageData object method - Get() image.Image -- ToBytes() []byte -- ToBase64() string +- ToBytes() ([]byte, error) +- ToBase64() (string, error) +- ToBase64Data() (string, error) - SaveToFile(filepath string) error
@@ -462,9 +465,9 @@ builder.SetResources(rotate.WithXxx(), ...) -

Solid ✔

-

MinProgram

-

UniApp

+-

Flutter App

-

Android App

-

IOS App

--

Flutter App

-

...


diff --git a/README_zh.md b/README_zh.md index 2ef0fec..8a47701 100644 --- a/README_zh.md +++ b/README_zh.md @@ -455,17 +455,20 @@ func loadPng(p string) (image.Image, error) { ### JPEGImageData - Get() image.Image 获取原图像 -- ToBytes() []byte 转为JPEG字节数组 -- ToBytesWithQuality(imageQuality int) []byte 指定清晰度转为JPEG字节数组 -- ToBase64() string 转为 JPEG Base64 字符串 -- ToBase64WithQuality(imageQuality int) string 指定清晰度转为 JPEG Base64 字符串 +- ToBytes() ([]byte, error) 转为JPEG字节数组 +- ToBytesWithQuality(imageQuality int) ([]byte, error) 指定清晰度转为JPEG字节数组 +- ToBase64() (string, error) 转为 JPEG Base64 字符串 +- ToBase64Data() (string, error) 转为 JPEG Base64 字符串,带 "data:image/jpeg;base64," 前缀 +- ToBase64WithQuality(imageQuality int) (string, error) 指定清晰度转为 JPEG Base64 字符串 +- ToBase64DataWithQuality(imageQuality int) (string, error) 指定清晰度转为 JPEG Base64 字符串,带 "data:image/jpeg;base64," 前缀 - SaveToFile(filepath string, quality int) error 保存 JPEG 到文件 ### PNGImageData - Get() image.Image 获取原图像 -- ToBytes() []byte 转为PNG字节数组 -- ToBase64() string 转为 PNG Base64 字符串 +- ToBytes() ([]byte, error) 转为PNG字节数组 +- ToBase64() (string, error) 转为 PNG Base64 字符串 +- ToBase64Data() (string, error) 转为 PNG Base64 字符串,带 "data:image/png;base64," 前缀 - SaveToFile(filepath string) error 保存 PNG 到文件
diff --git a/v2/base/canvas/canvas.go b/v2/base/canvas/canvas.go index 1e2d308..d4e7885 100644 --- a/v2/base/canvas/canvas.go +++ b/v2/base/canvas/canvas.go @@ -13,9 +13,8 @@ import ( // CreatePaletteCanvas is to the canvas that creates the palette func CreatePaletteCanvas(width, height int, colour []color.RGBA) Palette { - p := []color.Color{ - color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x00}, - } + p := make([]color.Color, 0, len(colour)+1) + p = append(p, color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x00}) for _, co := range colour { p = append(p, co) diff --git a/v2/base/canvas/nrgba.go b/v2/base/canvas/nrgba.go index 1b1f971..147f5fc 100644 --- a/v2/base/canvas/nrgba.go +++ b/v2/base/canvas/nrgba.go @@ -7,7 +7,6 @@ package canvas import ( - "fmt" "image" "image/color" "math" @@ -75,9 +74,7 @@ func (n *nRGBA) DrawString(params *DrawStringParams, pt fixed.Point26_6) error { fontColor := image.NewUniform(params.Color) dc.SetSrc(fontColor) - text := fmt.Sprintf("%s", params.Text) - - if _, err := dc.DrawString(text, pt); err != nil { + if _, err := dc.DrawString(params.Text, pt); err != nil { return err } diff --git a/v2/base/canvas/palette.go b/v2/base/canvas/palette.go index 21a0548..4c2ff57 100644 --- a/v2/base/canvas/palette.go +++ b/v2/base/canvas/palette.go @@ -7,7 +7,6 @@ package canvas import ( - "fmt" "image" "image/color" "math" @@ -239,9 +238,7 @@ func (p *palette) DrawString(params *DrawStringParams, pt fixed.Point26_6) error fontColor := image.NewUniform(params.Color) dc.SetSrc(fontColor) - text := fmt.Sprintf("%s", params.Text) - - if _, err := dc.DrawString(text, pt); err != nil { + if _, err := dc.DrawString(params.Text, pt); err != nil { return err } diff --git a/v2/base/codec/codec.go b/v2/base/codec/codec.go index cccaa8c..c3874eb 100644 --- a/v2/base/codec/codec.go +++ b/v2/base/codec/codec.go @@ -9,17 +9,19 @@ package codec import ( "bytes" "encoding/base64" - "fmt" "image" "image/jpeg" "image/png" ) +const pngBasePrefix = "data:image/png;base64," +const jpegBasePrefix = "data:image/jpeg;base64," + // EncodePNGToByte is to encode the png into a byte array -func EncodePNGToByte(img image.Image) (ret []byte) { +func EncodePNGToByte(img image.Image) (ret []byte, err error) { var buf bytes.Buffer - if err := png.Encode(&buf, img); err != nil { - panic(err.Error()) + if err = png.Encode(&buf, img); err != nil { + return } ret = buf.Bytes() buf.Reset() @@ -27,10 +29,10 @@ func EncodePNGToByte(img image.Image) (ret []byte) { } // EncodeJPEGToByte is to encode the image into a byte array -func EncodeJPEGToByte(img image.Image, quality int) (ret []byte) { +func EncodeJPEGToByte(img image.Image, quality int) (ret []byte, err error) { var buf bytes.Buffer - if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality}); err != nil { - panic(err.Error()) + if err = jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality}); err != nil { + return } ret = buf.Bytes() buf.Reset() @@ -55,12 +57,41 @@ func DecodeByteToPng(b []byte) (img image.Image, err error) { return } +// EncodePNGToBase64Data is to encode the png into string +func EncodePNGToBase64Data(img image.Image) (string, error) { + base64Str, err := EncodePNGToBase64(img) + if err != nil { + return "", err + } + + return pngBasePrefix + base64Str, nil +} + +// EncodeJPEGToBase64Data is to encode the image into string +func EncodeJPEGToBase64Data(img image.Image, quality int) (string, error) { + base64Str, err := EncodeJPEGToBase64(img, quality) + if err != nil { + return "", err + } + + return jpegBasePrefix + base64Str, nil +} + // EncodePNGToBase64 is to encode the png into string -func EncodePNGToBase64(img image.Image) string { - return fmt.Sprintf("data:%s;base64,%s", "image/png", base64.StdEncoding.EncodeToString(EncodePNGToByte(img))) +func EncodePNGToBase64(img image.Image) (string, error) { + byteCode, err := EncodePNGToByte(img) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(byteCode), nil } // EncodeJPEGToBase64 is to encode the image into string -func EncodeJPEGToBase64(img image.Image, quality int) string { - return fmt.Sprintf("data:%s;base64,%s", "image/jpeg", base64.StdEncoding.EncodeToString(EncodeJPEGToByte(img, quality))) +func EncodeJPEGToBase64(img image.Image, quality int) (string, error) { + byteCode, err := EncodeJPEGToByte(img, quality) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(byteCode), nil } diff --git a/v2/base/helper/helper.go b/v2/base/helper/helper.go index d1a8d21..dd0732a 100644 --- a/v2/base/helper/helper.go +++ b/v2/base/helper/helper.go @@ -11,7 +11,6 @@ import ( "image/color" "math" "os" - "regexp" "strconv" "unicode" "unicode/utf8" @@ -28,7 +27,7 @@ func t2x(t int64) string { return result } -// FormatAlpha is to formatting transparent +// FormatAlpha is formatting transparent func FormatAlpha(val float32) uint8 { a := math.Min(float64(val), 1) alpha := a * 255 @@ -51,11 +50,14 @@ func HexToRgb(hex string) (int64, int64, int64) { return r, g, b } +var ColorHexFormatErr = errors.New("hex color must start with '#'") +var ColorInvalidErr = errors.New("hexToByte component invalid") + // ParseHexColor is to turn the hex color to RGB color func ParseHexColor(s string) (c color.RGBA, err error) { c.A = 0xff if s[0] != '#' { - return c, errors.New("hex color must start with '#'") + return c, ColorHexFormatErr } hexToByte := func(b byte) byte { @@ -67,7 +69,7 @@ func ParseHexColor(s string) (c color.RGBA, err error) { case b >= 'A' && b <= 'F': return b - 'A' + 10 } - err = errors.New("hexToByte component invalid") + err = ColorInvalidErr return 0 } @@ -82,7 +84,7 @@ func ParseHexColor(s string) (c color.RGBA, err error) { c.G = hexToByte(s[2]) * 17 c.B = hexToByte(s[3]) * 17 default: - err = errors.New("hexToByte component invalid") + err = ColorInvalidErr } return } @@ -112,7 +114,7 @@ func InArrayWithStr(items []string, s string) bool { // IsChineseChar is to detect whether it is Chinese func IsChineseChar(str string) bool { for _, r := range str { - if unicode.Is(unicode.Scripts["Han"], r) || (regexp.MustCompile("[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]").MatchString(string(r))) { + if unicode.Is(unicode.Scripts["Han"], r) { return true } } diff --git a/v2/base/imagedata/base.go b/v2/base/imagedata/base.go index 6ad5c6d..b6d2544 100644 --- a/v2/base/imagedata/base.go +++ b/v2/base/imagedata/base.go @@ -7,6 +7,7 @@ package imagedata import ( + "errors" "image" "image/jpeg" "image/png" @@ -14,6 +15,9 @@ import ( "path" ) +var ImageEmptyErr = errors.New("image is empty") +var ImageMissingDataErr = errors.New("missing image data") + // saveToFile . func saveToFile(img image.Image, filepath string, isTransparent bool, quality int) error { var file *os.File diff --git a/v2/base/imagedata/jpegdata.go b/v2/base/imagedata/jpegdata.go index 0ade5db..3933afd 100644 --- a/v2/base/imagedata/jpegdata.go +++ b/v2/base/imagedata/jpegdata.go @@ -7,7 +7,6 @@ package imagedata import ( - "fmt" "image" "github.com/wenlng/go-captcha/v2/base/codec" @@ -17,10 +16,12 @@ import ( // JPEGImageData . type JPEGImageData interface { Get() image.Image - ToBytes() []byte - ToBytesWithQuality(imageQuality int) []byte - ToBase64() string - ToBase64WithQuality(imageQuality int) string + ToBytes() ([]byte, error) + ToBytesWithQuality(imageQuality int) ([]byte, error) + ToBase64() (string, error) + ToBase64WithQuality(imageQuality int) (string, error) + ToBase64Data() (string, error) + ToBase64DataWithQuality(imageQuality int) (string, error) SaveToFile(filepath string, quality int) error } @@ -46,25 +47,25 @@ func (c *jpegImageDta) Get() image.Image { // SaveToFile is to save JPEG as a file func (c *jpegImageDta) SaveToFile(filepath string, quality int) error { if c.image == nil { - return fmt.Errorf("missing image data") + return ImageMissingDataErr } return saveToFile(c.image, filepath, false, quality) } // ToBytes is to convert JPEG into byte array -func (c *jpegImageDta) ToBytes() []byte { +func (c *jpegImageDta) ToBytes() ([]byte, error) { if c.image == nil { - return []byte{} + return []byte{}, ImageEmptyErr } return codec.EncodeJPEGToByte(c.image, option.QualityNone) } // ToBytesWithQuality is to convert JPEG into byte array with quality -func (c *jpegImageDta) ToBytesWithQuality(imageQuality int) []byte { +func (c *jpegImageDta) ToBytesWithQuality(imageQuality int) ([]byte, error) { if c.image == nil { - return []byte{} + return []byte{}, ImageEmptyErr } if imageQuality <= option.QualityNone && imageQuality >= option.QualityLevel5 { @@ -73,19 +74,40 @@ func (c *jpegImageDta) ToBytesWithQuality(imageQuality int) []byte { return codec.EncodeJPEGToByte(c.image, option.QualityNone) } +// ToBase64Data is to convert JPEG into base64 +func (c *jpegImageDta) ToBase64Data() (string, error) { + if c.image == nil { + return "", ImageEmptyErr + } + + return codec.EncodeJPEGToBase64Data(c.image, option.QualityNone) +} + +// ToBase64DataWithQuality is to convert JPEG into base64 with quality +func (c *jpegImageDta) ToBase64DataWithQuality(imageQuality int) (string, error) { + if c.image == nil { + return "", ImageEmptyErr + } + + if imageQuality <= option.QualityNone && imageQuality >= option.QualityLevel5 { + return codec.EncodeJPEGToBase64Data(c.image, imageQuality) + } + return codec.EncodeJPEGToBase64Data(c.image, option.QualityNone) +} + // ToBase64 is to convert JPEG into base64 -func (c *jpegImageDta) ToBase64() string { +func (c *jpegImageDta) ToBase64() (string, error) { if c.image == nil { - return "" + return "", ImageEmptyErr } return codec.EncodeJPEGToBase64(c.image, option.QualityNone) } // ToBase64WithQuality is to convert JPEG into base64 with quality -func (c *jpegImageDta) ToBase64WithQuality(imageQuality int) string { +func (c *jpegImageDta) ToBase64WithQuality(imageQuality int) (string, error) { if c.image == nil { - return "" + return "", ImageEmptyErr } if imageQuality <= option.QualityNone && imageQuality >= option.QualityLevel5 { diff --git a/v2/base/imagedata/pngdata.go b/v2/base/imagedata/pngdata.go index 3f595a8..0febcb7 100644 --- a/v2/base/imagedata/pngdata.go +++ b/v2/base/imagedata/pngdata.go @@ -7,7 +7,6 @@ package imagedata import ( - "fmt" "image" "github.com/wenlng/go-captcha/v2/base/codec" @@ -17,8 +16,9 @@ import ( // PNGImageData . type PNGImageData interface { Get() image.Image - ToBytes() []byte - ToBase64() string + ToBytes() ([]byte, error) + ToBase64() (string, error) + ToBase64Data() (string, error) SaveToFile(filepath string) error } @@ -44,25 +44,32 @@ func (c *pngImageDta) Get() image.Image { // SaveToFile is to save PNG as a file func (c *pngImageDta) SaveToFile(filepath string) error { if c.image == nil { - return fmt.Errorf("missing image data") + return ImageMissingDataErr } return saveToFile(c.image, filepath, true, option.QualityNone) } // ToBytes is to convert PNG into byte array -func (c *pngImageDta) ToBytes() []byte { +func (c *pngImageDta) ToBytes() ([]byte, error) { if c.image == nil { - return []byte{} + return []byte{}, ImageEmptyErr } - return codec.EncodePNGToByte(c.image) } +// ToBase64Data is to convert PNG into base64 +func (c *pngImageDta) ToBase64Data() (string, error) { + if c.image == nil { + return "", ImageEmptyErr + } + return codec.EncodePNGToBase64Data(c.image) +} + // ToBase64 is to convert PNG into base64 -func (c *pngImageDta) ToBase64() string { +func (c *pngImageDta) ToBase64() (string, error) { if c.image == nil { - return "" + return "", ImageEmptyErr } return codec.EncodePNGToBase64(c.image) } diff --git a/v2/base/logger/logger.go b/v2/base/logger/logger.go index 034cf49..88216a6 100644 --- a/v2/base/logger/logger.go +++ b/v2/base/logger/logger.go @@ -34,6 +34,8 @@ func New() Logger { var _ Logger = (*logx)(nil) +var Logx = New() + // logx . type logx struct { l *log.Logger diff --git a/v2/click/click.go b/v2/click/click.go index cf9bc34..0598750 100644 --- a/v2/click/click.go +++ b/v2/click/click.go @@ -7,7 +7,7 @@ package click import ( - "fmt" + "errors" "image" "image/color" "math" @@ -22,7 +22,7 @@ import ( ) // Version # of captcha -const Version = "2.0.0" +const Version = "2.0.2" // Captcha . type Captcha interface { @@ -41,6 +41,14 @@ const ( var _ Captcha = (*captcha)(nil) +var EmptyShapesErr = errors.New("empty shapes") +var EmptyCharacterErr = errors.New("empty character") +var CharRangeLenErr = errors.New("character length must be large than to 'rangeLen.Max'") +var ShapesRangeLenErr = errors.New("total number of shapes must be large than to 'rangeLen.Max'") +var ShapesTypeErr = errors.New("shape must be is image type") +var EmptyBackgroundImageErr = errors.New("no background image") +var ModeSupportErr = errors.New("mode not supported") + // captcha . type captcha struct { version string @@ -181,7 +189,7 @@ func (c *captcha) genShapes() ([]string, error) { length := random.RandInt(c.opts.rangeLen.Min, c.opts.rangeLen.Max) shapeNames := c.genRandShape(length) if len(shapeNames) == 0 { - return []string{}, fmt.Errorf("click captcha err: %v", "no shapes generation") + return []string{}, EmptyShapesErr } return shapeNames, nil } @@ -191,14 +199,14 @@ func (c *captcha) genChars() ([]string, error) { length := random.RandInt(c.opts.rangeLen.Min, c.opts.rangeLen.Max) chars := c.genRandChar(length) if len(chars) == 0 { - return []string{}, fmt.Errorf("click captcha err: %v", "no character generation") + return []string{}, EmptyCharacterErr } return chars, nil } // genDots is to generate an orderly dot list func (c *captcha) genDots(imageSize *option.Size, size *option.RangeVal, values []string, padding int) map[int]*Dot { - var dots = make(map[int]*Dot) + var dots = make(map[int]*Dot, len(values)) width := imageSize.Width height := imageSize.Height if padding > 0 { @@ -255,7 +263,7 @@ func (c *captcha) genDots(imageSize *option.Size, size *option.RangeVal, values if c.mode == ModeShape { dots[i].Shape = value } else { - dots[i].Text = fmt.Sprintf("%s", value) + dots[i].Text = value } } @@ -266,17 +274,17 @@ func (c *captcha) genDots(imageSize *option.Size, size *option.RangeVal, values func (c *captcha) check() error { if c.mode == ModeText { if len(c.resources.chars) < c.opts.rangeLen.Max { - return fmt.Errorf("click captcha err: chars must be large than to %d", c.opts.rangeLen.Max) + return CharRangeLenErr } return nil } else if c.mode == ModeShape { if len(c.resources.shapes) < c.opts.rangeLen.Max { - return fmt.Errorf("click captcha err: shapes must be large than to %d", c.opts.rangeLen.Max) + return ShapesRangeLenErr } - for name, img := range c.resources.shapeMaps { + for _, img := range c.resources.shapeMaps { if img == nil { - return fmt.Errorf("click captcha err: [%s] shape must be is image type", name) + return ShapesTypeErr } } @@ -284,10 +292,10 @@ func (c *captcha) check() error { } if len(c.resources.rangBackgrounds) == 0 { - return fmt.Errorf("click captcha err: no rang backgroun image") + return EmptyBackgroundImageErr } - return fmt.Errorf("click captcha err: %v", "mode not supported") + return ModeSupportErr } // rangeCheckDots is to generate random detection points diff --git a/v2/click/draw.go b/v2/click/draw.go index 70928a0..f6e1cd0 100644 --- a/v2/click/draw.go +++ b/v2/click/draw.go @@ -104,10 +104,6 @@ func (d *drawImage) DrawWithNRGBA(params *DrawImageParams) (image.Image, error) // DrawWithPalette is to draw with a palette func (d *drawImage) DrawWithPalette(params *DrawImageParams, tColors []color.Color, bgColors []color.Color) (image.Image, error) { dots := params.CaptchaDrawDot - p := []color.Color{ - color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x00}, - } - p = append(p, tColors...) nBgColors := make([]color.Color, 0, len(bgColors)) for _, bgColor := range bgColors { @@ -115,6 +111,10 @@ func (d *drawImage) DrawWithPalette(params *DrawImageParams, tColors []color.Col aa := helper.FormatAlpha(params.ThumbDisturbAlpha) nBgColors = append(nBgColors, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: aa}) } + + var p = make([]color.Color, 0, len(tColors)+len(nBgColors)+1) + p = append(p, color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x00}) + p = append(p, tColors...) p = append(p, nBgColors...) cvs := canvas.NewPalette(image.Rect(0, 0, params.Width, params.Height), p) @@ -183,17 +183,16 @@ func (d *drawImage) DrawWithPalette(params *DrawImageParams, tColors []color.Col func (d *drawImage) DrawWithNRGBA2(params *DrawImageParams, tColors []color.Color, bgColors []color.Color) (image.Image, error) { dots := params.CaptchaDrawDot - p := []color.Color{ - color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x00}, - } - p = append(p, tColors...) - nBgColors := make([]color.Color, 0, len(bgColors)) for _, bgColor := range bgColors { r, g, b, _ := bgColor.RGBA() aa := helper.FormatAlpha(params.ThumbDisturbAlpha) nBgColors = append(nBgColors, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: aa}) } + + var p = make([]color.Color, 0, len(tColors)+len(nBgColors)+1) + p = append(p, color.RGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x00}) + p = append(p, tColors...) p = append(p, nBgColors...) ccvs := canvas.NewNRGBA(image.Rect(0, 0, params.Width, params.Height), true) @@ -309,6 +308,7 @@ func (d *drawImage) randomDrawSlimLine(m canvas.Palette, num int, colorB []color func (d *drawImage) DrawDotImage(dot *DrawDot, params *DrawImageParams) (canvas.NRGBA, *canvas.AreaRect, error) { cColor, _ := helper.ParseHexColor(dot.Color) cColor.A = helper.FormatAlpha(params.Alpha) + var cImage image.Image var err error if dot.DrawType == DrawTypeImage { @@ -320,19 +320,11 @@ func (d *drawImage) DrawDotImage(dot *DrawDot, params *DrawImageParams) (canvas. return nil, nil, err } - var colorArr = []color.RGBA{ - cColor, - } - shadowColorHex := shadowColor if params.ShadowColor != "" { shadowColorHex = params.ShadowColor } - sColor, _ := helper.ParseHexColor(shadowColorHex) - if params.ShowShadow { - colorArr = append(colorArr, sColor) - } cvs := canvas.CreateNRGBACanvas(dot.Width+10, dot.Height+10, true) if params.ShowShadow { @@ -387,10 +379,11 @@ func (d *drawImage) DrawStringImage(dot *DrawDot, textColor color.Color) (canvas // DrawShapeImage is to draw shape image func (d *drawImage) DrawShapeImage(dot *DrawDot, cColor color.Color) (canvas.NRGBA, error) { cr, cg, cb, ca := cColor.RGBA() + var colorArr = []color.RGBA{ {R: uint8(cr), G: uint8(cg), B: uint8(cb), A: uint8(ca)}, } - + ncvs := canvas.CreateNRGBACanvas(dot.Width+10, dot.Height+10, true) var bounds image.Rectangle var img image.Image diff --git a/v2/click/option.go b/v2/click/option.go index 0a7fc19..2a63664 100644 --- a/v2/click/option.go +++ b/v2/click/option.go @@ -7,11 +7,16 @@ package click import ( + "errors" + "github.com/wenlng/go-captcha/v2/base/logger" "github.com/wenlng/go-captcha/v2/base/option" "golang.org/x/image/font" ) +var ColorLenErr = errors.New("the color length must be less than or equal to 255") +var RangeVerifyLenErr = errors.New("the max value of 'rangeVerifyLen' must be less than or equal to the min value of 'rangeLen'") + // Options . type Options struct { fontDPI int @@ -236,7 +241,7 @@ func WithRangeSize(val option.RangeVal) Option { func WithRangeColors(colors []string) Option { return func(opts *Options) { if len(colors) > 255 { - logger.New().Errorf("withRangeColors error: the max value of rangColors must be less than or equal to 255") + logger.Logx.Warnf("withRangeColors(): %v", ColorLenErr) return } @@ -290,7 +295,7 @@ func WithRangeThumbImageSize(val option.Size) Option { func WithRangeVerifyLen(val option.RangeVal) Option { return func(opts *Options) { if val.Max > opts.rangeLen.Min { - logger.New().Errorf("withRangeVerifyLen error: the max value of rangeVerifyLen must be less than or equal to the min value of rangeLen") + logger.Logx.Warnf("withRangeVerifyLen(): %v", RangeVerifyLenErr) return } @@ -316,7 +321,7 @@ func WithRangeThumbSize(val option.RangeVal) Option { func WithRangeThumbColors(val []string) Option { return func(opts *Options) { if len(val) > 255 { - logger.New().Errorf("withRangeThumbColors error: the max value of rangeThumbColors must be less than or equal to 255") + logger.Logx.Warnf("WithRangeThumbColors(): %v", ColorLenErr) return } opts.rangeThumbColors = val @@ -327,7 +332,7 @@ func WithRangeThumbColors(val []string) Option { func WithRangeThumbBgColors(val []string) Option { return func(opts *Options) { if len(val) > 255 { - logger.New().Errorf("withRangeThumbBgColors error: the max value of rangeThumbBgColors must be less than or equal to 255") + logger.Logx.Warnf("withRangeThumbBgColors(): %v", ColorLenErr) return } diff --git a/v2/rotate/draw.go b/v2/rotate/draw.go index 1a77b36..520e2a9 100644 --- a/v2/rotate/draw.go +++ b/v2/rotate/draw.go @@ -51,6 +51,7 @@ type drawImage struct { // DrawWithCropCircle is to draw a crop circle func (d *drawImage) DrawWithCropCircle(params *DrawCropCircleImageParams) (image.Image, error) { bgImage := params.Background + bgBounds := bgImage.Bounds() cvs := canvas.CreateNRGBACanvas(bgImage.Bounds().Dx(), bgImage.Bounds().Dy(), true) draw.Draw(cvs.Get(), bgImage.Bounds(), bgImage, image.Point{}, draw.Over) diff --git a/v2/rotate/option.go b/v2/rotate/option.go index 550802c..5ccd07a 100644 --- a/v2/rotate/option.go +++ b/v2/rotate/option.go @@ -66,7 +66,7 @@ func WithImageSquareSize(val int) Option { // WithRangeAnglePos . func WithRangeAnglePos(vals []option.RangeVal) Option { return func(opts *Options) { - var newVals = make([]*option.RangeVal, 0) + var newVals = make([]*option.RangeVal, 0, len(vals)) for i := 0; i < len(vals); i++ { val := vals[i] newVals = append(newVals, &option.RangeVal{Min: val.Min, Max: val.Max}) diff --git a/v2/rotate/rotate.go b/v2/rotate/rotate.go index c509f3b..2ea3293 100644 --- a/v2/rotate/rotate.go +++ b/v2/rotate/rotate.go @@ -7,7 +7,7 @@ package rotate import ( - "fmt" + "errors" "image" "github.com/wenlng/go-captcha/v2/base/helper" @@ -18,7 +18,7 @@ import ( ) // Version # of captcha -const Version = "2.0.0" +const Version = "2.0.2" // Captcha . type Captcha interface { @@ -30,6 +30,9 @@ type Captcha interface { var _ Captcha = (*captcha)(nil) +var EmptyImageErr = errors.New("no image") +var ImageTypeErr = errors.New("image must be is image.Image type") + // captcha . type captcha struct { version string @@ -170,11 +173,11 @@ func (c *captcha) genBlock(imageSize int, thumbImageSquareSize int) *Block { // check is to check the captcha parameter func (c *captcha) check() error { if len(c.resources.rangImages) == 0 { - return fmt.Errorf("rotate captcha err: no rang image") + return EmptyImageErr } for _, img := range c.resources.rangImages { if img == nil { - return fmt.Errorf("rotate captcha err: image must be is image.Image type") + return ImageTypeErr } } return nil diff --git a/v2/slide/option.go b/v2/slide/option.go index 7517619..a6ae616 100644 --- a/v2/slide/option.go +++ b/v2/slide/option.go @@ -108,7 +108,7 @@ func WithRangeGraphSize(val option.RangeVal) Option { // WithRangeGraphAnglePos . func WithRangeGraphAnglePos(vals []option.RangeVal) Option { return func(opts *Options) { - var newVals = make([]*option.RangeVal, 0) + var newVals = make([]*option.RangeVal, 0, len(vals)) for i := 0; i < len(vals); i++ { val := vals[i] newVals = append(newVals, &option.RangeVal{Min: val.Min, Max: val.Max}) diff --git a/v2/slide/slide.go b/v2/slide/slide.go index 9bff8ee..54ceb3d 100644 --- a/v2/slide/slide.go +++ b/v2/slide/slide.go @@ -7,7 +7,7 @@ package slide import ( - "fmt" + "errors" "image" "math" @@ -20,7 +20,7 @@ import ( ) // Version # of captcha -const Version = "2.0.0" +const Version = "2.0.2" type Mode int @@ -39,6 +39,13 @@ type Captcha interface { var _ Captcha = (*captcha)(nil) +var GraphImageErr = errors.New("graph image is incorrect") +var GenerateDataErr = errors.New("generate data failed") +var ImageTypeErr = errors.New("tile image must be is image.Image type") +var ShadowImageTypeErr = errors.New("tile shadow image must be is image.Image type") +var MaskImageTypeErr = errors.New("tile shadow image must be is image.Image type") +var EmptyBackgroundImageErr = errors.New("no background image") + // captcha . type captcha struct { version string @@ -100,7 +107,7 @@ func (c *captcha) Generate() (CaptchaData, error) { overlayImage, shadowImage, maskImage := c.genGraph() if overlayImage == nil || shadowImage == nil || maskImage == nil { - return nil, fmt.Errorf("the graph image is incorrect") + return nil, GraphImageErr } blocks, tilePoint := c.genGraphBlocks(c.opts.imageSize, c.opts.rangeGraphSize, c.opts.genGraphNumber) @@ -116,7 +123,7 @@ func (c *captcha) Generate() (CaptchaData, error) { } if block == nil { - return nil, fmt.Errorf("gen captcha data failed") + return nil, GenerateDataErr } var masterImage, masterBgImage, tileImage image.Image @@ -309,16 +316,16 @@ func (c *captcha) genGraph() (maskImage, shadowImage, templateImage image.Image) func (c *captcha) check() error { for _, tile := range c.resources.rangGraphImage { if tile.OverlayImage == nil { - return fmt.Errorf("slide captcha err: tile image must be is image.Image type") + return ImageTypeErr } else if tile.ShadowImage == nil { - return fmt.Errorf("slide captcha err: tile shadow image must be is image.Image type") + return ShadowImageTypeErr } else if tile.MaskImage == nil { - return fmt.Errorf("slide captcha err: tile mask image must be is image.Image type") + return MaskImageTypeErr } } if len(c.resources.rangBackgrounds) == 0 { - return fmt.Errorf("slide captcha err: no rang backgroun image") + return EmptyBackgroundImageErr } return nil diff --git a/v2/tests/click_text_test.go b/v2/tests/click_text_test.go index 37b351e..6a2bc41 100644 --- a/v2/tests/click_text_test.go +++ b/v2/tests/click_text_test.go @@ -19,6 +19,7 @@ func init() { click.WithRangeLen(option.RangeVal{Min: 4, Max: 6}), click.WithRangeVerifyLen(option.RangeVal{Min: 2, Max: 4}), click.WithDisabledRangeVerifyLen(true), + click.WithIsThumbNonDeformAbility(false), ) fontN, err := loadFont("../.cache/fzshengsksjw_cu.ttf") @@ -26,15 +27,22 @@ func init() { log.Fatalln(err) } + fontN2, err := loadFont("../.cache/yrdzst-bold.ttf") + if err != nil { + log.Fatalln(err) + } + bgImage, err := loadPng("../.cache/bg.png") if err != nil { log.Fatalln(err) } builder.SetResources( + click.WithChars([]string{"鼓", "鼎", "默", "黔", "黑", "黎", "黍", "黄", "麻", "麸", "麦", "鹿"}), //click.WithChars([]string{"这", "是", "随", "机", "的", "文", "本", "种", "子", "呀"}), - click.WithChars([]string{"A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "I9", "J0"}), + //click.WithChars([]string{"A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "I9", "J0"}), click.WithFonts([]*truetype.Font{ + fontN2, fontN, }), click.WithBackgrounds([]image.Image{ @@ -61,8 +69,8 @@ func TestClickTextCaptcha(t *testing.T) { dots, _ := json.Marshal(dotData) fmt.Println(string(dots)) - fmt.Println(captData.GetMasterImage().ToBase64()) - fmt.Println(captData.GetThumbImage().ToBase64()) + fmt.Println(captData.GetMasterImage().ToBase64Data()) + fmt.Println(captData.GetThumbImage().ToBase64Data()) err = captData.GetMasterImage().SaveToFile("../.cache/master.jpg", option.QualityNone) if err != nil {