예제 #1
0
 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
예제 #2
0
    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()
예제 #3
0
    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)
예제 #4
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)
예제 #5
0
    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)
예제 #6
0
    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()
예제 #7
0
    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)