Programmatically manipulating typefaces

#!/usr/bin/env python

# usage: $ python rotate-font-fontforge.py "League Gothic.ufo" League-Gothic-tranformed.ufo

import fontforge
import psMat
import math
import sys

matrix = psMat.rotate(math.radians(45))

font = fontforge.open(sys.argv[1])

for glyph in font.glyphs():
    glyph.transform(matrix)

font.generate(sys.argv[2])

If you like programming, chances are you like typefaces. My favourite tumblelog, by developer Christian Neukirchen, often links to type design projects. As does Hacker News. And programming demigod Donald Knuth took time off from his epos The Art of Computer Programming to develop his own parametric typeface. And the language that describes it. And an accompanying lay out engine.

Typefaces are wonderful hybrids between design and tool. More so than any other type of design they are made to be reused. And more so than any other type of design they have a predictable structure (a font made out of glyphs made out of contours made out of points), that makes them especially suitable to be manipulated through computer programs of your own devising.

Yet if you haven’t worked within the confines of the type design world, chances are you have not yet experienced exactly how straightforward it is to work with typefaces programmatically, nowadays.

Yes, your typical binary font file is quite messy to open up and to play around with. That is why it is nice if you can use a programming library to access them. But in addition we now have the UFO file format, which is meant as an open, hackable file format for fonts. And there exist two libraries that really make it really easy to deal with font objects in a high level fashion: Robofab and FontForge-python. They allow you to iterate over all the glyphs, contours and points in your font in order to change them around.

Both libraries are written in the Python language. There is a historical reason for this. The typographers Just van Rossum and Erik van Blokland are pioneers in scripting for type design. Their choice to go with Python has contributed to making it the go to scripting language in the type design world.

I can imagine that reasons for choosing Python include that it is straightforward and high leveland in being white space sensitive it is arguably one of the few languages which is opiniated typographically! I imagine it also played a role that Just van Rossum is the brother of Guido van Rossum, who wrote the Python language.

If you already know Python, you are in luck. If you know programming, but do not know Python, it is pretty easy to pick up. And if you do not write programs yet, Python is a great language to get started as it is quite straightforward and consistent.

RoboFab is made by the aforementioned Dutch duo, joined by Tal Leming. It started its life as a scripting language for Fontlab, one of the more popular commercial font editors (and for quite some time the only one). But since the inception of the UFO file format, you can use the RoboFab library in your stand alone python scripts.

A downside to RoboFab is that it will only work with UFO fonts. In this sense the Python extension to FontForge is more flexible. It makes a lot of the functionality of FontForge available to Python: FontForge is the main open source font editor. With python-fontforge you can open and save in a slew of different font formats. It is also easy to export individual glyphs to images, or to import vector shapes into your font.

A downside to python-fontforge is that it might be tricky to install. On Linux it is usually quite easy (Debian/ubuntu: sudo apt-get install fontforge python-fontforge). On the Mac it used to be more hard: installing the Python extension through Homebrew is not working out yet. Luckily, developer Jeff Escelante recently reached out to me over this issue. He is now providing a Fontforge installer for Mac OSX that provides the python extension. But on Windows, I am not sure how feasible it is to get python-fontforge working? If someone could re-package the whole thing is an easy_installable package that would be wonderful.

In implementation the two libraries are quite similar. Imagine we have downloaded the open source League Gothic in UFO format (link! The ufo is in the source folder) and you put the UFO in the same folder as your python script.

Here is how you load in a font and print the names of the glyphs:

Fontforge

#!/usr/bin/env python

# usage: $ python print-glyphs-fontforge.py "League-Gothic.ufo"

import fontforge
import sys

font = fontforge.open(sys.argv[1])

for glyph in font.glyphs():
    print glyph

Robofab

#!/usr/bin/env python

# usage: $ python print-glyphs-robofab.py "League Gothic.ufo"

from robofab.world import RFont
import sys

font = RFont(sys.argv[1])

for glyph in font:
    print glyph.name

And this is to rotate each glyph 45 degrees and save to a new font.

Fontforge:

#!/usr/bin/env python

# usage: $ python rotate-font-fontforge.py "League Gothic.ufo" League-Gothic-tranformed.ufo

import fontforge
import psMat
import math
import sys

matrix = psMat.rotate(math.radians(45))

font = fontforge.open(sys.argv[1])

for glyph in font.glyphs():
    glyph.transform(matrix)

font.generate(sys.argv[2])

Robofab:

#!/usr/bin/env python

# usage: $ python rotate-font.py "League Gothic.ufo" League-Gothic-tranformed.ufo

from robofab.world import RFont
from fontTools.misc.transform import Identity
import math
import sys

matrix = Identity
matrix = matrix.rotate(math.radians(45))

font = RFont(sys.argv[1])

for glyph in font:
    glyph.transform(matrix)

font.save(sys.argv[2])

This article started out as a presentation for Montreal Python. It got finished on the occasion of the OSP workshops Morphologic at the Merz Akademie, Stuttgart and Write me a shadow, at the ESAD Valence.

9 Comments

There's also cool stuff you can do if you save the font as an SVG font. You can then just manipulate all of the nodes

With the rotation script, you might want to add something that changes the font name, otherwise you will get conflicts when installing both the original and the converted version.

There is three names to change. The Family name is the name shared by all the weights / variations of the font, i.e. ‘œLeague Gothic’. The Full name includes the specific variation ‘œLeague Gothic Bold’. The PostScript Font name is the same but without spaces. The latter is still being used by Mac OSX to identify typeface conflicts.

FontForge:

font.familyname += " Rotated"
font.fullname += " Rotated"
font.fontname += "-Rotated"

Robofab:

font.info.familyName += " Rotated"
font.info.fullName += " Rotated"
font.info.postscriptFontName += "-Rotated"

This is quite appropriate! I’m writing my thesis on the subject of conceptual manipulations of typefaces. Joost said I should follow your workshop. So a program can constitute a specific manipulationfor example, how would you go about to remove the curves from a typeface, €œto make all curves straight?

Sure!

from robofab.world import CurrentFont
font = CurrentFont()
for g in [glyph.name for glyph in font]:
    old = font[g]
    print len(old)
    new = font.newGlyph("dummytmp", clear=True)


    pen = new.getPointPen()
    for contour in old:
        pen.beginPath()
        for point in contour.points:
            if point.type != "offCurve":
                pen.addPoint((point.x,point.y),"line")
        pen.endPath()


    font.newGlyph(g, clear=True)
    old.appendGlyph(new)
font.removeGlyph("dummytmp")
font.update()

Yes so John Haltiwanger and me spent some time figuring this out for the workshop in Stuttgart. Basically we’re reconstructing the contours in the glyph point by point, but we skip off curve pointsthese are the control handles to the béziers. Without the control handles the curves become straight lines.

URW Palladio L Bold

becomes

URW Palladio L Bold

The new contours are first written to a temporary glyph, then they replace they old contours.

Oh my god!Oh my god!

I wonder why the metrics changed

 JajaJaja

Colorfonts! Combining superpositions with libre typefaces processed by scripts, that is what we did with at another workshop, Write me a shadow, in Valence.

Hey, now they are aligned again weird.

Note that your Make Curves Straight script is written to be used from within the font editor In this scenario CurrentFont() returns the currently selected font.

RoboFab is implemented in RoboFont and can be installed for Glyphs and Fontlab, so you can run scripts from the interface.

To make the script into a command line script just substitute the CurrentFont with the RFont object and the argv syntaxis like in the blog post.

Obviously these kind of manipulations only make sense with open source fonts The End User License Agreements of most typefaces expressly forbid manipulation, let only the redistribution of the manipulated versions

Reply

Leave a comment