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