def compile(self, ttFont): keys = sorted(self.data.keys()) headerSize = sstruct.calcsize(META_HEADER_FORMAT) dataOffset = headerSize + len(keys) * sstruct.calcsize(DATA_MAP_FORMAT) header = sstruct.pack( META_HEADER_FORMAT, { "version": 1, "flags": 0, "dataOffset": dataOffset, "numDataMaps": len(keys) }) dataMaps = [] dataBlocks = [] for tag in keys: if tag in ["dlng", "slng"]: data = self.data[tag].encode("utf-8") else: data = self.data[tag] dataMaps.append( sstruct.pack(DATA_MAP_FORMAT, { "tag": tag, "dataOffset": dataOffset, "dataLength": len(data) })) dataBlocks.append(data) dataOffset += len(data) return bytesjoin([header] + dataMaps + dataBlocks)
def compile(self, ttFont): keys = sorted(self.data.keys()) headerSize = sstruct.calcsize(META_HEADER_FORMAT) dataOffset = headerSize + len(keys) * sstruct.calcsize(DATA_MAP_FORMAT) header = sstruct.pack(META_HEADER_FORMAT, { "version": 1, "flags": 0, "dataOffset": dataOffset, "numDataMaps": len(keys) }) dataMaps = [] dataBlocks = [] for tag in keys: if tag in ["dlng", "slng"]: data = self.data[tag].encode("utf-8") else: data = self.data[tag] dataMaps.append(sstruct.pack(DATA_MAP_FORMAT, { "tag": tag, "dataOffset": dataOffset, "dataLength": len(data) })) dataBlocks.append(data) dataOffset += len(data) return bytesjoin([header] + dataMaps + dataBlocks)
def decompile(self, data, ttFont): pos = 0 # track current position from to start of VDMX table dummy, data = sstruct.unpack2(VDMX_HeaderFmt, data, self) pos += sstruct.calcsize(VDMX_HeaderFmt) self.ratRanges = [] for i in range(self.numRatios): ratio, data = sstruct.unpack2(VDMX_RatRangeFmt, data) pos += sstruct.calcsize(VDMX_RatRangeFmt) # the mapping between a ratio and a group is defined further below ratio['groupIndex'] = None self.ratRanges.append(ratio) lenOffset = struct.calcsize('>H') _offsets = [] # temporarily store offsets to groups for i in range(self.numRatios): offset = struct.unpack('>H', data[0:lenOffset])[0] data = data[lenOffset:] pos += lenOffset _offsets.append(offset) self.groups = [] for groupIndex in range(self.numRecs): # the offset to this group from beginning of the VDMX table currOffset = pos group, data = sstruct.unpack2(VDMX_GroupFmt, data) # the group lenght and bounding sizes are re-calculated on compile recs = group.pop('recs') startsz = group.pop('startsz') endsz = group.pop('endsz') pos += sstruct.calcsize(VDMX_GroupFmt) for j in range(recs): vTable, data = sstruct.unpack2(VDMX_vTableFmt, data) vTableLength = sstruct.calcsize(VDMX_vTableFmt) pos += vTableLength # group is a dict of (yMax, yMin) tuples keyed by yPelHeight group[vTable['yPelHeight']] = (vTable['yMax'], vTable['yMin']) # make sure startsz and endsz match the calculated values minSize = min(group.keys()) maxSize = max(group.keys()) assert startsz == minSize, \ "startsz (%s) must equal min yPelHeight (%s): group %d" % \ (group.startsz, minSize, groupIndex) assert endsz == maxSize, \ "endsz (%s) must equal max yPelHeight (%s): group %d" % \ (group.endsz, maxSize, groupIndex) self.groups.append(group) # match the defined offsets with the current group's offset for offsetIndex, offsetValue in enumerate(_offsets): # when numRecs < numRatios there can more than one ratio range # sharing the same VDMX group if currOffset == offsetValue: # map the group with the ratio range thas has the same # index as the offset to that group (it took me a while..) self.ratRanges[offsetIndex]['groupIndex'] = groupIndex # check that all ratio ranges have a group for i in range(self.numRatios): ratio = self.ratRanges[i] if ratio['groupIndex'] is None: from fontTools import ttLib raise ttLib.TTLibError( "no group defined for ratRange %d" % i)
def decompile(self, data, ttFont, version=2.0): if version >= 3.0: _, data = sstruct.unpack2(Silf_part1_format_v3, data, self) self.ruleVersion = float( floatToFixedToStr(self.ruleVersion, precisionBits=16)) _, data = sstruct.unpack2(Silf_part1_format, data, self) for jlevel in range(self.numJLevels): j, data = sstruct.unpack2(Silf_justify_format, data, _Object()) self.jLevels.append(j) _, data = sstruct.unpack2(Silf_part2_format, data, self) if self.numCritFeatures: self.critFeatures = struct.unpack_from( ('>%dH' % self.numCritFeatures), data) data = data[self.numCritFeatures * 2 + 1:] (numScriptTag, ) = struct.unpack_from('B', data) if numScriptTag: self.scriptTags = [ struct.unpack("4s", data[x:x + 4])[0].decode("ascii") for x in range(1, 1 + 4 * numScriptTag, 4) ] data = data[1 + 4 * numScriptTag:] (self.lbGID, ) = struct.unpack('>H', data[:2]) if self.numPasses: self.oPasses = struct.unpack(('>%dL' % (self.numPasses + 1)), data[2:6 + 4 * self.numPasses]) data = data[6 + 4 * self.numPasses:] (numPseudo, ) = struct.unpack(">H", data[:2]) for i in range(numPseudo): if version >= 3.0: pseudo = sstruct.unpack(Silf_pseudomap_format, data[8 + 6 * i:14 + 6 * i], _Object()) else: pseudo = sstruct.unpack(Silf_pseudomap_format_h, data[8 + 4 * i:12 + 4 * i], _Object()) self.pMap[pseudo.unicode] = ttFont.getGlyphName(pseudo.nPseudo) data = data[8 + 6 * numPseudo:] currpos = (sstruct.calcsize(Silf_part1_format) + sstruct.calcsize(Silf_justify_format) * self.numJLevels + sstruct.calcsize(Silf_part2_format) + 2 * self.numCritFeatures + 1 + 1 + 4 * numScriptTag + 6 + 4 * self.numPasses + 8 + 6 * numPseudo) if version >= 3.0: currpos += sstruct.calcsize(Silf_part1_format_v3) self.classes = Classes() self.classes.decompile(data, ttFont, version) for i in range(self.numPasses): p = Pass() self.passes.append(p) p.decompile( data[self.oPasses[i] - currpos:self.oPasses[i + 1] - currpos], ttFont, version)
def decompile(self, data, ttFont): headerSize = sstruct.calcsize(META_HEADER_FORMAT) header = sstruct.unpack(META_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 1: raise TTLibError("unsupported 'meta' version %d" % header["version"]) dataMapSize = sstruct.calcsize(DATA_MAP_FORMAT) for i in range(header["numDataMaps"]): dataMapOffset = headerSize + i * dataMapSize dataMap = sstruct.unpack( DATA_MAP_FORMAT, data[dataMapOffset:dataMapOffset + dataMapSize]) tag = dataMap["tag"] offset = dataMap["dataOffset"] self.data[tag] = data[offset:offset + dataMap["dataLength"]]
def decompile(self, data, ttFont): headerSize = sstruct.calcsize(META_HEADER_FORMAT) header = sstruct.unpack(META_HEADER_FORMAT, data[0 : headerSize]) if header["version"] != 1: raise TTLibError("unsupported 'meta' version %d" % header["version"]) dataMapSize = sstruct.calcsize(DATA_MAP_FORMAT) for i in range(header["numDataMaps"]): dataMapOffset = headerSize + i * dataMapSize dataMap = sstruct.unpack( DATA_MAP_FORMAT, data[dataMapOffset : dataMapOffset + dataMapSize]) tag = dataMap["tag"] offset = dataMap["dataOffset"] self.data[tag] = data[offset : offset + dataMap["dataLength"]]
def compile(self, ttFont): header = { "version": 0x00010000, "offsetToData": sstruct.calcsize(FVAR_HEADER_FORMAT), "countSizePairs": 2, "axisCount": len(self.axes), "axisSize": sstruct.calcsize(FVAR_AXIS_FORMAT), "instanceCount": len(self.instances), "instanceSize": sstruct.calcsize(FVAR_INSTANCE_FORMAT) + len(self.axes) * 4 } result = [sstruct.pack(FVAR_HEADER_FORMAT, header)] result.extend([axis.compile() for axis in self.axes]) axisTags = [axis.axisTag for axis in self.axes] result.extend([instance.compile(axisTags) for instance in self.instances]) return bytesjoin(result)
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos:pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos : pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4
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 compile(self, ttFont): instanceSize = sstruct.calcsize(FVAR_INSTANCE_FORMAT) + (len(self.axes) * 4) includePostScriptNames = any(instance.postscriptNameID != 0xFFFF for instance in self.instances) if includePostScriptNames: instanceSize += 2 header = { "version": 0x00010000, "offsetToData": sstruct.calcsize(FVAR_HEADER_FORMAT), "countSizePairs": 2, "axisCount": len(self.axes), "axisSize": sstruct.calcsize(FVAR_AXIS_FORMAT), "instanceCount": len(self.instances), "instanceSize": instanceSize, } result = [sstruct.pack(FVAR_HEADER_FORMAT, header)] result.extend([axis.compile() for axis in self.axes]) axisTags = [axis.axisTag for axis in self.axes] for instance in self.instances: result.append(instance.compile(axisTags, includePostScriptNames)) return bytesjoin(result)
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos : pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4 if pos + 2 <= len(data): self.postscriptNameID = struct.unpack(">H", data[pos : pos + 2])[0] else: self.postscriptNameID = 0xFFFF
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos:pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4 if pos + 2 <= len(data): self.postscriptNameID = struct.unpack(">H", data[pos:pos + 2])[0] else: self.postscriptNameID = 0xFFFF
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): sstruct.unpack2(Silf_hdr_format, data, self) if self.version >= 5.0: (data, self.scheme) = grUtils.decompress(data) sstruct.unpack2(Silf_hdr_format_3, data, self) base = sstruct.calcsize(Silf_hdr_format_3) elif self.version < 3.0: self.numSilf = struct.unpack('>H', data[4:6]) self.scheme = 0 self.compilerVersion = 0 base = 8 else: self.scheme = 0 sstruct.unpack2(Silf_hdr_format_3, data, self) base = sstruct.calcsize(Silf_hdr_format_3) silfoffsets = struct.unpack_from(('>%dL' % self.numSilf), data[base:]) for offset in silfoffsets: s = Silf() self.silfs.append(s) s.decompile(data[offset:], ttFont, self.version)
def decompile(self, data, ttFont, version=2.0): if version >= 3.0 : _, data = sstruct.unpack2(Silf_part1_format_v3, data, self) _, data = sstruct.unpack2(Silf_part1_format, data, self) for jlevel in range(self.numJLevels): j, data = sstruct.unpack2(Silf_justify_format, data, _Object()) self.jLevels.append(j) _, data = sstruct.unpack2(Silf_part2_format, data, self) if self.numCritFeatures: self.critFeatures = struct.unpack_from(('>%dH' % self.numCritFeatures), data) data = data[self.numCritFeatures * 2 + 1:] (numScriptTag,) = struct.unpack_from('B', data) if numScriptTag: self.scriptTags = [struct.unpack("4s", data[x:x+4])[0] for x in range(1, 1 + 4 * numScriptTag, 4)] data = data[1 + 4 * numScriptTag:] (self.lbGID,) = struct.unpack('>H', data[:2]) if self.numPasses: self.oPasses = struct.unpack(('>%dL' % (self.numPasses+1)), data[2:6+4*self.numPasses]) data = data[6 + 4 * self.numPasses:] (numPseudo,) = struct.unpack(">H", data[:2]) for i in range(numPseudo): if version >= 3.0: pseudo = sstruct.unpack(Silf_pseudomap_format, data[8+6*i:14+6*i], _Object()) else: pseudo = sstruct.unpack(Silf_pseudomap_format_h, data[8+4*i:12+4*i], _Object()) self.pMap[pseudo.unicode] = ttFont.getGlyphName(pseudo.nPseudo) data = data[8 + 6 * numPseudo:] currpos = (sstruct.calcsize(Silf_part1_format) + sstruct.calcsize(Silf_justify_format) * self.numJLevels + sstruct.calcsize(Silf_part2_format) + 2 * self.numCritFeatures + 1 + 1 + 4 * numScriptTag + 6 + 4 * self.numPasses + 8 + 6 * numPseudo) if version >= 3.0: currpos += sstruct.calcsize(Silf_part1_format_v3) self.classes = Classes() self.classes.decompile(data, ttFont, version) for i in range(self.numPasses): p = Pass() self.passes.append(p) p.decompile(data[self.oPasses[i]-currpos:self.oPasses[i+1]-currpos], ttFont, version)
def compile(self, ttFont): header = { "version": 0x00010000, "offsetToData": sstruct.calcsize(FVAR_HEADER_FORMAT), "countSizePairs": 2, "axisCount": len(self.axes), "axisSize": sstruct.calcsize(FVAR_AXIS_FORMAT), "instanceCount": len(self.instances), "instanceSize": sstruct.calcsize(FVAR_INSTANCE_FORMAT) + len(self.axes) * 4 } result = [sstruct.pack(FVAR_HEADER_FORMAT, header)] result.extend([axis.compile() for axis in self.axes]) axisTags = [axis.axisTag for axis in self.axes] result.extend( [instance.compile(axisTags) for instance in self.instances]) return bytesjoin(result)
def compile(self, ttFont, base, version=2.0): # build it all up backwards oActions = reduce(lambda a, x: (a[0] + len(x), a[1] + [a[0]]), self.actions + [b""], (0, []))[1] oConstraints = reduce(lambda a, x: (a[0] + len(x), a[1] + [a[0]]), self.ruleConstraints + [b""], (1, []))[1] constraintCode = b"\000" + b"".join(self.ruleConstraints) transes = [] for t in self.stateTrans: if sys.byteorder != "big": t.byteswap() transes.append(t.tobytes()) if sys.byteorder != "big": t.byteswap() if not len(transes): self.startStates = [0] oRuleMap = reduce(lambda a, x: (a[0] + len(x), a[1] + [a[0]]), self.rules + [[]], (0, []))[1] passRanges = [] gidcolmap = dict([(ttFont.getGlyphID(x[0]), x[1]) for x in self.colMap.items()]) for e in grUtils.entries(gidcolmap, sameval=True): if e[1]: passRanges.append((e[0], e[0] + e[1] - 1, e[2][0])) self.numRules = len(self.actions) self.fsmOffset = (sstruct.calcsize(Silf_pass_format) + 8 + len(passRanges) * 6 + len(oRuleMap) * 2 + 2 * oRuleMap[-1] + 2 + 2 * len(self.startStates) + 3 * self.numRules + 3 + 4 * self.numRules + 4) self.pcCode = self.fsmOffset + 2 * self.numTransitional * self.numColumns + 1 + base self.rcCode = self.pcCode + len(self.passConstraints) self.aCode = self.rcCode + len(constraintCode) self.oDebug = 0 # now generate output data = sstruct.pack(Silf_pass_format, self) data += grUtils.bininfo(len(passRanges), 6) data += b"".join(struct.pack(">3H", *p) for p in passRanges) data += struct.pack((">%dH" % len(oRuleMap)), *oRuleMap) flatrules = reduce(lambda a, x: a + x, self.rules, []) data += struct.pack((">%dH" % oRuleMap[-1]), *flatrules) data += struct.pack("BB", self.minRulePreContext, self.maxRulePreContext) data += struct.pack((">%dH" % len(self.startStates)), *self.startStates) data += struct.pack((">%dH" % self.numRules), *self.ruleSortKeys) data += struct.pack(("%dB" % self.numRules), *self.rulePreContexts) data += struct.pack(">BH", self.collisionThreshold, len(self.passConstraints)) data += struct.pack((">%dH" % (self.numRules + 1)), *oConstraints) data += struct.pack((">%dH" % (self.numRules + 1)), *oActions) return data + b"".join(transes) + struct.pack("B", 0) + \ self.passConstraints + constraintCode + b"".join(self.actions)
def _getOffsets(self): """ Calculate offsets to VDMX_Group records. For each ratRange return a list of offset values from the beginning of the VDMX table to a VDMX_Group. """ lenHeader = sstruct.calcsize(VDMX_HeaderFmt) lenRatRange = sstruct.calcsize(VDMX_RatRangeFmt) lenOffset = struct.calcsize('>H') lenGroupHeader = sstruct.calcsize(VDMX_GroupFmt) lenVTable = sstruct.calcsize(VDMX_vTableFmt) # offset to the first group pos = lenHeader + self.numRatios*lenRatRange + self.numRatios*lenOffset groupOffsets = [] for group in self.groups: groupOffsets.append(pos) lenGroup = lenGroupHeader + len(group) * lenVTable pos += lenGroup # offset to next group offsets = [] for ratio in self.ratRanges: groupIndex = ratio['groupIndex'] offsets.append(groupOffsets[groupIndex]) return offsets
def compile(self, ttFont, version=2.0): self.numPasses = len(self.passes) self.numJLevels = len(self.jLevels) self.numCritFeatures = len(self.critFeatures) numPseudo = len(self.pMap) data = b"" if version >= 3.0: hdroffset = sstruct.calcsize(Silf_part1_format_v3) else: hdroffset = 0 data += sstruct.pack(Silf_part1_format, self) for j in self.jLevels: data += sstruct.pack(Silf_justify_format, j) data += sstruct.pack(Silf_part2_format, self) if self.numCritFeatures: data += struct.pack((">%dH" % self.numCritFeaturs), *self.critFeatures) data += struct.pack("BB", 0, len(self.scriptTags)) if len(self.scriptTags): tdata = [ struct.pack("4s", x.encode("ascii")) for x in self.scriptTags ] data += b"".join(tdata) data += struct.pack(">H", self.lbGID) self.passOffset = len(data) data1 = grUtils.bininfo(numPseudo, 6) currpos = hdroffset + len(data) + 4 * (self.numPasses + 1) self.pseudosOffset = currpos + len(data1) for u, p in sorted(self.pMap.items()): data1 += struct.pack((">LH" if version >= 3.0 else ">HH"), u, ttFont.getGlyphID(p)) data1 += self.classes.compile(ttFont, version) currpos += len(data1) data2 = b"" datao = b"" for i, p in enumerate(self.passes): base = currpos + len(data2) datao += struct.pack(">L", base) data2 += p.compile(ttFont, base, version) datao += struct.pack(">L", currpos + len(data2)) if version >= 3.0: data3 = sstruct.pack(Silf_part1_format_v3, self) else: data3 = b"" return data3 + data + datao + data1 + data2
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) majorVersion = header["majorVersion"] if majorVersion != 1: raise TTLibError("unsupported 'avar' version %d" % majorVersion) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos+2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos+4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 0x00010000: raise TTLibError("unsupported 'avar' version %04x" % header["version"]) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos+2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos+4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4 self.fixupSegments_(warn=warnings.warn)
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) majorVersion = header["majorVersion"] if majorVersion != 1: raise TTLibError("unsupported 'avar' version %d" % majorVersion) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos + 2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos + 4]) segments[fi2fl(fromValue, 14)] = fi2fl(toValue, 14) pos = pos + 4
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, version=2.0): self.numPasses = len(self.passes) self.numJLevels = len(self.jLevels) self.numCritFeatures = len(self.critFeatures) numPseudo = len(self.pMap) data = b"" if version >= 3.0: hdroffset = sstruct.calcsize(Silf_part1_format_v3) else: hdroffset = 0 data += sstruct.pack(Silf_part1_format, self) for j in self.jLevels: data += sstruct.pack(Silf_justify_format, j) data += sstruct.pack(Silf_part2_format, self) if self.numCritFeatures: data += struct.pack((">%dH" % self.numCritFeaturs), *self.critFeatures) data += struct.pack("BB", 0, len(self.scriptTags)) if len(self.scriptTags): tdata = [struct.pack("4s", x) for x in self.scriptTags] data += "".join(tdata) data += struct.pack(">H", self.lbGID) self.passOffset = len(data) data1 = grUtils.bininfo(numPseudo, 6) currpos = hdroffset + len(data) + 4 * (self.numPasses + 1) self.pseudosOffset = currpos + len(data1) for u, p in sorted(self.pMap.items()): data1 += struct.pack((">LH" if version >= 3.0 else ">HH"), u, ttFont.getGlyphID(p)) data1 += self.classes.compile(ttFont, version) currpos += len(data1) data2 = b"" datao = b"" for i, p in enumerate(self.passes): base = currpos + len(data2) datao += struct.pack(">L", base) data2 += p.compile(ttFont, base, version) datao += struct.pack(">L", currpos + len(data2)) if version >= 3.0: data3 = sstruct.pack(Silf_part1_format_v3, self) else: data3 = b"" return data3 + data + datao + data1 + data2
def compile(self, ttFont, base, version=2.0): # build it all up backwards oActions = reduce(lambda a, x: (a[0]+len(x), a[1]+[a[0]]), self.actions + [b""], (0, []))[1] oConstraints = reduce(lambda a, x: (a[0]+len(x), a[1]+[a[0]]), self.ruleConstraints + [b""], (1, []))[1] constraintCode = b"\000" + b"".join(self.ruleConstraints) transes = [] for t in self.stateTrans: if sys.byteorder != "big": t.byteswap() transes.append(t.tostring()) if sys.byteorder != "big": t.byteswap() if not len(transes): self.startStates = [0] oRuleMap = reduce(lambda a, x: (a[0]+len(x), a[1]+[a[0]]), self.rules+[[]], (0, []))[1] passRanges = [] gidcolmap = dict([(ttFont.getGlyphID(x[0]), x[1]) for x in self.colMap.items()]) for e in grUtils.entries(gidcolmap, sameval = True): if e[1]: passRanges.append((e[0], e[0]+e[1]-1, e[2][0])) self.numRules = len(self.actions) self.fsmOffset = (sstruct.calcsize(Silf_pass_format) + 8 + len(passRanges) * 6 + len(oRuleMap) * 2 + 2 * oRuleMap[-1] + 2 + 2 * len(self.startStates) + 3 * self.numRules + 3 + 4 * self.numRules + 4) self.pcCode = self.fsmOffset + 2*self.numTransitional*self.numColumns + 1 + base self.rcCode = self.pcCode + len(self.passConstraints) self.aCode = self.rcCode + len(constraintCode) self.oDebug = 0 # now generate output data = sstruct.pack(Silf_pass_format, self) data += grUtils.bininfo(len(passRanges), 6) data += b"".join(struct.pack(">3H", *p) for p in passRanges) data += struct.pack((">%dH" % len(oRuleMap)), *oRuleMap) flatrules = reduce(lambda a,x: a+x, self.rules, []) data += struct.pack((">%dH" % oRuleMap[-1]), *flatrules) data += struct.pack("BB", self.minRulePreContext, self.maxRulePreContext) data += struct.pack((">%dH" % len(self.startStates)), *self.startStates) data += struct.pack((">%dH" % self.numRules), *self.ruleSortKeys) data += struct.pack(("%dB" % self.numRules), *self.rulePreContexts) data += struct.pack(">BH", self.collisionThreshold, len(self.passConstraints)) data += struct.pack((">%dH" % (self.numRules+1)), *oConstraints) data += struct.pack((">%dH" % (self.numRules+1)), *oActions) return data + b"".join(transes) + struct.pack("B", 0) + \ self.passConstraints + constraintCode + b"".join(self.actions)
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 0x00010000: raise TTLibError("unsupported 'avar' version %04x" % header["version"]) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos + 2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos + 4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4 self.fixupSegments_()
def decompile(self, data, ttFont): header = {} headerSize = sstruct.calcsize(FVAR_HEADER_FORMAT) header = sstruct.unpack(FVAR_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 0x00010000: raise TTLibError("unsupported 'fvar' version %04x" % header["version"]) pos = header["offsetToData"] axisSize = header["axisSize"] for _ in range(header["axisCount"]): axis = Axis() axis.decompile(data[pos:pos+axisSize]) self.axes.append(axis) pos += axisSize instanceSize = header["instanceSize"] axisTags = [axis.axisTag for axis in self.axes] for _ in range(header["instanceCount"]): instance = NamedInstance() instance.decompile(data[pos:pos+instanceSize], axisTags) self.instances.append(instance) pos += instanceSize
def decompile(self, data, ttFont): header = {} headerSize = sstruct.calcsize(FVAR_HEADER_FORMAT) header = sstruct.unpack(FVAR_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 0x00010000: raise TTLibError("unsupported 'fvar' version %04x" % header["version"]) pos = header["offsetToData"] axisSize = header["axisSize"] for _ in range(header["axisCount"]): axis = Axis() axis.decompile(data[pos : pos + axisSize]) self.axes.append(axis) pos += axisSize instanceSize = header["instanceSize"] axisTags = [axis.axisTag for axis in self.axes] for _ in range(header["instanceCount"]): instance = NamedInstance() instance.decompile(data[pos : pos + instanceSize], axisTags) self.instances.append(instance) pos += instanceSize
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 if offset % 2: # Pad to even bytes data.append(b'\0') return bytesjoin(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.__lt__() stringData = b"" 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 name.string in done: 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
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.__lt__() stringData = b"" 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 name.string in done: 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
from collections.abc import Sequence from dataclasses import dataclass, astuple from io import BytesIO import struct import logging log = logging.getLogger(__name__) SVG_format_0 = """ > # big endian version: H offsetToSVGDocIndex: L reserved: L """ SVG_format_0Size = sstruct.calcsize(SVG_format_0) doc_index_entry_format_0 = """ > # big endian startGlyphID: H endGlyphID: H svgDocOffset: L svgDocLength: L """ doc_index_entry_format_0Size = sstruct.calcsize(doc_index_entry_format_0) class table_S_V_G_(DefaultTable.DefaultTable): def decompile(self, data, ttFont): self.docList = []
the number of <colorParamUINameID> elements. """ 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
sbixStrikeHeaderFormat = """ > ppem: H # The PPEM for which this strike was designed (e.g., 9, # 12, 24) resolution: H # The screen resolution (in dpi) for which this strike # was designed (e.g., 72) """ sbixGlyphDataOffsetFormat = """ > glyphDataOffset: L # Offset from the beginning of the strike data record # to data for the individual glyph """ sbixStrikeHeaderFormatSize = sstruct.calcsize(sbixStrikeHeaderFormat) sbixGlyphDataOffsetFormatSize = sstruct.calcsize(sbixGlyphDataOffsetFormat) class Strike(object): def __init__(self, rawdata=None, ppem=0, resolution=72): self.data = rawdata self.ppem = ppem self.resolution = resolution self.glyphs = {} def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise ttLib.TTLibError if len(self.data) < sbixStrikeHeaderFormatSize:
from fontTools.misc.textTools import safeEval from fontTools.misc.encodingTools import getEncoding from . import DefaultTable import struct 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. Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset)) stringData = data[stringOffset:] data = data[6:] self.names = [] for i in range(n): if len(data) < 12:
import logging log = logging.getLogger(__name__) # Apple's documentation of 'avar': # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6avar.html AVAR_HEADER_FORMAT = """ > # big endian majorVersion: H minorVersion: H reserved: H axisCount: H """ assert sstruct.calcsize(AVAR_HEADER_FORMAT) == 8, sstruct.calcsize(AVAR_HEADER_FORMAT) class table__a_v_a_r(DefaultTable.DefaultTable): dependencies = ["fvar"] def __init__(self, tag=None): DefaultTable.DefaultTable.__init__(self, tag) self.segments = {} def compile(self, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = { "majorVersion": 1, "minorVersion": 0,
# -- 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
return absNameOffset = reader.absNameListOffset + self.nameOffset nameLength, = struct.unpack('B', reader._read(1, absNameOffset)) name, = struct.unpack('>%ss' % nameLength, reader._read(nameLength)) self.name = tostr(name, encoding='mac-roman') ResourceForkHeader = """ > # big endian dataOffset: L mapOffset: L dataLen: L mapLen: L """ ResourceForkHeaderSize = sstruct.calcsize(ResourceForkHeader) ResourceMapHeader = """ > # big endian attr: H typeListOffset: H nameListOffset: H """ ResourceMapHeaderSize = sstruct.calcsize(ResourceMapHeader) ResourceTypeItem = """ > # big endian type: 4s numRes: H refListOffset: H
import array 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) elif self.formatType == 4.0: self.decode_format_4_0(data, ttFont) else:
except ImportError: from UserDict import DictMixin as MutableMapping # Apple's documentation of 'trak': # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html TRAK_HEADER_FORMAT = """ > # big endian version: 16.16F format: H horizOffset: H vertOffset: H reserved: H """ TRAK_HEADER_FORMAT_SIZE = sstruct.calcsize(TRAK_HEADER_FORMAT) TRACK_DATA_FORMAT = """ > # big endian nTracks: H nSizes: H sizeTableOffset: L """ TRACK_DATA_FORMAT_SIZE = sstruct.calcsize(TRACK_DATA_FORMAT) TRACK_TABLE_ENTRY_FORMAT = """ > # big endian track: 16.16F nameIndex: H offset: H
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
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 = list(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 bytesjoin(dataList)
from fontTools.misc import sstruct from fontTools.misc.textTools import safeEval from . import DefaultTable import struct 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. Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset)) stringData = data[stringOffset:] data = data[6:] self.names = [] for i in range(n):
sbixGlyphHeaderFormat = """ > originOffsetX: h # The x-value of the point in the glyph relative to its # lower-left corner which corresponds to the origin of # the glyph on the screen, that is the point on the # baseline at the left edge of the glyph. originOffsetY: h # The y-value of the point in the glyph relative to its # lower-left corner which corresponds to the origin of # the glyph on the screen, that is the point on the # baseline at the left edge of the glyph. graphicType: 4s # e.g. "png " """ sbixGlyphHeaderFormatSize = sstruct.calcsize(sbixGlyphHeaderFormat) class Glyph(object): def __init__(self, glyphName=None, referenceGlyphName=None, originOffsetX=0, originOffsetY=0, graphicType=None, imageData=None, rawdata=None, gid=0): self.gid = gid self.glyphName = glyphName self.referenceGlyphName = referenceGlyphName self.originOffsetX = originOffsetX self.originOffsetY = originOffsetY self.rawdata = rawdata self.graphicType = graphicType self.imageData = imageData # fix self.graphicType if it is null terminated or too short if self.graphicType is not None:
from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * from fontTools.misc import sstruct from fontTools.misc.textTools import readHex import struct 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 def decompile(self, ttFont): self.glyphName = ttFont.getGlyphName(self.gid) if self.rawdata is None:
# FreeType2 source code for parsing 'gvar': # http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/truetype/ttgxvar.c GVAR_HEADER_FORMAT = """ > # big endian version: H reserved: H axisCount: H sharedTupleCount: H offsetToSharedTuples: I glyphCount: H flags: H offsetToGlyphVariationData: I """ GVAR_HEADER_SIZE = sstruct.calcsize(GVAR_HEADER_FORMAT) class table__g_v_a_r(DefaultTable.DefaultTable): dependencies = ["fvar", "glyf"] def __init__(self, tag=None): DefaultTable.DefaultTable.__init__(self, tag) self.version, self.reserved = 1, 0 self.variations = {} def compile(self, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] sharedTuples = tv.compileSharedTuples( axisTags, itertools.chain(*self.variations.values())) sharedTupleIndices = {coord:i for i, coord in enumerate(sharedTuples)}
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 _ 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 = list(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 bytesjoin(dataList)
> # 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
import struct import logging log = logging.getLogger(__name__) # Apple's documentation of 'avar': # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6avar.html AVAR_HEADER_FORMAT = """ > # big endian majorVersion: H minorVersion: H reserved: H axisCount: H """ assert sstruct.calcsize(AVAR_HEADER_FORMAT) == 8, sstruct.calcsize( AVAR_HEADER_FORMAT) class table__a_v_a_r(DefaultTable.DefaultTable): dependencies = ["fvar"] def __init__(self, tag=None): DefaultTable.DefaultTable.__init__(self, tag) self.segments = {} def compile(self, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = { "majorVersion": 1,
sfntVersion: 4s length: L # total woff2 file size numTables: H # number of tables reserved: H # set to 0 totalSfntSize: L # uncompressed size totalCompressedSize: L # compressed size majorVersion: H # major version of WOFF file minorVersion: H # minor version of WOFF file metaOffset: L # offset to metadata block metaLength: L # length of compressed metadata metaOrigLength: L # length of uncompressed metadata privOffset: L # offset to private data block privLength: L # length of private data block """ woff2DirectorySize = sstruct.calcsize(woff2DirectoryFormat) woff2KnownTags = ("cmap", "head", "hhea", "hmtx", "maxp", "name", "OS/2", "post", "cvt ", "fpgm", "glyf", "loca", "prep", "CFF ", "VORG", "EBDT", "EBLC", "gasp", "hdmx", "kern", "LTSH", "PCLT", "VDMX", "vhea", "vmtx", "BASE", "GDEF", "GPOS", "GSUB", "EBSC", "JSTF", "MATH", "CBDT", "CBLC", "COLR", "CPAL", "SVG ", "sbix", "acnt", "avar", "bdat", "bloc", "bsln", "cvar", "fdsc", "feat", "fmtx", "fvar", "gvar", "hsty", "just", "lcar", "mort", "morx", "opbd", "prop", "trak", "Zapf", "Silf", "Glat", "Gloc", "Feat", "Sill") woff2FlagsFormat = """ > # big endian flags: B # table type and flags """
# FreeType2 source code for parsing 'gvar': # http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/truetype/ttgxvar.c GVAR_HEADER_FORMAT = """ > # big endian version: H reserved: H axisCount: H sharedCoordCount: H offsetToCoord: I glyphCount: H flags: H offsetToData: I """ GVAR_HEADER_SIZE = sstruct.calcsize(GVAR_HEADER_FORMAT) TUPLES_SHARE_POINT_NUMBERS = 0x8000 TUPLE_COUNT_MASK = 0x0fff EMBEDDED_TUPLE_COORD = 0x8000 INTERMEDIATE_TUPLE = 0x4000 PRIVATE_POINT_NUMBERS = 0x2000 TUPLE_INDEX_MASK = 0x0fff DELTAS_ARE_ZERO = 0x80 DELTAS_ARE_WORDS = 0x40 DELTA_RUN_COUNT_MASK = 0x3f POINTS_ARE_WORDS = 0x80 POINT_RUN_COUNT_MASK = 0x7f