feat(字体处理): 优化字体裁剪与依赖校验
build.yaml / build (push) Successful in 1m17s

This commit is contained in:
xiaoqidun committed 2026-10-12 16:55:10 +08:00
1 parent 7bce701907
commit 92149b220e
3 files changed
+39 -38

No files matched your search

+14 -21
View File
@@ -283,17 +283,12 @@ func subsetSourceSFNTFont(data []byte, usage *editorFontUsage) []byte {
return nil
}
}
for id := range glyphs {
if id >= sfnt.NumGlyphs() {
return nil
}
dependencies, err := sfnt.glyphDependencies(id)
if err != nil {
return nil
}
for _, dependency := range dependencies {
glyphs[dependency] = true
}
dependencies, err := sfnt.glyphDependencies(slices.Collect(maps.Keys(glyphs))...)
if err != nil {
return nil
}
for _, dependency := range dependencies {
glyphs[dependency] = true
}
var glyf, loca []byte
for id := 0; id <= int(sfnt.NumGlyphs()); id++ {
@@ -426,16 +421,14 @@ func subsetCompactSFNTFont(sfnt *sfntFont, glyphs []uint16) ([]byte, error) {
ids = append(ids, id)
}
}
for index := 0; index < len(ids); index++ {
dependencies, err := sfnt.glyphDependencies(ids[index])
if err != nil {
return nil, err
}
for _, id := range dependencies {
if _, ok := remap[id]; !ok {
remap[id] = uint16(len(ids))
ids = append(ids, id)
}
dependencies, err := sfnt.glyphDependencies(ids...)
if err != nil {
return nil, err
}
for _, id := range dependencies {
if _, ok := remap[id]; !ok {
remap[id] = uint16(len(ids))
ids = append(ids, id)
}
}
table := make(map[string][]byte)
+17 -9
View File
@@ -263,21 +263,24 @@ func (f *sfntFont) VerticalMetrics() (uint16, uint16, uint16) {
// 返回: []byte 独立字体
func (f *sfntFont) Write() []byte { data, _ := serializeOTF(f.Tables); return data }
// glyphDependencies 收集复合字形依赖,拒绝循环引用和截断记录
// 入参: gid 字形编号
// glyphDependencies 批量收集复合字形依赖,校验引用、记录长度和嵌套深度
// 入参: glyphs 字形编号
// 返回: []uint16 依赖字形, error 字形错误
func (f *sfntFont) glyphDependencies(gid uint16) ([]uint16, error) {
seen, active := make(map[uint16]bool), make(map[uint16]bool)
func (f *sfntFont) glyphDependencies(glyphs ...uint16) ([]uint16, error) {
heights, active := make(map[uint16]int), make(map[uint16]bool)
var result []uint16
var visit func(uint16) error
visit = func(id uint16) error {
if id >= f.count || active[id] || len(active) > 64 {
return fmt.Errorf("invalid composite glyph reference")
}
if seen[id] {
if height := heights[id]; height != 0 {
if len(active)+height > 65 {
return fmt.Errorf("invalid composite glyph reference")
}
return nil
}
seen[id], active[id] = true, true
heights[id], active[id] = 1, true
defer delete(active, id)
data, err := trueTypeGlyphData(f.Tables, id)
if err != nil {
@@ -315,18 +318,23 @@ func (f *sfntFont) glyphDependencies(gid uint16) ([]uint16, error) {
if pos > len(data) {
return fmt.Errorf("truncated composite transform")
}
if !seen[child] {
if heights[child] == 0 {
result = append(result, child)
}
if err := visit(child); err != nil {
return err
}
heights[id] = max(heights[id], heights[child]+1)
if flags&0x20 == 0 {
break
}
}
return nil
}
err := visit(gid)
return result, err
for _, id := range glyphs {
if err := visit(id); err != nil {
return nil, err
}
}
return result, nil
}
+8 -8
View File
@@ -17,6 +17,8 @@ package ofdgo
import (
"encoding/binary"
"fmt"
"maps"
"slices"
)
// variableSFNTSubsettable 核对TrueType可变轴与字形变化表的基本结构
@@ -51,14 +53,12 @@ func subsetVariableSFNTFont(sfnt *sfntFont, glyphs []uint16) ([]byte, error) {
usage.chars[char] = true
}
}
for gid := range usage.glyphs {
dependencies, err := sfnt.glyphDependencies(gid)
if err != nil {
return nil, err
}
for _, dependency := range dependencies {
usage.glyphs[dependency] = true
}
dependencies, err := sfnt.glyphDependencies(slices.Collect(maps.Keys(usage.glyphs))...)
if err != nil {
return nil, err
}
for _, dependency := range dependencies {
usage.glyphs[dependency] = true
}
mapping := make(map[rune]uint16, len(usage.chars))
for char := range usage.chars {