transformPen.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. from fontTools.pens.filterPen import FilterPen, FilterPointPen
  2. __all__ = ["TransformPen", "TransformPointPen"]
  3. class TransformPen(FilterPen):
  4. """Pen that transforms all coordinates using a Affine transformation,
  5. and passes them to another pen.
  6. """
  7. def __init__(self, outPen, transformation):
  8. """The 'outPen' argument is another pen object. It will receive the
  9. transformed coordinates. The 'transformation' argument can either
  10. be a six-tuple, or a fontTools.misc.transform.Transform object.
  11. """
  12. super(TransformPen, self).__init__(outPen)
  13. if not hasattr(transformation, "transformPoint"):
  14. from fontTools.misc.transform import Transform
  15. transformation = Transform(*transformation)
  16. self._transformation = transformation
  17. self._transformPoint = transformation.transformPoint
  18. self._stack = []
  19. def moveTo(self, pt):
  20. self._outPen.moveTo(self._transformPoint(pt))
  21. def lineTo(self, pt):
  22. self._outPen.lineTo(self._transformPoint(pt))
  23. def curveTo(self, *points):
  24. self._outPen.curveTo(*self._transformPoints(points))
  25. def qCurveTo(self, *points):
  26. if points[-1] is None:
  27. points = self._transformPoints(points[:-1]) + [None]
  28. else:
  29. points = self._transformPoints(points)
  30. self._outPen.qCurveTo(*points)
  31. def _transformPoints(self, points):
  32. transformPoint = self._transformPoint
  33. return [transformPoint(pt) for pt in points]
  34. def closePath(self):
  35. self._outPen.closePath()
  36. def endPath(self):
  37. self._outPen.endPath()
  38. def addComponent(self, glyphName, transformation):
  39. transformation = self._transformation.transform(transformation)
  40. self._outPen.addComponent(glyphName, transformation)
  41. class TransformPointPen(FilterPointPen):
  42. """PointPen that transforms all coordinates using a Affine transformation,
  43. and passes them to another PointPen.
  44. >>> from fontTools.pens.recordingPen import RecordingPointPen
  45. >>> rec = RecordingPointPen()
  46. >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5))
  47. >>> v = iter(rec.value)
  48. >>> pen.beginPath(identifier="contour-0")
  49. >>> next(v)
  50. ('beginPath', (), {'identifier': 'contour-0'})
  51. >>> pen.addPoint((100, 100), "line")
  52. >>> next(v)
  53. ('addPoint', ((190, 205), 'line', False, None), {})
  54. >>> pen.endPath()
  55. >>> next(v)
  56. ('endPath', (), {})
  57. >>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
  58. >>> next(v)
  59. ('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'})
  60. """
  61. def __init__(self, outPointPen, transformation):
  62. """The 'outPointPen' argument is another point pen object.
  63. It will receive the transformed coordinates.
  64. The 'transformation' argument can either be a six-tuple, or a
  65. fontTools.misc.transform.Transform object.
  66. """
  67. super().__init__(outPointPen)
  68. if not hasattr(transformation, "transformPoint"):
  69. from fontTools.misc.transform import Transform
  70. transformation = Transform(*transformation)
  71. self._transformation = transformation
  72. self._transformPoint = transformation.transformPoint
  73. def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
  74. self._outPen.addPoint(
  75. self._transformPoint(pt), segmentType, smooth, name, **kwargs
  76. )
  77. def addComponent(self, baseGlyphName, transformation, **kwargs):
  78. transformation = self._transformation.transform(transformation)
  79. self._outPen.addComponent(baseGlyphName, transformation, **kwargs)
  80. if __name__ == "__main__":
  81. from fontTools.pens.basePen import _TestPen
  82. pen = TransformPen(_TestPen(None), (2, 0, 0.5, 2, -10, 0))
  83. pen.moveTo((0, 0))
  84. pen.lineTo((0, 100))
  85. pen.curveTo((50, 75), (60, 50), (50, 25), (0, 0))
  86. pen.closePath()