1*e1fe3e4aSElliott Hughesfrom fontTools.misc.roundTools import noRound, otRound 2*e1fe3e4aSElliott Hughesfrom fontTools.misc.transform import Transform 3*e1fe3e4aSElliott Hughesfrom fontTools.pens.filterPen import FilterPen, FilterPointPen 4*e1fe3e4aSElliott Hughes 5*e1fe3e4aSElliott Hughes 6*e1fe3e4aSElliott Hughes__all__ = ["RoundingPen", "RoundingPointPen"] 7*e1fe3e4aSElliott Hughes 8*e1fe3e4aSElliott Hughes 9*e1fe3e4aSElliott Hughesclass RoundingPen(FilterPen): 10*e1fe3e4aSElliott Hughes """ 11*e1fe3e4aSElliott Hughes Filter pen that rounds point coordinates and component XY offsets to integer. For 12*e1fe3e4aSElliott Hughes rounding the component transform values, a separate round function can be passed to 13*e1fe3e4aSElliott Hughes the pen. 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hughes >>> from fontTools.pens.recordingPen import RecordingPen 16*e1fe3e4aSElliott Hughes >>> recpen = RecordingPen() 17*e1fe3e4aSElliott Hughes >>> roundpen = RoundingPen(recpen) 18*e1fe3e4aSElliott Hughes >>> roundpen.moveTo((0.4, 0.6)) 19*e1fe3e4aSElliott Hughes >>> roundpen.lineTo((1.6, 2.5)) 20*e1fe3e4aSElliott Hughes >>> roundpen.qCurveTo((2.4, 4.6), (3.3, 5.7), (4.9, 6.1)) 21*e1fe3e4aSElliott Hughes >>> roundpen.curveTo((6.4, 8.6), (7.3, 9.7), (8.9, 10.1)) 22*e1fe3e4aSElliott Hughes >>> roundpen.addComponent("a", (1.5, 0, 0, 1.5, 10.5, -10.5)) 23*e1fe3e4aSElliott Hughes >>> recpen.value == [ 24*e1fe3e4aSElliott Hughes ... ('moveTo', ((0, 1),)), 25*e1fe3e4aSElliott Hughes ... ('lineTo', ((2, 3),)), 26*e1fe3e4aSElliott Hughes ... ('qCurveTo', ((2, 5), (3, 6), (5, 6))), 27*e1fe3e4aSElliott Hughes ... ('curveTo', ((6, 9), (7, 10), (9, 10))), 28*e1fe3e4aSElliott Hughes ... ('addComponent', ('a', (1.5, 0, 0, 1.5, 11, -10))), 29*e1fe3e4aSElliott Hughes ... ] 30*e1fe3e4aSElliott Hughes True 31*e1fe3e4aSElliott Hughes """ 32*e1fe3e4aSElliott Hughes 33*e1fe3e4aSElliott Hughes def __init__(self, outPen, roundFunc=otRound, transformRoundFunc=noRound): 34*e1fe3e4aSElliott Hughes super().__init__(outPen) 35*e1fe3e4aSElliott Hughes self.roundFunc = roundFunc 36*e1fe3e4aSElliott Hughes self.transformRoundFunc = transformRoundFunc 37*e1fe3e4aSElliott Hughes 38*e1fe3e4aSElliott Hughes def moveTo(self, pt): 39*e1fe3e4aSElliott Hughes self._outPen.moveTo((self.roundFunc(pt[0]), self.roundFunc(pt[1]))) 40*e1fe3e4aSElliott Hughes 41*e1fe3e4aSElliott Hughes def lineTo(self, pt): 42*e1fe3e4aSElliott Hughes self._outPen.lineTo((self.roundFunc(pt[0]), self.roundFunc(pt[1]))) 43*e1fe3e4aSElliott Hughes 44*e1fe3e4aSElliott Hughes def curveTo(self, *points): 45*e1fe3e4aSElliott Hughes self._outPen.curveTo( 46*e1fe3e4aSElliott Hughes *((self.roundFunc(x), self.roundFunc(y)) for x, y in points) 47*e1fe3e4aSElliott Hughes ) 48*e1fe3e4aSElliott Hughes 49*e1fe3e4aSElliott Hughes def qCurveTo(self, *points): 50*e1fe3e4aSElliott Hughes self._outPen.qCurveTo( 51*e1fe3e4aSElliott Hughes *((self.roundFunc(x), self.roundFunc(y)) for x, y in points) 52*e1fe3e4aSElliott Hughes ) 53*e1fe3e4aSElliott Hughes 54*e1fe3e4aSElliott Hughes def addComponent(self, glyphName, transformation): 55*e1fe3e4aSElliott Hughes xx, xy, yx, yy, dx, dy = transformation 56*e1fe3e4aSElliott Hughes self._outPen.addComponent( 57*e1fe3e4aSElliott Hughes glyphName, 58*e1fe3e4aSElliott Hughes Transform( 59*e1fe3e4aSElliott Hughes self.transformRoundFunc(xx), 60*e1fe3e4aSElliott Hughes self.transformRoundFunc(xy), 61*e1fe3e4aSElliott Hughes self.transformRoundFunc(yx), 62*e1fe3e4aSElliott Hughes self.transformRoundFunc(yy), 63*e1fe3e4aSElliott Hughes self.roundFunc(dx), 64*e1fe3e4aSElliott Hughes self.roundFunc(dy), 65*e1fe3e4aSElliott Hughes ), 66*e1fe3e4aSElliott Hughes ) 67*e1fe3e4aSElliott Hughes 68*e1fe3e4aSElliott Hughes 69*e1fe3e4aSElliott Hughesclass RoundingPointPen(FilterPointPen): 70*e1fe3e4aSElliott Hughes """ 71*e1fe3e4aSElliott Hughes Filter point pen that rounds point coordinates and component XY offsets to integer. 72*e1fe3e4aSElliott Hughes For rounding the component scale values, a separate round function can be passed to 73*e1fe3e4aSElliott Hughes the pen. 74*e1fe3e4aSElliott Hughes 75*e1fe3e4aSElliott Hughes >>> from fontTools.pens.recordingPen import RecordingPointPen 76*e1fe3e4aSElliott Hughes >>> recpen = RecordingPointPen() 77*e1fe3e4aSElliott Hughes >>> roundpen = RoundingPointPen(recpen) 78*e1fe3e4aSElliott Hughes >>> roundpen.beginPath() 79*e1fe3e4aSElliott Hughes >>> roundpen.addPoint((0.4, 0.6), 'line') 80*e1fe3e4aSElliott Hughes >>> roundpen.addPoint((1.6, 2.5), 'line') 81*e1fe3e4aSElliott Hughes >>> roundpen.addPoint((2.4, 4.6)) 82*e1fe3e4aSElliott Hughes >>> roundpen.addPoint((3.3, 5.7)) 83*e1fe3e4aSElliott Hughes >>> roundpen.addPoint((4.9, 6.1), 'qcurve') 84*e1fe3e4aSElliott Hughes >>> roundpen.endPath() 85*e1fe3e4aSElliott Hughes >>> roundpen.addComponent("a", (1.5, 0, 0, 1.5, 10.5, -10.5)) 86*e1fe3e4aSElliott Hughes >>> recpen.value == [ 87*e1fe3e4aSElliott Hughes ... ('beginPath', (), {}), 88*e1fe3e4aSElliott Hughes ... ('addPoint', ((0, 1), 'line', False, None), {}), 89*e1fe3e4aSElliott Hughes ... ('addPoint', ((2, 3), 'line', False, None), {}), 90*e1fe3e4aSElliott Hughes ... ('addPoint', ((2, 5), None, False, None), {}), 91*e1fe3e4aSElliott Hughes ... ('addPoint', ((3, 6), None, False, None), {}), 92*e1fe3e4aSElliott Hughes ... ('addPoint', ((5, 6), 'qcurve', False, None), {}), 93*e1fe3e4aSElliott Hughes ... ('endPath', (), {}), 94*e1fe3e4aSElliott Hughes ... ('addComponent', ('a', (1.5, 0, 0, 1.5, 11, -10)), {}), 95*e1fe3e4aSElliott Hughes ... ] 96*e1fe3e4aSElliott Hughes True 97*e1fe3e4aSElliott Hughes """ 98*e1fe3e4aSElliott Hughes 99*e1fe3e4aSElliott Hughes def __init__(self, outPen, roundFunc=otRound, transformRoundFunc=noRound): 100*e1fe3e4aSElliott Hughes super().__init__(outPen) 101*e1fe3e4aSElliott Hughes self.roundFunc = roundFunc 102*e1fe3e4aSElliott Hughes self.transformRoundFunc = transformRoundFunc 103*e1fe3e4aSElliott Hughes 104*e1fe3e4aSElliott Hughes def addPoint( 105*e1fe3e4aSElliott Hughes self, pt, segmentType=None, smooth=False, name=None, identifier=None, **kwargs 106*e1fe3e4aSElliott Hughes ): 107*e1fe3e4aSElliott Hughes self._outPen.addPoint( 108*e1fe3e4aSElliott Hughes (self.roundFunc(pt[0]), self.roundFunc(pt[1])), 109*e1fe3e4aSElliott Hughes segmentType=segmentType, 110*e1fe3e4aSElliott Hughes smooth=smooth, 111*e1fe3e4aSElliott Hughes name=name, 112*e1fe3e4aSElliott Hughes identifier=identifier, 113*e1fe3e4aSElliott Hughes **kwargs, 114*e1fe3e4aSElliott Hughes ) 115*e1fe3e4aSElliott Hughes 116*e1fe3e4aSElliott Hughes def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs): 117*e1fe3e4aSElliott Hughes xx, xy, yx, yy, dx, dy = transformation 118*e1fe3e4aSElliott Hughes self._outPen.addComponent( 119*e1fe3e4aSElliott Hughes baseGlyphName=baseGlyphName, 120*e1fe3e4aSElliott Hughes transformation=Transform( 121*e1fe3e4aSElliott Hughes self.transformRoundFunc(xx), 122*e1fe3e4aSElliott Hughes self.transformRoundFunc(xy), 123*e1fe3e4aSElliott Hughes self.transformRoundFunc(yx), 124*e1fe3e4aSElliott Hughes self.transformRoundFunc(yy), 125*e1fe3e4aSElliott Hughes self.roundFunc(dx), 126*e1fe3e4aSElliott Hughes self.roundFunc(dy), 127*e1fe3e4aSElliott Hughes ), 128*e1fe3e4aSElliott Hughes identifier=identifier, 129*e1fe3e4aSElliott Hughes **kwargs, 130*e1fe3e4aSElliott Hughes ) 131