459 lines
47 KiB
HTML
459 lines
47 KiB
HTML
|
<!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>
|
||
|
RoboThon 2006: Glyph and Pen objects
|
||
|
</title>
|
||
|
<link href="../default.css" type="text/css" rel="stylesheet" />
|
||
|
</head><body>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<script type="text/javascript" src="http://www.google-analytics.com/urchin.js"></script>
|
||
|
<script type="text/javascript">
|
||
|
_uacct = "UA-2044310-2";
|
||
|
urchinTracker();
|
||
|
</script>
|
||
|
|
||
|
<div id="modellogo">
|
||
|
<img src="../img/drawmodel_header.jpg" width="595" height="112" />
|
||
|
</div>
|
||
|
<div class="leftcontent">
|
||
|
<h1 class="crb-seealso">
|
||
|
RoboFab
|
||
|
</h1>
|
||
|
<p class="menu">
|
||
|
<a href="../index.html">
|
||
|
Home
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../download/index.html">
|
||
|
Download v1.1.1
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../intro.html">
|
||
|
Intro
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../install.html">
|
||
|
Install Notes
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../history.html">
|
||
|
History
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../executive.html">
|
||
|
Summary
|
||
|
</a>
|
||
|
</p>
|
||
|
|
||
|
<p class="menu">
|
||
|
<a href="../howto/index.html">
|
||
|
How to's
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="index.html">
|
||
|
Step by step
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../tools/dialogs.html">
|
||
|
Fab Dialogs
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../objects/index.html">
|
||
|
Object reference
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../objects/model.html">
|
||
|
Object map
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../tools/index.html">
|
||
|
Tools
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../ufo/index.html">
|
||
|
UFO Overview
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../ufo/specification.html">
|
||
|
UFO Spec
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../limitations.html">
|
||
|
Fab Limitations
|
||
|
</a>
|
||
|
|
||
|
<a href="../links/index.html">
|
||
|
Links
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../credits.html">
|
||
|
Credits
|
||
|
</a>
|
||
|
</p>
|
||
|
|
||
|
<h1 class="crb-seealso">
|
||
|
Support RoboFab
|
||
|
</h1>
|
||
|
|
||
|
|
||
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||
|
<input type="hidden" name="cmd" value="_s-xclick">
|
||
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but21.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
|
||
|
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||
|
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----
|
||
|
">
|
||
|
</form>
|
||
|
|
||
|
|
||
|
|
||
|
<h2 class="crb-seealso">
|
||
|
Up
|
||
|
</h2>
|
||
|
|
||
|
<p class="menu">
|
||
|
<p class="bonbon_uplink"><a href="index.html">Back to Step by step</a></p>
|
||
|
</p>
|
||
|
|
||
|
<h2 class="crb-seealso">
|
||
|
See also
|
||
|
</h2>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<p class="menu">
|
||
|
<a href="../howto/glyphmath.html">Using Glyph Math</a><br /><a href="../howto/interpolate.html">How to interpolate</a><br /><a href="../howto/usetransformations.html">Using transformations</a><br /><a href="../objects/anchor.html">RAnchor</a><br /><a href="../objects/bpoint.html">bPoint</a><br /><a href="../objects/component.html">RComponent</a><br /><a href="../objects/contour.html">RContour</a><br /><a href="../objects/font.html">RFont</a><br /><a href="../objects/glyph.html">RGlyph</a><br /><a href="../objects/index.html">Objects</a><br /><a href="../objects/info.html">RInfo</a><br /><a href="../objects/kerning.html">RKerning</a><br /><a href="../objects/lib.html">RLib</a><br /><a href="../objects/pen.html">Pen objects</a><br /><a href="../objects/point.html">RPoint</a><br /><a href="../objects/segment.html">RSegment</a><br /><a href="robofab_session1.html">Font object, Info object</a><br /><a href="robofab_session3.html">Kerning object and glyph building</a><br /><a href="robofab_session5.html">Interpolation</a><br />
|
||
|
</p>
|
||
|
</div>
|
||
|
|
||
|
<div class="footer">
|
||
|
<a href="../feedback.html">
|
||
|
Feedback
|
||
|
</a>
|
||
|
<br />
|
||
|
<a href="../map.html">
|
||
|
Sitemap
|
||
|
</a>
|
||
|
<br />
|
||
|
Please also refer to the
|
||
|
<a href="../download/license.html">
|
||
|
Legal
|
||
|
</a>
|
||
|
<br />
|
||
|
Copyright 2003-2006 RoboFab
|
||
|
<br />
|
||
|
version 1.1.1
|
||
|
</div>
|
||
|
|
||
|
<div class="google">
|
||
|
|
||
|
|
||
|
<h2>RoboFab Mailinglist</h2>
|
||
|
<p>
|
||
|
Join the RoboFab users community at Google groups.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<img src="http://groups.google.com/groups/img/3nb/groups_bar.gif" alt="Google Groups" height="26" width="132" />
|
||
|
|
||
|
<p>
|
||
|
<form action="http://groups.google.com/group/robofab/boxsubscribe">
|
||
|
Email: <input type="text" name="../email" />
|
||
|
<input type="submit" name="../sub" value="Subscribe" />
|
||
|
</form>
|
||
|
</p>
|
||
|
<p>
|
||
|
<a href="http://groups.google.com/group/robofab">Visit this group</a>
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<h2>RoboFab Sponsors</h2>
|
||
|
|
||
|
<script type="text/javascript">
|
||
|
|
||
|
|
||
|
google_ad_client = "pub-3703953449723704";
|
||
|
google_ad_width = 120;
|
||
|
google_ad_height = 600;
|
||
|
google_ad_format = "120x600_as";
|
||
|
google_ad_type = "text_image";
|
||
|
google_ad_channel ="";
|
||
|
google_color_border = "336699";
|
||
|
google_color_bg = "FFFFFF";
|
||
|
google_color_link = "0000FF";
|
||
|
google_color_url = "008000";
|
||
|
google_color_text = "000000";
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
</script>
|
||
|
|
||
|
|
||
|
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div class="content">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<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><<span class="py_key">RFont</span> <span class="py_key">font</span> <span class="py_res">for</span> <span class="py_key">SomeFont</span>></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> <span class="py_res">print</span> <span class="py_key">contour</span><br> <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><<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>]><br><<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>]></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>[<<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>]>,<br><<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>]>,<br>...<br><<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>]>]<br> <br>[<<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>]>,<br><<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>]>,<br>...<br><<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>]>]<br> <br>[<<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>]>,<br><<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>]>,<br>...<br><<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>]>]</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> <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><<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>></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> <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> <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> <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> <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> <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> <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> # check the source glyph is white or black at x,y<br> <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> <span class="py_key">drawRect</span>
|
||
|
|
||
|
|
||
|
<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>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
</body></html>
|