Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
669a328c35 | |||
31a767886d | |||
8b04542f19 | |||
0d18ee4d3f | |||
98c666bea2 | |||
d294d79360 | |||
b4b097a927 | |||
|
c34288c982 | ||
|
2f847d5947 | ||
|
fef853ee5e | ||
|
1d4172a01f | ||
|
6b08f978b6 | ||
|
9234bd71dd | ||
|
f6fd454518 | ||
|
20014aab1b | ||
|
6aa88d953f | ||
|
019b34f8f2 | ||
|
80cb7ffd68 |
8 changed files with 68 additions and 56 deletions
24
.github/workflows/go.yml
vendored
24
.github/workflows/go.yml
vendored
|
@ -1,24 +0,0 @@
|
|||
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)
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 - 2021 Weilin Shi
|
||||
Copyright (c) 2017 - 2024 Weilin Shi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
15
README.md
15
README.md
|
@ -2,19 +2,17 @@
|
|||
|
||||
<div>
|
||||
|
||||
[](https://pkg.go.dev/github.com/steambap/captcha)
|
||||
[](https://github.com/steambap/captcha/actions?workflow=CI)
|
||||
[](https://codecov.io/gh/steambap/captcha)
|
||||
[](https://goreportcard.com/report/github.com/steambap/captcha)
|
||||
[](https://pkg.go.dev/concord.hectabit.org/HectaBit/captcha)
|
||||
[](https://goreportcard.com/report/concord.hectabit.org/HectaBit/captcha)
|
||||
|
||||
</div>
|
||||
|
||||
## Why another captcha generator?
|
||||
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.
|
||||
Because I can.
|
||||
|
||||
## install
|
||||
```
|
||||
go get github.com/steambap/captcha
|
||||
go get concord.hectabit.org/HectaBit/captcha
|
||||
```
|
||||
|
||||
## usage
|
||||
|
@ -32,8 +30,9 @@ func handle(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
```
|
||||
|
||||
[documentation](https://pkg.go.dev/github.com/steambap/captcha) |
|
||||
[example](example/basic/main.go)
|
||||
[documentation](https://pkg.go.dev/concord.hectabit.org/HectaBit/captcha) |
|
||||
[example](example/basic/main.go) |
|
||||
[font example](example/load-font/main.go)
|
||||
|
||||
## sample image
|
||||

|
||||
|
|
43
captcha.go
43
captcha.go
|
@ -62,7 +62,7 @@ func newDefaultOption(width, height int) *Options {
|
|||
return &Options{
|
||||
BackgroundColor: color.Transparent,
|
||||
CharPreset: charPreset,
|
||||
TextLength: 4,
|
||||
TextLength: 6,
|
||||
CurveNumber: 2,
|
||||
FontDPI: 72.0,
|
||||
FontScale: 1.0,
|
||||
|
@ -136,11 +136,7 @@ func New(width int, height int, option ...SetOption) (*Data, error) {
|
|||
|
||||
text := randomText(options)
|
||||
img := image.NewNRGBA(image.Rect(0, 0, width, height))
|
||||
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 {
|
||||
if err := drawWithOption(text, img, options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -157,21 +153,42 @@ func NewMathExpr(width int, height int, option ...SetOption) (*Data, error) {
|
|||
|
||||
text, equation := randomEquation()
|
||||
img := image.NewNRGBA(image.Rect(0, 0, width, height))
|
||||
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 {
|
||||
if err := drawWithOption(equation, img, options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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) {
|
||||
n := len(opts.CharPreset)
|
||||
n := len([]rune(opts.CharPreset))
|
||||
for i := 0; i < opts.TextLength; i++ {
|
||||
text += string(opts.CharPreset[rand.Intn(n)])
|
||||
text += string([]rune(opts.CharPreset)[rand.Intn(n)])
|
||||
}
|
||||
|
||||
return text
|
||||
|
|
|
@ -69,6 +69,12 @@ func TestNewCaptchaOptions(t *testing.T) {
|
|||
NewMathExpr(100, 34, func(options *Options) {
|
||||
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) {
|
||||
|
@ -78,6 +84,15 @@ 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) {
|
||||
temp := ttfFont
|
||||
ttfFont = nil
|
||||
|
@ -92,6 +107,13 @@ func TestNilFontError(t *testing.T) {
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module github.com/steambap/captcha/example/basic
|
||||
module concord.hectabit.org/HectaBit/captcha/example/basic
|
||||
|
||||
go 1.12
|
||||
|
||||
replace github.com/steambap/captcha => ../../
|
||||
replace concord.hectabit.org/HectaBit/captcha => ../../
|
||||
|
||||
require github.com/steambap/captcha v0.0.0-00010101000000-000000000000
|
||||
require concord.hectabit.org/HectaBit/captcha v0.0.0-00010101000000-000000000000
|
||||
|
|
6
go.mod
6
go.mod
|
@ -1,8 +1,8 @@
|
|||
module github.com/steambap/captcha
|
||||
module concord.hectabit.org/HectaBit/captcha
|
||||
|
||||
go 1.16
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
|
||||
golang.org/x/image v0.15.0
|
||||
)
|
||||
|
|
6
go.sum
6
go.sum
|
@ -1,6 +1,4 @@
|
|||
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=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
|
||||
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=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
|
|
Reference in a new issue