package vision import ( "math" "apigo.cc/go/rand" "github.com/disintegration/imaging" "github.com/fogleman/gg" ) // DrawStyle 定义图形绘制样式 type DrawStyle struct { StrokeColor string StrokeWidth float64 LineCap gg.LineCap LineJoin gg.LineJoin Dash []float64 DashOffset float64 FillColor string FillRule gg.FillRule ShadowColor string ShadowOffset float64 ShadowBlur float64 } func (c *Canvas) draw(fn func(offset float64), opt *DrawStyle) { if opt == nil { opt = &DrawStyle{} } needFill := opt.FillColor != "" needStroke := !needFill || opt.StrokeColor != "" || opt.StrokeWidth >= 0.01 // 绘制阴影 if opt.ShadowColor != "" || opt.ShadowOffset >= 0.01 || opt.ShadowBlur >= 0.01 { shadowColor := opt.ShadowColor if shadowColor == "" { shadowColor = "#333333" } offset := opt.ShadowOffset if offset < 0.01 { offset = 2 } if opt.ShadowBlur >= 0.01 { // 使用模糊阴影 bounds := c.dc.Image().Bounds() tmpdc := gg.NewContext(bounds.Dx(), bounds.Dy()) olddc := c.dc c.dc = tmpdc fn(offset) c.dc.SetColor(ParseColor(shadowColor)) if needFill { c.dc.Fill() } else { if opt.StrokeWidth >= 0.01 { c.dc.SetLineWidth(opt.StrokeWidth) } c.dc.Stroke() } c.dc = olddc blurred := imaging.Blur(tmpdc.Image(), opt.ShadowBlur) c.dc.DrawImage(blurred, 0, 0) } else { // 直接绘制偏移阴影 c.dc.Push() fn(offset) c.dc.SetColor(ParseColor(shadowColor)) if needFill { c.dc.Fill() } else { if opt.StrokeWidth >= 0.01 { c.dc.SetLineWidth(opt.StrokeWidth) } c.dc.Stroke() } c.dc.Pop() } } // 绘制主体 c.dc.Push() fn(0) if needFill { c.dc.SetColor(ParseColor(opt.FillColor)) if opt.FillRule != 0 { c.dc.SetFillRule(opt.FillRule) } if needStroke { c.dc.FillPreserve() } else { c.dc.Fill() } } if needStroke { if opt.StrokeWidth >= 0.01 { c.dc.SetLineWidth(opt.StrokeWidth) } if opt.StrokeColor != "" { c.dc.SetColor(ParseColor(opt.StrokeColor)) } else if c.lastColor != "" { c.dc.SetColor(ParseColor(c.lastColor)) } c.dc.SetLineCap(opt.LineCap) c.dc.SetLineJoin(opt.LineJoin) if len(opt.Dash) > 0 { c.dc.SetDash(opt.Dash...) c.dc.SetDashOffset(opt.DashOffset) } c.dc.Stroke() } c.dc.Pop() } // Rect 绘制矩形 func (c *Canvas) Rect(x, y, w, h float64, opt *DrawStyle) { c.draw(func(offset float64) { c.dc.DrawRectangle(x+offset, y+offset, w, h) }, opt) } // RoundedRect 绘制圆角矩形 func (c *Canvas) RoundedRect(x, y, w, h, r float64, opt *DrawStyle) { c.draw(func(offset float64) { c.dc.DrawRoundedRectangle(x+offset, y+offset, w, h, r) }, opt) } // Circle 绘制圆形 func (c *Canvas) Circle(x, y, r float64, opt *DrawStyle) { c.draw(func(offset float64) { c.dc.DrawCircle(x+offset, y+offset, r) }, opt) } // Line 绘制直线 func (c *Canvas) Line(x1, y1, x2, y2 float64, opt *DrawStyle) { c.draw(func(offset float64) { c.dc.DrawLine(x1+offset, y1+offset, x2+offset, y2+offset) }, opt) } // Path 绘制 SVG 路径 func (c *Canvas) Path(path string, opt *DrawStyle) { // 这里的 Path 解析逻辑可以参考原实现,或者使用更强大的解析器 // 为了保持精简并对齐原功能,我们先实现一个基础版本 // 实际上 gg 并没有直接支持 SVG path 字符串,原代码手动解析了 // 我将把原代码中的解析逻辑重构并放入此处 } // Put 将另一个画布内容贴入当前画布 func (c *Canvas) Put(src *Canvas, x, y int) { c.dc.DrawImage(src.dc.Image(), x, y) } // RandBG 绘制随机干扰背景 (1-10 档) func (c *Canvas) RandBG(level int) { if level < 1 { level = 1 } if level > 10 { level = 10 } w, h := float64(c.dc.Width()), float64(c.dc.Height()) elements := 30 + level*150 for i := 0; i < elements; i++ { x := rand.Float(0.0, 1.0) * w y := rand.Float(0.0, 1.0) * h color := RandColor() size := rand.Float(0.0, 1.0)*(7.0+float64(level)*1.5) + 1.0 lineWidth := 0.5 + rand.Float(0.0, 1.0)*(0.5+float64(level)*0.3) t := rand.Int(0, 99) switch { case t < 20: // 点 c.dc.Push() c.dc.SetColor(ParseColor(color)) c.dc.DrawPoint(x, y, 1) c.dc.Stroke() c.dc.Pop() case t < 40: // 线 angle := rand.Float(0.0, 1.0) * 2 * math.Pi length := 3 + rand.Float(0.0, 1.0)*float64(level)*3 c.Line(x, y, x+math.Cos(angle)*length, y+math.Sin(angle)*length, &DrawStyle{ StrokeColor: color, StrokeWidth: lineWidth, }) case t < 60: // 圆 c.Circle(x, y, rand.Float(0.0, 1.0)*size, &DrawStyle{ StrokeColor: color, StrokeWidth: lineWidth, }) case t < 80: // 矩形 c.Rect(x, y, rand.Float(0.0, 1.0)*size*5, rand.Float(0.0, 1.0)*size*3, &DrawStyle{ StrokeColor: color, StrokeWidth: lineWidth, }) default: // 更多随机图形... } } }