_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