package font
import (
"bytes"
"compress/zlib"
"encoding/binary"
"fmt"
"math"
"sort"
)
var (
SFNT_OFFSET_TAG = 0
SFNT_OFFSET_CHECKSUM = 4
SFNT_OFFSET_OFFSET = 8
SFNT_OFFSET_LENGTH = 12
SFNT_ENTRY_OFFSET_FLAVOR = 0
SFNT_ENTRY_OFFSET_VERSION_MAJ = 4
SFNT_ENTRY_OFFSET_VERSION_MIN = 6
SFNT_ENTRY_OFFSET_CHECKSUM_ADJUSTMENT = 8
WOFF_OFFSET_MAGIC = 0
WOFF_OFFSET_FLAVOR = 4
WOFF_OFFSET_SIZE = 8
WOFF_OFFSET_NUM_TABLES = 12
WOFF_OFFSET_RESERVED = 14
WOFF_OFFSET_SFNT_SIZE = 16
WOFF_OFFSET_VERSION_MAJ = 20
WOFF_OFFSET_VERSION_MIN = 22
WOFF_OFFSET_META_OFFSET = 24
WOFF_OFFSET_META_LENGTH = 28
WOFF_OFFSET_META_ORIG_LENGTH = 32
WOFF_OFFSET_PRIV_OFFSET = 36
WOFF_OFFSET_PRIV_LENGTH = 40
WOFF_ENTRY_OFFSET_TAG = 0
WOFF_ENTRY_OFFSET_OFFSET = 4
WOFF_ENTRY_OFFSET_COMPR_LENGTH = 8
WOFF_ENTRY_OFFSET_LENGTH = 12
WOFF_ENTRY_OFFSET_CHECKSUM = 16
MAGIC_WOFF uint32 = 0x774f4646
MAGIC_CHECKSUM_ADJUSTMENT uint32 = 0xb1b0afba
SIZE_OF_WOFF_HEADER = 44
SIZE_OF_WOFF_ENTRY = 20
SIZE_OF_SFNT_HEADER = 12
SIZE_OF_SFNT_TABLE_ENTRY = 16
)
type TableEntry struct {
Tag []byte
CheckSum uint32
Offset uint32
Length uint32
}
func longAlign(n uint32 ) uint32 {
return (n + 3 ) & ^uint32 (3 )
}
func calcChecksum(buf []byte ) uint32 {
var sum uint32 = 0
var nlongs = len (buf ) / 4
for i := 0 ; i < nlongs ; i ++ {
var t = binary .BigEndian .Uint32 (buf [i *4 :])
sum = sum + t
}
return sum
}
func Sfnt2Woff (fontBuf []byte ) ([]byte , error ) {
numTables := binary .BigEndian .Uint16 (fontBuf [4 :])
woffHeader := make ([]byte , SIZE_OF_WOFF_HEADER )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_MAGIC :], MAGIC_WOFF )
binary .BigEndian .PutUint16 (woffHeader [WOFF_OFFSET_NUM_TABLES :], numTables )
binary .BigEndian .PutUint16 (woffHeader [WOFF_OFFSET_SFNT_SIZE :], 0 )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_META_OFFSET :], 0 )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_META_LENGTH :], 0 )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_META_ORIG_LENGTH :], 0 )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_PRIV_OFFSET :], 0 )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_PRIV_LENGTH :], 0 )
var entries []TableEntry
for i := 0 ; i < int (numTables ); i ++ {
table := fontBuf [SIZE_OF_SFNT_HEADER +i *SIZE_OF_SFNT_TABLE_ENTRY :]
entry := TableEntry {
Tag : table [SFNT_OFFSET_TAG : SFNT_OFFSET_TAG +4 ],
CheckSum : binary .BigEndian .Uint32 (table [SFNT_OFFSET_CHECKSUM :]),
Offset : binary .BigEndian .Uint32 (table [SFNT_OFFSET_OFFSET :]),
Length : binary .BigEndian .Uint32 (table [SFNT_OFFSET_LENGTH :]),
}
entries = append (entries , entry )
}
sort .Slice (entries , func (i , j int ) bool {
return string (entries [i ].Tag ) < string (entries [j ].Tag )
})
sfntSize := uint32 (SIZE_OF_SFNT_HEADER + int (numTables )*SIZE_OF_SFNT_TABLE_ENTRY )
tableInfo := make ([]byte , int (numTables )*SIZE_OF_WOFF_ENTRY )
for i := 0 ; i < len (entries ); i ++ {
tableEntry := entries [i ]
if string (tableEntry .Tag ) != "head" {
alignTable := fontBuf [tableEntry .Offset : tableEntry .Offset +longAlign (tableEntry .Length )]
if calcChecksum (alignTable ) != tableEntry .CheckSum {
return nil , fmt .Errorf ("checksum error in table: %v" , string (tableEntry .Tag ))
}
}
binary .BigEndian .PutUint32 (tableInfo [i *SIZE_OF_WOFF_ENTRY +WOFF_ENTRY_OFFSET_TAG :], binary .BigEndian .Uint32 (tableEntry .Tag ))
binary .BigEndian .PutUint32 (tableInfo [i *SIZE_OF_WOFF_ENTRY +WOFF_ENTRY_OFFSET_LENGTH :], tableEntry .Length )
binary .BigEndian .PutUint32 (tableInfo [i *SIZE_OF_WOFF_ENTRY +WOFF_ENTRY_OFFSET_CHECKSUM :], tableEntry .CheckSum )
sfntSize += longAlign (tableEntry .Length )
}
sfntOffset := uint32 (SIZE_OF_SFNT_HEADER + len (entries )*SIZE_OF_SFNT_TABLE_ENTRY )
csum := calcChecksum (fontBuf [:SIZE_OF_SFNT_HEADER ])
for i := 0 ; i < len (entries ); i ++ {
tableEntry := entries [i ]
b := make ([]byte , SIZE_OF_SFNT_TABLE_ENTRY )
binary .BigEndian .PutUint32 (b [SFNT_OFFSET_TAG :], binary .BigEndian .Uint32 (tableEntry .Tag ))
binary .BigEndian .PutUint32 (b [SFNT_OFFSET_CHECKSUM :], tableEntry .CheckSum )
binary .BigEndian .PutUint32 (b [SFNT_OFFSET_OFFSET :], sfntOffset )
binary .BigEndian .PutUint32 (b [SFNT_OFFSET_LENGTH :], tableEntry .Length )
sfntOffset += longAlign (tableEntry .Length )
csum += calcChecksum (b )
csum += tableEntry .CheckSum
}
var checksumAdjustment = MAGIC_CHECKSUM_ADJUSTMENT - csum
majorVersion := uint16 (0 )
minVersion := uint16 (1 )
flavor := uint32 (0 )
offset := SIZE_OF_WOFF_HEADER + int (numTables )*SIZE_OF_WOFF_ENTRY
var tableBytes []byte
for i := 0 ; i < len (entries ); i ++ {
tableEntry := entries [i ]
sfntData := fontBuf [tableEntry .Offset : tableEntry .Offset +tableEntry .Length ]
if string (tableEntry .Tag ) == "head" {
majorVersion = binary .BigEndian .Uint16 (sfntData [SFNT_ENTRY_OFFSET_VERSION_MAJ :])
minVersion = binary .BigEndian .Uint16 (sfntData [SFNT_ENTRY_OFFSET_VERSION_MIN :])
flavor = binary .BigEndian .Uint32 (sfntData [SFNT_ENTRY_OFFSET_FLAVOR :])
binary .BigEndian .PutUint32 (sfntData [SFNT_ENTRY_OFFSET_CHECKSUM_ADJUSTMENT :], uint32 (checksumAdjustment ))
}
var res bytes .Buffer
w := zlib .NewWriter (&res )
w .Write (sfntData )
w .Flush ()
w .Close ()
compLength := math .Min (float64 (len (res .Bytes ())), float64 (len (sfntData )))
length := longAlign (uint32 (compLength ))
table := make ([]byte , length )
if len (res .Bytes ()) >= len (sfntData ) {
copy (table , sfntData )
} else {
copy (table , res .Bytes ())
}
binary .BigEndian .PutUint32 (tableInfo [i *SIZE_OF_WOFF_ENTRY +WOFF_ENTRY_OFFSET_OFFSET :], uint32 (offset ))
offset += len (table )
binary .BigEndian .PutUint32 (tableInfo [i *SIZE_OF_WOFF_ENTRY +WOFF_ENTRY_OFFSET_COMPR_LENGTH :], uint32 (compLength ))
tableBytes = append (tableBytes , table ...)
}
woffSize := uint32 (len (woffHeader ) + len (tableInfo ) + len (tableBytes ))
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_SIZE :], woffSize )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_SFNT_SIZE :], sfntSize )
binary .BigEndian .PutUint16 (woffHeader [WOFF_OFFSET_VERSION_MAJ :], majorVersion )
binary .BigEndian .PutUint16 (woffHeader [WOFF_OFFSET_VERSION_MIN :], minVersion )
binary .BigEndian .PutUint32 (woffHeader [WOFF_OFFSET_FLAVOR :], flavor )
var out []byte
out = append (out , woffHeader ...)
out = append (out , tableInfo ...)
out = append (out , tableBytes ...)
return out , nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .