mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
This commit is contained in:
1 parent
60eb5ac6a1
commit
be697e7045
10 files changed
+508
-220
No files matched your search
+36
-27
@@ -16,7 +16,6 @@ package ofdgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
@@ -37,6 +36,7 @@ type type2Font struct {
|
||||
type type2State struct {
|
||||
font *type2Font
|
||||
widthTarget *type2Font
|
||||
matrix *[6]float64
|
||||
args []float64
|
||||
transient [32]float64
|
||||
stored uint32
|
||||
@@ -60,37 +60,24 @@ type type2State struct {
|
||||
// 入参: data 字体数据, offset 索引偏移
|
||||
// 返回: [][]byte 索引项, int 索引结束位置, error 错误信息
|
||||
func readType2Index(data []byte, offset int) ([][]byte, int, error) {
|
||||
if offset < 0 || offset > len(data)-2 {
|
||||
return nil, 0, fmt.Errorf("truncated CFF index")
|
||||
}
|
||||
count := int(binary.BigEndian.Uint16(data[offset:]))
|
||||
if count == 0 {
|
||||
return nil, offset + 2, nil
|
||||
}
|
||||
if offset > len(data)-3 {
|
||||
return nil, 0, fmt.Errorf("truncated CFF index header")
|
||||
count, base, end, err := scanCFFIndex(data, offset)
|
||||
if err != nil || count == 0 {
|
||||
return nil, end, err
|
||||
}
|
||||
width := int(data[offset+2])
|
||||
if width < 1 || width > 4 || count+1 > (len(data)-offset-3)/width {
|
||||
return nil, 0, fmt.Errorf("invalid CFF index offsets")
|
||||
}
|
||||
base := offset + 3 + (count+1)*width
|
||||
items := make([][]byte, count)
|
||||
previous := uint64(0)
|
||||
previous := 1
|
||||
for index := 0; index <= count; index++ {
|
||||
value := uint64(0)
|
||||
for _, b := range data[offset+3+index*width : offset+3+(index+1)*width] {
|
||||
value = value<<8 | uint64(b)
|
||||
}
|
||||
if value < 1 || value-1 > uint64(len(data)-base) || value < previous || index == 0 && value != 1 {
|
||||
return nil, 0, fmt.Errorf("invalid CFF index range")
|
||||
}
|
||||
if index != 0 {
|
||||
items[index-1] = data[base+int(previous)-1 : base+int(value)-1]
|
||||
items[index-1] = data[base+previous-1 : base+int(value)-1]
|
||||
}
|
||||
previous = value
|
||||
previous = int(value)
|
||||
}
|
||||
return items, base + int(previous) - 1, nil
|
||||
return items, end, nil
|
||||
}
|
||||
|
||||
// readType2Font 读取单FD字体的Type2执行资源,CID字体先经字体规范化
|
||||
@@ -197,6 +184,13 @@ func readType2Private(data []byte, values []float64, font *type2Font) (cffDict,
|
||||
// 入参: data CFF字体数据
|
||||
// 返回: [][]byte 字形程序, bool 是否变更, error 错误信息
|
||||
func normalizeType2Programs(data []byte) ([][]byte, bool, error) {
|
||||
return normalizeType2ProgramsMatrix(data, nil)
|
||||
}
|
||||
|
||||
// normalizeType2ProgramsMatrix 规范化字形指令并按需变换轮廓与字宽
|
||||
// 入参: data CFF字体数据, matrix 设计坐标变换,nil时保留原坐标
|
||||
// 返回: [][]byte 字形程序, bool 是否变更, error 错误信息
|
||||
func normalizeType2ProgramsMatrix(data []byte, matrix *[6]float64) ([][]byte, bool, error) {
|
||||
font, err := readType2Font(data)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
@@ -206,7 +200,10 @@ func normalizeType2Programs(data []byte) ([][]byte, bool, error) {
|
||||
var stack [48]float64
|
||||
for gid, program := range font.chars {
|
||||
if len(program) == 0 {
|
||||
continue
|
||||
if matrix == nil {
|
||||
continue
|
||||
}
|
||||
program = []byte{14}
|
||||
}
|
||||
steps := 0
|
||||
state := type2State{font: font, args: stack[:0], width: font.def, seed: font.seed + uint64(gid), steps: &steps}
|
||||
@@ -214,12 +211,15 @@ func normalizeType2Programs(data []byte) ([][]byte, bool, error) {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if !state.changed {
|
||||
if !state.changed && matrix == nil {
|
||||
continue
|
||||
}
|
||||
var output bytes.Buffer
|
||||
steps = 0
|
||||
state = type2State{font: font, args: stack[:0], width: font.def, seed: font.seed + uint64(gid), steps: &steps, output: &output}
|
||||
if matrix != nil {
|
||||
state.matrix, state.widthTarget, state.stripHints = matrix, &type2Font{}, true
|
||||
}
|
||||
if _, err := state.run(program, 0); err != nil {
|
||||
return nil, false, fmt.Errorf("CFF glyph %d: %w", gid, err)
|
||||
}
|
||||
@@ -286,7 +286,11 @@ func (s *type2State) takeWidth(explicit bool) error {
|
||||
s.args = s.args[:len(s.args)-1]
|
||||
}
|
||||
if s.output != nil && !s.component && s.widthTarget != nil && s.width != s.widthTarget.def {
|
||||
return encodeType2Number(s.output, s.width-s.widthTarget.nominal)
|
||||
width := s.width
|
||||
if s.matrix != nil {
|
||||
width *= s.matrix[0]
|
||||
}
|
||||
return encodeType2Number(s.output, width-s.widthTarget.nominal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -420,14 +424,19 @@ func (s *type2State) run(data []byte, depth int) (bool, error) {
|
||||
if !finite(s.x) || !finite(s.y) {
|
||||
return false, fmt.Errorf("invalid Type2 current point")
|
||||
}
|
||||
if s.component {
|
||||
if s.matrix != nil {
|
||||
x, y := s.transformedPoint()
|
||||
if err := s.emit(21, []float64{x - s.outX, y - s.outY}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if s.component {
|
||||
if err := s.emit(21, []float64{s.x + s.originX - s.outX, s.y + s.originY - s.outY}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if err := s.emit(op, s.args); err != nil {
|
||||
return false, err
|
||||
}
|
||||
s.outX, s.outY = s.x+s.originX, s.y+s.originY
|
||||
s.outX, s.outY = s.transformedPoint()
|
||||
s.pathStarted = true
|
||||
s.args = s.args[:0]
|
||||
case 14:
|
||||
@@ -498,7 +507,7 @@ func (s *type2State) appendComponent(code, x, y float64) error {
|
||||
if !ok {
|
||||
return fmt.Errorf("missing Type2 component %s", name)
|
||||
}
|
||||
child := type2State{font: s.font, 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}
|
||||
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}
|
||||
_, err := child.run(s.font.chars[gid], 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid Type2 component %s: %w", name, err)
|
||||
|
||||
Reference in new issue
Block a user