def __init__(self, refNum): self.__fileName = array.array("c", "\0" * 64) sstruct.unpack(_FCBPBFormat, "\0" * sstruct.calcsize(_FCBPBFormat), self) self.ioNamePtr = self.__fileName.buffer_info()[0] self.ioRefNum = refNum self.ioVRefNum = GetVRefNum(refNum) self.__haveInfo = 0
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) # workarounds for buggy fonts (Apple, mona) if not data: self.version = 0 elif len(data) == sstruct.calcsize(OS2_format_1_addition): self.version = 1 elif len(data) == sstruct.calcsize(OS2_format_2_addition): if self.version not in (2, 3, 4): self.version = 1 else: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % (self.version, len(data)) if self.version == 1: sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version <> 0: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) # workarounds for buggy fonts (Apple, mona) if not data: self.version = 0 elif len(data) == sstruct.calcsize(OS2_format_1_addition): self.version = 1 elif len(data) == sstruct.calcsize(OS2_format_2_addition): if self.version not in (2, 3, 4): self.version = 1 else: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % ( self.version, len(data)) if self.version == 1: sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version <> 0: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def compile(self, ttFont): packed = sstruct.pack(DSIG_HeaderFormat, self) headers = [packed] offset = len(packed) + self.usNumSigs * sstruct.calcsize(DSIG_SignatureFormat) data = [] for sigrec in self.signatureRecords: # first pack signature block sigrec.cbSignature = len(sigrec.pkcs7) packed = sstruct.pack(DSIG_SignatureBlockFormat, sigrec) + sigrec.pkcs7 data.append(packed) # update redundant length field sigrec.ulLength = len(packed) # update running table offset sigrec.ulOffset = offset headers.append(sstruct.pack(DSIG_SignatureFormat, sigrec)) offset += sigrec.ulLength return ''.join(headers+data)
def compile(self, ttFont): packed = sstruct.pack(DSIG_HeaderFormat, self) headers = [packed] offset = len(packed) + self.usNumSigs * sstruct.calcsize(DSIG_SignatureFormat) data = [] for sigrec in self.signatureRecords: # first pack signature block sigrec.cbSignature = len(sigrec.pkcs7) packed = sstruct.pack(DSIG_SignatureBlockFormat, sigrec) + sigrec.pkcs7 data.append(packed) # update redundant length field sigrec.ulLength = len(packed) # update running table offset sigrec.ulOffset = offset headers.append(sstruct.pack(DSIG_SignatureFormat, sigrec)) offset += sigrec.ulLength return "".join(headers + data)
def compile(self, ttFont): if not hasattr(self, "names"): # only happens when there are NO name table entries read # from the TTX file self.names = [] self.names.sort() # sort according to the spec; see NameRecord.__cmp__() stringData = "" format = 0 n = len(self.names) stringOffset = 6 + n * sstruct.calcsize(nameRecordFormat) data = struct.pack(">HHH", format, n, stringOffset) lastoffset = 0 done = {} # remember the data so we can reuse the "pointers" for name in self.names: if done.has_key(name.string): name.offset, name.length = done[name.string] else: name.offset, name.length = done[name.string] = len(stringData), len(name.string) stringData = stringData + name.string data = data + sstruct.pack(nameRecordFormat, name) return data + stringData
> # big endian signature: 4s flavor: 4s length: L numTables: H reserved: H totalSFNTSize: L majorVersion: H minorVersion: H metaOffset: L metaLength: L metaOrigLength: L privOffset: L privLength: L """ woffHeaderSize = sstruct.calcsize(woffHeaderFormat) class WOFFReader(object): def __init__(self, file, checkChecksums=1): self.file = file self.checkChecksums = checkChecksums # unpack the header self.file.seek(0) bytes = self.file.read(woffHeaderSize) if len(bytes) != woffHeaderSize: raise WOFFLibError("Not a properly formatted WOFF file.") sstruct.unpack(woffHeaderFormat, bytes, self) if self.signature != "wOFF": raise WOFFLibError("Not a properly formatted WOFF file.") # unpack the directory
from types import TupleType postFormat = """ > formatType: 16.16F italicAngle: 16.16F # italic angle in degrees underlinePosition: h underlineThickness: h isFixedPitch: L minMemType42: L # minimum memory if TrueType font is downloaded maxMemType42: L # maximum memory if TrueType font is downloaded minMemType1: L # minimum memory if Type1 font is downloaded maxMemType1: L # maximum memory if Type1 font is downloaded """ postFormatSize = sstruct.calcsize(postFormat) class table__p_o_s_t(DefaultTable.DefaultTable): def decompile(self, data, ttFont): sstruct.unpack(postFormat, data[:postFormatSize], self) data = data[postFormatSize:] if self.formatType == 1.0: self.decode_format_1_0(data, ttFont) elif self.formatType == 2.0: self.decode_format_2_0(data, ttFont) elif self.formatType == 3.0: self.decode_format_3_0(data, ttFont) else: # supported format raise ttLib.TTLibError, "'post' table format %f not supported" % self.formatType
import struct, sstruct from fontTools.misc.textTools import safeEval import string import types nameRecordFormat = """ > # big endian platformID: H platEncID: H langID: H nameID: H length: H offset: H """ nameRecordSize = sstruct.calcsize(nameRecordFormat) class table__n_a_m_e(DefaultTable.DefaultTable): def decompile(self, data, ttFont): format, n, stringOffset = struct.unpack(">HHH", data[:6]) expectedStringOffset = 6 + n * nameRecordSize if stringOffset != expectedStringOffset: # XXX we need a warn function print "Warning: 'name' table stringOffset incorrect.", print "Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset) stringData = data[stringOffset:] data = data[6:] self.names = [] for i in range(n):
postFormat = """ > formatType: 16.16F italicAngle: 16.16F # italic angle in degrees underlinePosition: h underlineThickness: h isFixedPitch: L minMemType42: L # minimum memory if TrueType font is downloaded maxMemType42: L # maximum memory if TrueType font is downloaded minMemType1: L # minimum memory if Type1 font is downloaded maxMemType1: L # maximum memory if Type1 font is downloaded """ postFormatSize = sstruct.calcsize(postFormat) class table__p_o_s_t(DefaultTable.DefaultTable): def decompile(self, data, ttFont): sstruct.unpack(postFormat, data[:postFormatSize], self) data = data[postFormatSize:] if self.formatType == 1.0: self.decode_format_1_0(data, ttFont) elif self.formatType == 2.0: self.decode_format_2_0(data, ttFont) elif self.formatType == 3.0: self.decode_format_3_0(data, ttFont) else: # supported format
> # big endian fontType: h # font type firstChar: h # ASCII code of first character lastChar: h # ASCII code of last character widMax: h # maximum character width kernMax: h # negative of maximum character kern nDescent: h # negative of descent fRectWidth: h # width of font rectangle fRectHeight: h # height of font rectangle owTLoc: H # offset to offset/width table (in words from _this_ point) ascent: h # ascent descent: h # descent leading: h # leading rowWords: h # row width of bit image / 2 """ headerSize = sstruct.calcsize(nfntHeaderFormat) assert headerSize == 26 class NFNT: def __init__(self, data=None): if data is not None: self.decompile(data) def decompile(self, data): # header; FontRec sstruct.unpack(nfntHeaderFormat, data[:headerSize], self) # assert self.fRectHeight == (self.ascent + self.descent) # rest
from sbixBitmap import * # from fontTools.misc.textTools import hexStr sbixBitmapSetHeaderFormat = """ > size: H # 00 28 resolution: H # 00 48 """ sbixBitmapOffsetEntryFormat = """ > ulOffset: L # 00 00 07 E0 # Offset from start of first offset entry to each bitmap """ sbixBitmapSetHeaderFormatSize = sstruct.calcsize(sbixBitmapSetHeaderFormat) sbixBitmapOffsetEntryFormatSize = sstruct.calcsize(sbixBitmapOffsetEntryFormat) class BitmapSet(object): def __init__(self, rawdata=None, size=0, resolution=72): self.data = rawdata self.size = size self.resolution = resolution self.bitmaps = {} def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise (ttLib.TTLibError, "No table data to decompile.")
def compile(self, ttFont): dataList = [] self.numSizes = len(self.strikes) dataList.append(sstruct.pack(eblcHeaderFormat, self)) # Data size of the header + bitmapSizeTable needs to be calculated # in order to form offsets. This value will hold the size of the data # in dataList after all the data is consolidated in dataList. dataSize = len(dataList[0]) # The table will be structured in the following order: # (0) header # (1) Each bitmapSizeTable [1 ... self.numSizes] # (2) Alternate between indexSubTableArray and indexSubTable # for each bitmapSizeTable present. # # The issue is maintaining the proper offsets when table information # gets moved around. All offsets and size information must be recalculated # when building the table to allow editing within ttLib and also allow easy # import/export to and from XML. All of this offset information is lost # when exporting to XML so everything must be calculated fresh so importing # from XML will work cleanly. Only byte offset and size information is # calculated fresh. Count information like numberOfIndexSubTables is # checked through assertions. If the information in this table was not # touched or was changed properly then these types of values should match. # # The table will be rebuilt the following way: # (0) Precompute the size of all the bitmapSizeTables. This is needed to # compute the offsets properly. # (1) For each bitmapSizeTable compute the indexSubTable and # indexSubTableArray pair. The indexSubTable must be computed first # so that the offset information in indexSubTableArray can be # calculated. Update the data size after each pairing. # (2) Build each bitmapSizeTable. # (3) Consolidate all the data into the main dataList in the correct order. for curStrike in self.strikes: dataSize += sstruct.calcsize(bitmapSizeTableFormatPart1) dataSize += len( ('hori', 'vert')) * sstruct.calcsize(sbitLineMetricsFormat) dataSize += sstruct.calcsize(bitmapSizeTableFormatPart2) indexSubTablePairDataList = [] for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable curTable.numberOfIndexSubTables = len(curStrike.indexSubTables) curTable.indexSubTableArrayOffset = dataSize # Precompute the size of the indexSubTableArray. This information # is important for correctly calculating the new value for # additionalOffsetToIndexSubtable. sizeOfSubTableArray = curTable.numberOfIndexSubTables * indexSubTableArraySize lowerBound = dataSize dataSize += sizeOfSubTableArray upperBound = dataSize indexSubTableDataList = [] for indexSubTable in curStrike.indexSubTables: indexSubTable.additionalOffsetToIndexSubtable = dataSize - curTable.indexSubTableArrayOffset glyphIds = map(ttFont.getGlyphID, indexSubTable.names) indexSubTable.firstGlyphIndex = min(glyphIds) indexSubTable.lastGlyphIndex = max(glyphIds) data = indexSubTable.compile(ttFont) indexSubTableDataList.append(data) dataSize += len(data) curTable.startGlyphIndex = min(ist.firstGlyphIndex for ist in curStrike.indexSubTables) curTable.endGlyphIndex = max(ist.lastGlyphIndex for ist in curStrike.indexSubTables) for i in curStrike.indexSubTables: data = struct.pack(indexSubHeaderFormat, i.firstGlyphIndex, i.lastGlyphIndex, i.additionalOffsetToIndexSubtable) indexSubTablePairDataList.append(data) indexSubTablePairDataList.extend(indexSubTableDataList) curTable.indexTablesSize = dataSize - curTable.indexSubTableArrayOffset for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable data = sstruct.pack(bitmapSizeTableFormatPart1, curTable) dataList.append(data) for metric in ('hori', 'vert'): metricObj = vars(curTable)[metric] data = sstruct.pack(sbitLineMetricsFormat, metricObj) dataList.append(data) data = sstruct.pack(bitmapSizeTableFormatPart2, curTable) dataList.append(data) dataList.extend(indexSubTablePairDataList) return string.join(dataList, "")
import string import types import re XML = ET.XML XMLElement = ET.Element xmlToString = ET.tostring SVG_format_0 = """ > # big endian version: H offsetToSVGDocIndex: L offsetToColorPalettes: L """ SVG_format_0Size = sstruct.calcsize(SVG_format_0) SVG_format_1 = """ > # big endian version: H numIndicies: H """ SVG_format_1Size = sstruct.calcsize(SVG_format_1) doc_index_entry_format_0 = """ > # big endian startGlyphID: H endGlyphID: H svgDocOffset: L svgDocLength: L
import struct, sstruct from fontTools.misc.textTools import readHex sbixBitmapHeaderFormat = """ > usReserved1: H # 00 00 usReserved2: H # 00 00 imageFormatTag: 4s # e.g. "png " """ sbixBitmapHeaderFormatSize = sstruct.calcsize(sbixBitmapHeaderFormat) class Bitmap(object): def __init__( self, glyphName=None, referenceGlyphName=None, usReserved1=0, usReserved2=0, imageFormatTag=None, imageData=None, rawdata=None, gid=0, ): self.gid = gid self.glyphName = glyphName self.referenceGlyphName = referenceGlyphName self.usReserved1 = usReserved1 self.usReserved2 = usReserved2 self.rawdata = rawdata
# -- sfnt directory helpers and cruft ttcHeaderFormat = """ > # big endian TTCTag: 4s # "ttcf" Version: L # 0x00010000 or 0x00020000 numFonts: L # number of fonts # OffsetTable[numFonts]: L # array with offsets from beginning of file # ulDsigTag: L # version 2.0 only # ulDsigLength: L # version 2.0 only # ulDsigOffset: L # version 2.0 only """ ttcHeaderSize = sstruct.calcsize(ttcHeaderFormat) sfntDirectoryFormat = """ > # big endian sfntVersion: 4s numTables: H # number of tables searchRange: H # (max2 <= numTables)*16 entrySelector: H # log2(max2 <= numTables) rangeShift: H # numTables*16-searchRange """ sfntDirectorySize = sstruct.calcsize(sfntDirectoryFormat) sfntDirectoryEntryFormat = """ > # big endian tag: 4s
bitmap: ULONG reserved 00 00 00 00 char[4] format data type, e.g. "png " (Variable) bitmap data """ sbixHeaderFormat = """ > usVal1: H # 00 01 usVal2: H # 00 01 numSets: L # 00 00 00 02 # number of bitmap sets """ sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat) sbixBitmapSetOffsetFormat = """ > offset: L # 00 00 00 10 # offset from table start to each bitmap set """ sbixBitmapSetOffsetFormatSize = sstruct.calcsize(sbixBitmapSetOffsetFormat) class table__s_b_i_x(DefaultTable.DefaultTable): def __init__(self, tag): self.tableTag = tag self.usVal1 = 1 self.usVal2 = 1 self.numSets = 0 self.bitmapSets = {}
def compile(self, ttFont): dataList = [] self.numSizes = len(self.strikes) dataList.append(sstruct.pack(eblcHeaderFormat, self)) # Data size of the header + bitmapSizeTable needs to be calculated # in order to form offsets. This value will hold the size of the data # in dataList after all the data is consolidated in dataList. dataSize = len(dataList[0]) # The table will be structured in the following order: # (0) header # (1) Each bitmapSizeTable [1 ... self.numSizes] # (2) Alternate between indexSubTableArray and indexSubTable # for each bitmapSizeTable present. # # The issue is maintaining the proper offsets when table information # gets moved around. All offsets and size information must be recalculated # when building the table to allow editing within ttLib and also allow easy # import/export to and from XML. All of this offset information is lost # when exporting to XML so everything must be calculated fresh so importing # from XML will work cleanly. Only byte offset and size information is # calculated fresh. Count information like numberOfIndexSubTables is # checked through assertions. If the information in this table was not # touched or was changed properly then these types of values should match. # # The table will be rebuilt the following way: # (0) Precompute the size of all the bitmapSizeTables. This is needed to # compute the offsets properly. # (1) For each bitmapSizeTable compute the indexSubTable and # indexSubTableArray pair. The indexSubTable must be computed first # so that the offset information in indexSubTableArray can be # calculated. Update the data size after each pairing. # (2) Build each bitmapSizeTable. # (3) Consolidate all the data into the main dataList in the correct order. for curStrike in self.strikes: dataSize += sstruct.calcsize(bitmapSizeTableFormatPart1) dataSize += len(('hori', 'vert')) * sstruct.calcsize(sbitLineMetricsFormat) dataSize += sstruct.calcsize(bitmapSizeTableFormatPart2) indexSubTablePairDataList = [] for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable curTable.numberOfIndexSubTables = len(curStrike.indexSubTables) curTable.indexSubTableArrayOffset = dataSize # Precompute the size of the indexSubTableArray. This information # is important for correctly calculating the new value for # additionalOffsetToIndexSubtable. sizeOfSubTableArray = curTable.numberOfIndexSubTables * indexSubTableArraySize lowerBound = dataSize dataSize += sizeOfSubTableArray upperBound = dataSize indexSubTableDataList = [] for indexSubTable in curStrike.indexSubTables: indexSubTable.additionalOffsetToIndexSubtable = dataSize - curTable.indexSubTableArrayOffset glyphIds = map(ttFont.getGlyphID, indexSubTable.names) indexSubTable.firstGlyphIndex = min(glyphIds) indexSubTable.lastGlyphIndex = max(glyphIds) data = indexSubTable.compile(ttFont) indexSubTableDataList.append(data) dataSize += len(data) curTable.startGlyphIndex = min(ist.firstGlyphIndex for ist in curStrike.indexSubTables) curTable.endGlyphIndex = max(ist.lastGlyphIndex for ist in curStrike.indexSubTables) for i in curStrike.indexSubTables: data = struct.pack(indexSubHeaderFormat, i.firstGlyphIndex, i.lastGlyphIndex, i.additionalOffsetToIndexSubtable) indexSubTablePairDataList.append(data) indexSubTablePairDataList.extend(indexSubTableDataList) curTable.indexTablesSize = dataSize - curTable.indexSubTableArrayOffset for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable data = sstruct.pack(bitmapSizeTableFormatPart1, curTable) dataList.append(data) for metric in ('hori', 'vert'): metricObj = vars(curTable)[metric] data = sstruct.pack(sbitLineMetricsFormat, metricObj) dataList.append(data) data = sstruct.pack(bitmapSizeTableFormatPart2, curTable) dataList.append(data) dataList.extend(indexSubTablePairDataList) return string.join(dataList, "")
from . import DefaultTable import struct, sstruct from fontTools.misc.textTools import safeEval import string nameRecordFormat = """ > # big endian platformID: H platEncID: H langID: H nameID: H length: H offset: H """ nameRecordSize = sstruct.calcsize(nameRecordFormat) class table__n_a_m_e(DefaultTable.DefaultTable): def decompile(self, data, ttFont): format, n, stringOffset = struct.unpack(">HHH", data[:6]) expectedStringOffset = 6 + n * nameRecordSize if stringOffset != expectedStringOffset: # XXX we need a warn function print("Warning: 'name' table stringOffset incorrect.", end=' ') print("Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset)) stringData = data[stringOffset:] data = data[6:] self.names = [] for i in range(n):
bitmap: ULONG reserved 00 00 00 00 char[4] format data type, e.g. "png " (Variable) bitmap data """ sbixHeaderFormat = """ > usVal1: H # 00 01 usVal2: H # 00 01 numSets: L # 00 00 00 02 # number of bitmap sets """ sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat) sbixBitmapSetOffsetFormat = """ > offset: L # 00 00 00 10 # offset from table start to each bitmap set """ sbixBitmapSetOffsetFormatSize = sstruct.calcsize(sbixBitmapSetOffsetFormat) class table__s_b_i_x(DefaultTable.DefaultTable): def __init__(self, tag): self.tableTag = tag self.usVal1 = 1 self.usVal2 = 1 self.numSets = 0
import struct, sstruct from fontTools.misc.textTools import readHex sbixBitmapHeaderFormat = """ > usReserved1: H # 00 00 usReserved2: H # 00 00 imageFormatTag: 4s # e.g. "png " """ sbixBitmapHeaderFormatSize = sstruct.calcsize(sbixBitmapHeaderFormat) class Bitmap(object): def __init__(self, glyphName=None, referenceGlyphName=None, usReserved1=0, usReserved2=0, imageFormatTag=None, imageData=None, rawdata=None, gid=0): self.gid = gid self.glyphName = glyphName self.referenceGlyphName = referenceGlyphName self.usReserved1 = usReserved1 self.usReserved2 = usReserved2 self.rawdata = rawdata self.imageFormatTag = imageFormatTag self.imageData = imageData