_h_m_t_x.py revision 1b7d54fedc29a9863250dc5486dcd86ed6f70a23
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import DefaultTable 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import numpy 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from fontTools import ttLib 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from fontTools.misc.textTools import safeEval 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class table__h_m_t_x(DefaultTable.DefaultTable): 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch headerTag = 'hhea' 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) advanceName = 'width' 1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) sideBearingName = 'lsb' 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numberOfMetricsName = 'numberOfHMetrics' 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def decompile(self, data, ttFont): 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName)) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metrics = numpy.fromstring(data[:4 * numberOfMetrics], 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numpy.int16) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if sys.byteorder <> "big": 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metrics = metrics.byteswap() 2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) metrics.shape = (numberOfMetrics, 2) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data[4 * numberOfMetrics:] 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numberOfSideBearings = ttFont['maxp'].numGlyphs - numberOfMetrics 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numberOfSideBearings = int(numberOfSideBearings) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if numberOfSideBearings: 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert numberOfSideBearings > 0, "bad hmtx/vmtx table" 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) lastAdvance = metrics[-1][0] 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) advances = numpy.array([lastAdvance] * numberOfSideBearings, 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch numpy.int16) 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch sideBearings = numpy.fromstring(data[:2 * numberOfSideBearings], 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch numpy.int16) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if sys.byteorder <> "big": 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sideBearings = sideBearings.byteswap() 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data[2 * numberOfSideBearings:] 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) additionalMetrics = numpy.array([advances, sideBearings], 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numpy.int16) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) metrics = numpy.concatenate((metrics, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numpy.transpose(additionalMetrics))) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if data: 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.stderr.write("too much data for hmtx/vmtx table\n") 41 metrics = metrics.tolist() 42 self.metrics = {} 43 for i in range(len(metrics)): 44 glyphName = ttFont.getGlyphName(i) 45 self.metrics[glyphName] = metrics[i] 46 47 def compile(self, ttFont): 48 metrics = [] 49 for glyphName in ttFont.getGlyphOrder(): 50 metrics.append(self.metrics[glyphName]) 51 lastAdvance = metrics[-1][0] 52 lastIndex = len(metrics) 53 while metrics[lastIndex-2][0] == lastAdvance: 54 lastIndex = lastIndex - 1 55 if lastIndex <= 1: 56 # all advances are equal 57 lastIndex = 1 58 break 59 additionalMetrics = metrics[lastIndex:] 60 additionalMetrics = map(lambda (advance, sb): sb, additionalMetrics) 61 metrics = metrics[:lastIndex] 62 setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics)) 63 64 metrics = numpy.array(metrics, numpy.int16) 65 if sys.byteorder <> "big": 66 metrics = metrics.byteswap() 67 data = metrics.tostring() 68 69 additionalMetrics = numpy.array(additionalMetrics, numpy.int16) 70 if sys.byteorder <> "big": 71 additionalMetrics = additionalMetrics.byteswap() 72 data = data + additionalMetrics.tostring() 73 return data 74 75 def toXML(self, writer, ttFont): 76 names = self.metrics.keys() 77 names.sort() 78 for glyphName in names: 79 advance, sb = self.metrics[glyphName] 80 writer.simpletag("mtx", [ 81 ("name", glyphName), 82 (self.advanceName, advance), 83 (self.sideBearingName, sb), 84 ]) 85 writer.newline() 86 87 def fromXML(self, (name, attrs, content), ttFont): 88 if not hasattr(self, "metrics"): 89 self.metrics = {} 90 if name == "mtx": 91 self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]), 92 safeEval(attrs[self.sideBearingName])] 93 94 def __getitem__(self, glyphName): 95 return self.metrics[glyphName] 96 97 def __setitem__(self, glyphName, (advance, sb)): 98 self.metrics[glyphName] = advance, sb 99 100