1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.misc import sstruct
4from fontTools.misc.textTools import readHex
5from . import DefaultTable
6from .sbixBitmap import *
7from .sbixBitmapSet import *
8import struct
9
10"""
11sbix Table organization:
12
13USHORT        version?
14USHORT        version?
15USHORT        count                    number of bitmap sets
16offsetEntry   offsetEntry[count]       offsetEntries
17(Variable)    storage for bitmap sets
18
19
20offsetEntry:
21
22ULONG         offset                   offset from table start to bitmap set
23
24
25bitmap set:
26
27USHORT        size                     height and width in pixels
28USHORT        resolution               ?
29offsetRecord  offsetRecord[]
30(Variable)    storage for bitmaps
31
32
33offsetRecord:
34
35ULONG         bitmapOffset             offset from start of bitmap set to individual bitmap
36
37
38bitmap:
39
40ULONG         reserved                 00 00 00 00
41char[4]       format                   data type, e.g. "png "
42(Variable)    bitmap data
43"""
44
45sbixHeaderFormat = """
46	>
47	usVal1:          H    # 00 01
48	usVal2:          H    #       00 01
49	numSets:         L    # 00 00 00 02 # number of bitmap sets
50"""
51sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat)
52
53
54sbixBitmapSetOffsetFormat = """
55	>
56	offset:          L    # 00 00 00 10 # offset from table start to each bitmap set
57"""
58sbixBitmapSetOffsetFormatSize = sstruct.calcsize(sbixBitmapSetOffsetFormat)
59
60
61class table__s_b_i_x(DefaultTable.DefaultTable):
62	def __init__(self, tag):
63		self.tableTag = tag
64		self.usVal1 = 1
65		self.usVal2 = 1
66		self.numSets = 0
67		self.bitmapSets = {}
68		self.bitmapSetOffsets = []
69
70	def decompile(self, data, ttFont):
71		# read table header
72		sstruct.unpack(sbixHeaderFormat, data[ : sbixHeaderFormatSize], self)
73		# collect offsets to individual bitmap sets in self.bitmapSetOffsets
74		for i in range(self.numSets):
75			myOffset = sbixHeaderFormatSize + i * sbixBitmapSetOffsetFormatSize
76			offsetEntry = sbixBitmapSetOffset()
77			sstruct.unpack(sbixBitmapSetOffsetFormat, \
78				data[myOffset : myOffset+sbixBitmapSetOffsetFormatSize], \
79				offsetEntry)
80			self.bitmapSetOffsets.append(offsetEntry.offset)
81
82		# decompile BitmapSets
83		for i in range(self.numSets-1, -1, -1):
84			myBitmapSet = BitmapSet(rawdata=data[self.bitmapSetOffsets[i]:])
85			data = data[:self.bitmapSetOffsets[i]]
86			myBitmapSet.decompile(ttFont)
87			#print "  BitmapSet length: %xh" % len(bitmapSetData)
88			#print "Number of Bitmaps:", myBitmapSet.numBitmaps
89			if myBitmapSet.size in self.bitmapSets:
90				from fontTools import ttLib
91				raise ttLib.TTLibError("Pixel 'size' must be unique for each BitmapSet")
92			self.bitmapSets[myBitmapSet.size] = myBitmapSet
93
94		# after the bitmaps have been extracted, we don't need the offsets anymore
95		del self.bitmapSetOffsets
96
97	def compile(self, ttFont):
98		sbixData = ""
99		self.numSets = len(self.bitmapSets)
100		sbixHeader = sstruct.pack(sbixHeaderFormat, self)
101
102		# calculate offset to start of first bitmap set
103		setOffset = sbixHeaderFormatSize + sbixBitmapSetOffsetFormatSize * self.numSets
104
105		for si in sorted(self.bitmapSets.keys()):
106			myBitmapSet = self.bitmapSets[si]
107			myBitmapSet.compile(ttFont)
108			# append offset to this bitmap set to table header
109			myBitmapSet.offset = setOffset
110			sbixHeader += sstruct.pack(sbixBitmapSetOffsetFormat, myBitmapSet)
111			setOffset += sbixBitmapSetHeaderFormatSize + len(myBitmapSet.data)
112			sbixData += myBitmapSet.data
113
114		return sbixHeader + sbixData
115
116	def toXML(self, xmlWriter, ttFont):
117		xmlWriter.simpletag("usVal1", value=self.usVal1)
118		xmlWriter.newline()
119		xmlWriter.simpletag("usVal2", value=self.usVal2)
120		xmlWriter.newline()
121		for i in sorted(self.bitmapSets.keys()):
122			self.bitmapSets[i].toXML(xmlWriter, ttFont)
123
124	def fromXML(self, name, attrs, content, ttFont):
125		if name in ["usVal1", "usVal2"]:
126			setattr(self, name, int(attrs["value"]))
127		elif name == "bitmapSet":
128			myBitmapSet = BitmapSet()
129			for element in content:
130				if isinstance(element, tuple):
131					name, attrs, content = element
132					myBitmapSet.fromXML(name, attrs, content, ttFont)
133			self.bitmapSets[myBitmapSet.size] = myBitmapSet
134		else:
135			from fontTools import ttLib
136			raise ttLib.TTLibError("can't handle '%s' element" % name)
137
138
139# Helper classes
140
141class sbixBitmapSetOffset(object):
142	pass
143