mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 14:31:12 +08:00
1 parent
62c81e7061
commit
226688bbdc
2 files changed
+33
-5
No files matched your search
@@ -51,7 +51,7 @@ func subsetNamedCFFFont(sfnt *sfntFont, glyphs []uint16) ([]byte, error) {
|
|||||||
return serializeOTF(tables)
|
return serializeOTF(tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
// subsetCFFCharstrings 清空未引用的Type2轮廓,保留原字宽、提示和子程序
|
// subsetCFFCharstrings 清空未引用的Type2轮廓及子程序,保留原字宽、提示和编号
|
||||||
// 入参: data 非CID的CFF数据, keep 保留的字形,调用后包含组合组件
|
// 入参: data 非CID的CFF数据, keep 保留的字形,调用后包含组合组件
|
||||||
// 返回: []byte 重建的CFF数据, error 结构或依赖错误
|
// 返回: []byte 重建的CFF数据, error 结构或依赖错误
|
||||||
func subsetCFFCharstrings(data []byte, keep map[uint16]bool) ([]byte, error) {
|
func subsetCFFCharstrings(data []byte, keep map[uint16]bool) ([]byte, error) {
|
||||||
@@ -60,12 +60,15 @@ func subsetCFFCharstrings(data []byte, keep map[uint16]bool) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
keep[0] = true
|
keep[0] = true
|
||||||
|
locals := make([]bool, len(font.locals))
|
||||||
|
globals := make([]bool, len(font.globals))
|
||||||
|
var stack [48]float64
|
||||||
for gid := range keep {
|
for gid := range keep {
|
||||||
if int(gid) >= len(font.chars) {
|
if int(gid) >= len(font.chars) {
|
||||||
return nil, fmt.Errorf("CFF glyph index out of range")
|
return nil, fmt.Errorf("CFF glyph index out of range")
|
||||||
}
|
}
|
||||||
steps := 0
|
steps := 0
|
||||||
state := type2State{font: font, width: font.def, seed: font.seed + uint64(gid), steps: &steps, dependencies: keep}
|
state := type2State{font: font, args: stack[:0], width: font.def, seed: font.seed + uint64(gid), steps: &steps, dependencies: keep, localUsage: locals, globalUsage: globals}
|
||||||
if _, err := state.run(font.chars[gid], 0); err != nil {
|
if _, err := state.run(font.chars[gid], 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -78,7 +81,7 @@ func subsetCFFCharstrings(data []byte, keep map[uint16]bool) ([]byte, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
steps := 0
|
steps := 0
|
||||||
state := type2State{font: font, width: font.def, widthOnly: true, seed: font.seed + uint64(gid), steps: &steps, dependencies: keep}
|
state := type2State{font: font, args: stack[:0], width: font.def, widthOnly: true, seed: font.seed + uint64(gid), steps: &steps, dependencies: keep}
|
||||||
if _, err := state.run(program, 0); err != nil {
|
if _, err := state.run(program, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -100,9 +103,27 @@ func subsetCFFCharstrings(data []byte, keep map[uint16]bool) ([]byte, error) {
|
|||||||
chars[gid] = encoded.Bytes()
|
chars[gid] = encoded.Bytes()
|
||||||
empty[state.width] = chars[gid]
|
empty[state.width] = chars[gid]
|
||||||
}
|
}
|
||||||
|
font.locals = subsetCFFSubroutines(font.locals, locals)
|
||||||
|
font.globals = subsetCFFSubroutines(font.globals, globals)
|
||||||
return rebuildNamedCFF(data, font, chars)
|
return rebuildNamedCFF(data, font, chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// subsetCFFSubroutines 将未引用的子程序替换为空返回,保持调用编号及偏移基数
|
||||||
|
// 入参: programs 子程序索引, used 引用标记
|
||||||
|
// 返回: [][]byte 裁剪后的子程序索引
|
||||||
|
func subsetCFFSubroutines(programs [][]byte, used []bool) [][]byte {
|
||||||
|
result := make([][]byte, len(programs))
|
||||||
|
empty := []byte{11}
|
||||||
|
for index, program := range programs {
|
||||||
|
if used[index] {
|
||||||
|
result[index] = program
|
||||||
|
} else {
|
||||||
|
result[index] = empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// rebuildNamedCFF 重建非CID的CFF偏移,保留字符集、编码和私有提示参数
|
// rebuildNamedCFF 重建非CID的CFF偏移,保留字符集、编码和私有提示参数
|
||||||
// 入参: data 原始CFF数据, font 执行资源, chars 替换后的字形程序
|
// 入参: data 原始CFF数据, font 执行资源, chars 替换后的字形程序
|
||||||
// 返回: []byte 重建的CFF数据, error 不支持的结构
|
// 返回: []byte 重建的CFF数据, error 不支持的结构
|
||||||
@@ -142,7 +163,7 @@ func rebuildNamedCFF(data []byte, font *type2Font, chars [][]byte) ([]byte, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
private, err := readType2Private(data, dict[18], font)
|
private, err := readType2Private(data, dict[18], &type2Font{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -55,6 +55,8 @@ type type2State struct {
|
|||||||
seed uint64
|
seed uint64
|
||||||
steps *int
|
steps *int
|
||||||
dependencies map[uint16]bool
|
dependencies map[uint16]bool
|
||||||
|
localUsage []bool
|
||||||
|
globalUsage []bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// readType2Index 读取并校验CFF索引的全部偏移,不复制程序字节
|
// readType2Index 读取并校验CFF索引的全部偏移,不复制程序字节
|
||||||
@@ -336,13 +338,18 @@ func (s *type2State) run(data []byte, depth int) (bool, error) {
|
|||||||
value := s.args[len(s.args)-1]
|
value := s.args[len(s.args)-1]
|
||||||
s.args = s.args[:len(s.args)-1]
|
s.args = s.args[:len(s.args)-1]
|
||||||
subrs := s.font.locals
|
subrs := s.font.locals
|
||||||
|
usage := s.localUsage
|
||||||
if op == 29 {
|
if op == 29 {
|
||||||
subrs = s.font.globals
|
subrs = s.font.globals
|
||||||
|
usage = s.globalUsage
|
||||||
}
|
}
|
||||||
value += float64(cffSubrBias(len(subrs)))
|
value += float64(cffSubrBias(len(subrs)))
|
||||||
if value < 0 || value >= float64(len(subrs)) || value != math.Trunc(value) {
|
if value < 0 || value >= float64(len(subrs)) || value != math.Trunc(value) {
|
||||||
return false, fmt.Errorf("invalid Type2 subroutine number")
|
return false, fmt.Errorf("invalid Type2 subroutine number")
|
||||||
}
|
}
|
||||||
|
if usage != nil {
|
||||||
|
usage[int(value)] = true
|
||||||
|
}
|
||||||
ended, err := s.run(subrs[int(value)], depth+1)
|
ended, err := s.run(subrs[int(value)], depth+1)
|
||||||
if ended || err != nil {
|
if ended || err != nil {
|
||||||
return ended, err
|
return ended, err
|
||||||
@@ -503,7 +510,7 @@ func (s *type2State) appendComponent(code, x, y float64) error {
|
|||||||
if s.dependencies != nil {
|
if s.dependencies != nil {
|
||||||
s.dependencies[uint16(gid)] = true
|
s.dependencies[uint16(gid)] = true
|
||||||
}
|
}
|
||||||
child := type2State{font: s.font, matrix: s.matrix, width: s.font.def, component: true, output: s.output, originX: x, originY: y, outX: s.outX, outY: s.outY, seed: s.font.seed + uint64(gid), steps: s.steps, stripHints: s.stripHints, dependencies: s.dependencies}
|
child := type2State{font: s.font, matrix: s.matrix, width: s.font.def, component: true, output: s.output, originX: x, originY: y, outX: s.outX, outY: s.outY, seed: s.font.seed + uint64(gid), steps: s.steps, stripHints: s.stripHints, dependencies: s.dependencies, localUsage: s.localUsage, globalUsage: s.globalUsage}
|
||||||
_, err := child.run(s.font.chars[gid], 0)
|
_, err := child.run(s.font.chars[gid], 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid Type2 component %s: %w", name, err)
|
return fmt.Errorf("invalid Type2 component %s: %w", name, err)
|
||||||
|
|||||||
Reference in new issue
Block a user