You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
7.6 KiB
254 lines
7.6 KiB
#######################
|
|
Scripting a designspace
|
|
#######################
|
|
|
|
It can be useful to build a designspace with a script rather than
|
|
construct one with an interface like
|
|
`Superpolator <http://superpolator.com>`__ or
|
|
`DesignSpaceEditor <https://github.com/LettError/designSpaceRoboFontExtension>`__.
|
|
|
|
`fontTools.designspaceLib` offers a some tools for building designspaces in
|
|
Python. This document shows an example.
|
|
|
|
********************************
|
|
Filling-in a DesignSpaceDocument
|
|
********************************
|
|
|
|
So, suppose you installed the `fontTools` package through your favorite
|
|
``git`` client.
|
|
|
|
The ``DesignSpaceDocument`` object represents the document, whether it
|
|
already exists or not. Make a new one:
|
|
|
|
.. code:: python
|
|
|
|
from fontTools.designspaceLib import (DesignSpaceDocument, AxisDescriptor,
|
|
SourceDescriptor, InstanceDescriptor)
|
|
doc = DesignSpaceDocument()
|
|
|
|
We want to create definitions for axes, sources and instances. That
|
|
means there are a lot of attributes to set. The **DesignSpaceDocument
|
|
object** uses objects to describe the axes, sources and instances. These
|
|
are relatively simple objects, think of these as collections of
|
|
attributes.
|
|
|
|
- Attributes of the :ref:`source-descriptor-object`
|
|
- Attributes of the :ref:`instance-descriptor-object`
|
|
- Attributes of the :ref:`axis-descriptor-object`
|
|
- Read about :ref:`subclassing-descriptors`
|
|
|
|
Make an axis object
|
|
===================
|
|
|
|
Make a descriptor object and add it to the document.
|
|
|
|
.. code:: python
|
|
|
|
a1 = AxisDescriptor()
|
|
a1.maximum = 1000
|
|
a1.minimum = 0
|
|
a1.default = 0
|
|
a1.name = "weight"
|
|
a1.tag = "wght"
|
|
doc.addAxis(a1)
|
|
|
|
- You can add as many axes as you need. OpenType has a maximum of
|
|
around 64K. DesignSpaceEditor has a maximum of 5.
|
|
- The ``name`` attribute is the name you'll be using as the axis name
|
|
in the locations.
|
|
- The ``tag`` attribute is the one of the registered `OpenType
|
|
Variation Axis
|
|
Tags <https://www.microsoft.com/typography/otspec/fvar.htm#VAT>`__
|
|
- The default master is expected at the intersection of all
|
|
default values of all axes.
|
|
|
|
Option: add label names
|
|
-----------------------
|
|
|
|
The **labelnames** attribute is intended to store localisable, human
|
|
readable names for this axis if this is not an axis that is registered
|
|
by OpenType. Think "The label next to the slider". The attribute is a
|
|
dictionary. The key is the `xml language
|
|
tag <https://www.w3.org/International/articles/language-tags/>`__, the
|
|
value is a ``unicode`` string with the name. Whether or not this attribute is
|
|
used depends on the font building tool, the operating system and the
|
|
authoring software. This, at least, is the place to record it.
|
|
|
|
.. code:: python
|
|
|
|
a1.labelNames['fa-IR'] = u"قطر"
|
|
a1.labelNames['en'] = u"Wéíght"
|
|
|
|
Option: add a map
|
|
-----------------
|
|
|
|
The **map** attribute is a list of (input, output) mapping values
|
|
intended for `axis variations table of
|
|
OpenType <https://www.microsoft.com/typography/otspec/avar.htm>`__.
|
|
|
|
.. code:: python
|
|
|
|
a1.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)]
|
|
|
|
Make a source object
|
|
====================
|
|
|
|
A **source** is an object that points to a UFO file. It provides the
|
|
outline geometry, kerning and font.info that we want to work with.
|
|
|
|
.. code:: python
|
|
|
|
s0 = SourceDescriptor()
|
|
s0.path = "my/path/to/thin.ufo"
|
|
s0.name = "master.thin"
|
|
s0.location = dict(weight=0)
|
|
doc.addSource(s0)
|
|
|
|
- You'll need to have at least 2 sources in your document, so go ahead
|
|
and add another one.
|
|
- The **location** attribute is a dictionary with the designspace
|
|
location for this master.
|
|
- The axis names in the location have to match one of the ``axis.name``
|
|
values you defined before.
|
|
- The **path** attribute is the absolute path to an existing UFO.
|
|
- The **name** attribute is a unique name for this source used to keep
|
|
track it.
|
|
- The **layerName** attribute is the name of the UFO3 layer. Default None for ``foreground``.
|
|
|
|
So go ahead and add another master:
|
|
|
|
.. code:: python
|
|
|
|
s1 = SourceDescriptor()
|
|
s1.path = "my/path/to/bold.ufo"
|
|
s1.name = "master.bold"
|
|
s1.location = dict(weight=1000)
|
|
doc.addSource(s1)
|
|
|
|
|
|
Option: exclude glyphs
|
|
----------------------
|
|
|
|
By default all glyphs in a source will be processed. If you want to
|
|
exclude certain glyphs, add their names to the ``mutedGlyphNames`` list.
|
|
|
|
.. code:: python
|
|
|
|
s1.mutedGlyphNames = ["A.test", "A.old"]
|
|
|
|
Make an instance object
|
|
=======================
|
|
|
|
An **instance** is description of a UFO that you want to generate with
|
|
the designspace. For an instance you can define more things. If you want
|
|
to generate UFO instances with MutatorMath then you can define different
|
|
names and set flags for if you want to generate kerning and font info
|
|
and so on. You can also set a path where to generate the instance.
|
|
|
|
.. code:: python
|
|
|
|
i0 = InstanceDescriptor()
|
|
i0.familyName = "MyVariableFontPrototype"
|
|
i0.styleName = "Medium"
|
|
i0.path = os.path.join(root, "instances","MyVariableFontPrototype-Medium.ufo")
|
|
i0.location = dict(weight=500)
|
|
i0.kerning = True
|
|
i0.info = True
|
|
doc.addInstance(i0)
|
|
|
|
- The ``path`` attribute needs to be the absolute (real or intended)
|
|
path for the instance. When the document is saved this path will
|
|
written as relative to the path of the document.
|
|
- instance paths should be on the same level as the document, or in a
|
|
level below.
|
|
- Instances for MutatorMath will generate to UFO.
|
|
- Instances for variable fonts become **named instances**.
|
|
|
|
Option: add more names
|
|
----------------------
|
|
|
|
If you want you can add a PostScript font name, a stylemap familyName
|
|
and a stylemap styleName.
|
|
|
|
.. code:: python
|
|
|
|
i0.postScriptFontName = "MyVariableFontPrototype-Medium"
|
|
i0.styleMapFamilyName = "MyVarProtoMedium"
|
|
i0.styleMapStyleName = "regular"
|
|
|
|
Option: add glyph specific masters
|
|
----------------------------------
|
|
|
|
This bit is not supported by OpenType variable fonts, but it is needed
|
|
for some designspaces intended for generating instances with
|
|
MutatorMath. The code becomes a bit verbose, so you're invited to wrap
|
|
this into something clever.
|
|
|
|
.. code:: python
|
|
|
|
# we're making a dict with all sorts of
|
|
#(optional) settings for a glyph.
|
|
#In this example: the dollar.
|
|
glyphData = dict(name="dollar", unicodeValue=0x24)
|
|
|
|
# you can specify a different location for a glyph
|
|
glyphData['instanceLocation'] = dict(weight=500)
|
|
|
|
# You can specify different masters
|
|
# for this specific glyph.
|
|
# You can also give those masters new
|
|
# locations. It's a miniature designspace.
|
|
# Remember the "name" attribute we assigned to the sources?
|
|
glyphData['masters'] = [
|
|
dict(font="master.thin",
|
|
glyphName="dollar.nostroke",
|
|
location=dict(weight=0)),
|
|
dict(font="master.bold",
|
|
glyphName="dollar.nostroke",
|
|
location=dict(weight=1000)),
|
|
]
|
|
|
|
# With all of that set up, store it in the instance.
|
|
i4.glyphs['dollar'] = glyphData
|
|
|
|
******
|
|
Saving
|
|
******
|
|
|
|
.. code:: python
|
|
|
|
path = "myprototype.designspace"
|
|
doc.write(path)
|
|
|
|
************************
|
|
Reading old designspaces
|
|
************************
|
|
|
|
Old designspace files might not contain ``axes`` definitions. This is
|
|
how you reconstruct the axes from the extremes of the source locations
|
|
|
|
.. code:: python
|
|
|
|
doc.checkAxes()
|
|
|
|
This is how you check the default font.
|
|
|
|
.. code:: python
|
|
|
|
doc.checkDefault()
|
|
|
|
***********
|
|
Generating?
|
|
***********
|
|
|
|
You can generate the UFO's with MutatorMath:
|
|
|
|
.. code:: python
|
|
|
|
from mutatorMath.ufo import build
|
|
build("whatevs/myprototype.designspace")
|
|
|
|
- Assuming the outline data in the masters is compatible.
|
|
|
|
Or you can use the file in making a **variable font** with varlib.
|