118 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
| from fontTools.misc import sstruct
 | |
| from fontTools.misc.textTools import readHex, safeEval
 | |
| import struct
 | |
| 
 | |
| 
 | |
| sbixGlyphHeaderFormat = """
 | |
| 	>
 | |
| 	originOffsetX: h	# The x-value of the point in the glyph relative to its
 | |
| 						# lower-left corner which corresponds to the origin of
 | |
| 						# the glyph on the screen, that is the point on the
 | |
| 						# baseline at the left edge of the glyph.
 | |
| 	originOffsetY: h	# The y-value of the point in the glyph relative to its
 | |
| 						# lower-left corner which corresponds to the origin of
 | |
| 						# the glyph on the screen, that is the point on the
 | |
| 						# baseline at the left edge of the glyph.
 | |
| 	graphicType:  4s	# e.g. "png "
 | |
| """
 | |
| 
 | |
| sbixGlyphHeaderFormatSize = sstruct.calcsize(sbixGlyphHeaderFormat)
 | |
| 
 | |
| 
 | |
| class Glyph(object):
 | |
| 	def __init__(self, glyphName=None, referenceGlyphName=None, originOffsetX=0, originOffsetY=0, graphicType=None, imageData=None, rawdata=None, gid=0):
 | |
| 		self.gid = gid
 | |
| 		self.glyphName = glyphName
 | |
| 		self.referenceGlyphName = referenceGlyphName
 | |
| 		self.originOffsetX = originOffsetX
 | |
| 		self.originOffsetY = originOffsetY
 | |
| 		self.rawdata = rawdata
 | |
| 		self.graphicType = graphicType
 | |
| 		self.imageData = imageData
 | |
| 
 | |
| 		# fix self.graphicType if it is null terminated or too short
 | |
| 		if self.graphicType is not None:
 | |
| 			if self.graphicType[-1] == "\0":
 | |
| 				self.graphicType = self.graphicType[:-1]
 | |
| 			if len(self.graphicType) > 4:
 | |
| 				from fontTools import ttLib
 | |
| 				raise ttLib.TTLibError("Glyph.graphicType must not be longer than 4 characters.")
 | |
| 			elif len(self.graphicType) < 4:
 | |
| 				# pad with spaces
 | |
| 				self.graphicType += "    "[:(4 - len(self.graphicType))]
 | |
| 
 | |
| 	def decompile(self, ttFont):
 | |
| 		self.glyphName = ttFont.getGlyphName(self.gid)
 | |
| 		if self.rawdata is None:
 | |
| 			from fontTools import ttLib
 | |
| 			raise ttLib.TTLibError("No table data to decompile")
 | |
| 		if len(self.rawdata) > 0:
 | |
| 			if len(self.rawdata) < sbixGlyphHeaderFormatSize:
 | |
| 				from fontTools import ttLib
 | |
| 				#print "Glyph %i header too short: Expected %x, got %x." % (self.gid, sbixGlyphHeaderFormatSize, len(self.rawdata))
 | |
| 				raise ttLib.TTLibError("Glyph header too short.")
 | |
| 
 | |
| 			sstruct.unpack(sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self)
 | |
| 
 | |
| 			if self.graphicType == "dupe":
 | |
| 				# this glyph is a reference to another glyph's image data
 | |
| 				gid, = struct.unpack(">H", self.rawdata[sbixGlyphHeaderFormatSize:])
 | |
| 				self.referenceGlyphName = ttFont.getGlyphName(gid)
 | |
| 			else:
 | |
| 				self.imageData = self.rawdata[sbixGlyphHeaderFormatSize:]
 | |
| 				self.referenceGlyphName = None
 | |
| 		# clean up
 | |
| 		del self.rawdata
 | |
| 		del self.gid
 | |
| 
 | |
| 	def compile(self, ttFont):
 | |
| 		if self.glyphName is None:
 | |
| 			from fontTools import ttLib
 | |
| 			raise ttLib.TTLibError("Can't compile Glyph without glyph name")
 | |
| 			# TODO: if ttFont has no maxp, cmap etc., ignore glyph names and compile by index?
 | |
| 			# (needed if you just want to compile the sbix table on its own)
 | |
| 		self.gid = struct.pack(">H", ttFont.getGlyphID(self.glyphName))
 | |
| 		if self.graphicType is None:
 | |
| 			self.rawdata = b""
 | |
| 		else:
 | |
| 			self.rawdata = sstruct.pack(sbixGlyphHeaderFormat, self) + self.imageData
 | |
| 
 | |
| 	def toXML(self, xmlWriter, ttFont):
 | |
| 		if self.graphicType == None:
 | |
| 			# TODO: ignore empty glyphs?
 | |
| 			# a glyph data entry is required for each glyph,
 | |
| 			# but empty ones can be calculated at compile time
 | |
| 			xmlWriter.simpletag("glyph", name=self.glyphName)
 | |
| 			xmlWriter.newline()
 | |
| 			return
 | |
| 		xmlWriter.begintag("glyph",
 | |
| 			graphicType=self.graphicType,
 | |
| 			name=self.glyphName,
 | |
| 			originOffsetX=self.originOffsetX,
 | |
| 			originOffsetY=self.originOffsetY,
 | |
| 		)
 | |
| 		xmlWriter.newline()
 | |
| 		if self.graphicType == "dupe":
 | |
| 			# graphicType == "dupe" is a reference to another glyph id.
 | |
| 			xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName)
 | |
| 		else:
 | |
| 			xmlWriter.begintag("hexdata")
 | |
| 			xmlWriter.newline()
 | |
| 			xmlWriter.dumphex(self.imageData)
 | |
| 			xmlWriter.endtag("hexdata")
 | |
| 		xmlWriter.newline()
 | |
| 		xmlWriter.endtag("glyph")
 | |
| 		xmlWriter.newline()
 | |
| 
 | |
| 	def fromXML(self, name, attrs, content, ttFont):
 | |
| 		if name == "ref":
 | |
| 			# glyph is a "dupe", i.e. a reference to another glyph's image data.
 | |
| 			# in this case imageData contains the glyph id of the reference glyph
 | |
| 			# get glyph id from glyphname
 | |
| 			self.imageData = struct.pack(">H", ttFont.getGlyphID(safeEval("'''" + attrs["glyphname"] + "'''")))
 | |
| 		elif name == "hexdata":
 | |
| 			self.imageData = readHex(content)
 | |
| 		else:
 | |
| 			from fontTools import ttLib
 | |
| 			raise ttLib.TTLibError("can't handle '%s' element" % name)
 |