def decompile(self, ttFont): self.glyphName = ttFont.getGlyphName(self.gid) if self.rawdata is None: from fontTools import ttLib raise ttLib.TTLibError("No table data to decompile") if len(self.rawdata) > 0: if len(self.rawdata) < sbixGlyphHeaderFormatSize: from fontTools import ttLib #print "Glyph %i header too short: Expected %x, got %x." % (self.gid, sbixGlyphHeaderFormatSize, len(self.rawdata)) raise ttLib.TTLibError("Glyph header too short.") sstruct.unpack(sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self) if self.graphicType == "dupe": # this glyph is a reference to another glyph's image data gid, = struct.unpack(">H", self.rawdata[sbixGlyphHeaderFormatSize:]) self.referenceGlyphName = ttFont.getGlyphName(gid) else: self.imageData = self.rawdata[sbixGlyphHeaderFormatSize:] self.referenceGlyphName = None # clean up del self.rawdata del self.gid
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] glyphs = ttFont.getGlyphOrder() sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self) assert len(glyphs) == self.glyphCount assert len(axisTags) == self.axisCount offsets = self.decompileOffsets_(data[GVAR_HEADER_SIZE:], tableFormat=(self.flags & 1), glyphCount=self.glyphCount) sharedCoords = tv.decompileSharedTuples(axisTags, self.sharedTupleCount, data, self.offsetToSharedTuples) self.variations = _lazy_dict() offsetToData = self.offsetToGlyphVariationData glyf = ttFont['glyf'] for i in range(self.glyphCount): glyphName = glyphs[i] glyph = glyf[glyphName] numPointsInGlyph = self.getNumPoints_(glyph) gvarData = data[offsetToData + offsets[i]:offsetToData + offsets[i + 1]] self.variations[glyphName] = partial(decompileGlyph_, numPointsInGlyph, sharedCoords, axisTags, gvarData)
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] glyphs = ttFont.getGlyphOrder() sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self) assert len(glyphs) == self.glyphCount assert len(axisTags) == self.axisCount offsets = self.decompileOffsets_(data[GVAR_HEADER_SIZE:], tableFormat=(self.flags & 1), glyphCount=self.glyphCount) sharedCoords = tv.decompileSharedTuples( axisTags, self.sharedTupleCount, data, self.offsetToSharedTuples) self.variations = {} offsetToData = self.offsetToGlyphVariationData for i in range(self.glyphCount): glyphName = glyphs[i] glyph = ttFont["glyf"][glyphName] numPointsInGlyph = self.getNumPoints_(glyph) gvarData = data[offsetToData + offsets[i] : offsetToData + offsets[i + 1]] try: self.variations[glyphName] = decompileGlyph_( numPointsInGlyph, sharedCoords, axisTags, gvarData) except Exception: log.error( "Failed to decompile deltas for glyph '%s' (%d points)", glyphName, numPointsInGlyph, ) raise
def decompile(self, data, ttFont): # read table header sstruct.unpack(sbixHeaderFormat, data[ : sbixHeaderFormatSize], self) # collect offsets to individual strikes in self.strikeOffsets for i in range(self.numStrikes): current_offset = sbixHeaderFormatSize + i * sbixStrikeOffsetFormatSize offset_entry = sbixStrikeOffset() sstruct.unpack(sbixStrikeOffsetFormat, \ data[current_offset:current_offset+sbixStrikeOffsetFormatSize], \ offset_entry) self.strikeOffsets.append(offset_entry.strikeOffset) # decompile Strikes for i in range(self.numStrikes-1, -1, -1): current_strike = Strike(rawdata=data[self.strikeOffsets[i]:]) data = data[:self.strikeOffsets[i]] current_strike.decompile(ttFont) #print " Strike length: %xh" % len(bitmapSetData) #print "Number of Glyph entries:", len(current_strike.glyphs) if current_strike.ppem in self.strikes: from fontTools import ttLib raise ttLib.TTLibError("Pixel 'ppem' must be unique for each Strike") self.strikes[current_strike.ppem] = current_strike # after the glyph data records have been extracted, we don't need the offsets anymore del self.strikeOffsets del self.numStrikes
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] glyphs = ttFont.getGlyphOrder() sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self) assert len(glyphs) == self.glyphCount assert len(axisTags) == self.axisCount offsets = self.decompileOffsets_(data[GVAR_HEADER_SIZE:], tableFormat=(self.flags & 1), glyphCount=self.glyphCount) sharedCoords = tv.decompileSharedTuples(axisTags, self.sharedTupleCount, data, self.offsetToSharedTuples) self.variations = {} offsetToData = self.offsetToGlyphVariationData for i in range(self.glyphCount): glyphName = glyphs[i] glyph = ttFont["glyf"][glyphName] numPointsInGlyph = self.getNumPoints_(glyph) gvarData = data[offsetToData + offsets[i]:offsetToData + offsets[i + 1]] try: self.variations[glyphName] = decompileGlyph_( numPointsInGlyph, sharedCoords, axisTags, gvarData) except Exception: log.error( "Failed to decompile deltas for glyph '%s' (%d points)", glyphName, numPointsInGlyph, ) raise
def decompile(self, data, ttFont): # read table header sstruct.unpack(sbixHeaderFormat, data[:sbixHeaderFormatSize], self) # collect offsets to individual bitmap sets in self.bitmapSetOffsets for i in range(self.numSets): myOffset = sbixHeaderFormatSize + i * sbixBitmapSetOffsetFormatSize offsetEntry = sbixBitmapSetOffset() sstruct.unpack(sbixBitmapSetOffsetFormat, \ data[myOffset : myOffset+sbixBitmapSetOffsetFormatSize], \ offsetEntry) self.bitmapSetOffsets.append(offsetEntry.offset) # decompile BitmapSets for i in range(self.numSets - 1, -1, -1): myBitmapSet = BitmapSet(rawdata=data[self.bitmapSetOffsets[i]:]) data = data[:self.bitmapSetOffsets[i]] myBitmapSet.decompile(ttFont) #print " BitmapSet length: %xh" % len(bitmapSetData) #print "Number of Bitmaps:", myBitmapSet.numBitmaps if myBitmapSet.size in self.bitmapSets: from fontTools import ttLib raise ttLib.TTLibError( "Pixel 'size' must be unique for each BitmapSet") self.bitmapSets[myBitmapSet.size] = myBitmapSet # after the bitmaps have been extracted, we don't need the offsets anymore del self.bitmapSetOffsets
def decompile(self, data): # header; FontRec sstruct.unpack(nfntHeaderFormat, data[:headerSize], self) #assert self.fRectHeight == (self.ascent + self.descent) # rest tableSize = 2 * (self.lastChar - self.firstChar + 3) bitmapSize = 2 * self.rowWords * self.fRectHeight self.bits = data[headerSize:headerSize + bitmapSize] # XXX deal with self.nDescent being a positive number assert (headerSize + bitmapSize + tableSize - 16) / 2 == self.owTLoc # ugh... locTable = data[headerSize + bitmapSize:headerSize + bitmapSize + tableSize] if len(locTable) <> tableSize: raise ValueError, 'invalid NFNT format' owTable = data[headerSize + bitmapSize + tableSize:headerSize + bitmapSize + 2 * tableSize] if len(owTable) <> tableSize: raise ValueError, 'invalid NFNT format' # fill tables self.offsetTable = [] self.widthTable = [] self.locTable = [] for i in range(0, tableSize, 2): self.offsetTable.append(ord(owTable[i])) self.widthTable.append(ord(owTable[i+1])) loc, = struct.unpack("h", locTable[i:i+2]) self.locTable.append(loc)
def decompile(self, data, ttFont): # read table header sstruct.unpack(sbixHeaderFormat, data[ : sbixHeaderFormatSize], self) # collect offsets to individual bitmap sets in self.bitmapSetOffsets for i in range(self.numSets): myOffset = sbixHeaderFormatSize + i * sbixBitmapSetOffsetFormatSize offsetEntry = sbixBitmapSetOffset() sstruct.unpack(sbixBitmapSetOffsetFormat, \ data[myOffset : myOffset+sbixBitmapSetOffsetFormatSize], \ offsetEntry) self.bitmapSetOffsets.append(offsetEntry.offset) # decompile BitmapSets for i in range(self.numSets-1, -1, -1): myBitmapSet = BitmapSet(rawdata=data[self.bitmapSetOffsets[i]:]) data = data[:self.bitmapSetOffsets[i]] myBitmapSet.decompile(ttFont) #print " BitmapSet length: %xh" % len(bitmapSetData) #print "Number of Bitmaps:", myBitmapSet.numBitmaps if myBitmapSet.size in self.bitmapSets: from fontTools import ttLib raise ttLib.TTLibError("Pixel 'size' must be unique for each BitmapSet") self.bitmapSets[myBitmapSet.size] = myBitmapSet # after the bitmaps have been extracted, we don't need the offsets anymore del self.bitmapSetOffsets
def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise ttLib.TTLibError if len(self.data) < sbixBitmapSetHeaderFormatSize: from fontTools import ttLib raise(ttLib.TTLibError, "BitmapSet header too short: Expected %x, got %x.") \ % (sbixBitmapSetHeaderFormatSize, len(self.data)) # read BitmapSet header from raw data sstruct.unpack(sbixBitmapSetHeaderFormat, self.data[:sbixBitmapSetHeaderFormatSize], self) # calculate number of bitmaps firstBitmapOffset, = struct.unpack(">L", \ self.data[sbixBitmapSetHeaderFormatSize : sbixBitmapSetHeaderFormatSize + sbixBitmapOffsetEntryFormatSize]) self.numBitmaps = (firstBitmapOffset - sbixBitmapSetHeaderFormatSize) // sbixBitmapOffsetEntryFormatSize - 1 # ^ -1 because there's one more offset than bitmaps # build offset list for single bitmap offsets self.bitmapOffsets = [] for i in range(self.numBitmaps + 1): # + 1 because there's one more offset than bitmaps start = i * sbixBitmapOffsetEntryFormatSize + sbixBitmapSetHeaderFormatSize myOffset, = struct.unpack(">L", self.data[start : start + sbixBitmapOffsetEntryFormatSize]) self.bitmapOffsets.append(myOffset) # iterate through offset list and slice raw data into bitmaps for i in range(self.numBitmaps): myBitmap = Bitmap(rawdata=self.data[self.bitmapOffsets[i] : self.bitmapOffsets[i+1]], gid=i) myBitmap.decompile(ttFont) self.bitmaps[myBitmap.glyphName] = myBitmap del self.bitmapOffsets del self.data
def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise ttLib.TTLibError if len(self.data) < sbixStrikeHeaderFormatSize: from fontTools import ttLib raise(ttLib.TTLibError, "Strike header too short: Expected %x, got %x.") \ % (sbixStrikeHeaderFormatSize, len(self.data)) # read Strike header from raw data sstruct.unpack(sbixStrikeHeaderFormat, self.data[:sbixStrikeHeaderFormatSize], self) # calculate number of glyphs firstGlyphDataOffset, = struct.unpack(">L", \ self.data[sbixStrikeHeaderFormatSize:sbixStrikeHeaderFormatSize + sbixGlyphDataOffsetFormatSize]) self.numGlyphs = (firstGlyphDataOffset - sbixStrikeHeaderFormatSize) // sbixGlyphDataOffsetFormatSize - 1 # ^ -1 because there's one more offset than glyphs # build offset list for single glyph data offsets self.glyphDataOffsets = [] for i in range(self.numGlyphs + 1): # + 1 because there's one more offset than glyphs start = i * sbixGlyphDataOffsetFormatSize + sbixStrikeHeaderFormatSize current_offset, = struct.unpack(">L", self.data[start:start + sbixGlyphDataOffsetFormatSize]) self.glyphDataOffsets.append(current_offset) # iterate through offset list and slice raw data into glyph data records for i in range(self.numGlyphs): current_glyph = Glyph(rawdata=self.data[self.glyphDataOffsets[i]:self.glyphDataOffsets[i+1]], gid=i) current_glyph.decompile(ttFont) self.glyphs[current_glyph.glyphName] = current_glyph del self.glyphDataOffsets del self.numGlyphs del self.data
def decompile(self, data, ttFont): # read table header sstruct.unpack(sbixHeaderFormat, data[:sbixHeaderFormatSize], self) # collect offsets to individual strikes in self.strikeOffsets for i in range(self.numStrikes): current_offset = sbixHeaderFormatSize + i * sbixStrikeOffsetFormatSize offset_entry = sbixStrikeOffset() sstruct.unpack(sbixStrikeOffsetFormat, \ data[current_offset:current_offset+sbixStrikeOffsetFormatSize], \ offset_entry) self.strikeOffsets.append(offset_entry.strikeOffset) # decompile Strikes for i in range(self.numStrikes - 1, -1, -1): current_strike = Strike(rawdata=data[self.strikeOffsets[i]:]) data = data[:self.strikeOffsets[i]] current_strike.decompile(ttFont) #print " Strike length: %xh" % len(bitmapSetData) #print "Number of Glyph entries:", len(current_strike.glyphs) if current_strike.ppem in self.strikes: from fontTools import ttLib raise ttLib.TTLibError( "Pixel 'ppem' must be unique for each Strike") self.strikes[current_strike.ppem] = current_strike # after the glyph data records have been extracted, we don't need the offsets anymore del self.strikeOffsets del self.numStrikes
def decompile(self, data, ttFont): sstruct.unpack(TRAK_HEADER_FORMAT, data[:TRAK_HEADER_FORMAT_SIZE], self) for direction in ('horiz', 'vert'): trackData = TrackData() offset = getattr(self, direction + 'Offset') if offset != 0: trackData.decompile(data, offset) setattr(self, direction + 'Data', trackData)
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): sstruct.unpack(TRAK_HEADER_FORMAT, data[:TRAK_HEADER_FORMAT_SIZE], self) for direction in ("horiz", "vert"): trackData = TrackData() offset = getattr(self, direction + "Offset") if offset != 0: trackData.decompile(data, offset) setattr(self, direction + "Data", trackData)
def _getheader(self): data = self.FOND.data sstruct.unpack(headerformat, data[:28], self) self.ffProperty = struct.unpack(">9h", data[28:46]) self.ffIntl = struct.unpack(">hh", data[46:50]) self.ffVersion, = struct.unpack(">h", data[50:FONDheadersize]) if DEBUG: self._rawheader = data[:FONDheadersize] self.parsedthings.append((0, FONDheadersize, 'header'))
def _readHeaderAndMap(self): self.file.seek(0) headerData = self._read(ResourceForkHeaderSize) sstruct.unpack(ResourceForkHeader, headerData, self) # seek to resource map, skip reserved mapOffset = self.mapOffset + 22 resourceMapData = self._read(ResourceMapHeaderSize, mapOffset) sstruct.unpack(ResourceMapHeader, resourceMapData, self) self.absTypeListOffset = self.mapOffset + self.typeListOffset self.absNameListOffset = self.mapOffset + self.nameListOffset
def getInfo(self): if self.__haveInfo: return data = sstruct.pack(_FCBPBFormat, self) buf = array.array("c", data) ptr = buf.buffer_info()[0] err = _getInfo(ptr) if err: raise Res.Error("can't get file info", err) sstruct.unpack(_FCBPBFormat, buf.tostring(), self) self.__haveInfo = 1
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, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} sstruct.unpack(CVAR_HEADER_FORMAT, data[0:CVAR_HEADER_SIZE], header) self.majorVersion = header["majorVersion"] self.minorVersion = header["minorVersion"] assert self.majorVersion == 1, self.majorVersion self.variations = decompileTupleVariationStore( tableTag=self.tableTag, axisTags=axisTags, tupleVariationCount=header["tupleVariationCount"], pointCount=len(ttFont["cvt "].values), sharedTuples=None, data=data, pos=CVAR_HEADER_SIZE, dataPos=header["offsetToData"])
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)
def decompile(self, refData, reader): sstruct.unpack(ResourceRefItem, refData, self) # interpret 3-byte dataOffset as (padded) ULONG to unpack it with struct self.dataOffset, = struct.unpack('>L', bytesjoin([b"\0", self.dataOffset])) absDataOffset = reader.dataOffset + self.dataOffset dataLength, = struct.unpack(">L", reader._read(4, absDataOffset)) self.data = reader._read(dataLength) if self.nameOffset == -1: 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')
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 readTTCHeader(file): file.seek(0) data = file.read(ttcHeaderSize) if len(data) != ttcHeaderSize: raise TTLibError("Not a Font Collection (not enough data)") self = SimpleNamespace() sstruct.unpack(ttcHeaderFormat, data, self) if self.TTCTag != "ttcf": raise TTLibError("Not a Font Collection") assert self.Version == 0x00010000 or self.Version == 0x00020000, "unrecognized TTC version 0x%08x" % self.Version self.offsetTable = struct.unpack(">%dL" % self.numFonts, file.read(self.numFonts * 4)) if self.Version == 0x00020000: pass # ignoring version 2.0 signatures return self
def __init__(self, file, checkChecksums=1, fontNumber=-1): if not haveBrotli: print( 'The WOFF2 decoder requires the Brotli Python extension, available at:\n' 'https://github.com/google/brotli', file=sys.stderr) raise ImportError("No module named brotli") self.file = file signature = Tag(self.file.read(4)) if signature != b"wOF2": raise TTLibError("Not a WOFF2 font (bad signature)") self.file.seek(0) self.DirectoryEntry = WOFF2DirectoryEntry data = self.file.read(woff2DirectorySize) if len(data) != woff2DirectorySize: raise TTLibError('Not a WOFF2 font (not enough data)') sstruct.unpack(woff2DirectoryFormat, data, self) self.tables = OrderedDict() offset = 0 for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) tag = Tag(entry.tag) self.tables[tag] = entry entry.offset = offset offset += entry.length totalUncompressedSize = offset compressedData = self.file.read(self.totalCompressedSize) decompressedData = brotli.decompress(compressedData) if len(decompressedData) != totalUncompressedSize: raise TTLibError( 'unexpected size for decompressed font data: expected %d, found %d' % (totalUncompressedSize, len(decompressedData))) self.transformBuffer = BytesIO(decompressedData) self.file.seek(0, 2) if self.length != self.file.tell(): raise TTLibError( "reported 'length' doesn't match the actual file size") self.flavorData = WOFF2FlavorData(self) # make empty TTFont to store data while reconstructing tables self.ttFont = TTFont(recalcBBoxes=False, recalcTimestamp=False)
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 decompile(self, data, ttFont): axisTags = [axis.AxisTag for axis in ttFont["fvar"].table.VariationAxis] glyphs = ttFont.getGlyphOrder() sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self) assert len(glyphs) == self.glyphCount assert len(axisTags) == self.axisCount offsets = self.decompileOffsets_(data[GVAR_HEADER_SIZE:], tableFormat=(self.flags & 1), glyphCount=self.glyphCount) sharedCoords = self.decompileSharedCoords_(axisTags, data) self.variations = {} for i in range(self.glyphCount): glyphName = glyphs[i] glyph = ttFont["glyf"][glyphName] numPoints = self.getNumPoints_(glyph) gvarData = data[self.offsetToData + offsets[i] : self.offsetToData + offsets[i + 1]] self.variations[glyphName] = self.decompileGlyph_(numPoints, sharedCoords, axisTags, gvarData)
def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums self.flavor = None self.flavorData = None self.DirectoryEntry = SFNTDirectoryEntry self.sfntVersion = self.file.read(4) self.file.seek(0) if self.sfntVersion == b"ttcf": data = self.file.read(ttcHeaderSize) if len(data) != ttcHeaderSize: from fontTools import ttLib raise ttLib.TTLibError("Not a Font Collection (not enough data)") sstruct.unpack(ttcHeaderFormat, data, self) assert self.Version == 0x00010000 or self.Version == 0x00020000, "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError("specify a font number between 0 and %d (inclusive)" % (self.numFonts - 1)) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == 0x00020000: pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) data = self.file.read(sfntDirectorySize) if len(data) != sfntDirectorySize: from fontTools import ttLib raise ttLib.TTLibError("Not a Font Collection (not enough data)") sstruct.unpack(sfntDirectoryFormat, data, self) elif self.sfntVersion == b"wOFF": self.flavor = "woff" self.DirectoryEntry = WOFFDirectoryEntry data = self.file.read(woffDirectorySize) if len(data) != woffDirectorySize: from fontTools import ttLib raise ttLib.TTLibError("Not a WOFF font (not enough data)") sstruct.unpack(woffDirectoryFormat, data, self) else: data = self.file.read(sfntDirectorySize) if len(data) != sfntDirectorySize: from fontTools import ttLib raise ttLib.TTLibError("Not a TrueType or OpenType font (not enough data)") sstruct.unpack(sfntDirectoryFormat, data, self) self.sfntVersion = Tag(self.sfntVersion) if self.sfntVersion not in ("\x00\x01\x00\x00", "OTTO", "true"): from fontTools import ttLib raise ttLib.TTLibError("Not a TrueType or OpenType font (bad sfntVersion)") tables = {} for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) tag = Tag(entry.tag) tables[tag] = entry self.tables = OrderedDict(sorted(tables.items(), key=lambda i: i[1].offset)) # Load flavor data if any if self.flavor == "woff": self.flavorData = WOFFFlavorData(self)
def test_incorrect_compressed_size(self): data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) header['totalCompressedSize'] = 0 data = sstruct.pack(woff2DirectoryFormat, header) with self.assertRaises((brotli.error, ttLib.TTLibError)): WOFF2Reader(BytesIO(data + self.file.read()))
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] glyphs = ttFont.getGlyphOrder() sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self) assert len(glyphs) == self.glyphCount assert len(axisTags) == self.axisCount offsets = self.decompileOffsets_(data[GVAR_HEADER_SIZE:], tableFormat=(self.flags & 1), glyphCount=self.glyphCount) sharedCoords = self.decompileSharedCoords_(axisTags, data) self.variations = {} for i in range(self.glyphCount): glyphName = glyphs[i] glyph = ttFont["glyf"][glyphName] numPointsInGlyph = self.getNumPoints_(glyph) gvarData = data[self.offsetToData + offsets[i] : self.offsetToData + offsets[i + 1]] self.variations[glyphName] = \ self.decompileGlyph_(numPointsInGlyph, sharedCoords, axisTags, gvarData)
def test_incorrect_file_size(self): data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) header["length"] -= 1 data = sstruct.pack(woff2DirectoryFormat, header) with self.assertRaisesRegex(ttLib.TTLibError, "doesn't match the actual file size"): WOFF2Reader(BytesIO(data + self.file.read()))
def __init__(self, file, checkChecksums=1, fontNumber=-1): if not haveBrotli: log.error( 'The WOFF2 decoder requires the Brotli Python extension, available at: ' 'https://github.com/google/brotli') raise ImportError("No module named brotli") self.file = file signature = Tag(self.file.read(4)) if signature != b"wOF2": raise TTLibError("Not a WOFF2 font (bad signature)") self.file.seek(0) self.DirectoryEntry = WOFF2DirectoryEntry data = self.file.read(woff2DirectorySize) if len(data) != woff2DirectorySize: raise TTLibError('Not a WOFF2 font (not enough data)') sstruct.unpack(woff2DirectoryFormat, data, self) self.tables = OrderedDict() offset = 0 for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) tag = Tag(entry.tag) self.tables[tag] = entry entry.offset = offset offset += entry.length totalUncompressedSize = offset compressedData = self.file.read(self.totalCompressedSize) decompressedData = brotli.decompress(compressedData) if len(decompressedData) != totalUncompressedSize: raise TTLibError( 'unexpected size for decompressed font data: expected %d, found %d' % (totalUncompressedSize, len(decompressedData))) self.transformBuffer = BytesIO(decompressedData) self.file.seek(0, 2) if self.length != self.file.tell(): raise TTLibError("reported 'length' doesn't match the actual file size") self.flavorData = WOFF2FlavorData(self) # make empty TTFont to store data while reconstructing tables self.ttFont = TTFont(recalcBBoxes=False, recalcTimestamp=False)
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 self.tables = {} for i in range(self.numTables): entry = WOFFDirectoryEntry() entry.fromFile(self.file) self.tables[entry.tag] = entry
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 test_incorrect_file_size(self): data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) header['length'] -= 1 data = sstruct.pack(woff2DirectoryFormat, header) with self.assertRaisesRegex( ttLib.TTLibError, "doesn't match the actual file size"): WOFF2Reader(BytesIO(data + self.file.read()))
def decompile(self, data, offset): # initial offset is from the start of trak table to the current TrackData trackDataHeader = data[offset:offset + TRACK_DATA_FORMAT_SIZE] if len(trackDataHeader) != TRACK_DATA_FORMAT_SIZE: raise TTLibError('not enough data to decompile TrackData header') sstruct.unpack(TRACK_DATA_FORMAT, trackDataHeader, self) offset += TRACK_DATA_FORMAT_SIZE nSizes = self.nSizes sizeTableOffset = self.sizeTableOffset sizeTable = [] for i in range(nSizes): sizeValueData = data[sizeTableOffset:sizeTableOffset + SIZE_VALUE_FORMAT_SIZE] if len(sizeValueData) < SIZE_VALUE_FORMAT_SIZE: raise TTLibError( 'not enough data to decompile TrackData size subtable') sizeValue, = struct.unpack(SIZE_VALUE_FORMAT, sizeValueData) sizeTable.append(fi2fl(sizeValue, 16)) sizeTableOffset += SIZE_VALUE_FORMAT_SIZE for i in range(self.nTracks): entry = TrackTableEntry() entryData = data[offset:offset + TRACK_TABLE_ENTRY_FORMAT_SIZE] if len(entryData) < TRACK_TABLE_ENTRY_FORMAT_SIZE: raise TTLibError( 'not enough data to decompile TrackTableEntry record') sstruct.unpack(TRACK_TABLE_ENTRY_FORMAT, entryData, entry) perSizeOffset = entry.offset for j in range(nSizes): size = sizeTable[j] perSizeValueData = data[perSizeOffset:perSizeOffset + PER_SIZE_VALUE_FORMAT_SIZE] if len(perSizeValueData) < PER_SIZE_VALUE_FORMAT_SIZE: raise TTLibError( 'not enough data to decompile per-size track values') perSizeValue, = struct.unpack(PER_SIZE_VALUE_FORMAT, perSizeValueData) entry[size] = perSizeValue perSizeOffset += PER_SIZE_VALUE_FORMAT_SIZE self[entry.track] = entry offset += TRACK_TABLE_ENTRY_FORMAT_SIZE
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 __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums self.flavor = None self.flavorData = None self.DirectoryEntry = SFNTDirectoryEntry self.sfntVersion = self.file.read(4) self.file.seek(0) if self.sfntVersion == b"ttcf": sstruct.unpack(ttcHeaderFormat, self.file.read(ttcHeaderSize), self) assert self.Version == 0x00010000 or self.Version == 0x00020000, "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError( "specify a font number between 0 and %d (inclusive)" % (self.numFonts - 1)) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == 0x00020000: pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) elif self.sfntVersion == b"wOFF": self.flavor = "woff" self.DirectoryEntry = WOFFDirectoryEntry sstruct.unpack(woffDirectoryFormat, self.file.read(woffDirectorySize), self) else: sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) self.sfntVersion = Tag(self.sfntVersion) if self.sfntVersion not in ("\x00\x01\x00\x00", "OTTO", "true"): from fontTools import ttLib raise ttLib.TTLibError( "Not a TrueType or OpenType font (bad sfntVersion)") self.tables = {} for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) self.tables[Tag(entry.tag)] = entry # Load flavor data if any if self.flavor == "woff": self.flavorData = WOFFFlavorData(self)
def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise ttLib.TTLibError if len(self.data) < sbixBitmapSetHeaderFormatSize: from fontTools import ttLib raise(ttLib.TTLibError, "BitmapSet header too short: Expected %x, got %x.") \ % (sbixBitmapSetHeaderFormatSize, len(self.data)) # read BitmapSet header from raw data sstruct.unpack(sbixBitmapSetHeaderFormat, self.data[:sbixBitmapSetHeaderFormatSize], self) # calculate number of bitmaps firstBitmapOffset, = struct.unpack(">L", \ self.data[sbixBitmapSetHeaderFormatSize : sbixBitmapSetHeaderFormatSize + sbixBitmapOffsetEntryFormatSize]) self.numBitmaps = (firstBitmapOffset - sbixBitmapSetHeaderFormatSize ) // sbixBitmapOffsetEntryFormatSize - 1 # ^ -1 because there's one more offset than bitmaps # build offset list for single bitmap offsets self.bitmapOffsets = [] for i in range(self.numBitmaps + 1): # + 1 because there's one more offset than bitmaps start = i * sbixBitmapOffsetEntryFormatSize + sbixBitmapSetHeaderFormatSize myOffset, = struct.unpack( ">L", self.data[start:start + sbixBitmapOffsetEntryFormatSize]) self.bitmapOffsets.append(myOffset) # iterate through offset list and slice raw data into bitmaps for i in range(self.numBitmaps): myBitmap = Bitmap( rawdata=self.data[self.bitmapOffsets[i]:self.bitmapOffsets[i + 1]], gid=i) myBitmap.decompile(ttFont) self.bitmaps[myBitmap.glyphName] = myBitmap del self.bitmapOffsets del self.data
def decompile(self, data, ttFont): self.docList = [] # Version 0 is the standardized version of the table; and current. # https://www.microsoft.com/typography/otspec/svg.htm sstruct.unpack(SVG_format_0, data[:SVG_format_0Size], self) if self.version != 0: log.warning( "Unknown SVG table version '%s'. Decompiling as version 0.", self.version) # read in SVG Documents Index # data starts with the first entry of the entry list. pos = subTableStart = self.offsetToSVGDocIndex self.numEntries = struct.unpack(">H", data[pos:pos + 2])[0] pos += 2 if self.numEntries > 0: data2 = data[pos:] 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] compressed = False if doc.startswith(b"\x1f\x8b"): import gzip bytesIO = BytesIO(doc) with gzip.GzipFile(None, "r", fileobj=bytesIO) as gunzipper: doc = gunzipper.read() del bytesIO compressed = True doc = tostr(doc, "utf_8") self.docList.append( SVGDocument(doc, entry.startGlyphID, entry.endGlyphID, compressed))
def decompile(self, ttFont): self.glyphName = ttFont.getGlyphName(self.gid) if self.rawdata is None: from fontTools import ttLib raise ttLib.TTLibError("No table data to decompile") if len(self.rawdata) > 0: if len(self.rawdata) < sbixBitmapHeaderFormatSize: from fontTools import ttLib #print "Bitmap %i header too short: Expected %x, got %x." % (self.gid, sbixBitmapHeaderFormatSize, len(self.rawdata)) raise ttLib.TTLibError("Bitmap header too short.") sstruct.unpack(sbixBitmapHeaderFormat, self.rawdata[:sbixBitmapHeaderFormatSize], self) if self.imageFormatTag == "dupe": # bitmap is a reference to another glyph's bitmap gid, = struct.unpack(">H", self.rawdata[sbixBitmapHeaderFormatSize:]) self.referenceGlyphName = ttFont.getGlyphName(gid) else: self.imageData = self.rawdata[sbixBitmapHeaderFormatSize:] self.referenceGlyphName = None # clean up del self.rawdata del self.gid
def _readTypeList(self): absTypeListOffset = self.absTypeListOffset numTypesData = self._read(2, absTypeListOffset) self.numTypes, = struct.unpack('>H', numTypesData) absTypeListOffset2 = absTypeListOffset + 2 for i in range(self.numTypes + 1): resTypeItemOffset = absTypeListOffset2 + ResourceTypeItemSize * i resTypeItemData = self._read(ResourceTypeItemSize, resTypeItemOffset) item = sstruct.unpack(ResourceTypeItem, resTypeItemData) resType = tostr(item['type'], encoding='mac-roman') refListOffset = absTypeListOffset + item['refListOffset'] numRes = item['numRes'] + 1 resources = self._readReferenceList(resType, refListOffset, numRes) self._resources[resType] = resources
def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums self.flavor = None self.flavorData = None self.DirectoryEntry = SFNTDirectoryEntry self.sfntVersion = self.file.read(4) self.file.seek(0) if self.sfntVersion == b"ttcf": sstruct.unpack(ttcHeaderFormat, self.file.read(ttcHeaderSize), self) assert self.Version == 0x00010000 or self.Version == 0x00020000, "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError("specify a font number between 0 and %d (inclusive)" % (self.numFonts - 1)) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == 0x00020000: pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) elif self.sfntVersion == b"wOFF": self.flavor = "woff" self.DirectoryEntry = WOFFDirectoryEntry sstruct.unpack(woffDirectoryFormat, self.file.read(woffDirectorySize), self) else: sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) self.sfntVersion = Tag(self.sfntVersion) if self.sfntVersion not in ("\x00\x01\x00\x00", "OTTO", "true"): from fontTools import ttLib raise ttLib.TTLibError("Not a TrueType or OpenType font (bad sfntVersion)") self.tables = {} for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) if entry.length > 0: self.tables[Tag(entry.tag)] = entry else: # Ignore zero-length tables. This doesn't seem to be documented, # yet it's apparently how the Windows TT rasterizer behaves. # Besides, at least one font has been sighted which actually # *has* a zero-length table. pass # Load flavor data if any if self.flavor == "woff": self.flavorData = WOFFFlavorData(self)
def decompile(self, data, offset): # initial offset is from the start of trak table to the current TrackData trackDataHeader = data[offset:offset+TRACK_DATA_FORMAT_SIZE] if len(trackDataHeader) != TRACK_DATA_FORMAT_SIZE: raise TTLibError('not enough data to decompile TrackData header') sstruct.unpack(TRACK_DATA_FORMAT, trackDataHeader, self) offset += TRACK_DATA_FORMAT_SIZE nSizes = self.nSizes sizeTableOffset = self.sizeTableOffset sizeTable = [] for i in range(nSizes): sizeValueData = data[sizeTableOffset:sizeTableOffset+SIZE_VALUE_FORMAT_SIZE] if len(sizeValueData) < SIZE_VALUE_FORMAT_SIZE: raise TTLibError('not enough data to decompile TrackData size subtable') sizeValue, = struct.unpack(SIZE_VALUE_FORMAT, sizeValueData) sizeTable.append(fi2fl(sizeValue, 16)) sizeTableOffset += SIZE_VALUE_FORMAT_SIZE for i in range(self.nTracks): entry = TrackTableEntry() entryData = data[offset:offset+TRACK_TABLE_ENTRY_FORMAT_SIZE] if len(entryData) < TRACK_TABLE_ENTRY_FORMAT_SIZE: raise TTLibError('not enough data to decompile TrackTableEntry record') sstruct.unpack(TRACK_TABLE_ENTRY_FORMAT, entryData, entry) perSizeOffset = entry.offset for j in range(nSizes): size = sizeTable[j] perSizeValueData = data[perSizeOffset:perSizeOffset+PER_SIZE_VALUE_FORMAT_SIZE] if len(perSizeValueData) < PER_SIZE_VALUE_FORMAT_SIZE: raise TTLibError('not enough data to decompile per-size track values') perSizeValue, = struct.unpack(PER_SIZE_VALUE_FORMAT, perSizeValueData) entry[size] = perSizeValue perSizeOffset += PER_SIZE_VALUE_FORMAT_SIZE self[entry.track] = entry offset += TRACK_TABLE_ENTRY_FORMAT_SIZE
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 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 __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums self.flavor = None self.flavorData = None self.DirectoryEntry = SFNTDirectoryEntry self.file.seek(0) self.sfntVersion = self.file.read(4) self.file.seek(0) if self.sfntVersion == b"ttcf": header = readTTCHeader(self.file) numFonts = header.numFonts if not 0 <= fontNumber < numFonts: raise TTLibError( "specify a font number between 0 and %d (inclusive)" % (numFonts - 1)) self.numFonts = numFonts self.file.seek(header.offsetTable[fontNumber]) data = self.file.read(sfntDirectorySize) if len(data) != sfntDirectorySize: raise TTLibError("Not a Font Collection (not enough data)") sstruct.unpack(sfntDirectoryFormat, data, self) elif self.sfntVersion == b"wOFF": self.flavor = "woff" self.DirectoryEntry = WOFFDirectoryEntry data = self.file.read(woffDirectorySize) if len(data) != woffDirectorySize: raise TTLibError("Not a WOFF font (not enough data)") sstruct.unpack(woffDirectoryFormat, data, self) else: data = self.file.read(sfntDirectorySize) if len(data) != sfntDirectorySize: raise TTLibError( "Not a TrueType or OpenType font (not enough data)") sstruct.unpack(sfntDirectoryFormat, data, self) self.sfntVersion = Tag(self.sfntVersion) if self.sfntVersion not in ("\x00\x01\x00\x00", "OTTO", "true"): raise TTLibError( "Not a TrueType or OpenType font (bad sfntVersion)") tables = {} for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) tag = Tag(entry.tag) tables[tag] = entry self.tables = OrderedDict( sorted(tables.items(), key=lambda i: i[1].offset)) # Load flavor data if any if self.flavor == "woff": self.flavorData = WOFFFlavorData(self)
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())