recordingPen

Pen recording operations that can be accessed or replayed.

fontTools.pens.recordingPen.replayRecording(recording, pen)[source]

Replay a recording, as produced by RecordingPen or DecomposingRecordingPen, to a pen.

Note that recording does not have to be produced by those pens. It can be any iterable of tuples of method name and tuple-of-arguments. Likewise, pen can be any objects receiving those method calls.

class fontTools.pens.recordingPen.RecordingPen[source]

Bases: AbstractPen

Pen recording operations that can be accessed or replayed.

The recording can be accessed as pen.value; or replayed using pen.replay(otherPen).

Example:
from fontTools.ttLib import TTFont
from fontTools.pens.recordingPen import RecordingPen

glyph_name = 'dollar'
font_path = 'MyFont.otf'

font = TTFont(font_path)
glyphset = font.getGlyphSet()
glyph = glyphset[glyph_name]

pen = RecordingPen()
glyph.draw(pen)
print(pen.value)
moveTo(p0)[source]
lineTo(p1)[source]
qCurveTo(*points)[source]
curveTo(*points)[source]
closePath()[source]
endPath()[source]
addComponent(glyphName, transformation)[source]
addVarComponent(glyphName, transformation, location)[source]
replay(pen)[source]
draw(pen)
class fontTools.pens.recordingPen.DecomposingRecordingPen(glyphSet, *args, skipMissingComponents=None, reverseFlipped=False, **kwargs)[source]

Bases: DecomposingPen, RecordingPen

Same as RecordingPen, except that it doesn’t keep components as references, but draws them decomposed as regular contours.

The constructor takes a required ‘glyphSet’ positional argument, a dictionary of glyph objects (i.e. with a ‘draw’ method) keyed by thir name; other arguments are forwarded to the DecomposingPen’s constructor:

>>> class SimpleGlyph(object):
...     def draw(self, pen):
...         pen.moveTo((0, 0))
...         pen.curveTo((1, 1), (2, 2), (3, 3))
...         pen.closePath()
>>> class CompositeGlyph(object):
...     def draw(self, pen):
...         pen.addComponent('a', (1, 0, 0, 1, -1, 1))
>>> class MissingComponent(object):
...     def draw(self, pen):
...         pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
>>> class FlippedComponent(object):
...     def draw(self, pen):
...         pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
>>> glyphSet = {
...    'a': SimpleGlyph(),
...    'b': CompositeGlyph(),
...    'c': MissingComponent(),
...    'd': FlippedComponent(),
... }
>>> for name, glyph in sorted(glyphSet.items()):
...     pen = DecomposingRecordingPen(glyphSet)
...     try:
...         glyph.draw(pen)
...     except pen.MissingComponentError:
...         pass
...     print("{}: {}".format(name, pen.value))
a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
c: []
d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())]

>>> for name, glyph in sorted(glyphSet.items()):
...     pen = DecomposingRecordingPen(
...         glyphSet, skipMissingComponents=True, reverseFlipped=True,
...     )
...     glyph.draw(pen)
...     print("{}: {}".format(name, pen.value))
a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
c: []
d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())]
skipMissingComponents = False
class fontTools.pens.recordingPen.DecomposingRecordingPointPen(glyphSet, *args, skipMissingComponents=None, reverseFlipped=False, **kwargs)[source]

Bases: DecomposingPointPen, RecordingPointPen

Same as RecordingPointPen, except that it doesn’t keep components as references, but draws them decomposed as regular contours.

The constructor takes a required ‘glyphSet’ positional argument, a dictionary of pointPen-drawable glyph objects (i.e. with a ‘drawPoints’ method) keyed by thir name; other arguments are forwarded to the DecomposingPointPen’s constructor:

>>> from pprint import pprint
>>> class SimpleGlyph(object):
...     def drawPoints(self, pen):
...         pen.beginPath()
...         pen.addPoint((0, 0), "line")
...         pen.addPoint((1, 1))
...         pen.addPoint((2, 2))
...         pen.addPoint((3, 3), "curve")
...         pen.endPath()
>>> class CompositeGlyph(object):
...     def drawPoints(self, pen):
...         pen.addComponent('a', (1, 0, 0, 1, -1, 1))
>>> class MissingComponent(object):
...     def drawPoints(self, pen):
...         pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
>>> class FlippedComponent(object):
...     def drawPoints(self, pen):
...         pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
>>> glyphSet = {
...    'a': SimpleGlyph(),
...    'b': CompositeGlyph(),
...    'c': MissingComponent(),
...    'd': FlippedComponent(),
... }
>>> for name, glyph in sorted(glyphSet.items()):
...     pen = DecomposingRecordingPointPen(glyphSet)
...     try:
...         glyph.drawPoints(pen)
...     except pen.MissingComponentError:
...         pass
...     pprint({name: pen.value})
{'a': [('beginPath', (), {}),
       ('addPoint', ((0, 0), 'line', False, None), {}),
       ('addPoint', ((1, 1), None, False, None), {}),
       ('addPoint', ((2, 2), None, False, None), {}),
       ('addPoint', ((3, 3), 'curve', False, None), {}),
       ('endPath', (), {})]}
{'b': [('beginPath', (), {}),
       ('addPoint', ((-1, 1), 'line', False, None), {}),
       ('addPoint', ((0, 2), None, False, None), {}),
       ('addPoint', ((1, 3), None, False, None), {}),
       ('addPoint', ((2, 4), 'curve', False, None), {}),
       ('endPath', (), {})]}
{'c': []}
{'d': [('beginPath', (), {}),
       ('addPoint', ((0, 0), 'line', False, None), {}),
       ('addPoint', ((-1, 1), None, False, None), {}),
       ('addPoint', ((-2, 2), None, False, None), {}),
       ('addPoint', ((-3, 3), 'curve', False, None), {}),
       ('endPath', (), {})]}

>>> for name, glyph in sorted(glyphSet.items()):
...     pen = DecomposingRecordingPointPen(
...         glyphSet, skipMissingComponents=True, reverseFlipped=True,
...     )
...     glyph.drawPoints(pen)
...     pprint({name: pen.value})
{'a': [('beginPath', (), {}),
       ('addPoint', ((0, 0), 'line', False, None), {}),
       ('addPoint', ((1, 1), None, False, None), {}),
       ('addPoint', ((2, 2), None, False, None), {}),
       ('addPoint', ((3, 3), 'curve', False, None), {}),
       ('endPath', (), {})]}
{'b': [('beginPath', (), {}),
       ('addPoint', ((-1, 1), 'line', False, None), {}),
       ('addPoint', ((0, 2), None, False, None), {}),
       ('addPoint', ((1, 3), None, False, None), {}),
       ('addPoint', ((2, 4), 'curve', False, None), {}),
       ('endPath', (), {})]}
{'c': []}
{'d': [('beginPath', (), {}),
       ('addPoint', ((0, 0), 'curve', False, None), {}),
       ('addPoint', ((-3, 3), 'line', False, None), {}),
       ('addPoint', ((-2, 2), None, False, None), {}),
       ('addPoint', ((-1, 1), None, False, None), {}),
       ('endPath', (), {})]}
skipMissingComponents = False
class fontTools.pens.recordingPen.RecordingPointPen[source]

Bases: AbstractPointPen

PointPen recording operations that can be accessed or replayed.

The recording can be accessed as pen.value; or replayed using pointPen.replay(otherPointPen).

Example:
from defcon import Font
from fontTools.pens.recordingPen import RecordingPointPen

glyph_name = 'a'
font_path = 'MyFont.ufo'

font = Font(font_path)
glyph = font[glyph_name]

pen = RecordingPointPen()
glyph.drawPoints(pen)
print(pen.value)

new_glyph = font.newGlyph('b')
pen.replay(new_glyph.getPointPen())
beginPath(identifier=None, **kwargs)[source]
endPath()[source]
addPoint(pt, segmentType=None, smooth=False, name=None, identifier=None, **kwargs)[source]
addComponent(baseGlyphName, transformation, identifier=None, **kwargs)[source]
addVarComponent(baseGlyphName, transformation, location, identifier=None, **kwargs)[source]
replay(pointPen)[source]
drawPoints(pointPen)
fontTools.pens.recordingPen.lerpRecordings(recording1, recording2, factor=0.5)[source]

Linearly interpolate between two recordings. The recordings must be decomposed, i.e. they must not contain any components.

Factor is typically between 0 and 1. 0 means the first recording, 1 means the second recording, and 0.5 means the average of the two recordings. Other values are possible, and can be useful to extrapolate. Defaults to 0.5.

Returns a generator with the new recording.