lifeasageek

TTF sbit parser

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