From dc9487613b88e6471d76805e8aaa8e8c40ba7662 Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Thu, 25 Jun 2026 23:41:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=8D=B0=E7=AB=A0=E6=B8=B2=E6=9F=93):=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8D=B0=E7=AB=A0=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ofdgo_renderer.go | 61 ++++++++++++++++++++++++++++++++++++++--------- ofdgo_sign.go | 33 ++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ofdgo_renderer.go b/ofdgo_renderer.go index 798c8cf..374e502 100644 --- a/ofdgo_renderer.go +++ b/ofdgo_renderer.go @@ -650,7 +650,8 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 if obj.VScale != 0 { sizeMM *= obj.VScale } - if scale := ctm.YScale(); scale > 0 { + useTextMatrix := hasTextMatrix(ctm) + if scale := ctm.YScale(); scale > 0 && !useTextMatrix { sizeMM *= scale } sizePt := sizeMM * 2.83465 @@ -754,18 +755,38 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 } if glyphFillPaint != nil { ctx.SetFill(glyphFillPaint) - if embeddedFont { - path, width := face.ToPath(str) - textWidth = width - ctx.DrawPath(canvasX, canvasY, path) - } else { - textFace := face - if fillColorNode != nil && fillColorNode.AxialShd != nil { - textFace = ff.Face(sizePt, glyphFillPaint, fontStyle, canvas.FontNormal) + drawGlyph := func(x, y float64) { + if embeddedFont { + path, width := face.ToPath(str) + textWidth = width + ctx.DrawPath(x, y, path) + } else { + textFace := face + if fillColorNode != nil && fillColorNode.AxialShd != nil { + textFace = ff.Face(sizePt, glyphFillPaint, fontStyle, canvas.FontNormal) + } + text := canvas.NewTextLine(textFace, str, canvas.Left) + ctx.DrawText(x, y, text) } - text := canvas.NewTextLine(textFace, str, canvas.Left) - ctx.DrawText(canvasX, canvasY, text) } + if useTextMatrix { + ctx.Push() + ctx.Translate(canvasX, canvasY) + ctx.ComposeView(textMatrix(ctm)) + drawGlyph(0, 0) + if strings.Contains(obj.Decoration, "Underline") { + uw := sizeMM * 0.05 + ctx.SetStrokeWidth(uw) + ctx.SetStrokeColor(fillColor) + off := sizeMM * 0.1 + ctx.MoveTo(0, -off) + ctx.LineTo(textWidth, -off) + ctx.Stroke() + } + ctx.Pop() + continue + } + drawGlyph(canvasX, canvasY) } if strings.Contains(obj.Decoration, "Underline") { uw := sizeMM * 0.05 @@ -782,6 +803,24 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 ctx.Pop() } +// hasTextMatrix 判断文本是否需要应用字形变换 +// 入参: ctm 变换矩阵 +// 返回: bool 是否需要变换 +func hasTextMatrix(ctm Matrix) bool { + const eps = 1e-9 + return math.Abs(ctm.a-1) > eps || math.Abs(ctm.b) > eps || math.Abs(ctm.c) > eps || math.Abs(ctm.d-1) > eps +} + +// textMatrix 获取文本字形变换矩阵 +// 入参: ctm OFD变换矩阵 +// 返回: canvas.Matrix 画布变换矩阵 +func textMatrix(ctm Matrix) canvas.Matrix { + return canvas.Matrix{ + {ctm.a, -ctm.c, 0}, + {-ctm.b, ctm.d, 0}, + } +} + // loadFont 加载字体 // 入参: fontID 字体ID // 返回: *canvas.FontFamily 字体族 diff --git a/ofdgo_sign.go b/ofdgo_sign.go index 3905e37..e44bffa 100644 --- a/ofdgo_sign.go +++ b/ofdgo_sign.go @@ -138,9 +138,10 @@ func extractSeal(data []byte) (string, []byte) { if node.IsCompound { if elements, ok := asn1Children(node.Bytes); ok { if len(elements) >= 2 && elements[1].Tag == 4 { - sealType := sealString(elements[0]) - if sealType == "es" { - sealType = "png" + sealType := normalizeSealType(sealString(elements[0])) + if isSealMediaType(sealType) { + foundType, foundData = sealType, elements[1].Bytes + return true } if imgType, sealData := extractImageData(elements[1].Bytes); len(sealData) > 0 { if sealType == "" { @@ -197,6 +198,32 @@ func sealString(raw asn1.RawValue) string { return s } +// normalizeSealType 标准化印章媒体类型 +// 入参: s 原始媒体类型 +// 返回: string 标准媒体类型 +func normalizeSealType(s string) string { + switch s { + case "jpg": + return "jpeg" + case "jb2", "gbig2": + return "jbig2" + default: + return s + } +} + +// isSealMediaType 判断是否为可渲染印章媒体类型 +// 入参: s 媒体类型 +// 返回: bool 是否可渲染 +func isSealMediaType(s string) bool { + switch s { + case "png", "jpeg", "jbig2", "ofd": + return true + default: + return false + } +} + // extractImageData 提取图片数据 // 入参: data 原始数据 // 返回: string 图片类型, []byte 图片数据