Scripting Glyphs, part 1
This is the first of a series of Python tutorials. No prior knowledge required. In this first installment, we’ll make our first steps in the Macro window.
This multi-part tutorial will get you started with Python. You can read through it all in one morning, have lunch, and write your first scripts in the afternoon of the same day. Have fun!
The macro panel
Go to the Window menu and choose Macro Panel (Opt-Cmd-M). You’ll get a window like this:
The upper half is for you to write Python code in. In the lower half, Glyphs can react and answer to your code. You can drag the horizontal separator line to a position you’re comfortable with. Alright, let’s give Glyphs something to react to. Start by typing this line into the upper half:
print( "Hello World!" )
Uppercase/lowercase is important, so write
It is crucial to open the brackets after
'...' or double
Click on the Run button (Cmd-Return, fn-Return, or Enter on extended keyboards) and you should see something like this:
Strings, integers, floats and objects
Speaking of numbers, you can have Python print the result of any calculation. Python differentiates between whole numbers (‘integers’) and decimal numbers (‘floats’), and will keep the result in integers or decimals depending of what you entered. 5 divided by 2 will result in 2, but 5.0 divided by 2.0 will give you 2.5:
If you click on Run (Cmd-Return) a couple of times, you’ll see the result area cluttering up quickly. Click Clear (Cmd-K) to wipe the slate clean.
Now, let’s have Python print a few other things. Try this:
print( Glyphs )
The result is not very surprising. But
Glyphs is neither a string nor a number calculation, but what we call an object. Now,
Glyphs is an object that contains other objects. To refer to those sub-objects, we add a period to
Glyphs and the name of that sub-object. Try this:
print( Glyphs.fonts ) print( Glyphs.font )
And Python will print the list of currently opened fonts between brackets (the result of
print Glyphs.fonts), plus the frontmost font (the result of
print Glyphs.font). If you have no fonts open, you’ll receive an empty list (brackets with nothing in between) and
None as answer:
Open a few fonts, go back to the Macro Panel and click Clear (Cmd-K) and Run (Cmd-Return) again. Bring different fonts to the front and see what happens if you run your code again.
So, Glyphs.fonts returns a list of fonts. You can access the individual fonts in the list by adding digits in brackets, starting at 0, like this:
print( Glyphs.fonts ) # 1st open font, same as Glyphs.font print( Glyphs.fonts ) # 2nd open font
Oh, yes: the number sign
# marks a comment. Everything following it will be ignored. It’s a good idea to insert descriptive comments into your code. If you try to fix or adapt your script years later, you will thank yourself for your commentary. Really.
And you probably guessed it already: You can use
Glyphs.font as a short cut for
And as you can imagine, even a font has sub-objects. Again, we can address those by adding a period and the object name. Try this:
print( Glyphs.font.glyphs )
You can access individual glyphs by adding either their index number or their name in brackets. Try these:
print( Glyphs.font.glyphs ) print( Glyphs.font.glyphs["a"] )
Again, we can add a period and access whatever information a glyph contains. Try these:
print( Glyphs.font.glyphs["a"].name ) print( Glyphs.font.glyphs["a"].category ) print( Glyphs.font.glyphs["a"].subCategory ) print( Glyphs.font.glyphs["a"].unicode )
Remember, you can use Copy and Paste. You don’t have to retype every line.
Sure enough, this is a pretty inefficient way of accessing glyph info. If we want the same info about b, we’d have to change a to b in four lines. So let’s introduce a variable:
glyphname = "b" print( Glyphs.font.glyphs[glyphname].name ) print( Glyphs.font.glyphs[glyphname].category ) print( Glyphs.font.glyphs[glyphname].subCategory ) print( Glyphs.font.glyphs[glyphname].unicode )
end=" " after the comma to the end of a print command if you want to avoid a linebreak and keep all the info on one line:
glyphname = "b" print( Glyphs.font.glyphs[glyphname].name, end=" " ) print( Glyphs.font.glyphs[glyphname].category, end=" " ) print( Glyphs.font.glyphs[glyphname].subCategory, end=" " ) print( Glyphs.font.glyphs[glyphname].unicode, end=" " )
Now, programming is about not having to retype everything. We should let Python do the repetitive stuff. You see the stuff that stays the same in all lines? Let’s add another variable for that and perhaps a blank line for clarity:
glyphname = "b" myGlyph = Glyphs.font.glyphs[glyphname] print( myGlyph.name, end=" " ) print( myGlyph.category, end=" " ) print( myGlyph.subCategory, end=" " ) print( myGlyph.unicode )
All we need to change now is the glyph name in the first line.
But let’s say, we want those infos for every glyph in the font, what do we do? Sure, we could copy and paste the whole block a hundred times and change the glyph name everywhere. But that’s boring for non-robots, so let’s have Python do that for us:
for myGlyph in Glyphs.font.glyphs: print( myGlyph.name, end=" " ) print( myGlyph.category, end=" " ) print( myGlyph.subCategory, end=" " ) print( myGlyph.unicode )
Note that all the
Python steps through all the glyphs, and prints an info line each time. Hey! This is, like, the first result in this tutorial we can actually use for something. We can, for instance, copy it and paste it into an e-mail for a status report. Let’s make it a little more versatile, get rid of all but one
for myGlyph in Glyphs.font.glyphs: print( myGlyph.name, myGlyph.category, myGlyph.subCategory, myGlyph.unicode )
Now, we want our glyph info report for all open fonts. Luckily, we can nest indentations. How about this:
for myFont in Glyphs.fonts: print() print( "Report for:", myFont.familyName ) for myGlyph in myFont.glyphs: print( myGlyph.name, myGlyph.category, myGlyph.subCategory, myGlyph.unicode )
Want your report to contain other info? Head on over to the Glyphs Python Documentation and see what else the Glyph object (‘GSGlyph’) and the Font object (‘GSFont’) can do for you.
In the next part, we’ll dig a little deeper into GSGlyph and drill all the way down to the nodes.
Update 2014-10-04: added shortcut Glyphs.font, and link to part 2.
Update 2015-07-30: updated Screenshots for Glyphs 2.
Update 2016-12-08: updated screenshots, fixed formatting, use Glyphs.font instead of Glyphs.currentDocument.
Update 2016-12-09: added first paragraph.
Update 2020-12-02: updated for Python3.
Update 2022-18-08: updated title, minor formatting changes, related article.
Update 2022-09-23: fixed a typo (thx Kaliata).