mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 14:53:44 +08:00
This commit is contained in:
1 parent
f27c5b666e
commit
3cd6cb3afd
5 files changed
+67
-42
No files matched your search
@@ -196,6 +196,8 @@ type AxialShd struct {
|
||||
type RadialShd struct {
|
||||
MapType string `xml:"MapType,attr"`
|
||||
MapUnit float64 `xml:"MapUnit,attr"`
|
||||
Eccentricity float64 `xml:"Eccentricity,attr"`
|
||||
Angle float64 `xml:"Angle,attr"`
|
||||
Extend string `xml:"Extend,attr"`
|
||||
StartPoint string `xml:"StartPoint,attr"`
|
||||
StartRadius float64 `xml:"StartRadius,attr"`
|
||||
|
||||
+13
-8
@@ -167,8 +167,8 @@ func parseFillPaint(fillColor *FillColor, x, y, pageH float64) any {
|
||||
if gradient := parseAxialShdGradient(fillColor.AxialShd, fillColor.Alpha, x, y, pageH); gradient != nil {
|
||||
return newShdPaint(gradient, fillColor.AxialShd.Extend, fillColor.AxialShd.MapType, fillColor.AxialShd.MapUnit)
|
||||
}
|
||||
if gradient := parseRadialShdGradient(fillColor.RadialShd, fillColor.Alpha, x, y, pageH); gradient != nil {
|
||||
return newShdPaint(gradient, fillColor.RadialShd.Extend, fillColor.RadialShd.MapType, fillColor.RadialShd.MapUnit)
|
||||
if paint := parseRadialShdPaint(fillColor.RadialShd, fillColor.Alpha, x, y, pageH); paint != nil {
|
||||
return paint
|
||||
}
|
||||
if fillColor.AxialShd != nil {
|
||||
return parseShdColor(fillColor.AxialShd.Segment, fillColor.Alpha)
|
||||
@@ -211,8 +211,8 @@ func parseStrokePaint(strokeColor *StrokeColor, x, y, pageH float64) any {
|
||||
if gradient := parseAxialShdGradient(strokeColor.AxialShd, strokeColor.Alpha, x, y, pageH); gradient != nil {
|
||||
return newShdPaint(gradient, strokeColor.AxialShd.Extend, strokeColor.AxialShd.MapType, strokeColor.AxialShd.MapUnit)
|
||||
}
|
||||
if gradient := parseRadialShdGradient(strokeColor.RadialShd, strokeColor.Alpha, x, y, pageH); gradient != nil {
|
||||
return newShdPaint(gradient, strokeColor.RadialShd.Extend, strokeColor.RadialShd.MapType, strokeColor.RadialShd.MapUnit)
|
||||
if paint := parseRadialShdPaint(strokeColor.RadialShd, strokeColor.Alpha, x, y, pageH); paint != nil {
|
||||
return paint
|
||||
}
|
||||
if strokeColor.AxialShd != nil {
|
||||
return parseShdColor(strokeColor.AxialShd.Segment, strokeColor.Alpha)
|
||||
@@ -339,10 +339,10 @@ func axialShdClip(ctx *canvas.Context, gradient *canvas.LinearGradient, extend i
|
||||
return area.ToPath().Transform(axis)
|
||||
}
|
||||
|
||||
// parseRadialShdGradient 解析径向渐变
|
||||
// parseRadialShdPaint 解析径向渐变画刷
|
||||
// 入参: radialShd 径向渐变节点, alpha 透明度, x X坐标, y Y坐标, pageH 页面高度
|
||||
// 返回: canvas.Gradient 渐变对象
|
||||
func parseRadialShdGradient(radialShd *RadialShd, alpha *int, x, y, pageH float64) canvas.Gradient {
|
||||
// 返回: *shdPaint 渐变画刷
|
||||
func parseRadialShdPaint(radialShd *RadialShd, alpha *int, x, y, pageH float64) *shdPaint {
|
||||
if radialShd == nil || radialShd.EndRadius <= 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -357,7 +357,12 @@ func parseRadialShdGradient(radialShd *RadialShd, alpha *int, x, y, pageH float6
|
||||
}
|
||||
startPoint := canvas.Point{X: x + start[0], Y: pageH - (y + start[1])}
|
||||
endPoint := canvas.Point{X: x + end[0], Y: pageH - (y + end[1])}
|
||||
return gradient.ToRadial(startPoint, radialShd.StartRadius, endPoint, radialShd.EndRadius)
|
||||
paint := newShdPaint(gradient.ToRadial(startPoint, radialShd.StartRadius, endPoint, radialShd.EndRadius), radialShd.Extend, radialShd.MapType, radialShd.MapUnit)
|
||||
if e := radialShd.Eccentricity; 0 < e && e < 1 {
|
||||
paint.view = canvas.Identity.Translate(startPoint.X, startPoint.Y).Rotate(-radialShd.Angle).Scale(1, math.Sqrt(1-e*e)).Translate(-startPoint.X, -startPoint.Y)
|
||||
paint.gradient = gradient.ToRadial(startPoint, radialShd.StartRadius, paint.view.Inv().Dot(endPoint), radialShd.EndRadius)
|
||||
}
|
||||
return paint
|
||||
}
|
||||
|
||||
// colorToRGBA 转换颜色对象
|
||||
|
||||
+10
-11
@@ -211,7 +211,7 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
style.fillPaint = style.fillColor
|
||||
}
|
||||
if shouldFill {
|
||||
fillPaint, shadingClip := resolveShdPaint(ctx, style.fillPaint)
|
||||
fillPaint, shadingClip, fillView := resolveShdPaint(ctx, style.fillPaint)
|
||||
fillClip := intersectClipPath(clipPath, shadingClip)
|
||||
fp := p
|
||||
fillRule := canvas.NonZero
|
||||
@@ -232,7 +232,7 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
ctx.SetFillRule(fillRule)
|
||||
ctx.SetFill(fillPaint)
|
||||
ctx.SetStrokeColor(canvas.Transparent)
|
||||
ctx.DrawPath(0, 0, fp)
|
||||
drawShdPath(ctx, fp, fillView)
|
||||
}
|
||||
}
|
||||
shouldStroke := true
|
||||
@@ -247,28 +247,27 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
if style.strokePaint == nil {
|
||||
style.strokePaint = colorWithAlpha(canvas.Black, obj.Alpha)
|
||||
}
|
||||
strokePaint, shadingClip := resolveShdPaint(ctx, style.strokePaint)
|
||||
strokePaint, shadingClip, strokeView := resolveShdPaint(ctx, style.strokePaint)
|
||||
ctx.SetFillColor(canvas.Transparent)
|
||||
ctx.SetStroke(strokePaint)
|
||||
ctx.SetStrokeWidth(style.lineWidth)
|
||||
ctx.SetStrokeCapper(style.lineCap)
|
||||
ctx.SetStrokeJoiner(style.lineJoin)
|
||||
if len(style.dashPattern) > 0 {
|
||||
ctx.SetDashes(style.dashOffset, style.dashPattern...)
|
||||
}
|
||||
strokeClip := intersectClipPath(clipPath, shadingClip)
|
||||
if strokeClip != nil {
|
||||
sp := p.Copy()
|
||||
sp := p
|
||||
if len(style.dashPattern) > 0 {
|
||||
sp = sp.Dash(style.dashOffset, style.dashPattern...)
|
||||
ctx.SetDashes(0)
|
||||
}
|
||||
strokeClip := intersectClipPath(clipPath, shadingClip)
|
||||
if strokeClip != nil || strokeView != canvas.Identity {
|
||||
sp = sp.Copy()
|
||||
sp = sp.Stroke(style.lineWidth, style.lineCap, style.lineJoin, canvas.Tolerance)
|
||||
sp = applyClipPath(sp, strokeClip)
|
||||
ctx.SetFill(strokePaint)
|
||||
ctx.SetStrokeColor(canvas.Transparent)
|
||||
ctx.DrawPath(0, 0, sp)
|
||||
drawShdPath(ctx, sp, strokeView)
|
||||
} else {
|
||||
ctx.DrawPath(0, 0, p)
|
||||
ctx.DrawPath(0, 0, sp)
|
||||
}
|
||||
}
|
||||
ctx.Pop()
|
||||
|
||||
@@ -89,10 +89,11 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
||||
if fillPaint == nil {
|
||||
fillPaint = fillColor
|
||||
}
|
||||
fillPaint, shadingClip := resolveShdPaint(ctx, fillPaint)
|
||||
fillPaint, shadingClip, fillView := resolveShdPaint(ctx, fillPaint)
|
||||
fillClip := intersectClipPath(clipPath, shadingClip)
|
||||
strokeStyle := newPathStyle(nil, defaultStroke, 0, obj.Alpha)
|
||||
strokeClip := clipPath
|
||||
strokeView := canvas.Identity
|
||||
if shouldStroke {
|
||||
if dp != nil {
|
||||
strokeStyle.applyDrawParam(dp, bx, by, pageH, obj.Alpha)
|
||||
@@ -107,7 +108,7 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
||||
strokeStyle.strokePaint = colorWithAlpha(canvas.Black, obj.Alpha)
|
||||
}
|
||||
strokeStyle.scale(ctm)
|
||||
strokeStyle.strokePaint, shadingClip = resolveShdPaint(ctx, strokeStyle.strokePaint)
|
||||
strokeStyle.strokePaint, shadingClip, strokeView = resolveShdPaint(ctx, strokeStyle.strokePaint)
|
||||
strokeClip = intersectClipPath(strokeClip, shadingClip)
|
||||
}
|
||||
fontStyle := canvas.FontRegular
|
||||
@@ -240,7 +241,7 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
||||
if shouldFill && fillPaint != nil {
|
||||
ctx.SetFill(fillPaint)
|
||||
ctx.SetStrokeColor(canvas.Transparent)
|
||||
ctx.DrawPath(0, 0, applyClipPath(path.Copy(), fillClip))
|
||||
drawShdPath(ctx, applyClipPath(path.Copy(), fillClip), fillView)
|
||||
}
|
||||
if len(strokeStyle.dashPattern) > 0 {
|
||||
path = path.Dash(strokeStyle.dashOffset, strokeStyle.dashPattern...)
|
||||
@@ -248,7 +249,7 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
||||
path = path.Stroke(strokeStyle.lineWidth, strokeStyle.lineCap, strokeStyle.lineJoin, canvas.Tolerance)
|
||||
ctx.SetFill(strokeStyle.strokePaint)
|
||||
ctx.SetStrokeColor(canvas.Transparent)
|
||||
ctx.DrawPath(0, 0, applyClipPath(path, strokeClip))
|
||||
drawShdPath(ctx, applyClipPath(path, strokeClip), strokeView)
|
||||
if hasUnderline {
|
||||
underline := &canvas.Path{}
|
||||
underline.MoveTo(0, -sizeMM*0.1)
|
||||
@@ -256,8 +257,10 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
||||
underline = underline.Stroke(sizeMM*0.05, canvas.ButtCap, canvas.MiterJoin, canvas.Tolerance)
|
||||
if shouldFill {
|
||||
ctx.SetFillColor(fillColor)
|
||||
}
|
||||
ctx.DrawPath(0, 0, applyClipPath(underline.Transform(transform), clipPath))
|
||||
} else {
|
||||
drawShdPath(ctx, applyClipPath(underline.Transform(transform), strokeClip), strokeView)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -274,7 +277,7 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
||||
textTransform = textTransform.Mul(glyphMatrix)
|
||||
}
|
||||
glyphPath = applyClipPath(glyphPath.Copy().Transform(textTransform.Scale(scaleX, 1)), fillClip)
|
||||
ctx.DrawPath(0, 0, glyphPath)
|
||||
drawShdPath(ctx, glyphPath, fillView)
|
||||
if hasUnderline {
|
||||
uw := sizeMM * 0.05
|
||||
off := sizeMM * 0.1
|
||||
|
||||
+33
-17
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
type shdPaint struct {
|
||||
gradient canvas.Gradient
|
||||
view canvas.Matrix
|
||||
extend int
|
||||
mapType string
|
||||
period float64
|
||||
@@ -44,46 +45,49 @@ func newShdPaint(gradient canvas.Gradient, extend, mapType string, mapUnit float
|
||||
if mapUnit > 0 && length > 0 {
|
||||
period = mapUnit / length
|
||||
}
|
||||
return &shdPaint{gradient: gradient, extend: flags, mapType: mapType, period: period}
|
||||
return &shdPaint{gradient: gradient, view: canvas.Identity, extend: flags, mapType: mapType, period: period}
|
||||
}
|
||||
|
||||
// resolveShdPaint 解析渐变画刷和裁剪区域
|
||||
// 入参: ctx 画布上下文, paint 画刷
|
||||
// 返回: any 画刷, *canvas.Path 裁剪区域
|
||||
func resolveShdPaint(ctx *canvas.Context, paint any) (any, *canvas.Path) {
|
||||
// 返回: any 画刷, *canvas.Path 裁剪区域, canvas.Matrix 渐变变换
|
||||
func resolveShdPaint(ctx *canvas.Context, paint any) (any, *canvas.Path, canvas.Matrix) {
|
||||
s, ok := paint.(*shdPaint)
|
||||
if !ok {
|
||||
return paint, nil
|
||||
return paint, nil, canvas.Identity
|
||||
}
|
||||
switch g := s.gradient.(type) {
|
||||
case *canvas.LinearGradient:
|
||||
clip := axialShdClip(ctx, g, s.extend)
|
||||
if s.mapType != "Reflect" {
|
||||
return g, clip
|
||||
return g, clip, s.view
|
||||
}
|
||||
d := g.End.Sub(g.Start)
|
||||
axis := canvas.Matrix{{d.X, -d.Y, g.Start.X}, {d.Y, d.X, g.Start.Y}}
|
||||
area := shdCanvasBounds(ctx).Transform(axis.Inv())
|
||||
lo, hi := s.rangeLimits(area.X0, area.X1)
|
||||
if hi <= lo {
|
||||
return g, &canvas.Path{}
|
||||
return g, &canvas.Path{}, s.view
|
||||
}
|
||||
gradient := reflectShdGrad(g.Grad, s.period, lo, hi)
|
||||
return gradient.ToLinear(g.Start.Add(d.Mul(lo)), g.Start.Add(d.Mul(hi))), clip
|
||||
return gradient.ToLinear(g.Start.Add(d.Mul(lo)), g.Start.Add(d.Mul(hi))), clip, s.view
|
||||
case *canvas.RadialGradient:
|
||||
d, dr := g.C1.Sub(g.C0), g.R1-g.R0
|
||||
length := d.Length()
|
||||
if length >= math.Abs(dr) {
|
||||
return g, nil
|
||||
return g, nil, s.view
|
||||
}
|
||||
bounds := shdCanvasBounds(ctx).Transform(s.view.Inv())
|
||||
clip := radialShdClip(g, s.extend, bounds)
|
||||
if clip != nil && s.view != canvas.Identity {
|
||||
clip = clip.Transform(s.view)
|
||||
}
|
||||
clip := radialShdClip(ctx, g, s.extend)
|
||||
if s.mapType != "Reflect" {
|
||||
return g, clip
|
||||
return g, clip, s.view
|
||||
}
|
||||
lo, hi := 0.0, 1.0
|
||||
if s.extend != 0 {
|
||||
distance := 0.0
|
||||
bounds := shdCanvasBounds(ctx)
|
||||
for _, point := range []canvas.Point{{X: bounds.X0, Y: bounds.Y0}, {X: bounds.X1, Y: bounds.Y0}, {X: bounds.X1, Y: bounds.Y1}, {X: bounds.X0, Y: bounds.Y1}} {
|
||||
distance = math.Max(distance, point.Sub(g.C0).Length())
|
||||
}
|
||||
@@ -96,12 +100,24 @@ func resolveShdPaint(ctx *canvas.Context, paint any) (any, *canvas.Path) {
|
||||
hi = math.Min(hi, -g.R0/dr)
|
||||
}
|
||||
if hi <= lo {
|
||||
return g, &canvas.Path{}
|
||||
return g, &canvas.Path{}, s.view
|
||||
}
|
||||
gradient := reflectShdGrad(g.Grad, s.period, lo, hi)
|
||||
return gradient.ToRadial(g.C0.Add(d.Mul(lo)), math.Max(0, g.R0+dr*lo), g.C0.Add(d.Mul(hi)), math.Max(0, g.R0+dr*hi)), clip
|
||||
return gradient.ToRadial(g.C0.Add(d.Mul(lo)), math.Max(0, g.R0+dr*lo), g.C0.Add(d.Mul(hi)), math.Max(0, g.R0+dr*hi)), clip, s.view
|
||||
}
|
||||
return s.gradient, nil
|
||||
return s.gradient, nil, s.view
|
||||
}
|
||||
|
||||
// drawShdPath 绘制渐变路径并保持图形轮廓不变
|
||||
// 入参: ctx 画布上下文, path 填充路径, view 渐变变换
|
||||
func drawShdPath(ctx *canvas.Context, path *canvas.Path, view canvas.Matrix) {
|
||||
if view == canvas.Identity {
|
||||
ctx.DrawPath(0, 0, path)
|
||||
return
|
||||
}
|
||||
origin := ctx.CoordView().Dot(canvas.Point{})
|
||||
m := ctx.CoordSystemView().Mul(ctx.View()).Translate(origin.X, origin.Y).Mul(view)
|
||||
ctx.RenderPath(path.Copy().Transform(view.Inv()), ctx.Style, m)
|
||||
}
|
||||
|
||||
// rangeLimits 限制渐变延伸区间
|
||||
@@ -131,9 +147,9 @@ func shdCanvasBounds(ctx *canvas.Context) canvas.Rect {
|
||||
}
|
||||
|
||||
// radialShdClip 获取包含双圆的径向渐变裁剪区域
|
||||
// 入参: ctx 画布上下文, g 径向渐变, extend 延伸方向
|
||||
// 入参: g 径向渐变, extend 延伸方向, bounds 渐变坐标系下的画布边界
|
||||
// 返回: *canvas.Path 裁剪区域
|
||||
func radialShdClip(ctx *canvas.Context, g *canvas.RadialGradient, extend int) *canvas.Path {
|
||||
func radialShdClip(g *canvas.RadialGradient, extend int, bounds canvas.Rect) *canvas.Path {
|
||||
inner, outer := g.C0, g.C1
|
||||
r0, r1 := g.R0, g.R1
|
||||
if r1 < r0 {
|
||||
@@ -147,7 +163,7 @@ func radialShdClip(ctx *canvas.Context, g *canvas.RadialGradient, extend int) *c
|
||||
if extend&2 == 0 {
|
||||
clip = canvas.Circle(r1).Translate(outer.X, outer.Y)
|
||||
} else {
|
||||
clip = shdCanvasBounds(ctx).ToPath()
|
||||
clip = bounds.ToPath()
|
||||
}
|
||||
if extend&1 == 0 && r0 > 0 {
|
||||
clip = clip.Not(canvas.Circle(r0).Translate(inner.X, inner.Y))
|
||||
|
||||
Reference in new issue
Block a user