Compare commits

..

No commits in common. "main" and "v1.4.0" have entirely different histories.
main ... v1.4.0

9 changed files with 63 additions and 74 deletions

24
.github/workflows/go.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: CI
on: [push, pull_request]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Golang
uses: actions/setup-go@v2
with:
go-version: '^1.16.0'
- run: go version
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: install dependencies
run: go mod download
- name: run test
run: go test -race -coverprofile=coverage.txt -covermode=atomic
- name: upload coverage
run: bash <(curl -s https://codecov.io/bash)

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017 - 2024 Weilin Shi Copyright (c) 2017 - 2021 Weilin Shi
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -2,17 +2,19 @@
<div> <div>
[![PkgGoDev](https://pkg.go.dev/badge/concord.hectabit.org/HectaBit/captcha)](https://pkg.go.dev/concord.hectabit.org/HectaBit/captcha) [![PkgGoDev](https://pkg.go.dev/badge/github.com/steambap/captcha)](https://pkg.go.dev/github.com/steambap/captcha)
[![Go Report Card](https://goreportcard.com/badge/concord.hectabit.org/HectaBit/captcha)](https://goreportcard.com/report/concord.hectabit.org/HectaBit/captcha) [![Build Status](https://github.com/steambap/captcha/workflows/CI/badge.svg)](https://github.com/steambap/captcha/actions?workflow=CI)
[![codecov](https://codecov.io/gh/steambap/captcha/branch/main/graph/badge.svg)](https://codecov.io/gh/steambap/captcha)
[![Go Report Card](https://goreportcard.com/badge/github.com/steambap/captcha)](https://goreportcard.com/report/github.com/steambap/captcha)
</div> </div>
## Why another captcha generator? ## Why another captcha generator?
Because I can. I want a simple and framework-independent way to generate captcha. It also should be flexible, at least allow me to pick my favorite font.
## install ## install
``` ```
go get concord.hectabit.org/HectaBit/captcha go get github.com/steambap/captcha
``` ```
## usage ## usage
@ -30,9 +32,8 @@ func handle(w http.ResponseWriter, r *http.Request) {
``` ```
[documentation](https://pkg.go.dev/concord.hectabit.org/HectaBit/captcha) | [documentation](https://pkg.go.dev/github.com/steambap/captcha) |
[example](example/basic/main.go) | [example](example/basic/main.go)
[font example](example/load-font/main.go)
## sample image ## sample image
![image](example/captcha.png) ![image](example/captcha.png)
@ -41,7 +42,7 @@ func handle(w http.ResponseWriter, r *http.Request) {
## Compatibility ## Compatibility
This package uses embed package from Go 1.16. If for some reasons you have to use pre 1.16 version of Go, reference pre 1.4 version of this module in your go.mod. This package uses embed package from Go 1.16. If for some reason you have to use pre 1.16 version of Go, reference pre 1.4 version of this module in your go.mod.
## Contributing ## Contributing
If your found a bug, please contribute! If your found a bug, please contribute!

View file

@ -2,7 +2,8 @@
package captcha package captcha
import ( import (
_ "embed" // embed font "bytes"
_ "embed"
"image" "image"
"image/color" "image/color"
"image/draw" "image/draw"
@ -62,7 +63,7 @@ func newDefaultOption(width, height int) *Options {
return &Options{ return &Options{
BackgroundColor: color.Transparent, BackgroundColor: color.Transparent,
CharPreset: charPreset, CharPreset: charPreset,
TextLength: 6, TextLength: 4,
CurveNumber: 2, CurveNumber: 2,
FontDPI: 72.0, FontDPI: 72.0,
FontScale: 1.0, FontScale: 1.0,
@ -118,12 +119,12 @@ func LoadFont(fontData []byte) error {
// LoadFontFromReader load an external font from an io.Reader interface. // LoadFontFromReader load an external font from an io.Reader interface.
func LoadFontFromReader(reader io.Reader) error { func LoadFontFromReader(reader io.Reader) error {
b, err := io.ReadAll(reader) var buf bytes.Buffer
if err != nil { if _, err := io.Copy(&buf, reader); err != nil {
return err return err
} }
return LoadFont(b) return LoadFont(buf.Bytes())
} }
// New creates a new captcha. // New creates a new captcha.
@ -136,7 +137,11 @@ func New(width int, height int, option ...SetOption) (*Data, error) {
text := randomText(options) text := randomText(options)
img := image.NewNRGBA(image.Rect(0, 0, width, height)) img := image.NewNRGBA(image.Rect(0, 0, width, height))
if err := drawWithOption(text, img, options); err != nil { draw.Draw(img, img.Bounds(), &image.Uniform{options.BackgroundColor}, image.Point{}, draw.Src)
drawNoise(img, options)
drawCurves(img, options)
err := drawText(text, img, options)
if err != nil {
return nil, err return nil, err
} }
@ -153,42 +158,21 @@ func NewMathExpr(width int, height int, option ...SetOption) (*Data, error) {
text, equation := randomEquation() text, equation := randomEquation()
img := image.NewNRGBA(image.Rect(0, 0, width, height)) img := image.NewNRGBA(image.Rect(0, 0, width, height))
if err := drawWithOption(equation, img, options); err != nil { draw.Draw(img, img.Bounds(), &image.Uniform{options.BackgroundColor}, image.Point{}, draw.Src)
drawNoise(img, options)
drawCurves(img, options)
err := drawText(equation, img, options)
if err != nil {
return nil, err return nil, err
} }
return &Data{Text: text, img: img}, nil return &Data{Text: text, img: img}, nil
} }
// NewCustomGenerator creates a new captcha based on a custom text generator.
func NewCustomGenerator(
width int, height int, generator func() (anwser string, question string), option ...SetOption,
) (*Data, error) {
options := newDefaultOption(width, height)
for _, setOption := range option {
setOption(options)
}
answer, question := generator()
img := image.NewNRGBA(image.Rect(0, 0, width, height))
if err := drawWithOption(question, img, options); err != nil {
return nil, err
}
return &Data{Text: answer, img: img}, nil
}
func drawWithOption(text string, img *image.NRGBA, options *Options) error {
draw.Draw(img, img.Bounds(), &image.Uniform{options.BackgroundColor}, image.Point{}, draw.Src)
drawNoise(img, options)
drawCurves(img, options)
return drawText(text, img, options)
}
func randomText(opts *Options) (text string) { func randomText(opts *Options) (text string) {
n := len([]rune(opts.CharPreset)) n := len(opts.CharPreset)
for i := 0; i < opts.TextLength; i++ { for i := 0; i < opts.TextLength; i++ {
text += string([]rune(opts.CharPreset)[rand.Intn(n)]) text += string(opts.CharPreset[rand.Intn(n)])
} }
return text return text

View file

@ -69,12 +69,6 @@ func TestNewCaptchaOptions(t *testing.T) {
NewMathExpr(100, 34, func(options *Options) { NewMathExpr(100, 34, func(options *Options) {
options.BackgroundColor = color.Black options.BackgroundColor = color.Black
}) })
NewCustomGenerator(100, 34, func() (anwser string, question string) {
return "4", "2x2?"
}, func(o *Options) {
o.BackgroundColor = color.Black
})
} }
func TestNewMathExpr(t *testing.T) { func TestNewMathExpr(t *testing.T) {
@ -84,15 +78,6 @@ func TestNewMathExpr(t *testing.T) {
} }
} }
func TestNewCustomGenerator(t *testing.T) {
_, err := NewCustomGenerator(150, 50, func() (anwser string, question string) {
return "1", "2"
})
if err != nil {
t.Fatal(err)
}
}
func TestNilFontError(t *testing.T) { func TestNilFontError(t *testing.T) {
temp := ttfFont temp := ttfFont
ttfFont = nil ttfFont = nil
@ -107,13 +92,6 @@ func TestNilFontError(t *testing.T) {
t.Fatal("Expect to get nil font error") t.Fatal("Expect to get nil font error")
} }
_, err = NewCustomGenerator(150, 50, func() (anwser string, question string) {
return "1", "2"
})
if err == nil {
t.Fatal("Expect to get nil font error")
}
ttfFont = temp ttfFont = temp
} }

View file

@ -1 +1 @@
[https://www.contributor-covenant.org/version/2/1/code_of_conduct/](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) [https://contributor-covenant.org/version/1/4/](https://contributor-covenant.org/version/1/4/)

View file

@ -1,7 +1,7 @@
module concord.hectabit.org/HectaBit/captcha/example/basic module github.com/steambap/captcha/example/basic
go 1.12 go 1.12
replace concord.hectabit.org/HectaBit/captcha => ../../ replace github.com/steambap/captcha => ../../
require concord.hectabit.org/HectaBit/captcha v0.0.0-00010101000000-000000000000 require github.com/steambap/captcha v0.0.0-00010101000000-000000000000

6
go.mod
View file

@ -1,8 +1,8 @@
module concord.hectabit.org/HectaBit/captcha module github.com/steambap/captcha
go 1.20 go 1.16
require ( require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
golang.org/x/image v0.15.0 golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
) )

6
go.sum
View file

@ -1,4 +1,6 @@
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=