{"id":15035849,"url":"https://github.com/wenlng/go-captcha","last_synced_at":"2025-05-14T07:09:09.527Z","repository":{"id":37381183,"uuid":"387534990","full_name":"wenlng/go-captcha","owner":"wenlng","description":"🖖 GoCaptcha is a behavior captcha, which implements click mode, slider mode, drag-drop mode and rotation mode.","archived":false,"fork":false,"pushed_at":"2025-03-20T07:53:39.000Z","size":28474,"stargazers_count":1865,"open_issues_count":1,"forks_count":170,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-11T02:51:42.054Z","etag":null,"topics":["base64","base64-captcha","captcha","captcha-generator","click-captcha","drag-drop-captcha","go","golang","image-captcha","rotation-captcha","slider-captcha"],"latest_commit_sha":null,"homepage":"http://gocaptcha.wencodes.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wenlng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-19T16:52:43.000Z","updated_at":"2025-04-09T16:19:11.000Z","dependencies_parsed_at":"2024-06-18T13:55:08.464Z","dependency_job_id":"64abeaf1-d9ff-4e51-a294-7a5706b1457a","html_url":"https://github.com/wenlng/go-captcha","commit_stats":{"total_commits":28,"total_committers":1,"mean_commits":28.0,"dds":0.0,"last_synced_commit":"1f507178487fcad942570ca692ff2225a93a2935"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wenlng%2Fgo-captcha","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wenlng%2Fgo-captcha/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wenlng%2Fgo-captcha/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wenlng%2Fgo-captcha/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wenlng","download_url":"https://codeload.github.com/wenlng/go-captcha/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254092779,"owners_count":22013290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["base64","base64-captcha","captcha","captcha-generator","click-captcha","drag-drop-captcha","go","golang","image-captcha","rotation-captcha","slider-captcha"],"created_at":"2024-09-24T20:29:36.634Z","updated_at":"2025-05-14T07:09:04.516Z","avatar_url":"https://github.com/wenlng.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cimg width=\"120\" style=\"padding-top: 50px; margin: 0;\" src=\"http://47.104.180.148/go-captcha/gocaptcha_logo.svg?v=1\"/\u003e\n\u003ch1 style=\"margin: 0; padding: 0\"\u003eGo Captcha\u003c/h1\u003e\n\u003cp\u003eBehavior Captcha\u003c/p\u003e\n\u003ca href=\"https://goreportcard.com/report/github.com/wenlng/go-captcha\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/wenlng/go-captcha\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://godoc.org/github.com/wenlng/go-captcha\"\u003e\u003cimg src=\"https://godoc.org/github.com/wenlng/go-captcha?status.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/wenlng/go-captcha/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/wenlng/go-captcha.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/wenlng/go-captcha/blob/v2/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-Apache2.0-green.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/wenlng/go-captcha\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/wenlng/go-captcha.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/wenlng/go-captcha\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/wenlng/go-captcha.svg\"/\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003e English | [中文](README_zh.md)\n\n\u003cp style=\"text-align: center\"\u003e\u003ca href=\"https://github.com/wenlng/go-captcha\"\u003eGo Captcha\u003c/a\u003e is a behavior CAPTCHA, which implements click mode, slider mode, drag-drop mode and rotation mode.\u003c/p\u003e\n\n\u003cp style=\"text-align: center\"\u003e ⭐️ If it helps you, please give a star.\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e \n    \u003cimg src=\"http://47.104.180.148/go-captcha/go-captcha-v2.jpg\" alt=\"Poster\"\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n- GoCaptcha：[https://github.com/wenlng/go-captcha](https://github.com/wenlng/go-captcha)\n- GoCaptcha Document：[http://gocaptcha.wencodes.com](http://gocaptcha.wencodes.com)\n- Go Assets File：[https://github.com/wenlng/go-captcha-assets](https://github.com/wenlng/go-captcha-assets)\n- Example Project：[https://github.com/wenlng/go-captcha-example](https://github.com/wenlng/go-captcha-example)\n- Online Demo：[http://gocaptcha.wencodes.com/demo](http://gocaptcha.wencodes.com/demo)\n- Javascript Library：[https://github.com/wenlng/go-captcha-jslib](https://github.com/wenlng/go-captcha-jslib)\n- Vue Package：[https://github.com/wenlng/go-captcha-vue](https://github.com/wenlng/go-captcha-vue)\n- React Package：[https://github.com/wenlng/go-captcha-react](https://github.com/wenlng/go-captcha-react)\n- Angular Package：[https://github.com/wenlng/go-captcha-angular](https://github.com/wenlng/go-captcha-angular)\n- Svelte Package：[https://github.com/wenlng/go-captcha-svelte](https://github.com/wenlng/go-captcha-svelte)\n- Solid Package：[https://github.com/wenlng/go-captcha-solid](https://github.com/wenlng/go-captcha-solid)\n- UniApp Module：[https://github.com/wenlng/go-captcha-uni](https://github.com/wenlng/go-captcha-uni)\n- ...\n\n\u003cbr/\u003e\n\n## Install Module\n```shell\n$ go get -u github.com/wenlng/go-captcha/v2@latest\n```\n\n## Import Module\n```go\npackage main\n\nimport \"github.com/wenlng/go-captcha/v2\"\n\nfunc main(){\n   // ...\n}\n```\n\n\u003cbr /\u003e\n\n## 🖖 Click Mode\n### Quick Use\n```go\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"image\"\n\t\"log\"\n\t\"io/ioutil\"\n\n\t\"github.com/golang/freetype\"\n\t\"github.com/golang/freetype/truetype\"\n\t\"github.com/wenlng/go-captcha/v2/base/option\"\n\t\"github.com/wenlng/go-captcha/v2/click\"\n\t\"github.com/wenlng/go-captcha/v2/base/codec\"\n)\n\nvar textCapt click.Captcha\n\nfunc init() {\n\tbuilder := click.NewBuilder(\n\t\tclick.WithRangeLen(option.RangeVal{Min: 4, Max: 6}),\n\t\tclick.WithRangeVerifyLen(option.RangeVal{Min: 2, Max: 4}),\n\t)\n\n\t// You can use preset material resources：https://github.com/wenlng/go-captcha-assets\n\tfontN, err := loadFont(\"../resources/fzshengsksjw_cu.ttf\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tbgImage, err := loadPng(\"../resources/bg.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tbuilder.SetResources(\n\t\tclick.WithChars([]string{\n\t\t\t\"1A\",\n\t\t\t\"5E\",\n\t\t\t\"3d\",\n\t\t\t\"0p\",\n\t\t\t\"78\",\n\t\t\t\"DL\",\n\t\t\t\"CB\",\n\t\t\t\"9M\",\n\t\t\t// ...\n\t\t}),\n\t\tclick.WithFonts([]*truetype.Font{\n\t\t\tfontN,\n\t\t}),\n\t\tclick.WithBackgrounds([]image.Image{\n\t\t\tbgImage,\n\t\t}),\n\t)\n\n\ttextCapt= builder.Make()\n}\n\nfunc loadPng(p string) (image.Image, error) {\n\timgBytes, err := ioutil.ReadFile(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn codec.DecodeByteToPng(imgBytes)\n}\n\nfunc loadFont(p string) (*truetype.Font, error) {\n\tfontBytes, err := ioutil.ReadFile(p)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn freetype.ParseFont(fontBytes)\n}\n\n\nfunc main() {\n\tcaptData, err := textCapt.Generate()\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tdotData := captData.GetData()\n\tif dotData == nil {\n\t\tlog.Fatalln(\"\u003e\u003e\u003e\u003e\u003e generate err\")\n\t}\n\n\tdots, _ := json.Marshal(dotData)\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", string(dots))\n\n\tvar mBase64, tBase64 string\n\tmBase64, err = captData.GetMasterImage().ToBase64()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\ttBase64, err = captData.GetThumbImage().ToBase64()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\t\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", mBase64)\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", tBase64)\n\t\n\t//err = captData.GetMasterImage().SaveToFile(\"../resources/master.jpg\", option.QualityNone)\n\t//if err != nil {\n\t//\tfmt.Println(err)\n\t//}\n\t//err = captData.GetThumbImage().SaveToFile(\"../resources/thumb.png\")\n\t//if err != nil {\n\t//\tfmt.Println(err)\n\t//}\n}\n```\n\n### Make Instance\n- builder.Make()\n- builder.MakeWithShape()\n\n### Configuration Options\n\u003e click.NewBuilder(click.WithXxx(), ...) OR builder.SetOptions(click.WithXxx(), ...)\n- click.WithImageSize(option.Size)\n- click.WithRangeLen(option.RangeVal) \n- click.WithRangeAnglePos([]option.RangeVal) \n- click.WithRangeSize(option.RangeVal)\n- click.WithRangeColors([]string) \n- click.WithDisplayShadow(bool) \n- click.WithShadowColor(string) \n- click.WithShadowPoint(option.Point)\n- click.WithImageAlpha(float32) \n- click.WithUseShapeOriginalColor(bool)\n\n- click.WithThumbImageSize(option.Size)\n- click.WithRangeVerifyLen(option.RangeVal)\n- click.WithDisabledRangeVerifyLen(bool)\n- click.WithRangeThumbSize(option.RangeVal)\n- click.WithRangeThumbColors([]string)\n- click.WithRangeThumbBgColors([]string)\n- click.WithIsThumbNonDeformAbility(bool)\n- click.WithThumbBgDistort(int) \n- click.WithThumbBgCirclesNum(int) \n- click.WithThumbBgSlimLineNum(int) \n\n\n### Set Resources\n\u003e builder.SetResources(click.WithXxx(), ...)\n- click.WithChars([]string) \n- click.WithShapes(map[string]image.Image) \n- click.WithFonts([]*truetype.Font) \n- click.WithBackgrounds([]image.Image) \n- click.WithThumbBackgrounds([]image.Image) \n\n### Captcha Data\n- GetData() map[int]*Dot\n- GetMasterImage() imagedata.JPEGImageData\n- GetThumbImage() imagedata.PNGImageData\n\n\u003cbr /\u003e\n\n## 🖖 Slider  Or Drag-Drop Mode\n### Quick Use\n```go\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"image\"\n\t\"log\"\n\t\"io/ioutil\"\n\n\t\"github.com/wenlng/go-captcha/v2/base/option\"\n\t\"github.com/wenlng/go-captcha/v2/slide\"\n\t\"github.com/wenlng/go-captcha/v2/base/codec\"\n)\n\nvar slideTileCapt slide.Captcha\n\nfunc init() {\n\tbuilder := slide.NewBuilder()\n\n\t// You can use preset material resources：https://github.com/wenlng/go-captcha-assets\n\tbgImage, err := loadPng(\"../resources/bg.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tbgImage1, err := loadPng(\"../resources/bg1.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tgraphs := getSlideTileGraphArr()\n\n\tbuilder.SetResources(\n\t\tslide.WithGraphImages(graphs),\n\t\tslide.WithBackgrounds([]image.Image{\n\t\t\tbgImage,\n\t\t\tbgImage1,\n\t\t}),\n\t)\n\n\tslideTileCapt = builder.Make()\n}\n\nfunc getSlideTileGraphArr() []*slide.GraphImage {\n\ttileImage1, err := loadPng(\"../resources/tile-1.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\ttileShadowImage1, err := loadPng(\"../resources/tile-shadow-1.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\ttileMaskImage1, err := loadPng(\"../resources/tile-mask-1.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\treturn []*slide.GraphImage{\n\t\t{\n\t\t\tOverlayImage: tileImage1,\n\t\t\tShadowImage:  tileShadowImage1,\n\t\t\tMaskImage:    tileMaskImage1,\n\t\t},\n\t}\n}\n\nfunc main() {\n\tcaptData, err := slideTileCapt.Generate()\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tblockData := captData.GetData()\n\tif blockData == nil {\n\t\tlog.Fatalln(\"\u003e\u003e\u003e\u003e\u003e generate err\")\n\t}\n\n\tblock, _ := json.Marshal(blockData)\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e\", string(block))\n\n\tvar mBase64, tBase64 string\n\tmBase64, err = captData.GetMasterImage().ToBase64()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\ttBase64, err = captData.GetTileImage().ToBase64()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", mBase64)\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", tBase64)\n\t\n\t//err = captData.GetMasterImage().SaveToFile(\"../resources/master.jpg\", option.QualityNone)\n\t//if err != nil {\n\t//\tfmt.Println(err)\n\t//}\n\t//err = captData.GetTileImage().SaveToFile(\"../resources/thumb.png\")\n\t//if err != nil {\n\t//\tfmt.Println(err)\n\t//}\n}\n\nfunc loadPng(p string) (image.Image, error) {\n\timgBytes, err := ioutil.ReadFile(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn codec.DecodeByteToPng(imgBytes)\n}\n```\n\n\n### Make Instance\n- builder.Make()\n- builder.MakeWithRegion() \n\n\n### Configuration Options\n\u003e slide.NewBuilder(slide.WithXxx(), ...) OR builder.SetOptions(slide.WithXxx(), ...)\n- slide.WithImageSize(*option.Size)\n- slide.WithImageAlpha(float32) \n- slide.WithRangeGraphSize(val option.RangeVal) \n- slide.WithRangeGraphAnglePos([]option.RangeVal) \n- slide.WithGenGraphNumber(val int)\n- slide.WithEnableGraphVerticalRandom(val bool) \n- slide.WithRangeDeadZoneDirections(val []DeadZoneDirectionType) \n\n\n### Set Resources\nbuilder.SetResources(slide.WithXxx(), ...)\n- slide.WithBackgrounds([]image.Image) \n- slide.WithGraphImages(images []*GraphImage)\n\n### Captcha Data\n- GetData() *Block\n- GetMasterImage() imagedata.JPEGImageData\n- GetTileImage() imagedata.PNGImageData\n\n\n\u003cbr /\u003e\n\n## 🖖 Rotation Mode\n### Quick Use\n```go\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"image\"\n\t\"log\"\n\t\"io/ioutil\"\n\n\t\"github.com/wenlng/go-captcha/v2/rotate\"\n\t\"github.com/wenlng/go-captcha/v2/base/codec\"\n)\n\nvar rotateCapt rotate.Captcha\n\nfunc init() {\n\tbuilder := rotate.NewBuilder()\n\n\t// You can use preset material resources：https://github.com/wenlng/go-captcha-assets\n\tbgImage, err := loadPng(\"../resources/bg.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tbgImage1, err := loadPng(\"../resources/bg1.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tbuilder.SetResources(\n\t\trotate.WithImages([]image.Image{\n\t\t\tbgImage,\n\t\t\tbgImage1,\n\t\t}),\n\t)\n\n\trotateCapt = builder.Make()\n}\n\nfunc main() {\n\tcaptData, err := rotateCapt.Generate()\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tblockData := captData.GetData()\n\tif blockData == nil {\n\t\tlog.Fatalln(\"\u003e\u003e\u003e\u003e\u003e generate err\")\n\t}\n\n\tblock, _ := json.Marshal(blockData)\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e\", string(block))\n\n\tvar mBase64, tBase64 string\n\tmBase64, err = captData.GetMasterImage().ToBase64()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\ttBase64, err = captData.GetThumbImage().ToBase64()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", mBase64)\n\tfmt.Println(\"\u003e\u003e\u003e\u003e\u003e \", tBase64)\n\t\n\t//err = captData.GetMasterImage().SaveToFile(\"../resources/master.png\")\n\t//if err != nil {\n\t//\tfmt.Println(err)\n\t//}\n\t//err = captData.GetThumbImage().SaveToFile(\"../resources/thumb.png\")\n\t//if err != nil {\n\t//\tfmt.Println(err)\n\t//}\n}\n\nfunc loadPng(p string) (image.Image, error) {\n\timgBytes, err := ioutil.ReadFile(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn codec.DecodeByteToPng(imgBytes)\n}\n```\n\n\n### Make Instance\n- builder.Make()\n\n\n### Configuration Options\n\u003e rotate.NewBuilder(rotate.WithXxx(), ...) OR builder.SetOptions(rotate.WithXxx(), ...)\n- rotate.WithImageSquareSize(val int) \n- rotate.WithRangeAnglePos(vals []option.RangeVal)\n- rotate.WithRangeThumbImageSquareSize(val []int) \n- rotate.WithThumbImageAlpha(val float32)\n\n\n### Set Resources\nbuilder.SetResources(rotate.WithXxx(), ...)\n- rotate.WithBackgrounds([]image.Image)\n\n### Captcha Data\n- GetData() *Block\n- GetMasterImage() imagedata.PNGImageData\n- GetThumbImage() imagedata.PNGImageData\n\n\u003cbr/\u003e\n\n## Captcha Image Data\n### Object Method Of JPEGImageData\n- Get() image.Image\n- ToBytes() ([]byte, error)\n- ToBytesWithQuality(imageQuality int) ([]byte, error)\n- ToBase64() (string, error)\n- ToBase64Data() (string, error)\n- ToBase64WithQuality(imageQuality int) (string, error)\n- ToBase64DataWithQuality(imageQuality int) (string, error)\n- SaveToFile(filepath string, quality int) error\n\n\n### Object Method Of PNGImageData\n- Get() image.Image \n- ToBytes() ([]byte, error)\n- ToBase64() (string, error)\n- ToBase64Data() (string, error)\n- SaveToFile(filepath string) error\n\n\u003cbr/\u003e\n\n## Language Support\n- [x] Golang\n- [ ] NodeJs\n- [ ] Rust\n\n## Install Package\n- [x] JavaScript\n- [x] Vue \n- [x] React\n- [x] Angular\n- [x] Svelte\n- [x] Solid\n- [x] UniApp\n- [ ] WX-Applet\n- [ ] React Native App\n- [ ] Flutter App\n- [ ] Android App\n- [ ] IOS App\n- [ ] ... \n\n\u003cbr/\u003e\n\n## LICENSE\nGo Captcha source code is licensed under the Apache Licence, Version 2.0 [http://www.apache.org/licenses/LICENSE-2.0.html](http://www.apache.org/licenses/LICENSE-2.0.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwenlng%2Fgo-captcha","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwenlng%2Fgo-captcha","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwenlng%2Fgo-captcha/lists"}