Merge pull request #3627 from n8willis/docs-cleanup

Docs: clean up various code blocks in docstrings, to enable correct syntax highlighting in HTML / RTD output.
This commit is contained in:
n8willis 2024-09-16 10:40:05 +01:00 committed by GitHub
commit 63611d4474
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 290 additions and 226 deletions

View File

@ -46,7 +46,7 @@ class FreeTypePen(BasePen):
glyphSet: a dictionary of drawable glyph objects keyed by name glyphSet: a dictionary of drawable glyph objects keyed by name
used to resolve component references in composite glyphs. used to resolve component references in composite glyphs.
:Examples: Examples:
If `numpy` and `matplotlib` is available, the following code will If `numpy` and `matplotlib` is available, the following code will
show the glyph image of `fi` in a new window:: show the glyph image of `fi` in a new window::
@ -178,7 +178,7 @@ class FreeTypePen(BasePen):
object of the resulted bitmap and ``size`` is a 2-tuple of its object of the resulted bitmap and ``size`` is a 2-tuple of its
dimension. dimension.
:Notes: Notes:
The image size should always be given explicitly if you need to get The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get forcifully fits to the bounding box and the side bearings get
@ -188,15 +188,15 @@ class FreeTypePen(BasePen):
maintained but RSB wont. The difference between the two becomes maintained but RSB wont. The difference between the two becomes
more obvious when rotate or skew transformation is applied. more obvious when rotate or skew transformation is applied.
:Example: Example:
.. code-block:: .. code-block:: pycon
>>>
>> pen = FreeTypePen(None) >> pen = FreeTypePen(None)
>> glyph.draw(pen) >> glyph.draw(pen)
>> buf, size = pen.buffer(width=500, height=1000) >> buf, size = pen.buffer(width=500, height=1000)
>> type(buf), len(buf), size >> type(buf), len(buf), size
(<class 'bytes'>, 500000, (500, 1000)) (<class 'bytes'>, 500000, (500, 1000))
""" """
transform = transform or Transform() transform = transform or Transform()
if not hasattr(transform, "transformPoint"): if not hasattr(transform, "transformPoint"):
@ -269,7 +269,7 @@ class FreeTypePen(BasePen):
A ``numpy.ndarray`` object with a shape of ``(height, width)``. A ``numpy.ndarray`` object with a shape of ``(height, width)``.
Each element takes a value in the range of ``[0.0, 1.0]``. Each element takes a value in the range of ``[0.0, 1.0]``.
:Notes: Notes:
The image size should always be given explicitly if you need to get The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get forcifully fits to the bounding box and the side bearings get
@ -279,15 +279,17 @@ class FreeTypePen(BasePen):
maintained but RSB wont. The difference between the two becomes maintained but RSB wont. The difference between the two becomes
more obvious when rotate or skew transformation is applied. more obvious when rotate or skew transformation is applied.
:Example: Example:
.. code-block:: .. code-block:: pycon
>>>
>> pen = FreeTypePen(None) >> pen = FreeTypePen(None)
>> glyph.draw(pen) >> glyph.draw(pen)
>> arr = pen.array(width=500, height=1000) >> arr = pen.array(width=500, height=1000)
>> type(a), a.shape >> type(a), a.shape
(<class 'numpy.ndarray'>, (1000, 500)) (<class 'numpy.ndarray'>, (1000, 500))
""" """
import numpy as np import numpy as np
buf, size = self.buffer( buf, size = self.buffer(
@ -318,7 +320,7 @@ class FreeTypePen(BasePen):
rendering glyphs with negative sidebearings without clipping. rendering glyphs with negative sidebearings without clipping.
evenOdd: Pass ``True`` for even-odd fill instead of non-zero. evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
:Notes: Notes:
The image size should always be given explicitly if you need to get The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get forcifully fits to the bounding box and the side bearings get
@ -328,9 +330,10 @@ class FreeTypePen(BasePen):
maintained but RSB wont. The difference between the two becomes maintained but RSB wont. The difference between the two becomes
more obvious when rotate or skew transformation is applied. more obvious when rotate or skew transformation is applied.
:Example: Example:
.. code-block:: .. code-block:: pycon
>>>
>> pen = FreeTypePen(None) >> pen = FreeTypePen(None)
>> glyph.draw(pen) >> glyph.draw(pen)
>> pen.show(width=500, height=1000) >> pen.show(width=500, height=1000)
@ -370,7 +373,7 @@ class FreeTypePen(BasePen):
A ``PIL.image`` object. The image is filled in black with alpha A ``PIL.image`` object. The image is filled in black with alpha
channel obtained from the rendered bitmap. channel obtained from the rendered bitmap.
:Notes: Notes:
The image size should always be given explicitly if you need to get The image size should always be given explicitly if you need to get
a proper glyph image. When ``width`` and ``height`` are omitted, it a proper glyph image. When ``width`` and ``height`` are omitted, it
forcifully fits to the bounding box and the side bearings get forcifully fits to the bounding box and the side bearings get
@ -380,9 +383,10 @@ class FreeTypePen(BasePen):
maintained but RSB wont. The difference between the two becomes maintained but RSB wont. The difference between the two becomes
more obvious when rotate or skew transformation is applied. more obvious when rotate or skew transformation is applied.
:Example: Example:
.. code-block:: .. code-block:: pycon
>>>
>> pen = FreeTypePen(None) >> pen = FreeTypePen(None)
>> glyph.draw(pen) >> glyph.draw(pen)
>> img = pen.image(width=500, height=1000) >> img = pen.image(width=500, height=1000)

View File

@ -15,7 +15,8 @@ class PointInsidePen(BasePen):
Instances of this class can be recycled, as long as the Instances of this class can be recycled, as long as the
setTestPoint() method is used to set the new point to test. setTestPoint() method is used to set the new point to test.
Typical usage: :Example:
.. code-block::
pen = PointInsidePen(glyphSet, (100, 200)) pen = PointInsidePen(glyphSet, (100, 200))
outline.draw(pen) outline.draw(pen)

View File

@ -33,6 +33,7 @@ class RecordingPen(AbstractPen):
pen.replay(otherPen). pen.replay(otherPen).
:Example: :Example:
.. code-block::
from fontTools.ttLib import TTFont from fontTools.ttLib import TTFont
from fontTools.pens.recordingPen import RecordingPen from fontTools.pens.recordingPen import RecordingPen
@ -91,47 +92,48 @@ class DecomposingRecordingPen(DecomposingPen, RecordingPen):
by thir name; other arguments are forwarded to the DecomposingPen's by thir name; other arguments are forwarded to the DecomposingPen's
constructor:: constructor::
>>> class SimpleGlyph(object): >>> class SimpleGlyph(object):
... def draw(self, pen): ... def draw(self, pen):
... pen.moveTo((0, 0)) ... pen.moveTo((0, 0))
... pen.curveTo((1, 1), (2, 2), (3, 3)) ... pen.curveTo((1, 1), (2, 2), (3, 3))
... pen.closePath() ... pen.closePath()
>>> class CompositeGlyph(object): >>> class CompositeGlyph(object):
... def draw(self, pen): ... def draw(self, pen):
... pen.addComponent('a', (1, 0, 0, 1, -1, 1)) ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
>>> class MissingComponent(object): >>> class MissingComponent(object):
... def draw(self, pen): ... def draw(self, pen):
... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0)) ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
>>> class FlippedComponent(object): >>> class FlippedComponent(object):
... def draw(self, pen): ... def draw(self, pen):
... pen.addComponent('a', (-1, 0, 0, 1, 0, 0)) ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
>>> glyphSet = { >>> glyphSet = {
... 'a': SimpleGlyph(), ... 'a': SimpleGlyph(),
... 'b': CompositeGlyph(), ... 'b': CompositeGlyph(),
... 'c': MissingComponent(), ... 'c': MissingComponent(),
... 'd': FlippedComponent(), ... 'd': FlippedComponent(),
... } ... }
>>> for name, glyph in sorted(glyphSet.items()): >>> for name, glyph in sorted(glyphSet.items()):
... pen = DecomposingRecordingPen(glyphSet) ... pen = DecomposingRecordingPen(glyphSet)
... try: ... try:
... glyph.draw(pen) ... glyph.draw(pen)
... except pen.MissingComponentError: ... except pen.MissingComponentError:
... pass ... pass
... print("{}: {}".format(name, pen.value)) ... print("{}: {}".format(name, pen.value))
a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())] a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())] b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
c: [] c: []
d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())] d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())]
>>> for name, glyph in sorted(glyphSet.items()):
... pen = DecomposingRecordingPen( >>> for name, glyph in sorted(glyphSet.items()):
... glyphSet, skipMissingComponents=True, reverseFlipped=True, ... pen = DecomposingRecordingPen(
... ) ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
... glyph.draw(pen) ... )
... print("{}: {}".format(name, pen.value)) ... glyph.draw(pen)
a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())] ... print("{}: {}".format(name, pen.value))
b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())] a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
c: [] b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())] c: []
d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())]
""" """
# raises MissingComponentError(KeyError) if base glyph is not found in glyphSet # raises MissingComponentError(KeyError) if base glyph is not found in glyphSet
@ -145,6 +147,7 @@ class RecordingPointPen(AbstractPointPen):
pointPen.replay(otherPointPen). pointPen.replay(otherPointPen).
:Example: :Example:
.. code-block::
from defcon import Font from defcon import Font
from fontTools.pens.recordingPen import RecordingPointPen from fontTools.pens.recordingPen import RecordingPointPen
@ -211,81 +214,82 @@ class DecomposingRecordingPointPen(DecomposingPointPen, RecordingPointPen):
keyed by thir name; other arguments are forwarded to the DecomposingPointPen's keyed by thir name; other arguments are forwarded to the DecomposingPointPen's
constructor:: constructor::
>>> from pprint import pprint >>> from pprint import pprint
>>> class SimpleGlyph(object): >>> class SimpleGlyph(object):
... def drawPoints(self, pen): ... def drawPoints(self, pen):
... pen.beginPath() ... pen.beginPath()
... pen.addPoint((0, 0), "line") ... pen.addPoint((0, 0), "line")
... pen.addPoint((1, 1)) ... pen.addPoint((1, 1))
... pen.addPoint((2, 2)) ... pen.addPoint((2, 2))
... pen.addPoint((3, 3), "curve") ... pen.addPoint((3, 3), "curve")
... pen.endPath() ... pen.endPath()
>>> class CompositeGlyph(object): >>> class CompositeGlyph(object):
... def drawPoints(self, pen): ... def drawPoints(self, pen):
... pen.addComponent('a', (1, 0, 0, 1, -1, 1)) ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
>>> class MissingComponent(object): >>> class MissingComponent(object):
... def drawPoints(self, pen): ... def drawPoints(self, pen):
... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0)) ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
>>> class FlippedComponent(object): >>> class FlippedComponent(object):
... def drawPoints(self, pen): ... def drawPoints(self, pen):
... pen.addComponent('a', (-1, 0, 0, 1, 0, 0)) ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
>>> glyphSet = { >>> glyphSet = {
... 'a': SimpleGlyph(), ... 'a': SimpleGlyph(),
... 'b': CompositeGlyph(), ... 'b': CompositeGlyph(),
... 'c': MissingComponent(), ... 'c': MissingComponent(),
... 'd': FlippedComponent(), ... 'd': FlippedComponent(),
... } ... }
>>> for name, glyph in sorted(glyphSet.items()): >>> for name, glyph in sorted(glyphSet.items()):
... pen = DecomposingRecordingPointPen(glyphSet) ... pen = DecomposingRecordingPointPen(glyphSet)
... try: ... try:
... glyph.drawPoints(pen) ... glyph.drawPoints(pen)
... except pen.MissingComponentError: ... except pen.MissingComponentError:
... pass ... pass
... pprint({name: pen.value}) ... pprint({name: pen.value})
{'a': [('beginPath', (), {}), {'a': [('beginPath', (), {}),
('addPoint', ((0, 0), 'line', False, None), {}), ('addPoint', ((0, 0), 'line', False, None), {}),
('addPoint', ((1, 1), None, False, None), {}), ('addPoint', ((1, 1), None, False, None), {}),
('addPoint', ((2, 2), None, False, None), {}), ('addPoint', ((2, 2), None, False, None), {}),
('addPoint', ((3, 3), 'curve', False, None), {}), ('addPoint', ((3, 3), 'curve', False, None), {}),
('endPath', (), {})]} ('endPath', (), {})]}
{'b': [('beginPath', (), {}), {'b': [('beginPath', (), {}),
('addPoint', ((-1, 1), 'line', False, None), {}), ('addPoint', ((-1, 1), 'line', False, None), {}),
('addPoint', ((0, 2), None, False, None), {}), ('addPoint', ((0, 2), None, False, None), {}),
('addPoint', ((1, 3), None, False, None), {}), ('addPoint', ((1, 3), None, False, None), {}),
('addPoint', ((2, 4), 'curve', False, None), {}), ('addPoint', ((2, 4), 'curve', False, None), {}),
('endPath', (), {})]} ('endPath', (), {})]}
{'c': []} {'c': []}
{'d': [('beginPath', (), {}), {'d': [('beginPath', (), {}),
('addPoint', ((0, 0), 'line', False, None), {}), ('addPoint', ((0, 0), 'line', False, None), {}),
('addPoint', ((-1, 1), None, False, None), {}), ('addPoint', ((-1, 1), None, False, None), {}),
('addPoint', ((-2, 2), None, False, None), {}), ('addPoint', ((-2, 2), None, False, None), {}),
('addPoint', ((-3, 3), 'curve', False, None), {}), ('addPoint', ((-3, 3), 'curve', False, None), {}),
('endPath', (), {})]} ('endPath', (), {})]}
>>> for name, glyph in sorted(glyphSet.items()):
... pen = DecomposingRecordingPointPen( >>> for name, glyph in sorted(glyphSet.items()):
... glyphSet, skipMissingComponents=True, reverseFlipped=True, ... pen = DecomposingRecordingPointPen(
... ) ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
... glyph.drawPoints(pen) ... )
... pprint({name: pen.value}) ... glyph.drawPoints(pen)
{'a': [('beginPath', (), {}), ... pprint({name: pen.value})
('addPoint', ((0, 0), 'line', False, None), {}), {'a': [('beginPath', (), {}),
('addPoint', ((1, 1), None, False, None), {}), ('addPoint', ((0, 0), 'line', False, None), {}),
('addPoint', ((2, 2), None, False, None), {}), ('addPoint', ((1, 1), None, False, None), {}),
('addPoint', ((3, 3), 'curve', False, None), {}), ('addPoint', ((2, 2), None, False, None), {}),
('endPath', (), {})]} ('addPoint', ((3, 3), 'curve', False, None), {}),
{'b': [('beginPath', (), {}), ('endPath', (), {})]}
('addPoint', ((-1, 1), 'line', False, None), {}), {'b': [('beginPath', (), {}),
('addPoint', ((0, 2), None, False, None), {}), ('addPoint', ((-1, 1), 'line', False, None), {}),
('addPoint', ((1, 3), None, False, None), {}), ('addPoint', ((0, 2), None, False, None), {}),
('addPoint', ((2, 4), 'curve', False, None), {}), ('addPoint', ((1, 3), None, False, None), {}),
('endPath', (), {})]} ('addPoint', ((2, 4), 'curve', False, None), {}),
{'c': []} ('endPath', (), {})]}
{'d': [('beginPath', (), {}), {'c': []}
('addPoint', ((0, 0), 'curve', False, None), {}), {'d': [('beginPath', (), {}),
('addPoint', ((-3, 3), 'line', False, None), {}), ('addPoint', ((0, 0), 'curve', False, None), {}),
('addPoint', ((-2, 2), None, False, None), {}), ('addPoint', ((-3, 3), 'line', False, None), {}),
('addPoint', ((-1, 1), None, False, None), {}), ('addPoint', ((-2, 2), None, False, None), {}),
('endPath', (), {})]} ('addPoint', ((-1, 1), None, False, None), {}),
('endPath', (), {})]}
""" """
# raises MissingComponentError(KeyError) if base glyph is not found in glyphSet # raises MissingComponentError(KeyError) if base glyph is not found in glyphSet

View File

@ -9,27 +9,30 @@ def pointToString(pt, ntos=str):
class SVGPathPen(BasePen): class SVGPathPen(BasePen):
"""Pen to draw SVG path d commands. """Pen to draw SVG path d commands.
Example::
>>> pen = SVGPathPen(None)
>>> pen.moveTo((0, 0))
>>> pen.lineTo((1, 1))
>>> pen.curveTo((2, 2), (3, 3), (4, 4))
>>> pen.closePath()
>>> pen.getCommands()
'M0 0 1 1C2 2 3 3 4 4Z'
Args: Args:
glyphSet: a dictionary of drawable glyph objects keyed by name glyphSet: a dictionary of drawable glyph objects keyed by name
used to resolve component references in composite glyphs. used to resolve component references in composite glyphs.
ntos: a callable that takes a number and returns a string, to ntos: a callable that takes a number and returns a string, to
customize how numbers are formatted (default: str). customize how numbers are formatted (default: str).
:Example:
.. code-block::
>>> pen = SVGPathPen(None)
>>> pen.moveTo((0, 0))
>>> pen.lineTo((1, 1))
>>> pen.curveTo((2, 2), (3, 3), (4, 4))
>>> pen.closePath()
>>> pen.getCommands()
'M0 0 1 1C2 2 3 3 4 4Z'
Note: Note:
Fonts have a coordinate system where Y grows up, whereas in SVG, Fonts have a coordinate system where Y grows up, whereas in SVG,
Y grows down. As such, rendering path data from this pen in Y grows down. As such, rendering path data from this pen in
SVG typically results in upside-down glyphs. You can fix this SVG typically results in upside-down glyphs. You can fix this
by wrapping the data from this pen in an SVG group element with by wrapping the data from this pen in an SVG group element with
transform, or wrap this pen in a transform pen. For example: transform, or wrap this pen in a transform pen. For example:
.. code-block:: python
spen = svgPathPen.SVGPathPen(glyphset) spen = svgPathPen.SVGPathPen(glyphset)
pen= TransformPen(spen , (1, 0, 0, -1, 0, 0)) pen= TransformPen(spen , (1, 0, 0, -1, 0, 0))

View File

@ -58,22 +58,27 @@ class TransformPointPen(FilterPointPen):
"""PointPen that transforms all coordinates using a Affine transformation, """PointPen that transforms all coordinates using a Affine transformation,
and passes them to another PointPen. and passes them to another PointPen.
>>> from fontTools.pens.recordingPen import RecordingPointPen For example::
>>> rec = RecordingPointPen()
>>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5)) >>> from fontTools.pens.recordingPen import RecordingPointPen
>>> v = iter(rec.value) >>> rec = RecordingPointPen()
>>> pen.beginPath(identifier="contour-0") >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5))
>>> next(v) >>> v = iter(rec.value)
('beginPath', (), {'identifier': 'contour-0'}) >>> pen.beginPath(identifier="contour-0")
>>> pen.addPoint((100, 100), "line") >>> next(v)
>>> next(v) ('beginPath', (), {'identifier': 'contour-0'})
('addPoint', ((190, 205), 'line', False, None), {})
>>> pen.endPath() >>> pen.addPoint((100, 100), "line")
>>> next(v) >>> next(v)
('endPath', (), {}) ('addPoint', ((190, 205), 'line', False, None), {})
>>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
>>> next(v) >>> pen.endPath()
('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'}) >>> next(v)
('endPath', (), {})
>>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
>>> next(v)
('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'})
""" """
def __init__(self, outPointPen, transformation): def __init__(self, outPointPen, transformation):

View File

@ -14,6 +14,8 @@ class SVGPath(object):
For example, reading from an SVG file and drawing to a Defcon Glyph: For example, reading from an SVG file and drawing to a Defcon Glyph:
.. code-block::
import defcon import defcon
glyph = defcon.Glyph() glyph = defcon.Glyph()
pen = glyph.getPen() pen = glyph.getPen()
@ -23,6 +25,8 @@ class SVGPath(object):
Or reading from a string containing SVG data, using the alternative Or reading from a string containing SVG data, using the alternative
'fromstring' (a class method): 'fromstring' (a class method):
.. code-block::
data = '<?xml version="1.0" ...' data = '<?xml version="1.0" ...'
svg = SVGPath.fromstring(data) svg = SVGPath.fromstring(data)
svg.draw(pen) svg.draw(pen)

View File

@ -103,6 +103,8 @@ def parse_path(pathdef, pen, current_pos=(0, 0), arc_class=EllipticalArc):
If the pen has an "arcTo" method, it is called with the original values If the pen has an "arcTo" method, it is called with the original values
of the elliptical arc curve commands: of the elliptical arc curve commands:
.. code-block::
pen.arcTo(rx, ry, rotation, arc_large, arc_sweep, (x, y)) pen.arcTo(rx, ry, rotation, arc_large, arc_sweep, (x, y))
Otherwise, the arcs are approximated by series of cubic Bezier segments Otherwise, the arcs are approximated by series of cubic Bezier segments

View File

@ -1,8 +1,9 @@
"""ttLib/sfnt.py -- low-level module to deal with the sfnt file format. """ttLib/sfnt.py -- low-level module to deal with the sfnt file format.
Defines two public classes: Defines two public classes:
SFNTReader
SFNTWriter - SFNTReader
- SFNTWriter
(Normally you don't have to use these classes explicitly; they are (Normally you don't have to use these classes explicitly; they are
used automatically by ttLib.TTFont.) used automatically by ttLib.TTFont.)

View File

@ -26,37 +26,43 @@ class TTFont(object):
accessing tables. Tables will be only decompiled when necessary, ie. when accessing tables. Tables will be only decompiled when necessary, ie. when
they're actually accessed. This means that simple operations can be extremely fast. they're actually accessed. This means that simple operations can be extremely fast.
Example usage:: Example usage:
.. code-block:: pycon
>> from fontTools import ttLib >>>
>> tt = ttLib.TTFont("afont.ttf") # Load an existing font file >> from fontTools import ttLib
>> tt['maxp'].numGlyphs >> tt = ttLib.TTFont("afont.ttf") # Load an existing font file
242 >> tt['maxp'].numGlyphs
>> tt['OS/2'].achVendID 242
'B&H\000' >> tt['OS/2'].achVendID
>> tt['head'].unitsPerEm 'B&H\000'
2048 >> tt['head'].unitsPerEm
2048
For details of the objects returned when accessing each table, see :ref:`tables`. For details of the objects returned when accessing each table, see :ref:`tables`.
To add a table to the font, use the :py:func:`newTable` function:: To add a table to the font, use the :py:func:`newTable` function:
.. code-block:: pycon
>> os2 = newTable("OS/2") >>>
>> os2.version = 4 >> os2 = newTable("OS/2")
>> # set other attributes >> os2.version = 4
>> font["OS/2"] = os2 >> # set other attributes
>> font["OS/2"] = os2
TrueType fonts can also be serialized to and from XML format (see also the TrueType fonts can also be serialized to and from XML format (see also the
:ref:`ttx` binary):: :ref:`ttx` binary):
.. code-block:: pycon
>> tt.saveXML("afont.ttx") >>
Dumping 'LTSH' table... >> tt.saveXML("afont.ttx")
Dumping 'OS/2' table... Dumping 'LTSH' table...
[...] Dumping 'OS/2' table...
[...]
>> tt2 = ttLib.TTFont() # Create a new font object >> tt2 = ttLib.TTFont() # Create a new font object
>> tt2.importXML("afont.ttx") >> tt2.importXML("afont.ttx")
>> tt2['maxp'].numGlyphs >> tt2['maxp'].numGlyphs
242 242
The TTFont object may be used as a context manager; this will cause the file The TTFont object may be used as a context manager; this will cause the file
reader to be closed after the context ``with`` block is exited:: reader to be closed after the context ``with`` block is exited::
@ -981,14 +987,16 @@ def tagToIdentifier(tag):
letters get an underscore after the letter. Trailing spaces are letters get an underscore after the letter. Trailing spaces are
trimmed. Illegal characters are escaped as two hex bytes. If the trimmed. Illegal characters are escaped as two hex bytes. If the
result starts with a number (as the result of a hex escape), an result starts with a number (as the result of a hex escape), an
extra underscore is prepended. Examples:: extra underscore is prepended. Examples:
.. code-block:: pycon
>>> tagToIdentifier('glyf') >>>
'_g_l_y_f' >> tagToIdentifier('glyf')
>>> tagToIdentifier('cvt ') '_g_l_y_f'
'_c_v_t' >> tagToIdentifier('cvt ')
>>> tagToIdentifier('OS/2') '_c_v_t'
'O_S_2f_2' >> tagToIdentifier('OS/2')
'O_S_2f_2'
""" """
import re import re

View File

@ -7,25 +7,29 @@ of the specification.
Sets that list the font info attribute names for the fontinfo.plist Sets that list the font info attribute names for the fontinfo.plist
formats are available for external use. These are: formats are available for external use. These are:
fontInfoAttributesVersion1
fontInfoAttributesVersion2 - fontInfoAttributesVersion1
fontInfoAttributesVersion3 - fontInfoAttributesVersion2
- fontInfoAttributesVersion3
A set listing the fontinfo.plist attributes that were deprecated A set listing the fontinfo.plist attributes that were deprecated
in version 2 is available for external use: in version 2 is available for external use:
deprecatedFontInfoAttributesVersion2
- deprecatedFontInfoAttributesVersion2
Functions that do basic validation on values for fontinfo.plist Functions that do basic validation on values for fontinfo.plist
are available for external use. These are are available for external use. These are
validateFontInfoVersion2ValueForAttribute
validateFontInfoVersion3ValueForAttribute - validateFontInfoVersion2ValueForAttribute
- validateFontInfoVersion3ValueForAttribute
Value conversion functions are available for converting Value conversion functions are available for converting
fontinfo.plist values between the possible format versions. fontinfo.plist values between the possible format versions.
convertFontInfoValueForAttributeFromVersion1ToVersion2
convertFontInfoValueForAttributeFromVersion2ToVersion1 - convertFontInfoValueForAttributeFromVersion1ToVersion2
convertFontInfoValueForAttributeFromVersion2ToVersion3 - convertFontInfoValueForAttributeFromVersion2ToVersion1
convertFontInfoValueForAttributeFromVersion3ToVersion2 - convertFontInfoValueForAttributeFromVersion2ToVersion3
- convertFontInfoValueForAttributeFromVersion3ToVersion2
""" """
import os import os

View File

@ -10,10 +10,14 @@ ttf-interpolatable files for the masters and build a variable-font from
them. Such ttf-interpolatable and designspace files can be generated from them. Such ttf-interpolatable and designspace files can be generated from
a Glyphs source, eg., using noto-source as an example: a Glyphs source, eg., using noto-source as an example:
.. code-block:: sh
$ fontmake -o ttf-interpolatable -g NotoSansArabic-MM.glyphs $ fontmake -o ttf-interpolatable -g NotoSansArabic-MM.glyphs
Then you can make a variable-font this way: Then you can make a variable-font this way:
.. code-block:: sh
$ fonttools varLib master_ufo/NotoSansArabic.designspace $ fonttools varLib master_ufo/NotoSansArabic.designspace
API *will* change in near future. API *will* change in near future.

View File

@ -96,7 +96,7 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
* step through each key in FontDict.Private. * step through each key in FontDict.Private.
* For each key, step through each relevant source font Private dict, and * For each key, step through each relevant source font Private dict, and
build a list of values to blend. build a list of values to blend.
The 'relevant' source fonts are selected by first getting the right The 'relevant' source fonts are selected by first getting the right
submodel using ``vsindex_dict[vsindex]``. The indices of the submodel using ``vsindex_dict[vsindex]``. The indices of the

View File

@ -5,7 +5,9 @@ create full instances (i.e. static fonts) from variable fonts, as well as "parti
variable fonts that only contain a subset of the original variation space. variable fonts that only contain a subset of the original variation space.
For example, if you wish to pin the width axis to a given location while also For example, if you wish to pin the width axis to a given location while also
restricting the weight axis to 400..700 range, you can do:: restricting the weight axis to 400..700 range, you can do:
.. code-block:: sh
$ fonttools varLib.instancer ./NotoSans-VF.ttf wdth=85 wght=400:700 $ fonttools varLib.instancer ./NotoSans-VF.ttf wdth=85 wght=400:700
@ -17,32 +19,38 @@ and returns a new TTFont representing either a partial VF, or full instance if a
the VF axes were given an explicit coordinate. the VF axes were given an explicit coordinate.
E.g. here's how to pin the wght axis at a given location in a wght+wdth variable E.g. here's how to pin the wght axis at a given location in a wght+wdth variable
font, keeping only the deltas associated with the wdth axis:: font, keeping only the deltas associated with the wdth axis:
.. code-block:: pycon
| >>> from fontTools import ttLib >>>
| >>> from fontTools.varLib import instancer >> from fontTools import ttLib
| >>> varfont = ttLib.TTFont("path/to/MyVariableFont.ttf") >> from fontTools.varLib import instancer
| >>> [a.axisTag for a in varfont["fvar"].axes] # the varfont's current axes >> varfont = ttLib.TTFont("path/to/MyVariableFont.ttf")
| ['wght', 'wdth'] >> [a.axisTag for a in varfont["fvar"].axes] # the varfont's current axes
| >>> partial = instancer.instantiateVariableFont(varfont, {"wght": 300}) ['wght', 'wdth']
| >>> [a.axisTag for a in partial["fvar"].axes] # axes left after pinning 'wght' >> partial = instancer.instantiateVariableFont(varfont, {"wght": 300})
| ['wdth'] >> [a.axisTag for a in partial["fvar"].axes] # axes left after pinning 'wght'
['wdth']
If the input location specifies all the axes, the resulting instance is no longer If the input location specifies all the axes, the resulting instance is no longer
'variable' (same as using fontools varLib.mutator): 'variable' (same as using fontools varLib.mutator):
.. code-block:: pycon
| >>> instance = instancer.instantiateVariableFont( >>>
| ... varfont, {"wght": 700, "wdth": 67.5} >> instance = instancer.instantiateVariableFont(
| ... ) ... varfont, {"wght": 700, "wdth": 67.5}
| >>> "fvar" not in instance ... )
| True >> "fvar" not in instance
True
If one just want to drop an axis at the default location, without knowing in If one just want to drop an axis at the default location, without knowing in
advance what the default value for that axis is, one can pass a `None` value: advance what the default value for that axis is, one can pass a `None` value:
.. code-block:: pycon
| >>> instance = instancer.instantiateVariableFont(varfont, {"wght": None}) >>>
| >>> len(varfont["fvar"].axes) >> instance = instancer.instantiateVariableFont(varfont, {"wght": None})
| 1 >> len(varfont["fvar"].axes)
1
From the console script, this is equivalent to passing `wght=drop` as input. From the console script, this is equivalent to passing `wght=drop` as input.
@ -56,25 +64,33 @@ course be combined:
L1 L1
dropping one or more axes while leaving the default tables unmodified; dropping one or more axes while leaving the default tables unmodified;
.. code-block:: pycon
| >>> font = instancer.instantiateVariableFont(varfont, {"wght": None}) >>>
>> font = instancer.instantiateVariableFont(varfont, {"wght": None})
L2 L2
dropping one or more axes while pinning them at non-default locations; dropping one or more axes while pinning them at non-default locations;
.. code-block:: pycon
| >>> font = instancer.instantiateVariableFont(varfont, {"wght": 700})
>>>
>> font = instancer.instantiateVariableFont(varfont, {"wght": 700})
L3 L3
restricting the range of variation of one or more axes, by setting either restricting the range of variation of one or more axes, by setting either
a new minimum or maximum, potentially -- though not necessarily -- dropping a new minimum or maximum, potentially -- though not necessarily -- dropping
entire regions of variations that fall completely outside this new range. entire regions of variations that fall completely outside this new range.
.. code-block:: pycon
| >>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300)})
>>>
>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300)})
L4 L4
moving the default location of an axis, by specifying (min,defalt,max) values: moving the default location of an axis, by specifying (min,defalt,max) values:
.. code-block:: pycon
| >>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300, 700)})
>>>
>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300, 700)})
Currently only TrueType-flavored variable fonts (i.e. containing 'glyf' table) Currently only TrueType-flavored variable fonts (i.e. containing 'glyf' table)
are supported, but support for CFF2 variable fonts will be added soon. are supported, but support for CFF2 variable fonts will be added soon.

View File

@ -1,7 +1,9 @@
""" """
Instantiate a variation font. Run, eg: Instantiate a variation font. Run, eg:
$ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85 .. code-block:: sh
$ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
""" """
from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed
@ -162,7 +164,9 @@ def instantiateVariableFont(varfont, location, inplace=False, overlap=True):
defining the desired location along the variable font's axes. defining the desired location along the variable font's axes.
The location values must be specified as user-space coordinates, e.g.: The location values must be specified as user-space coordinates, e.g.:
{'wght': 400, 'wdth': 100} .. code-block::
{'wght': 400, 'wdth': 100}
By default, a new TTFont object is returned. If ``inplace`` is True, the By default, a new TTFont object is returned. If ``inplace`` is True, the
input varfont is modified and reduced to a static font. input varfont is modified and reduced to a static font.

View File

@ -7,12 +7,16 @@ Usage
To convert a VTP project file: To convert a VTP project file:
.. code-block:: sh
$ fonttools voltLib.voltToFea input.vtp output.fea $ fonttools voltLib.voltToFea input.vtp output.fea
It is also possible convert font files with `TSIV` table (as saved from Volt), It is also possible convert font files with `TSIV` table (as saved from Volt),
in this case the glyph names used in the Volt project will be mapped to the in this case the glyph names used in the Volt project will be mapped to the
actual glyph names in the font files when written to the feature file: actual glyph names in the font files when written to the feature file:
.. code-block:: sh
$ fonttools voltLib.voltToFea input.ttf output.fea $ fonttools voltLib.voltToFea input.ttf output.fea
The ``--quiet`` option can be used to suppress warnings. The ``--quiet`` option can be used to suppress warnings.