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