feat(渲染能力): 修正渐变色标位置,完善底纹翻转与边界变换
build.yaml / build (push) Successful in 37s

This commit is contained in:
xiaoqidun committed 2026-09-09 10:43:44 +08:00
1 parent 48a7f7c636
commit be125d6436
4 files changed
+59 -13

No files matched your search

+9
View File
@@ -237,6 +237,15 @@ func (p *PatternContent) decodeObject(d *xml.Decoder, start xml.StartElement) er
return d.Skip() return d.Skip()
} }
// UnmarshalXML 解析渐变分段并保留位置的缺省状态
// 入参: d XML解码器, start 起始节点
// 返回: error 错误信息
func (s *ShdSegment) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type segment ShdSegment
*s = ShdSegment{positionMissing: attrValue(start, "Position") == ""}
return d.DecodeElement((*segment)(s), &start)
}
// attrValue 获取XML属性值 // attrValue 获取XML属性值
// 入参: start 起始节点, name 属性名 // 入参: start 起始节点, name 属性名
// 返回: string 属性值 // 返回: string 属性值
+10 -8
View File
@@ -114,12 +114,13 @@ type FillColor struct {
// Pattern 图案填充 // Pattern 图案填充
type Pattern struct { type Pattern struct {
Width float64 `xml:"Width,attr"` Width float64 `xml:"Width,attr"`
Height float64 `xml:"Height,attr"` Height float64 `xml:"Height,attr"`
XStep float64 `xml:"XStep,attr"` XStep float64 `xml:"XStep,attr"`
YStep float64 `xml:"YStep,attr"` YStep float64 `xml:"YStep,attr"`
CTM string `xml:"CTM,attr"` ReflectMethod string `xml:"ReflectMethod,attr"`
CellContent PatternContent `xml:"CellContent"` CTM string `xml:"CTM,attr"`
CellContent PatternContent `xml:"CellContent"`
} }
// PatternContent 图案单元内容 // PatternContent 图案单元内容
@@ -201,8 +202,9 @@ type RadialShd struct {
// ShdSegment 渐变分段 // ShdSegment 渐变分段
type ShdSegment struct { type ShdSegment struct {
Position float64 `xml:"Position,attr"` Position float64 `xml:"Position,attr"`
Color ShdColor `xml:"Color"` Color ShdColor `xml:"Color"`
positionMissing bool
} }
// ShdColor 渐变颜色 // ShdColor 渐变颜色
+21 -2
View File
@@ -257,7 +257,26 @@ func parseShdColor(segments []ShdSegment, alpha *int) color.Color {
// 返回: canvas.Grad 渐变分段 // 返回: canvas.Grad 渐变分段
func parseShdSegments(segments []ShdSegment, alpha *int) canvas.Grad { func parseShdSegments(segments []ShdSegment, alpha *int) canvas.Grad {
gradient := canvas.NewGradient() gradient := canvas.NewGradient()
for _, segment := range segments { position, step := 0.0, 0.0
for i, segment := range segments {
if !segment.positionMissing {
position = segment.Position
} else if i == len(segments)-1 {
position = 1
}
if i == 0 || !segment.positionMissing {
next := i + 1
for next < len(segments)-1 && segments[next].positionMissing {
next++
}
end := 1.0
if next < len(segments) && !segments[next].positionMissing {
end = segments[next].Position
}
step = (end - position) / float64(next-i)
}
offset := position
position += step
if strings.TrimSpace(segment.Color.Value) == "" { if strings.TrimSpace(segment.Color.Value) == "" {
continue continue
} }
@@ -265,7 +284,7 @@ func parseShdSegments(segments []ShdSegment, alpha *int) canvas.Grad {
if segmentAlpha == nil { if segmentAlpha == nil {
segmentAlpha = segment.Color.Alpha segmentAlpha = segment.Color.Alpha
} }
gradient.Add(segment.Position, colorToRGBA(parseColorWithAlpha(segment.Color.Value, segmentAlpha))) gradient.Add(offset, colorToRGBA(parseColorWithAlpha(segment.Color.Value, segmentAlpha)))
} }
if len(gradient) == 0 { if len(gradient) == 0 {
return nil return nil
+19 -3
View File
@@ -188,10 +188,20 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
} }
style.applyPathObject(obj, bx, by, pageH) style.applyPathObject(obj, bx, by, pageH)
style.scale(ctm) style.scale(ctm)
p := r.buildPath(obj, pageH, ctm, boundaryInCTM) pathCTM := ctm
if rectPath := r.buildTinyFillRectPath(obj, pageH, ctm, bx, by); rectPath != nil { if boundaryInCTM {
pathCTM = localCTM
}
p := r.buildPath(obj, pageH, pathCTM, false)
if rectPath := r.buildTinyFillRectPath(obj, pageH, pathCTM, bx, by); rectPath != nil {
p = rectPath p = rectPath
} }
if boundaryInCTM && parentCTM != nil {
p = p.Transform(canvas.Matrix{
{parentCTM.a, -parentCTM.c, parentCTM.c*pageH + parentCTM.e},
{-parentCTM.b, parentCTM.d, pageH*(1-parentCTM.d) - parentCTM.f},
})
}
clipPath := intersectClipPath(parentClip, r.buildObjectClipPath(obj.Clips, pageH, bx, by, localCTM, parentCTM, boundaryInCTM)) clipPath := intersectClipPath(parentClip, r.buildObjectClipPath(obj.Clips, pageH, bx, by, localCTM, parentCTM, boundaryInCTM))
shouldFill := false shouldFill := false
if obj.Fill != nil { if obj.Fill != nil {
@@ -309,8 +319,14 @@ func (r *Renderer) renderPattern(ctx *canvas.Context, pattern *Pattern, defaultC
for ix := startX; ix <= endX; ix++ { for ix := startX; ix <= endX; ix++ {
for iy := startY; iy <= endY; iy++ { for iy := startY; iy <= endY; iy++ {
tileCTM := patternCTM.Multiply(TranslationMatrix(float64(ix)*xStep, float64(iy)*yStep)) tileCTM := patternCTM.Multiply(TranslationMatrix(float64(ix)*xStep, float64(iy)*yStep))
if ix%2 != 0 && (pattern.ReflectMethod == "Column" || pattern.ReflectMethod == "RowAndColumn") {
tileCTM = tileCTM.Multiply(Matrix{a: -1, d: 1, e: pattern.Width})
}
if iy%2 != 0 && (pattern.ReflectMethod == "Row" || pattern.ReflectMethod == "RowAndColumn") {
tileCTM = tileCTM.Multiply(Matrix{a: 1, d: -1, f: pattern.Height})
}
for _, obj := range pattern.CellContent.Objects { for _, obj := range pattern.CellContent.Objects {
r.renderObject(ctx, obj, pageH, defaultColor, defaultColor, 0, &tileCTM, false, clip) r.renderObject(ctx, obj, pageH, defaultColor, defaultColor, 0, &tileCTM, true, clip)
} }
} }
} }