mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
This commit is contained in:
1 parent
0f86c8d727
commit
f8eeaad9f2
16 files changed
+546
-109
No files matched your search
+122
-38
@@ -37,8 +37,7 @@ type CompositeSelection struct {
|
||||
source *editorSourcePage
|
||||
}
|
||||
|
||||
// PasteCompositeSelection 将内部基本对象快照粘贴到页面顶层,保持源继承外观和裁剪
|
||||
// 复合成员需留在原范围操作,不将未知嵌套结构强制扁平化
|
||||
// PasteCompositeSelection 将内部对象快照粘贴到页面顶层,保持嵌套结构、源继承外观和裁剪
|
||||
// 入参: page 目标页, selection 当前编辑器内捕获的快照, dx、dy 页面位移
|
||||
// 返回: []string 新对象标识, error 错误信息
|
||||
func (e *Editor) PasteCompositeSelection(page int, selection *CompositeSelection, dx, dy float64) ([]string, error) {
|
||||
@@ -48,31 +47,35 @@ func (e *Editor) PasteCompositeSelection(page int, selection *CompositeSelection
|
||||
if _, err := e.page(page); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objects, err := e.compositeSelectionObjects(selection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.CopyObjects(page, objects, dx, dy)
|
||||
var result []string
|
||||
err := e.pasteCompositeSelection(selection, func(objects []GraphicObject) error {
|
||||
var err error
|
||||
result, err = e.CopyObjects(page, objects, dx, dy)
|
||||
return err
|
||||
})
|
||||
return result, err
|
||||
}
|
||||
|
||||
// compositeSelectionObjects 固定内部基本对象的页面几何和父裁剪,保留原XML扩展
|
||||
// 入参: selection 独立内部快照
|
||||
// 返回: []GraphicObject 可复制到其他范围的快照, error 错误信息
|
||||
func (e *Editor) compositeSelectionObjects(selection *CompositeSelection) ([]GraphicObject, error) {
|
||||
// pasteCompositeSelection 固定内部快照的页面几何和外观,粘贴失败时回收新增绘制资源
|
||||
// 入参: selection 独立内部快照, paste 目标范围粘贴操作
|
||||
// 返回: error 错误信息
|
||||
func (e *Editor) pasteCompositeSelection(selection *CompositeSelection, paste func([]GraphicObject) error) (err error) {
|
||||
if selection == nil || selection.editor != e {
|
||||
return nil, fmt.Errorf("composite selection belongs to another editor")
|
||||
return fmt.Errorf("composite selection belongs to another editor")
|
||||
}
|
||||
for _, node := range selection.nodes {
|
||||
if node.object.Type == "CompositeObject" || node.object.Type == "CompositeGraphicUnit" {
|
||||
return nil, fmt.Errorf("composite groups require their original editing scope")
|
||||
count, maximum, ready := len(e.resources), e.maxID, e.source.idsReady
|
||||
defer func() {
|
||||
if err != nil {
|
||||
clear(e.resources[count:])
|
||||
e.resources, e.maxID, e.source.idsReady = e.resources[:count], maximum, ready
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err := e.prepareSourceIDs(); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
reader, err := e.Reader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
renderer := NewRenderer(reader, WithFontFS(e.fontFS...))
|
||||
@@ -80,12 +83,13 @@ func (e *Editor) compositeSelectionObjects(selection *CompositeSelection) ([]Gra
|
||||
for _, source := range selection.nodes {
|
||||
copy, err := newEditorCompositeNode(source.data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
copy.setStates(source.states)
|
||||
copy.defaults = source.defaults
|
||||
object, err := e.compositeMemberStyle(source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
object = mergeGraphicObjectAlpha(object, source.alpha)
|
||||
if !source.visible || source.clip != nil && source.clip.Empty() {
|
||||
@@ -97,48 +101,126 @@ func (e *Editor) compositeSelectionObjects(selection *CompositeSelection) ([]Gra
|
||||
object.PathObject.Visible = &visible
|
||||
case "ImageObject":
|
||||
object.ImageObject.Visible = &visible
|
||||
case "CompositeObject", "CompositeGraphicUnit":
|
||||
object.CompositeGraphicUnit.Visible = &visible
|
||||
}
|
||||
}
|
||||
if !source.boundaryInCTM {
|
||||
object = compositeBoundary(object, source.parent, true)
|
||||
}
|
||||
if err := copy.update(object); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if !source.boundaryInCTM {
|
||||
if err := copy.convertCoordinates(source.parent, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
copy.parent, copy.boundaryInCTM = IdentityMatrix, true
|
||||
if err := e.transformCompositeMember(renderer, copy, source.parent); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if err := e.isolateCompositeStyle(copy); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if source.clip != nil && !source.clip.Empty() {
|
||||
shape := compositeClipPath(source.clip)
|
||||
clips := *editorObjectClips(©.object)
|
||||
matrix, ok := copy.matrix(clips == nil || clips.TransFlag == nil || *clips.TransFlag).Invert()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("composite clip transform is not invertible")
|
||||
return fmt.Errorf("composite clip transform is not invertible")
|
||||
}
|
||||
if err := appendCompositeClip(copy, shape, matrix, false); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
if copy.object.Type == "CompositeObject" || copy.object.Type == "CompositeGraphicUnit" {
|
||||
if err := copy.convertCoordinates(IdentityMatrix, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
copy.node.parent = &editorXML{name: xml.Name{Local: "Layer"}, parent: &editorXML{name: xml.Name{Local: "Content"}}}
|
||||
object, err = e.resolveEditorStyle(copy.object, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
object.state = copy.states[editorObjectID(copy.object)]
|
||||
object.TextObject.layout = object.state.layout
|
||||
copy.object.TextObject.layout = object.TextObject.layout
|
||||
if object.Type == "CompositeObject" || object.Type == "CompositeGraphicUnit" {
|
||||
object.CompositeGraphicUnit.states = maps.Clone(copy.states)
|
||||
copy.object.CompositeGraphicUnit.states = object.CompositeGraphicUnit.states
|
||||
}
|
||||
object.origin = &editorObjectOrigin{page: selection.source, data: copy.data, node: copy.node, object: copy.object}
|
||||
objects = append(objects, object)
|
||||
}
|
||||
return objects, nil
|
||||
return paste(objects)
|
||||
}
|
||||
|
||||
// convertCoordinates 转换内联基本成员的边界约定,引用资源保持标准局部坐标
|
||||
// 入参: parent 所在范围矩阵, inward 是否转换到随父变换的坐标
|
||||
// 返回: error 错误信息
|
||||
func (n *editorCompositeNode) convertCoordinates(parent Matrix, inward bool) error {
|
||||
if n.object.Type != "CompositeObject" && n.object.Type != "CompositeGraphicUnit" {
|
||||
return n.update(compositeBoundary(n.object, parent, inward))
|
||||
}
|
||||
var patches []editorXMLPatch
|
||||
var visit func(*editorXML, Matrix) error
|
||||
visit = func(node *editorXML, matrix Matrix) error {
|
||||
if node.name.Local == "CompositeObject" || node.name.Local == "CompositeGraphicUnit" {
|
||||
box, _ := ParseBox(node.attr("Boundary"))
|
||||
matrix = matrix.Multiply(TranslationMatrix(box.X, box.Y)).Multiply(NewMatrix(node.attr("CTM")))
|
||||
if _, ok := matrix.Invert(); !ok {
|
||||
return fmt.Errorf("composite copy requires invertible transforms")
|
||||
}
|
||||
}
|
||||
for _, child := range node.children {
|
||||
if child.name.Space != "" && child.name.Space != ofdNamespace && child.name.Space != "http://www.ofdspec.org" {
|
||||
continue
|
||||
}
|
||||
switch child.name.Local {
|
||||
case "Content", "PageBlock", "CompositeObject", "CompositeGraphicUnit":
|
||||
if err := visit(child, matrix); err != nil {
|
||||
return err
|
||||
}
|
||||
case "TextObject", "PathObject", "ImageObject":
|
||||
data, err := editorXMLStandalone(n.data[child.start:child.end], child)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member, err := newEditorCompositeNode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := member.update(compositeBoundary(cloneEditorData(member.object), matrix, inward)); err != nil {
|
||||
return err
|
||||
}
|
||||
patches = append(patches, editorXMLPatch{child.start, child.end, member.data})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := visit(n.node, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
data := editorPatchXML(n.data, patches)
|
||||
next, err := newEditorCompositeNode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.data, n.node, n.object = data, next.node, next.object
|
||||
return nil
|
||||
}
|
||||
|
||||
// compositeClipPath 将已解析的父裁剪转换为标准紧缩路径,使用页面毫米坐标
|
||||
// 入参: path 画布裁剪
|
||||
// 返回: PathObject 标准裁剪路径
|
||||
func compositeClipPath(path *canvas.Path) PathObject {
|
||||
path = path.Copy().Transform(canvas.Matrix{{1, 0, 0}, {0, -1, 0}}).ReplaceArcs()
|
||||
return editorClipPath(path.Copy().Transform(canvas.Matrix{{1, 0, 0}, {0, -1, 0}}))
|
||||
}
|
||||
|
||||
// editorClipPath 将页面坐标路径写为标准紧缩裁剪路径
|
||||
// 入参: path 页面毫米路径
|
||||
// 返回: PathObject 标准裁剪路径
|
||||
func editorClipPath(path *canvas.Path) PathObject {
|
||||
path = path.ReplaceArcs()
|
||||
data := path.Data()
|
||||
var value strings.Builder
|
||||
for i := 0; i < len(data); {
|
||||
@@ -211,7 +293,7 @@ func (e *Editor) CaptureCompositeObjects(page int, path ObjectPath, indexes []in
|
||||
}
|
||||
|
||||
// PasteCompositeObjects 将快照粘贴至内部范围末尾,不依赖源成员当前的序号或存在性
|
||||
// 同范围沿用原容器和当前继承样式,跨范围固定基本对象的源外观,位移使用页面毫米
|
||||
// 同范围沿用原容器和当前继承样式,跨范围固定对象的源外观,位移使用页面毫米
|
||||
// 目标范围的父透明度及裁剪仍作用于新成员,全部成员提交一次撤销记录
|
||||
// 入参: page 页面索引, path 父复合路径, selection 捕获的快照, dx、dy 页面位移
|
||||
// 返回: []int 新成员序号, error 错误信息
|
||||
@@ -226,11 +308,13 @@ func (e *Editor) PasteCompositeObjects(page int, path ObjectPath, selection *Com
|
||||
return nil, err
|
||||
}
|
||||
if e.pages[page].ID != selection.page || path.ID != selection.path.ID || !slices.Equal(path.Children, selection.path.Children) {
|
||||
objects, err := e.compositeSelectionObjects(selection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.CopyObjectsToComposite(page, path, objects, dx, dy)
|
||||
var result []int
|
||||
err := e.pasteCompositeSelection(selection, func(objects []GraphicObject) error {
|
||||
var err error
|
||||
result, err = e.CopyObjectsToComposite(page, path, objects, dx, dy)
|
||||
return err
|
||||
})
|
||||
return result, err
|
||||
}
|
||||
var result []int
|
||||
err := e.editCompositeScope(page, path, func(renderer *Renderer, root *editorCompositeNode, _ []*editorCompositeNode) error {
|
||||
@@ -321,7 +405,7 @@ func (n *editorCompositeNode) loadedScope(path []int) *editorCompositeNode {
|
||||
func compositeContainers(node *editorXML) []*editorXML {
|
||||
var result []*editorXML
|
||||
for _, child := range node.children {
|
||||
if child.name.Local == "Content" || child.name.Local == "PageBlock" {
|
||||
if (child.name.Local == "Content" || child.name.Local == "PageBlock") && (child.name.Space == "" || child.name.Space == ofdNamespace || child.name.Space == "http://www.ofdspec.org") {
|
||||
result = append(result, child)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user