sbixBitmap.py revision 4801a3ae39bfd79b05e3bb00245c06ab5e09d622
1import struct, sstruct
2from fontTools.misc.textTools import readHex
3
4sbixBitmapHeaderFormat = """
5	>
6	usReserved1:     H    # 00 00
7	usReserved2:     H    #       00 00
8	imageFormatTag:  4s   # e.g. "png "
9"""
10
11sbixBitmapHeaderFormatSize = sstruct.calcsize(sbixBitmapHeaderFormat)
12
13
14class Bitmap(object):
15	def __init__(self, glyphName=None, referenceGlyphName=None, usReserved1=0, usReserved2=0, imageFormatTag=None, imageData=None, rawdata=None, gid=0):
16		self.gid = gid
17		self.glyphName = glyphName
18		self.referenceGlyphName = referenceGlyphName
19		self.usReserved1 = usReserved1
20		self.usReserved2 = usReserved2
21		self.rawdata = rawdata
22		self.imageFormatTag = imageFormatTag
23		self.imageData = imageData
24
25	def decompile(self, ttFont):
26		self.glyphName = ttFont.getGlyphName(self.gid)
27		if self.rawdata is None:
28			from fontTools import ttLib
29			raise(ttLib.TTLibError, "No table data to decompile.")
30		if len(self.rawdata) > 0:
31			if len(self.rawdata) < sbixBitmapHeaderFormatSize:
32				from fontTools import ttLib
33				#print "Bitmap %i header too short: Expected %x, got %x." % (self.gid, sbixBitmapHeaderFormatSize, len(self.rawdata))
34				raise(ttLib.TTLibError, "Bitmap header too short.")
35
36			sstruct.unpack(sbixBitmapHeaderFormat, self.rawdata[:sbixBitmapHeaderFormatSize], self)
37
38			if self.imageFormatTag == "dupe":
39				# bitmap is a reference to another glyph's bitmap
40				gid, = struct.unpack(">H", self.rawdata[sbixBitmapHeaderFormatSize:])
41				self.referenceGlyphName = ttFont.getGlyphName(gid)
42			else:
43				self.imageData = self.rawdata[sbixBitmapHeaderFormatSize:]
44				self.referenceGlyphName = None
45		# clean up
46		del self.rawdata
47		del self.gid
48
49	def compile(self, ttFont):
50		if self.glyphName is None:
51			from fontTools import ttLib
52			raise ttLib.TTLibError, "Can't compile bitmap without glyph name"
53			# TODO: if ttFont has no maxp, cmap etc., ignore glyph names and compile by index?
54			# (needed if you just want to compile the sbix table on its own)
55		self.gid = struct.pack(">H", ttFont.getGlyphID(self.glyphName))
56		if self.imageFormatTag is None:
57			self.rawdata = ""
58		else:
59			self.rawdata = sstruct.pack(sbixBitmapHeaderFormat, self) + self.imageData
60
61	def toXML(self, xmlWriter, ttFont):
62		if self.imageFormatTag == None:
63			# TODO: ignore empty bitmaps?
64			# a bitmap entry is required for each glyph,
65			# but empty ones can be calculated at compile time
66			xmlWriter.simpletag("bitmap", glyphname=self.glyphName)
67			xmlWriter.newline()
68			return
69		xmlWriter.begintag("bitmap", format=self.imageFormatTag, glyphname=self.glyphName)
70		xmlWriter.newline()
71		#xmlWriter.simpletag("usReserved1", value=self.usReserved1)
72		#xmlWriter.newline()
73		#xmlWriter.simpletag("usReserved2", value=self.usReserved2)
74		#xmlWriter.newline()
75		if self.imageFormatTag == "dupe":
76			# format == "dupe" is apparently a reference to another glyph id.
77			xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName)
78		else:
79			xmlWriter.begintag("hexdata")
80			xmlWriter.newline()
81			xmlWriter.dumphex(self.imageData)
82			xmlWriter.endtag("hexdata")
83		xmlWriter.newline()
84		xmlWriter.endtag("bitmap")
85		xmlWriter.newline()
86
87	def fromXML(self, (name, attrs, content), ttFont):
88		#if name in ["usReserved1", "usReserved2"]:
89		#	setattr(self, name, int(attrs["value"]))
90		#elif
91		if name == "ref":
92			# bitmap is a "dupe", i.e. a reference to another bitmap.
93			# in this case imageData contains the glyph id of the reference glyph
94			# get glyph id from glyphname
95			self.imageData = struct.pack(">H", ttFont.getGlyphID(attrs["glyphname"]))
96		elif name == "hexdata":
97			self.imageData = readHex(content)
98		else:
99			from fontTools import ttLib
100			raise ttLib.TTLibError, "can't handle '%s' element" % name
101