mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
feat(图形绘制): 支持更多的图形绘制
This commit is contained in:
+21
-7
@@ -58,7 +58,8 @@ type GraphicObject struct {
|
||||
|
||||
// Clips 裁剪区域集合
|
||||
type Clips struct {
|
||||
Clip []Clip `xml:"Clip"`
|
||||
TransFlag bool `xml:"TransFlag,attr"`
|
||||
Clip []Clip `xml:"Clip"`
|
||||
}
|
||||
|
||||
// Clip 裁剪
|
||||
@@ -68,6 +69,7 @@ type Clip struct {
|
||||
|
||||
// ClipArea 裁剪区域
|
||||
type ClipArea struct {
|
||||
CTM string `xml:"CTM,attr"`
|
||||
Path []PathObject `xml:"Path"`
|
||||
Text []TextObject `xml:"Text"`
|
||||
}
|
||||
@@ -97,9 +99,10 @@ type TextObject struct {
|
||||
|
||||
// FillColor 填充颜色
|
||||
type FillColor struct {
|
||||
Value string `xml:"Value,attr"`
|
||||
Alpha *int `xml:"Alpha,attr"`
|
||||
AxialShd *AxialShd `xml:"AxialShd"`
|
||||
Value string `xml:"Value,attr"`
|
||||
Alpha *int `xml:"Alpha,attr"`
|
||||
AxialShd *AxialShd `xml:"AxialShd"`
|
||||
RadialShd *RadialShd `xml:"RadialShd"`
|
||||
}
|
||||
|
||||
// TextCode 文本内容节点
|
||||
@@ -142,9 +145,10 @@ type PathObject struct {
|
||||
|
||||
// StrokeColor 勾边颜色
|
||||
type StrokeColor struct {
|
||||
Value string `xml:"Value,attr"`
|
||||
Alpha *int `xml:"Alpha,attr"`
|
||||
AxialShd *AxialShd `xml:"AxialShd"`
|
||||
Value string `xml:"Value,attr"`
|
||||
Alpha *int `xml:"Alpha,attr"`
|
||||
AxialShd *AxialShd `xml:"AxialShd"`
|
||||
RadialShd *RadialShd `xml:"RadialShd"`
|
||||
}
|
||||
|
||||
// AxialShd 轴向渐变
|
||||
@@ -155,6 +159,16 @@ type AxialShd struct {
|
||||
Segment []ShdSegment `xml:"Segment"`
|
||||
}
|
||||
|
||||
// RadialShd 径向渐变
|
||||
type RadialShd struct {
|
||||
Extend string `xml:"Extend,attr"`
|
||||
StartPoint string `xml:"StartPoint,attr"`
|
||||
StartRadius float64 `xml:"StartRadius,attr"`
|
||||
EndPoint string `xml:"EndPoint,attr"`
|
||||
EndRadius float64 `xml:"EndRadius,attr"`
|
||||
Segment []ShdSegment `xml:"Segment"`
|
||||
}
|
||||
|
||||
// ShdSegment 渐变分段
|
||||
type ShdSegment struct {
|
||||
Position float64 `xml:"Position,attr"`
|
||||
|
||||
+59
-2
@@ -557,6 +557,7 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
if rectPath := r.buildTinyFillRectPath(obj, pageH, ctm, bx, by); rectPath != nil {
|
||||
p = rectPath
|
||||
}
|
||||
clipPath := r.buildClipPath(obj.Clips, pageH, bx, by, ctm)
|
||||
shouldFill := true
|
||||
if obj.Fill != nil {
|
||||
shouldFill = *obj.Fill
|
||||
@@ -567,7 +568,13 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
if shouldFill && fillPaint != nil {
|
||||
ctx.SetFill(fillPaint)
|
||||
ctx.SetStrokeColor(canvas.Transparent)
|
||||
ctx.DrawPath(0, 0, p)
|
||||
fp := p
|
||||
if clipPath != nil {
|
||||
fp = p.Copy()
|
||||
fp.Close()
|
||||
fp = fp.And(clipPath)
|
||||
}
|
||||
ctx.DrawPath(0, 0, fp)
|
||||
}
|
||||
shouldStroke := true
|
||||
if obj.Stroke != nil {
|
||||
@@ -588,7 +595,19 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
||||
if len(dashPattern) > 0 {
|
||||
ctx.SetDashes(dashOffset, dashPattern...)
|
||||
}
|
||||
ctx.DrawPath(0, 0, p)
|
||||
if clipPath != nil {
|
||||
sp := p.Copy()
|
||||
if len(dashPattern) > 0 {
|
||||
sp = sp.Dash(dashOffset, dashPattern...)
|
||||
}
|
||||
sp = sp.Stroke(lineWidth, lineCap, lineJoin, canvas.Tolerance)
|
||||
sp = sp.And(clipPath)
|
||||
ctx.SetFill(strokePaint)
|
||||
ctx.SetStrokeColor(canvas.Transparent)
|
||||
ctx.DrawPath(0, 0, sp)
|
||||
} else {
|
||||
ctx.DrawPath(0, 0, p)
|
||||
}
|
||||
}
|
||||
ctx.Pop()
|
||||
}
|
||||
@@ -1158,6 +1177,44 @@ func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix) *canvas.
|
||||
return p
|
||||
}
|
||||
|
||||
// buildClipPath 构建裁剪路径
|
||||
// 入参: clips 裁剪对象, pageH 页面高度, bx 边界X坐标, by 边界Y坐标, objectCTM 对象CTM
|
||||
// 返回: *canvas.Path 路径对象
|
||||
func (r *Renderer) buildClipPath(clips *Clips, pageH float64, bx, by float64, objectCTM Matrix) *canvas.Path {
|
||||
if clips == nil {
|
||||
return nil
|
||||
}
|
||||
var p *canvas.Path
|
||||
for _, clip := range clips.Clip {
|
||||
var clipPath *canvas.Path
|
||||
for _, area := range clip.Area {
|
||||
areaCTM := NewMatrix(area.CTM)
|
||||
if clips.TransFlag {
|
||||
areaCTM = objectCTM.Multiply(areaCTM)
|
||||
}
|
||||
for _, pathObj := range area.Path {
|
||||
ctm := areaCTM.Multiply(NewMatrix(pathObj.CTM))
|
||||
cp := r.buildPath(pathObj, pageH, ctm)
|
||||
cp.Translate(bx, -by)
|
||||
cp.Close()
|
||||
if clipPath == nil {
|
||||
clipPath = cp
|
||||
} else {
|
||||
clipPath = clipPath.Or(cp)
|
||||
}
|
||||
}
|
||||
}
|
||||
if clipPath != nil {
|
||||
if p == nil {
|
||||
p = clipPath
|
||||
} else {
|
||||
p = p.And(clipPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// buildTinyFillRectPath 构建微小填充矩形路径
|
||||
// 入参: obj 路径对象, pageH 页面高度, ctm 变换矩阵, bx 边界X坐标, by 边界Y坐标
|
||||
// 返回: *canvas.Path 路径对象
|
||||
|
||||
+71
-4
@@ -57,7 +57,10 @@ func parseFillColor(fillColor *FillColor) color.Color {
|
||||
if strings.TrimSpace(fillColor.Value) != "" {
|
||||
return parseColorWithAlpha(fillColor.Value, fillColor.Alpha)
|
||||
}
|
||||
return parseAxialShdColor(fillColor.AxialShd, fillColor.Alpha)
|
||||
if fillColor.AxialShd != nil {
|
||||
return parseAxialShdColor(fillColor.AxialShd, fillColor.Alpha)
|
||||
}
|
||||
return parseRadialShdColor(fillColor.RadialShd, fillColor.Alpha)
|
||||
}
|
||||
|
||||
// parseFillPaint 解析填充画刷
|
||||
@@ -73,7 +76,13 @@ func parseFillPaint(fillColor *FillColor, x, y, pageH, originX, originY float64)
|
||||
if gradient := parseAxialShdGradient(fillColor.AxialShd, fillColor.Alpha, x, y, pageH, originX, originY); gradient != nil {
|
||||
return gradient
|
||||
}
|
||||
return parseAxialShdColor(fillColor.AxialShd, fillColor.Alpha)
|
||||
if gradient := parseRadialShdGradient(fillColor.RadialShd, fillColor.Alpha, x, y, pageH, originX, originY); gradient != nil {
|
||||
return gradient
|
||||
}
|
||||
if fillColor.AxialShd != nil {
|
||||
return parseAxialShdColor(fillColor.AxialShd, fillColor.Alpha)
|
||||
}
|
||||
return parseRadialShdColor(fillColor.RadialShd, fillColor.Alpha)
|
||||
}
|
||||
|
||||
// parseStrokeColor 解析勾边颜色
|
||||
@@ -86,7 +95,10 @@ func parseStrokeColor(strokeColor *StrokeColor) color.Color {
|
||||
if strings.TrimSpace(strokeColor.Value) != "" {
|
||||
return parseColorWithAlpha(strokeColor.Value, strokeColor.Alpha)
|
||||
}
|
||||
return parseAxialShdColor(strokeColor.AxialShd, strokeColor.Alpha)
|
||||
if strokeColor.AxialShd != nil {
|
||||
return parseAxialShdColor(strokeColor.AxialShd, strokeColor.Alpha)
|
||||
}
|
||||
return parseRadialShdColor(strokeColor.RadialShd, strokeColor.Alpha)
|
||||
}
|
||||
|
||||
// parseStrokePaint 解析勾边画刷
|
||||
@@ -102,7 +114,13 @@ func parseStrokePaint(strokeColor *StrokeColor, x, y, pageH, originX, originY fl
|
||||
if gradient := parseAxialShdGradient(strokeColor.AxialShd, strokeColor.Alpha, x, y, pageH, originX, originY); gradient != nil {
|
||||
return gradient
|
||||
}
|
||||
return parseAxialShdColor(strokeColor.AxialShd, strokeColor.Alpha)
|
||||
if gradient := parseRadialShdGradient(strokeColor.RadialShd, strokeColor.Alpha, x, y, pageH, originX, originY); gradient != nil {
|
||||
return gradient
|
||||
}
|
||||
if strokeColor.AxialShd != nil {
|
||||
return parseAxialShdColor(strokeColor.AxialShd, strokeColor.Alpha)
|
||||
}
|
||||
return parseRadialShdColor(strokeColor.RadialShd, strokeColor.Alpha)
|
||||
}
|
||||
|
||||
// parseAxialShdColor 解析轴向渐变颜色
|
||||
@@ -157,6 +175,55 @@ func parseAxialShdGradient(axialShd *AxialShd, alpha *int, x, y, pageH, originX,
|
||||
return grad.ToLinear(startPoint, endPoint)
|
||||
}
|
||||
|
||||
// parseRadialShdColor 解析径向渐变颜色
|
||||
// 入参: radialShd 径向渐变节点, alpha 透明度
|
||||
// 返回: color.Color 颜色对象
|
||||
func parseRadialShdColor(radialShd *RadialShd, alpha *int) color.Color {
|
||||
if radialShd != nil {
|
||||
for _, segment := range radialShd.Segment {
|
||||
if strings.TrimSpace(segment.Color.Value) == "" {
|
||||
continue
|
||||
}
|
||||
if alpha == nil {
|
||||
alpha = segment.Color.Alpha
|
||||
}
|
||||
return parseColorWithAlpha(segment.Color.Value, alpha)
|
||||
}
|
||||
}
|
||||
return color.Black
|
||||
}
|
||||
|
||||
// parseRadialShdGradient 解析径向渐变
|
||||
// 入参: radialShd 径向渐变节点, alpha 透明度, x X坐标, y Y坐标, pageH 页面高度, originX 原点X坐标, originY 原点Y坐标
|
||||
// 返回: canvas.Gradient 渐变对象
|
||||
func parseRadialShdGradient(radialShd *RadialShd, alpha *int, x, y, pageH, originX, originY float64) canvas.Gradient {
|
||||
if radialShd == nil || radialShd.EndRadius <= 0 {
|
||||
return nil
|
||||
}
|
||||
start := parseFloats(radialShd.StartPoint)
|
||||
end := parseFloats(radialShd.EndPoint)
|
||||
if len(start) < 2 || len(end) < 2 {
|
||||
return nil
|
||||
}
|
||||
grad := canvas.NewGradient()
|
||||
for _, segment := range radialShd.Segment {
|
||||
if strings.TrimSpace(segment.Color.Value) == "" {
|
||||
continue
|
||||
}
|
||||
segmentAlpha := alpha
|
||||
if segmentAlpha == nil {
|
||||
segmentAlpha = segment.Color.Alpha
|
||||
}
|
||||
grad.Add(segment.Position, colorToRGBA(parseColorWithAlpha(segment.Color.Value, segmentAlpha)))
|
||||
}
|
||||
if len(grad) == 0 {
|
||||
return nil
|
||||
}
|
||||
startPoint := canvas.Point{X: x + start[0] - originX, Y: pageH - (y + start[1]) - originY}
|
||||
endPoint := canvas.Point{X: x + end[0] - originX, Y: pageH - (y + end[1]) - originY}
|
||||
return grad.ToRadial(startPoint, radialShd.StartRadius, endPoint, radialShd.EndRadius)
|
||||
}
|
||||
|
||||
// colorToRGBA 转换颜色对象
|
||||
// 入参: c 颜色对象
|
||||
// 返回: color.RGBA RGBA颜色
|
||||
|
||||
Reference in New Issue
Block a user