feat(剪裁编辑): 规范裁剪编辑,优化资源扫描
build.yaml / build (push) Successful in 43s

This commit is contained in:
xiaoqidun committed 2026-10-09 19:02:02 +08:00
1 parent 2c96b4e490
commit 32ab7fe732
18 files changed
+83 -56

No files matched your search

+1 -1
View File
@@ -1035,7 +1035,7 @@ func transformEditorObject(object GraphicObject, dx, dy, scale float64) (Graphic
default: default:
return GraphicObject{}, fmt.Errorf("unsupported object type %q", object.Type) return GraphicObject{}, fmt.Errorf("unsupported object type %q", object.Type)
} }
if clips := editorObjectClips(&object); scale != 1 && *clips != nil && (object.Type == "TextObject" || (*clips).TransFlag != nil && !*(*clips).TransFlag) { if clips := editorObjectClips(&object); scale != 1 && *clips != nil && (object.Type == "TextObject" || !(*clips).usesObjectMatrix()) {
*clips = transformObjectClips(*clips, Matrix{a: scale, d: scale}) *clips = transformObjectClips(*clips, Matrix{a: scale, d: scale})
} }
box, err := ParseBox(*boundary) box, err := ParseBox(*boundary)
+5 -7
View File
@@ -470,10 +470,8 @@ func (e *Editor) compositeMembers(n *editorCompositeNode, reader *Reader, render
boundary := n.parent.Multiply(TranslationMatrix(box.X, box.Y)) boundary := n.parent.Multiply(TranslationMatrix(box.X, box.Y))
matrix := boundary.Multiply(NewMatrix(c.CTM)) matrix := boundary.Multiply(NewMatrix(c.CTM))
clips, clipMatrix := c.Clips, matrix clips, clipMatrix := c.Clips, matrix
if clips != nil && clips.TransFlag != nil && !*clips.TransFlag { if !clips.usesObjectMatrix() {
copy := *clips clipMatrix = boundary
copy.TransFlag = nil
clips, clipMatrix = &copy, boundary
} }
clip := n.clip clip := n.clip
var err error var err error
@@ -658,7 +656,7 @@ func (e *Editor) measureCompositeMembers(renderer *Renderer, nodes []*editorComp
} }
if transform && node.object.Type == "ImageObject" && bounds.Bounds.W > 0 && bounds.Bounds.H > 0 { if transform && node.object.Type == "ImageObject" && bounds.Bounds.W > 0 && bounds.Bounds.H > 0 {
clips := node.object.ImageObject.Clips clips := node.object.ImageObject.Clips
_, capability.CropImage = node.matrix(clips == nil || clips.TransFlag == nil || *clips.TransFlag).Invert() _, capability.CropImage = node.matrix(clips.usesObjectMatrix()).Invert()
capability.FitImage = capability.CropImage && axisAlignedMatrix(NewMatrix(node.object.ImageObject.CTM)) capability.FitImage = capability.CropImage && axisAlignedMatrix(NewMatrix(node.object.ImageObject.CTM))
capability.ResetCrop = node.states[editorObjectID(node.object)].crop != nil capability.ResetCrop = node.states[editorObjectID(node.object)].crop != nil
} }
@@ -903,7 +901,7 @@ func transformCompositeOffsets(data []byte, matrix Matrix) ([]byte, error) {
} }
object := cloneEditorData(n.object) object := cloneEditorData(n.object)
object = compositeBoundary(object, Matrix{a: matrix.a, b: matrix.b, c: matrix.c, d: matrix.d}, false) object = compositeBoundary(object, Matrix{a: matrix.a, b: matrix.b, c: matrix.c, d: matrix.d}, false)
if clips := editorObjectClips(&object); *clips != nil && (*clips).TransFlag != nil && !*(*clips).TransFlag { if clips := editorObjectClips(&object); *clips != nil && !(*clips).usesObjectMatrix() {
*clips = transformObjectClips(*clips, TranslationMatrix(matrix.e, matrix.f)) *clips = transformObjectClips(*clips, TranslationMatrix(matrix.e, matrix.f))
} }
fragment, err = editorXMLObject(n.data, n.node, n.object, object) fragment, err = editorXMLObject(n.data, n.node, n.object, object)
@@ -943,7 +941,7 @@ func compositeBoundary(object GraphicObject, parent Matrix, inward bool) Graphic
case "ImageObject": case "ImageObject":
object.ImageObject.Boundary = editorBoxString(box) object.ImageObject.Boundary = editorBoxString(box)
} }
if clips := editorObjectClips(&object); *clips != nil && (*clips).TransFlag != nil && !*(*clips).TransFlag { if clips := editorObjectClips(&object); *clips != nil && !(*clips).usesObjectMatrix() {
*clips = transformObjectClips(*clips, clipMatrix) *clips = transformObjectClips(*clips, clipMatrix)
} }
return object return object
+1 -1
View File
@@ -299,7 +299,7 @@ func (e *Editor) pasteCompositeSelection(selection *CompositeSelection, paste fu
return err return err
} }
clips := *editorObjectClips(&copy.object) clips := *editorObjectClips(&copy.object)
matrix, ok := copy.matrix(clips == nil || clips.TransFlag == nil || *clips.TransFlag).Invert() matrix, ok := copy.matrix(clips.usesObjectMatrix()).Invert()
if !ok { if !ok {
return fmt.Errorf("composite clip transform is not invertible") return fmt.Errorf("composite clip transform is not invertible")
} }
+9 -5
View File
@@ -43,7 +43,7 @@ func (e *Editor) CropCompositeImage(page int, path ObjectPath, index int, box Bo
return fmt.Errorf("crop does not intersect the image") return fmt.Errorf("crop does not intersect the image")
} }
clips := node.object.ImageObject.Clips clips := node.object.ImageObject.Clips
inverse, _ := node.matrix(clips == nil || clips.TransFlag == nil || *clips.TransFlag).Invert() inverse, _ := node.matrix(clips.usesObjectMatrix()).Invert()
shape, err := NewShape(ShapeRectangle, box) shape, err := NewShape(ShapeRectangle, box)
if err != nil { if err != nil {
return err return err
@@ -143,7 +143,7 @@ func (e *Editor) FitCompositeImage(page int, path ObjectPath, index int, mode st
frame = TranslationMatrix(box.X, box.Y).Multiply(node.parent) frame = TranslationMatrix(box.X, box.Y).Multiply(node.parent)
} }
clips := object.ImageObject.Clips clips := object.ImageObject.Clips
inverse, _ := node.matrix(clips == nil || clips.TransFlag == nil || *clips.TransFlag).Invert() inverse, _ := node.matrix(clips.usesObjectMatrix()).Invert()
return appendCompositeClip(node, shape, inverse.Multiply(frame), true) return appendCompositeClip(node, shape, inverse.Multiply(frame), true)
}) })
} }
@@ -192,7 +192,7 @@ func appendCompositeClip(node *editorCompositeNode, shape PathObject, matrix Mat
state.crop = &crop state.crop = &crop
} }
data, err := encodeOFDXML(func(x *ofdXML) { data, err := encodeOFDXML(func(x *ofdXML) {
x.clips(&Clips{Clip: []Clip{clip}}) x.clips(&Clips{Clip: []Clip{clip}}, "")
}) })
if err != nil { if err != nil {
return err return err
@@ -209,8 +209,12 @@ func appendCompositeClip(node *editorCompositeNode, shape PathObject, matrix Mat
patch = editorXMLContent(node.data, original, content) patch = editorXMLContent(node.data, original, content)
} else { } else {
data = editorXMLEncodedFragment(data, root) data = editorXMLEncodedFragment(data, root)
content := append(data, node.data[node.node.open:node.node.close]...) if actions := node.node.child("Actions"); actions != nil {
patch = editorXMLContent(node.data, node.node, content) patch = editorXMLPatch{actions.end, actions.end, data}
} else {
content := append(data, node.data[node.node.open:node.node.close]...)
patch = editorXMLContent(node.data, node.node, content)
}
} }
updated, err := newEditorCompositeNode(editorPatchXML(node.data, []editorXMLPatch{patch})) updated, err := newEditorCompositeNode(editorPatchXML(node.data, []editorXMLPatch{patch}))
if err != nil { if err != nil {
+2 -2
View File
@@ -133,7 +133,7 @@ func (e *Editor) eraseCompositeObjects(page int, path ObjectPath, indexes []int,
return fmt.Errorf("composite member cannot be erased") return fmt.Errorf("composite member cannot be erased")
} }
clips := *editorObjectClips(&node.object) clips := *editorObjectClips(&node.object)
inverse, ok := node.matrix(clips == nil || clips.TransFlag == nil || *clips.TransFlag).Invert() inverse, ok := node.matrix(clips.usesObjectMatrix()).Invert()
if !ok { if !ok {
return fmt.Errorf("composite clip transform is not invertible") return fmt.Errorf("composite clip transform is not invertible")
} }
@@ -212,7 +212,7 @@ func (e *Editor) eraseObjects(page int, ids []string, box Box, points []Point, r
*clips = &Clips{} *clips = &Clips{}
} }
matrix := IdentityMatrix matrix := IdentityMatrix
if (*clips).TransFlag == nil || *(*clips).TransFlag { if (*clips).usesObjectMatrix() {
if object.Type == "ImageObject" && ctm == "" { if object.Type == "ImageObject" && ctm == "" {
ctm = Matrix{a: frame.W, d: frame.H}.String() ctm = Matrix{a: frame.W, d: frame.H}.String()
} }
+5
View File
@@ -261,6 +261,11 @@ func (x *ofdXML) referenceElement(name string, value any) {
} }
var attrs ofdAttrs var attrs ofdAttrs
switch value := value.(type) { switch value := value.(type) {
case *Dest:
if value == nil {
return
}
attrs.add("PageID", value.PageID)
case ShdColor: case ShdColor:
attrs.add("ColorSpace", value.ColorSpace) attrs.add("ColorSpace", value.ColorSpace)
case *ShdColor: case *ShdColor:
+4 -9
View File
@@ -456,7 +456,7 @@ func transformEditorMatrix(object GraphicObject, matrix Matrix) GraphicObject {
local := TranslationMatrix(-after.X, -after.Y).Multiply(matrix).Multiply(TranslationMatrix(before.X, before.Y)) local := TranslationMatrix(-after.X, -after.Y).Multiply(matrix).Multiply(TranslationMatrix(before.X, before.Y))
*ctm = local.Multiply(NewMatrix(*ctm)).String() *ctm = local.Multiply(NewMatrix(*ctm)).String()
*boundary = editorBoxString(after) *boundary = editorBoxString(after)
if clips := editorObjectClips(&object); *clips != nil && (*clips).TransFlag != nil && !*(*clips).TransFlag { if clips := editorObjectClips(&object); *clips != nil && !(*clips).usesObjectMatrix() {
*clips = transformObjectClips(*clips, local) *clips = transformObjectClips(*clips, local)
} }
if !axisAlignedMatrix(matrix) && before.W > 0 && before.H > 0 { if !axisAlignedMatrix(matrix) && before.W > 0 && before.H > 0 {
@@ -469,13 +469,12 @@ func transformEditorMatrix(object GraphicObject, matrix Matrix) GraphicObject {
*clips = &copy *clips = &copy
} }
clipMatrix := local clipMatrix := local
if (*clips).TransFlag == nil || *(*clips).TransFlag { if (*clips).usesObjectMatrix() {
if inverse, ok := NewMatrix(*ctm).Invert(); ok { if inverse, ok := NewMatrix(*ctm).Invert(); ok {
clipMatrix = inverse.Multiply(local) clipMatrix = inverse.Multiply(local)
} else { } else {
*clips = transformObjectClips(*clips, NewMatrix(*ctm)) *clips = transformObjectClips(*clips, NewMatrix(*ctm))
flag := false (*clips).TransFlag = nil
(*clips).TransFlag = &flag
} }
} }
fill, stroke := true, false fill, stroke := true, false
@@ -526,17 +525,13 @@ func cropImageObject(image *ImageObject, box Box) error {
image.Boundary = editorBoxString(box) image.Boundary = editorBoxString(box)
image.Clips = nil image.Clips = nil
if box != full { if box != full {
inverse, ok := NewMatrix(image.CTM).Invert()
if !ok {
return fmt.Errorf("image transform is not invertible")
}
path, err := NewShape(ShapeRectangle, Box{W: box.W, H: box.H}) path, err := NewShape(ShapeRectangle, Box{W: box.W, H: box.H})
if err != nil { if err != nil {
return err return err
} }
fill, stroke := true, false fill, stroke := true, false
path.Fill, path.Stroke = &fill, &stroke path.Fill, path.Stroke = &fill, &stroke
image.Clips = &Clips{Clip: []Clip{{Area: []ClipArea{{CTM: inverse.String(), Path: []PathObject{path}}}}}} image.Clips = &Clips{Clip: []Clip{{Area: []ClipArea{{Path: []PathObject{path}}}}}}
} }
return nil return nil
} }
+16
View File
@@ -373,6 +373,19 @@ func editorXMLObject(data []byte, node *editorXML, before, after GraphicObject)
// 入参: data 原文, node 原节点, oldXML 修改前编码, newXML 修改后编码 // 入参: data 原文, node 原节点, oldXML 修改前编码, newXML 修改后编码
// 返回: []byte 更新节点, error 错误信息 // 返回: []byte 更新节点, error 错误信息
func editorXMLMerge(data []byte, node *editorXML, oldXML, newXML []byte) ([]byte, error) { func editorXMLMerge(data []byte, node *editorXML, oldXML, newXML []byte) ([]byte, error) {
legacyClip := node.name.Local == "Clips" && node.hasAttr("TransFlag")
if legacyClip {
var clips Clips
if err := xml.Unmarshal(data[node.start:node.end], &clips); err != nil {
return nil, err
}
clips.TransFlag = nil
var err error
oldXML, err = encodeOFDXML(func(x *ofdXML) { x.clips(&clips, "") })
if err != nil {
return nil, err
}
}
oldNode, err := parseEditorXML(oldXML) oldNode, err := parseEditorXML(oldXML)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -382,6 +395,9 @@ func editorXMLMerge(data []byte, node *editorXML, oldXML, newXML []byte) ([]byte
return nil, err return nil, err
} }
changes := make(map[string]string) changes := make(map[string]string)
if legacyClip {
changes["TransFlag"] = ""
}
for _, attr := range append(oldNode.attrs, newNode.attrs...) { for _, attr := range append(oldNode.attrs, newNode.attrs...) {
if attr.Name.Space == "" && (oldNode.attr(attr.Name.Local) != newNode.attr(attr.Name.Local) || oldNode.hasAttr(attr.Name.Local) != newNode.hasAttr(attr.Name.Local)) { if attr.Name.Space == "" && (oldNode.attr(attr.Name.Local) != newNode.attr(attr.Name.Local) || oldNode.hasAttr(attr.Name.Local) != newNode.hasAttr(attr.Name.Local)) {
changes[attr.Name.Local] = newNode.attr(attr.Name.Local) changes[attr.Name.Local] = newNode.attr(attr.Name.Local)
+1 -1
View File
@@ -47,7 +47,7 @@ type StrokeOptions struct {
} }
// GeometryBackend 操作库自有路径,坐标以页面左上角为原点,不修改任何输入 // GeometryBackend 操作库自有路径,坐标以页面左上角为原点,不修改任何输入
// Clip返回nil表示不裁剪,空路径指针表示完全裁去,矩阵映射到页面坐标 // Clip返回nil表示不裁剪,空路径指针表示完全裁去,矩阵将裁剪坐标映射到页面坐标
type GeometryBackend interface { type GeometryBackend interface {
Backend Backend
Path(object PathObject) (GeometryPath, error) Path(object PathObject) (GeometryPath, error)
+6
View File
@@ -47,6 +47,12 @@ func (o GraphicObject) Actions() []Action {
return nil return nil
} }
// usesObjectMatrix 判断旧式扩展是否要求裁剪跟随对象变换,标准裁剪以外接矩形为基准
// 返回: bool 是否叠加对象CTM
func (clips *Clips) usesObjectMatrix() bool {
return clips != nil && clips.TransFlag != nil && *clips.TransFlag
}
// UnmarshalXML 解析路径并区分省略样式、显式实线与零线宽 // UnmarshalXML 解析路径并区分省略样式、显式实线与零线宽
// 入参: d XML解码器, start 起始节点 // 入参: d XML解码器, start 起始节点
// 返回: error 错误信息 // 返回: error 错误信息
+2 -1
View File
@@ -62,7 +62,8 @@ type GraphicObject struct {
state editorCompositeState state editorCompositeState
} }
// Clips 裁剪区域集合 // Clips 相对于对象外接矩形的裁剪集合
// TransFlag仅兼容旧式扩展,写入时折算为Area的CTM
type Clips struct { type Clips struct {
TransFlag *bool `xml:"TransFlag,attr"` TransFlag *bool `xml:"TransFlag,attr"`
Clip []Clip `xml:"Clip"` Clip []Clip `xml:"Clip"`
+1 -1
View File
@@ -502,7 +502,7 @@ func (p *pdfImporter) clips(paths []pdfgo.Path, origin Box) (*Clips, error) {
continue continue
} }
if clips == nil { if clips == nil {
clips = &Clips{TransFlag: new(false), Clip: make([]Clip, 0, len(paths))} clips = &Clips{Clip: make([]Clip, 0, len(paths))}
areas = make([]ClipArea, len(paths)) areas = make([]ClipArea, len(paths))
if origin.X != 0 || origin.Y != 0 { if origin.X != 0 || origin.Y != 0 {
translation = pdfNumbers(1, 0, 0, 1, -origin.X, -origin.Y) translation = pdfNumbers(1, 0, 0, 1, -origin.X, -origin.Y)
+3 -3
View File
@@ -74,7 +74,7 @@ func pdfPageClip(object GraphicObject) *Clips {
return nil return nil
} }
clips := *editorObjectClips(&object) clips := *editorObjectClips(&object)
if clips == nil || clips.TransFlag == nil || *clips.TransFlag || len(clips.Clip) == 0 { if clips == nil || clips.usesObjectMatrix() || len(clips.Clip) == 0 {
return nil return nil
} }
boundary, _ := editorGeometry(object) boundary, _ := editorGeometry(object)
@@ -87,7 +87,7 @@ func pdfPageClip(object GraphicObject) *Clips {
translation = pdfNumbers(1, 0, 0, 1, -box.X, -box.Y) translation = pdfNumbers(1, 0, 0, 1, -box.X, -box.Y)
} }
bytes := 0 bytes := 0
result := &Clips{TransFlag: clips.TransFlag, Clip: make([]Clip, len(clips.Clip))} result := &Clips{Clip: make([]Clip, len(clips.Clip))}
for index, clip := range clips.Clip { for index, clip := range clips.Clip {
if len(clip.Area) != 1 || clip.Area[0].CTM != translation { if len(clip.Area) != 1 || clip.Area[0].CTM != translation {
return nil return nil
@@ -113,7 +113,7 @@ func pdfMatchesPageClip(object GraphicObject, pageClip *Clips) bool {
return false return false
} }
clips := *editorObjectClips(&object) clips := *editorObjectClips(&object)
if clips == nil || clips.TransFlag == nil || *clips.TransFlag || len(clips.Clip) != len(pageClip.Clip) { if clips == nil || clips.usesObjectMatrix() || len(clips.Clip) != len(pageClip.Clip) {
return false return false
} }
boundary, _ := editorGeometry(object) boundary, _ := editorGeometry(object)
+1 -4
View File
@@ -373,10 +373,7 @@ func (r *Renderer) objectGeometryClip(clips *Clips, boundary string, local Matri
return clip, nil return clip, nil
} }
matrix, _ := renderObjectMatrix(boundary, local, state) matrix, _ := renderObjectMatrix(boundary, local, state)
if clips.TransFlag != nil && !*clips.TransFlag { if !clips.usesObjectMatrix() {
copy := *clips
copy.TransFlag = nil
clips = &copy
box, _ := ParseBox(boundary) box, _ := ParseBox(boundary)
matrix = TranslationMatrix(box.X, box.Y) matrix = TranslationMatrix(box.X, box.Y)
if state.BoundaryInCTM && state.Parent != nil { if state.BoundaryInCTM && state.Parent != nil {
+2 -4
View File
@@ -225,10 +225,8 @@ func (r *Renderer) walkComposite(object CompositeGraphicUnit, state RenderState,
return err return err
} }
clips, clipMatrix := object.Clips, matrix clips, clipMatrix := object.Clips, matrix
if clips != nil && clips.TransFlag != nil && !*clips.TransFlag { if !clips.usesObjectMatrix() {
copy := *clips clipMatrix = boundary
copy.TransFlag = nil
clips, clipMatrix = &copy, boundary
} }
if clips != nil { if clips != nil {
geometry, err := r.Geometry() geometry, err := r.Geometry()
+3 -6
View File
@@ -86,9 +86,9 @@ func (r *Renderer) buildObjectClipPath(clips *Clips, pageH float64, boundary str
} }
// buildClipPath 构建裁剪路径 // buildClipPath 构建裁剪路径
// 入参: clips 裁剪对象, pageH 页面高度, bx 边界X坐标, by 边界Y坐标, objectCTM 对象CTM // 入参: clips 裁剪对象, pageH 页面高度, bx 边界X坐标, by 边界Y坐标, matrix 裁剪坐标到页面的变换
// 返回: *canvas.Path 路径对象 // 返回: *canvas.Path 路径对象
func (r *Renderer) buildClipPath(clips *Clips, pageH float64, bx, by float64, objectCTM Matrix) *canvas.Path { func (r *Renderer) buildClipPath(clips *Clips, pageH float64, bx, by float64, matrix Matrix) *canvas.Path {
if clips == nil { if clips == nil {
return nil return nil
} }
@@ -96,10 +96,7 @@ func (r *Renderer) buildClipPath(clips *Clips, pageH float64, bx, by float64, ob
for _, clip := range clips.Clip { for _, clip := range clips.Clip {
renderer := &clipRenderer{} renderer := &clipRenderer{}
for _, area := range clip.Area { for _, area := range clip.Area {
areaCTM := NewMatrix(area.CTM) areaCTM := matrix.Multiply(NewMatrix(area.CTM))
if clips.TransFlag == nil || *clips.TransFlag {
areaCTM = objectCTM.Multiply(areaCTM)
}
for _, pathObj := range area.Path { for _, pathObj := range area.Path {
renderer.add(r.buildClipAreaPath(pathObj, area.DrawParam, areaCTM, pageH, bx, by)) renderer.add(r.buildClipAreaPath(pathObj, area.DrawParam, areaCTM, pageH, bx, by))
if r.renderError != nil { if r.renderError != nil {
+1 -1
View File
@@ -181,7 +181,7 @@ func (CanvasBackend) Stroke(path GeometryPath, options StrokeOptions) (result Ge
} }
// Clip 解析对象裁剪并与父裁剪相交,保留未裁剪与完全裁去的区别 // Clip 解析对象裁剪并与父裁剪相交,保留未裁剪与完全裁去的区别
// 入参: r 渲染器, clips OFD裁剪, matrix 页面变换, parent 父裁剪 // 入参: r 渲染器, clips OFD裁剪, matrix 裁剪坐标到页面的变换, parent 父裁剪
// 返回: *GeometryPath 页面裁剪, error 无效父路径错误 // 返回: *GeometryPath 页面裁剪, error 无效父路径错误
func (CanvasBackend) Clip(r *Renderer, clips *Clips, matrix Matrix, parent *GeometryPath) (*GeometryPath, error) { func (CanvasBackend) Clip(r *Renderer, clips *Clips, matrix Matrix, parent *GeometryPath) (*GeometryPath, error) {
p, err := geometryToCanvasPath(parent) p, err := geometryToCanvasPath(parent)
+20 -10
View File
@@ -870,17 +870,22 @@ func (x *ofdXML) object(object GraphicObject, root bool) {
x.start(object.Type, attrs) x.start(object.Type, attrs)
x.actions(actions) x.actions(actions)
if object.Type == "ImageObject" { if object.Type == "ImageObject" {
x.clips(object.ImageObject.Clips) ctm := object.ImageObject.CTM
if ctm == "" && object.ImageObject.Clips.usesObjectMatrix() {
box, _ := ParseBox(object.ImageObject.Boundary)
ctm = (Matrix{a: box.W, d: box.H}).String()
}
x.clips(object.ImageObject.Clips, ctm)
x.border(object.ImageObject.Border) x.border(object.ImageObject.Border)
} else if object.Type == "CompositeObject" || object.Type == "CompositeGraphicUnit" { } else if object.Type == "CompositeObject" || object.Type == "CompositeGraphicUnit" {
x.clips(object.CompositeGraphicUnit.Clips) x.clips(object.CompositeGraphicUnit.Clips, object.CompositeGraphicUnit.CTM)
} else if object.Type == "PathObject" || object.Type == "Path" { } else if object.Type == "PathObject" || object.Type == "Path" {
x.clips(object.PathObject.Clips) x.clips(object.PathObject.Clips, object.PathObject.CTM)
x.color("StrokeColor", stroke) x.color("StrokeColor", stroke)
x.color("FillColor", fill) x.color("FillColor", fill)
x.text("AbbreviatedData", object.PathObject.AbbreviatedData) x.text("AbbreviatedData", object.PathObject.AbbreviatedData)
} else if object.Type == "TextObject" || object.Type == "Text" { } else if object.Type == "TextObject" || object.Type == "Text" {
x.clips(object.TextObject.Clips) x.clips(object.TextObject.Clips, object.TextObject.CTM)
x.color("FillColor", fill) x.color("FillColor", fill)
x.color("StrokeColor", stroke) x.color("StrokeColor", stroke)
offset, index := 0, 0 offset, index := 0, 0
@@ -917,15 +922,17 @@ func (x *ofdXML) object(object GraphicObject, root bool) {
x.end(object.Type) x.end(object.Type)
} }
// clips 写出对象裁剪,保留区域内的路径与文字 // clips 写出标准裁剪,将旧式随动裁剪折算为区域变换
// 入参: clips 裁剪集合,nil不输出节点 // 入参: clips 裁剪集合,nil不输出节点, ctm 对象变换矩阵
func (x *ofdXML) clips(clips *Clips) { func (x *ofdXML) clips(clips *Clips, ctm string) {
if clips == nil || !x.checkContext() { if clips == nil || !x.checkContext() {
return return
} }
var attrs ofdAttrs matrix := IdentityMatrix
attrs.flag("TransFlag", clips.TransFlag) if clips.usesObjectMatrix() {
x.start("Clips", attrs) matrix = NewMatrix(ctm)
}
x.start("Clips", nil)
for _, clip := range clips.Clip { for _, clip := range clips.Clip {
if x.err != nil { if x.err != nil {
return return
@@ -936,6 +943,9 @@ func (x *ofdXML) clips(clips *Clips) {
return return
} }
var attrs ofdAttrs var attrs ofdAttrs
if clips.usesObjectMatrix() {
area.CTM = matrix.Multiply(NewMatrix(area.CTM)).String()
}
attrs.add("CTM", area.CTM) attrs.add("CTM", area.CTM)
attrs.add("DrawParam", area.DrawParam) attrs.add("DrawParam", area.DrawParam)
for _, path := range area.Path { for _, path := range area.Path {