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