def decompile(self, data, ttFont): # Get the version but don't advance the slice. # Most of the lookup for this table is done relative # to the begining so slice by the offsets provided # in the EBLC table. sstruct.unpack2(ebdtTableVersionFormat, data, self) # Keep a dict of glyphs that have been seen so they aren't remade. # This dict maps intervals of data to the BitmapGlyph. glyphDict = {} # Pull out the EBLC table and loop through glyphs. # A strike is a concept that spans both tables. # The actual bitmap data is stored in the EBDT. locator = ttFont[self.__class__.locatorName] self.strikeData = [] for curStrike in locator.strikes: bitmapGlyphDict = {} self.strikeData.append(bitmapGlyphDict) for indexSubTable in curStrike.indexSubTables: dataIter = zip(indexSubTable.names, indexSubTable.locations) for curName, curLoc in dataIter: # Don't create duplicate data entries for the same glyphs. # Instead just use the structures that already exist if they exist. if curLoc in glyphDict: curGlyph = glyphDict[curLoc] else: curGlyphData = data[slice(*curLoc)] imageFormatClass = self.getImageFormatClass(indexSubTable.imageFormat) curGlyph = imageFormatClass(curGlyphData, ttFont) glyphDict[curLoc] = curGlyph bitmapGlyphDict[curName] = curGlyph
def decompile_format_0(self, data, ttFont): dummy, data2 = sstruct.unpack2(SVG_format_0, data, self) # read in SVG Documents Index self.decompileEntryList(data) # read in colorPalettes table. self.colorPalettes = colorPalettes = ColorPalettes() pos = self.offsetToColorPalettes if pos > 0: colorPalettes.numColorParams = numColorParams = struct.unpack(">H", data[pos:pos+2])[0] if numColorParams > 0: colorPalettes.colorParamUINameIDs = colorParamUINameIDs = [] pos = pos + 2 for i in range(numColorParams): nameID = struct.unpack(">H", data[pos:pos+2])[0] colorParamUINameIDs.append(nameID) pos = pos + 2 colorPalettes.numColorPalettes = numColorPalettes = struct.unpack(">H", data[pos:pos+2])[0] pos = pos + 2 if numColorPalettes > 0: colorPalettes.colorPaletteList = colorPaletteList = [] for i in range(numColorPalettes): colorPalette = ColorPalette() colorPaletteList.append(colorPalette) colorPalette.uiNameID = struct.unpack(">H", data[pos:pos+2])[0] pos = pos + 2 colorPalette.paletteColors = paletteColors = [] for j in range(numColorParams): colorRecord, colorPaletteData = sstruct.unpack2(colorRecord_format_0, data[pos:], ColorRecord()) paletteColors.append(colorRecord) pos += 4
def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(METAHeaderFormat, data, self) self.glyphRecords = [] for i in range(self.nMetaRecs): glyphRecord, newData = sstruct.unpack2(METAGlyphRecordFormat, newData, GlyphRecord()) if self.metaFlags == 0: [glyphRecord.offset] = struct.unpack(">H", newData[:2]) newData = newData[2:] elif self.metaFlags == 1: [glyphRecord.offset] = struct.unpack(">H", newData[:4]) newData = newData[4:] else: assert 0, "The metaFlags field in the META table header has a value other than 0 or 1 :" + str( self.metaFlags) glyphRecord.stringRecs = [] newData = data[glyphRecord.offset:] for j in range(glyphRecord.nMetaEntry): stringRec, newData = sstruct.unpack2(METAStringRecordFormat, newData, StringRecord()) if self.metaFlags == 0: [stringRec.offset] = struct.unpack(">H", newData[:2]) newData = newData[2:] else: [stringRec.offset] = struct.unpack(">H", newData[:4]) newData = newData[4:] stringRec.string = data[stringRec.offset:stringRec.offset + stringRec.stringLen] glyphRecord.stringRecs.append(stringRec) self.glyphRecords.append(glyphRecord)
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 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): (self.imageSize,) = struct.unpack(">L", self.data[:4]) self.metrics = BigGlyphMetrics() sstruct.unpack2(bigGlyphMetricsFormat, self.data[4:], self.metrics) glyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex+1)) offsets = [self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds)+1)] self.locations = list(zip(offsets, offsets[1:])) self.names = list(map(self.ttFont.getGlyphName, glyphIds))
def decompile(self): (self.imageSize,) = struct.unpack(">L", self.data[:4]) self.metrics = BigGlyphMetrics() sstruct.unpack2(bigGlyphMetricsFormat, self.data[4:], self.metrics) glyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex+1)) offsets = [self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds)+1)] self.locations = list(zip(offsets, offsets[1:])) self.names = list(map(self.ttFont.getGlyphName, glyphIds)) del self.data, self.ttFont
def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(GMAPFormat, data, self) self.psFontName = tostr(newData[:self.fontNameLength]) assert (self.recordsOffset % 4) == 0, "GMAP error: recordsOffset is not 32 bit aligned." newData = data[self.recordsOffset:] self.gmapRecords = [] for i in range (self.recordsCount): gmapRecord, newData = sstruct.unpack2(GMAPRecordFormat1, newData, GMAPRecord()) gmapRecord.name = gmapRecord.name.strip('\0') self.gmapRecords.append(gmapRecord)
def decompile(self, data, ttFont): # Save the original data because offsets are from the start of the table. origData = data i = 0 dummy = sstruct.unpack(eblcHeaderFormat, data[:8], self) i += 8 self.strikes = [] for curStrikeIndex in range(self.numSizes): curStrike = Strike() self.strikes.append(curStrike) curTable = curStrike.bitmapSizeTable dummy = sstruct.unpack2(bitmapSizeTableFormatPart1, data[i:i + 16], curTable) i += 16 for metric in ('hori', 'vert'): metricObj = SbitLineMetrics() vars(curTable)[metric] = metricObj dummy = sstruct.unpack2(sbitLineMetricsFormat, data[i:i + 12], metricObj) i += 12 dummy = sstruct.unpack(bitmapSizeTableFormatPart2, data[i:i + 8], curTable) i += 8 for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable for subtableIndex in range(curTable.numberOfIndexSubTables): i = curTable.indexSubTableArrayOffset + subtableIndex * indexSubTableArraySize tup = struct.unpack(indexSubTableArrayFormat, data[i:i + indexSubTableArraySize]) (firstGlyphIndex, lastGlyphIndex, additionalOffsetToIndexSubtable) = tup i = curTable.indexSubTableArrayOffset + additionalOffsetToIndexSubtable tup = struct.unpack(indexSubHeaderFormat, data[i:i + indexSubHeaderSize]) (indexFormat, imageFormat, imageDataOffset) = tup indexFormatClass = self.getIndexFormatClass(indexFormat) indexSubTable = indexFormatClass(data[i + indexSubHeaderSize:], ttFont) indexSubTable.firstGlyphIndex = firstGlyphIndex indexSubTable.lastGlyphIndex = lastGlyphIndex indexSubTable.additionalOffsetToIndexSubtable = additionalOffsetToIndexSubtable indexSubTable.indexFormat = indexFormat indexSubTable.imageFormat = imageFormat indexSubTable.imageDataOffset = imageDataOffset indexSubTable.decompile( ) # https://github.com/fonttools/fonttools/issues/317 curStrike.indexSubTables.append(indexSubTable)
def decompile(self): self.metrics = BigGlyphMetrics() dummy, data = sstruct.unpack2(bigGlyphMetricsFormat, self.data, self.metrics) (numComponents,) = struct.unpack(">H", data[:2]) data = data[2:] self.componentArray = [] for i in range(numComponents): curComponent = EbdtComponent() dummy, data = sstruct.unpack2(ebdtComponentFormat, data, curComponent) curComponent.name = self.ttFont.getGlyphName(curComponent.glyphCode) self.componentArray.append(curComponent)
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, 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 decompileAttributes3(self, data): if self.hasOctaboxes: o, data = sstruct.unpack2(Glat_format_3_octabox_metrics, data, _Object()) numsub = bin(o.subboxBitmap).count("1") o.subboxes = [] for b in range(numsub): if len(data) >= 8 : subbox, data = sstruct.unpack2(Glat_format_3_subbox_entry, data, _Object()) o.subboxes.append(subbox) attrs = self.decompileAttributes12(data, Glat_format_23_entry) if self.hasOctaboxes: attrs.octabox = o return attrs
def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(DSIG_HeaderFormat, data, self) assert self.ulVersion == 1, "DSIG ulVersion must be 1" assert self.usFlag & ~1 == 0, "DSIG usFlag must be 0x1 or 0x0" self.signatureRecords = sigrecs = [] for n in range(self.usNumSigs): sigrec, newData = sstruct.unpack2(DSIG_SignatureFormat, newData, SignatureRecord()) assert sigrec.ulFormat == 1, "DSIG signature record #%d ulFormat must be 1" % n sigrecs.append(sigrec) for sigrec in sigrecs: dummy, newData = sstruct.unpack2(DSIG_SignatureBlockFormat, data[sigrec.ulOffset:], sigrec) assert sigrec.usReserved1 == 0, "DSIG signature record #%d usReserverd1 must be 0" % n assert sigrec.usReserved2 == 0, "DSIG signature record #%d usReserverd2 must be 0" % n sigrec.pkcs7 = newData[:sigrec.cbSignature]
def decompile(self, data, ttFont): # Save the original data because offsets are from the start of the table. origData = data dummy, data = sstruct.unpack2(eblcHeaderFormat, data, self) self.strikes = [] for curStrikeIndex in range(self.numSizes): curStrike = Strike() self.strikes.append(curStrike) curTable = curStrike.bitmapSizeTable dummy, data = sstruct.unpack2(bitmapSizeTableFormatPart1, data, curTable) for metric in ('hori', 'vert'): metricObj = SbitLineMetrics() vars(curTable)[metric] = metricObj dummy, data = sstruct.unpack2(sbitLineMetricsFormat, data, metricObj) dummy, data = sstruct.unpack2(bitmapSizeTableFormatPart2, data, curTable) for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable for subtableIndex in range(curTable.numberOfIndexSubTables): lowerBound = curTable.indexSubTableArrayOffset + subtableIndex * indexSubTableArraySize upperBound = lowerBound + indexSubTableArraySize data = origData[lowerBound:upperBound] tup = struct.unpack(indexSubTableArrayFormat, data) (firstGlyphIndex, lastGlyphIndex, additionalOffsetToIndexSubtable) = tup offsetToIndexSubTable = curTable.indexSubTableArrayOffset + additionalOffsetToIndexSubtable data = origData[offsetToIndexSubTable:] tup = struct.unpack(indexSubHeaderFormat, data[:indexSubHeaderSize]) (indexFormat, imageFormat, imageDataOffset) = tup indexFormatClass = self.getIndexFormatClass(indexFormat) indexSubTable = indexFormatClass(data[indexSubHeaderSize:], ttFont) indexSubTable.firstGlyphIndex = firstGlyphIndex indexSubTable.lastGlyphIndex = lastGlyphIndex indexSubTable.additionalOffsetToIndexSubtable = additionalOffsetToIndexSubtable indexSubTable.indexFormat = indexFormat indexSubTable.imageFormat = imageFormat indexSubTable.imageDataOffset = imageDataOffset curStrike.indexSubTables.append(indexSubTable)
def decompileEntryList(self, data): # data starts with the first entry of the entry list. pos = subTableStart = self.offsetToSVGDocIndex self.numEntries = numEntries = struct.unpack(">H", data[pos:pos+2])[0] pos += 2 if self.numEntries > 0: data2 = data[pos:] self.docList = [] self.entries = entries = [] for i in range(self.numEntries): docIndexEntry, data2 = sstruct.unpack2(doc_index_entry_format_0, data2, DocumentIndexEntry()) entries.append(docIndexEntry) for entry in entries: start = entry.svgDocOffset + subTableStart end = start + entry.svgDocLength doc = data[start:end] if doc.startswith(b"\x1f\x8b"): import gzip bytesIO = BytesIO(doc) with gzip.GzipFile(None, "r", fileobj=bytesIO) as gunzipper: doc = gunzipper.read() self.compressed = True del bytesIO doc = tostr(doc, "utf_8") self.docList.append( [doc, entry.startGlyphID, entry.endGlyphID] )
def decompile(self, data, ttFont): format, n, stringOffset = struct.unpack(b">HHH", data[:6]) expectedStringOffset = 6 + n * nameRecordSize if stringOffset != expectedStringOffset: log.error( "'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: log.error('skipping malformed name record #%d', i) continue name, data = sstruct.unpack2(nameRecordFormat, data, NameRecord()) name.string = stringData[name.offset:name.offset+name.length] if name.offset + name.length > len(stringData): log.error('skipping malformed name record #%d', i) continue assert len(name.string) == name.length #if (name.platEncID, name.platformID) in ((0, 0), (1, 3)): # if len(name.string) % 2: # print "2-byte string doesn't have even length!" # print name.__dict__ del name.offset, name.length self.names.append(name)
def decompile(self, data, ttFont, version=2.0): sstruct.unpack2(Silf_classmap_format, data, self) if version >= 4.0 : oClasses = struct.unpack((">%dL" % (self.numClass+1)), data[4:8+4*self.numClass]) else: oClasses = struct.unpack((">%dH" % (self.numClass+1)), data[4:6+2*self.numClass]) for s,e in zip(oClasses[:self.numLinear], oClasses[1:self.numLinear+1]): self.linear.append(ttFont.getGlyphName(x) for x in struct.unpack((">%dH" % ((e-s)/2)), data[s:e])) for s,e in zip(oClasses[self.numLinear:self.numClass], oClasses[self.numLinear+1:self.numClass+1]): nonLinids = [struct.unpack(">HH", data[x:x+4]) for x in range(s+8, e, 4)] nonLin = dict([(ttFont.getGlyphName(x[0]), x[1]) for x in nonLinids]) self.nonLinear.append(nonLin)
def decompile(self, data, ttFont): (_, data) = sstruct.unpack2(Feat_hdr_format, data, self) numFeats, = struct.unpack('>H', data[:2]) data = data[8:] allfeats = [] maxsetting = 0 for i in range(numFeats): if self.version >= 2.0: (fid, nums, _, offset, flags, lid) = struct.unpack(">LHHLHH", data[16 * i:16 * (i + 1)]) offset = int((offset - 12 - 16 * numFeats) / 4) else: (fid, nums, offset, flags, lid) = struct.unpack(">HHLHH", data[12 * i:12 * (i + 1)]) offset = int((offset - 12 - 12 * numFeats) / 4) allfeats.append((fid, nums, offset, flags, lid)) maxsetting = max(maxsetting, offset + nums) data = data[16 * numFeats:] allsettings = [] for i in range(maxsetting): if len(data) >= 4 * (i + 1): (val, lid) = struct.unpack(">HH", data[4 * i:4 * (i + 1)]) allsettings.append((val, lid)) for f in allfeats: (fid, nums, offset, flags, lid) = f fobj = Feature() fobj.flags = flags fobj.label = lid self.features[grUtils.num2tag(fid)] = fobj fobj.settings = {} for i in range(offset, offset + nums): if i >= len(allsettings): continue (vid, vlid) = allsettings[i] fobj.settings[vid] = vlid
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: # compensate for buggy font break name, data = sstruct.unpack2(nameRecordFormat, data, NameRecord()) name.string = stringData[name.offset : name.offset + name.length] assert len(name.string) == name.length # if (name.platEncID, name.platformID) in ((0, 0), (1, 3)): # if len(name.string) % 2: # print "2-byte string doesn't have even length!" # print name.__dict__ del name.offset, name.length self.names.append(name)
def decompile(self, data, ttFont): dummy, rest = sstruct.unpack2(headFormat, data, self) if rest: # this is quite illegal, but there seem to be fonts out there that do this log.warning("extra bytes at the end of 'head' table") assert rest == "\0\0" # For timestamp fields, ignore the top four bytes. Some fonts have # bogus values there. Since till 2038 those bytes only can be zero, # ignore them. # # https://github.com/behdad/fonttools/issues/99#issuecomment-66776810 for stamp in 'created', 'modified': value = getattr(self, stamp) if value > 0xFFFFFFFF: log.warning("'%s' timestamp out of range; ignoring top bytes", stamp) value &= 0xFFFFFFFF setattr(self, stamp, value) if value < 0x7C259DC0: # January 1, 1970 00:00:00 log.warning( "'%s' timestamp seems very low; regarding as unix timestamp", stamp) value += 0x7C259DC0 setattr(self, stamp, value)
def _decodeBBox(self, glyphID, glyph): haveBBox = bool(self.bboxBitmap[glyphID >> 3] & (0x80 >> (glyphID & 7))) if glyph.isComposite() and not haveBBox: raise TTLibError('no bbox values for composite glyph %d' % glyphID) if haveBBox: dummy, self.bboxStream = sstruct.unpack2(bboxFormat, self.bboxStream, glyph) else: glyph.recalcBounds(self)
def decompile(self, data, ttFont): # Save the original data because offsets are from the start of the table. origData = data i = 0; dummy = sstruct.unpack(eblcHeaderFormat, data[:8], self) i += 8; self.strikes = [] for curStrikeIndex in range(self.numSizes): curStrike = Strike() self.strikes.append(curStrike) curTable = curStrike.bitmapSizeTable dummy = sstruct.unpack2(bitmapSizeTableFormatPart1, data[i:i+16], curTable) i += 16 for metric in ('hori', 'vert'): metricObj = SbitLineMetrics() vars(curTable)[metric] = metricObj dummy = sstruct.unpack2(sbitLineMetricsFormat, data[i:i+12], metricObj) i += 12 dummy = sstruct.unpack(bitmapSizeTableFormatPart2, data[i:i+8], curTable) i += 8 for curStrike in self.strikes: curTable = curStrike.bitmapSizeTable for subtableIndex in range(curTable.numberOfIndexSubTables): i = curTable.indexSubTableArrayOffset + subtableIndex * indexSubTableArraySize tup = struct.unpack(indexSubTableArrayFormat, data[i:i+indexSubTableArraySize]) (firstGlyphIndex, lastGlyphIndex, additionalOffsetToIndexSubtable) = tup i = curTable.indexSubTableArrayOffset + additionalOffsetToIndexSubtable tup = struct.unpack(indexSubHeaderFormat, data[i:i+indexSubHeaderSize]) (indexFormat, imageFormat, imageDataOffset) = tup indexFormatClass = self.getIndexFormatClass(indexFormat) indexSubTable = indexFormatClass(data[i+indexSubHeaderSize:], ttFont) indexSubTable.firstGlyphIndex = firstGlyphIndex indexSubTable.lastGlyphIndex = lastGlyphIndex indexSubTable.additionalOffsetToIndexSubtable = additionalOffsetToIndexSubtable indexSubTable.indexFormat = indexFormat indexSubTable.imageFormat = imageFormat indexSubTable.imageDataOffset = imageDataOffset indexSubTable.decompile() # https://github.com/behdad/fonttools/issues/317 curStrike.indexSubTables.append(indexSubTable)
def decompile(self): self.metrics = BigGlyphMetrics() dummy, data = sstruct.unpack2(bigGlyphMetricsFormat, self.data, self.metrics) (dataLen,) = struct.unpack(">L", data[:4]) data = data[4:] # For the image data cut it to the size specified by dataLen. assert dataLen <= len(data), "Data overun in format 18" self.imageData = data[:dataLen]
def decompile(self, data, ttFont): sstruct.unpack2(Glat_format_0, data, self) if self.version <= 1.9: decoder = partial(self.decompileAttributes12,fmt=Glat_format_1_entry) elif self.version <= 2.9: decoder = partial(self.decompileAttributes12,fmt=Glat_format_23_entry) elif self.version >= 3.0: (data, self.scheme) = grUtils.decompress(data) sstruct.unpack2(Glat_format_3, data, self) self.hasOctaboxes = (self.compression & 1) == 1 decoder = self.decompileAttributes3 gloc = ttFont['Gloc'] self.attributes = {} count = 0 for s,e in zip(gloc,gloc[1:]): self.attributes[ttFont.getGlyphName(count)] = decoder(data[s:e]) count += 1
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) if self.version == 1: dummy, data = sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): dummy, data = sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version == 5: dummy, data = sstruct.unpack2(OS2_format_5_addition, data, self) self.usLowerOpticalPointSize /= 20 self.usUpperOpticalPointSize /= 20 elif self.version != 0: from fontTools import ttLib raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version) if len(data): log.warning("too much 'OS/2' table data") self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def decompile(self, data, ttFont, version=2.0): _, data = sstruct.unpack2(Silf_pass_format, data, self) (numRange, _, _, _) = struct.unpack(">4H", data[:8]) data = data[8:] for i in range(numRange): (first, last, col) = struct.unpack(">3H", data[6 * i:6 * i + 6]) for g in range(first, last + 1): self.colMap[ttFont.getGlyphName(g)] = col data = data[6 * numRange:] oRuleMap = struct.unpack_from((">%dH" % (self.numSuccess + 1)), data) data = data[2 + 2 * self.numSuccess:] rules = struct.unpack_from((">%dH" % oRuleMap[-1]), data) self.rules = [rules[s:e] for (s, e) in zip(oRuleMap, oRuleMap[1:])] data = data[2 * oRuleMap[-1]:] (self.minRulePreContext, self.maxRulePreContext) = struct.unpack('BB', data[:2]) numStartStates = self.maxRulePreContext - self.minRulePreContext + 1 self.startStates = struct.unpack((">%dH" % numStartStates), data[2:2 + numStartStates * 2]) data = data[2 + numStartStates * 2:] self.ruleSortKeys = struct.unpack((">%dH" % self.numRules), data[:2 * self.numRules]) data = data[2 * self.numRules:] self.rulePreContexts = struct.unpack(("%dB" % self.numRules), data[:self.numRules]) data = data[self.numRules:] (self.collisionThreshold, pConstraint) = struct.unpack(">BH", data[:3]) oConstraints = list( struct.unpack((">%dH" % (self.numRules + 1)), data[3:5 + self.numRules * 2])) data = data[5 + self.numRules * 2:] oActions = list( struct.unpack((">%dH" % (self.numRules + 1)), data[:2 + self.numRules * 2])) data = data[2 * self.numRules + 2:] for i in range(self.numTransitional): a = array( "H", data[i * self.numColumns * 2:(i + 1) * self.numColumns * 2]) a.byteswap() self.stateTrans.append(a) data = data[self.numTransitional * self.numColumns * 2 + 1:] self.passConstraints = data[:pConstraint] data = data[pConstraint:] for i in range(len(oConstraints) - 2, -1, -1): if oConstraints[i] == 0: oConstraints[i] = oConstraints[i + 1] self.ruleConstraints = [(data[s:e] if (e - s > 1) else "") for (s, e) in zip(oConstraints, oConstraints[1:])] data = data[oConstraints[-1]:] for i in range(len(oActions) - 2, -1, -1): if oActions[i] == 0: oActions[i] = oActions[i + 1] self.actions = [(data[s:e] if (e - s > 1) else "") for (s, e) in zip(oActions, oActions[1:])] data = data[oActions[-1]:]
def decompileAttributes12(self, data, fmt): attributes = _Dict() while len(data) > 3: e, data = sstruct.unpack2(fmt, data, _Object()) keys = range(e.attNum, e.attNum + e.num) if len(data) >= 2 * e.num: vals = struct.unpack_from(('>%dh' % e.num), data) attributes.update(zip(keys, vals)) data = data[2 * e.num:] return attributes
def decompileAttributes12(self, data, fmt): attributes = _Dict() while len(data) > 3: e, data = sstruct.unpack2(fmt, data, _Object()) keys = range(e.attNum, e.attNum+e.num) if len(data) >= 2 * e.num : vals = struct.unpack_from(('>%dh' % e.num), data) attributes.update(zip(keys,vals)) data = data[2*e.num:] return attributes
def decompile(self, data, ttFont): _, data = sstruct.unpack2(Gloc_header, data, self) flags = self.flags; del self.flags self.locations = array.array('I' if flags & 1 else 'H') self.locations.fromstring(data[:len(data)-self.numAttribs*(flags & 2)]) self.locations.byteswap() self.attribIds = array.array('H') if flags & 2: self.attribIds.fromstring(data[-self.numAttribs*2:]) self.attribIds.byteswap()
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): numGlyphs = ttFont['maxp'].numGlyphs glyphOrder = ttFont.getGlyphOrder() dummy, data = sstruct.unpack2(hdmxHeaderFormat, data, self) self.hdmx = {} for i in range(self.numRecords): ppem = byteord(data[0]) maxSize = byteord(data[1]) widths = _GlyphnamedList(ttFont.getReverseGlyphMap(), array.array("B", data[2:2+numGlyphs])) self.hdmx[ppem] = widths data = data[self.recordSize:] assert len(data) == 0, "too much hdmx data"
def decompile(self, data, ttFont): dummy, rest = sstruct.unpack2(SINGFormat, data, self) self.uniqueName = self.decompileUniqueName(self.uniqueName) self.nameLength = byteord(self.nameLength) assert len(rest) == self.nameLength self.baseGlyphName = tostr(rest) rawMETAMD5 = self.METAMD5 self.METAMD5 = "[" + hex(byteord(self.METAMD5[0])) for char in rawMETAMD5[1:]: self.METAMD5 = self.METAMD5 + ", " + hex(byteord(char)) self.METAMD5 = self.METAMD5 + "]"
def decompile(self): self.origDataLen = 0 (self.imageSize,) = struct.unpack(">L", self.data[:4]) data = self.data[4:] self.metrics, data = sstruct.unpack2(bigGlyphMetricsFormat, data, BigGlyphMetrics()) (numGlyphs,) = struct.unpack(">L", data[:4]) data = data[4:] glyphIds = [struct.unpack(">H", data[2*i:2*(i+1)])[0] for i in range(numGlyphs)] offsets = [self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds)+1)] self.locations = list(zip(offsets, offsets[1:])) self.names = list(map(self.ttFont.getGlyphName, glyphIds))
def decompile(self, data, ttFont): _, data = sstruct.unpack2(Gloc_header, data, self) flags = self.flags del self.flags self.locations = array.array('I' if flags & 1 else 'H') self.locations.fromstring(data[:len(data) - self.numAttribs * (flags & 2)]) if sys.byteorder != "big": self.locations.byteswap() self.attribIds = array.array('H') if flags & 2: self.attribIds.fromstring(data[-self.numAttribs * 2:]) if sys.byteorder != "big": self.attribIds.byteswap()
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 decompile(self): self.origDataLen = 0 (self.imageSize,) = struct.unpack(">L", self.data[:4]) data = self.data[4:] self.metrics, data = sstruct.unpack2(bigGlyphMetricsFormat, data, BigGlyphMetrics()) (numGlyphs,) = struct.unpack(">L", data[:4]) data = data[4:] glyphIds = [struct.unpack(">H", data[2*i:2*(i+1)])[0] for i in range(numGlyphs)] offsets = [self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds)+1)] self.locations = list(zip(offsets, offsets[1:])) self.names = list(map(self.ttFont.getGlyphName, glyphIds)) del self.data, self.ttFont
def fromString(self, data): if len(data) < 1: raise TTLibError("can't read table 'flags': not enough data") dummy, data = sstruct.unpack2(woff2FlagsFormat, data, self) if self.flags & 0x3F == 0x3F: # if bits [0..5] of the flags byte == 63, read a 4-byte arbitrary tag value if len(data) < woff2UnknownTagSize: raise TTLibError("can't read table 'tag': not enough data") dummy, data = sstruct.unpack2(woff2UnknownTagFormat, data, self) else: # otherwise, tag is derived from a fixed 'Known Tags' table self.tag = woff2KnownTags[self.flags & 0x3F] self.tag = Tag(self.tag) self.origLength, data = unpackBase128(data) self.length = self.origLength if self.transformed: self.length, data = unpackBase128(data) if self.tag == 'loca' and self.length != 0: raise TTLibError( "the transformLength of the 'loca' table must be 0") # return left over data return data
def expand(self, glyfTable): if not hasattr(self, "data"): # already unpacked return if not self.data: # empty char self.numberOfContours = 0 return dummy, data = sstruct.unpack2(glyphHeaderFormat, self.data, self) del self.data if self.isComposite(): self.decompileComponents(data, glyfTable) else: self.decompileCoordinates(data)
def decompile(self, data, ttFont): numGlyphs = ttFont['maxp'].numGlyphs glyphOrder = ttFont.getGlyphOrder() dummy, data = sstruct.unpack2(hdmxHeaderFormat, data, self) self.hdmx = {} for i in range(self.numRecords): ppem = byteord(data[0]) maxSize = byteord(data[1]) widths = {} for glyphID in range(numGlyphs): widths[glyphOrder[glyphID]] = byteord(data[glyphID + 2]) self.hdmx[ppem] = widths data = data[self.recordSize:] assert len(data) == 0, "too much hdmx data"