mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 17:27:08 +08:00
1 parent
6926ceafc9
commit
0b1dc7e6c8
7 files changed
+148
-25
No files matched your search
@@ -18,7 +18,7 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"maps"
|
||||
"sort"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/go-text/typesetting/font/opentype/tables"
|
||||
@@ -34,10 +34,11 @@ type SFNT struct {
|
||||
reverse map[uint16][]rune
|
||||
}
|
||||
|
||||
// sfntCmap 保存编码记录及对应字符映射
|
||||
// sfntCmap 保存编码记录及对应字符映射,标记已解析的共享子表
|
||||
type sfntCmap struct {
|
||||
platform, encoding, format uint16
|
||||
mapping map[rune]uint16
|
||||
duplicate bool
|
||||
}
|
||||
|
||||
// ParseSFNT 校验独立字体的必需表、度量范围及字符映射
|
||||
@@ -86,6 +87,9 @@ func ParseSFNTTables(table map[string][]byte) (*SFNT, error) {
|
||||
}
|
||||
f.cmaps = cmaps
|
||||
for _, cmap := range f.cmaps {
|
||||
if cmap.duplicate {
|
||||
continue
|
||||
}
|
||||
for _, glyph := range cmap.mapping {
|
||||
if glyph >= f.count {
|
||||
return nil, fmt.Errorf("cmap glyph index out of range")
|
||||
@@ -150,7 +154,7 @@ func readSFNTCmaps(data []byte) ([]sfntCmap, error) {
|
||||
}
|
||||
parsed[offset] = mapping
|
||||
}
|
||||
result = append(result, sfntCmap{binary.BigEndian.Uint16(record), binary.BigEndian.Uint16(record[2:]), format, mapping})
|
||||
result = append(result, sfntCmap{platform: binary.BigEndian.Uint16(record), encoding: binary.BigEndian.Uint16(record[2:]), format: format, mapping: mapping, duplicate: found})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -164,11 +168,11 @@ func (f *SFNT) UnitsPerEm() uint16 { return f.units }
|
||||
func (f *SFNT) NumGlyphs() uint16 { return f.count }
|
||||
|
||||
// CmapEntries 返回各编码记录的映射项总数,共享子表按记录分别计数
|
||||
// 返回: int 用于缓存预算的映射项数量
|
||||
func (f *SFNT) CmapEntries() int {
|
||||
count := 0
|
||||
// 返回: uint64 用于缓存预算的映射项数量
|
||||
func (f *SFNT) CmapEntries() uint64 {
|
||||
var count uint64
|
||||
for _, cmap := range f.cmaps {
|
||||
count += len(cmap.mapping)
|
||||
count += uint64(len(cmap.mapping))
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -178,6 +182,9 @@ func (f *SFNT) CmapEntries() int {
|
||||
// 返回: uint16 字形编号
|
||||
func (f *SFNT) GlyphIndex(char rune) uint16 {
|
||||
for _, cmap := range f.cmaps {
|
||||
if cmap.duplicate {
|
||||
continue
|
||||
}
|
||||
if gid := cmap.mapping[char]; gid != 0 {
|
||||
return gid
|
||||
}
|
||||
@@ -193,6 +200,9 @@ func (f *SFNT) glyphCharacters(gid uint16) []rune {
|
||||
f.reverse = make(map[uint16][]rune)
|
||||
seen := make(map[rune]bool)
|
||||
for _, cmap := range f.cmaps {
|
||||
if cmap.duplicate {
|
||||
continue
|
||||
}
|
||||
for char, glyph := range cmap.mapping {
|
||||
if glyph != 0 && !seen[char] {
|
||||
f.reverse[glyph] = append(f.reverse[glyph], char)
|
||||
@@ -201,7 +211,7 @@ func (f *SFNT) glyphCharacters(gid uint16) []rune {
|
||||
}
|
||||
}
|
||||
for _, chars := range f.reverse {
|
||||
sort.Slice(chars, func(i, j int) bool { return chars[i] < chars[j] })
|
||||
slices.Sort(chars)
|
||||
}
|
||||
})
|
||||
return f.reverse[gid]
|
||||
|
||||
@@ -134,7 +134,8 @@ func SubsetSFNT(data []byte, glyphs []uint16, mapped bool) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if subset := SubsetSourceSFNT(fixed, usage); subset != nil {
|
||||
sfnt.Tables = tables
|
||||
if subset := subsetSourceSFNT(sfnt, usage, len(fixed)); subset != nil {
|
||||
return subset, nil
|
||||
}
|
||||
return fixed, nil
|
||||
@@ -147,7 +148,7 @@ func SubsetSFNT(data []byte, glyphs []uint16, mapped bool) ([]byte, error) {
|
||||
// 入参: data 字体数据, usage 全包用字记录
|
||||
// 返回: []byte 更小的字体子集,无确定收益时为空
|
||||
func SubsetSourceSFNT(data []byte, usage *Usage) []byte {
|
||||
if usage.Unsafe || len(usage.Characters)+len(usage.Glyphs) == 0 || bytes.HasPrefix(data, []byte("ttcf")) {
|
||||
if usage == nil || usage.Unsafe || len(usage.Characters)+len(usage.Glyphs) == 0 || bytes.HasPrefix(data, []byte("ttcf")) {
|
||||
return nil
|
||||
}
|
||||
fontTables, err := FileTables(data, 0)
|
||||
@@ -162,7 +163,17 @@ func SubsetSourceSFNT(data []byte, usage *Usage) []byte {
|
||||
}
|
||||
}
|
||||
sfnt, err := ParseSFNTTables(fontTables)
|
||||
if err != nil || !sfnt.IsTrueType && !sfnt.IsCFF || fontEmbeddingFlags(sfnt)&0x0100 != 0 {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return subsetSourceSFNT(sfnt, usage, len(data))
|
||||
}
|
||||
|
||||
// subsetSourceSFNT 复用已校验的字体表裁剪字形,仅返回小于原编码的结果
|
||||
// 入参: sfnt 已解析字体, usage 用字记录, size 原编码长度
|
||||
// 返回: []byte 更小的字体子集,无确定收益时为空
|
||||
func subsetSourceSFNT(sfnt *SFNT, usage *Usage, size int) []byte {
|
||||
if usage == nil || usage.Unsafe || len(usage.Characters)+len(usage.Glyphs) == 0 || !sfnt.IsTrueType && !sfnt.IsCFF || fontEmbeddingFlags(sfnt)&0x0100 != 0 {
|
||||
return nil
|
||||
}
|
||||
var unicodeTables []sfntCmap
|
||||
@@ -178,6 +189,9 @@ func SubsetSourceSFNT(data []byte, usage *Usage) []byte {
|
||||
return nil
|
||||
}
|
||||
glyphs := maps.Clone(usage.Glyphs)
|
||||
if glyphs == nil {
|
||||
glyphs = make(map[uint16]bool)
|
||||
}
|
||||
glyphs[0] = true
|
||||
mapping := make(map[rune]uint16, len(usage.Characters))
|
||||
for char := range usage.Characters {
|
||||
@@ -210,7 +224,7 @@ func SubsetSourceSFNT(data []byte, usage *Usage) []byte {
|
||||
tables["cmap"] = buildCmapWithVariations(sfnt.NumGlyphs(), mapping, variations)
|
||||
delete(tables, "DSIG")
|
||||
result, err := SerializeOTF(tables)
|
||||
if err != nil || len(result) >= len(data) {
|
||||
if err != nil || len(result) >= size {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
@@ -258,7 +272,7 @@ func SubsetSourceSFNT(data []byte, usage *Usage) []byte {
|
||||
clear(tables["head"][8:12])
|
||||
delete(tables, "DSIG")
|
||||
result, err := SerializeOTF(tables)
|
||||
if err != nil || len(result) >= len(data) {
|
||||
if err != nil || len(result) >= size {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
|
||||
Reference in new issue
Block a user