1from __future__ import print_function, division, absolute_import 2from fontTools.misc.py23 import * 3from fontTools.misc import sstruct 4from fontTools.misc.textTools import readHex, safeEval 5import struct 6 7 8sbixGlyphHeaderFormat = """ 9 > 10 originOffsetX: h # The x-value of the point in the glyph relative to its 11 # lower-left corner which corresponds to the origin of 12 # the glyph on the screen, that is the point on the 13 # baseline at the left edge of the glyph. 14 originOffsetY: h # The y-value of the point in the glyph relative to its 15 # lower-left corner which corresponds to the origin of 16 # the glyph on the screen, that is the point on the 17 # baseline at the left edge of the glyph. 18 graphicType: 4s # e.g. "png " 19""" 20 21sbixGlyphHeaderFormatSize = sstruct.calcsize(sbixGlyphHeaderFormat) 22 23 24class Glyph(object): 25 def __init__(self, glyphName=None, referenceGlyphName=None, originOffsetX=0, originOffsetY=0, graphicType=None, imageData=None, rawdata=None, gid=0): 26 self.gid = gid 27 self.glyphName = glyphName 28 self.referenceGlyphName = referenceGlyphName 29 self.originOffsetX = originOffsetX 30 self.originOffsetY = originOffsetY 31 self.rawdata = rawdata 32 self.graphicType = graphicType 33 self.imageData = imageData 34 35 # fix self.graphicType if it is null terminated or too short 36 if self.graphicType is not None: 37 if self.graphicType[-1] == "\0": 38 self.graphicType = self.graphicType[:-1] 39 if len(self.graphicType) > 4: 40 from fontTools import ttLib 41 raise ttLib.TTLibError("Glyph.graphicType must not be longer than 4 characters.") 42 elif len(self.graphicType) < 4: 43 # pad with spaces 44 self.graphicType += " "[:(4 - len(self.graphicType))] 45 46 def decompile(self, ttFont): 47 self.glyphName = ttFont.getGlyphName(self.gid) 48 if self.rawdata is None: 49 from fontTools import ttLib 50 raise ttLib.TTLibError("No table data to decompile") 51 if len(self.rawdata) > 0: 52 if len(self.rawdata) < sbixGlyphHeaderFormatSize: 53 from fontTools import ttLib 54 #print "Glyph %i header too short: Expected %x, got %x." % (self.gid, sbixGlyphHeaderFormatSize, len(self.rawdata)) 55 raise ttLib.TTLibError("Glyph header too short.") 56 57 sstruct.unpack(sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self) 58 59 if self.graphicType == "dupe": 60 # this glyph is a reference to another glyph's image data 61 gid, = struct.unpack(">H", self.rawdata[sbixGlyphHeaderFormatSize:]) 62 self.referenceGlyphName = ttFont.getGlyphName(gid) 63 else: 64 self.imageData = self.rawdata[sbixGlyphHeaderFormatSize:] 65 self.referenceGlyphName = None 66 # clean up 67 del self.rawdata 68 del self.gid 69 70 def compile(self, ttFont): 71 if self.glyphName is None: 72 from fontTools import ttLib 73 raise ttLib.TTLibError("Can't compile Glyph without glyph name") 74 # TODO: if ttFont has no maxp, cmap etc., ignore glyph names and compile by index? 75 # (needed if you just want to compile the sbix table on its own) 76 self.gid = struct.pack(">H", ttFont.getGlyphID(self.glyphName)) 77 if self.graphicType is None: 78 self.rawdata = b"" 79 else: 80 self.rawdata = sstruct.pack(sbixGlyphHeaderFormat, self) + self.imageData 81 82 def toXML(self, xmlWriter, ttFont): 83 if self.graphicType == None: 84 # TODO: ignore empty glyphs? 85 # a glyph data entry is required for each glyph, 86 # but empty ones can be calculated at compile time 87 xmlWriter.simpletag("glyph", name=self.glyphName) 88 xmlWriter.newline() 89 return 90 xmlWriter.begintag("glyph", 91 graphicType=self.graphicType, 92 name=self.glyphName, 93 originOffsetX=self.originOffsetX, 94 originOffsetY=self.originOffsetY, 95 ) 96 xmlWriter.newline() 97 if self.graphicType == "dupe": 98 # graphicType == "dupe" is a reference to another glyph id. 99 xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName) 100 else: 101 xmlWriter.begintag("hexdata") 102 xmlWriter.newline() 103 xmlWriter.dumphex(self.imageData) 104 xmlWriter.endtag("hexdata") 105 xmlWriter.newline() 106 xmlWriter.endtag("glyph") 107 xmlWriter.newline() 108 109 def fromXML(self, name, attrs, content, ttFont): 110 if name == "ref": 111 # glyph is a "dupe", i.e. a reference to another glyph's image data. 112 # in this case imageData contains the glyph id of the reference glyph 113 # get glyph id from glyphname 114 self.imageData = struct.pack(">H", ttFont.getGlyphID(safeEval("'''" + attrs["glyphname"] + "'''"))) 115 elif name == "hexdata": 116 self.imageData = readHex(content) 117 else: 118 from fontTools import ttLib 119 raise ttLib.TTLibError("can't handle '%s' element" % name) 120