mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 14:53:44 +08:00
1 parent
e78ea6f919
commit
3b9f88cbba
16 files changed
+383
-43
No files matched your search
@@ -0,0 +1,122 @@
|
||||
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ofdgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// normalizeCmap 转换旧式双字节子表,保留各编码记录及原字形编号
|
||||
// 入参: data 字符映射表
|
||||
// 返回: []byte 等价字符映射表, error 子表错误
|
||||
func normalizeCmap(data []byte) ([]byte, error) {
|
||||
if len(data) < 4 {
|
||||
return data, nil
|
||||
}
|
||||
count := int(binary.BigEndian.Uint16(data[2:]))
|
||||
if count > (len(data)-4)/8 {
|
||||
return nil, fmt.Errorf("invalid cmap encoding records")
|
||||
}
|
||||
var out []byte
|
||||
converted := make(map[uint32]uint32)
|
||||
for n := 0; n < count; n++ {
|
||||
record := 8 + 8*n
|
||||
offset := binary.BigEndian.Uint32(data[record:])
|
||||
if uint64(offset)+2 > uint64(len(data)) {
|
||||
return nil, fmt.Errorf("invalid cmap subtable offset")
|
||||
}
|
||||
if binary.BigEndian.Uint16(data[offset:]) != 2 {
|
||||
continue
|
||||
}
|
||||
if out == nil {
|
||||
out = bytes.Clone(data)
|
||||
}
|
||||
next, ok := converted[offset]
|
||||
if !ok {
|
||||
mapping, err := parseCmapFormat2(data[offset:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
table := buildCmapTable(0, mapping)
|
||||
subtable := table[binary.BigEndian.Uint32(table[8:]):]
|
||||
language := binary.BigEndian.Uint16(data[offset+4:])
|
||||
if binary.BigEndian.Uint16(subtable) == 12 {
|
||||
binary.BigEndian.PutUint32(subtable[8:], uint32(language))
|
||||
} else {
|
||||
binary.BigEndian.PutUint16(subtable[4:], language)
|
||||
}
|
||||
next = uint32(len(out))
|
||||
converted[offset] = next
|
||||
out = append(out, subtable...)
|
||||
}
|
||||
binary.BigEndian.PutUint32(out[record:], next)
|
||||
}
|
||||
if out == nil {
|
||||
return data, nil
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// parseCmapFormat2 解析混合单字节与双字节字符的子头映射
|
||||
// 入参: data format 2子表
|
||||
// 返回: map[rune]uint16 编码值到字形编号, error 子头或字形数组越界
|
||||
func parseCmapFormat2(data []byte) (map[rune]uint16, error) {
|
||||
if len(data) < 526 {
|
||||
return nil, fmt.Errorf("truncated cmap format 2")
|
||||
}
|
||||
length := int(binary.BigEndian.Uint16(data[2:]))
|
||||
if length < 526 || length > len(data) {
|
||||
return nil, fmt.Errorf("invalid cmap format 2 length")
|
||||
}
|
||||
data = data[:length]
|
||||
maxKey := 0
|
||||
for n := 0; n < 256; n++ {
|
||||
key := int(binary.BigEndian.Uint16(data[6+2*n:]))
|
||||
if key%8 != 0 || 518+key+8 > len(data) {
|
||||
return nil, fmt.Errorf("invalid cmap format 2 subheader")
|
||||
}
|
||||
maxKey = max(maxKey, key)
|
||||
}
|
||||
mapping := make(map[rune]uint16)
|
||||
for high := 0; high < 256; high++ {
|
||||
key := 0
|
||||
if high != 0 {
|
||||
key = int(binary.BigEndian.Uint16(data[6+2*high:]))
|
||||
if key == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
pos := 518 + key
|
||||
first, count := int(binary.BigEndian.Uint16(data[pos:])), int(binary.BigEndian.Uint16(data[pos+2:]))
|
||||
delta := binary.BigEndian.Uint16(data[pos+4:])
|
||||
start := pos + 6 + int(binary.BigEndian.Uint16(data[pos+6:]))
|
||||
if first+count > 256 || count > 0 && (start < 526+maxKey || start+count*2 > len(data)) {
|
||||
return nil, fmt.Errorf("invalid cmap format 2 glyph array")
|
||||
}
|
||||
for n := 0; n < count; n++ {
|
||||
low := first + n
|
||||
if high == 0 && binary.BigEndian.Uint16(data[6+2*low:]) != 0 {
|
||||
continue
|
||||
}
|
||||
glyph := binary.BigEndian.Uint16(data[start+2*n:])
|
||||
if glyph != 0 {
|
||||
mapping[rune(high*256+low)] = glyph + delta
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapping, nil
|
||||
}
|
||||
Reference in new issue
Block a user