def buildBinary(self, w, **kwArgs): """ Adds the binary data to the specified LinkedWriter. >>> h = utilities.hexdump >>> h(_testingValues[0].binaryString()) 0 | 0002 0000 |.... | >>> h(_testingValues[1].binaryString()) 0 | 0001 0004 0004 0002 0002 0002 0001 |.............. | >>> h(_testingValues[2].binaryString()) 0 | 0002 0004 0004 0006 0002 0007 0007 0001 |................| 10 | 000A 000B 0002 000F 000F 0002 |............ | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() if self: v = sorted(self) sv = [] if len(v) == (v[-1] - v[0] + 1): # ok to try format 1 w1 = writer.LinkedWriter() w1.add("3H", 1, v[0], len(v)) w1.addGroup("H", [self[i] for i in v]) sv.append(w1.binaryString()) w2 = writer.LinkedWriter() groups = [] for start, stop, skip in utilities.monotonicGroupsGenerator(v): cumulCount = 0 it = (self[i] for i in range(start, stop, skip)) for k, g in itertools.groupby(it): subCount = len(list(g)) groups.append(( start + cumulCount, start + cumulCount + subCount - 1, k)) cumulCount += subCount w2.add("HH", 2, len(groups)) w2.addGroup("3H", groups) sv.append(w2.binaryString()) sv.sort(key=len) w.addString(sv[0]) # shortest else: w.add("HH", 2, 0) # format 0, no ranges
def _makeFormat2(sortedGlyphs): groups = [] currIndex = 0 it = utilities.monotonicGroupsGenerator(sortedGlyphs) for start, stop, skip in it: groups.append((start, stop - 1, currIndex)) currIndex += (stop - start) w = writer.LinkedWriter() w.add("HH", 2, len(groups)) w.addGroup("3H", groups) return w.binaryString()
def _fmt4Analyze(glyphs, startCode): """ Determines the idDelta for the specified list of glyphs. Missing glyphs are ignored as long as they don't break the sequence. >>> Format4._fmt4Analyze([12, 13, 14, 15], 60) -48 >>> Format4._fmt4Analyze([12, 0, 14, 15], 60) -48 >>> Format4._fmt4Analyze([12, 19, 14, 15], 60) 0 """ g = utilities.monotonicGroupsGenerator(glyphs, allowZeroes=True) return (glyphs[0] - startCode if len(list(g)) == 1 else 0)
def ranges(self): """ Returns a generator over (first, last) pairs for the current contents of the Span. >>> print(list(Span({2, 3, 4, 12, 15, 16}).ranges())) [(2, 4), (12, 12), (15, 16)] >>> print(list(Span().ranges())) [] """ it = utilities.monotonicGroupsGenerator(sorted(self)) for start, stop, ignore in it: yield (start, stop - 1)
def buildBinary(self, w, **kwArgs): """ Adds the binary data for the Groups object to the specified LinkedWriter. >>> utilities.hexdump(_testingValues[0].binaryString()) 0 | 0000 |.. | >>> utilities.hexdump(_testingValues[1].binaryString()) 0 | 0002 04B0 04E1 0000 0578 058B 0000 0001 |.........x......| 10 | 000C 001E 0000 0000 |........ | >>> utilities.hexdump(_testingValues[2].binaryString()) 0 | 0003 012C 0167 0000 04B0 04E1 0001 0578 |...,.g.........x| 10 | 058B 0001 0002 0004 000C 0001 0000 000C |................| 20 | 001E 0000 0000 |...... | """ countStake = w.addDeferredValue("H") itBig = (i for i in sorted(self) if self[i] is not None) groupCount = 0 pool = {} poolList = [] for start, stop, delta in utilities.monotonicGroupsGenerator(itBig): it = (self[i] for i in range(start, stop)) for k, g in itertools.groupby(it): groupCount += 1 v = list(g) last = start + len(v) - 1 immut = v[0].asImmutable() if immut not in pool: pool[immut] = len(poolList) poolList.append(v[0]) w.add("3H", start, last, pool[immut]) start = last + 1 w.setDeferredValue(countStake, "H", groupCount) if poolList: w.add("H", len(poolList)) for obj in poolList: obj.buildBinary(w, **kwArgs)
def _makeFormat2(sortedKeys): """ Returns a format 2 binary string. """ # already checked density and monotonicity groups = [] currIndex = 0 it = utilities.monotonicGroupsGenerator(sortedKeys) for start, stop, skip in it: groups.append((start, stop - 1, currIndex)) currIndex += (stop - start) w = writer.LinkedWriter() w.add("HH", 2, len(groups)) w.addGroup("3H", groups) return w.binaryString()
def buildBinary(self, w, **kwArgs): """ Adds the binary content for ``self`` to the specified writer. :param w: A :py:class:`~fontio3.utilities.writer.LinkedWriter` :param kwArgs: Optional keyword arguments (there are none here) :return: None :raises ValueError: if one or more values cannot fit into four bytes >>> pp.PP().sequence_grouped(_testingValues[0].binaryString()) [0]: 0 [1]: 8 [2-5]: 0 [6]: 32 [7]: 16 [8-8207]: 0 >>> pp.PP().sequence_grouped(_testingValues[1].binaryString()) [0]: 0 [1]: 8 [2-5]: 0 [6]: 32 [7]: 28 [8-11]: 0 [12]: 32 [13-8206]: 0 [8207]: 1 [8208]: 0 [8209]: 2 [8210-8212]: 0 [8213]: 2 [8214-8217]: 0 [8218]: 11 [8219]: 184 >>> pp.PP().sequence_grouped(_testingValues[2].binaryString()) [0]: 0 [1]: 8 [2-5]: 0 [6]: 32 [7]: 28 [8-11]: 0 [12]: 32 [13-8206]: 0 [8207]: 1 [8208]: 0 [8209]: 2 [8210-8212]: 0 [8213]: 2 [8214]: 0 [8215]: 1 [8216-8217]: 0 [8218]: 11 [8219]: 184 """ self._preBuildValidate() startLength = w.byteLength w.add("HH", 8, 0) # format and pad lengthStake = w.addDeferredValue("L") w.add("L", (self.language or 0)) highSet = set(c >> 16 for c in self) v = [0] * 65536 for i in highSet: v[i] = 1 w.addString(utilitiesbackend.utImplode(v)) countStake = w.addDeferredValue("L") count = 0 for spanStart, spanEnd in span2.Span(self).ranges(): if spanEnd < 0x7FFFFFFE: v = [self[i] for i in range(spanStart, spanEnd + 1)] else: v = [self[i] for i in range(spanStart, spanEnd + 1)] for gStart, gStop, ignore in utilities.monotonicGroupsGenerator(v): count += 1 thisLen = gStop - gStart w.add("3L", spanStart, spanStart + thisLen - 1, gStart) spanStart += thisLen w.setDeferredValue(countStake, "L", count) w.setDeferredValue(lengthStake, "L", w.byteLength - startLength)