package vision import ( "image" "image/color" "image/draw" "github.com/fogleman/gg" ) // JigsawResult 滑块拼图结果 type JigsawResult struct { Background *Canvas // 带槽口的背景 Piece *Canvas // 拼图块 X, Y int // 槽口位置 } // GenerateJigsaw 生成滑块拼图物料 func (c *Canvas) GenerateJigsaw(x, y, size int) *JigsawResult { sw, sh := c.Width(), c.Height() if x < 0 { x = 0 } if y < 0 { y = 0 } if x+size > sw { x = sw - size } if y+size > sh { y = sh - size } // 1. 创建背景副本并绘制槽口 bg := c.Clone() piece := New(size, size) // 定义拼图路径 (带有四个圆润突起/凹陷的拼图块形状) drawPuzzlePath := func(dc *gg.Context, px, py, s float64) { r := s / 4.0 dc.MoveTo(px, py) dc.LineTo(px+s/2-r, py) dc.QuadraticTo(px+s/2, py-r*1.5, px+s/2+r, py) // 上凸起 dc.LineTo(px+s, py) dc.LineTo(px+s, py+s/2-r) dc.QuadraticTo(px+s+r*1.5, py+s/2, px+s, py+s/2+r) // 右凸起 dc.LineTo(px+s, py+s) dc.LineTo(px+s/2+r, py+s) dc.QuadraticTo(px+s/2, py+s-r*1.5, px+s/2-r, py+s) // 下凹陷 (可以改反向) dc.LineTo(px, py+s) dc.LineTo(px, py+s/2+r) dc.QuadraticTo(px-r*1.5, py+s/2, px, py+s/2-r) // 左凹陷 dc.ClosePath() } // 2. 提取拼图块内容 // 我们需要一个蒙版来裁剪 mask := gg.NewContext(sw, sh) drawPuzzlePath(mask, float64(x), float64(y), float64(size)) mask.SetFillRule(gg.FillRuleWinding) mask.Fill() // 裁剪 Piece draw.DrawMask(piece.dc.Image().(draw.Image), image.Rect(0, 0, size, size), c.dc.Image(), image.Pt(x, y), mask.Image(), image.Pt(x, y), draw.Src) // 3. 在背景上绘制半透明槽口 (遮罩) bg.dc.Push() drawPuzzlePath(bg.dc, float64(x), float64(y), float64(size)) bg.dc.SetColor(color.RGBA{0, 0, 0, 160}) bg.dc.Fill() bg.dc.Pop() // 4. 给拼图块加一点描边或投影增强识别度 piece.dc.Push() drawPuzzlePath(piece.dc, 0, 0, float64(size)) piece.dc.SetColor(color.RGBA{255, 255, 255, 128}) piece.dc.SetLineWidth(2) piece.dc.Stroke() piece.dc.Pop() return &JigsawResult{ Background: bg, Piece: piece, X: x, Y: y, } }