sbixBitmap.py revision 4801a3ae39bfd79b05e3bb00245c06ab5e09d622
1import struct, sstruct 2from fontTools.misc.textTools import readHex 3 4sbixBitmapHeaderFormat = """ 5 > 6 usReserved1: H # 00 00 7 usReserved2: H # 00 00 8 imageFormatTag: 4s # e.g. "png " 9""" 10 11sbixBitmapHeaderFormatSize = sstruct.calcsize(sbixBitmapHeaderFormat) 12 13 14class Bitmap(object): 15 def __init__(self, glyphName=None, referenceGlyphName=None, usReserved1=0, usReserved2=0, imageFormatTag=None, imageData=None, rawdata=None, gid=0): 16 self.gid = gid 17 self.glyphName = glyphName 18 self.referenceGlyphName = referenceGlyphName 19 self.usReserved1 = usReserved1 20 self.usReserved2 = usReserved2 21 self.rawdata = rawdata 22 self.imageFormatTag = imageFormatTag 23 self.imageData = imageData 24 25 def decompile(self, ttFont): 26 self.glyphName = ttFont.getGlyphName(self.gid) 27 if self.rawdata is None: 28 from fontTools import ttLib 29 raise(ttLib.TTLibError, "No table data to decompile.") 30 if len(self.rawdata) > 0: 31 if len(self.rawdata) < sbixBitmapHeaderFormatSize: 32 from fontTools import ttLib 33 #print "Bitmap %i header too short: Expected %x, got %x." % (self.gid, sbixBitmapHeaderFormatSize, len(self.rawdata)) 34 raise(ttLib.TTLibError, "Bitmap header too short.") 35 36 sstruct.unpack(sbixBitmapHeaderFormat, self.rawdata[:sbixBitmapHeaderFormatSize], self) 37 38 if self.imageFormatTag == "dupe": 39 # bitmap is a reference to another glyph's bitmap 40 gid, = struct.unpack(">H", self.rawdata[sbixBitmapHeaderFormatSize:]) 41 self.referenceGlyphName = ttFont.getGlyphName(gid) 42 else: 43 self.imageData = self.rawdata[sbixBitmapHeaderFormatSize:] 44 self.referenceGlyphName = None 45 # clean up 46 del self.rawdata 47 del self.gid 48 49 def compile(self, ttFont): 50 if self.glyphName is None: 51 from fontTools import ttLib 52 raise ttLib.TTLibError, "Can't compile bitmap without glyph name" 53 # TODO: if ttFont has no maxp, cmap etc., ignore glyph names and compile by index? 54 # (needed if you just want to compile the sbix table on its own) 55 self.gid = struct.pack(">H", ttFont.getGlyphID(self.glyphName)) 56 if self.imageFormatTag is None: 57 self.rawdata = "" 58 else: 59 self.rawdata = sstruct.pack(sbixBitmapHeaderFormat, self) + self.imageData 60 61 def toXML(self, xmlWriter, ttFont): 62 if self.imageFormatTag == None: 63 # TODO: ignore empty bitmaps? 64 # a bitmap entry is required for each glyph, 65 # but empty ones can be calculated at compile time 66 xmlWriter.simpletag("bitmap", glyphname=self.glyphName) 67 xmlWriter.newline() 68 return 69 xmlWriter.begintag("bitmap", format=self.imageFormatTag, glyphname=self.glyphName) 70 xmlWriter.newline() 71 #xmlWriter.simpletag("usReserved1", value=self.usReserved1) 72 #xmlWriter.newline() 73 #xmlWriter.simpletag("usReserved2", value=self.usReserved2) 74 #xmlWriter.newline() 75 if self.imageFormatTag == "dupe": 76 # format == "dupe" is apparently a reference to another glyph id. 77 xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName) 78 else: 79 xmlWriter.begintag("hexdata") 80 xmlWriter.newline() 81 xmlWriter.dumphex(self.imageData) 82 xmlWriter.endtag("hexdata") 83 xmlWriter.newline() 84 xmlWriter.endtag("bitmap") 85 xmlWriter.newline() 86 87 def fromXML(self, (name, attrs, content), ttFont): 88 #if name in ["usReserved1", "usReserved2"]: 89 # setattr(self, name, int(attrs["value"])) 90 #elif 91 if name == "ref": 92 # bitmap is a "dupe", i.e. a reference to another bitmap. 93 # in this case imageData contains the glyph id of the reference glyph 94 # get glyph id from glyphname 95 self.imageData = struct.pack(">H", ttFont.getGlyphID(attrs["glyphname"])) 96 elif name == "hexdata": 97 self.imageData = readHex(content) 98 else: 99 from fontTools import ttLib 100 raise ttLib.TTLibError, "can't handle '%s' element" % name 101