feat(性能优化): 优化页面渲染与文字传输性能
build.yaml / build (push) Successful in 42s

This commit is contained in:
xiaoqidun committed 2026-09-13 20:16:39 +08:00
1 parent 2b2e83bdbe
commit 740c088bfd
9 files changed
+34 -6

No files matched your search

+1
View File
@@ -1665,6 +1665,7 @@ async function processPageRenderQueue() {
const page = await callWASM("ofdgoRenderPage", task.index); const page = await callWASM("ofdgoRenderPage", task.index);
await loadSVGFonts(page.fonts, task.openSeq); await loadSVGFonts(page.fonts, task.openSeq);
if (task.openSeq === state.openSeq) { if (task.openSeq === state.openSeq) {
page.text = JSON.parse(page.text);
state.pageCache.set(task.index, page); state.pageCache.set(task.index, page);
} }
task.resolve(page); task.resolve(page);
+1 -1
View File
@@ -210,7 +210,7 @@ func renderPage(args []js.Value) (any, error) {
"svg": page.SVG, "svg": page.SVG,
"links": links, "links": links,
"fonts": fonts, "fonts": fonts,
"text": js.Global().Get("JSON").Call("parse", string(textData)), "text": string(textData),
}), nil }), nil
} }
+7 -1
View File
@@ -418,7 +418,13 @@ func (s *Session) RenderPageSVG(index int) (PageSVG, error) {
return PageSVG{}, err return PageSVG{}, err
} }
var buf bytes.Buffer var buf bytes.Buffer
fonts, err := s.Renderer.RenderToSVGWithFonts(page, &buf) renderer := *s.Renderer
if s.textCache[index] == nil {
renderer.OnPageText = func(_ *ofdgo.PageContent, text *ofdgo.PageText) {
s.textCache[index] = text
}
}
fonts, err := renderer.RenderToSVGWithFonts(page, &buf)
if err != nil { if err != nil {
return PageSVG{}, err return PageSVG{}, err
} }
+11
View File
@@ -23,10 +23,12 @@ import (
) )
// Renderer 渲染器实现 // Renderer 渲染器实现
// OnPageText可选,接收页面绘制时同步提取的文字,不包含图案和签名外观
type Renderer struct { type Renderer struct {
Reader *Reader Reader *Reader
DPI float64 DPI float64
RenderAnnotations bool RenderAnnotations bool
OnPageText func(*PageContent, *PageText)
fontFamily *canvas.FontFamily fontFamily *canvas.FontFamily
defaultFontLoaded bool defaultFontLoaded bool
DrawParams map[string]*DrawParam DrawParams map[string]*DrawParam
@@ -47,6 +49,7 @@ type Renderer struct {
fontFS []fs.FS fontFS []fs.FS
decodeImages bool decodeImages bool
pageText *PageText pageText *PageText
textOnly bool
} }
// RendererOption 渲染器配置选项 // RendererOption 渲染器配置选项
@@ -137,6 +140,11 @@ func (r *Renderer) renderPageToContext(ctx *canvas.Context, page *PageContent, d
if err != nil { if err != nil {
return err return err
} }
if r.OnPageText != nil {
renderer := *r
renderer.pageText = &PageText{}
r = &renderer
}
pageH := box.H pageH := box.H
if drawBackground { if drawBackground {
ctx.SetFillColor(canvas.White) ctx.SetFillColor(canvas.White)
@@ -164,6 +172,9 @@ func (r *Renderer) renderPageToContext(ctx *canvas.Context, page *PageContent, d
r.renderStamp(ctx, stamp, pageH) r.renderStamp(ctx, stamp, pageH)
} }
} }
if r.OnPageText != nil {
r.OnPageText(page, r.pageText)
}
return nil return nil
} }
+1 -1
View File
@@ -30,7 +30,7 @@ import (
// renderImage 渲染图片 // renderImage 渲染图片
// 入参: ctx 画布上下文, obj 图片对象, pageH 页面高度, parentCTM 父级CTM, boundaryInCTM 边界是否参与父级CTM, parentClip 父级裁剪路径 // 入参: ctx 画布上下文, obj 图片对象, pageH 页面高度, parentCTM 父级CTM, boundaryInCTM 边界是否参与父级CTM, parentClip 父级裁剪路径
func (r *Renderer) renderImage(ctx *canvas.Context, obj ImageObject, pageH float64, parentCTM *Matrix, boundaryInCTM bool, parentClip *canvas.Path) { func (r *Renderer) renderImage(ctx *canvas.Context, obj ImageObject, pageH float64, parentCTM *Matrix, boundaryInCTM bool, parentClip *canvas.Path) {
if r.pageText != nil { if r.textOnly {
return return
} }
if obj.Visible != nil && !*obj.Visible { if obj.Visible != nil && !*obj.Visible {
+7 -1
View File
@@ -173,7 +173,7 @@ func (s *pathStyle) scale(ctm Matrix) {
// renderPath 渲染路径 // renderPath 渲染路径
// 入参: ctx 画布上下文, obj 路径对象, pageH 页面高度, defaults 默认绘制参数, parentCTM 父级CTM, boundaryInCTM 边界是否参与CTM变换, parentClip 父级裁剪路径 // 入参: ctx 画布上下文, obj 路径对象, pageH 页面高度, defaults 默认绘制参数, parentCTM 父级CTM, boundaryInCTM 边界是否参与CTM变换, parentClip 父级裁剪路径
func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64, defaults *DrawParam, parentCTM *Matrix, boundaryInCTM bool, parentClip *canvas.Path) { func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64, defaults *DrawParam, parentCTM *Matrix, boundaryInCTM bool, parentClip *canvas.Path) {
if r.pageText != nil { if r.textOnly {
return return
} }
if obj.Visible != nil && !*obj.Visible { if obj.Visible != nil && !*obj.Visible {
@@ -304,6 +304,11 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
// renderPattern 渲染图案填充 // renderPattern 渲染图案填充
// 入参: ctx 画布上下文, pattern 底纹画刷, pageH 页面高度, clip 绘制区域, objectCTM 对象变换矩阵 // 入参: ctx 画布上下文, pattern 底纹画刷, pageH 页面高度, clip 绘制区域, objectCTM 对象变换矩阵
func (r *Renderer) renderPattern(ctx *canvas.Context, pattern *patternPaint, pageH float64, clip *canvas.Path, objectCTM Matrix) { func (r *Renderer) renderPattern(ctx *canvas.Context, pattern *patternPaint, pageH float64, clip *canvas.Path, objectCTM Matrix) {
if r.pageText != nil {
renderer := *r
renderer.pageText = nil
r = &renderer
}
if clip == nil || clip.Empty() || len(pattern.CellContent.Objects) == 0 { if clip == nil || clip.Empty() || len(pattern.CellContent.Objects) == 0 {
return return
} }
@@ -504,6 +509,7 @@ func (r *Renderer) buildClipPath(clips *Clips, pageH float64, bx, by float64, ob
textObj.StrokeColor = &StrokeColor{Value: "0 0 0"} textObj.StrokeColor = &StrokeColor{Value: "0 0 0"}
textRenderer := *r textRenderer := *r
textRenderer.pageText = nil textRenderer.pageText = nil
textRenderer.textOnly = false
textRenderer.renderText(ctx, textObj, 0, r.drawParamDefaults(area.DrawParam, nil), nil, false, nil) textRenderer.renderText(ctx, textObj, 0, r.drawParamDefaults(area.DrawParam, nil), nil, false, nil)
} }
} }
+1 -1
View File
@@ -28,7 +28,7 @@ import (
// renderStamp 渲染印章 // renderStamp 渲染印章
// 入参: ctx 画布上下文, s 印章对象, pageH 页面高度 // 入参: ctx 画布上下文, s 印章对象, pageH 页面高度
func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) { func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) {
if r.pageText != nil { if r.textOnly {
return return
} }
if s.Type == "ofd" && len(s.Data) > 0 { if s.Type == "ofd" && len(s.Data) > 0 {
+3 -1
View File
@@ -301,7 +301,9 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
} }
textRun.addSpan(textPos+spans[i][0], textPos+spans[i][1], bounds, m.Scale(scaleX, 1), clipPath, pageH) textRun.addSpan(textPos+spans[i][0], textPos+spans[i][1], bounds, m.Scale(scaleX, 1), clipPath, pageH)
} }
continue if r.textOnly {
continue
}
} }
if shouldStroke { if shouldStroke {
scaleX := hScale scaleX := hScale
+2
View File
@@ -65,7 +65,9 @@ func (r *Renderer) PageText(page *PageContent) (*PageText, error) {
return nil, err return nil, err
} }
renderer := *r renderer := *r
renderer.OnPageText = nil
renderer.pageText = &PageText{} renderer.pageText = &PageText{}
renderer.textOnly = true
if err := renderer.renderPageToContext(canvas.NewContext(canvas.New(box.W, box.H)), page, false); err != nil { if err := renderer.renderPageToContext(canvas.NewContext(canvas.New(box.W, box.H)), page, false); err != nil {
return nil, err return nil, err
} }