滑动/拖拽验证码(Slide/Drag-Drop) 
滑动验证码要求用户将拼图块滑动到主图像中的正确位置,支持两种模式:
- 基本模式:拼图块沿固定 Y 轴滑动,适合简单验证场景。
 - 拖拽模式:拼图块可以在更大范围内自由拖动,适合需要更高交互自由度的场景。
 
工作原理 
- 生成主图像(
masterImage):包含拼图块的缺口和阴影效果,通常为 JPEG 格式。 - 生成拼图图像(
tileImage):用户需要滑动的拼图块,通常为 PNG 格式。 - 用户交互:用户滑动拼图块到目标位置(
TileX,TileY),前端捕获滑动终点坐标。 - 验证逻辑:后端比较用户滑动的位置与目标位置是否匹配。
 
安装 
shell
$ go get -u github.com/wenlng/go-captcha/v2@latest$ go get -u github.com/wenlng/go-captcha/v2@latest安装预置内嵌素材资源
shell
$ go get -u github.com/wenlng/go-captcha-assets@latest$ go get -u github.com/wenlng/go-captcha-assets@latest实例 
go
package main
import (
	"encoding/json"
	"fmt"
	"log"
	"github.com/golang/freetype/truetype"
	"github.com/wenlng/go-captcha-assets/resources/imagesv2"
	"github.com/wenlng/go-captcha-assets/resources/tiles"
	"github.com/wenlng/go-captcha/v2/base/option"
	"github.com/wenlng/go-captcha/v2/slide"
)
var slideCapt slide.Captcha
func init() {
  builder := slide.NewBuilder(
		// slide.WithGenGraphNumber(2),
		// slide.WithEnableGraphVerticalRandom(true),
	)
	// background images
	imgs, err := imagesv2.GetImages()
	if err != nil {
		log.Fatalln(err)
	}
	graphs, err := tiles.GetTiles()
	if err != nil {
		log.Fatalln(err)
	}
	var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
	for i := 0; i < len(graphs); i++ {
		graph := graphs[i]
		newGraphs = append(newGraphs, &slide.GraphImage{
			OverlayImage: graph.OverlayImage,
			MaskImage:    graph.MaskImage,
			ShadowImage:  graph.ShadowImage,
		})
	}
	// set resources
	builder.SetResources(
		slide.WithGraphImages(newGraphs),
		slide.WithBackgrounds(imgs),
	)
	
	slideCapt = builder.Make()
}
func main() {
	captData, err := slideCapt.Generate()
	if err != nil {
		log.Fatalln(err)
	}
	dotData := captData.GetData()
	if dotData == nil {
		log.Fatalln(">>>>> generate err")
	}
	dots, _ := json.Marshal(dotData)
	fmt.Println(">>>>> ", string(dots))
	var mBase64, tBase64 string
	mBase64, err = captData.GetMasterImage().ToBase64()
	if err != nil {
		fmt.Println(err)
	}
	tBase64, err = captData.GetTileImage().ToBase64()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(">>>>> ", mBase64)
	fmt.Println(">>>>> ", tBase64)
	
	// err = captData.GetMasterImage().SaveToFile("./.caches/master.jpg", option.QualityNone)
	// if err != nil {
	// 	fmt.Println(err)
	// }
	// err = captData.GetTileImage().SaveToFile("./.caches/thumb.png")
	// if err != nil {
	// 	fmt.Println(err)
	// }
}package main
import (
	"encoding/json"
	"fmt"
	"log"
	"github.com/golang/freetype/truetype"
	"github.com/wenlng/go-captcha-assets/resources/imagesv2"
	"github.com/wenlng/go-captcha-assets/resources/tiles"
	"github.com/wenlng/go-captcha/v2/base/option"
	"github.com/wenlng/go-captcha/v2/slide"
)
var slideCapt slide.Captcha
func init() {
  builder := slide.NewBuilder(
		// slide.WithGenGraphNumber(2),
		// slide.WithEnableGraphVerticalRandom(true),
	)
	// background images
	imgs, err := imagesv2.GetImages()
	if err != nil {
		log.Fatalln(err)
	}
	graphs, err := tiles.GetTiles()
	if err != nil {
		log.Fatalln(err)
	}
	var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
	for i := 0; i < len(graphs); i++ {
		graph := graphs[i]
		newGraphs = append(newGraphs, &slide.GraphImage{
			OverlayImage: graph.OverlayImage,
			MaskImage:    graph.MaskImage,
			ShadowImage:  graph.ShadowImage,
		})
	}
	// set resources
	builder.SetResources(
		slide.WithGraphImages(newGraphs),
		slide.WithBackgrounds(imgs),
	)
	
	slideCapt = builder.Make()
}
func main() {
	captData, err := slideCapt.Generate()
	if err != nil {
		log.Fatalln(err)
	}
	dotData := captData.GetData()
	if dotData == nil {
		log.Fatalln(">>>>> generate err")
	}
	dots, _ := json.Marshal(dotData)
	fmt.Println(">>>>> ", string(dots))
	var mBase64, tBase64 string
	mBase64, err = captData.GetMasterImage().ToBase64()
	if err != nil {
		fmt.Println(err)
	}
	tBase64, err = captData.GetTileImage().ToBase64()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(">>>>> ", mBase64)
	fmt.Println(">>>>> ", tBase64)
	
	// err = captData.GetMasterImage().SaveToFile("./.caches/master.jpg", option.QualityNone)
	// if err != nil {
	// 	fmt.Println(err)
	// }
	// err = captData.GetTileImage().SaveToFile("./.caches/thumb.png")
	// if err != nil {
	// 	fmt.Println(err)
	// }
}使用 
创建实例 
- builder.Make() 滑动式
 - builder.MakeWithRegion() 区域内拖拽滑动式
 
配置 
TIP
配置举例:slide.NewBuilder(slide.WithXxxx(), slide.WithXxxx(), ....) 或 builder.SetOptions(slide.WithXxxx(), slide.WithXxxx(), ....)
| Options | Desc | 
|---|---|
| slide.WithImageSize(*option.Size) | 设置主图尺寸,默认 300x220 | 
| slide.WithImageAlpha(float32) | 设置主图透明度 | 
| slide.WithRangeGraphSize(val option.RangeVal) | 设置图形随机尺寸范围 | 
| slide.WithRangeGraphAnglePos([]option.RangeVal) | 设置图形随机角度范围 | 
| slide.WithGenGraphNumber(val int) | 设置图形个数 | 
| slide.WithEnableGraphVerticalRandom(val bool) | 设置图形水平方向是否随机排序 | 
| slide.WithRangeDeadZoneDirections(val []DeadZoneDirectionType) | 设置贴图盲区 | 
设置资源 
TIP
配置举例:builder.SetResources(slide.WithXxxx(), slide.WithXxxx(), ....)
| Options | Desc | 
|---|---|
| slide.WithBackgrounds([]image.Image) | 设置主图背景 | 
| slide.WithGraphImages(images []*GraphImage) | 设置贴图的图形 | 
验证码数据 
TIP
captData, err := capt.Generate()
| Method | Desc | 
|---|---|
| GetData() *Block | 获取当前校验的信息 | 
| GetMasterImage() imagedata.JPEGImageData | 获取主图 | 
| GetTileImage() imagedata.PNGImageData | 获取缩略图 | 
图像实例 
TIP
通过 Generate() 生成的数据,有图像实例 JPEG、PNG 两种格式,分别为 JPEGImageData 和 PNGImageData
JPEGImageData 
- Get() image.Image 获取原图像
 - ToBytes() ([]byte, error) 转为字节数组
 - ToBytesWithQuality(imageQuality int) ([]byte, error) 指定清晰度转为字节数组
 - ToBase64() (string, error) 转为 Base64 字符串,带 "data:image/jpeg;base64," 前缀
 - ToBase64Data() (string, error) 转为 Base64 字符串
 - ToBase64WithQuality(imageQuality int) (string, error) 指定清晰度转为 Base64 字符串,带 "data:image/jpeg;base64," 前缀
 - ToBase64DataWithQuality(imageQuality int) (string, error) 指定清晰度转为 Base64 字符串
 - SaveToFile(filepath string, quality int) error 保存 JPEG 到文件
 
PNGImageData 
- Get() image.Image 获取原图像
 - ToBytes() ([]byte, error) 转为字节数组
 - ToBase64() (string, error) 转为 Base64 字符串,带 "data:image/png;base64," 前缀
 - ToBase64Data() (string, error) 转为 Base64 字符串
 - SaveToFile(filepath string) error 保存 到文件
 
验证码校验 
TIP
ok := slide.Validate(srcX, srcY, X, Y, paddingValue)
| Params | Desc | 
|---|---|
| srcX | 用户交互的 X 值 | 
| srcY | 用户交互的 Y 值 | 
| X | 验证码校验的 X 值 | 
| Y | 验证码校验的 Y 值 | 
| paddingValue | 控制误差值 | 
注意事项 
- 拼图块的图像资源(
OverlayImage,ShadowImage,MaskImage)必须有效,否则会触发ImageTypeErr,ShadowImageTypeErr或MaskImageTypeErr。 - 背景图像不能为空,否则会触发 
EmptyBackgroundImageErr。 - 基本模式下,拼图块的 Y 坐标固定;拖拽模式下,Y 坐标可根据 
rangeDeadZoneDirections随机分布。 - 拖拽模式适合需要更