_h_m_t_x.py revision 3de0e58f294263cd5d0b18aab95e267e8abc2689
1import sys 2import DefaultTable 3import numpy 4from fontTools import ttLib 5from fontTools.misc.textTools import safeEval 6import warnings 7 8 9class table__h_m_t_x(DefaultTable.DefaultTable): 10 11 headerTag = 'hhea' 12 advanceName = 'width' 13 sideBearingName = 'lsb' 14 numberOfMetricsName = 'numberOfHMetrics' 15 16 def decompile(self, data, ttFont): 17 numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName)) 18 metrics = numpy.fromstring(data[:4 * numberOfMetrics], 19 numpy.int16) 20 if sys.byteorder <> "big": 21 metrics = metrics.byteswap() 22 metrics.shape = (numberOfMetrics, 2) 23 data = data[4 * numberOfMetrics:] 24 numberOfSideBearings = ttFont['maxp'].numGlyphs - numberOfMetrics 25 numberOfSideBearings = int(numberOfSideBearings) 26 if numberOfSideBearings: 27 assert numberOfSideBearings > 0, "bad hmtx/vmtx table" 28 lastAdvance = metrics[-1][0] 29 advances = numpy.array([lastAdvance] * numberOfSideBearings, 30 numpy.int16) 31 sideBearings = numpy.fromstring(data[:2 * numberOfSideBearings], 32 numpy.int16) 33 if sys.byteorder <> "big": 34 sideBearings = sideBearings.byteswap() 35 data = data[2 * numberOfSideBearings:] 36 if len(advances) and len(sideBearings): 37 additionalMetrics = numpy.array([advances, sideBearings], numpy.int16) 38 metrics = numpy.concatenate((metrics, numpy.transpose(additionalMetrics))) 39 else: 40 warnings.warn('Unable to include additional metrics') 41 if data: 42 sys.stderr.write("too much data for hmtx/vmtx table\n") 43 metrics = metrics.tolist() 44 self.metrics = {} 45 for i in range(len(metrics)): 46 glyphName = ttFont.getGlyphName(i) 47 self.metrics[glyphName] = metrics[i] 48 49 def compile(self, ttFont): 50 metrics = [] 51 for glyphName in ttFont.getGlyphOrder(): 52 metrics.append(self.metrics[glyphName]) 53 lastAdvance = metrics[-1][0] 54 lastIndex = len(metrics) 55 while metrics[lastIndex-2][0] == lastAdvance: 56 lastIndex = lastIndex - 1 57 if lastIndex <= 1: 58 # all advances are equal 59 lastIndex = 1 60 break 61 additionalMetrics = metrics[lastIndex:] 62 additionalMetrics = map(lambda (advance, sb): sb, additionalMetrics) 63 metrics = metrics[:lastIndex] 64 setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics)) 65 66 metrics = numpy.array(metrics, numpy.int16) 67 if sys.byteorder <> "big": 68 metrics = metrics.byteswap() 69 data = metrics.tostring() 70 71 additionalMetrics = numpy.array(additionalMetrics, numpy.int16) 72 if sys.byteorder <> "big": 73 additionalMetrics = additionalMetrics.byteswap() 74 data = data + additionalMetrics.tostring() 75 return data 76 77 def toXML(self, writer, ttFont): 78 names = self.metrics.keys() 79 names.sort() 80 for glyphName in names: 81 advance, sb = self.metrics[glyphName] 82 writer.simpletag("mtx", [ 83 ("name", glyphName), 84 (self.advanceName, advance), 85 (self.sideBearingName, sb), 86 ]) 87 writer.newline() 88 89 def fromXML(self, (name, attrs, content), ttFont): 90 if not hasattr(self, "metrics"): 91 self.metrics = {} 92 if name == "mtx": 93 self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]), 94 safeEval(attrs[self.sideBearingName])] 95 96 def __getitem__(self, glyphName): 97 return self.metrics[glyphName] 98 99 def __setitem__(self, glyphName, (advance, sb)): 100 self.metrics[glyphName] = advance, sb 101 102