SHARE
TWEET

TTF sbit parser

lifeasageek Jan 30th, 2012 643 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # TTF sbit parser
  2. # supports EBLC and EBDT table
  3.  
  4. # lifeasageek@gmail.com
  5. # Byounyoung Lee
  6.  
  7. import struct
  8. import StringIO
  9. import collections
  10. import sys
  11.  
  12.  
  13. def sUnpack( sData, size):
  14.     return unpack( sData.read(size), size)
  15.  
  16. def unpack( data, size):
  17.     if size == 1:
  18.         return struct.unpack(">B", data)[0]
  19.     elif size == 2:
  20.         return struct.unpack(">H", data)[0]                    
  21.     elif size == 4:
  22.         return struct.unpack(">I", data)[0]
  23.     else:
  24.         print "ERROR : unpack size"
  25.         return ""
  26.  
  27. class SbitParser:
  28.     def __init__(self, ttfFilename ):
  29.         self.tables = {}
  30.         self.tableNames = ["EBLC", "EBDT" ]   # EBLC should be parsed before EBDT
  31.        
  32.         self.ttfFilename = ttfFilename
  33.         self.ttf = open(ttfFilename, "rb").read()
  34.  
  35.         for tableName in self.tableNames:
  36.             self.parseTables( tableName)
  37.         return
  38.  
  39.  
  40.     def parseTables(self,tableName):
  41.         # table header
  42.         idx = self.ttf.find(tableName)
  43.        
  44.         tName = self.ttf[idx:idx+4]
  45.        
  46.         tChecksum = self.ttf[idx+4:idx+8]
  47.         tOffset = self.ttf[idx+8:idx+12]
  48.         tSize = self.ttf[idx+12:idx+16]
  49.  
  50.         tChecksum = struct.unpack(">I", tChecksum)[0]
  51.         tOffset = struct.unpack(">I", tOffset)[0]
  52.         tSize  = struct.unpack(">I", tSize)[0]
  53.  
  54.         tData = self.ttf[tOffset:tOffset+tSize]
  55.         self.tables[tableName] = {}
  56.        
  57.         self.tables[tableName]["checksum"] = tChecksum
  58.         self.tables[tableName]["offset"] = tOffset
  59.         self.tables[tableName]["size"] = tSize
  60.         self.tables[tableName]["data"] = tData
  61.  
  62.         sData = StringIO.StringIO()
  63.         sData.write(tData)
  64.         sData.seek(0)
  65.  
  66.         d = getattr(self, "parse%s" % tName)(sData) # call each parse function
  67.         self.tables[tName] = d
  68.        
  69.         self.dumpTable(d)
  70.         return
  71.  
  72.     def dumpTable( self, d, depth = 1):
  73.         indent = " " * depth * 4
  74.         for key, value in d.iteritems():
  75.             if type(value) == type(1): # integer
  76.                 print indent, "%s : 0x%x" % (key, value)
  77.            
  78.             elif type(value) == type([]): # list
  79.                 for i, k in enumerate(value):
  80.                     print indent, "[-] %dth %s " % (i,key)
  81.                     self.dumpTable(k, depth+1)
  82.             else:
  83.                 binStr = " ".join(["%02x" % ord(c) for c in value])
  84.                 print indent, "%s : %s" % (key, binStr)
  85.         return
  86.  
  87.     def __hBigGlyphMetrics(self, sData, d):
  88.         d["height"] = sUnpack( sData, 1)
  89.         d["width"] = sUnpack( sData, 1)
  90.         d["horiBearingX"] = sUnpack( sData, 1)
  91.         d["horiBearingY"] = sUnpack( sData, 1)
  92.         d["horiAdvance"] = sUnpack( sData, 1)
  93.         d["vertBearingX"] = sUnpack( sData, 1)
  94.         d["vertBearingY"] = sUnpack( sData, 1)
  95.         d["vertAdvance"] = sUnpack( sData, 1)                                
  96.         return d
  97.    
  98.     def __hSmallGlyphMetrics(self, sData, d):
  99.         d["height"] = sUnpack( sData, 1)
  100.         d["width"] = sUnpack( sData, 1)
  101.         d["BearingX"] = sUnpack( sData, 1)
  102.         d["BearingY"] = sUnpack( sData, 1)
  103.         d["Advance"] = sUnpack( sData, 1)        
  104.         return d
  105.  
  106.  
  107.     def parseEBDT( self,sData):
  108.         print "[*] parseEBDT"
  109.         ebdt = collections.OrderedDict()
  110.        
  111.         ebdt["version"] = sUnpack(sData, 4)
  112.  
  113.         ebdt["metrics"] = []
  114.         for bTable in self.tables["EBLC"]["bitmapSizeTable"]:
  115.             for i in range(len(bTable["subArray"])):
  116.                 imageFormat = bTable["subArray"][i]["imageFormat"]
  117.  
  118.                 imageDataOffset = bTable["subArray"][i]["imageDataOffset"]
  119.  
  120.                 # now only supports 1 component
  121.                 arrayOffset0 = bTable["subArray"][i]["offsetArray0"]
  122.                 arrayOffset1 = bTable["subArray"][i]["offsetArray1"]
  123.  
  124.                 offset = imageDataOffset + arrayOffset0
  125.                
  126.                 pos = sData.tell()
  127.                 sData.seek(offset, 0)
  128.                
  129.                 m = collections.OrderedDict()
  130.                 if imageFormat == 1:
  131.                     self.__hSmallGlyphMetrics(sData, m)
  132.                     imageSize = imageDataOffset + arrayOffset1 - sData.tell()
  133.                     m["imageData"] = sData.read(imageSize)
  134.  
  135.                 elif imageFormat == 8:
  136.                     self.__hSmallGlyphMetrics(sData, m)
  137.                     m["pad"] = sUnpack( sData, 1)
  138.                     m["numComponents"] = sUnpack( sData, 2)
  139.                     m["ComponentArray"] = []
  140.                     for i in range(m["numComponents"]):
  141.                         c = collections.OrderedDict()
  142.                         c["glyphCode"] = sUnpack( sData, 2)
  143.                         c["xOffset"] = sUnpack( sData, 1)
  144.                         c["yOffset"] = sUnpack( sData, 1)
  145.                         m["ComponentArray"].append( c)
  146.  
  147.                 sData.seek(pos, 0)
  148.                 ebdt["metrics"].append( m)
  149.                    
  150.         return ebdt
  151.        
  152.     def parseEBLC( self, sData):
  153.         print "[*] parseEBLC"
  154.         eblc = collections.OrderedDict()
  155.         eblc["version"] = sUnpack( sData, 4)
  156.         eblc["numSizes"] = sUnpack( sData, 4)
  157.  
  158.         eblc["bitmapSizeTable"] = []
  159.         for i in range(eblc["numSizes"]):
  160.             t = collections.OrderedDict()            
  161.             t["indexSubTableArrayOffset"] = sUnpack( sData, 4)
  162.             t["indexTablesSize"] = sUnpack( sData, 4)
  163.             t["numberOfIndexSubTables"] = sUnpack( sData, 4)
  164.             t["colorRef"] = sUnpack( sData, 4)
  165.             t["hori"] = sData.read(12) # hori
  166.             t["vert"] = sData.read(12) # vert
  167.             t["startGlyphIndex"] = sUnpack( sData, 2)
  168.             t["endGlyphIndex"] = sUnpack( sData, 2)
  169.             t["ppemX"] = sUnpack( sData, 1)
  170.             t["ppemY"] = sUnpack( sData, 1)
  171.             t["bitDepth"] = sUnpack( sData, 1)
  172.             t["flags"] = sUnpack( sData, 1)
  173.  
  174.             #subtable
  175.             oldPos = sData.tell()
  176.             sData.seek(t["indexSubTableArrayOffset"], 0)
  177.  
  178.             t["subArray"] = []
  179.             for j in range(t["numberOfIndexSubTables"]):
  180.                 s = collections.OrderedDict()
  181.                 s["firstGlyphIndex"] = sUnpack( sData, 2)
  182.                 s["lastGlyphIndex"] = sUnpack( sData, 2)
  183.                 s["additionalOffsetToIndexSubtable"] = sUnpack( sData, 4)
  184.  
  185.                 oldPos2 = sData.tell()
  186.                 newPos = t["indexSubTableArrayOffset"]
  187.                 newPos += s["additionalOffsetToIndexSubtable"]
  188.                
  189.                 sData.seek(newPos, 0)
  190.                
  191.                 s["indexFormat"] = sUnpack( sData, 2)
  192.                 s["imageFormat"] = sUnpack( sData, 2)
  193.                 s["imageDataOffset"] = sUnpack( sData, 4)
  194.  
  195.                 assert s["indexFormat"] == 3, "only supports indexFormat == 3"
  196.  
  197.                 sizeOfArray = (s["lastGlyphIndex"] - s["firstGlyphIndex"] + 1) + 1
  198.  
  199.                 for k in range(sizeOfArray):
  200.                     s["offsetArray%d"%k] = sUnpack( sData, 2)
  201.  
  202.                 sData.seek(oldPos2)
  203.                
  204.                 t["subArray"].append(s)
  205.  
  206.             sData.seek(oldPos, 0)
  207.             eblc["bitmapSizeTable"].append(t)            
  208.            
  209.         return eblc
  210.  
  211. if __name__ == '__main__':
  212.     ttfFilename = sys.argv[1]
  213.     t = SbitParser(ttfFilename )
RAW Paste Data
Top