mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 15:06:46 +08:00
This commit is contained in:
1 parent
537b5779e1
commit
bed08b2c4b
2 files changed
+75
-3
No files matched your search
+10
-3
@@ -223,6 +223,14 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
fillPaint, shadingClip, fillView := resolveShdPaint(ctx, style.fillPaint)
|
||||
fillClip := intersectClipPath(clipPath, shadingClip)
|
||||
fp := p
|
||||
_, repeat := fillPaint.(*repeatAxialGradient)
|
||||
if fillClip != nil || repeat {
|
||||
paths := canvas.Paths(p.Copy().Split())
|
||||
for _, path := range paths {
|
||||
path.Close()
|
||||
}
|
||||
fp = paths.Merge()
|
||||
}
|
||||
fillRule := canvas.NonZero
|
||||
if obj.Rule == "Even-Odd" {
|
||||
fillRule = canvas.EvenOdd
|
||||
@@ -231,8 +239,6 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
}
|
||||
}
|
||||
if fillClip != nil {
|
||||
fp = fp.Copy()
|
||||
fp.Close()
|
||||
fp = applyClipPath(fp, fillClip)
|
||||
}
|
||||
if style.fillPattern != nil {
|
||||
@@ -268,7 +274,8 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
ctx.SetDashes(0)
|
||||
}
|
||||
strokeClip := intersectClipPath(clipPath, shadingClip)
|
||||
if strokeClip != nil || strokeView != canvas.Identity || style.strokePattern != nil {
|
||||
_, repeat := strokePaint.(*repeatAxialGradient)
|
||||
if strokeClip != nil || strokeView != canvas.Identity || repeat || style.strokePattern != nil {
|
||||
sp = sp.Copy()
|
||||
sp = sp.Stroke(style.lineWidth, style.lineCap, style.lineJoin, canvas.Tolerance)
|
||||
sp = applyClipPath(sp, strokeClip)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package ofdgo
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
@@ -29,6 +30,28 @@ type shdPaint struct {
|
||||
period float64
|
||||
}
|
||||
|
||||
// repeatAxialGradient 轴向重复渐变
|
||||
type repeatAxialGradient struct {
|
||||
*canvas.LinearGradient
|
||||
period float64
|
||||
}
|
||||
|
||||
// At 获取重复区间内的渐变颜色
|
||||
// 入参: x X坐标, y Y坐标
|
||||
// 返回: color.RGBA 渐变颜色
|
||||
func (g *repeatAxialGradient) At(x, y float64) color.RGBA {
|
||||
d := g.End.Sub(g.Start)
|
||||
t := (canvas.Point{X: x, Y: y}).Sub(g.Start).Dot(d) / d.Dot(d) / g.period
|
||||
return g.Grad.At(t - math.Floor(t))
|
||||
}
|
||||
|
||||
// SetColorSpace 转换重复渐变颜色空间
|
||||
// 入参: space 颜色空间
|
||||
// 返回: canvas.Gradient 渐变对象
|
||||
func (g *repeatAxialGradient) SetColorSpace(space canvas.ColorSpace) canvas.Gradient {
|
||||
return &repeatAxialGradient{LinearGradient: g.LinearGradient.SetColorSpace(space).(*canvas.LinearGradient), period: g.period}
|
||||
}
|
||||
|
||||
// newShdPaint 创建渐变画刷
|
||||
// 入参: gradient 渐变对象, extend 延伸方向, mapType 绘制方式, mapUnit 渐变区间长度
|
||||
// 返回: *shdPaint 渐变画刷
|
||||
@@ -66,6 +89,9 @@ func resolveShdPaint(ctx *canvas.Context, paint any) (any, *canvas.Path, canvas.
|
||||
if clip != nil && s.view != canvas.Identity {
|
||||
clip = clip.Transform(s.view)
|
||||
}
|
||||
if s.mapType == "Repeat" {
|
||||
return &repeatAxialGradient{LinearGradient: g, period: s.period}, clip, s.view
|
||||
}
|
||||
if s.mapType != "Reflect" {
|
||||
return g, clip, s.view
|
||||
}
|
||||
@@ -135,6 +161,10 @@ func transformShdPaint(paint any, parentCTM *Matrix, bx, by, pageH float64, boun
|
||||
// drawShdPath 绘制渐变路径并保持图形轮廓不变
|
||||
// 入参: ctx 画布上下文, path 填充路径, view 渐变变换
|
||||
func drawShdPath(ctx *canvas.Context, path *canvas.Path, view canvas.Matrix) {
|
||||
if gradient, ok := ctx.Style.Fill.Gradient.(*repeatAxialGradient); ok {
|
||||
drawRepeatAxialPath(ctx, path, gradient, view)
|
||||
return
|
||||
}
|
||||
if view == canvas.Identity {
|
||||
ctx.DrawPath(0, 0, path)
|
||||
return
|
||||
@@ -144,6 +174,41 @@ func drawShdPath(ctx *canvas.Context, path *canvas.Path, view canvas.Matrix) {
|
||||
ctx.RenderPath(path.Copy().Transform(view.Inv()), ctx.Style, m)
|
||||
}
|
||||
|
||||
// drawRepeatAxialPath 按周期裁剪并绘制轴向重复渐变
|
||||
// 入参: ctx 画布上下文, path 填充路径, gradient 重复渐变, view 渐变变换
|
||||
func drawRepeatAxialPath(ctx *canvas.Context, path *canvas.Path, gradient *repeatAxialGradient, view canvas.Matrix) {
|
||||
p := path.Copy()
|
||||
if ctx.FillRule == canvas.EvenOdd {
|
||||
p = p.Settle(canvas.EvenOdd)
|
||||
}
|
||||
p = p.Transform(view.Inv())
|
||||
d := gradient.End.Sub(gradient.Start).Mul(gradient.period)
|
||||
axis := canvas.Matrix{{d.X, -d.Y, gradient.Start.X}, {d.Y, d.X, gradient.Start.Y}}
|
||||
bounds := p.FastBounds().And(shdCanvasBounds(ctx).Transform(view.Inv()))
|
||||
area := bounds.Transform(axis.Inv())
|
||||
origin := ctx.CoordView().Dot(canvas.Point{})
|
||||
m := ctx.CoordSystemView().Mul(ctx.View()).Translate(origin.X, origin.Y).Mul(view)
|
||||
style := ctx.Style
|
||||
style.FillRule = canvas.NonZero
|
||||
stops := gradient.Grad
|
||||
if stops[0].Offset > 0 {
|
||||
stops = append(canvas.Grad{{Offset: 0, Color: stops[0].Color}}, stops...)
|
||||
}
|
||||
if last := stops[len(stops)-1]; last.Offset < 1 {
|
||||
stops = append(append(canvas.Grad(nil), stops...), canvas.Stop{Offset: 1, Color: last.Color})
|
||||
}
|
||||
for i, end := math.Floor(area.X0), math.Ceil(area.X1); i < end; i++ {
|
||||
clip := (canvas.Rect{X0: i, Y0: area.Y0, X1: i + 1, Y1: area.Y1}).ToPath().Transform(axis)
|
||||
part := applyClipPath(p, clip)
|
||||
if part.Empty() {
|
||||
continue
|
||||
}
|
||||
start := gradient.Start.Add(d.Mul(i))
|
||||
style.Fill = canvas.Paint{Gradient: stops.ToLinear(start, start.Add(d))}
|
||||
ctx.RenderPath(part, style, m)
|
||||
}
|
||||
}
|
||||
|
||||
// rangeLimits 限制渐变延伸区间
|
||||
// 入参: lo 区间起点, hi 区间终点
|
||||
// 返回: float64 起点, float64 终点
|
||||
|
||||
Reference in new issue
Block a user