mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 08:46:55 +08:00
1 parent
5e0da3da28
commit
ee6c9f6a16
82 files changed
+4316
-4310
No files matched your search
+109
-109
@@ -22,28 +22,6 @@ import (
|
||||
"slices"
|
||||
)
|
||||
|
||||
// matrix 获取对象局部坐标到页面的变换,兼容旧式内联边界
|
||||
// 入参: transform 是否包含对象CTM
|
||||
// 返回: Matrix 坐标变换
|
||||
func (n *editorCompositeNode) matrix(transform bool) Matrix {
|
||||
boundary, ctm := editorGeometry(n.object)
|
||||
box, _ := ParseBox(boundary)
|
||||
m := IdentityMatrix
|
||||
if transform {
|
||||
m = NewMatrix(ctm)
|
||||
if n.object.Type == "ImageObject" && ctm == "" {
|
||||
m = Matrix{a: box.W, d: box.H}
|
||||
}
|
||||
}
|
||||
if n.boundaryInCTM || n.object.Type == "CompositeObject" || n.object.Type == "CompositeGraphicUnit" {
|
||||
return n.parent.Multiply(TranslationMatrix(box.X, box.Y)).Multiply(m)
|
||||
}
|
||||
if !transform {
|
||||
return TranslationMatrix(box.X, box.Y)
|
||||
}
|
||||
return TranslationMatrix(box.X, box.Y).Multiply(n.parent).Multiply(m)
|
||||
}
|
||||
|
||||
// CropCompositeImage 将内部图片与页面矩形取交集,保留原裁剪、蒙版、变换和边框
|
||||
// 只收窄可见区域,撤销恢复上次裁剪,不重采样图片
|
||||
// 入参: page 页面索引, path 父复合路径, index 图片序号, box 页面毫米范围
|
||||
@@ -76,57 +54,6 @@ func (e *Editor) CropCompositeImage(page int, path ObjectPath, index int, box Bo
|
||||
})
|
||||
}
|
||||
|
||||
// appendCompositeClip 追加独立交集裁剪并记录可还原序号,保留原始裁剪XML
|
||||
// 入参: node 对象节点, shape 裁剪路径, matrix 路径到裁剪坐标的变换, track 是否记录还原序号
|
||||
// 返回: error 错误信息
|
||||
func appendCompositeClip(node *editorCompositeNode, shape PathObject, matrix Matrix, track bool) error {
|
||||
clip := Clip{Area: []ClipArea{{CTM: matrix.String(), Path: []PathObject{shape}}}}
|
||||
if clips := *editorObjectClips(&node.object); clips != nil && slices.ContainsFunc(clips.Clip, func(previous Clip) bool { return reflect.DeepEqual(previous, clip) }) {
|
||||
return nil
|
||||
}
|
||||
state := node.states[editorObjectID(node.object)]
|
||||
if track {
|
||||
crop := editorCompositeCrop{exists: node.node.child("Clips") != nil}
|
||||
if state.crop != nil {
|
||||
crop = *state.crop
|
||||
}
|
||||
count := 0
|
||||
if clips := node.object.ImageObject.Clips; clips != nil {
|
||||
count = len(clips.Clip)
|
||||
}
|
||||
crop.indexes = append(slices.Clone(crop.indexes), count)
|
||||
state.crop = &crop
|
||||
}
|
||||
data, err := encodeOFDXML(func(x *ofdXML) {
|
||||
x.clips(&Clips{Clip: []Clip{clip}})
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = bytes.TrimPrefix(data, []byte(xml.Header))
|
||||
root, err := parseEditorXML(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var patch editorXMLPatch
|
||||
if original := node.node.child("Clips"); original != nil {
|
||||
clip := editorXMLEncodedFragment(data, root.children[0])
|
||||
content := append(bytes.Clone(node.data[original.open:original.close]), clip...)
|
||||
patch = editorXMLContent(node.data, original, content)
|
||||
} else {
|
||||
data = editorXMLEncodedFragment(data, root)
|
||||
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}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.data, node.node, node.object, node.changed = updated.data, updated.node, updated.object, true
|
||||
node.setState(state)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetCompositeImageCrop 仅移除本次编辑追加的裁剪,保留输入文件中的裁剪、蒙版和其他属性
|
||||
// 入参: page 页面索引, path 父路径, index 图片序号
|
||||
// 返回: error 错误信息
|
||||
@@ -181,42 +108,6 @@ func (e *Editor) ResetImageCrop(page int, id string) error {
|
||||
return e.updateObjectOrigins(page, []GraphicObject{node.object}, true, map[string]*editorObjectOrigin{id: next})
|
||||
}
|
||||
|
||||
// resetCompositeImageCrop 恢复图片原始裁剪节点,不还原后续变换和资源替换
|
||||
// 入参: node 图片节点
|
||||
// 返回: error 错误信息
|
||||
func resetCompositeImageCrop(node *editorCompositeNode) error {
|
||||
if node.object.Type != "ImageObject" {
|
||||
return fmt.Errorf("composite member is not an image")
|
||||
}
|
||||
state := node.states[editorObjectID(node.object)]
|
||||
if state.crop == nil {
|
||||
return nil
|
||||
}
|
||||
clips := node.node.child("Clips")
|
||||
var patches []editorXMLPatch
|
||||
if !state.crop.exists && len(node.object.ImageObject.Clips.Clip) == len(state.crop.indexes) {
|
||||
patches = append(patches, editorXMLPatch{clips.start, clips.end, nil})
|
||||
} else {
|
||||
count := 0
|
||||
for _, child := range clips.children {
|
||||
if child.name.Local == "Clip" {
|
||||
if slices.Contains(state.crop.indexes, count) {
|
||||
patches = append(patches, editorXMLPatch{child.start, child.end, nil})
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
updated, err := newEditorCompositeNode(editorPatchXML(node.data, patches))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.data, node.node, node.object, node.changed = updated.data, updated.node, updated.object, true
|
||||
state.crop = nil
|
||||
node.setState(state)
|
||||
return nil
|
||||
}
|
||||
|
||||
// FitCompositeImage 按原像素比例适应或填充内部图片框,保留原始裁剪和蒙版
|
||||
// 入参: page 页面索引, path 父路径, index 图片序号, mode 为contain或cover
|
||||
// 返回: error 错误信息
|
||||
@@ -256,3 +147,112 @@ func (e *Editor) FitCompositeImage(page int, path ObjectPath, index int, mode st
|
||||
return appendCompositeClip(node, shape, inverse.Multiply(frame), true)
|
||||
})
|
||||
}
|
||||
|
||||
// matrix 获取对象局部坐标到页面的变换,兼容旧式内联边界
|
||||
// 入参: transform 是否包含对象CTM
|
||||
// 返回: Matrix 坐标变换
|
||||
func (n *editorCompositeNode) matrix(transform bool) Matrix {
|
||||
boundary, ctm := editorGeometry(n.object)
|
||||
box, _ := ParseBox(boundary)
|
||||
m := IdentityMatrix
|
||||
if transform {
|
||||
m = NewMatrix(ctm)
|
||||
if n.object.Type == "ImageObject" && ctm == "" {
|
||||
m = Matrix{a: box.W, d: box.H}
|
||||
}
|
||||
}
|
||||
if n.boundaryInCTM || n.object.Type == "CompositeObject" || n.object.Type == "CompositeGraphicUnit" {
|
||||
return n.parent.Multiply(TranslationMatrix(box.X, box.Y)).Multiply(m)
|
||||
}
|
||||
if !transform {
|
||||
return TranslationMatrix(box.X, box.Y)
|
||||
}
|
||||
return TranslationMatrix(box.X, box.Y).Multiply(n.parent).Multiply(m)
|
||||
}
|
||||
|
||||
// appendCompositeClip 追加独立交集裁剪并记录可还原序号,保留原始裁剪XML
|
||||
// 入参: node 对象节点, shape 裁剪路径, matrix 路径到裁剪坐标的变换, track 是否记录还原序号
|
||||
// 返回: error 错误信息
|
||||
func appendCompositeClip(node *editorCompositeNode, shape PathObject, matrix Matrix, track bool) error {
|
||||
clip := Clip{Area: []ClipArea{{CTM: matrix.String(), Path: []PathObject{shape}}}}
|
||||
if clips := *editorObjectClips(&node.object); clips != nil && slices.ContainsFunc(clips.Clip, func(previous Clip) bool { return reflect.DeepEqual(previous, clip) }) {
|
||||
return nil
|
||||
}
|
||||
state := node.states[editorObjectID(node.object)]
|
||||
if track {
|
||||
crop := editorCompositeCrop{exists: node.node.child("Clips") != nil}
|
||||
if state.crop != nil {
|
||||
crop = *state.crop
|
||||
}
|
||||
count := 0
|
||||
if clips := node.object.ImageObject.Clips; clips != nil {
|
||||
count = len(clips.Clip)
|
||||
}
|
||||
crop.indexes = append(slices.Clone(crop.indexes), count)
|
||||
state.crop = &crop
|
||||
}
|
||||
data, err := encodeOFDXML(func(x *ofdXML) {
|
||||
x.clips(&Clips{Clip: []Clip{clip}})
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = bytes.TrimPrefix(data, []byte(xml.Header))
|
||||
root, err := parseEditorXML(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var patch editorXMLPatch
|
||||
if original := node.node.child("Clips"); original != nil {
|
||||
clip := editorXMLEncodedFragment(data, root.children[0])
|
||||
content := append(bytes.Clone(node.data[original.open:original.close]), clip...)
|
||||
patch = editorXMLContent(node.data, original, content)
|
||||
} else {
|
||||
data = editorXMLEncodedFragment(data, root)
|
||||
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}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.data, node.node, node.object, node.changed = updated.data, updated.node, updated.object, true
|
||||
node.setState(state)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resetCompositeImageCrop 恢复图片原始裁剪节点,不还原后续变换和资源替换
|
||||
// 入参: node 图片节点
|
||||
// 返回: error 错误信息
|
||||
func resetCompositeImageCrop(node *editorCompositeNode) error {
|
||||
if node.object.Type != "ImageObject" {
|
||||
return fmt.Errorf("composite member is not an image")
|
||||
}
|
||||
state := node.states[editorObjectID(node.object)]
|
||||
if state.crop == nil {
|
||||
return nil
|
||||
}
|
||||
clips := node.node.child("Clips")
|
||||
var patches []editorXMLPatch
|
||||
if !state.crop.exists && len(node.object.ImageObject.Clips.Clip) == len(state.crop.indexes) {
|
||||
patches = append(patches, editorXMLPatch{clips.start, clips.end, nil})
|
||||
} else {
|
||||
count := 0
|
||||
for _, child := range clips.children {
|
||||
if child.name.Local == "Clip" {
|
||||
if slices.Contains(state.crop.indexes, count) {
|
||||
patches = append(patches, editorXMLPatch{child.start, child.end, nil})
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
updated, err := newEditorCompositeNode(editorPatchXML(node.data, patches))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.data, node.node, node.object, node.changed = updated.data, updated.node, updated.object, true
|
||||
state.crop = nil
|
||||
node.setState(state)
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user