feat(字体渲染): 修复字体引用与渲染
build.yaml / build (push) Successful in 50s

This commit is contained in:
xiaoqidun committed 2026-10-10 15:52:36 +08:00
1 parent 04058ce76a
commit a5f51294eb
9 files changed
+50 -13

No files matched your search

+3
View File
@@ -1080,6 +1080,9 @@ func scaleTextNumbers(value string, scale float64) string {
// 入参: obj 文字对象 // 入参: obj 文字对象
// 返回: error 错误信息 // 返回: error 错误信息
func (e *Editor) prepareText(obj *TextObject) error { func (e *Editor) prepareText(obj *TextObject) error {
if id := editorResourceID(obj.Font); id != "" {
obj.Font = id
}
var sfnt FontMetrics var sfnt FontMetrics
external := false external := false
for _, resource := range e.resources { for _, resource := range e.resources {
+7 -1
View File
@@ -179,13 +179,16 @@ func (e *Editor) ObjectCapabilities(page int, id string) (ObjectCapabilities, er
// 入参: id 字体资源标识 // 入参: id 字体资源标识
// 返回: []byte 独立字体数据, error 错误信息 // 返回: []byte 独立字体数据, error 错误信息
func (e *Editor) FontData(id string) ([]byte, error) { func (e *Editor) FontData(id string) ([]byte, error) {
if key := editorResourceID(id); key != "" {
id = key
}
for _, resource := range e.resources { for _, resource := range e.resources {
if resource.font != nil && resource.font.ID == id && len(resource.data) != 0 { if resource.font != nil && resource.font.ID == id && len(resource.data) != 0 {
return bytes.Clone(resource.data), nil return bytes.Clone(resource.data), nil
} }
} }
if e.source != nil { if e.source != nil {
if definition := e.source.reader.fontCache[id]; definition != nil && definition.FontFile != "" { if definition := e.source.reader.fontDefinition(id); definition != nil && definition.FontFile != "" {
return e.source.reader.FontData(id) return e.source.reader.FontData(id)
} }
} }
@@ -799,6 +802,9 @@ func editorGeometry(object GraphicObject) (string, string) {
// 入参: id 字体资源标识 // 入参: id 字体资源标识
// 返回: FontMetrics 字体度量, error 错误信息 // 返回: FontMetrics 字体度量, error 错误信息
func (e *Editor) editorFont(id string) (FontMetrics, error) { func (e *Editor) editorFont(id string) (FontMetrics, error) {
if key := editorResourceID(id); key != "" {
id = key
}
if metrics := e.fontMetrics[id]; metrics != nil { if metrics := e.fontMetrics[id]; metrics != nil {
return metrics, nil return metrics, nil
} }
+16 -4
View File
@@ -146,12 +146,18 @@ func (r *Renderer) ResolveFont(id string, exact bool) (ResolvedFont, error) {
if r.backends.Fonts == nil { if r.backends.Fonts == nil {
return ResolvedFont{}, fmt.Errorf("fonts: %w", ErrBackendUnavailable) return ResolvedFont{}, fmt.Errorf("fonts: %w", ErrBackendUnavailable)
} }
key := resolvedFontKey{id: id, exact: exact, definition: r.Reader.fontCache[id]} key := resolvedFontKey{id: id, exact: exact, definition: r.Reader.fontDefinition(id)}
if key.definition != nil && key.definition.ID != "" {
key.id = key.definition.ID
}
if cached, ok := r.resolvedFonts[key]; ok { if cached, ok := r.resolvedFonts[key]; ok {
return cached.font, cached.err return cached.font, cached.err
} }
resolved, err := r.backends.Fonts.ResolveFont(r, id, exact) resolved, err := r.backends.Fonts.ResolveFont(r, key.id, exact)
key.definition = r.Reader.fontCache[id] key.definition = r.Reader.fontDefinition(id)
if key.definition != nil && key.definition.ID != "" {
key.id = key.definition.ID
}
r.resolvedFonts[key] = resolvedFontResult{font: resolved, err: err} r.resolvedFonts[key] = resolvedFontResult{font: resolved, err: err}
return resolved, err return resolved, err
} }
@@ -161,6 +167,9 @@ func (r *Renderer) ResolveFont(id string, exact bool) (ResolvedFont, error) {
// 入参: id 字体资源标识 // 入参: id 字体资源标识
// 返回: *PreparedFont 绘制字体, error 字体解析错误 // 返回: *PreparedFont 绘制字体, error 字体解析错误
func (r *Renderer) PrepareFont(id string) (*PreparedFont, error) { func (r *Renderer) PrepareFont(id string) (*PreparedFont, error) {
if definition := r.Reader.fontDefinition(id); definition != nil && definition.ID != "" {
id = definition.ID
}
if cached := r.preparedFonts[id]; cached != nil { if cached := r.preparedFonts[id]; cached != nil {
return cached, nil return cached, nil
} }
@@ -168,8 +177,11 @@ func (r *Renderer) PrepareFont(id string) (*PreparedFont, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
definition := r.Reader.fontDefinition(id)
if definition != nil && definition.ID != "" {
id = definition.ID
}
prepared := &PreparedFont{ResolvedFont: resolved} prepared := &PreparedFont{ResolvedFont: resolved}
definition := r.Reader.fontCache[id]
if definition != nil && definition.FontFile != "" { if definition != nil && definition.FontFile != "" {
key := r.fontDigest(resolved.Data) key := r.fontDigest(resolved.Data)
if content, ok := r.fontPreparations.get(key); ok { if content, ok := r.fontPreparations.get(key); ok {
+1 -1
View File
@@ -262,7 +262,7 @@ func (r *Reader) MatchFontFiles(files []string, ids ...string) ([]string, error)
return nil, err return nil, err
} }
for _, id := range ids { for _, id := range ids {
if r.fontCache[id] == nil { if r.fontDefinition(id) == nil {
fonts = append(fonts, Font{ID: id}) fonts = append(fonts, Font{ID: id})
} }
} }
+18 -2
View File
@@ -111,12 +111,12 @@ func (r *Reader) FontData(id string) ([]byte, error) {
// 入参: id 字体资源标识, readonly 是否允许借用只读资源 // 入参: id 字体资源标识, readonly 是否允许借用只读资源
// 返回: []byte 字体数据, error 资源或集合错误 // 返回: []byte 字体数据, error 资源或集合错误
func (r *Reader) fontData(id string, readonly bool) ([]byte, error) { func (r *Reader) fontData(id string, readonly bool) ([]byte, error) {
if r.fontCache[id] == nil { if r.fontDefinition(id) == nil {
if _, err := r.Fonts(); err != nil { if _, err := r.Fonts(); err != nil {
return nil, err return nil, err
} }
} }
f := r.fontCache[id] f := r.fontDefinition(id)
if f == nil || f.FontFile == "" { if f == nil || f.FontFile == "" {
return nil, fmt.Errorf("embedded font %q not found", id) return nil, fmt.Errorf("embedded font %q not found", id)
} }
@@ -135,6 +135,14 @@ func (r *Reader) fontData(id string, readonly bool) ([]byte, error) {
return data, nil return data, nil
} }
// fontDefinition 按资源标识查找已加载的字体,数值等价的引用共用同一定义
// 入参: id 字体资源标识
// 返回: *Font 字体定义,未找到或别名冲突时为nil
func (r *Reader) fontDefinition(id string) *Font {
font, _ := resourceValue(r.fontCache, id)
return font
}
// FontInfos 获取OFD字体诊断信息 // FontInfos 获取OFD字体诊断信息
// 返回: []FontInfo 字体诊断列表, error 错误信息 // 返回: []FontInfo 字体诊断列表, error 错误信息
func (r *Renderer) FontInfos() ([]FontInfo, error) { func (r *Renderer) FontInfos() ([]FontInfo, error) {
@@ -293,6 +301,14 @@ func (r *Renderer) fontInfos(usage map[string]int) ([]FontInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
counts := make(map[string]int, len(usage))
for id, used := range usage {
if font := r.Reader.fontDefinition(id); font != nil {
id = font.ID
}
counts[id] += used
}
usage = counts
infos := make([]FontInfo, 0, len(fonts)+len(usage)) infos := make([]FontInfo, 0, len(fonts)+len(usage))
seen := make(map[string]bool) seen := make(map[string]bool)
for _, font := range fonts { for _, font := range fonts {
+2 -2
View File
@@ -158,12 +158,12 @@ func (r *Renderer) fontSourceMatch(backend FontBackend, fontID string, definitio
// 入参: backend 字体后端, id 字体ID, exact 是否禁止无关回退 // 入参: backend 字体后端, id 字体ID, exact 是否禁止无关回退
// 返回: ResolvedFont 字体及来源, error 解析错误 // 返回: ResolvedFont 字体及来源, error 解析错误
func (r *Renderer) resolveFontSource(backend FontBackend, id string, exact bool) (ResolvedFont, error) { func (r *Renderer) resolveFontSource(backend FontBackend, id string, exact bool) (ResolvedFont, error) {
definition := r.Reader.fontCache[id] definition := r.Reader.fontDefinition(id)
if definition == nil && !r.Reader.fontResourcesRead && r.Reader.OFD != nil { if definition == nil && !r.Reader.fontResourcesRead && r.Reader.OFD != nil {
if _, err := r.Reader.Fonts(); err != nil { if _, err := r.Reader.Fonts(); err != nil {
return ResolvedFont{}, err return ResolvedFont{}, err
} }
definition = r.Reader.fontCache[id] definition = r.Reader.fontDefinition(id)
} }
if definition == nil { if definition == nil {
definition = &Font{ID: id} definition = &Font{ID: id}
+1 -1
View File
@@ -118,7 +118,7 @@ func (r *Renderer) PositionText(object TextObject, state RenderState) (*Position
italic = italic || defaults.Italic italic = italic || defaults.Italic
} }
bold := weight >= 700 bold := weight >= 700
if definition := r.Reader.fontCache[id]; definition != nil { if definition := r.Reader.fontDefinition(id); definition != nil {
bold = bold && !definition.Bold bold = bold && !definition.Bold
if definition.FontFile == "" && fontNoSyntheticBold(definition.FontName, definition.FamilyName) { if definition.FontFile == "" && fontNoSyntheticBold(definition.FontName, definition.FamilyName) {
bold = false bold = false
+1 -1
View File
@@ -32,7 +32,7 @@ func (r *Renderer) loadFont(fontID string) *canvas.FontFamily {
r.renderError = err r.renderError = err
return nil return nil
} }
of := r.Reader.fontCache[fontID] of := r.Reader.fontDefinition(fontID)
if len(resolved.Data) == 0 { if len(resolved.Data) == 0 {
return nil return nil
} }
+1 -1
View File
@@ -142,7 +142,7 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
} }
fontID := r.textObjectFontID(obj) fontID := r.textObjectFontID(obj)
embeddedFont := false embeddedFont := false
if of, ok := r.Reader.fontCache[fontID]; ok { if of := r.Reader.fontDefinition(fontID); of != nil {
embeddedFont = of.FontFile != "" embeddedFont = of.FontFile != ""
if syntheticBold && !embeddedFont && fontNoSyntheticBold(of.FontName, of.FamilyName) { if syntheticBold && !embeddedFont && fontNoSyntheticBold(of.FontName, of.FamilyName) {
syntheticBold = false syntheticBold = false