def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Prop object to the specified LinkedWriter. >>> GP = Prop.GP >>> p1 = GP() >>> p2 = GP(floater=True) >>> d = Prop.fromkeys(range(20), p1) >>> d[12] = d[13] = d[14] = p2 >>> utilities.hexdump(d.binaryString()) 0 | 0003 0000 0001 0000 0008 000C 0003 8000 |................| 10 | 8000 8000 |.... | >>> d = Prop.fromkeys(range(50), p1) >>> d[4] = d[42] = d[43] = d[44] = p2 >>> utilities.hexdump(d.binaryString()) 0 | 0003 0000 0001 0000 0002 0006 0002 000C |................| 10 | 0001 0000 0004 0004 8000 002C 002A 8000 |...........,.*..| 20 | FFFF FFFF 0000 |...... | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() w.add("L", self.tableVersion) fan = self.GP.asNumber d = {k: fan(gp, glyphIndex=k) for k, gp in self.items()} valueToCount = collections.defaultdict(int) for n in d.values(): valueToCount[n] += 1 if len(valueToCount) == 1: w.add("2H", 0, next(iter(valueToCount))) return freq = sorted(valueToCount.items(), key=operator.itemgetter(1), reverse=True) default = freq[0][0] w.add("2H", 1, default) d = {k: n for k, n in d.items() if n != default} lookup.Lookup(d).buildBinary(w, sentinelValue=0)
def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Bsln object to the specified LinkedWriter. >>> utilities.hexdump(_testingValues[0].binaryString()) 0 | 0001 0000 0000 0000 0000 0400 FFEC 0708 |................| 10 | 0384 0000 0000 0000 0000 0000 0000 0000 |................| 20 | 0000 0000 0000 0000 0000 0000 0000 0000 |................| 30 | 0000 0000 0000 0000 0000 0000 0000 0000 |................| 40 | 0000 0000 0000 0000 |........ | >>> utilities.hexdump(_testingValues[1].binaryString()) 0 | 0001 0000 0001 0000 0000 0400 FFEC 0708 |................| 10 | 0384 0000 0000 0000 0000 0000 0000 0000 |................| 20 | 0000 0000 0000 0000 0000 0000 0000 0000 |................| 30 | 0000 0000 0000 0000 0000 0000 0000 0000 |................| 40 | 0000 0000 0000 0000 0002 0006 0003 000C |................| 50 | 0001 0006 0006 0004 0001 000B 000B 0004 |................| 60 | 0014 0013 0001 FFFF FFFF 0000 |............ | >>> utilities.hexdump(_testingValues[2].binaryString()) 0 | 0001 0000 0002 0000 0020 0006 0002 0013 |......... ......| 10 | 0004 000E FFFF FFFF FFFF FFFF FFFF FFFF |................| 20 | FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF |................| 30 | FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF |................| 40 | FFFF FFFF FFFF FFFF FFFF |.......... | >>> utilities.hexdump(_testingValues[3].binaryString()) 0 | 0001 0000 0003 0000 0020 0006 0002 0013 |......... ......| 10 | 0004 000E FFFF FFFF FFFF FFFF FFFF FFFF |................| 20 | FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF |................| 30 | FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF |................| 40 | FFFF FFFF FFFF FFFF FFFF 0002 0006 0003 |................| 50 | 000C 0001 0006 0006 0004 0001 000B 000B |................| 60 | 0004 0014 0013 0001 FFFF FFFF 0000 |.............. | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() w.add("L", 0x10000) dCounts = collections.defaultdict(int) for value in self.values(): dCounts[int(value)] += 1 format = (0 if len(dCounts) == 1 else 1) if not self.positions.isDistance: format += 2 w.add("H", format) v = sorted(dCounts.items(), key=operator.itemgetter(1)) default = v[-1][0] w.add("H", default) self.positions.buildBinary(w, **kwArgs) if len(dCounts) > 1: lk = lookup.Lookup({g: n for g, n in self.items() if n != default}) lk.buildBinary(w, noGaps=True, sentinelValue=0)
def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Contextual object to the specified writer. The following keyword arguments are supported: preferredIOLookupFormat If you need the actual input glyph to output glyph lookup to be written in a specific format, use this keyword. The default (as usual for Lookup objects) is to use the smallest one possible. Note this keyword is usually specified in the perTableOptions dict passed into the Editor's writeFont() method. stakeValue A value that will stake the start of the data. This is optional. >>> h = utilities.hexdump >>> h(_testingValues[0].binaryString()) 0 | 0000 0006 0000 0034 0000 0052 0000 0076 |.......4...R...v| 10 | 0000 008E FEED 0002 0553 7761 7368 0754 |.........Swash.T| 20 | 7269 6767 6572 0001 0B53 6177 2074 7269 |rigger...Saw tri| 30 | 6767 6572 0002 0006 0002 000C 0001 0000 |gger............| 40 | 0019 0016 0004 0032 0032 0005 FFFF FFFF |.......2.2......| 50 | FFFF 0000 0000 0000 0000 0000 0001 0000 |................| 60 | 0000 0000 0000 0000 0001 0001 0001 0001 |................| 70 | 0001 0002 0001 0000 0000 FFFF FFFF 0002 |................| 80 | 0000 FFFF FFFF 0002 0000 FFFF 0000 0000 |................| 90 | 0004 0008 0016 0004 005F 0060 0061 0062 |........._.`.a.b| >>> d = {'preferredIOLookupFormat': 2} >>> h(_testingValues[0].binaryString(**d)) 0 | 0000 0006 0000 0034 0000 0052 0000 0076 |.......4...R...v| 10 | 0000 008E FEED 0002 0553 7761 7368 0754 |.........Swash.T| 20 | 7269 6767 6572 0001 0B53 6177 2074 7269 |rigger...Saw tri| 30 | 6767 6572 0002 0006 0002 000C 0001 0000 |gger............| 40 | 0019 0016 0004 0032 0032 0005 FFFF FFFF |.......2.2......| 50 | FFFF 0000 0000 0000 0000 0000 0001 0000 |................| 60 | 0000 0000 0000 0000 0001 0001 0001 0001 |................| 70 | 0001 0002 0001 0000 0000 FFFF FFFF 0002 |................| 80 | 0000 FFFF FFFF 0002 0000 FFFF 0000 0000 |................| 90 | 0004 0002 0006 0004 0018 0002 0000 0016 |................| A0 | 0016 005F 0017 0017 0060 0018 0018 0061 |..._.....`.....a| B0 | 0019 0019 0062 FFFF FFFF FFFF |.....b...... | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() nsObj = namestash.NameStash.fromstatedict(self) classNames = nsObj.allClassNames() revClassMap = {s: i for i, s in enumerate(classNames)} stateNames = nsObj.allStateNames() revStateMap = {s: i for i, s in enumerate(stateNames)} w.add("L", len(classNames)) ctStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, ctStake) saStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, saStake) etStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, etStake) gtStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, gtStake) kwArgs.pop('neededAlignment', None) kwArgs.pop('classDict', None) nsObj.buildBinary(w, neededAlignment=2, **kwArgs) self.classTable.buildBinary(w, stakeValue=ctStake, classDict=revClassMap, **kwArgs) w.stakeCurrentWithValue(saStake) entryPool = {} # immut -> (entryIndex, obj) for stateName in stateNames: row = self[stateName] for className in classNames: thisEntry = row[className] immut = thisEntry.asImmutable() if immut not in entryPool: entryPool[immut] = (len(entryPool), thisEntry) w.add("H", entryPool[immut][0]) w.stakeCurrentWithValue(etStake) lookupPool = {} # immut -> (lookupIndex, obj) it = sorted(entryPool.values(), key=operator.itemgetter(0)) for entryIndex, obj in it: w.add("H", revStateMap[obj.newState]) flags = (0x8000 if obj.mark else 0) flags += (0x4000 if obj.noAdvance else 0) w.add("H", flags) md = obj.markSubstitutionDict cd = obj.currSubstitutionDict if md: immut = md.asImmutable() if immut not in lookupPool: lookupPool[immut] = (len(lookupPool), md) w.add("H", lookupPool[immut][0]) else: w.add("h", -1) if cd: immut = cd.asImmutable() if immut not in lookupPool: lookupPool[immut] = (len(lookupPool), cd) w.add("H", lookupPool[immut][0]) else: w.add("h", -1) w.stakeCurrentWithValue(gtStake) v = sorted(lookupPool.values(), key=operator.itemgetter(0)) lookupStakes = [w.getNewStake() for obj in v] for stake in lookupStakes: w.addUnresolvedOffset("L", gtStake, stake) preferredFormat = kwArgs.get('preferredIOLookupFormat', None) for (lookupIndex, gd), stake in zip(v, lookupStakes): lkObj = lookup.Lookup(gd) if preferredFormat is not None: lkObj._preferredFormat = preferredFormat lkObj.buildBinary(w, stakeValue=stake)
def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Format2 object to the specified LinkedWriter. >>> _testingValues[1].pprint() ClassPair((1, 1)): -25 ClassPair((1, 2)): -10 ClassPair((2, 1)): 15 Left-hand classes: 15: 1 25: 1 35: 2 Right-hand classes: 9: 1 12: 1 15: 1 40: 2 Header information: Horizontal With-stream No variation kerning Process forward >>> utilities.hexdump(_testingValues[1].binaryString()) 0 | 0000 0006 0000 001C 0000 0038 0000 0058 |...........8...X| 10 | 0006 0004 0003 0008 0001 0004 000F 0006 |................| 20 | 0019 0006 0023 000C FFFF FFFF 0006 0004 |.....#..........| 30 | 0004 0010 0002 0000 0009 0002 000C 0002 |................| 40 | 000F 0002 0028 0004 FFFF FFFF 0000 0000 |.....(..........| 50 | 0000 0000 FFE7 FFF6 0000 000F 0000 |.............. | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() self = self._keysCompacted() leftUniques = set(self.leftClassDef.values()) rightUniques = set(self.rightClassDef.values()) nRows = 1 + len(leftUniques) nCols = 1 + len(rightUniques) rowBytes = nCols * 2 w.add("L", rowBytes) headerAdj = 12 leftLookup = lookup.Lookup( {i: j * rowBytes for i, j in self.leftClassDef.items()}) rightLookup = lookup.Lookup( {i: j * 2 for i, j in self.rightClassDef.items()}) leftStake = w.getNewStake() rightStake = w.getNewStake() arrayStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, leftStake, offsetByteDelta=headerAdj) w.addUnresolvedOffset("L", stakeValue, rightStake, offsetByteDelta=headerAdj) w.addUnresolvedOffset("L", stakeValue, arrayStake, offsetByteDelta=headerAdj) leftLookup.buildBinary(w, stakeValue=leftStake, **kwArgs) rightLookup.buildBinary(w, stakeValue=rightStake, **kwArgs) v = [0] * (nRows * nCols) CP = classpair.ClassPair for leftIndex in leftUniques: for rightIndex in rightUniques: key = CP([leftIndex, rightIndex]) if key in self: v[leftIndex * nCols + rightIndex] = self[key] w.stakeCurrentWithValue(arrayStake) w.addGroup("h", v)
def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Ankr object to the specified writer. The following keyword arguments are supported: preferredIOLookupFormat If you need the actual input glyph to output glyph lookup to be written in a specific format, use this keyword. The default (as usual for Lookup objects) is to use the smallest one possible. Note this keyword is usually specified in the perTableOptions dict passed into the Editor's writeFont() method. stakeValue A value that will stake the start of the data. This is optional. >>> utilities.hexdump(_testingValues[1].binaryString()) 0 | 0000 0000 0000 000C 0000 0030 0006 0004 |...........0....| 10 | 0005 0010 0002 0004 000A 001C 000B 0010 |................| 20 | 000E 001C 000F 001C 0064 0000 FFFF FFFF |.........d......| 30 | 0000 0003 FF38 0000 0000 0096 0000 FF06 |.....8..........| 40 | 0000 0002 0000 0000 0064 0000 0000 0002 |.........d......| 50 | 0064 FF9C 0102 0304 |.d...... | >>> d = {'preferredIOLookupFormat': 2} >>> utilities.hexdump(_testingValues[1].binaryString(**d)) 0 | 0000 0000 0000 000C 0000 003A 0002 0006 |...........:....| 10 | 0004 0018 0002 0000 000A 000A 001C 000B |................| 20 | 000B 0010 000F 000E 001C 0064 0064 0000 |...........d.d..| 30 | FFFF FFFF FFFF FFFF FFFF 0000 0003 FF38 |...............8| 40 | 0000 0000 0096 0000 FF06 0000 0002 0000 |................| 50 | 0000 0064 0000 0000 0002 0064 FF9C 0102 |...d.......d....| 60 | 0304 |.. | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() w.add("2H", 0, 0) # version, flags lookupStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, lookupStake) dataStake = w.getNewStake() w.addUnresolvedOffset("L", stakeValue, dataStake) w.stakeCurrentWithValue(lookupStake) # To build the lookup we first need to determine which format is # smallest. d = {} for glyph, obj in self.items(): immut = obj.asImmutable() d.setdefault(immut, set()).add(glyph) stakeDict = {} for immut, glyphSet in d.items(): sv = w.getNewStake() for glyph in glyphSet: stakeDict[glyph] = sv # For now, raise an error if the largest stake is >64K; if this ever # actually arises, we could remap the stakes temporarily. if max(stakeDict.values()) > 65535: raise ValueError("Too many stakes!") lk = lookup.Lookup(stakeDict) preferredFormat = kwArgs.get('preferredIOLookupFormat', None) if preferredFormat is None: bestFormat = lk.binaryString(noGaps=True)[1] lk._preferredFormat = bestFormat else: lk._preferredFormat = preferredFormat lk.buildBinary(w, baseStake=dataStake) # Now add the actual data w.stakeCurrentWithValue(dataStake) it = sorted(d.items(), key=operator.itemgetter(0)) for immut, glyphSet in it: glyph = glyphSet.pop() self[glyph].buildBinary(w, stakeValue=stakeDict[glyph])