diff --git a/ofdgo_object.go b/ofdgo_object.go index 6466e6b..7e4e918 100644 --- a/ofdgo_object.go +++ b/ofdgo_object.go @@ -102,16 +102,52 @@ func (p *PathObject) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error // 入参: d XML解码器, start 起始节点 // 返回: error 错误信息 func (p *DrawParam) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - type plain DrawParam - var value struct { - plain - DashPattern *string `xml:"DashPattern,attr"` + *p = DrawParam{ + ID: attrValue(start, "ID"), Relative: attrValue(start, "Relative"), ResourceID: attrValue(start, "ResourceID"), + BaseLoc: attrValue(start, "BaseLoc"), Link: attrValue(start, "Link"), Join: attrValue(start, "Join"), + Cap: attrValue(start, "Cap"), Font: attrValue(start, "Font"), DashPattern: attrValue(start, "DashPattern"), } - if err := d.DecodeElement(&value, &start); err != nil { - return err - } - *p = DrawParam(value.plain) for _, attr := range start.Attr { + if attr.Name.Space != "" { + continue + } + var target *float64 + switch attr.Name.Local { + case "LineWidth": + target = &p.LineWidth + case "MiterLimit": + target = &p.MiterLimit + case "DashOffset": + p.DashOffset = new(float64) + target = p.DashOffset + case "Size": + target = &p.Size + case "DashPattern": + p.dashPatternSet = p.DashPattern == "" + case "Weight": + if value := strings.TrimSpace(attr.Value); value != "" { + weight, err := strconv.Atoi(value) + if err != nil { + return err + } + p.Weight = weight + } + case "Italic": + if value := strings.TrimSpace(attr.Value); value != "" { + italic, err := strconv.ParseBool(value) + if err != nil { + return err + } + p.Italic = italic + } + } + if value := strings.TrimSpace(attr.Value); target != nil && value != "" { + number, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *target = number + } if attr.Name.Local == "LineWidth" { p.LineWidthSet = p.LineWidth == 0 } @@ -119,32 +155,52 @@ func (p *DrawParam) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { p.MiterLimitSet = p.MiterLimit == 0 } } - if value.DashPattern != nil { - p.DashPattern = *value.DashPattern - p.dashPatternSet = p.DashPattern == "" - } - return nil + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + switch node.Name.Local { + case "FillColor": + return d.DecodeElement(&p.FillColor, &node) + case "StrokeColor": + return d.DecodeElement(&p.StrokeColor, &node) + } + return d.Skip() + }) } // UnmarshalXML 解析填充颜色并区分未支持的复杂颜色 // 入参: d XML解码器, start 起始节点 // 返回: error 错误信息 func (c *FillColor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - type plain FillColor - var value struct { - plain - LegacyMesh *LaGouraudShd `xml:"LaGourandShd"` - Other *struct{} `xml:",any"` - } - if err := d.DecodeElement(&value, &start); err != nil { + var base ShdColor + if err := base.decodeAttributes(start); err != nil { return err } - *c = FillColor(value.plain) + *c = FillColor{Value: base.Value, Index: base.Index, ColorSpace: base.ColorSpace, Alpha: base.Alpha} + var schemaMesh *LaGouraudShd + err := decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + var target any + switch node.Name.Local { + case "Pattern": + target = &c.Pattern + case "AxialShd": + target = &c.AxialShd + case "RadialShd": + target = &c.RadialShd + case "GouraudShd": + target = &c.GouraudShd + case "LaGouraudShd": + target = &c.LaGouraudShd + case "LaGourandShd": + target = &schemaMesh + default: + c.unsupported = true + return d.Skip() + } + return d.DecodeElement(target, &node) + }) if c.LaGouraudShd == nil { - c.LaGouraudShd = value.LegacyMesh + c.LaGouraudShd = schemaMesh } - c.unsupported = value.Other != nil - return nil + return err } // UnmarshalXML 解析勾边颜色并区分未支持的复杂颜色 @@ -270,9 +326,124 @@ func (p PatternContent) empty() bool { // 入参: 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) + if value := strings.TrimSpace(attrValue(start, "Position")); value != "" { + position, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + s.Position = position + } + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local == "Color" { + return d.DecodeElement(&s.Color, &node) + } + return d.Skip() + }) +} + +// UnmarshalXML 解析图案参数及所属命名空间中的单元内容 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (p *Pattern) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *p = Pattern{ReflectMethod: attrValue(start, "ReflectMethod"), RelativeTo: attrValue(start, "RelativeTo"), CTM: attrValue(start, "CTM")} + for _, field := range []struct { + name string + target *float64 + }{ + {"Width", &p.Width}, {"Height", &p.Height}, {"XStep", &p.XStep}, {"YStep", &p.YStep}, + } { + if value := strings.TrimSpace(attrValue(start, field.name)); value != "" { + number, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *field.target = number + } + } + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local == "CellContent" { + return d.DecodeElement(&p.CellContent, &node) + } + return d.Skip() + }) +} + +// UnmarshalXML 解析轴向渐变参数及有序颜色分段 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (s *AxialShd) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *s = AxialShd{MapType: attrValue(start, "MapType"), Extend: attrValue(start, "Extend"), StartPoint: attrValue(start, "StartPoint"), EndPoint: attrValue(start, "EndPoint")} + if value := strings.TrimSpace(attrValue(start, "MapUnit")); value != "" { + number, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + s.MapUnit = number + } + return decodeOFDCollection(d, start, "Segment", &s.Segment) +} + +// UnmarshalXML 解析径向渐变参数及有序颜色分段 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (s *RadialShd) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *s = RadialShd{MapType: attrValue(start, "MapType"), Extend: attrValue(start, "Extend"), StartPoint: attrValue(start, "StartPoint"), EndPoint: attrValue(start, "EndPoint")} + for _, field := range []struct { + name string + target *float64 + }{ + {"MapUnit", &s.MapUnit}, {"Eccentricity", &s.Eccentricity}, {"Angle", &s.Angle}, {"StartRadius", &s.StartRadius}, {"EndRadius", &s.EndRadius}, + } { + if value := strings.TrimSpace(attrValue(start, field.name)); value != "" { + number, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *field.target = number + } + } + return decodeOFDCollection(d, start, "Segment", &s.Segment) +} + +// decodeAttributes 解析基本颜色属性,忽略带命名空间的扩展属性 +// 入参: start 颜色起始节点 +// 返回: error 属性格式错误 +func (c *ShdColor) decodeAttributes(start xml.StartElement) error { + *c = ShdColor{Value: attrValue(start, "Value"), ColorSpace: attrValue(start, "ColorSpace")} + for _, attr := range start.Attr { + if attr.Name.Space != "" { + continue + } + var target **int + switch attr.Name.Local { + case "Index": + target = &c.Index + case "Alpha": + target = &c.Alpha + default: + continue + } + *target = new(int) + if value := strings.TrimSpace(attr.Value); value != "" { + number, err := strconv.Atoi(value) + if err != nil { + return err + } + **target = number + } + } + return nil +} + +// UnmarshalXML 解析渐变使用的基本颜色,不读取扩展子节点 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (c *ShdColor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + if err := c.decodeAttributes(start); err != nil { + return err + } + return d.Skip() } // decodeGraphicObject 解析图形对象 diff --git a/ofdgo_paint_mesh.go b/ofdgo_paint_mesh.go index 01d0af0..8fbfdd8 100644 --- a/ofdgo_paint_mesh.go +++ b/ofdgo_paint_mesh.go @@ -15,9 +15,12 @@ package ofdgo import ( + "encoding/xml" "fmt" "image/color" "math" + "strconv" + "strings" ) // GouraudShd 高洛德渐变,按EdgeFlag连接三角形 @@ -58,6 +61,95 @@ type MeshShading struct { Background color.RGBA } +// UnmarshalXML 解析高洛德渐变的控制点和背景色 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (s *GouraudShd) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *s = GouraudShd{} + if value := strings.TrimSpace(attrValue(start, "Extend")); value != "" { + number, err := strconv.Atoi(value) + if err != nil { + return err + } + s.Extend = number + } + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + switch node.Name.Local { + case "Point": + return d.DecodeElement(&s.Point, &node) + case "BackColor": + return d.DecodeElement(&s.BackColor, &node) + default: + return d.Skip() + } + }) +} + +// UnmarshalXML 解析格构高洛德渐变的每行控制点数、控制点和背景色 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (s *LaGouraudShd) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *s = LaGouraudShd{} + for _, field := range []struct { + name string + target *int + }{ + {"Extend", &s.Extend}, {"VerticesPerRow", &s.VerticesPerRow}, + } { + if value := strings.TrimSpace(attrValue(start, field.name)); value != "" { + number, err := strconv.Atoi(value) + if err != nil { + return err + } + *field.target = number + } + } + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + switch node.Name.Local { + case "Point": + return d.DecodeElement(&s.Point, &node) + case "BackColor": + return d.DecodeElement(&s.BackColor, &node) + default: + return d.Skip() + } + }) +} + +// UnmarshalXML 解析网格控制点坐标、连接标志和基本颜色 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解码错误 +func (p *ShdPoint) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *p = ShdPoint{} + for _, field := range []struct { + name string + target *float64 + }{ + {"X", &p.X}, {"Y", &p.Y}, + } { + if value := strings.TrimSpace(attrValue(start, field.name)); value != "" { + number, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *field.target = number + } + } + if value := strings.TrimSpace(attrValue(start, "EdgeFlag")); value != "" { + number, err := strconv.Atoi(value) + if err != nil { + return err + } + p.EdgeFlag = number + } + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local == "Color" { + return d.DecodeElement(&p.Color, &node) + } + return d.Skip() + }) +} + // At 按三角形面积权重插值原颜色分量,返回预乘RGBA // 入参: x 横坐标, y 纵坐标 // 返回: color.RGBA 采样颜色