roundingPen.py 3.7 KB

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