feat(归并文件): 归并根包文件,保持接口不变
build.yaml / build (push) Successful in 43s

This commit is contained in:
xiaoqidun committed 2026-10-19 09:43:06 +08:00
1 parent aab5d40f93
commit 84808cda61
22 files changed
+1066 -1306

No files matched your search

+93
View File
@@ -15,6 +15,7 @@
package ofdgo
import (
"encoding/binary"
"fmt"
"sync"
@@ -24,6 +25,34 @@ import (
// sfntGlyphBoundsLimit 限制单个字体保留的字形与字号边界数量
const sfntGlyphBoundsLimit = 4096
// FontResource 保存独立字体数据、标准元信息与只读度量,不包含绘图库类型
type FontResource struct {
FontMetrics
Data []byte
Font Font
Extension string
CanSubset bool
}
// FontUsage 描述全包已确认的字体引用,Unsafe禁止裁剪
type FontUsage struct {
Characters []rune
Glyphs []uint16
Unsafe bool
}
// FontResourceBackend 解析和裁剪保存资源,独立于显示字体后端
// SubsetFont的preserve为true时不得改变字形编号,SubsetSourceFont无安全收益时返回nil
type FontResourceBackend interface {
Backend
OpenFontResource(file FontFile, index int) (*FontResource, error)
SubsetFont(data []byte, glyphs []uint16, preserve bool) ([]byte, error)
SubsetSourceFont(data []byte, usage FontUsage) ([]byte, error)
}
// SFNTBackend 提供独立的OpenType字体度量、轮廓和资源处理
type SFNTBackend struct{}
// sfntFontMetrics 保留默认字体度量,写出时不更新原始时间
type sfntFontMetrics struct {
*basefont.SFNT
@@ -47,6 +76,9 @@ type sfntGlyphSize struct {
// glyphGeometry 将字体轮廓转换为纵轴向下的几何路径
type glyphGeometry struct{ path GeometryPath }
// sfntResourceMetrics 隔离资源解析器的度量实现
type sfntResourceMetrics struct{ *basefont.SFNT }
// MoveTo 开始子路径
// 入参: x 横坐标, y 纵坐标
func (p *glyphGeometry) MoveTo(x, y float64) {
@@ -180,3 +212,64 @@ func (f sfntFontMetrics) GlyphOutlines(glyphs []uint16, size float64) ([]Geometr
}
return result, nil
}
// Name 返回资源后端标识
// 返回: string 后端标识
func (SFNTBackend) Name() string { return "sfnt" }
// OpenFontResource 提取独立字体并读取名称、样式和裁剪能力
// CFF2使用默认实例的静态轮廓,不改变原字体文件
// 入参: file 字体文件, index 集合索引
// 返回: *FontResource 字体资源, error 解析错误
func (SFNTBackend) OpenFontResource(file FontFile, index int) (*FontResource, error) {
data, err := file.Face(index)
if err != nil {
return nil, err
}
data, err = basefont.DefaultCFF2Font(data)
if err != nil {
return nil, err
}
sfnt, err := basefont.ParseSFNT(data)
if err != nil {
return nil, err
}
name := basefont.SFNTName(sfnt, 6, 4, 1)
if name == "" {
return nil, fmt.Errorf("font has no name")
}
extension := ".ttf"
if sfnt.IsCFF {
extension = ".otf"
}
return &FontResource{
FontMetrics: sfntResourceMetrics{sfnt}, Data: data, Extension: extension,
Font: Font{FontName: name, FamilyName: basefont.SFNTName(sfnt, 16, 1), Charset: "unicode", Bold: binary.BigEndian.Uint16(sfnt.Tables["head"][44:])&1 != 0, Italic: binary.BigEndian.Uint16(sfnt.Tables["head"][44:])&2 != 0, FixedWidth: len(sfnt.Tables["post"]) >= 16 && binary.BigEndian.Uint32(sfnt.Tables["post"][12:]) != 0},
CanSubset: basefont.Subsettable(sfnt),
}, nil
}
// SubsetFont 裁剪新建字体并按要求保留显式字形编号
// 入参: data 字体数据, glyphs 用字, preserve 是否保留编号
// 返回: []byte 子集, error 裁剪错误
func (SFNTBackend) SubsetFont(data []byte, glyphs []uint16, preserve bool) ([]byte, error) {
return basefont.SubsetSFNT(data, glyphs, preserve)
}
// SubsetSourceFont 按全包引用裁剪原字体,不确定时保留原资源
// 入参: data 字体数据, usage 用字信息
// 返回: []byte 子集, error 裁剪错误
func (SFNTBackend) SubsetSourceFont(data []byte, usage FontUsage) ([]byte, error) {
u := &basefont.Usage{Characters: make(map[rune]bool), Glyphs: make(map[uint16]bool), Unsafe: usage.Unsafe}
for _, char := range usage.Characters {
u.Characters[char] = true
}
for _, glyph := range usage.Glyphs {
u.Glyphs[glyph] = true
}
return basefont.SubsetSourceSFNT(data, u), nil
}
// Write 返回未改动元信息的字体数据
// 返回: []byte 字体数据
func (f sfntResourceMetrics) Write() []byte { return f.SFNT.Write() }