• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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