254 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
#######################
 | 
						|
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.
 |