如何计算TTF文件的
checksumAdjustment
表中的head
(ms,apple)字段?这是我的计算方法。
package main
import (
"encoding/binary"
"os"
)
func CalcCheckSum(data []byte) uint32 {
var sum uint32
step := 3
for _, c := range data {
sum += uint32(c) << ((step & 3) * 8)
step--
}
return sum
}
func main() {
var bs []byte
bs, _ = os.ReadFile("myFont.ttf")
// Handle TableHeader
// ...
// Handle TableRecord
// ...
var headOffset uint32 // Assume it is provided by `TableRecord["head"].Offset` and it's correct.
binary.BigEndian.PutUint32(bs[headOffset+8:headOffset+12], 0) // 8~12 is checksumAdjustment: https://learn.microsoft.com/en-us/typography/opentype/spec/head
sum := CalcCheckSum(bs)
checksumAdjustment := 0xB1B0AFBA - sum
binary.BigEndian.PutUint32(bs[headOffset+8:headOffset+12], checksumAdjustment)
}
在某些字体中(很抱歉由于许可问题无法提供详细信息),我使用了这种计算方法。当我将生成的字体文件提交到FontVal-2.1.2
进行验证时它抱怨
head.ChecksumAdjustment
计算不正确。我要疯了,请帮助我。
无法直接读取所有数据内容进行计算。
原因:如果有些表需要补零,那么单独做和一次性做会有区别。一次性全部做只会在数据末尾加零,但单独做会检查每条数据以确定是否需要加零,从而产生差异。见下文:
func CalcCheckSum(data []byte) uint32 {
var sum uint32
step := 3
for _, c := range data {
sum += uint32(c) << ((step & 3) * 8)
step--
}
return sum
}
func Test(t *testing.T) {
// Doing it separately
allData := []byte{0x01, 0x03}
v1 := CalcCheckSum(allData) // 0x0103_0000
v2 := CalcCheckSum(allData[0:1]) // 0x0100_0000
v3 := CalcCheckSum(allData[1:]) // 0x0300_0000
fmt.Printf("%08X, %08X, %08X\n", v1, v2, v3)
if v1 != v2+v3 {
fmt.Println("test1")
}
// Doing it all at once. If the data does not need to be padded with zeros, then there is no difference between the two methods.
allData = []byte{1, 2, 3, 4, 5, 6, 7, 8}
v1 = CalcCheckSum(allData) // 0x01020304 + 0x05060708 = 0x0608_0A0C
v2 = CalcCheckSum(allData[0:4]) // 0x01020304
v3 = CalcCheckSum(allData[4:]) // 0x05060708
fmt.Printf("%08X, %08X, %08X\n", v1, v2, v3)
if v1 == v2+v3 {
fmt.Println("test2")
}
// Output:
// test1
// test2
}
所以你应该分开做:
0xB1B0AFBA - CalcCheckSum(bs[:recordsOffset]) + (CalcCheckSum(table1Bytes) + CalcCheckSum(table2Bytes) + ... + CalcCheckSum[tableNBytes])
详细流程如下代码
注意,以下代码假设每个TableRecord的
是正确的。CheckSum
package main
import (
"bytes"
"encoding/binary"
"fmt"
"os"
)
func CalcCheckSum(data []byte) uint32 {
var sum uint32
step := 3
for _, c := range data {
sum += uint32(c) << ((step & 3) * 8)
step--
}
return sum
}
type TableHeader struct {
SFNTVersion uint32
NumTables uint16
SearchRange uint16
EntrySelector uint16
RangeShift uint16
}
type TableRecord struct {
Tag [4]byte
CheckSum uint32
Offset uint32
Length uint32
}
type TTFont struct {
TableHeader
TableRecords []TableRecord
}
func main() {
var bs []byte
var font TTFont
bs, _ = os.ReadFile("test.ttf")
r := bytes.NewReader(bs)
_ = binary.Read(r, binary.BigEndian, &font.TableHeader)
font.TableRecords = make([]TableRecord, font.NumTables)
_ = binary.Read(r, binary.BigEndian, &font.TableRecords)
/*
set head.ChecksumAdjustment = 0
and Compile each table...
update each TableRecords...
*/
var sum uint32
recordsOffset := 12 /*header size*/ + font.NumTables*16
sum += CalcCheckSum(bs[:recordsOffset])
for _, record := range font.TableRecords {
sum += record.CheckSum
}
checksumAdjustment := 0xB1B0AFBA - sum
fmt.Printf("0x%X", checksumAdjustment)
}