mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
a7e86a322f
commit
92585edd1e
6 files changed
+46
-8
No files matched your search
@@ -839,6 +839,7 @@ button.outline-link:hover {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: #1f2428;
|
color: #1f2428;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -670,6 +670,16 @@ async function loadWASM() {
|
|||||||
}
|
}
|
||||||
if (data.type === "progress") {
|
if (data.type === "progress") {
|
||||||
setProgress(data.text, data.percent);
|
setProgress(data.text, data.percent);
|
||||||
|
} else if (data.type === "export") {
|
||||||
|
if (wasmRequests.get(data.id)?.openSeq === state.openSeq && state.exporting) {
|
||||||
|
if (data.stage === "save") {
|
||||||
|
setProgress("正在保存", null);
|
||||||
|
} else if (data.completed === data.total) {
|
||||||
|
setProgress("正在封装", null);
|
||||||
|
} else {
|
||||||
|
setProgress(`正在导出 ${data.completed} / ${data.total} 页`, data.completed / data.total * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (data.type === "ready") {
|
} else if (data.type === "ready") {
|
||||||
state.ready = true;
|
state.ready = true;
|
||||||
resolve();
|
resolve();
|
||||||
@@ -1589,7 +1599,6 @@ async function exportFile(whole, indices = null) {
|
|||||||
if (openSeq !== state.openSeq) {
|
if (openSeq !== state.openSeq) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setProgress(`正在保存 ${result.label}`, 100);
|
|
||||||
if (result.blob) {
|
if (result.blob) {
|
||||||
downloadBytes(result.blob, result.mime, fileName);
|
downloadBytes(result.blob, result.mime, fileName);
|
||||||
}
|
}
|
||||||
@@ -3302,7 +3311,7 @@ async function callWASM(name, ...args) {
|
|||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const id = ++wasmRequestID;
|
const id = ++wasmRequestID;
|
||||||
wasmRequests.set(id, { resolve, reject });
|
wasmRequests.set(id, { resolve, reject, openSeq: state.openSeq });
|
||||||
try {
|
try {
|
||||||
wasmWorker.postMessage({ id, name, args });
|
wasmWorker.postMessage({ id, name, args });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -24,11 +24,17 @@ async function handleMessage({ id, name, args }) {
|
|||||||
setTimeout(done, 0);
|
setTimeout(done, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (name === "ofdgoExportDocument") {
|
||||||
|
args.push((completed, total) => {
|
||||||
|
self.postMessage({ id, type: "export", stage: "pages", completed, total });
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const payload = await globalThis[name](...args);
|
const payload = await globalThis[name](...args);
|
||||||
const result = typeof payload === "string" ? JSON.parse(payload) : payload;
|
const result = typeof payload === "string" ? JSON.parse(payload) : payload;
|
||||||
if (exporting && result.ok) {
|
if (exporting && result.ok) {
|
||||||
result.data.size = size;
|
result.data.size = size;
|
||||||
|
self.postMessage({ id, type: "export", stage: "save" });
|
||||||
if (output) {
|
if (output) {
|
||||||
await output.close();
|
await output.close();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -335,6 +335,11 @@ func exportDocument(args []js.Value) (any, error) {
|
|||||||
if currentSession == nil {
|
if currentSession == nil {
|
||||||
return nil, fmt.Errorf("ofd document is not opened")
|
return nil, fmt.Errorf("ofd document is not opened")
|
||||||
}
|
}
|
||||||
|
renderer := currentSession.Renderer
|
||||||
|
renderer.OnExportProgress = func(completed, total int) {
|
||||||
|
args[4].Invoke(completed, total)
|
||||||
|
}
|
||||||
|
defer func() { renderer.OnExportProgress = nil }()
|
||||||
var indices []int
|
var indices []int
|
||||||
if !args[2].IsNull() {
|
if !args[2].IsNull() {
|
||||||
indices = make([]int, args[2].Length())
|
indices = make([]int, args[2].Length())
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ import (
|
|||||||
// Renderer 渲染器实现
|
// Renderer 渲染器实现
|
||||||
// 通过NewRenderer创建,实例及共享的Reader需串行使用
|
// 通过NewRenderer创建,实例及共享的Reader需串行使用
|
||||||
// OnPageText可选,接收页面绘制时同步提取的文字,不包含图案和签名外观
|
// OnPageText可选,接收页面绘制时同步提取的文字,不包含图案和签名外观
|
||||||
|
// OnExportProgress可选,同步回报文档导出的已处理页数及总页数,不代表封装或写入成功
|
||||||
type Renderer struct {
|
type Renderer struct {
|
||||||
Reader *Reader
|
Reader *Reader
|
||||||
DPI float64
|
DPI float64
|
||||||
RenderAnnotations bool
|
RenderAnnotations bool
|
||||||
OnPageText func(*PageContent, *PageText)
|
OnPageText func(*PageContent, *PageText)
|
||||||
|
OnExportProgress func(completed, total int)
|
||||||
DrawParams map[string]*DrawParam
|
DrawParams map[string]*DrawParam
|
||||||
CompositeGraphicUnits map[string]*CompositeGraphicUnit
|
CompositeGraphicUnits map[string]*CompositeGraphicUnit
|
||||||
fontFamily *canvas.FontFamily
|
fontFamily *canvas.FontFamily
|
||||||
|
|||||||
@@ -90,7 +90,10 @@ func (r *Renderer) RenderToZIP(writer io.Writer, format string, indices ...int)
|
|||||||
method = zip.Store
|
method = zip.Store
|
||||||
}
|
}
|
||||||
width := len(strconv.Itoa(count))
|
width := len(strconv.Itoa(count))
|
||||||
for _, index := range indices {
|
if r.OnExportProgress != nil {
|
||||||
|
r.OnExportProgress(0, len(indices))
|
||||||
|
}
|
||||||
|
for i, index := range indices {
|
||||||
page, err := r.Reader.PageContentByIndex(index)
|
page, err := r.Reader.PageContentByIndex(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read page %d: %w", index+1, err)
|
return fmt.Errorf("failed to read page %d: %w", index+1, err)
|
||||||
@@ -105,6 +108,9 @@ func (r *Renderer) RenderToZIP(writer io.Writer, format string, indices ...int)
|
|||||||
if err := render(page, entry); err != nil {
|
if err := render(page, entry); err != nil {
|
||||||
return fmt.Errorf("failed to export page %d: %w", index+1, err)
|
return fmt.Errorf("failed to export page %d: %w", index+1, err)
|
||||||
}
|
}
|
||||||
|
if r.OnExportProgress != nil {
|
||||||
|
r.OnExportProgress(i+1, len(indices))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return archive.Close()
|
return archive.Close()
|
||||||
}
|
}
|
||||||
@@ -248,7 +254,7 @@ func (r *Renderer) RenderToPDF(page *PageContent, writer io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pages := []pdfPage{{Content: page, Box: box}}
|
pages := []pdfPage{{Content: page, Box: box}}
|
||||||
return r.renderPDFPages(pages, writer)
|
return r.renderPDFPages(pages, writer, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderToEPS 渲染为EPS
|
// RenderToEPS 渲染为EPS
|
||||||
@@ -282,6 +288,9 @@ func (r *Renderer) RenderToMultiPagePDF(writer io.Writer, indices ...int) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if r.OnExportProgress != nil {
|
||||||
|
r.OnExportProgress(0, len(indices))
|
||||||
|
}
|
||||||
pages := make([]pdfPage, len(indices))
|
pages := make([]pdfPage, len(indices))
|
||||||
for i, index := range indices {
|
for i, index := range indices {
|
||||||
page, err := r.Reader.PageContent(doc.Pages.Page[index])
|
page, err := r.Reader.PageContent(doc.Pages.Page[index])
|
||||||
@@ -294,7 +303,7 @@ func (r *Renderer) RenderToMultiPagePDF(writer io.Writer, indices ...int) error
|
|||||||
}
|
}
|
||||||
pages[i] = pdfPage{Content: page, Box: box}
|
pages[i] = pdfPage{Content: page, Box: box}
|
||||||
}
|
}
|
||||||
return r.renderPDFPages(pages, writer)
|
return r.renderPDFPages(pages, writer, r.OnExportProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderPagesToPDF 按指定顺序导出已解析的页面,复用调用方的页面缓存
|
// RenderPagesToPDF 按指定顺序导出已解析的页面,复用调用方的页面缓存
|
||||||
@@ -304,6 +313,9 @@ func (r *Renderer) RenderPagesToPDF(contents []*PageContent, writer io.Writer) e
|
|||||||
if len(contents) == 0 {
|
if len(contents) == 0 {
|
||||||
return fmt.Errorf("no pages found")
|
return fmt.Errorf("no pages found")
|
||||||
}
|
}
|
||||||
|
if r.OnExportProgress != nil {
|
||||||
|
r.OnExportProgress(0, len(contents))
|
||||||
|
}
|
||||||
pages := make([]pdfPage, len(contents))
|
pages := make([]pdfPage, len(contents))
|
||||||
for i, page := range contents {
|
for i, page := range contents {
|
||||||
box, err := r.GetPageBox(page)
|
box, err := r.GetPageBox(page)
|
||||||
@@ -312,13 +324,13 @@ func (r *Renderer) RenderPagesToPDF(contents []*PageContent, writer io.Writer) e
|
|||||||
}
|
}
|
||||||
pages[i] = pdfPage{Content: page, Box: box}
|
pages[i] = pdfPage{Content: page, Box: box}
|
||||||
}
|
}
|
||||||
return r.renderPDFPages(pages, writer)
|
return r.renderPDFPages(pages, writer, r.OnExportProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderPDFPages 渲染页面并复用调用方的字节缓冲
|
// renderPDFPages 渲染页面并复用调用方的字节缓冲
|
||||||
// 入参: pages 页面列表, writer 输出流
|
// 入参: pages 页面列表, writer 输出流, progress 页面处理进度
|
||||||
// 返回: error 错误信息
|
// 返回: error 错误信息
|
||||||
func (r *Renderer) renderPDFPages(pages []pdfPage, writer io.Writer) error {
|
func (r *Renderer) renderPDFPages(pages []pdfPage, writer io.Writer, progress func(int, int)) error {
|
||||||
navigation := newPDFNavigation(r, r.Reader.doc, pages)
|
navigation := newPDFNavigation(r, r.Reader.doc, pages)
|
||||||
buf, direct := writer.(*bytes.Buffer)
|
buf, direct := writer.(*bytes.Buffer)
|
||||||
if !direct {
|
if !direct {
|
||||||
@@ -337,6 +349,9 @@ func (r *Renderer) renderPDFPages(pages []pdfPage, writer io.Writer) error {
|
|||||||
buf.Truncate(start)
|
buf.Truncate(start)
|
||||||
return fmt.Errorf("failed to render page %d: %w", i+1, err)
|
return fmt.Errorf("failed to render page %d: %w", i+1, err)
|
||||||
}
|
}
|
||||||
|
if progress != nil {
|
||||||
|
progress(i+1, len(pages))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := p.Close(); err != nil {
|
if err := p.Close(); err != nil {
|
||||||
buf.Truncate(start)
|
buf.Truncate(start)
|
||||||
|
|||||||
Reference in new issue
Block a user