From ad00e95ae6ce1fd89abdd6dbc879be76dce5c323 Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Sun, 13 Sep 2026 23:49:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96):=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96PDF=E5=AD=97=E5=BD=A2=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E9=99=8D=E4=BD=8E=E5=A4=9A=E9=A1=B5=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E8=80=97=E6=97=B6=E4=B8=8E=E5=86=85=E5=AD=98=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ofdgo_renderer_output.go | 3 ++- ofdgo_renderer_pdf.go | 21 +++++++++++++++++++++ ofdgo_renderer_text.go | 5 +++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ofdgo_renderer_output.go b/ofdgo_renderer_output.go index e4167fb..b7eca0c 100644 --- a/ofdgo_renderer_output.go +++ b/ofdgo_renderer_output.go @@ -244,13 +244,14 @@ func (r *Renderer) renderPDFPages(pages []pdfPage, writer io.Writer) error { } start := buf.Len() p := pdf.New(buf, pages[0].Box.W, pages[0].Box.H, nil) + renderer := &pdfRenderer{PDF: p, glyphPaths: make(map[*canvas.Path]*canvas.Path)} p.SetInfo("", "", "", "", "xiaoqidun/ofdgo") for i, page := range pages { if i > 0 { p.NewPage(page.Box.W, page.Box.H) } navigation.apply(p, i) - if err := r.renderPageToContext(canvas.NewContext(p), page.Content, true); err != nil { + if err := r.renderPageToContext(canvas.NewContext(renderer), page.Content, true); err != nil { buf.Truncate(start) return fmt.Errorf("failed to render page %d: %w", i+1, err) } diff --git a/ofdgo_renderer_pdf.go b/ofdgo_renderer_pdf.go index b55a4c4..d7b749f 100644 --- a/ofdgo_renderer_pdf.go +++ b/ofdgo_renderer_pdf.go @@ -21,6 +21,27 @@ import ( "github.com/tdewolff/canvas/renderers/pdf" ) +// pdfRenderer PDF渲染器 +type pdfRenderer struct { + *pdf.PDF + glyphPaths map[*canvas.Path]*canvas.Path +} + +// glyphPath 复用相似变换下的PDF字形圆弧转换 +// 入参: path 缓存字形路径, matrix 字形变换 +// 返回: *canvas.Path PDF字形路径 +func (r *pdfRenderer) glyphPath(path *canvas.Path, matrix canvas.Matrix) *canvas.Path { + if !matrix.IsSimilarity() { + return path + } + if cached, ok := r.glyphPaths[path]; ok { + return cached + } + converted := path.ReplaceArcs() + r.glyphPaths[path] = converted + return converted +} + // pdfPage PDF页面数据 type pdfPage struct { Content *PageContent diff --git a/ofdgo_renderer_text.go b/ofdgo_renderer_text.go index ce29d71..ae8b01e 100644 --- a/ofdgo_renderer_text.go +++ b/ofdgo_renderer_text.go @@ -396,6 +396,11 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 scaleX = advanceLimit / glyphWidth } textWidth = glyphWidth * scaleX + if face.FauxBold != 0 { + if renderer, ok := ctx.Renderer.(*pdfRenderer); ok { + glyphPath = renderer.glyphPath(glyphPath, ctx.View().Scale(scaleX, 1)) + } + } if scaleX != 1 { ctx.Push() ctx.Translate(x, y)