From ac1490c4d117a12bf25465b11d2249f8c2f0ff2a Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Tue, 29 Sep 2026 20:31:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=8E=8B=E7=BC=A9=E8=83=BD=E5=8A=9B):=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8E=8B=E7=BC=A9=E6=80=A7=E8=83=BD=E4=B8=8E?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/webui/ofdgo.js | 9 +++++---- ofdgo_compression.go | 21 ++++++++++++++++----- ofdgo_editor.go | 5 +++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/assets/webui/ofdgo.js b/assets/webui/ofdgo.js index 035db85..3d2bab9 100644 --- a/assets/webui/ofdgo.js +++ b/assets/webui/ofdgo.js @@ -3366,8 +3366,8 @@ async function loadWASM() { setProgress("正在保存", null); } else if (!el.cancelExportButton.disabled) { if (data.stage === "prepare") { - const label = { snapshot: "正在准备", ids: "正在检查", commit: "正在整理", fonts: "正在处理字体", pages: "正在处理页面", references: "正在检查引用", resources: "正在整理资源", write: "正在写入", sign: "正在签署", encrypt: "正在加密" }[data.phase]; - setProgress(label, data.total ? data.completed / data.total * 100 : null); + const label = { snapshot: "正在准备", ids: "正在检查", commit: "正在整理", fonts: "正在处理字体", pages: "正在处理页面", references: "正在检查引用", resources: "正在整理资源", compress: "正在压缩", write: "正在写入", sign: "正在签署", encrypt: "正在加密" }[data.phase]; + setProgress(data.phase === "compress" && data.completed ? `${label} · 已处理 ${data.completed} 项` : label, data.total ? data.completed / data.total * 100 : null); } else if (data.completed === data.total) { setProgress("正在收尾", null); } else { @@ -4880,8 +4880,9 @@ function batchProgress(item, position, count, progress) { const now = performance.now(); if (now - batch.progressTime < 80 && progress.completed !== progress.total) return; batch.progressTime = now; - const stage = progress.phase?.startsWith("write.") ? "写入" : { open: "读取", pages: "解析", convert: "转换", prepare: "准备", fonts: "字体", resources: "资源", references: "检查", write: "写入", export: "导出", pack: "打包", commit: "保存" }[progress.phase] || "处理"; - const detail = progress.total > 0 ? `${progress.completed}/${progress.total}` : ""; + const compressing = progress.phase === "compress" || progress.phase === "write.compress"; + const stage = compressing ? "压缩" : progress.phase?.startsWith("write.") ? "写入" : { open: "读取", pages: "解析", convert: "转换", prepare: "准备", fonts: "字体", resources: "资源", references: "检查", write: "写入", export: "导出", pack: "打包", commit: "保存" }[progress.phase] || "处理"; + const detail = progress.total > 0 ? `${progress.completed}/${progress.total}` : compressing && progress.completed ? `已处理 ${progress.completed} 项` : ""; if (item) batchStatus(item, "running", stage); batchElements.Status.textContent = progress.phase === "pack" ? `打包 ${detail}` : `文件 ${position + 1}/${count} · ${stage}${detail ? ` ${detail}` : ""}`; batchElements.Progress.max = count; diff --git a/ofdgo_compression.go b/ofdgo_compression.go index 16f9192..61eea48 100644 --- a/ofdgo_compression.go +++ b/ofdgo_compression.go @@ -47,12 +47,14 @@ type CompressionOptions = pdfgo.CompressionOptions // WriteOptions 配置OFD输出副本,不修改编辑资源和撤销记录 type WriteOptions struct{ Compression CompressionOptions } -// outputOptimization 保存单次写出的配置及图片路径,不缓存资源数据 +// outputOptimization 保存单次写出的配置、图片路径及压缩进度,复用压缩器 type outputOptimization struct { ctx context.Context options CompressionOptions images map[string]bool protected bool + completed int + deflater *flate.Writer } // WriteToWithOptions 按压缩策略写出OFD,签名文档不额外改写资源内容 @@ -241,7 +243,7 @@ func (e *Editor) writeOutputEntry(archive *zip.Writer, header zip.FileHeader, da _, err = entry.Write(data) return err } - if err := editorProgress(e.OnWriteProgress).report("compress", 0, 0); err != nil { + if err := editorProgress(e.OnWriteProgress).report("compress", e.output.completed, 0); err != nil { return err } if lossy, ok := e.output.images[strings.ToLower(cleanPackagePath(header.Name))]; ok { @@ -259,7 +261,13 @@ func (e *Editor) writeOutputEntry(archive *zip.Writer, header zip.FileHeader, da } } var compressed bytes.Buffer - deflater, _ := flate.NewWriter(&compressed, flate.BestCompression) + deflater := e.output.deflater + if deflater == nil { + deflater, _ = flate.NewWriter(&compressed, flate.BestCompression) + e.output.deflater = deflater + } else { + deflater.Reset(&compressed) + } for offset := 0; offset < len(data); { if err := e.output.ctx.Err(); err != nil { deflater.Close() @@ -288,8 +296,11 @@ func (e *Editor) writeOutputEntry(archive *zip.Writer, header zip.FileHeader, da if err != nil { return err } - _, err = entry.Write(payload) - return err + if _, err = entry.Write(payload); err != nil { + return err + } + e.output.completed++ + return editorProgress(e.OnWriteProgress).report("compress", e.output.completed, 0) } // WithCompression 设置导出策略,不修改文档资源和渲染缓存 diff --git a/ofdgo_editor.go b/ofdgo_editor.go index d347690..960393e 100644 --- a/ofdgo_editor.go +++ b/ofdgo_editor.go @@ -37,8 +37,9 @@ import ( // Editor 编辑OFD文档,长度单位为毫米,页面索引从0开始,实例需串行使用 // Info可修改文档元数据,通过方法管理页面、对象和资源,WriteTo另存结果,不覆盖输入 -// OnWriteProgress可选,按fonts、pages、references、resources、write阶段同步回报准备进度,返回错误则停止保存 -// completed和total为当前阶段已处理及总工作项,write阶段不计数;阶段可重复,准备完成不代表保存成功 +// OnWriteProgress可选,按fonts、pages、references、resources、compress、write阶段同步回报进度,返回错误则停止保存 +// completed和total为当前阶段已处理及总工作项,compress累计完成条目数且total为0,write阶段不计数 +// 阶段可重复,准备完成不代表保存成功 // 回调不可重入修改编辑器,可返回context.Canceled等调用方停止原因 type Editor struct { OnWriteProgress func(stage string, completed, total int) error