Erik van Blokland 3646055ea2 initial import
git-svn-id: http://svn.robofab.com/trunk@1 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
2008-01-07 17:40:34 +00:00

1789 lines
181 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>
RoboThon06: Print
</title>
<link href="../print.css" type="text/css" rel="stylesheet" />
</head><body>
<div class="content">
<img src="robothon06_logo.gif" alt="robothon06 logo" width="369" height="372" />
<h1>Robothon06 Conference</h1>
<p>
This is a printed version of the notes of the Robothon 06 conference. Robothon 06, Februari 16 and 17 2006, The Hague. Hosted at the Royal Academy of Arts.
</p>
<h2>About the printed version</h2>
<p>
This version of the notes is specially formatted for printing from a browser. As much as such is possible at all, it will produce reasonable results. At the time of the conference, this documentation (or an updated version) is available from <strong>www.letterror.com/code/robothon06/index.html</strong>. Some of the material will be added to the robofab documentation which can be found at <strong>www.robofab.com</strong> but probably not immediately after the conference. The online version has working links and cross references to other sources of documentation.
</p>
<h2>Thanks:</h2>
<p class="small">
<a href="http://www.kabk.nl" target="new" title="Koninklijke Academie van Kunsten">KABK, Royal Academy of Arts: www.kabk.nl</a> for hosting and support.
<br /><a href="http://www.houseind.com" target="new" title="House Industries">House Industries: www.houseind.com</a>
<br /><a href="http://www.fontshop.com" target="new" title="FontShop International">FontShop International: www.fontshop.com</a>
<br /><a href="http://typesupply.com" target="new" title="Type Supply">Type Supply: typesupply.com</a>
<br /><a href="http://letterror.com" target="new" title="LettError">LettError: letterror.com</a>
<br /><a href="http://type-invaders.com/" target="new" title="Type-Invaders">Type-Invaders: type-invaders.com</a>
<br /><a href="http://xml.petr.com/" target="new" title="Buro Petr van Blokland + Claudia Mens">Buro Petr van Blokland: petr.com</a>
<br />The 2005-2006 class of Type]Media.
</p>
<h3>Version</h3>
<p>
This version was generated on Mon Nov 19 20:59:58 2007.
</p>
<h2>Contents</h2>
<p>
<ul>
<li>Editors
</li>
<li>Font and Info objects
</li>
<li>Glyph and Pen objects
</li>
<li>Kerning and glyph building
</li>
<li>Scripting and Interpolation
</li>
<li>Scripting and production
</li>
<li>Scripting and NoneLab
</li>
</ul>
</p>
<img src="robothon06_logo.gif" alt="robothon06 logo" width="369" height="372" />
<h1>
Python, RoboFab, FontLab, Editors
</h1>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_17.gif" width="140" height="96" />
<h2>Scripting?</h2>
<p>
These talks are about scripting. The term <strong>scripting</strong> is loosely defined as "writing small programs" without making it sound as difficult or complicated as "programming". Scripting is programming of course, but you don't have to tell anyone. You're using a programming language, <strong>Python</strong>, to write a script (or whatever you want to call it), which is then acted out by the <strong>Python interpreter</strong>. This is a program which will try to follow your instructions, giving feedback when it runs into problems or finishing the job when it doesn't. Running into problems is not something to be afraid of, Python does it very politely with a <strong>traceback</strong>, Python's way of reporting what went wrong and roughly where it the code it happened. We'll see a lot of these and we'll learn how to read these reports and understand what went wrong.
</p>
<h2>Why?</h2>
<p>
Scripting is not type design. Or perhaps better: scripting is everything but typedesign. Scripts won't help you find ideas or draw a better curve. But it might help you make simple tools for things you need to do often. Just like anything, it will get better with some experience, but even a badly written, simple script can save you lots of time. You don't have to be (or become) a professional programmer to make it a useful skill.
</p>
<h2>Where</h2>
<p>
Python is a modern, open source, programming language which is relatively easy to work with. There are Pythons for all operating systems and it has many developers building many different tools for it. It is not just for fonts and glyphs, there are networking and scientific tools, games, web applications. Years ago <strong>RoboFog</strong> introduced Python to make tools for typedesign and the idea stuck. Now there is a range of type applications that use Python: FontLab, the Adobe FDK, MetricsMachine, RoboFab. Learning Python means you can use your skills in more than one application.
</p>
<p>
There are several places where you can write your code. Each with their own purpose and use. We'll look at some of them:
<ul>
<li><strong>FontLab's Macro panel</strong>: a simple code editor in FontLab where you can edit and run scripts. The advantage is that you're in FontLab and can start work immediately, manipulating fonts and glyphs which are open. But the panel is lacking features which are useful when writing a lot of code, which is why FontLab includes the:</li>
<li><strong>FontLab with "external editor"</strong>: in the FontLab preferences panel you can select another application as your python editor of choice. So when you hit the Macros button, this editor will pop up. This requires that your script is saved in a file somewhere on disk. You can use the editor to write the code, but FontLab will still run the program. FontLab doesn't actually execute the Python code, but uses a system installed interpreter.</li>
<li><strong>Python IDE, Win, Mac OSX:</strong> There are several IDE ("Integrated Development Environment") programs for Python on Mac and Windows. This means basically a Python code editor which can also run your code. Some of them offer debugging tools, module browsers or even complete interface toolkits. These IDE's are general programming tools and don't know much about type specific things. More and more code editors offer Python execution, for instance in <strong>BBEdit</strong> and <strong>Textmate</strong> on OSX you can edit your code, hit a cmd key and have the code run in the OSX Python interpreter. This is similar to the FontLab-with-external-editor option</li>
<li><strong>Command-line python interpreter:</strong> a form of Python where you write a line of code at a prompt and it is immediately executed. Useful to test simple problems, but not for anything over a couple of lines of code.</li>
<li><strong>Command-line python:</strong> use the installed command-line Python interpreter to execute files. The interpreter is called with the filename as an argument
<div class="pythonsource"><pre><span class="py_key">python</span> <span class="py_key">myCode</span>.<span class="py_key">py</span></pre></div>
<div class="pythonoutput"><pre>..<span class="py_key">does</span> <span class="py_key">stuf</span>..</pre></div>
</li>
</ul>
</p>
<h2>Objects</h2>
<p>
Perhaps the most useful invention in programming since the paper-punch card is called <strong>object oriented programming</strong>. The term is used to describe a way of programming in which the data you're working on, and the code which belongs to that data are kept together, much like a person holding a handful of balloons on strings, in a single <strong>object</strong>, the cluster of balloons. This may sound a bit abstract. But it's a way to keep all the code and data sorted in a useful way. Otherwise there will be too much stuff very quickly. More terminology:
<ul>
<li><strong>attributes</strong>: the things an object knows about, its data or value. An object's data is stored in its attributes.</li>
<li><strong>methods</strong>: the things an object can do. The code to manipulate an object, its functions.</li>
</ul>
</p>
<p>
Risking an example: an object of the class <strong>car</strong> has an attribute <strong>color</strong> (blue) and a method <strong>drive</strong> (slow). Big objects are usually split up into smaller, more specific objects. For instance, a <strong>Font</strong> object offers access to <strong>Glyph</strong> objects. The way the various objects relate, wich object contains what etc. — the way something is abstracted — is called an <strong>object model</strong>. A map of the object model used in RoboFab is <a href="http://www.robofab.com/objects/model.html" class="reference" target="new">in the Fab docs</a>. An object model is also called <strong>API</strong> for Application Programming Interface.
</p>
<img src="http://www.robofab.com/img/logo.gif" alt="" border="0" width="102" height="88" />
<p>
FontLab objects? RoboFab objects? Are there different flavors of objects? doesn't that confuse things? FontLab has its own object model. There are FontLab Font objects and FontLab Glyph objects. But these objects are relatively low-level, that means that while using these objects, you have to keep track of a lot of things yourself and understand some FontLab peculiarities. This makes it difficult to write code efficiently. RoboFab is a layer of objects built on top of the FontLab objects, making it a lot easier to work with the data, fewer things to memorise and that means faster development. FontLab now comes bundled with RoboFab. In this conference we focus mainly on the RoboFab objects, but for some things the FontLab objects are needed.
</p>
<p>
Back to Python. Objects, attributes and methods follow the <strong>dot separated syntax</strong> which is a handy way to clearly state what method or attribute you want to talk to. Other programming languages use dot syntax as well, for instance javascript or php.
</p>
<div class="pythonsource"><pre># attribute<br><span class="py_key">someObject</span>.<span class="py_key">someAttribute</span><br><span class="py_key">someObject</span>.<span class="py_key">anotherAttribute</span><br><span class="py_key">font</span>.<span class="py_key">path</span><br><span class="py_key">glyph</span>.<span class="py_key">width</span><br> <br># method<br><span class="py_key">someObject</span>.<span class="py_key">someMethod</span>(<span class="py_key">aParameter</span>)<br><span class="py_key">someObject</span>.<span class="py_key">anotherMethod</span>()<br><span class="py_key">font</span>.<span class="py_key">generate</span>()<br><span class="py_key">glyph</span>.<span class="py_key">clear</span>()</pre></div>
<p>
See how the dot connects the names? But this can go deeper than one level as well. Sometimes objects contain other objects, which in turn can have.. etc. Dont' worry about getting lost, this is why there is documentation.
</p>
<div class="pythonsource"><pre># attribute<br><span class="py_key">someObject</span>.<span class="py_key">someOtherObject</span>.<span class="py_key">theOtherObjectsAttribute</span><br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span><br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span><br> <br># method<br><span class="py_key">someObject</span>.<span class="py_key">someOtherObject</span>.<span class="py_key">theOtherObjectsMethod</span>(<span class="py_key">aParameter</span>)<br><span class="py_key">font</span>.<span class="py_key">kerning</span>.<span class="py_key">update</span>()<br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">autoNaming</span>()</pre></div>
<p>
Did you notice some lines has parentheses after them, and others don't? Writing <strong>( )</strong> means you want to use the method and execute it. In Python terms: the <strong>method</strong> is <strong>called</strong>.
</p>
<div class="pythonsource"><pre># a method but not called, you're looking at<br># the python object which contains the method.<br><span class="py_key">font</span>.<span class="py_key">update</span><br> <br># but calling a method is more useful,<br># it means: take this code and run it.<br><span class="py_key">font</span>.<span class="py_key">update</span>()</pre></div>
<h2>Names of variables and methods</h2>
<p>
In Robofab we have a couple of conventions for naming classes, attributes, methods and functions. These make it easier to predict what something is called and that means fewer trips to the documentation. This is what we're talking about:
<ul>
<li><strong>camelCase</strong>: this means that when a name is made up from several words, each<strong>A</strong>dditional<strong>W</strong>ord<strong>S</strong>tarts<strong>W</strong>ith<strong>AC</strong>ap. Examples: glyphName, kernTable, groupList, fontTools.
</li>
<li><strong>class names</strong> always start with an uppercase, then camelCase. Examples: RFont(), RGlyph, RKerning().
</li>
<li><strong>attribute and method names</strong> always start with a lowercase, then camelCase. Examples: kerning.importAFM(), glyph.drawPoints()
</li>
</ul>
</p>
<p>Note: these are our conventions, we do it this way because we prefer it. But that does not mean that Python requires it, as long as your names are legal Python you can write whatever you want. It's just useful to stick to a predictable method one way or the other. Please look at the standard <a href="http://www.python.org/doc/" class="reference" target="docs">Python documentation</a> for a full description of the language. Some rules about legal Python names:
<ul>
<li>Names can be arbitrarily long.</li>
<li>Names can contain letters and numbers.</li>
<li>The first character has to be a letter.</li>
<li>Names can contain upper and lower case letters.</li>
<li>Upper and lower case letters are different.</li>
<li>bruce and Bruce are different variable names</li>
<li>The underscore character,_, is legal. my_name</li>
</ul>
</p>
<h2>Installing RoboFab</h2>
<p>
Installing RoboFab is usually straightforward. There are quite a few combinations of operating system, FontLab version and Python version possible, some with their own pecularities. There's not much we can do about that, you just have to get it sorted.
<ul>
<li>Some notes on installing RoboFab for FontLab Studio 5, on <a href="http://just.letterror.com/ltrwiki/RoboFab_2fFontLabStudio5" class="reference" target="docs">the LettError wiki.</a>
</li>
<li>
More <a href="http://letterror.com/code/robofab/install.html" class="reference" target="docs">installation notes</a> in the RoboFab documentation
</li>
</ul>
</p>
<h2>Documentation</h2>
<p>
There is a lot of documentation available on the internet. When writing code, <a href="http://www.google.com/search?rls=en&amp;q=python+robofab&amp;ie=UTF-8&amp;oe=UTF-8" target="docs">google</a> is your best friend - there is almost always someone else who has dealt with or written about the same problem. Reading the documentation is always a good idea. Looking at code snippets is useful too because it will explain how other people have solved problems. Even if a particular bit of code doesn't do what you're looking for, it can give you ideas.
<ul>
<li><strong>RoboFab objects</strong>: <a href="http://letterror.com/code/robofab/objects/index.html" class="reference" target="docs">the RoboFab API and reference.</a></li>
<li><strong>FontLab objects</strong>: <a href="http://dev.fontlab.net/flpydoc/" class="reference" target="docs">the FontLab documentation</a>. API and reference for the FontLab objects.</li>
<li>
<strong>RoboFab introduction to Scripting</strong>: <a href="http://letterror.com/code/robofab/howto/scripting.html" class="reference" target="docs">RoboFab scripting intro</a>
</li>
<li><strong>How to think like a computer scientist</strong>: an introduction into <a href="http://www.ibiblio.org/obp/thinkCSpy/" class="reference" target="docs">learning Python</a>. Not specifically about typedesign, but general Python programming, lists, dicts, variables, stuff like that.
</li>
<li><strong>Emergency Python Basics</strong>: elsewhere on this site <a href="basic.html" class="reference" target="docs"> an short overview of some of Python's basic stuff.</a>
</li>
</ul>
</p>
<h1>
Font & Info objects
</h1>
<img src="http://letterror.com/code/robofab/img/offdrawmodel_07.gif" width="140" height="96" />
<h2>
Code!
</h2>
<p>
So now then, you should have your editor fired up. Your RoboFab installed. Locate the
<strong>
output
</strong>
window as well.
</p>
<div class="pythonsource"><pre><span class="py_res">import</span> <span class="py_key">robofab</span>.<span class="py_key">world</span></pre></div>
<p>
If that runs without problems you're good to go. If a new window pops up with a <strong>traceback</strong> like this it means there's something wrong with the installation.
</p>
<div class="pythonoutput"><pre><span class="py_key">Traceback</span> (<span class="py_key">most</span> <span class="py_key">recent</span> <span class="py_key">call</span> <span class="py_key">last</span>):<br><span class="py_key">File</span> <span class="py_str">"&lt;string&gt;"</span>, <span class="py_key">line</span> <span class="py_num">1</span>, <span class="py_res">in</span><span class="py_com"> </span><span class="py_com">?</span><br><span class="py_key">ImportError</span>: <span class="py_key">No</span> <span class="py_key">module</span> <span class="py_key">named</span> <span class="py_key">robofab</span>.<span class="py_key">world</span></pre></div>
<p>
In this documentation, stuff in the output window is indicated with a tinted background. Whenever something is printed in Python code it will end up in the output window.
</p>
<h2>
Huh, import ?
</h2>
<p>
Python can do a lot of different things. Some of its functionality is always available (the
<strong>
built-in
</strong>
things) but most of it is stored in seperate
<strong>
modules</strong>. When you want to use code from a different module, you need to
<strong>
import
</strong>
it first so that Python knows it needs to look somewhere else for objects, functions and stuff. Most of the Robofab stuff is stored in the
<strong>
robofab.world
</strong>
module. Notice that dot there? The dot syntax also works for modules and modules within modules. If you want to import a module and Python can't find it, you will get a traceback with an <strong>ImportError</strong>. You can also import specific things from another module, then you write:
</p>
<div class="pythonsource"><pre><span class="py_res">from</span> <span class="py_key">someModule</span> <span class="py_res">import</span> <span class="py_key">oneSpecificThing</span><br><span class="py_res">from</span> <span class="py_key">someModule</span>.<span class="py_key">subModule</span> <span class="py_res">import</span> <span class="py_key">oneSpecificThing</span><br><span class="py_res">from</span> <span class="py_key">someModule</span> <span class="py_res">import</span> <span class="py_key">anotherSpecificThing</span>, <span class="py_key">andAnotherThing</span><br> <br># and these:<br><span class="py_res">import</span> <span class="py_key">someModule</span><br><span class="py_res">import</span> <span class="py_key">someModule</span>.<span class="py_key">subModule</span></pre></div>
<h2>CurrentFont()</h2>
<p>
So, suppose you have FontLab, and a font file open. Make sure it is a font you can trash if you have to, and not the single copy of the production master of your newest bestseller. How do you get started talking to that font in Python? Use <strong>CurrentFont()</strong>. This is a special function which will return an object for the font which is at the front. When there are no fonts it will return <strong>None</strong>.
</p>
<div class="pythonsource"><pre><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_res">print</span> <span class="py_key">CurrentFont</span>()</pre></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RFont</span> <span class="py_key">font</span> <span class="py_res">for</span> <span class="py_key">DemoFont</span> <span class="py_key">Italic</span>&gt;</pre></div>
<p>
A <a href="http://letterror.com/code/robofab/objects/font.html" target="new" class="reference">Font</a> object! We'll be using CurrentFont and that font object shortly, but first let's have a look at CurrentFont's siblings: <strong>CurrentGlyph</strong> and <strong>AllFonts</strong>.
</p>
<div class="pythonsource"><pre># open a glyph in FL first!<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentGlyph</span><br><span class="py_res">print</span> <span class="py_key">CurrentGlyph</span>()</pre></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">DemoFont</span>.<span class="py_key">ograve</span>&gt;</pre></div>
<p>
<strong>CurrentGlyph()</strong> returns a <a href="http://letterror.com/code/robofab/objects/glyph.html" target="new" class="reference">Glyph</a> object for the glyph which is at the front. So this is a useful place to start if you want to write a script which manipulates a single glyph and you want an object for that glyph.
</p>
<div class="pythonsource"><pre># open a couple of fonts in FL first!<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">AllFonts</span><br><span class="py_res">print</span> <span class="py_key">AllFonts</span>()</pre></div>
<div class="pythonoutput"><pre>[&lt;<span class="py_key">RFont</span> <span class="py_key">font</span> <span class="py_res">for</span> <span class="py_key">MyDemoFont</span>&gt;,<br>&lt;<span class="py_key">RFont</span> <span class="py_key">font</span> <span class="py_res">for</span> <span class="py_key">AnotherFont</span> <span class="py_key">Plain</span>&gt;,<br>&lt;<span class="py_key">RFont</span> <span class="py_key">font</span> <span class="py_res">for</span> <span class="py_key">AnotherFont</span> <span class="py_key">Italic</span>&gt;]</pre></div>
<p>
<strong>AllFonts()</strong> returns a list with Font objects, one object for each open font. CurrentFont, CurrentGlyph and AllFonts are three very useful functions, and they all live in the robofab.world module. We'll be using them a lot.
</p>
<h2>Some Font attributes</h2>
<p>
So what are attributes of fonts objects? Let's have a look (at the documentation!).
</p>
<div class="pythonsource"><pre># open a couple of fonts in FL first!<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">path</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">kerning</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span></pre></div>
<div class="pythonoutput"><pre>/<span class="py_key">aFolder</span>/<span class="py_key">anotherFolder</span>/<span class="py_key">demoStuff</span>/<span class="py_key">myFont</span>.<span class="py_key">vfb</span><br>&lt;<span class="py_key">RKerning</span> <span class="py_res">for</span> <span class="py_key">MyFont</span> <span class="py_key">Plain</span>&gt;<br>&lt;<span class="py_key">RInfo</span> <span class="py_res">for</span> <span class="py_key">MyFont</span> <span class="py_key">Plain</span>&gt;</pre></div>
<p>
Hang on! that didn't print anything that looks like kerning, and what's that font.info thing? Remember that objects can contain objects? The object model splits all font related data into smaller, easier to manage pieces. So a <strong>Font</strong> object has one single <strong>Info</strong> object which in turn stores all of the naming and dimensions. Same for font.kerning, it's an object which represents all kerning data of the font. We'll get back to the <a href="http://letterror.com/code/robofab/objects/kerning.html" target="new" class="reference">kerning object</a> later.
</p>
<h2>Some Info attributes</h2>
<p>
The <strong>Info</strong> object stores all of the <a href="http://letterror.com/code/robofab/objects/info.html" target="new" class="reference">font's names, key dimensions</a> etc.
</p>
<div class="pythonsource"><pre># robothon06<br># getting data from the info object<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br># naming attributes<br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span><br># dimension attributes<br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">unitsPerEm</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">ascender</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">descender</span><br></pre></div><div class="pythonsourcetitle"><a href="examples/someFontInfoAttributes.py" target="new">download examples/someFontInfoAttributes.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">MyDemo</span><br><span class="py_key">Plain</span><br><span class="py_key">MyDemo</span> <span class="py_key">Plain</span><br><span class="py_num">1000</span><br><span class="py_num">720</span><br>-<span class="py_num">280</span></pre></div>
<p>
Almost all attributes can also be set to new values. This is when it starts getting interesting. But it also opens new ways of messing your font up.
</p>
<div class="pythonsource"><pre># robothon06<br># setting data in the info object<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br># naming attributes<br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span> = <span class="py_str">"MyFamily"</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span><br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span> = <span class="py_str">"Roman"</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span><br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span> = <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span> + <span class="py_str">'-'</span> + <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span><br># dimension attributes<br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">ascender</span> = <span class="py_num">600</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">ascender</span><br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">descender</span> = -<span class="py_num">400</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">descender</span><br><span class="py_key">font</span>.<span class="py_key">update</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/someFontInfoAttributes2.py" target="new">download examples/someFontInfoAttributes2.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">MyFamily</span><br><span class="py_key">Roman</span><br><span class="py_key">MyFamily</span>-<span class="py_key">Roman</span><br><span class="py_num">600</span><br>-<span class="py_num">400</span></pre></div>
<p>
A useful method of the Info object is <strong>autoNaming()</strong>. It assumes you have entered correct data for <strong>familyName</strong> and <strong>styleName</strong>. Based on these 2 values, a bunch of variations and permutations are generated and stored in the appropriate fields. These are the basic names, no fancy OpenType stuff.
</p>
<div class="pythonsource"><pre># robothon06<br># get a particular glyph<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br> <br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span> = <span class="py_str">"myFamilyName"</span><br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span> = <span class="py_str">"myStyleName"</span><br> <br><span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">autoNaming</span>()<br> <br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fontName</span><br><span class="py_res">print</span> <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fondName</span></pre></div><div class="pythonsourcetitle"><a href="examples/infoAutonaming.py" target="new">download examples/infoAutonaming.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">myFamilyName</span> <span class="py_key">myStyleName</span><br><span class="py_key">myFamilyName</span>-<span class="py_key">myStyleName</span><br><span class="py_key">myFamilyName</span></pre></div>
<h2>Getting to glyphs</h2>
<p>
We've seen <strong>CurrentGlyph</strong> and <strong>CurrentFont</strong>, but how do you we get to other glyphs in a font? A <strong>Font</strong> object contains glyphs and this is what you do to get to them:
</p>
<div class="pythonsource"><pre># robothon06<br># get a particular glyph<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_res">print</span> <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_res">print</span> <span class="py_key">font</span>[<span class="py_str">'Adieresis'</span>]<br><span class="py_res">print</span> <span class="py_key">font</span>[<span class="py_str">'two'</span>]<br><span class="py_res">print</span> <span class="py_key">font</span>[<span class="py_str">'afii12934'</span>]<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/getSomeGlyphs.py" target="new">download examples/getSomeGlyphs.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">A</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Adieresis</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">two</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">afii12934</span>&gt;</pre></div>
<p>
The Font object in this case behaves like a Python dictionary object. Between the <strong>[</strong> square brackets <strong>]</strong> you can ask for a glyph by its (postscript) name. In Python speak:
</p>
<div class="pythonsource"><pre><span class="py_key">value</span> = <span class="py_key">dictionary</span>[<span class="py_key">key</span>]</pre></div>
<p>
If you want to look at all glyphs in a font, one at a time, you can <strong>loop</strong> or <strong>iterate</strong> through the font. It's written like this:
</p>
<div class="pythonsource"><pre># robothon06<br># iteration through glyphs in a font<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_res">print</span> <span class="py_str">"font has %d glyphs"</span> % <span class="py_key">len</span>(<span class="py_key">font</span>)<br><span class="py_res">for</span> <span class="py_key">glyph</span> <span class="py_res">in</span> <span class="py_key">font</span>:<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">glyph</span><br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/iterateFont.py" target="new">download examples/iterateFont.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">font</span> <span class="py_key">has</span> <span class="py_num">201</span> <span class="py_key">glyphs</span><br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">aring</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">ordfeminine</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">less</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">ograve</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">V</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">dollar</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">circumflex</span>&gt;<br>..<span class="py_key">etc</span>..</pre></div>
<p>
A couple of things to look for in the example above:
<ul>
<li><strong>len(font)</strong> shows Python's built-in <strong>len()</strong> function, which will try to count the thing its given and it will return the number. Fonts like to be counted and they respond with the number of glyphs. In this case the font has 201 glyphs.</li>
<li>
All the glyphs are mixed up! there is no particular order! chaos! In Python dictionaries there is no standard order in which the keys appear. It will iterate through all the glyphs though.
</li>
<li>Notice the indentation at the beginning of the line under <strong>for glyph in font:</strong> This is Python's way of showing that all of the code that's indented belongs to the same loop. When the code is <strong>dedented</strong> again that's where Python will continue when it is done with the loop.
</li>
</ul>
</p>
<p>
When you want to be sure about the order in which the glyphs are looked at, you need to sort them first. Example:
</p>
<div class="pythonsource"><pre># iteration through alphabetically sorted glyphnames<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_res">print</span> <span class="py_str">"font has %d glyphs"</span> % <span class="py_key">len</span>(<span class="py_key">font</span>)<br> <br># names is now a list of strings, the names of the glyphs<br># not the glyphs themselves!<br><span class="py_key">names</span> = <span class="py_key">font</span>.<span class="py_key">keys</span>()<br> <br># the list of names is sorted<br><span class="py_key">names</span>.<span class="py_key">sort</span>()<br> <br># now we iterate through the list of names<br><span class="py_res">for</span> <span class="py_key">glyphName</span> <span class="py_res">in</span> <span class="py_key">names</span>:<br>&nbsp; &nbsp; # now we ask for the glyph with glyphName<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">font</span>[<span class="py_key">glyphName</span>]</pre></div>
<div class="pythonoutput"><pre><span class="py_key">font</span> <span class="py_key">has</span> <span class="py_num">201</span> <span class="py_key">glyphs</span><br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">A</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">AE</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Aacute</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Acircumflex</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Adieresis</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Agrave</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Aring</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">Atilde</span>&gt;<br>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">MyFamily</span>-<span class="py_key">Roman</span>.<span class="py_key">B</span>&gt;<br>..<span class="py_key">etc</span>..</pre></div>
<h1>
Glyph, Contour & Pen
</h1>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_17.gif" width="140" height="96" />
<p>
Working with <a href="http://letterror.com/code/robofab/objects/glyph.html" target="new" class="reference">Glyph</a>, <a href="http://letterror.com/code/robofab/objects/contour.html" target="new" class="reference">Contour</a>, <a href="http://letterror.com/code/robofab/howto/usepens.html" target="new" class="reference">Pen</a> objects. Deep in the font live the glyphs. Inside the glyphs are contours, components. Inside a contour are segments and points!
</p>
<p>Previous: <a href="robofab_session1.html">fonts</a>, next: <a href="robofab_session3.html">kerning and metrics, building glyphs</a>
</p>
<h2>Some Glyph attributes</h2>
<p>
In the previous talk we saw ways of getting fonts and glyph objects. Now we're going to see what Glyph objects can do for us. Glyphs are perhaps the most interesting object in the whole API. Some basic attributes of a glyph object:
</p>
<div class="pythonsource"><pre># robothon06<br># set basic attributes in a glyph<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_key">glyph</span>.<span class="py_key">width</span> = <span class="py_num">200</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">width</span><br><span class="py_key">glyph</span>.<span class="py_key">leftMargin</span> = <span class="py_num">50</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">leftMargin</span><br><span class="py_key">glyph</span>.<span class="py_key">rightMargin</span> = <span class="py_num">50</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">rightMargin</span><br> <br><span class="py_key">glyph</span>.<span class="py_key">unicode</span> = <span class="py_num">666</span><br><span class="py_key">glyph</span>.<span class="py_key">update</span>()</pre></div><div class="pythonsourcetitle"><a href="examples/someGlyphAttributes.py" target="new">download examples/someGlyphAttributes.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">A</span><br><span class="py_num">812</span><br><span class="py_num">0</span><br><span class="py_num">0</span><br>(<span class="py_num">0</span>, <span class="py_num">0</span>, <span class="py_num">812</span>, <span class="py_num">600</span>)<br><span class="py_num">65</span></pre></div>
<p>Some of these attributes can also be set, you can put new values in them. Why not all of them? For instance, the bounding box of a glyph is an attribute, it is useful information. But it depends entirely on the size of the contours in the glyph. There's no way in which you could set this attribute other than by changing the actual paths. Useful attributes you <strong>can</strong> set are things like the width, left and right margin:
</p>
<div class="pythonsource"><pre># robothon06<br># set basic attributes in a glyph<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_key">glyph</span>.<span class="py_key">width</span> = <span class="py_num">200</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">width</span><br><span class="py_key">glyph</span>.<span class="py_key">leftMargin</span> = <span class="py_num">50</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">leftMargin</span><br><span class="py_key">glyph</span>.<span class="py_key">rightMargin</span> = <span class="py_num">50</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">rightMargin</span><br> <br><span class="py_key">glyph</span>.<span class="py_key">unicode</span> = <span class="py_num">666</span><br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">unicode</span><br> <br><span class="py_key">glyph</span>.<span class="py_key">update</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/someGlyphAttributes2.py" target="new">download examples/someGlyphAttributes2.py</a></div>
<div class="pythonoutput"><pre><span class="py_num">200</span><br><span class="py_num">50</span><br><span class="py_num">50</span><br><span class="py_num">666</span></pre></div>
<p>
Notice the <strong>glyph.update()</strong> statement at the end. After setting the attributes to new values, the glyph data will be changed. But the FontLab interface will not have noticed your changes. For instance, the little preview in the font window might still show the old version. The <strong>update()</strong> method of the glyph object is a wakeup call for the application to refresh all glyph drawings with the new data. Note that it is just the <strong>representation</strong> that's being updated. The data itself was changed when the script was executed. Saving the file and opening it again will have the same effect in this respect.
</p>
<p>
Have a look at the RoboFab documentation on the <a href="http://letterror.com/code/robofab/objects/glyph.html" target="new" class="reference">Glyph</a> object for more attributes and methods.
</p>
<h2>Some Glyph methods</h2>
<p>
</p>
<div class="pythonsource"><pre># robothon06<br># use some methods to transform a glyph<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br> <br># ask a font for a glyph by name<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br> <br># now you have a glyph object<br># make it do stuff by calling some of its methods<br><span class="py_key">glyph</span>.<span class="py_key">move</span>((<span class="py_num">100</span>, <span class="py_num">75</span>))<br><span class="py_key">glyph</span>.<span class="py_key">scale</span>((<span class="py_num">.5</span>, <span class="py_num">1.5</span>))<br><span class="py_key">glyph</span>.<span class="py_key">appendGlyph</span>(<span class="py_key">font</span>[<span class="py_str">'B'</span>])<br><span class="py_key">glyph</span>.<span class="py_key">removeOverlap</span>()<br><span class="py_key">glyph</span>.<span class="py_key">correctDirection</span>()<br><span class="py_key">glyph</span>.<span class="py_key">update</span>()<br> <br><br></pre></div><div class="pythonsourcetitle"><a href="examples/transformGlyph.py" target="new">download examples/transformGlyph.py</a></div>
<p>
Note: these will really screw up your glyph if you don't want it to be moved 100 units horizontally and 75 units vertically, then scaled 50% horizontally and 150% vertically. Then the glyph <strong>B</strong> is added, the overlap is removed, the path directions are corrected and finally the app is told something was changed.
</p>
<h2>getParent()</h2>
<p>
The Glyph object has a <strong>glyph.getParent()</strong> method. When called it will return the <strong>Font</strong> object the glyph belongs to. If it has one: "orphan" glyphs are objects which don't belong to any particular font like the result of a <strong>GlyphMath</strong> operation or glyph level interpolation. When there is no parent, <strong>getParent()</strong> returns <strong>None</strong>. You need to test for this result.
</p>
<div class="pythonsource"><pre># robothon06<br># iterate through a glyph's contours<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br> <br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">"A"</span>]<br><span class="py_res">print</span> <span class="py_key">glyph</span>.<span class="py_key">getParent</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/aGlyphParent.py" target="new">download examples/aGlyphParent.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RFont</span> <span class="py_key">font</span> <span class="py_res">for</span> <span class="py_key">SomeFont</span>&gt;</pre></div>
<h2>The stuff glyphs are made of</h2>
<p>
A glyph consists of contours, which in turn consist of points, right? If only it were that easy. There are all sorts of points conspiring to become all sorts of shapes. Bezier curves, Quadratic curves, open, closed, components. Sometimes it is just the point of view that's different. The <a href="http://letterror.com/code/robofab/howto/understandcontours.html" target="docs" class="reference">Understanding Contours and Segments</a> section of the RoboFab documentation has a couple of diagrams of the different ways of looking at the vectors in a glyph. Let's have a look at <a href="http://letterror.com/code/robofab/objects/contour.html" target="new" class="reference">Contour</a> objects first.
</p>
<div class="pythonsource"><pre># robothon06<br># iterate through a glyph's contours<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_res">print</span> <span class="py_str">"glyph has %d contours"</span> % <span class="py_key">len</span>(<span class="py_key">glyph</span>)<br><span class="py_res">for</span> <span class="py_key">contour</span> <span class="py_res">in</span> <span class="py_key">glyph</span>.<span class="py_key">contours</span>:<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">contour</span><br>&nbsp; &nbsp; <br></pre></div><div class="pythonsourcetitle"><a href="examples/iterateGlyph.py" target="new">download examples/iterateGlyph.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">glyph</span> <span class="py_key">has</span> <span class="py_num">2</span> <span class="py_key">contours</span><br>&lt;<span class="py_key">RContour</span> <span class="py_res">for</span> <span class="py_key">MyDemo</span> <span class="py_key">Italic</span>.<span class="py_key">A</span>[<span class="py_num">0</span>]&gt;<br>&lt;<span class="py_key">RContour</span> <span class="py_res">for</span> <span class="py_key">MyDemo</span> <span class="py_key">Italic</span>.<span class="py_key">A</span>[<span class="py_num">1</span>]&gt;</pre></div>
<p>So a <strong>Glyph</strong> object contains zero, one or more <strong>Contour</strong> objects. Let's see what secrets a Contour has:
</p>
<div class="pythonsource"><pre># robothon06<br># get a specific contour and view it<br>#through point, segment and bPoint structures<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_key">contour</span> = <span class="py_key">glyph</span>[<span class="py_num">0</span>]<br><span class="py_res">print</span> <span class="py_key">contour</span>.<span class="py_key">points</span><br><span class="py_res">print</span> <span class="py_key">countours</span>.<span class="py_key">segments</span><br><span class="py_res">print</span> <span class="py_key">contour</span>.<span class="py_key">bPoints</span><br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/iterateContour.py" target="new">download examples/iterateContour.py</a></div>
<div class="pythonoutput"><pre>[&lt;<span class="py_key">RPoint</span> <span class="py_res">for</span> <span class="py_key">Plinc01</span> <span class="py_key">Plinc01</span>.<span class="py_key">A</span>[<span class="py_num">0</span>][<span class="py_num">0</span>]&gt;,<br>&lt;<span class="py_key">RPoint</span> <span class="py_res">for</span> <span class="py_key">Plinc01</span> <span class="py_key">Plinc01</span>.<span class="py_key">A</span>[<span class="py_num">0</span>][<span class="py_num">1</span>]&gt;,<br>...<br>&lt;<span class="py_key">RPoint</span> <span class="py_res">for</span> <span class="py_key">Plinc01</span> <span class="py_key">Plinc01</span>.<span class="py_key">A</span>[<span class="py_num">0</span>][<span class="py_num">4</span>]&gt;]<br> <br>[&lt;<span class="py_key">RSegment</span> <span class="py_res">for</span> <span class="py_key">Plinc01</span> <span class="py_key">Plinc01</span>.<span class="py_key">A</span>[<span class="py_num">0</span>][<span class="py_num">0</span>]&gt;,<br>&lt;<span class="py_key">RSegment</span> <span class="py_res">for</span> <span class="py_key">Plinc01</span> <span class="py_key">Plinc01</span>.<span class="py_key">A</span>[<span class="py_num">0</span>][<span class="py_num">1</span>]&gt;,<br>...<br>&lt;<span class="py_key">RSegment</span> <span class="py_res">for</span> <span class="py_key">Plinc01</span> <span class="py_key">Plinc01</span>.<span class="py_key">A</span>[<span class="py_num">0</span>][<span class="py_num">4</span>]&gt;]<br> <br>[&lt;<span class="py_key">RBPoint</span> <span class="py_res">for</span> <span class="py_key">unnamed_font</span>.<span class="py_key">unnamed_glyph</span>[<span class="py_num">7</span>][<span class="py_num">0</span>][<span class="py_num">0</span>]&gt;,<br>&lt;<span class="py_key">RBPoint</span> <span class="py_res">for</span> <span class="py_key">unnamed_font</span>.<span class="py_key">unnamed_glyph</span>[<span class="py_num">7</span>][<span class="py_num">0</span>][<span class="py_num">1</span>]&gt;,<br>...<br>&lt;<span class="py_key">RBPoint</span> <span class="py_res">for</span> <span class="py_key">unnamed_font</span>.<span class="py_key">unnamed_glyph</span>[<span class="py_num">7</span>][<span class="py_num">0</span>][<span class="py_num">4</span>]&gt;]</pre></div>
<p>
Let's have a look at these different attributes. In the end, they're all describing the same shape, the same actual points. It's just sorted in different ways for different purposes.
<ul>
<li>
<strong>contour.points:</strong> This is a list of all points on a contour. off-curve and on-curve points are presented as <strong>RPoint</strong>objects. Each RPoint has x, y, type and smooth attributes. On-cuve and off-curve points are treated as equals.
</li>
<li>
<strong>contour.segments:</strong> A segment is an object which represents a series of off-curve points and finally one on-curve point. Though kind of abstract, segments are needed to deal with quadratic curves which can have several off-curves on a row.
</li>
<li>
<strong>contour.bPoints:</strong> bPoints are objects which look more or less like the curve points you know from editing Beziers. One main on-curve point and two satellite off-curve points or <strong>bcps</strong>: an incoming one and an outgoing one. This is more or less the kind of point that was used in <strong>RoboFog</strong> code.
</li>
</ul>
</p>
<p>
Again, please refer to the <a href="http://letterror.com/code/robofab/howto/understandcontours.html" target="docs" class="reference">Understanding Contours and Segments</a> to make sense of these things visually.
</p>
<p>
Finally, when you iterate through the contour.points, you get to see <a href="http://letterror.com/code/robofab/objects/point.html" target="new" class="reference">RPoint</a> objects with familiar things like x, y, and type attributes.
</p>
<div class="pythonsource"><pre># robothon06<br># iterate through points<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_res">for</span> <span class="py_key">p</span> <span class="py_res">in</span> <span class="py_key">glyph</span>[<span class="py_num">0</span>].<span class="py_key">points</span>:<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">p</span>.<span class="py_key">x</span>, <span class="py_key">p</span>.<span class="py_key">y</span>, <span class="py_key">p</span>.<span class="py_key">type</span><br></pre></div><div class="pythonsourcetitle"><a href="examples/iteratePoints.py" target="new">download examples/iteratePoints.py</a></div>
<div class="pythonoutput"><pre><span class="py_num">37</span> <span class="py_num">509</span> <span class="py_key">move</span><br><span class="py_num">37</span> <span class="py_num">407</span> <span class="py_key">offcurve</span><br><span class="py_num">119</span> <span class="py_num">325</span> <span class="py_key">offcurve</span><br><span class="py_num">221</span> <span class="py_num">325</span> <span class="py_key">curve</span><br><span class="py_num">323</span> <span class="py_num">325</span> <span class="py_key">offcurve</span><br><span class="py_num">405</span> <span class="py_num">407</span> <span class="py_key">offcurve</span><br><span class="py_num">405</span> <span class="py_num">509</span> <span class="py_key">curve</span><br><span class="py_num">405</span> <span class="py_num">611</span> <span class="py_key">offcurve</span><br><span class="py_num">323</span> <span class="py_num">693</span> <span class="py_key">offcurve</span><br><span class="py_num">221</span> <span class="py_num">693</span> <span class="py_key">curve</span><br><span class="py_num">119</span> <span class="py_num">693</span> <span class="py_key">offcurve</span><br><span class="py_num">37</span> <span class="py_num">611</span> <span class="py_key">offcurve</span><br><span class="py_num">37</span> <span class="py_num">509</span> <span class="py_key">curve</span></pre></div>
<p>
That looks interesting! Finally we're dealing with the stuff that letters are made of. You can now find the coordinates of every single point in the font, and change them if you want. But it looks very cumbersome to actually add shapes like this, all these contour objects, point objects. That's going to hurt, no? Yes. So, if you want to draw new forms there is a solution.
</p>
<h2>The Pen and Draw model</h2>
<p>
The pen/draw model is a very powerful concept, but it might seem a bit abstract to begin with. If you're interested in building filters, shape manipulating scripts, or programmatically draw glyphs, this is good to study. Otherwise, if you're here for the first time, just remember that there are ways to get paths into glyphs and that this is where you saw the examples for later reference.
</p>
<p>
Glyph objects have a
<strong>
draw()
</strong>
method which takes a
<strong>
Pen
</strong>
object as a parameter. All glyphs know how to draw and all pen objects have the same methods (see below). When draw() is called, the glyph instructs the pen to recreate the shapes using <strong>moveTo()</strong>, <strong>lineTo()</strong>, <strong>curveTo()</strong> commands. The pen/draw() model is a standardised way of getting to the point data in a glyph. It is also a standardised way of getting data into a glyph. The glyph doesn't have to know what the pen is doing with its information and the pen doesn't have to know where the glyph gets its data from. That's how we like things in the object oriented world.
</p>
<p>
There is a wide range of pen objects available for different things. Some pens just print the coordinates of a glyph. Some pens draw contours in a glyph, some manipulate the data, others can draw on screen under certain conditions.
</p>
<p>
How to get a pen object? A bunch of them are stored in the <strong>robofab/pens</strong> module, have a look in the source! But one of the first things you'll want to use a pen for is to construct paths in a glyph. A Glyph object has a <strong>glyph.getPen()</strong> method which will return the right Pen object for drawing in that glyph. Example:
</p>
<div class="pythonsource"><pre># robothon06<br># get a pen and draw something in the current glyph<br># what will it draw? ha! run the script and find out!<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentGlyph</span><br><span class="py_key">g</span> = <span class="py_key">CurrentGlyph</span>()<br><span class="py_key">myPen</span> = <span class="py_key">g</span>.<span class="py_key">getPen</span>()<br> <br># myPen is a pen object of a type meant for<br># constructing paths in a glyph.<br># So rather than use this pen with the glyph's<br># own draw() method, we're going to tell it <br># to do things ourselves. (Just like DrawBot!)<br><span class="py_res">print</span> <span class="py_key">myPen</span><br> <br><span class="py_key">myPen</span>.<span class="py_key">moveTo</span>((<span class="py_num">344</span>, <span class="py_num">645</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">647</span>, <span class="py_num">261</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">662</span>, -<span class="py_num">32</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">648</span>, -<span class="py_num">61</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">619</span>, -<span class="py_num">61</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">352</span>, <span class="py_num">54</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">72</span>, <span class="py_num">446</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">117</span>, <span class="py_num">590</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">228</span>, <span class="py_num">665</span>))<br><span class="py_key">myPen</span>.<span class="py_key">closePath</span>()<br><span class="py_key">myPen</span>.<span class="py_key">moveTo</span>((<span class="py_num">99</span>, <span class="py_num">451</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">365</span>, <span class="py_num">74</span>))<br><span class="py_key">myPen</span>.<span class="py_key">curveTo</span>((<span class="py_num">359</span>, <span class="py_num">122</span>), (<span class="py_num">376</span>, <span class="py_num">178</span>), (<span class="py_num">420</span>, <span class="py_num">206</span>))<br><span class="py_key">myPen</span>.<span class="py_key">curveTo</span>((<span class="py_num">422</span>, <span class="py_num">203</span>), (<span class="py_num">142</span>, <span class="py_num">579</span>), (<span class="py_num">142</span>, <span class="py_num">579</span>))<br><span class="py_key">myPen</span>.<span class="py_key">closePath</span>()<br><span class="py_key">myPen</span>.<span class="py_key">moveTo</span>((<span class="py_num">631</span>, -<span class="py_num">32</span>))<br><span class="py_key">myPen</span>.<span class="py_key">lineTo</span>((<span class="py_num">629</span>, <span class="py_num">103</span>))<br><span class="py_key">myPen</span>.<span class="py_key">curveTo</span>((<span class="py_num">556</span>, <span class="py_num">111</span>), (<span class="py_num">524</span>, <span class="py_num">71</span>), (<span class="py_num">508</span>, <span class="py_num">20</span>))<br><span class="py_key">myPen</span>.<span class="py_key">closePath</span>()<br> <br><span class="py_key">g</span>.<span class="py_key">update</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/drawStuffWithPen.py" target="new">download examples/drawStuffWithPen.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">adapterPens</span>.<span class="py_key">SegmentToPointPen</span> <span class="py_key">instance</span> <span class="py_key">at</span> <span class="py_num">0x65d2558</span>&gt;</pre></div>
<p>
The next example will show the use of a Pen object which doesn't construct any path, but rather it prints the instructions the glyph is calling to draw itself. Note: the stuff printed out by <strong>PrintingSegmentPen</strong> is python code too. You can use this snippet to convert a shape into python code, if for whatever reason you want to draw stuff programmatically. That's how the previous example was created: draw a shape in a glyph, print the draw instructions, write the rest of the code.
</p>
<div class="pythonsource"><pre># robothon06<br># get a pen and use it to print the coordinates<br># to the output window. This is actually almost-python<br># code which you can use it other scripts!<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">pointPen</span> <span class="py_res">import</span> <span class="py_key">PrintingSegmentPen</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br> <br># PrintingSegmentPen won't actually draw anything<br># just print the coordinates to the output:<br><span class="py_key">pen</span> = <span class="py_key">PrintingSegmentPen</span>()<br><span class="py_key">glyph</span>.<span class="py_key">draw</span>(<span class="py_key">pen</span>)<br></pre></div><div class="pythonsourcetitle"><a href="examples/printingPen.py" target="new">download examples/printingPen.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">pen</span>.<span class="py_key">moveTo</span>((<span class="py_num">37</span>, <span class="py_num">509</span>))<br><span class="py_key">pen</span>.<span class="py_key">curveTo</span>((<span class="py_num">37</span>, <span class="py_num">407</span>), (<span class="py_num">119</span>, <span class="py_num">325</span>), (<span class="py_num">221</span>, <span class="py_num">325</span>))<br><span class="py_key">pen</span>.<span class="py_key">curveTo</span>((<span class="py_num">323</span>, <span class="py_num">325</span>), (<span class="py_num">405</span>, <span class="py_num">407</span>), (<span class="py_num">405</span>, <span class="py_num">509</span>))<br><span class="py_key">pen</span>.<span class="py_key">curveTo</span>((<span class="py_num">405</span>, <span class="py_num">611</span>), (<span class="py_num">323</span>, <span class="py_num">693</span>), (<span class="py_num">221</span>, <span class="py_num">693</span>))<br><span class="py_key">pen</span>.<span class="py_key">curveTo</span>((<span class="py_num">119</span>, <span class="py_num">693</span>), (<span class="py_num">37</span>, <span class="py_num">611</span>), (<span class="py_num">37</span>, <span class="py_num">509</span>))<br><span class="py_key">pen</span>.<span class="py_key">closePath</span>()</pre></div>
<p>
The following example uses a Pen to draw boxes as a simple rasteriser. Perhaps a bit overboard, but it illustrates what you can do with Pens and creating paths in RoboFab.
</p>
<div class="pythonsource"><pre># robothon06<br># rasterise the shape in glyph "A"<br># and draw boxes in a new glyph named "A.silly"<br>#<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span>, <span class="py_key">CurrentGlyph</span><br> <br><span class="py_key">sourceGlyph</span> = <span class="py_str">"a"</span><br> <br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">source</span> = <span class="py_key">f</span>[<span class="py_key">sourceGlyph</span>]<br> <br># find out how big the shape is from the glyph.box attribute<br><span class="py_key">xMin</span>, <span class="py_key">yMin</span>, <span class="py_key">xMax</span>, <span class="py_key">yMax</span> = <span class="py_key">source</span>.<span class="py_key">box</span><br> <br># create a new glyph<br><span class="py_key">dest</span> = <span class="py_key">f</span>.<span class="py_key">newGlyph</span>(<span class="py_key">sourceGlyph</span>+<span class="py_str">".silly"</span>)<br><span class="py_key">dest</span>.<span class="py_key">width</span> = <span class="py_key">source</span>.<span class="py_key">width</span><br> <br># get a pen to draw in the new glyph<br><span class="py_key">myPen</span> = <span class="py_key">dest</span>.<span class="py_key">getPen</span>()<br> <br># a function which draws a rectangle at a specified place<br><span class="py_res">def</span> <span class="py_def">drawRect</span>(<span class="py_key">pen</span>, <span class="py_key">x</span>, <span class="py_key">y</span>, <span class="py_key">size</span>=<span class="py_num">50</span>):<br>&nbsp; &nbsp; <span class="py_key">pen</span>.<span class="py_key">moveTo</span>((<span class="py_key">x</span>-<span class="py_num">.5</span>*<span class="py_key">size</span>, <span class="py_key">y</span>-<span class="py_num">.5</span>*<span class="py_key">size</span>))<br>&nbsp; &nbsp; <span class="py_key">pen</span>.<span class="py_key">lineTo</span>((<span class="py_key">x</span>+<span class="py_num">.5</span>*<span class="py_key">size</span>, <span class="py_key">y</span>-<span class="py_num">.5</span>*<span class="py_key">size</span>))<br>&nbsp; &nbsp; <span class="py_key">pen</span>.<span class="py_key">lineTo</span>((<span class="py_key">x</span>+<span class="py_num">.5</span>*<span class="py_key">size</span>, <span class="py_key">y</span>+<span class="py_num">.5</span>*<span class="py_key">size</span>))<br>&nbsp; &nbsp; <span class="py_key">pen</span>.<span class="py_key">lineTo</span>((<span class="py_key">x</span>-<span class="py_num">.5</span>*<span class="py_key">size</span>, <span class="py_key">y</span>+<span class="py_num">.5</span>*<span class="py_key">size</span>))<br>&nbsp; &nbsp; <span class="py_key">pen</span>.<span class="py_key">closePath</span>()<br> <br># the size of the raster unit<br><span class="py_key">resolution</span> = <span class="py_num">30</span><br> <br># draw from top to bottom<br><span class="py_key">yValues</span> = <span class="py_key">range</span>(<span class="py_key">yMin</span>, <span class="py_key">yMax</span>, <span class="py_key">resolution</span>)<br><span class="py_key">yValues</span>.<span class="py_key">reverse</span>()<br> <br># go for it!<br><span class="py_res">for</span> <span class="py_key">y</span> <span class="py_res">in</span> <span class="py_key">yValues</span>:<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">x</span> <span class="py_res">in</span> <span class="py_key">range</span>(<span class="py_key">xMin</span>, <span class="py_key">xMax</span>, <span class="py_key">resolution</span>):<br>&nbsp; &nbsp; &nbsp; &nbsp; # check the source glyph is white or black at x,y<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">source</span>.<span class="py_key">pointInside</span>((<span class="py_key">x</span>, <span class="py_key">y</span>)):<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">drawRect</span>(<span class="py_key">myPen</span>, <span class="py_key">x</span>, <span class="py_key">y</span>, <span class="py_key">resolution</span>-<span class="py_num">5</span>)<br>&nbsp; &nbsp; # update for each line if you like the animation<br>&nbsp; &nbsp; # otherwise move the update() out of the loop<br>&nbsp; &nbsp; <span class="py_key">dest</span>.<span class="py_key">update</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/sillyRasteriser.py" target="new">download examples/sillyRasteriser.py</a></div>
<p>
<img src="rasteriser.gif" alt="rasteriser" width="400" height="193" />
<br />
This is what it looks like.
</p>
<p>
A more in-depth discussion of the Pen protocol at the <a href="http://just.letterror.com/ltrwiki/PenProtocol" class="reference" target="docs">LettError wiki</a>. More examples of using pens, and some samples using pens to filter letterforms in the <a href="http://letterror.com/code/robofab/howto/usepens.html" class="reference" target="new">RoboFab docs</a>.
</p>
<h2>Another kind of pen</h2>
<p>
Well, it wouldn't be Python if there weren't at least two ways of doing things. The pen/draw() model draws on-curve points and only accepts off-curves as part of the curveTo() and qCurveTo() methods, there's no room for additional information. For instance a <strong>smooth</strong> flag or a name for a point (and there are good reasons to want to do that). That's where <strong>glyph.drawPoints()</strong> comes in handy. This method is similar to <strong>glyph.draw()</strong> but it takes a different pen, a <strong>PointPen</strong>. All points are drawn one by one. PointPens are useful when you want to exactly address all information of each point in a shape. Compare the output of this example with the previous one. It's the same shape. Chances are you won't need pointPens for some time, but if you start working with pens it is good to know they exist.
</p>
<div class="pythonsource"><pre># use a point pen<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">pointPen</span> <span class="py_res">import</span> <span class="py_key">PrintingPointPen</span><br> <br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">font</span>[<span class="py_str">'A'</span>]<br><span class="py_key">pen</span> = <span class="py_key">PrintingPointPen</span>()<br><span class="py_key">glyph</span>.<span class="py_key">drawPoints</span>(<span class="py_key">pen</span>)</pre></div>
<div class="pythonoutput"><pre><span class="py_key">pen</span>.<span class="py_key">beginPath</span>()<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">37</span>, <span class="py_num">509</span>), <span class="py_key">segmentType</span>=<span class="py_str">'curve'</span>, <span class="py_key">smooth</span>=<span class="py_key">True</span>)<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">37</span>, <span class="py_num">407</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">119</span>, <span class="py_num">325</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">221</span>, <span class="py_num">325</span>), <span class="py_key">segmentType</span>=<span class="py_str">'curve'</span>, <span class="py_key">smooth</span>=<span class="py_key">True</span>, **{<span class="py_str">'selected'</span>: <span class="py_num">0</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">323</span>, <span class="py_num">325</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">405</span>, <span class="py_num">407</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">405</span>, <span class="py_num">509</span>), <span class="py_key">segmentType</span>=<span class="py_str">'curve'</span>, <span class="py_key">smooth</span>=<span class="py_key">True</span>, **{<span class="py_str">'selected'</span>: <span class="py_num">0</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">405</span>, <span class="py_num">611</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">323</span>, <span class="py_num">693</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">221</span>, <span class="py_num">693</span>), <span class="py_key">segmentType</span>=<span class="py_str">'curve'</span>, <span class="py_key">smooth</span>=<span class="py_key">True</span>, **{<span class="py_str">'selected'</span>: <span class="py_num">0</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">119</span>, <span class="py_num">693</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">addPoint</span>((<span class="py_num">37</span>, <span class="py_num">611</span>), **{<span class="py_str">'selected'</span>: <span class="py_key">False</span>})<br><span class="py_key">pen</span>.<span class="py_key">endPath</span>()</pre></div>
<p>
Notice that a pointPen only has 3 methods: <strong>addPoint</strong>, <strong>beginPath</strong> and <strong>endPath</strong>.
</p>
<h2>Path manipulation</h2>
<p>
FontLab has path manipulation tools which let you remove overlap and add and subtract shapes. Remove overlap is available: <strong>glyph.removeOverlap()</strong>. Here is an example using the FontLab layer to subtract one shape from another to produce a third.
</p>
<div class="pythonsource"><pre># robothon06
<br># Use FontLab pathfinder functionality to cut one glyph from another
<br>
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span>
<br>
<br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()
<br>
<br><span class="py_key">base</span> = <span class="py_key">f</span>[<span class="py_str">"A"</span>]
<br><span class="py_key">cutter</span> = <span class="py_key">f</span>[<span class="py_str">"B"</span>]
<br><span class="py_key">dest</span> = <span class="py_key">f</span>[<span class="py_str">"C"</span>]
<br>
<br><span class="py_key">dest</span>.<span class="py_key">clear</span>()
<br><span class="py_key">dest</span>.<span class="py_key">appendGlyph</span>(<span class="py_key">base</span>)
<br><span class="py_key">dest</span>.<span class="py_key">width</span> = <span class="py_key">base</span>.<span class="py_key">width</span>
<br><span class="py_key">dest</span>.<span class="py_key">naked</span>().<span class="py_key">Bsubtract</span>(<span class="py_key">cutter</span>.<span class="py_key">naked</span>())
<br>
<br><span class="py_key">dest</span>.<span class="py_key">update</span>()
<br>
<br></pre></div><div class="pythonsourcetitle"><a href="examples/cookieCutter.py" target="new">download examples/cookieCutter.py</a></div>
<p>
This example also sneakily introduces the <strong>naked()</strong> method of the glyph object. This method returns FontLab's own object for the glyph. We'll look at this in a bit more detail later on.
</p>
<h1>
Kerning and building Glyphs
</h1>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_11.gif" />
<h2>Kerning</h2>
<p>
All kerning data of a font is represented by the <strong>Kerning</strong> object. This object behaves like a Python dictionary: the key is a tuple of two glyph or groupnames, the dictionary value is the kern distance.
</p>
<p>In FontLab, font.kerning should not be called repeatedly like a normal attribute. Nothing will go wrong if you do, it will just be slow. The reason for this is that font.kerning is an attribute which (under the hood) has to do a lot of work to collect the data from the underlying FontLab file. Kerning in FontLab is stored at the glyph level, so to pull it up to the RoboFab level a massive iteration must occur when the kerning object is created. This happens each time you ask for the font.kerning attribute. But there's a simple way to work with that efficiently: cache the kerning object. Like so:
</p>
<div class="pythonsource"><pre># robothon06<br># work with kerning 1<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br> <br># now the kerning object is generated once<br><span class="py_key">kerning</span> = <span class="py_key">font</span>.<span class="py_key">kerning</span><br> <br># and ready for your instructions.<br><span class="py_res">print</span> <span class="py_key">kerning</span><br><span class="py_res">print</span> <span class="py_key">len</span>(<span class="py_key">kerning</span>)<br><span class="py_res">print</span> <span class="py_key">kerning</span>.<span class="py_key">keys</span>()<br> <br># proceed to work with the myKerning object<br># this happens in the following examples too.</pre></div><div class="pythonsourcetitle"><a href="examples/workWithKerning1.py" target="new">download examples/workWithKerning1.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RKerning</span> <span class="py_res">for</span> <span class="py_key">MyFont</span> <span class="py_key">Normal</span>&gt;<br><span class="py_num">3141</span><br>[(<span class="py_str">'F'</span>, <span class="py_str">'L'</span>), (<span class="py_str">'D'</span>, <span class="py_str">'G'</span>), (<span class="py_str">'N'</span>, <span class="py_str">'Eacute'</span>), ..<span class="py_key">etc</span>.. ]</pre></div>
<p>
The Kerning object has some useful methods to transform and analyse the data.
</p>
<div class="pythonsource"><pre># robothon06<br># work with kerning 2<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">kerning</span> = <span class="py_key">font</span>.<span class="py_key">kerning</span><br> <br># calculate the average offset<br><span class="py_res">print</span> <span class="py_key">kerning</span>.<span class="py_key">getAverage</span>()<br> <br># count pairs with these glyphs<br><span class="py_res">print</span> <span class="py_key">kerning</span>.<span class="py_key">occurrenceCount</span>([<span class="py_str">"a"</span>, <span class="py_str">"b"</span>])<br> <br># get the maximum values<br><span class="py_res">print</span> <span class="py_key">kerning</span>.<span class="py_key">getExtremes</span>()<br> <br># count the pars<br><span class="py_res">print</span> <span class="py_str">"font has %d kerning pairs"</span> % <span class="py_key">len</span>(<span class="py_key">kerning</span>)<br> <br># this prints all the pairs<br><span class="py_res">for</span> (<span class="py_key">left</span>, <span class="py_key">right</span>), <span class="py_key">value</span> <span class="py_res">in</span> <span class="py_key">kerning</span>.<span class="py_key">items</span>():<br>&nbsp; &nbsp; <span class="py_res">print</span> (<span class="py_key">left</span>, <span class="py_key">right</span>), <span class="py_key">value</span><br>&nbsp; &nbsp; <br></pre></div><div class="pythonsourcetitle"><a href="examples/workWithKerning2.py" target="new">download examples/workWithKerning2.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RKerning</span> <span class="py_res">for</span> <span class="py_key">MyFont</span> <span class="py_key">Normal</span>&gt;<br>-<span class="py_num">20.5953517988</span><br>{<span class="py_str">'a'</span>: <span class="py_num">82</span>, <span class="py_str">'b'</span>: <span class="py_num">52</span>}<br>(-<span class="py_num">191</span>, <span class="py_num">184</span>)<br><span class="py_key">font</span> <span class="py_key">has</span> <span class="py_num">3141</span> <span class="py_key">kerning</span> <span class="py_key">pairs</span><br>(<span class="py_str">'F'</span>, <span class="py_str">'L'</span>) -<span class="py_num">7</span><br>(<span class="py_str">'D'</span>, <span class="py_str">'G'</span>) <span class="py_num">31</span><br>(<span class="py_str">'N'</span>, <span class="py_str">'Eacute'</span>) -<span class="py_num">34</span><br>(<span class="py_str">'agrave.sc'</span>, <span class="py_str">'z'</span>) -<span class="py_num">7</span><br>(<span class="py_str">'K'</span>, <span class="py_str">'v'</span>) -<span class="py_num">111</span><br>(<span class="py_str">'Z'</span>, <span class="py_str">'N'</span>) -<span class="py_num">15</span><br>..<span class="py_key">etc</span>..</pre></div>
<p>
In the example above you see the Kerning object as attribute of a font object, then it is cached by storing it in a new variable. <strong>len(kerning)</strong> gives you the length of the kerning dictionary, the number of kern pairs. Have a look at the attributes and methods of the <a href="http://letterror.com/code/robofab/objects/kerning.html" target="new" class="reference">Kerning object here.</a> It has some very useful methods for interpolating, sorting, combining and splitting kern tables. Back to the example, did you note that the kern pairs appear in random order? It's that Python dictionary thing again: keys of a dictionary have no particular order. Just like the example of the glyphnames in a font object.
</p>
<div class="pythonsource"><pre># robothon06<br># work with kerning 3<br># print a specific set of pairs<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">kerning</span> = <span class="py_key">font</span>.<span class="py_key">kerning</span><br><span class="py_res">for</span> <span class="py_key">left</span>, <span class="py_key">right</span> <span class="py_res">in</span> <span class="py_key">kerning</span>.<span class="py_key">keys</span>():<br>&nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">kerning</span>[(<span class="py_key">left</span>, <span class="py_key">right</span>)] &lt; -<span class="py_num">100</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">left</span>, <span class="py_key">right</span>, <span class="py_key">kerning</span>[(<span class="py_key">left</span>, <span class="py_key">right</span>)]<br></pre></div><div class="pythonsourcetitle"><a href="examples/workWithKerning3.py" target="new">download examples/workWithKerning3.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">K</span> <span class="py_key">v</span> -<span class="py_num">111</span><br><span class="py_key">N</span> <span class="py_key">Atilde</span> -<span class="py_num">114</span><br><span class="py_key">W</span> <span class="py_key">o</span> -<span class="py_num">118</span><br><span class="py_key">W</span> <span class="py_key">odieresis</span> -<span class="py_num">118</span><br><span class="py_key">Acircumflex</span> <span class="py_key">Y</span> -<span class="py_num">103</span><br><span class="py_key">T</span> <span class="py_key">e</span> -<span class="py_num">153</span><br><span class="py_key">T</span> <span class="py_key">adieresis</span> -<span class="py_num">126</span><br><span class="py_key">T</span> <span class="py_key">odieresis</span> -<span class="py_num">133</span><br><span class="py_key">T</span> <span class="py_key">aacute</span> -<span class="py_num">126</span><br><span class="py_key">W</span> <span class="py_key">eacute</span> -<span class="py_num">141</span><br>..<span class="py_key">etc</span>..</pre></div>
<p>
Another example of iterating through the kerning dictionary. This time each kern is tested if the value is less than -100, and only when this is the case the pair is printed. This shows you how you can write code which responds to particular kinds of kerns.
</p>
<div class="pythonsource"><pre># robothon06<br># work with kerning 4<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">kerning</span> = <span class="py_key">font</span>.<span class="py_key">kerning</span><br><span class="py_res">for</span> <span class="py_key">left</span>, <span class="py_key">right</span> <span class="py_res">in</span> <span class="py_key">kerning</span>.<span class="py_key">keys</span>():<br>&nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">left</span> == <span class="py_str">"acircumflex"</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">left</span>, <span class="py_key">right</span>, <span class="py_key">kerning</span>[(<span class="py_key">left</span>, <span class="py_key">right</span>)]<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/workWithKerning4.py" target="new">download examples/workWithKerning4.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">acircumflex</span> <span class="py_key">k</span> -<span class="py_num">7</span><br><span class="py_key">acircumflex</span> <span class="py_key">v</span> -<span class="py_num">38</span><br><span class="py_key">acircumflex</span> <span class="py_key">r</span> -<span class="py_num">4</span><br><span class="py_key">acircumflex</span> <span class="py_key">u</span> -<span class="py_num">4</span><br><span class="py_key">acircumflex</span> <span class="py_key">y</span> -<span class="py_num">31</span><br><span class="py_key">acircumflex</span> <span class="py_key">j</span> -<span class="py_num">26</span><br>..<span class="py_key">etc</span>..</pre></div>
<p>
This script prints all kerns with <strong>acircumflex</strong> as first glyph.
</p>
<h3>Building glyphs</h3>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_20.gif" />
<img src="http://letterror.com/code/robofab/img/ondrawmodel_26.gif" />
<p>
A particularly interesting topic of scripting is building glyphs out of component parts. If a font already has all the parts, a script can, in many cases, assemble the accented versions. An overview of <a href="http://letterror.com/code/robofab/howto/buildingaccents.html" class="reference" target="docs">glyph building options is in the how-to section of the Robofab docs</a>. The first example takes a look at all necessary ingredients: making a new glyph, adding parts and finishing it. Then we'll look at more efficient ways.
</p>
<div class="pythonsource"><pre># robothon06<br># building a glyph from parts<br># the hard way<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br> <br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br> <br># make a new glyph<br><span class="py_key">f</span>.<span class="py_key">newGlyph</span>(<span class="py_str">"aacute"</span>)<br> <br># add the component for the base glyph, a<br><span class="py_key">f</span>[<span class="py_str">"aacute"</span>].<span class="py_key">appendComponent</span>(<span class="py_str">"a"</span>)<br> <br># add the component for the accent, acute<br># note it has an offset<br><span class="py_key">f</span>[<span class="py_str">"aacute"</span>].<span class="py_key">appendComponent</span>(<span class="py_str">"acute"</span>, (<span class="py_num">200</span>, <span class="py_num">0</span>))<br> <br># set the width too<br><span class="py_key">f</span>[<span class="py_str">"aacute"</span>].<span class="py_key">width</span> = <span class="py_key">f</span>[<span class="py_str">"a"</span>].<span class="py_key">width</span><br><span class="py_key">f</span>.<span class="py_key">update</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/buildingAccents1.py" target="new">download examples/buildingAccents1.py</a></div>
<p>
Let's have a look at that line by line. <strong>f.newGlyph("aacute")</strong>. The <strong>newGlyph()</strong> of the <strong>Font</strong> object creates a new glyph and names it <strong>"aacute"</strong>. Then we can get to the new glyph by asking the font. The <strong>Glyph</strong> object has a <strong>appendComponent()</strong> method, which takes a glyphName of the glyph you want to add as a component and optionally an offset coordinate. This you can see in the line where the <strong>acute</strong> glyph is added. Then the width of the new glyph is set to the width of the original glyph. Finally FontLab is told to update.
</p>
<p>
Well, that's going to be an awful lot of code if you have to write 4 lines of code for each new letter. There are other ways of going about this, using FontLab's <strong>Anchor</strong> points. </p>
<h3>glyph.generateGlyph()</h3>
<p>
RoboFab has a database of glyph constructions based on the Adobe Glyph List. Have a look in your RoboFab code folder, <strong>robofab/Data/GlyphConstruction.txt</strong>. The RoboFab list contains information about where components should be connected and what the anchor points are called.
</p>
<div class="pythonsource"><pre><span class="py_key">Acircumflexdotaccent</span>: <span class="py_key">A</span> <span class="py_key">circumflex</span>.<span class="py_key">top</span> <span class="py_key">dotaccent</span>.<span class="py_key">bottom</span></pre></div>
<p>
This entry shows that Acircumflexdotaccent is constructed with components from A, a circumflex using the <strong>top</strong> anchor, and dotaccent using the <strong>bottom</strong> anchor. In order to make this work, you need to add anchor points to your glyphs and accents. Check the FontLab manual for instructions. For instance the "a" has an anchor point named "top", the "acute" glyph has one named "_top".
</p>
<div class="pythonsource"><pre># building a glyph from parts<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">font</span>.<span class="py_key">generateGlyph</span>(<span class="py_str">"aacute"</span>)</pre></div>
<p>
This creates a new glyph at "aacute", it puts all the components in the right place and sets the width.
</p>
<h3>glyph.compileGlyph()</h3>
<p>
Suppose you want to create glyphs using anchor points, but the glyphs don't have entries in Robofab's <strong>GlyphConstruction.txt</strong> list. What to do? Editing GlyphConstruction.txt is not recommended because you will loose your changes when you install a new version of RoboFab. Glyph has another method: <strong>compileGlyph()</strong>. This method, like generateGlyph, builds a new glyph with components, but you get to provide the list and tell which anchor points you want to use. CompileGlyph takes a list of accents and anchors. It will follow the list and allow "stacking" of accents.
</p>
<div class="pythonsource"><pre># robothon06
<br># Compile a new glyph from a list of accents and required anchors
<br># Demo of multiple accents chaining together, or "stacking".
<br># For this example you need to set&nbsp; up a couple of things
<br># in your test font:
<br>#&nbsp; &nbsp; - base glyph "a", with anchor "top" and anchor "bottom"
<br>#&nbsp; &nbsp; - glyph "dieresis" with anchor "_top" and anchor "top"
<br>#&nbsp; &nbsp; - glyph "acture" with anchor "_top"
<br>#&nbsp; &nbsp; - glyph "cedilla" with anchor "_bottom"
<br>#
<br>
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span>
<br><span class="py_key">font</span> = <span class="py_key">CurrentFont</span>()
<br>
<br># this is a list of tuples
<br># each tuple has the name of the accent as first element
<br># and the name of the anchor which to use as the second element
<br><span class="py_key">accentList</span> = [(<span class="py_str">"dieresis"</span>, <span class="py_str">"top"</span>),
<br>&nbsp; &nbsp; (<span class="py_str">"acute"</span>, <span class="py_str">"top"</span>),
<br>&nbsp; &nbsp; (<span class="py_str">"cedilla"</span>, <span class="py_str">"bottom"</span>)]
<br>
<br># The accents are compiled in this order, so first
<br>#&nbsp; &nbsp; "dieresis" connects to "a" using "top" anchor
<br>#&nbsp; &nbsp; "acute" connects to dieresis, using the next "top" anchor
<br>
<br><span class="py_key">font</span>.<span class="py_key">compileGlyph</span>(<span class="py_str">"myCompiledGlyph"</span>, <span class="py_str">"a"</span>, <span class="py_key">accentList</span>)
<br><span class="py_key">font</span>.<span class="py_key">update</span>()
<br>
<br></pre></div><div class="pythonsourcetitle"><a href="examples/compileGlyph.py" target="new">download examples/compileGlyph.py</a></div>
<h2>Next</h2>
<p>
The Robofab stuff will continue with:
<a href="robofab_session5.html">Scripting for interpolation</a>
</p>
<h1>
Scripting for interpolation
</h1>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_17.gif" width="140" height="96" />
<img src="http://letterror.com/code/robofab/img/ondrawmodel_07.gif" />
<h2>Interpolation</h2>
<p>
In this session we're going to look at scripting and interpolation. Building an interpolation system has 2 phases: <strong>preparing</strong> it and <strong>using</strong> it. Though this isn't necessarily a design / production difference. In the first phase you need to make sure all the data is set up properly, the compatible glyphs in each master, matching contours in each glyph, path directions, start point locations etc. This can be a lot of work, but RoboFab can assist by reporting the problems. The second phase, using the interpolation comes when everything works and rather than look for problems (there shouldn't be any) you just want to generate all the weights as fast as possible and get on with it proofing and other things.
</p>
<h2>Terminology</h2>
<p>
The glyphs (or whole fonts) that are used in an interpolation system are usually called <strong>masters</strong>. The <strong>interpolation factor</strong> is a number between 0 and 1. With factor = 0 the result will be identical to the first master (in this case glyph "A"), and as you can probably guess, with factor = 1 the result will match glyph "B". Factor =0.5 means the resulting shape will be exactly between the two masters. The factor can actually also be outside the 0, 1 range - in that case we speak of <strong>extrapolation</strong>. The particular change in a glyph when interpolating from one master to another is called an <strong>axis</strong>.
</p>
<h2>Why use RoboFab interpolation?</h2>
<p>
All the alternatives come with strings attached. FontLab's <strong>Blend</strong> tool forces points in contours which don't match. This is handy if you're looking for a quick fix, but it can more or less destroy your masters. Alternatively you can use the Multiple Master tools, but this requires all of your masters to be in the same file and drawing this way can be tricky. Since interpolation is a useful process in typedesign, and a good candidate for scripting we decided to include solid interpolation support in Robofab.
</p>
<h2>Interpolating glyphs</h2>
<p>
In the first example we're going to interpolate two glyphs in the same font. This can be useful in the design stage, for sketching or testing. The result is stored in a third glyph. Note: if you want to run this example in FontLab, open a new, empty font. Use the circle tool to draw one circle in "A", and again in "B". Make sure these are different enough to tell what's going on.
</p>
<div class="pythonsource"><pre># robothon06<br># interpolate two glyphs in the same font<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">factor</span> = <span class="py_num">0.5</span><br><span class="py_key">f</span>[<span class="py_str">"C"</span>].<span class="py_key">interpolate</span>(<span class="py_key">factor</span>, <span class="py_key">f</span>[<span class="py_str">"A"</span>], <span class="py_key">f</span>[<span class="py_str">"B"</span>])<br><span class="py_key">f</span>[<span class="py_str">"C"</span>].<span class="py_key">update</span>()<br></pre></div><div class="pythonsourcetitle"><a href="examples/interpolateGlyphs.py" target="new">download examples/interpolateGlyphs.py</a></div>
<p>
You see there are 3 glyphs involved: the two masters (<strong>"A"</strong> and <strong>"B"</strong>) and a new glyph which is used to store the results. In this case the new glyph is stored as <strong>"C"</strong>, but it can be helpful to give it a more descriptive name. This is not very PostScript-like, but chances are these glyphs won't make it to production anyway, so it's not a problem. Notice that <strong>interpolate()</strong> is a method of the <strong>Glyph</strong> object. The <strong>Font</strong> object has an interpolate method as well, more about that later. The <a href="http://letterror.com/code/robofab/howto/interpolate.html" class="reference" target="docs">obligatory link</a> to the relevant RoboFab documentation.
</p>
<p>
Here's the same script, but now it generates a range of interpolated glyphs, each with a better name which tells you which interpolation factor was used:
</p>
<div class="pythonsource"><pre># robothon06<br># interpolate two glyphs in the same font a bunch of times<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_res">for</span> <span class="py_key">i</span> <span class="py_res">in</span> <span class="py_key">range</span>(<span class="py_num">0</span>, <span class="py_num">10</span>):<br>&nbsp; &nbsp; <span class="py_key">factor</span> = <span class="py_key">i</span>*<span class="py_num">.1</span><br>&nbsp; &nbsp; <span class="py_key">name</span> = <span class="py_str">"result_%f"</span>%<span class="py_key">factor</span><br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">"interpolating"</span>, <span class="py_key">name</span><br>&nbsp; &nbsp; <span class="py_key">f</span>[<span class="py_key">name</span>].<span class="py_key">interpolate</span>(<span class="py_key">factor</span>, <span class="py_key">f</span>[<span class="py_str">"A"</span>], <span class="py_key">f</span>[<span class="py_str">"B"</span>])<br><span class="py_key">f</span>.<span class="py_key">update</span>()</pre></div><div class="pythonsourcetitle"><a href="examples/interpolateSeries.py" target="new">download examples/interpolateSeries.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.000000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.100000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.200000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.300000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.400000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.500000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.600000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.700000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.800000</span><br><span class="py_key">interpolating</span> <span class="py_key">result_0</span><span class="py_num">.900000</span></pre></div>
<img src="glyphinterpol.gif" alt="" width="493" height="65" />
<p>
Here you see a range of resulting glyphs as they could be generated by the script above.
</p>
<h2>Rounding errors</h2>
<p>
When you interpolate in FontLab you need to take into account that the results will be rounded off. Coordinates can only consist of whole numbers, i,e, "101" or "102" but not "101.3290" There is a nice solution for working with floating point precision glyphs using RoboFab. Here's a brief introduction:</p>
<div class="pythonsource"><pre># robothon06
<br>
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span>
<br># We need to import a class with a different
<br># implementation for the glyph object.
<br># It looks a bit odd, but this is how it is done
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">objects</span>.<span class="py_key">objectsRF</span> <span class="py_res">import</span> <span class="py_key">RGlyph</span> <span class="py_key">as</span> <span class="py_key">_RGlyph</span>
<br>
<br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()
<br>
<br># pick two compatible glyphs as masters
<br><span class="py_key">m1</span> = <span class="py_key">f</span>[<span class="py_str">"A"</span>]
<br><span class="py_key">m2</span> = <span class="py_key">f</span>[<span class="py_str">"B"</span>]
<br>
<br># make a new glyph object from this other glyph class
<br><span class="py_key">g</span> = <span class="py_key">_RGlyph</span>()
<br>
<br># interpolation factor which is&nbsp; bound to make floats
<br><span class="py_key">oddFactor</span> = <span class="py_num">0.2382345</span>
<br>
<br># go!
<br><span class="py_key">g</span>.<span class="py_key">interpolate</span>(<span class="py_key">oddFactor</span>, <span class="py_key">m1</span>, <span class="py_key">m2</span>)
<br>
<br># let's have a look at the raw results
<br><span class="py_res">for</span> <span class="py_key">contour</span> <span class="py_res">in</span> <span class="py_key">g</span>:
<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">pt</span> <span class="py_res">in</span> <span class="py_key">contour</span>.<span class="py_key">points</span>:
<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">"float"</span>, <span class="py_key">pt</span>.<span class="py_key">x</span>, <span class="py_key">pt</span>.<span class="py_key">y</span>
<br>&nbsp; &nbsp;
<br># a glyph can round itself off:
<br><span class="py_key">g</span>.<span class="py_key">round</span>()
<br>
<br># and then it looks like integers again
<br><span class="py_res">for</span> <span class="py_key">contour</span> <span class="py_res">in</span> <span class="py_key">g</span>:
<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">pt</span> <span class="py_res">in</span> <span class="py_key">contour</span>.<span class="py_key">points</span>:
<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">"integer"</span>, <span class="py_key">pt</span>.<span class="py_key">x</span>, <span class="py_key">pt</span>.<span class="py_key">y</span>
<br><span class="py_com"></span></pre></div><div class="pythonsourcetitle"><a href="examples/floatingPointGlyph.py" target="new">download examples/floatingPointGlyph.py</a></div>
<div class="pythonoutput"><pre><span class="py_key">float</span> <span class="py_key">glyph</span> <span class="py_num">285.07676</span> <span class="py_num">114.59806</span><br><span class="py_key">float</span> <span class="py_key">glyph</span> <span class="py_num">641.51202</span> <span class="py_num">285.66048</span><br><span class="py_key">float</span> <span class="py_key">glyph</span> <span class="py_num">452.009385</span> <span class="py_num">679.5407</span><br><span class="py_key">float</span> <span class="py_key">glyph</span> <span class="py_num">95.96647</span> <span class="py_num">508.47828</span><br><span class="py_key">integer</span> <span class="py_key">glyph</span> <span class="py_num">285</span> <span class="py_num">115</span><br><span class="py_key">integer</span> <span class="py_key">glyph</span> <span class="py_num">642</span> <span class="py_num">286</span><br><span class="py_key">integer</span> <span class="py_key">glyph</span> <span class="py_num">452</span> <span class="py_num">680</span><br><span class="py_key">integer</span> <span class="py_key">glyph</span> <span class="py_num">96</span> <span class="py_num">508</span></pre></div>
<p>
Use <strong>font.insertGlyph(myOrphanFloatGlyph, as="someName")</strong> if you want to insert the glyph back into a real font. Inserting causes the glyph points to be rounded off again. In a similar way you can make a font object which does not refer to an open FontLab font. In such a font you can store intermediate floating point glyphs of interpolations.
</p>
<h2>Making it work</h2>
<p>
The following table shows the problems glyphs can have when interpolating. <strong>Compatible</strong> means that the data can interpolate. <strong>Functioning</strong> means that the result actually works as a glyph. You'll see there are several combinations where glyphs are compatible, but the interpolation is not functional.
</p>
<table>
<thead>
<tr>
<td>masters</td>
<td>result</td>
<td>fix</td>
</tr>
</thead>
<tr>
<td>
<img src="compatibility-scheme_2_01.gif" alt="compatibility" width="226" height="89" />
</td>
<td>
Compatible and functioning. Same number of points, same direction, same start point location.
</td>
<td>-
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_02.gif" alt="unusual but compatible and functioning" width="226" height="90" />
</td>
<td>
Unusual, but compatible and functioning. The number of off-curve points differ, but these are assumed to be on top of the on-curve when missing. Note: this only works for segments with 2 off-curve points.
</td>
<td>-
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_03.gif" alt="compatible, functioning" width="226" height="90" />
</td>
<td>
Compatible and functioning. Same number of points, same direction, same start point location, same contour order.
</td>
<td>-
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_04.gif" alt="incompatible" width="226" height="90" />
</td>
<td>
Incompatible and not functioning: different number of points
</td>
<td>Edit the masters.
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_05.gif" alt="compatible, but not functioning" width="226" height="90" />
</td>
<td>
Compatible but not functioning: start point is in the wrong place.</td>
<td>apply <strong> c.autoStartSegment()</strong> on each contour, otherwise edit the masters.
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_06.gif" alt="incompatible and not functioning" width="226" height="90" />
</td>
<td>
Incompatible and not functioning: different number of contours
</td>
<td>
Edit the masters.
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_07.gif" alt="compatible but not functioning" width="226" height="90" />
</td>
<td>
Compatible but not functioning: one of the contours is turning in the wrong direction.
</td>
<td>apply <strong>glyph.correctDirection()</strong>, otherwise edit the masters.
</td>
</tr>
<tr>
<td><img src="compatibility-scheme_2_08.gif" alt="compatible but not functioning" width="226" height="91" />
</td>
<td>
Compatible but not functioning. Contour order: the paths are in the wrong order.
</td>
<td>
apply <strong>glyph.autoContourOrder()</strong>, otherwise edit the masters.
</td>
</tr>
</table>
<p>
Here are some snippets which can help prepare your glyphs. Suppose your test font has two incompatible glyphs "A" and "B".
</p>
<div class="pythonsource"><pre># see if "A" and "B" can interpolate<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">a</span> = <span class="py_key">f</span>[<span class="py_str">"a"</span>]<br><span class="py_res">print</span> <span class="py_key">a</span>.<span class="py_key">isCompatible</span>(<span class="py_key">f</span>[<span class="py_str">"b"</span>], <span class="py_key">False</span>)</pre></div>
<div class="pythonoutput"><pre><span class="py_key">False</span></pre></div>
<p>
So, there's the answer in code, they can't interpolate. Suppose the glyphs were in fact compatible, the answer will read <strong>True</strong>. The <strong>isCompatible()</strong> method takes another parameter,
</p>
<div class="pythonsource"><pre># see if "A" and "B" can interpolate<br># and find out what's wrong if you can<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">a</span> = <span class="py_key">f</span>[<span class="py_str">"a"</span>]<br><span class="py_res">print</span> <span class="py_key">a</span>.<span class="py_key">isCompatible</span>(<span class="py_key">f</span>[<span class="py_str">"b"</span>], <span class="py_key">True</span>)</pre></div>
<div class="pythonoutput"><pre>(<span class="py_key">False</span>, [<span class="py_com">"</span><span class="py_key">Fatal</span> <span class="py_key">error</span>: <span class="py_key">contour</span> <span class="py_num">1</span> <span class="py_res">in</span> <span class="py_key">glyph</span> <span class="py_key">A</span> <span class="py_res">and</span> <span class="py_key">glyph</span> <span class="py_key">B</span><br><span class="py_key">don</span><span class="py_com">'</span><span class="py_key">t</span> <span class="py_key">have</span> <span class="py_key">the</span> <span class="py_key">same</span> <span class="py_key">number</span> <span class="py_key">of</span> <span class="py_key">segments</span>.<span class="py_com">"</span>])</pre></div>
<p>Apart from the stunted grammar, this will tell you more or less what's wrong with the two glyphs. Now you have something to fix. Another frequently found error is this:
</p>
<div class="pythonoutput"><pre>(<span class="py_key">False</span>, [<span class="py_com">"</span><span class="py_key">Fatal</span> <span class="py_key">error</span>: <span class="py_key">glyph</span> <span class="py_key">A</span> <span class="py_res">and</span> <span class="py_key">glyph</span> <span class="py_key">B</span><br><span class="py_key">don</span><span class="py_com">'</span><span class="py_key">t</span> <span class="py_key">have</span> <span class="py_key">the</span> <span class="py_key">same</span> <span class="py_key">number</span> <span class="py_key">of</span> <span class="py_key">contours</span>.<span class="py_com">"</span>])</pre></div>
<p>
More subtle errors happen when one of the contours in one of the masters turns in the wrong direction, or the start point of the contour is in a different place. These won't trip incompatibility errors like ones above, you have to verify the results.
</p>
<p>
The following example shows methods which can help to make glyph more compatible. These methods use rules to arrange the starting point, the order of the contours and the direction of the contours. It is likely, but not garanteed, that other masters of your interpolation will respond the same way to these rules. For instance, <strong>autoStartSegment()</strong> moves the starting point of a contour to the most, bottom left point on the contour. If all your masters share the same structure, this will make sense. But if the masters are radically different on purpose, these rules won't produce the right results and you have to prepare the glyphs manually.
</p>
<div class="pythonsource"><pre># robothon06<br># prepare glyph for interpolation<br># move startpoints<br># fix directions<br># fix contour order<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">glyph</span> = <span class="py_key">f</span>[<span class="py_str">"A"</span>]<br> <br><span class="py_key">glyph</span>.<span class="py_key">autoContourOrder</span>()<br><span class="py_key">glyph</span>.<span class="py_key">correctDirection</span>()<br><span class="py_res">for</span> <span class="py_key">c</span> <span class="py_res">in</span> <span class="py_key">glyph</span>.<span class="py_key">contours</span>:<br>&nbsp; &nbsp; <span class="py_key">c</span>.<span class="py_key">autoStartSegment</span>()<br><span class="py_key">glyph</span>.<span class="py_key">update</span>()</pre></div><div class="pythonsourcetitle"><a href="examples/prepareInterpolGlyph.py" target="new">download examples/prepareInterpolGlyph.py</a></div>
<br />
<h2>Interpolating fonts</h2>
<p>
The following script interpolates two fonts and stores the results in a third. It also smoothly introduces a couple of simple user interface thingies: <strong>AskString</strong> and <strong>SelectFont.</strong> Have a look at the <a href="http://letterror.com/code/robofab/tools/dialogs.html" target="new" class="reference">how to page on the simple dialogs stuff</a>. <strong>AskString()</strong> presents a small dialogbox with a prompt and a text input box. It will return the value you typed in, or <strong>None</strong> if you didn't. Which kinda implies you need to check whether the input makes sense before continuing, but that's a different project. <strong>SelectFont()</strong> gives you simple dialog with a list of the currently open fonts. When you select a fontname, the object for that font is returned. If you don't select anything, <strong>None</strong> is returned.
</p>
<div class="pythonsource"><pre># robothon06<br># interpolate two fonts<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">SelectFont</span>, <span class="py_key">NewFont</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">interface</span>.<span class="py_key">all</span>.<span class="py_key">dialogs</span> <span class="py_res">import</span> <span class="py_key">AskString</span><br> <br><span class="py_key">font1</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select font 1"</span>)<br><span class="py_key">font2</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select font 2"</span>)<br><span class="py_key">value</span> = <span class="py_key">AskString</span>(<span class="py_str">"What percentage?"</span>)<br><span class="py_key">value</span> = <span class="py_key">int</span>(<span class="py_key">value</span>) * <span class="py_num">.01</span><br> <br><span class="py_key">destination</span> = <span class="py_key">NewFont</span>()<br># this interpolates the glyphs<br><span class="py_key">destination</span>.<span class="py_key">interpolate</span>(<span class="py_key">value</span>, <span class="py_key">font1</span>, <span class="py_key">font2</span>, <span class="py_key">doProgress</span>=<span class="py_key">True</span>)<br># this interpolates the kerning<br># comment this line out of you're just testing<br><span class="py_key">destination</span>.<span class="py_key">kerning</span>.<span class="py_key">interpolate</span>(<span class="py_key">font1</span>.<span class="py_key">kerning</span>, <span class="py_key">font2</span>.<span class="py_key">kerning</span>, <span class="py_key">value</span>)<br><span class="py_key">destination</span>.<span class="py_key">update</span>()<br></pre></div><div class="pythonsourcetitle"><a href="examples/interpolateTwoFonts.py" target="new">download examples/interpolateTwoFonts.py</a></div>
<p>
This script asks you to select 2 fonts, then it asks you for an interpolation factor. Then is creates a new font (in FontLab a new empty font window will pop up). Then the <strong>font.interpolate()</strong> method of this new font is called with the interpolation factor you entered before, and the two fonts you selected.
</p>
<h2>Interpolate Kerning</h2>
<p>
In the example above the kerning is interpolated seperately, the Kerning object has its own <strong>interpolate()</strong> method. When a kernpair exists in both masters, the resulting pair will be the expected interpolated value. If a pair is missing from one, the interpolation will assume it has value 0. This only works for flat, non-class kerning. Interpolating class based kerning with exceptions requires more attention. Some Robofab developers have this working though.
</p>
<h2>GlyphMath (aside 1)</h2>
<p>
If they're compatible, Robofab Glyph objects can be used in Python math expression: you can add, subtract, multiply and divide them like normal numbers or variables. The math is applied to the coordinates of each point in the glyph. The result of a glyphMath operation is a new glyph. You can then insert this glyph in a font, or use it for other math operations.
</p>
<table>
<thead>
<tr><td>GlyphMath</td><td>operation</td></tr>
</thead>
<tr><td><img src="glyphmath_examples_01.gif" alt="addition" width="285" height="77" />
</td><td><strong>addition:</strong> the coordinates of each point are added</td>
</tr>
<tr><td><img src="glyphmath_examples_02.gif" alt="subtraction" width="285" height="78" />
</td><td><strong>subtraction:</strong> the coordinates of each point are subtracted. Note that though the glyph looks unrecognisable, all points are still there. Literally the difference between the two glyphs.</td>
</tr>
<tr><td><img src="glyphmath_examples_03.gif" alt="multiplication" width="285" height="78" />
</td><td><strong>multiplication:</strong> scaling the glyph up. When you multiply with a tuple like (1.3, 1.05) the first value is used to multiply the x coordinates, the second value is used for the y coordinates.</td>
</tr>
<tr><td><img src="glyphmath_examples_04.gif" alt="division" width="285" height="78" />
</td><td><strong>division:</strong> scaling the glyph down. When you divide with a tuple like (30, 29) the first value is used to divide the x coordinates, the second value is used for the y coordinates.</td>
</tr>
<tr><td><img src="glyphmath_examples_05.gif" alt="alltogether" width="285" height="193" />
</td><td>Combination of operations to make a real interpolation.</td>
</tr>
</table>
<div class="pythonsource"><pre># glyphmath example, using glyphs in math<br># in the test font: two interpolatable, different glyphs<br># on positions A and B.<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br> <br># glyphmath<br><span class="py_key">a</span> = <span class="py_key">f</span>[<span class="py_str">"A"</span>]<br><span class="py_key">b</span> = <span class="py_key">f</span>[<span class="py_str">"B"</span>]<br> <br># multiply works as scaling up<br><span class="py_key">d</span> = <span class="py_key">a</span> * <span class="py_num">2</span><br>#or<br><span class="py_key">d</span> = <span class="py_num">2</span> * <span class="py_key">a</span><br><span class="py_key">f</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">d</span>, <span class="py_key">as</span>=<span class="py_str">"A.A_times_2"</span>)<br> <br># division works as scaling down<br><span class="py_key">d</span> = <span class="py_key">a</span> / <span class="py_num">2</span><br><span class="py_key">f</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">d</span>, <span class="py_key">as</span>=<span class="py_str">"A.A_divide_2"</span>)<br> <br># addition: add coordinates of each point<br><span class="py_key">d</span> = <span class="py_key">a</span> + <span class="py_key">b</span><br><span class="py_key">f</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">d</span>, <span class="py_key">as</span>=<span class="py_str">"A.A_plus_B"</span>)<br> <br># subtraction: subtract coordinates of each point<br><span class="py_key">d</span> = <span class="py_key">a</span> - <span class="py_key">b</span><br><span class="py_key">f</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">d</span>, <span class="py_key">as</span>=<span class="py_str">"A.A_minus_B"</span>)<br> <br># combination: interpolation!<br><span class="py_key">d</span> = <span class="py_key">a</span> + <span class="py_num">.5</span> * (<span class="py_key">b</span>-<span class="py_key">a</span>)<br><span class="py_key">f</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">d</span>, <span class="py_key">as</span>=<span class="py_str">"A.A_interpolate_B"</span>)<br> <br><span class="py_key">f</span>.<span class="py_key">update</span>()</pre></div><div class="pythonsourcetitle"><a href="examples/glyphMathOperations.py" target="new">download examples/glyphMathOperations.py</a></div>
<p>
You can use GlyphMath to create interpolation effects, transplant transformations from one glyph to another and superimpose several effects at once.
</p>
<h2>Superpolation (aside 2)</h2>
<p>
Shameless commercial: <a href="../http:?//http://letterror.com/code/superpolator/index.html" class="reference" target="docs">Superpolator</a> is a tool for building complex interpolation systems. It's based on Robofab and doesn't really have a place in this presentation. It doesn't make complex interpolations easier, it makes them possible. But ask Erik afterwards.
</p>
<h2>Advanced Interpolation</h2>
<p>
Here are two more advanced examples of interpolation. The first script asks for two master fonts. Then it will generate a list of weights with predefined names and factors. After interpolating, it will close the result font and continue with the next weigt.
</p>
<div class="pythonsource"><pre># robothon06
<br># interpolate two fonts with a series of factors.
<br># for each factor create a new font file.
<br>
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">SelectFont</span>, <span class="py_key">NewFont</span>
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">interface</span>.<span class="py_key">all</span>.<span class="py_key">dialogs</span> <span class="py_res">import</span> <span class="py_key">AskString</span>, <span class="py_key">GetFolder</span>
<br><span class="py_res">import</span> <span class="py_key">os</span>
<br>
<br><span class="py_key">font1</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select font 1"</span>)
<br><span class="py_key">font2</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select font 2"</span>)
<br>
<br><span class="py_key">where</span> = <span class="py_key">GetFolder</span>(<span class="py_str">"Select a folder to save the interpolations"</span>)
<br>
<br><span class="py_key">instances</span> = [ (<span class="py_str">"Light"</span>, <span class="py_num">0</span>),
<br>&nbsp; &nbsp; &nbsp; &nbsp; (<span class="py_str">"NotTooLight"</span>, <span class="py_num">.25</span>),
<br>&nbsp; &nbsp; &nbsp; &nbsp; (<span class="py_str">"Regular"</span>, <span class="py_num">.5</span>),
<br>&nbsp; &nbsp; &nbsp; &nbsp; (<span class="py_str">"Demi"</span>, <span class="py_num">.75</span>),
<br>&nbsp; &nbsp; &nbsp; &nbsp; (<span class="py_str">"Medium"</span>, <span class="py_num">1</span>),
<br>]
<br>
<br><span class="py_res">for</span> <span class="py_key">thing</span> <span class="py_res">in</span> <span class="py_key">instances</span>:
<br>&nbsp; &nbsp; <span class="py_key">name</span>, <span class="py_key">value</span> = <span class="py_key">thing</span>
<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">"generating"</span>, <span class="py_key">name</span>, <span class="py_key">value</span>
<br>&nbsp; &nbsp; <span class="py_key">dst</span> = <span class="py_key">NewFont</span>()
<br>&nbsp; &nbsp;
<br>&nbsp; &nbsp; # this interpolates the glyphs
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">interpolate</span>(<span class="py_key">value</span>, <span class="py_key">font1</span>, <span class="py_key">font2</span>, <span class="py_key">doProgress</span>=<span class="py_key">True</span>)
<br>
<br>&nbsp; &nbsp; # this interpolates the kerning
<br>&nbsp; &nbsp; # comment this line out of you're just testing
<br>&nbsp; &nbsp; #dst.kerning.interpolate(font1.kerning, font2.kerning, value)
<br>
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span> = <span class="py_str">"MyBigFamily"</span>
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span> = <span class="py_key">name</span>
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">info</span>.<span class="py_key">autoNaming</span>()
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">update</span>()
<br>&nbsp; &nbsp; <span class="py_key">fileName</span> = <span class="py_key">dst</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span> + <span class="py_str">"-"</span> + <span class="py_key">dst</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span> + <span class="py_str">".vfb"</span>
<br>&nbsp; &nbsp; <span class="py_key">path</span> = <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">join</span>(<span class="py_key">where</span>, <span class="py_key">fileName</span>)
<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">'saving at'</span>, <span class="py_key">path</span>
<br>&nbsp; &nbsp;
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">save</span>(<span class="py_key">path</span>)
<br>&nbsp; &nbsp; <span class="py_key">dst</span>.<span class="py_key">close</span>()
<br></pre></div><div class="pythonsourcetitle"><a href="examples/interpolateFontSeries.py" target="new">download examples/interpolateFontSeries.py</a></div>
<p>
The next script is a bit tricky, but it can be useful tool in typedesign. Suppose you have a two interpolating masters of different weights. The script interpolates <strong>in horizontal direction</strong> with the heavy weight to increase the stem thickness of the glyph. Then it proceeds to horizontally scale the glyph in such a way that the increase of weight from the interpolation is reduced again. The effect of both operations is a condensed version of the original glyph, but with a comparable stem thickness as the original. If you measure the stems of both masters and enter the values in the script, it can calculate an exact match. Note that the success of this script depends on the quality of the interpolation, and how far you're pushing the limit. From a design point of view you might not even want the condensed to have the same stem thickness. This script won't produce ready-made condensed versions of your typeface, but it can be used to create a starting point for further editing.
</p>
<div class="pythonsource"><pre># robothon06
<br># Get started with a condensed if you have a regular and a bold:
<br>#&nbsp; &nbsp; seperate x, y interpolation to make stems fatter
<br>#&nbsp; &nbsp; then scaling to reduce width
<br>#&nbsp; &nbsp; stems will get their original thickness
<br>
<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span>
<br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()
<br>
<br># these are measurements you have to take
<br># from your font. The width of a stem.
<br><span class="py_key">lightStem</span> = <span class="py_num">106</span>
<br><span class="py_key">fatStem</span> = <span class="py_num">200</span>
<br>
<br><span class="py_res">for</span> <span class="py_key">i</span> <span class="py_res">in</span> <span class="py_key">range</span>(<span class="py_num">0</span>, <span class="py_num">10</span>):
<br>&nbsp; &nbsp; <span class="py_key">factor</span> = (<span class="py_key">i</span>*<span class="py_num">.1</span>, <span class="py_num">0</span>)
<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">factor</span>
<br>&nbsp; &nbsp; <span class="py_key">name</span> = <span class="py_str">"result_%f"</span>%<span class="py_key">factor</span>[<span class="py_num">0</span>]
<br>&nbsp; &nbsp; <span class="py_key">scale</span> = <span class="py_key">float</span>(<span class="py_num">41</span>)/(<span class="py_num">41</span> + <span class="py_key">factor</span>[<span class="py_num">0</span>]*(<span class="py_num">116</span>-<span class="py_num">41</span>))
<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">scale</span>
<br>&nbsp; &nbsp; <span class="py_key">f</span>[<span class="py_key">name</span>].<span class="py_key">interpolate</span>(<span class="py_key">factor</span>, <span class="py_key">f</span>[<span class="py_str">"A"</span>], <span class="py_key">f</span>[<span class="py_str">"B"</span>])
<br>&nbsp; &nbsp; <span class="py_key">f</span>[<span class="py_key">name</span>].<span class="py_key">scale</span>((<span class="py_key">scale</span>, <span class="py_num">1</span>))
<br>&nbsp; &nbsp; <span class="py_key">f</span>[<span class="py_key">name</span>].<span class="py_key">leftMargin</span> = <span class="py_key">f</span>[<span class="py_str">"A"</span>].<span class="py_key">leftMargin</span>
<br>&nbsp; &nbsp; <span class="py_key">f</span>[<span class="py_key">name</span>].<span class="py_key">rightMargin</span> = <span class="py_key">f</span>[<span class="py_str">"A"</span>].<span class="py_key">rightMargin</span>
<br>&nbsp; &nbsp; &nbsp; &nbsp;
<br><span class="py_key">f</span>.<span class="py_key">update</span>()<span class="py_com"></span></pre></div><div class="pythonsourcetitle"><a href="examples/glyphCondensor.py" target="new">download examples/glyphCondensor.py</a></div>
<img src="condensor.jpg" alt="condensor examples" width="552" height="90" />
<p>
</p>
<h1>
Scripting for production
</h1>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_07.gif" />
<h2>Production</h2>
<p>
In the production phase of a font it all comes together: moving stuff around, naming, interpolations, quality control, generating, database work, it pays to invest some time (or money) in some really good scripts. Each foundry and designer has their own preferred ways of doing things. It's impossible to describe one production process and please everyone. So instead we're going to look at some of the things you probably have to do anyway. You will have to match and adapt for your own methods.
</p>
<p>
Production scripts can save a lot of time. But be careful: it is costly to make mistakes with your production sources. Make sure to <strong>test</strong> production scripts first on duplicate data, preferably in a different folder. Doing something "quickly" to a massive kerning table only to discover it was your only copy, and the action was wrong — will not save you any time. Like carpentry: measure twice, cut once.
</p>
<h2>Batch processing</h2>
<p>
Here are some examples of applying changes to several fonts at once using <strong>AllFonts()</strong>. Keep in mind that this applies to all fonts you have open in FontLab. So make sure to close any fonts that you don't want treated this way before running the script.
</p>
<div class="pythonsource"><pre># robothon06<br># set font info in all fonts<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">AllFonts</span><br><span class="py_res">for</span> <span class="py_key">font</span> <span class="py_res">in</span> <span class="py_key">AllFonts</span>():<br>&nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span> = <span class="py_str">"MyFamily"</span><br>&nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">ascender</span> = <span class="py_num">700</span><br>&nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">descender</span> = -<span class="py_num">300</span><br>&nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">update</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/allFontsFontInfo.py" target="new">download examples/allFontsFontInfo.py</a></div>
<p>
Obviously you can extend these to do lots more.
</p>
<div class="pythonsource"><pre># robothon 2006<br># get info attributes for all fonts<br># and dump them to a text file<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">AllFonts</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">interface</span>.<span class="py_key">all</span>.<span class="py_key">dialogs</span> <span class="py_res">import</span> <span class="py_key">PutFile</span><br> <br><span class="py_key">text</span> = []<br> <br><span class="py_res">for</span> <span class="py_key">font</span> <span class="py_res">in</span> <span class="py_key">AllFonts</span>():<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">path</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">familyName</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">styleName</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">unitsPerEm</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">ascender</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_key">str</span>(<span class="py_key">font</span>.<span class="py_key">info</span>.<span class="py_key">descender</span>))<br>&nbsp; &nbsp; <span class="py_key">text</span>.<span class="py_key">append</span>(<span class="py_str">''</span>)<br> <br><span class="py_key">text</span> = <span class="py_str">'\n'</span>.<span class="py_key">join</span>(<span class="py_key">text</span>)<br><span class="py_key">path</span> = <span class="py_key">PutFile</span>(<span class="py_str">'Save file as:'</span>)<br><span class="py_res">if</span> <span class="py_key">path</span>:<br>&nbsp; &nbsp; <span class="py_key">file</span> = <span class="py_key">open</span>(<span class="py_key">path</span>, <span class="py_str">'w'</span>)<br>&nbsp; &nbsp; <span class="py_key">file</span>.<span class="py_key">write</span>(<span class="py_key">text</span>)<br>&nbsp; &nbsp; <span class="py_key">file</span>.<span class="py_key">close</span>()<span class="py_com"></span></pre></div><div class="pythonsourcetitle"><a href="examples/makeFontInfoReport.py" target="new">download examples/makeFontInfoReport.py</a></div>
<p>
This is a more complex script. It iterates through all open fonts, collects some data in each and finally asks for a place to save all the data in a text file.
</p>
<div class="pythonsource"><pre># robothon 2006<br># batch save as<br> <br><span class="py_res">import</span> <span class="py_key">os</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">AllFonts</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">interface</span>.<span class="py_key">all</span>.<span class="py_key">dialogs</span> <span class="py_res">import</span> <span class="py_key">GetFolder</span><br> <br><span class="py_key">path</span> = <span class="py_key">GetFolder</span>()<br><span class="py_res">if</span> <span class="py_key">path</span>:<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">font</span> <span class="py_res">in</span> <span class="py_key">AllFonts</span>():<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">fileName</span> = <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">basename</span>(<span class="py_key">font</span>.<span class="py_key">path</span>)<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">newPath</span> = <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">join</span>(<span class="py_key">path</span>, <span class="py_key">fileName</span>)<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">save</span>(<span class="py_key">newPath</span>)<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/batchSaveAs.py" target="new">download examples/batchSaveAs.py</a></div>
<p>
This asks for a folder, then proceeds to save all open fonts in this folder.
</p>
<div class="pythonsource"><pre># robothon 2006<br># batch interpolate<br> <br><span class="py_res">import</span> <span class="py_key">os</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">SelectFont</span>, <span class="py_key">NewFont</span><br> <br># ask for two masters to interpolate:<br><span class="py_key">font1</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select font 1"</span>)<br><span class="py_key">font2</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select font 2"</span>)<br># these are the interpolation factors:<br><span class="py_key">values</span> = [<span class="py_num">.3</span>, <span class="py_num">.6</span>]<br> <br><span class="py_res">for</span> <span class="py_key">value</span> <span class="py_res">in</span> <span class="py_key">values</span>:<br>&nbsp; &nbsp; # make a new font<br>&nbsp; &nbsp; <span class="py_key">destination</span> = <span class="py_key">NewFont</span>()<br>&nbsp; &nbsp; # do the interpolation<br>&nbsp; &nbsp; <span class="py_key">destination</span>.<span class="py_key">interpolate</span>(<span class="py_key">value</span>, <span class="py_key">font1</span>, <span class="py_key">font2</span>, <span class="py_key">doProgress</span>=<span class="py_key">True</span>)<br>&nbsp; &nbsp; <span class="py_key">destination</span>.<span class="py_key">update</span>()<br>&nbsp; &nbsp; # make a new path + filename for the new font to be saved at:<br>&nbsp; &nbsp; <span class="py_key">dir</span> = <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">dirname</span>(<span class="py_key">font1</span>.<span class="py_key">path</span>)<br>&nbsp; &nbsp; <span class="py_key">fileName</span> = <span class="py_str">"Demo_%d.vfb"</span> % (<span class="py_num">1000</span> * <span class="py_key">value</span>)<br>&nbsp; &nbsp; # save at this path and close the font <br>&nbsp; &nbsp; <span class="py_key">destination</span>.<span class="py_key">save</span>(<span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">join</span>(<span class="py_key">dir</span>, <span class="py_key">fileName</span>))<br>&nbsp; &nbsp; <span class="py_key">destination</span>.<span class="py_key">close</span>()<br> <br><br></pre></div><div class="pythonsourcetitle"><a href="examples/batchInterpolate.py" target="new">download examples/batchInterpolate.py</a></div>
<p>
Here you can pick two fonts from the open fonts. The script will create a new, third font, and make interpolations with the interpolation factors in the <strong>values = [.3, .6]</strong> list. The interpolated font is then saved in the same folder as the first master.
</p>
<p>
This touches on a slippery problem which can cause a lot of confusion. Robofab can only tell FontLab fonts apart from their path attribute, the place where each font is saved. A newly created font has not been saved yet, so it has no path. The effect is that when you have more than one new, unsaved font open, Robofab can't tell them apart (for a couple of reasons) and will continue to work with the first one. It will look like nothing is happening when you run a script. The way around this is to make sure you save each font you created with a script before creating another one. This is safer anyway.
</p>
<p>Here are some useful bits for batch processing fonts which are not open, but in a file. This script is a way to make python collect all files of a particular kind in a folder or folders within that folder. You can use the walker function outside of this script too, it's a useful thing to know.
</p>
<div class="pythonsource"><pre># robothon06<br># ask for a folder<br># find (nested) fontlab files in the folder<br># open the fonts<br># Demonstrates: recursive function,, dialog, os module<br> <br><span class="py_res">import</span> <span class="py_key">os</span>.<span class="py_key">path</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">interface</span>.<span class="py_key">all</span>.<span class="py_key">dialogs</span> <span class="py_res">import</span> <span class="py_key">GetFolder</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">OpenFont</span><br> <br># this function looks for fontlab files in a folder <br><span class="py_res">def</span> <span class="py_def">walk</span>(<span class="py_key">someFolder</span>, <span class="py_key">extension</span>):<br>&nbsp; &nbsp; <span class="py_key">extension</span> = <span class="py_key">extension</span>.<span class="py_key">lower</span>()<br>&nbsp; &nbsp; <span class="py_key">files</span> = []<br>&nbsp; &nbsp; # the os module has tools to deal with<br>&nbsp; &nbsp; # the operating system. This returns a list of names<br>&nbsp; &nbsp; # of stuff in the folder you feed it:<br>&nbsp; &nbsp; <span class="py_key">names</span> = <span class="py_key">os</span>.<span class="py_key">listdir</span>(<span class="py_key">someFolder</span>)<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">n</span> <span class="py_res">in</span> <span class="py_key">names</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">p</span> = <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">join</span>(<span class="py_key">someFolder</span>, <span class="py_key">n</span>)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # if this new thing is a folder itself,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # call this function again, but now with the<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # new path to check that as well. This is<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # called recursion.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">isdir</span>(<span class="py_key">p</span>):<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # add the results of the other folder<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # to the list<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">files</span> += <span class="py_key">walk</span>(<span class="py_key">p</span>, <span class="py_key">extension</span>)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">continue</span><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # is it a file with the extension we want?<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # add it then!<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">n</span>.<span class="py_key">lower</span>().<span class="py_key">find</span>(<span class="py_key">extension</span>) &lt;&gt; -<span class="py_num">1</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">files</span>.<span class="py_key">append</span>(<span class="py_key">p</span>)<br>&nbsp; &nbsp; <span class="py_res">return</span> <span class="py_key">files</span><br> <br><br><span class="py_key">yourFolder</span> = <span class="py_key">GetFolder</span>(<span class="py_str">"Search a folder:"</span>)<br><span class="py_res">if</span> <span class="py_key">yourFolder</span> <span class="py_res">is</span> <span class="py_res">not</span> <span class="py_key">None</span>:<br>&nbsp; &nbsp; <span class="py_key">fontPaths</span> = <span class="py_key">walk</span>(<span class="py_key">yourFolder</span>, <span class="py_str">".vfb"</span>)<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">path</span> <span class="py_res">in</span> <span class="py_key">fontPaths</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">OpenFont</span>(<span class="py_key">path</span>)<span class="py_com"></span><br>&nbsp; &nbsp; &nbsp; &nbsp; <br></pre></div><div class="pythonsourcetitle"><a href="examples/fileWalker.py" target="new">download examples/fileWalker.py</a></div>
<div class="pythonoutput"><pre>[<span class="py_str">'/Applications/FontLab/Samples/FREESANS.VFB'</span>,<br><span class="py_str">'/Applications/FontLab/Samples/FREESERF.VFB'</span>]</pre></div>
<h2>Moving stuff around</h2>
<p>
The moving, merging and splitting of fonts. The first example moves selected glyphs in the same font and renames them. Note that if you remove the line <strong>f.removeGlyph(g.name)</strong> the same script effectively <strong>copies</strong> the glyphs. Also new in this script: it iterates through the whole font and checks for each glyph if the <strong>g.selected</strong> attribute is 1 or 0. If it is 0, the glyph is not selected in the font window. If it is 1, is <strong>is</strong> selected. It then proceeds to create a new glyph name, and calls <strong>f.insertGlyph()</strong> method which takes a glyph as parameter. The optional parameter <strong>as</strong> is to be able to insert the glyph under a different name. If you don't pass a parameter for <strong>as</strong>, the font will insert the glyph under its own name. The glyph can come from the same font, or a different font, or be an orphan glyph.
</p>
<div class="pythonsource"><pre># rename the selected glyphs<br># in the current font to &lt;glyphname&gt;.sc<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br> <br><span class="py_res">for</span> <span class="py_key">g</span> <span class="py_res">in</span> <span class="py_key">f</span>:<br>&nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">g</span>.<span class="py_key">selected</span> == <span class="py_num">0</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">continue</span><br>&nbsp; &nbsp; <span class="py_key">newName</span> = <span class="py_key">g</span>.<span class="py_key">name</span>+<span class="py_str">".sc"</span><br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">"moving"</span>, <span class="py_key">g</span>.<span class="py_key">name</span>, <span class="py_str">"to"</span>, <span class="py_key">newName</span><br>&nbsp; &nbsp; <span class="py_key">f</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">g</span>, <span class="py_key">as</span>=<span class="py_key">newName</span>)<br>&nbsp; &nbsp; <span class="py_key">f</span>.<span class="py_key">removeGlyph</span>(<span class="py_key">g</span>.<span class="py_key">name</span>)<br>&nbsp; &nbsp; <span class="py_key">f</span>.<span class="py_key">update</span>()</pre></div>
<div class="pythonoutput"><pre><span class="py_key">moving</span> <span class="py_key">A</span> <span class="py_key">to</span> <span class="py_key">A</span>.<span class="py_key">sc</span><br><span class="py_key">moving</span> <span class="py_key">C</span> <span class="py_key">to</span> <span class="py_key">C</span>.<span class="py_key">sc</span><br><span class="py_key">moving</span> <span class="py_key">B</span> <span class="py_key">to</span> <span class="py_key">B</span>.<span class="py_key">sc</span></pre></div>
<h2>Generating font binaries</h2>
<p>
</p>
<div class="pythonsource"><pre># robothon 2006<br># batch generate<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">AllFonts</span><br> <br><span class="py_res">for</span> <span class="py_key">font</span> <span class="py_res">in</span> <span class="py_key">AllFonts</span>():<br>&nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">generate</span>(<span class="py_str">'otfcff'</span>)<br></pre></div><div class="pythonsourcetitle"><a href="examples/batchGenerate.py" target="new">download examples/batchGenerate.py</a></div>
<p>
This will generate CFF flavored OpenType fonts for all open files.
</p>
<div class="pythonsource"><pre># robothon 2006<br># a more robust batch generator that only has one font open at the time.<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">interface</span>.<span class="py_key">all</span>.<span class="py_key">dialogs</span> <span class="py_res">import</span> <span class="py_key">GetFolder</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">RFont</span>, <span class="py_key">OpenFont</span><br><span class="py_res">import</span> <span class="py_key">os</span><br> <br><span class="py_res">def</span> <span class="py_def">collectSources</span>(<span class="py_key">root</span>):<br>&nbsp; &nbsp; <span class="py_key">files</span> = []<br>&nbsp; &nbsp; <span class="py_key">ext</span> = [<span class="py_str">'.vfb'</span>]<br>&nbsp; &nbsp; <span class="py_key">names</span> = <span class="py_key">os</span>.<span class="py_key">listdir</span>(<span class="py_key">root</span>)<br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">n</span> <span class="py_res">in</span> <span class="py_key">names</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">splitext</span>(<span class="py_key">n</span>)[<span class="py_num">1</span>] <span class="py_res">in</span> <span class="py_key">ext</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">files</span>.<span class="py_key">append</span>(<span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">join</span>(<span class="py_key">root</span>, <span class="py_key">n</span>))<br>&nbsp; &nbsp; <span class="py_res">return</span> <span class="py_key">files</span><br> <br># A little function for making folders. we'll need it later.<br><span class="py_res">def</span> <span class="py_def">makeFolder</span>(<span class="py_key">path</span>):<br>&nbsp; &nbsp; #if the path doesn't exist, make it!<br>&nbsp; &nbsp; <span class="py_res">if</span> <span class="py_res">not</span> <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">exists</span>(<span class="py_key">path</span>):<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">os</span>.<span class="py_key">makedirs</span>(<span class="py_key">path</span>)<br> <br><span class="py_res">def</span> <span class="py_def">makeDestination</span>(<span class="py_key">root</span>):<br>&nbsp; &nbsp; <span class="py_key">macPath</span> = <span class="py_key">os</span>.<span class="py_key">path</span>.<span class="py_key">join</span>(<span class="py_key">root</span>, <span class="py_str">'FabFonts'</span>, <span class="py_str">'ForMac'</span>)<br>&nbsp; &nbsp; <span class="py_key">makeFolder</span>(<span class="py_key">macPath</span>)<br>&nbsp; &nbsp; <span class="py_res">return</span> <span class="py_key">macPath</span><br> <br><span class="py_res">def</span> <span class="py_def">generateOne</span>(<span class="py_key">f</span>, <span class="py_key">dstDir</span>):<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">"generating %s"</span>%<span class="py_key">f</span>.<span class="py_key">info</span>.<span class="py_key">fullName</span><br>&nbsp; &nbsp; <span class="py_key">f</span>.<span class="py_key">generate</span>(<span class="py_str">'otfcff'</span>,&nbsp; <span class="py_key">dstDir</span>)<br>&nbsp; &nbsp; <br> <br><span class="py_key">f</span> = <span class="py_key">GetFolder</span>()<br> <br><span class="py_res">if</span> <span class="py_key">f</span> <span class="py_res">is</span> <span class="py_res">not</span> <span class="py_key">None</span>:<br>&nbsp; &nbsp; <span class="py_key">paths</span> = <span class="py_key">collectSources</span>(<span class="py_key">f</span>)<br>&nbsp; &nbsp; <span class="py_key">dstDir</span> = <span class="py_key">makeDestination</span>(<span class="py_key">f</span>)<br> <br>&nbsp; &nbsp; <span class="py_res">for</span> <span class="py_key">f</span> <span class="py_res">in</span> <span class="py_key">paths</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">font</span> = <span class="py_key">None</span><br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">f</span><br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">try</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">font</span> = <span class="py_key">OpenFont</span>(<span class="py_key">f</span>)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">generateOne</span>(<span class="py_key">font</span>, <span class="py_key">dstDir</span>)<br> <br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">finally</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">font</span> <span class="py_res">is</span> <span class="py_res">not</span> <span class="py_key">None</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">font</span>.<span class="py_key">close</span>(<span class="py_key">False</span>)<br> <br><br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">'done'</span><br> <br><br></pre></div><div class="pythonsourcetitle"><a href="examples/robustBatchGenerate.py" target="new">download examples/robustBatchGenerate.py</a></div>
<p>
The script above generates fonts too, but is a bit more robust. FontLab sometimes crashes when it has to generate a long list of fonts and they're all open at the same time. This script asks you for a folder of .vfb sources (which in itself can be a useful ingredient for your own scripts). Then it will open them one by one and generate the fonts in the flavor indicated in the line <strong>f.generate('mactype1', dstDir)</strong>. A list of types and their names can be found in the robofab documentation how-to page on <a href="http://letterror.com/code/robofab/howto/generatefonts.html" class="reference" target="docs">generating fonts.</a> This script also creates a new folder to store the generated fonts in, sorted by type.
</p>
<h2>Merging</h2>
<p>
Here's an script, quite complex, for combining two fonts into one. Maybe not for the newbie, but if you're into it try to figure out how it works. It uses a couple of new concepts, like <strong>Sets</strong> and <strong>DigestPens</strong>. If it is too complicated: don't worry.
</p>
<div class="pythonsource"><pre># robothon 2006<br># merge two fonts<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">SelectFont</span>, <span class="py_key">NewFont</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">digestPen</span> <span class="py_res">import</span> <span class="py_key">DigestPointPen</span><br><span class="py_res">from</span> <span class="py_key">sets</span> <span class="py_res">import</span> <span class="py_key">Set</span><br> <br><span class="py_key">font1</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select base font"</span>)<br><span class="py_key">font2</span> = <span class="py_key">SelectFont</span>(<span class="py_str">"Select alternate font"</span>)<br> <br><span class="py_key">font1Names</span> = <span class="py_key">Set</span>(<span class="py_key">font1</span>.<span class="py_key">keys</span>())<br><span class="py_key">font2Names</span> = <span class="py_key">Set</span>(<span class="py_key">font2</span>.<span class="py_key">keys</span>())<br> <br><span class="py_key">commonNames</span> = <span class="py_key">font1Names</span> &amp; <span class="py_key">font2Names</span><br><span class="py_key">uncommonNames</span> = <span class="py_key">font2Names</span> - <span class="py_key">font1Names</span><br> <br><span class="py_res">for</span> <span class="py_key">glyphName</span> <span class="py_res">in</span> <span class="py_key">commonNames</span>:<br>&nbsp; &nbsp; <span class="py_key">glyph1</span> = <span class="py_key">font1</span>[<span class="py_key">glyphName</span>]<br>&nbsp; &nbsp; <span class="py_key">pointPen</span> = <span class="py_key">DigestPointPen</span>()<br>&nbsp; &nbsp; <span class="py_key">glyph1</span>.<span class="py_key">drawPoints</span>(<span class="py_key">pointPen</span>)<br>&nbsp; &nbsp; <span class="py_key">digest1</span> = <span class="py_key">pointPen</span>.<span class="py_key">getDigest</span>()<br>&nbsp; &nbsp; <br>&nbsp; &nbsp; <span class="py_key">glyph2</span> = <span class="py_key">font2</span>[<span class="py_key">glyphName</span>]<br>&nbsp; &nbsp; <span class="py_key">pointPen</span> = <span class="py_key">DigestPointPen</span>()<br>&nbsp; &nbsp; <span class="py_key">glyph2</span>.<span class="py_key">drawPoints</span>(<span class="py_key">pointPen</span>)<br>&nbsp; &nbsp; <span class="py_key">digest2</span> = <span class="py_key">pointPen</span>.<span class="py_key">getDigest</span>()<br>&nbsp; &nbsp; <br>&nbsp; &nbsp; <span class="py_res">if</span> <span class="py_key">digest1</span> != <span class="py_key">digest2</span>:<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">'&gt; alt &gt;'</span>, <span class="py_key">glyphName</span><br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">glyph3</span> = <span class="py_key">font1</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">glyph2</span>, <span class="py_key">as</span>=<span class="py_key">glyphName</span>+<span class="py_str">'.alt'</span>)<br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">glyph3</span>.<span class="py_key">mark</span> = <span class="py_num">1</span><br>&nbsp; &nbsp; &nbsp; &nbsp; <span class="py_key">glyph3</span>.<span class="py_key">update</span>()<br> <br><span class="py_res">for</span> <span class="py_key">glyphName</span> <span class="py_res">in</span> <span class="py_key">uncommonNames</span>:<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_str">'&gt;'</span>, <span class="py_key">glyphName</span><br>&nbsp; &nbsp; <span class="py_key">glyph</span> = <span class="py_key">font1</span>.<span class="py_key">insertGlyph</span>(<span class="py_key">font2</span>[<span class="py_key">glyphName</span>])<br>&nbsp; &nbsp; <span class="py_key">glyph</span>.<span class="py_key">mark</span> = <span class="py_num">60</span><br>&nbsp; &nbsp; <span class="py_key">glyph</span>.<span class="py_key">update</span>()<br>&nbsp; &nbsp; <br><span class="py_key">font1</span>.<span class="py_key">update</span>()<br></pre></div><div class="pythonsourcetitle"><a href="examples/mergeTwoFonts.py" target="new">download examples/mergeTwoFonts.py</a></div>
<p>
</p>
<h2>Dealing with Robofab limitations</h2>
<p>
A handful of FontLab's own glyph and font methods are not supported in RoboFab. The reasons for this vary, some of them are very FontLab specific (for instance <strong>fl.productnumber</strong> or <strong>fl.username</strong>), but most of the missing stuff was just not needed very often — the following examples show how to get access to all functionality and attributes in the FontLab layer.
</p>
<h3>FontLab layer</h3>
<p>
To get to the FontLab layer, Robofab's Font and Glyph objects have a <strong>naked()</strong> method which returns the FontLab object. Note that you can still use the Robofab functionality like CurrentFont, CurrentGlyph, pens etc. The FontLab layer <a href="http://dev.fontlab.net/flpydoc/view_html.html" class="reference" target="new">is documented here.</a> Maybe you remember the <strong>naked()</strong> method from the cookie cutter example.
</p>
<div class="pythonsource"><pre># show the objects from the fontlab layer<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_res">print</span> <span class="py_key">f</span>.<span class="py_key">naked</span>()<br> <br><span class="py_key">g</span> =&nbsp; <span class="py_key">f</span>[<span class="py_str">"A"</span>]<br><span class="py_res">print</span> <span class="py_key">g</span>.<span class="py_key">naked</span>()</pre></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">Font</span>: <span class="py_str">'MyFont'</span>&gt;<br>&lt;<span class="py_key">Glyph</span>: <span class="py_str">'A'</span>, <span class="py_num">0</span> <span class="py_key">nodes</span>, <span class="py_key">parent</span>: <span class="py_str">'MyFont'</span>&gt;</pre></div>
<p>
Other things you need to dig deeper for. Note that some of these objects appear to be broken.
<ul>
<li>
<strong>PostScript hints</strong>: the vertical and horizontal hint zones as well as blue values can be read and set.
<div class="pythonsource"><pre># show vhints for current glyph<br><span class="py_key">g</span> = <span class="py_key">CurrentGlyph</span>()<br><span class="py_key">g</span>.<span class="py_key">naked</span>().<span class="py_key">vhints</span></pre></div>
<div class="pythonoutput"><pre>[&lt;<span class="py_key">VHint</span>: <span class="py_key">p</span>=<span class="py_num">25</span>, <span class="py_key">w</span>=<span class="py_num">163</span>, <span class="py_key">parent</span>: <span class="py_str">"a"</span>&gt;,&lt;<span class="py_key">VHint</span>: <span class="py_key">p</span>=<span class="py_num">42</span>, <span class="py_key">w</span>=<span class="py_num">146</span>, <span class="py_key">parent</span>: <span class="py_str">"a"</span>&gt;]</pre></div>
</li>
<li>
<strong>All name fields</strong>: the FontLab table of OpenType names, the naming record, is available. See also the <a href="http://dev.fontlab.net/flpydoc/html/NameRecord.xml.html" class="reference" target="new">the FontLab reference for NameRecord</a>
<div class="pythonsource"><pre># robothon06<br># show OpenType naming records<br># in the fontlab API<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">fn</span> = <span class="py_key">f</span>.<span class="py_key">naked</span>()<br><span class="py_res">for</span> <span class="py_key">r</span> <span class="py_res">in</span> <span class="py_key">fn</span>.<span class="py_key">fontnames</span>:<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">r</span>.<span class="py_key">nid</span>, <span class="py_key">r</span>.<span class="py_key">pid</span>, <span class="py_key">r</span>.<span class="py_key">eid</span>, <span class="py_key">r</span>.<span class="py_key">lid</span>, <span class="py_key">r</span>.<span class="py_key">name</span><span class="py_com"></span></pre></div><div class="pythonsourcetitle"><a href="examples/showNamingRecords.py" target="new">download examples/showNamingRecords.py</a></div>
<div class="pythonoutput"><pre><span class="py_num">256</span> <span class="py_num">1</span> <span class="py_num">0</span> <span class="py_num">0</span> <span class="py_key">Bold</span><br><span class="py_num">256</span> <span class="py_num">3</span> <span class="py_num">1</span> <span class="py_num">1033</span> <span class="py_key">Bold</span></pre></div>
</li>
<li>
<strong>Encodings</strong>.The FontLab Encoding object. See also the
<a href="http://dev.fontlab.net/flpydoc/html/Encoding.xml.html" class="reference" target="new">the FontLab reference for Encoding</a>
<div class="pythonsource"><pre># robothon06<br># show encoding <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">CurrentFont</span><br><span class="py_key">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">fn</span> = <span class="py_key">f</span>.<span class="py_key">naked</span>()<br> <br># object containing encoding records<br># you can iterate through it by using<br># an index.<br><span class="py_res">print</span> <span class="py_key">fn</span>.<span class="py_key">encoding</span><br><span class="py_res">for</span> <span class="py_key">i</span> <span class="py_res">in</span> <span class="py_key">range</span>(<span class="py_key">len</span>(<span class="py_key">fn</span>.<span class="py_key">encoding</span>)):<br>&nbsp; &nbsp; <span class="py_key">er</span> = <span class="py_key">fn</span>.<span class="py_key">encoding</span>[<span class="py_key">i</span>]<br>&nbsp; &nbsp; <span class="py_res">print</span> <span class="py_key">er</span>, <span class="py_key">er</span>.<span class="py_key">name</span>, <span class="py_key">er</span>.<span class="py_key">unicode</span><br><span class="py_com"></span></pre></div><div class="pythonsourcetitle"><a href="examples/showEncoding.py" target="new">download examples/showEncoding.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">Encoding</span>: <span class="py_key">parent</span>: <span class="py_str">"MyDemoRegular"</span>&gt;<br>...<br>&lt;<span class="py_key">EncodingRecord</span>: <span class="py_str">"eacute"</span>, <span class="py_key">unicode</span>: <span class="py_num">233</span>&gt; <span class="py_key">eacute</span> <span class="py_num">233</span><br>&lt;<span class="py_key">EncodingRecord</span>: <span class="py_str">"ecircumflex"</span>, <span class="py_key">unicode</span>: <span class="py_num">234</span>&gt; <span class="py_key">ecircumflex</span> <span class="py_num">234</span><br>&lt;<span class="py_key">EncodingRecord</span>: <span class="py_str">"edieresis"</span>, <span class="py_key">unicode</span>: <span class="py_num">235</span>&gt; <span class="py_key">edieresis</span> <span class="py_num">235</span><br>&lt;<span class="py_key">EncodingRecord</span>: <span class="py_str">"igrave"</span>, <span class="py_key">unicode</span>: <span class="py_num">236</span>&gt; <span class="py_key">igrave</span> <span class="py_num">236</span><br>&lt;<span class="py_key">EncodingRecord</span>: <span class="py_str">"iacute"</span>, <span class="py_key">unicode</span>: <span class="py_num">237</span>&gt; <span class="py_key">iacute</span> <span class="py_num">237</span><br>&lt;<span class="py_key">EncodingRecord</span>: <span class="py_str">"icircumflex"</span>, <span class="py_key">unicode</span>: <span class="py_num">238</span>&gt; <span class="py_key">icircumflex</span> <span class="py_num">238</span><br>..<span class="py_key">etc</span>..</pre></div>
</li>
</ul>
</p>
<h1>
Adventures in NoneLab, scripting outside the box
</h1>
<img src="http://letterror.com/code/robofab/img/ondrawmodel_17.gif" width="140" id="smallforprint" height="96" />
<p>
Working with text sources UFO, and GLIF's. Fontlab export and import of UFO. Processing UFO's outside FontLab.
</p>
<p>Previous: <a href="robofab_session6.html">Scripting for production</a>, next: <a href="dialogkit.html">Dialog Kit</a>
</p>
<h2>UFO</h2>
<p>
Scripting a font editor without the font editor?
RoboFab can export and import to the text based <a href="http://letterror.com/code/robofab/ufo/index.html" class="reference" target="docs">UFO format</a> for font sources. You can export a FontLab font to .ufo, and you can import a .ufo to FontLab easily. Read the <a href="http://letterror.com/code/robofab/howto/makeufo.html" class="reference" target="docs">how-to</a>. UFO export and import scripts are available from the RoboFab Scripts menu. But what do you do with ufos then?
</p>
<h2>Scripting with fonts outside FontLab</h2>
<p>
The nice thing about UFO is that RoboFab can read the files even when it is not running in FontLab. The Python interpreter that you use for FontLab, can run RoboFab scripts and apply them to font and glyphs stored in a UFO rather than a .vfb. That opens possibilities for batch processing, storage in databases or version management systems, archiving or connecting your own tools to your workflow. FontLab specific functionality, such as generating font binaries, and complex path manipulations are not available in the <strong>NoneLab</strong> RoboFab, but you can make fonts, create and move glyphs, generate and manipulate kerning. We've taken great care to make sure that RoboFab based scripts work in both worlds.
</p>
<h2>NoneLab</h2>
<p>
NoneLab is a word we coined to describe Robofab/Python environments outside FontLab. Let's have a look at main the differences.
<table>
<thead>
<tr>
<td>
</td>
<td>
FontLab
</td>
<td>
NoneLab
</td>
</tr>
</thead>
<tr>
<td class="item">
Font binary generation
</td>
<td>
All formats. Import, export UFO.
</td>
<td>
Read, write UFO. Read TT, OTF, PS T1 (through fontTools). Experimental support for SVG fonts.
</td>
</tr>
<tr>
<td class="item">
CurrentFont, CurrentGlyph, AllFonts
</td>
<td>
Yes
</td>
<td>
No. Use OpenFont(aPathToUFO) instead, or open the .ufo fonts with RFont(aPathToUFO)
</td>
</tr>
<tr>
<td class="item">
Interpolation
</td>
<td>
Yes
</td>
<td>
Yes - quite a bit faster too.
</td>
</tr>
<tr>
<td class="item">
Make new fonts, move glyphs, merge, split files
</td>
<td>
Yes
</td>
<td>
Yes
</td>
</tr>
<tr>
<td class="item">
Build accented glyphs
</td>
<td>
Yes
</td>
<td>
Yes
</td>
</tr>
<tr>
<td class="item">
Manipulate kerning
</td>
<td>
Yes
</td>
<td>
Yes
</td>
</tr>
<tr>
<td class="item">
Remove overlap
</td>
<td>
Yes
</td>
<td>
No
</td>
</tr>
<tr>
<td class="item">
API
</td>
<td>
All Robofab objects. Plus the underlying FontLab objects.
</td>
<td>
All Robofab objects.
</td>
</tr>
<tr>
<td class="item">
Platform
</td>
<td>
Mac OSX, Windows, within FontLab
</td>
<td>
All platforms which support Python, Mac OSX, Windows, Linux, Unix
</td>
</tr>
<tr>
<td class="item">
Open file format
</td>
<td>
No, .vfb is a proprietary, binary file format.
</td>
<td>
Yes. UFO and GLIF formats are XML based, open and documented. You can build your own tools and use these formats.
</td>
</tr>
<tr>
<td class="item">
Widgets, UI toolkit
</td>
<td>
DialogKit, plus the set of basic windows from robofab.interface
</td>
<td>
When run as a window-less user in OSX or linux the interface things are disabled. In some Python IDE's: the set of basic windows from robofab.interface. On OSX: Vanilla.
</td>
</tr>
</table>
</p>
<h2>The UFO</h2>
<p>A UFO is not really a single file, but rather a whole folder full of stuff with a .ufo extension in the name. So you can open up a .ufo and have a look inside. Some data is stored in .plist format. This is a flavor of XML and contains kerning, lib and font info. The glyphs are stored level deeper, in the glyphs folder.
</p>
<img src="ufo.jpg" alt="UFO files and folders" width="515" id="smallforprint" height="368" />
<p>
The MyFont.ufo/glyphs/ folder contains a list of .glif files and a single contents.plist file. This is the table of contents for the folder, it contains a table of glyph name to file name mappings. So when you start working with a .ufo and you want a particular glyph, Robofab can find it faster.
</p>
<h2>The GLIF</h2>
<p>GLyph Interchange Format, a readable XML based file with all data for a single glyph: width, unicode value, all contours, points and components. The glyph.lib is also stored here.
</p>
<img src="cent.gif" alt="view of a glif" width="394" id="smallforprint" height="478" />
<p>
These screenshots are taken on an OSX machine, but the data is platform independent. Basically you can take any text editor and mess around with the points. While this is not a very efficient way to design type, it shows that the data is still there, accessible forever.
</p>
<h2>Exporting UFO</h2>
<p>
In the FontLab scripts folder that is distributed with Robofab, you will find a set of scripts for importing and exporting UFO and GLIF. Open a test font and run this script from the Macro menu. It will generate a .ufo in the same folder as the source font file.
</p>
<img src="exportmenu.gif" alt="export UFO menu" width="376" id="smallforprint" height="170" />
<p>
</p>
<h2>FontLab Remote</h2>
<p>
If you happen to be using FontLab in mac, you can use the FontLab Remote module to make FontLab receive Python instructions and data by <strong>AppleEvents.</strong> You need to start the AppleEvent handler by importing the <strong>robofab.tools.remote</strong> module. After importing it, FontLab can receive instructions by AppleEvent. You need to call remote once after starting FontLab. Now external scripts running outside FontLab can call the FontLab application, send it glyphs, get results back.
</p>
<div class="pythonsource"><pre># start the AppleEvent handler<br><span class="py_res">import</span> <span class="py_key">robofab</span>.<span class="py_key">tools</span>.<span class="py_key">remote</span></pre></div>
<div class="pythonoutput"><pre><span class="py_key">FontLabRemote</span> <span class="py_res">is</span> <span class="py_key">on</span>.</pre></div>
<p>
The following script needs to be run in a python IDE. It will ask FontLab for its current glyph, and then it will store this glyph in a new font object outside FontLab.
</p>
<div class="pythonsource"><pre># robothon06<br># demo of executing python in FontLab, MacOS only<br> <br># this script runs in the Python IDE<br># it will send some python code to FontLab<br># FontLab will execute the python code:<br># it will find the current glyph and send it to our other script.<br> <br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">tools</span>.<span class="py_key">remote</span> <span class="py_res">import</span> <span class="py_key">runFontLabRemote</span>, <span class="py_key">receiveGlyph</span><br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">world</span> <span class="py_res">import</span> <span class="py_key">RFont</span><br> <br># this is what we want FontLab to do:<br><span class="py_key">pythonCode</span> = <span class="py_str">"""<br>from robofab.world import CurrentGlyph<br>from robofab.tools.remote import transmitGlyph<br>g = CurrentGlyph()<br>transmitGlyph(g)<br>"""</span><br> <br># this the font where we'll store the glyph from FontLab<br><span class="py_key">destFont</span> = <span class="py_key">RFont</span>()<br> <br><span class="py_key">result</span> = <span class="py_key">runFontLabRemote</span>(<span class="py_key">pythonCode</span>)<br><span class="py_key">receiveGlyph</span>(<span class="py_key">result</span>, <span class="py_key">destFont</span>)<br><span class="py_res">print</span> <span class="py_key">destFont</span>.<span class="py_key">keys</span>()</pre></div><div class="pythonsourcetitle"><a href="examples/fontLabRemote.py" target="new">download examples/fontLabRemote.py</a></div>
<div class="pythonoutput"><pre>&lt;<span class="py_key">RGlyph</span> <span class="py_res">for</span> <span class="py_key">None</span>.<span class="py_key">parenright</span>&gt;<br>[<span class="py_str">'parenright'</span>]</pre></div>
<img src="robothon06_logo.gif" alt="robothon06 logo" width="369" height="372" />
</div>
</body></html>