mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
feat(编辑能力): 统一字体隔离与保存处理
This commit is contained in:
1 parent
01b1740a83
commit
63e56c5ab8
2 files changed
+11
-144
No files matched your search
@@ -345,17 +345,9 @@ func (e *Editor) changeFontSnapshot(ctx context.Context, scan *editorFontDocumen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
changes[declaration.file.name] = data
|
changes[declaration.file.name] = data
|
||||||
working := *scan.reader
|
if err := scan.apply(ctx, changes); err != nil {
|
||||||
working.files = maps.Clone(scan.reader.files)
|
|
||||||
next := *scan
|
|
||||||
next.reader = &working
|
|
||||||
if err := next.apply(ctx, changes); err != nil {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if err := working.initRoot(); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
*scan.reader = working
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-135
@@ -33,22 +33,14 @@ type editorFontDocument struct {
|
|||||||
unsafe bool
|
unsafe bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// editorFontXML 保存内容XML及其直接文件引用
|
// editorFontXML 保存字体声明及文字引用所在的XML
|
||||||
type editorFontXML struct {
|
type editorFontXML struct {
|
||||||
name string
|
name string
|
||||||
data []byte
|
data []byte
|
||||||
root *editorXML
|
root *editorXML
|
||||||
links []editorFontLink
|
|
||||||
texts []*editorXML
|
texts []*editorXML
|
||||||
}
|
}
|
||||||
|
|
||||||
// editorFontLink 记录需要随共享资源隔离而更新的路径
|
|
||||||
type editorFontLink struct {
|
|
||||||
node *editorXML
|
|
||||||
attribute string
|
|
||||||
target string
|
|
||||||
}
|
|
||||||
|
|
||||||
// editorFontDeclaration 关联字体声明、所属资源文件及嵌入数据路径
|
// editorFontDeclaration 关联字体声明、所属资源文件及嵌入数据路径
|
||||||
type editorFontDeclaration struct {
|
type editorFontDeclaration struct {
|
||||||
font Font
|
font Font
|
||||||
@@ -132,25 +124,23 @@ func scanEditorFonts(ctx context.Context, reader *Reader, index int) (*editorFon
|
|||||||
scan.unsafe = true
|
scan.unsafe = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attribute, value := "", ""
|
value := ""
|
||||||
switch node.name.Local {
|
switch node.name.Local {
|
||||||
case "PublicRes", "DocumentRes", "PageRes", "Annotations":
|
case "PublicRes", "DocumentRes", "PageRes", "Annotations":
|
||||||
value = strings.TrimSpace(editorImportText(data, node))
|
value = strings.TrimSpace(editorImportText(data, node))
|
||||||
case "Page", "TemplatePage", "CompositeGraphicUnit":
|
case "Page", "TemplatePage", "CompositeGraphicUnit":
|
||||||
attribute, value = "BaseLoc", node.attr("BaseLoc")
|
value = node.attr("BaseLoc")
|
||||||
case "PageAnnot":
|
case "PageAnnot":
|
||||||
attribute, value = "FileLoc", node.attr("FileLoc")
|
value = node.attr("FileLoc")
|
||||||
case "DrawParam":
|
case "DrawParam":
|
||||||
attribute, value = "Link", node.attr("Link")
|
value = node.attr("Link")
|
||||||
case "FileLoc":
|
case "FileLoc":
|
||||||
if node.parent != nil && node.parent.matchesOFD("Page") && root.matchesOFD("Annotations") {
|
if node.parent != nil && node.parent.matchesOFD("Page") && root.matchesOFD("Annotations") {
|
||||||
value = strings.TrimSpace(editorImportText(data, node))
|
value = strings.TrimSpace(editorImportText(data, node))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value != "" {
|
if value != "" {
|
||||||
target := resolveResourcePath(name, base, value)
|
queue = append(queue, resolveResourcePath(name, base, value))
|
||||||
file.links = append(file.links, editorFontLink{node: node, attribute: attribute, target: target})
|
|
||||||
queue = append(queue, target)
|
|
||||||
}
|
}
|
||||||
for _, child := range node.children {
|
for _, child := range node.children {
|
||||||
if err := visit(child); err != nil {
|
if err := visit(child); err != nil {
|
||||||
@@ -166,11 +156,10 @@ func scanEditorFonts(ctx context.Context, reader *Reader, index int) (*editorFon
|
|||||||
return scan, nil
|
return scan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply 隔离其他文档共享的内容XML,再提交字体修改及上层路径引用
|
// apply 隔离其他文档及版本的共享文件,提交字体修改和路径引用
|
||||||
// 入参: ctx 取消上下文, changes 按原文件路径保存的修改
|
// 入参: ctx 取消上下文, changes 按原文件路径保存的修改
|
||||||
// 返回: error 引用扫描或XML修改错误
|
// 返回: error 引用扫描或XML修改错误
|
||||||
func (s *editorFontDocument) apply(ctx context.Context, changes map[string][]byte) error {
|
func (s *editorFontDocument) apply(ctx context.Context, changes map[string][]byte) error {
|
||||||
if s.reader.OFD.DocBody[s.index].versioned {
|
|
||||||
view := *s.reader
|
view := *s.reader
|
||||||
if s.index != view.documentIndex {
|
if s.index != view.documentIndex {
|
||||||
view.selectedVersion = nil
|
view.selectedVersion = nil
|
||||||
@@ -190,126 +179,12 @@ func (s *editorFontDocument) apply(ctx context.Context, changes map[string][]byt
|
|||||||
if err := next.initRoot(); err != nil {
|
if err := next.initRoot(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
*s.reader = next
|
*s.reader = next
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
shared := make(map[string]bool)
|
|
||||||
if s.reader.DocumentCount() > 1 {
|
|
||||||
for index := range s.reader.DocumentCount() {
|
|
||||||
if index == s.index {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
files, err := s.reader.documentFiles(ctx, index)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
maps.Copy(shared, files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
paths := make(map[string]string)
|
|
||||||
for name := range changes {
|
|
||||||
if shared[name] {
|
|
||||||
paths[name] = packageAvailableName(s.reader, changes, name+".font.xml")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for changed := true; changed; {
|
|
||||||
changed = false
|
|
||||||
for name, file := range s.files {
|
|
||||||
if paths[name] != "" || !shared[name] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, link := range file.links {
|
|
||||||
if paths[link.target] != "" {
|
|
||||||
paths[name] = packageAvailableName(s.reader, changes, name+".font.xml")
|
|
||||||
changed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, name := range slices.Sorted(maps.Keys(s.files)) {
|
|
||||||
file := s.files[name]
|
|
||||||
if !slices.ContainsFunc(file.links, func(link editorFontLink) bool { return paths[link.target] != "" }) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
data, modified := changes[name]
|
|
||||||
if !modified {
|
|
||||||
data = file.data
|
|
||||||
}
|
|
||||||
root, err := parseEditorXML(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var patches []editorXMLPatch
|
|
||||||
var patch func(*editorXML) error
|
|
||||||
patch = func(node *editorXML) error {
|
|
||||||
for _, link := range file.links {
|
|
||||||
target := paths[link.target]
|
|
||||||
if target == "" || node.name != link.node.name {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if link.attribute != "" && node.attr(link.attribute) == link.node.attr(link.attribute) {
|
|
||||||
fragment, err := editorXMLAttribute(data, node, link.attribute, "/"+target)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
header, err := parseEditorXML(fragment)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if node.open == node.end {
|
|
||||||
patches = append(patches, editorXMLPatch{node.start, node.end, fragment})
|
|
||||||
} else {
|
|
||||||
patches = append(patches, editorXMLPatch{node.start, node.open, fragment[:header.open]})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if link.attribute == "" && editorImportText(data, node) == editorImportText(file.data, link.node) {
|
|
||||||
patches = append(patches, editorXMLContent(data, node, editorFontXMLText("/"+target)))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, child := range node.children {
|
|
||||||
if err := patch(child); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := patch(root); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(patches) != 0 {
|
|
||||||
data, modified = editorPatchXML(data, patches), true
|
|
||||||
}
|
|
||||||
if modified {
|
|
||||||
changes[name] = data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rootName, err := s.reader.documentEntry(s.index)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if target := paths[rootName]; target != "" {
|
|
||||||
data, err := s.reader.readFile("OFD.xml")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
root, err := parseEditorXML(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
node := root.childAt("DocBody", s.index).child("DocRoot")
|
|
||||||
changes["OFD.xml"] = editorPatchXML(data, []editorXMLPatch{editorXMLContent(data, node, editorFontXMLText("/"+target))})
|
|
||||||
}
|
|
||||||
for name, data := range changes {
|
|
||||||
if target := paths[name]; target != "" {
|
|
||||||
name = target
|
|
||||||
}
|
|
||||||
s.reader.files[name] = data
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// editorFontXMLText 编码资源路径文本,不改变包内名称
|
// editorFontXMLText 编码资源路径文本,不改变包内名称
|
||||||
// 入参: value 原始文本
|
// 入参: value 原始文本
|
||||||
|
|||||||
Reference in new issue
Block a user