• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc import sstruct
2from fontTools.misc.textTools import safeEval, num2binary, binary2num
3from . import DefaultTable
4from .sbixStrike import Strike
5
6
7sbixHeaderFormat = """
8	>
9	version:       H	# Version number (set to 1)
10	flags:         H	# The only two bits used in the flags field are bits 0
11						# and 1. For historical reasons, bit 0 must always be 1.
12						# Bit 1 is a sbixDrawOutlines flag and is interpreted as
13						# follows:
14						#     0: Draw only 'sbix' bitmaps
15						#     1: Draw both 'sbix' bitmaps and outlines, in that
16						#        order
17	numStrikes:    L	# Number of bitmap strikes to follow
18"""
19sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat)
20
21
22sbixStrikeOffsetFormat = """
23	>
24	strikeOffset:  L	# Offset from begining of table to data for the
25						# individual strike
26"""
27sbixStrikeOffsetFormatSize = sstruct.calcsize(sbixStrikeOffsetFormat)
28
29
30class table__s_b_i_x(DefaultTable.DefaultTable):
31
32	def __init__(self, tag=None):
33		DefaultTable.DefaultTable.__init__(self, tag)
34		self.version = 1
35		self.flags = 1
36		self.numStrikes = 0
37		self.strikes = {}
38		self.strikeOffsets = []
39
40	def decompile(self, data, ttFont):
41		# read table header
42		sstruct.unpack(sbixHeaderFormat, data[ : sbixHeaderFormatSize], self)
43		# collect offsets to individual strikes in self.strikeOffsets
44		for i in range(self.numStrikes):
45			current_offset = sbixHeaderFormatSize + i * sbixStrikeOffsetFormatSize
46			offset_entry = sbixStrikeOffset()
47			sstruct.unpack(sbixStrikeOffsetFormat, \
48				data[current_offset:current_offset+sbixStrikeOffsetFormatSize], \
49				offset_entry)
50			self.strikeOffsets.append(offset_entry.strikeOffset)
51
52		# decompile Strikes
53		for i in range(self.numStrikes-1, -1, -1):
54			current_strike = Strike(rawdata=data[self.strikeOffsets[i]:])
55			data = data[:self.strikeOffsets[i]]
56			current_strike.decompile(ttFont)
57			#print "  Strike length: %xh" % len(bitmapSetData)
58			#print "Number of Glyph entries:", len(current_strike.glyphs)
59			if current_strike.ppem in self.strikes:
60				from fontTools import ttLib
61				raise ttLib.TTLibError("Pixel 'ppem' must be unique for each Strike")
62			self.strikes[current_strike.ppem] = current_strike
63
64		# after the glyph data records have been extracted, we don't need the offsets anymore
65		del self.strikeOffsets
66		del self.numStrikes
67
68	def compile(self, ttFont):
69		sbixData = b""
70		self.numStrikes = len(self.strikes)
71		sbixHeader = sstruct.pack(sbixHeaderFormat, self)
72
73		# calculate offset to start of first strike
74		setOffset = sbixHeaderFormatSize + sbixStrikeOffsetFormatSize * self.numStrikes
75
76		for si in sorted(self.strikes.keys()):
77			current_strike = self.strikes[si]
78			current_strike.compile(ttFont)
79			# append offset to this strike to table header
80			current_strike.strikeOffset = setOffset
81			sbixHeader += sstruct.pack(sbixStrikeOffsetFormat, current_strike)
82			setOffset += len(current_strike.data)
83			sbixData += current_strike.data
84
85		return sbixHeader + sbixData
86
87	def toXML(self, xmlWriter, ttFont):
88		xmlWriter.simpletag("version", value=self.version)
89		xmlWriter.newline()
90		xmlWriter.simpletag("flags", value=num2binary(self.flags, 16))
91		xmlWriter.newline()
92		for i in sorted(self.strikes.keys()):
93			self.strikes[i].toXML(xmlWriter, ttFont)
94
95	def fromXML(self, name, attrs, content, ttFont):
96		if name =="version":
97			setattr(self, name, safeEval(attrs["value"]))
98		elif name == "flags":
99			setattr(self, name, binary2num(attrs["value"]))
100		elif name == "strike":
101			current_strike = Strike()
102			for element in content:
103				if isinstance(element, tuple):
104					name, attrs, content = element
105					current_strike.fromXML(name, attrs, content, ttFont)
106			self.strikes[current_strike.ppem] = current_strike
107		else:
108			from fontTools import ttLib
109			raise ttLib.TTLibError("can't handle '%s' element" % name)
110
111
112# Helper classes
113
114class sbixStrikeOffset(object):
115	pass
116