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