如何获取head.ChecksumAdjustment?

问题描述 投票:0回答:1

如何计算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
计算不正确。我要疯了,请帮助我。

go fonts checksum truetype
1个回答
0
投票

无法直接读取所有数据内容进行计算。

原因:如果有些表需要补零,那么单独做和一次性做会有区别。一次性全部做只会在数据末尾加零,但单独做会检查每条数据以确定是否需要加零,从而产生差异。见下文:

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.