feat(印章渲染): 优化印章渲染

This commit is contained in:
2026-06-25 23:41:23 +08:00
parent f792f0da3b
commit dc9487613b
2 changed files with 80 additions and 14 deletions
+50 -11
View File
@@ -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 字体族
+30 -3
View File
@@ -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 图片数据