Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # TTF sbit parser
- # supports EBLC and EBDT table
- # lifeasageek@gmail.com
- # Byounyoung Lee
- import struct
- import StringIO
- import collections
- import sys
- def sUnpack( sData, size):
- return unpack( sData.read(size), size)
- def unpack( data, size):
- if size == 1:
- return struct.unpack(">B", data)[0]
- elif size == 2:
- return struct.unpack(">H", data)[0]
- elif size == 4:
- return struct.unpack(">I", data)[0]
- else:
- print "ERROR : unpack size"
- return ""
- class SbitParser:
- def __init__(self, ttfFilename ):
- self.tables = {}
- self.tableNames = ["EBLC", "EBDT" ] # EBLC should be parsed before EBDT
- self.ttfFilename = ttfFilename
- self.ttf = open(ttfFilename, "rb").read()
- for tableName in self.tableNames:
- self.parseTables( tableName)
- return
- def parseTables(self,tableName):
- # table header
- idx = self.ttf.find(tableName)
- tName = self.ttf[idx:idx+4]
- tChecksum = self.ttf[idx+4:idx+8]
- tOffset = self.ttf[idx+8:idx+12]
- tSize = self.ttf[idx+12:idx+16]
- tChecksum = struct.unpack(">I", tChecksum)[0]
- tOffset = struct.unpack(">I", tOffset)[0]
- tSize = struct.unpack(">I", tSize)[0]
- tData = self.ttf[tOffset:tOffset+tSize]
- self.tables[tableName] = {}
- self.tables[tableName]["checksum"] = tChecksum
- self.tables[tableName]["offset"] = tOffset
- self.tables[tableName]["size"] = tSize
- self.tables[tableName]["data"] = tData
- sData = StringIO.StringIO()
- sData.write(tData)
- sData.seek(0)
- d = getattr(self, "parse%s" % tName)(sData) # call each parse function
- self.tables[tName] = d
- self.dumpTable(d)
- return
- def dumpTable( self, d, depth = 1):
- indent = " " * depth * 4
- for key, value in d.iteritems():
- if type(value) == type(1): # integer
- print indent, "%s : 0x%x" % (key, value)
- elif type(value) == type([]): # list
- for i, k in enumerate(value):
- print indent, "[-] %dth %s " % (i,key)
- self.dumpTable(k, depth+1)
- else:
- binStr = " ".join(["%02x" % ord(c) for c in value])
- print indent, "%s : %s" % (key, binStr)
- return
- def __hBigGlyphMetrics(self, sData, d):
- d["height"] = sUnpack( sData, 1)
- d["width"] = sUnpack( sData, 1)
- d["horiBearingX"] = sUnpack( sData, 1)
- d["horiBearingY"] = sUnpack( sData, 1)
- d["horiAdvance"] = sUnpack( sData, 1)
- d["vertBearingX"] = sUnpack( sData, 1)
- d["vertBearingY"] = sUnpack( sData, 1)
- d["vertAdvance"] = sUnpack( sData, 1)
- return d
- def __hSmallGlyphMetrics(self, sData, d):
- d["height"] = sUnpack( sData, 1)
- d["width"] = sUnpack( sData, 1)
- d["BearingX"] = sUnpack( sData, 1)
- d["BearingY"] = sUnpack( sData, 1)
- d["Advance"] = sUnpack( sData, 1)
- return d
- def parseEBDT( self,sData):
- print "[*] parseEBDT"
- ebdt = collections.OrderedDict()
- ebdt["version"] = sUnpack(sData, 4)
- ebdt["metrics"] = []
- for bTable in self.tables["EBLC"]["bitmapSizeTable"]:
- for i in range(len(bTable["subArray"])):
- imageFormat = bTable["subArray"][i]["imageFormat"]
- imageDataOffset = bTable["subArray"][i]["imageDataOffset"]
- # now only supports 1 component
- arrayOffset0 = bTable["subArray"][i]["offsetArray0"]
- arrayOffset1 = bTable["subArray"][i]["offsetArray1"]
- offset = imageDataOffset + arrayOffset0
- pos = sData.tell()
- sData.seek(offset, 0)
- m = collections.OrderedDict()
- if imageFormat == 1:
- self.__hSmallGlyphMetrics(sData, m)
- imageSize = imageDataOffset + arrayOffset1 - sData.tell()
- m["imageData"] = sData.read(imageSize)
- elif imageFormat == 8:
- self.__hSmallGlyphMetrics(sData, m)
- m["pad"] = sUnpack( sData, 1)
- m["numComponents"] = sUnpack( sData, 2)
- m["ComponentArray"] = []
- for i in range(m["numComponents"]):
- c = collections.OrderedDict()
- c["glyphCode"] = sUnpack( sData, 2)
- c["xOffset"] = sUnpack( sData, 1)
- c["yOffset"] = sUnpack( sData, 1)
- m["ComponentArray"].append( c)
- sData.seek(pos, 0)
- ebdt["metrics"].append( m)
- return ebdt
- def parseEBLC( self, sData):
- print "[*] parseEBLC"
- eblc = collections.OrderedDict()
- eblc["version"] = sUnpack( sData, 4)
- eblc["numSizes"] = sUnpack( sData, 4)
- eblc["bitmapSizeTable"] = []
- for i in range(eblc["numSizes"]):
- t = collections.OrderedDict()
- t["indexSubTableArrayOffset"] = sUnpack( sData, 4)
- t["indexTablesSize"] = sUnpack( sData, 4)
- t["numberOfIndexSubTables"] = sUnpack( sData, 4)
- t["colorRef"] = sUnpack( sData, 4)
- t["hori"] = sData.read(12) # hori
- t["vert"] = sData.read(12) # vert
- t["startGlyphIndex"] = sUnpack( sData, 2)
- t["endGlyphIndex"] = sUnpack( sData, 2)
- t["ppemX"] = sUnpack( sData, 1)
- t["ppemY"] = sUnpack( sData, 1)
- t["bitDepth"] = sUnpack( sData, 1)
- t["flags"] = sUnpack( sData, 1)
- #subtable
- oldPos = sData.tell()
- sData.seek(t["indexSubTableArrayOffset"], 0)
- t["subArray"] = []
- for j in range(t["numberOfIndexSubTables"]):
- s = collections.OrderedDict()
- s["firstGlyphIndex"] = sUnpack( sData, 2)
- s["lastGlyphIndex"] = sUnpack( sData, 2)
- s["additionalOffsetToIndexSubtable"] = sUnpack( sData, 4)
- oldPos2 = sData.tell()
- newPos = t["indexSubTableArrayOffset"]
- newPos += s["additionalOffsetToIndexSubtable"]
- sData.seek(newPos, 0)
- s["indexFormat"] = sUnpack( sData, 2)
- s["imageFormat"] = sUnpack( sData, 2)
- s["imageDataOffset"] = sUnpack( sData, 4)
- assert s["indexFormat"] == 3, "only supports indexFormat == 3"
- sizeOfArray = (s["lastGlyphIndex"] - s["firstGlyphIndex"] + 1) + 1
- for k in range(sizeOfArray):
- s["offsetArray%d"%k] = sUnpack( sData, 2)
- sData.seek(oldPos2)
- t["subArray"].append(s)
- sData.seek(oldPos, 0)
- eblc["bitmapSizeTable"].append(t)
- return eblc
- if __name__ == '__main__':
- ttfFilename = sys.argv[1]
- t = SbitParser(ttfFilename )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement