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

301 lines
20 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>How to use pens</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="index.html">
How to's
</a>
<br />
<a href="../talks/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 How To</a></p>
</p>
<h2 class="crb-seealso">
See also
</h2>
<p class="menu">
<a href="../objects/pen.html">Pen objects</a><br /><a href="buildingaccents.html">Building accents</a><br /><a href="fontlabremote.html">FontLab Remote</a><br /><a href="generatefonts.html">Generate Fonts</a><br /><a href="index.html">How To</a><br /><a href="interpolate.html">How to interpolate</a><br /><a href="lowlevel.html">How to get to FontLab stuff</a><br /><a href="scripting.html">Scripting</a><br /><a href="understandcontours.html">Understanding Contours</a><br /><a href="usethelib.html">Using the lib</a><br /><a href="world.html">The world module</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>How to use pens</h1>
<p>
On the <a href="../objects/pen.html">pens page</a> we discussed the different pens and their methods. Here we'll look at some practical applications of pens in RoboFab.
</p>
<h2>Drawing stuff in glyphs</h2>
<p>
Sometimes it is necessary to draw things in glyph with a script. Boxes around glyphs, logos, patterns. Whatever the reason, a pen is the way to do it. Rather than constructing all the Contour and Segment objects yourself (it's complex and it can be a pain to get it right), just use a pen to tell the Glyph what you want to draw. In order to make it somewhat easier to find the right pen for the right glyph, RGlyph.getPen() will return a pen object for the current environment. So if you're in FontLab getPen() returns a pen fit for drawing in FontLab RGlyphs. In UFO based fonts, getPen() returns a pen for drawing in UFO glyphs. This way you can keep the code free of environment specific imports.
</p>
<div id="rightimage">
<img src="drawingexample.jpg" alt="result of drawing in a glyph" width="232" height="211" />
</div>
<div class="pythonsource"><pre># robofab manual<br>#&nbsp; &nbsp;&nbsp; Usepens howto<br>#&nbsp; &nbsp; usage examples<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">f</span> = <span class="py_key">CurrentFont</span>()<br><span class="py_key">newGlyph</span> = <span class="py_key">f</span>.<span class="py_key">newGlyph</span>(<span class="py_str">'demoDrawGlyph'</span>, <span class="py_key">clear</span>=<span class="py_key">True</span>)<br><span class="py_key">newGlyph</span>.<span class="py_key">width</span> = <span class="py_num">1000</span><br> <br># hey, what's this:<br><span class="py_key">pen</span> = <span class="py_key">newGlyph</span>.<span class="py_key">getPen</span>()<br># ha! a sneaky way to get a pen object!<br> <br><span class="py_key">pen</span>.<span class="py_key">moveTo</span>((<span class="py_num">100</span>, <span class="py_num">100</span>))<br><span class="py_key">pen</span>.<span class="py_key">lineTo</span>((<span class="py_num">800</span>, <span class="py_num">100</span>))<br><span class="py_key">pen</span>.<span class="py_key">curveTo</span>((<span class="py_num">1000</span>, <span class="py_num">300</span>), (<span class="py_num">1000</span>, <span class="py_num">600</span>), (<span class="py_num">800</span>, <span class="py_num">800</span>))<br><span class="py_key">pen</span>.<span class="py_key">lineTo</span>((<span class="py_num">100</span>, <span class="py_num">800</span>))<br><span class="py_key">pen</span>.<span class="py_key">lineTo</span>((<span class="py_num">100</span>, <span class="py_num">100</span>))<br><span class="py_key">pen</span>.<span class="py_key">closePath</span>()<br> <br><span class="py_key">newGlyph</span>.<span class="py_key">update</span>()<br><span class="py_key">f</span>.<span class="py_key">update</span>()<br></pre></div><div class="pythonsourcetitle"><a href="examples/usagePens.py" target="new">download examples/usagePens.py</a></div>
<h2>robofab.objects.pen.digestPen</h2>
<p>
Using pens to get to contour and outline data.
</p>
<h3>DigestPointPen</h3>
<p>
The DigestPointPen is a pointsPen and it doesn't draw anything, but collects all the coordinates and drawing instructions from glyph.drawPoints(). When the drawing is done you can get to the data with myPen.getDigest(). The result is a tuple with a series of coordinates and instructions. Because it is a tuple you can use it to compare it to other digests, for instance if you want to test if two glyphs are the same or not.
</p>
<div class="pythonsource"><pre># robofab manual<br>#&nbsp; &nbsp;&nbsp; Usepens howto<br>#&nbsp; &nbsp; attribute examples<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">OpenFont</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> <br><span class="py_key">f</span> = <span class="py_key">OpenFont</span>()<br><span class="py_key">myPen</span> = <span class="py_key">DigestPointPen</span>()<br> <br><span class="py_key">f</span>[<span class="py_str">'period'</span>].<span class="py_key">drawPoints</span>(<span class="py_key">myPen</span>)<br><span class="py_res">print</span> <span class="py_key">myPen</span>.<span class="py_key">getDigest</span>()<br> <br></pre></div><div class="pythonsourcetitle"><a href="examples/useDigestPointPen.py" target="new">download examples/useDigestPointPen.py</a></div>
<div class="pythonoutput"><pre>(<span class="py_str">'beginPath'</span>, <br>&nbsp; &nbsp; ((<span class="py_num">140</span>, -<span class="py_num">4</span>), <span class="py_str">'curve'</span>, <span class="py_key">True</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">103</span>, -<span class="py_num">4</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">71</span>, <span class="py_num">30</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">71</span>, <span class="py_num">69</span>), <span class="py_str">'curve'</span>, <span class="py_key">True</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">71</span>, <span class="py_num">109</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">103</span>, <span class="py_num">143</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">140</span>, <span class="py_num">143</span>), <span class="py_str">'curve'</span>, <span class="py_key">True</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">178</span>, <span class="py_num">143</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">210</span>, <span class="py_num">109</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">210</span>, <span class="py_num">69</span>), <span class="py_str">'curve'</span>, <span class="py_key">True</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">210</span>, <span class="py_num">30</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; ((<span class="py_num">178</span>, -<span class="py_num">4</span>), <span class="py_key">None</span>, <span class="py_key">None</span>, <span class="py_key">None</span>), <br>&nbsp; &nbsp; <span class="py_str">'endPath'</span>)</pre></div>
<h3>DigestPointStructurePen</h3>
<p>
The DigestPointStructurePen is very similar to the DigestPointPen, but it only returns a tuple of the structure without any coordinates. This is very useful in comparing point structures between glyphs. For instance if you want to test if the glyphs can be used in interpolation. Using the same glyph as the example above, compare the results.
</p>
<div class="pythonsource"><pre># robofab manual<br>#&nbsp; &nbsp;&nbsp; Usepens howto<br>#&nbsp; &nbsp; DigestPointStructurePen examples<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">OpenFont</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">DigestPointStructurePen</span><br> <br><span class="py_key">f</span> = <span class="py_key">OpenFont</span>()<br><span class="py_key">myPen</span> = <span class="py_key">DigestPointStructurePen</span>()<br> <br><span class="py_key">f</span>[<span class="py_str">'period'</span>].<span class="py_key">drawPoints</span>(<span class="py_key">myPen</span>)<br><span class="py_res">print</span> <span class="py_key">myPen</span>.<span class="py_key">getDigest</span>()<br></pre></div><div class="pythonsourcetitle"><a href="examples/useDigestPtStructure.py" target="new">download examples/useDigestPtStructure.py</a></div>
<div class="pythonoutput"><pre>(<span class="py_str">'beginPath'</span>, <br>&nbsp; &nbsp; <span class="py_str">'curve'</span>, <span class="py_key">None</span>, <span class="py_key">None</span>,<br>&nbsp; &nbsp; <span class="py_str">'curve'</span>, <span class="py_key">None</span>, <span class="py_key">None</span>,<br>&nbsp; &nbsp; <span class="py_str">'curve'</span>, <span class="py_key">None</span>, <span class="py_key">None</span>,<br>&nbsp; &nbsp; <span class="py_str">'curve'</span>, <span class="py_key">None</span>, <span class="py_key">None</span>,<br>&nbsp; &nbsp; <span class="py_str">'endPath'</span>)</pre></div>
<h2>robofab.objects.pen.filterPen</h2>
<p>
As you can see, pen objects are handy tools to get to the glyph data. The <strong>filterPen.py</strong> module contains a couple of pens which modify the contour when it is being drawn. Basically a filterPen controls another pen to do the drawing.
</p>
<h3>FlattenPen and flattenGlyph()</h3>
<p>
Process the contours into a series of straight lines by flattening the curves. That means that a curve is drawn as a series of straight lines, approximating the curve. The length of the segment (and therefor the number of segments) determines the precision. The pen can be controlled to flatten with different lengths. FlattenPen works slightly differently from the PostScript "flattenpath" operator: flattenpath slices a cubic curve a fixed number of times, causing the segments to be of different lengths. The FlattenPen measures each segment and tries to get them all the same length.
</p>
<p>
In order to make working with the FlattenPen easier, filterPen.py also has a convenience function <strong>flattenGlyph()</strong>. This takes care of the one-pen-controlling-another thing, and replaces the current outlines with the filtered results.
</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> *<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">filterPen</span> <span class="py_res">import</span> <span class="py_key">flattenGlyph</span><br> <br><span class="py_key">d</span> = <span class="py_num">10</span><br><span class="py_key">flattenGlyph</span>(<span class="py_key">CurrentGlyph</span>(), <span class="py_key">d</span>)</pre></div>
<img src="../img/flatten.gif" width="400" height="84" />
<p>
Different values for d will result in different lengths for the segments drawn by the FlattenPen.
</p>
<h3>ThresholdPen and thresholdGlyph()</h3>
<p>
ThresholdPen only draws segments which are longer than a certain distance. This can be useful for filtering small unnecessary details from autotraced contours. Obviously this is not a replacement for a trained eye, more like a vacuumcleaner for points.
</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> *<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">filterPen</span> <span class="py_res">import</span> <span class="py_key">thresholdGlyph</span><br> <br><span class="py_key">d</span> = <span class="py_num">10</span><br><span class="py_key">thresholdGlyph</span>(<span class="py_key">CurrentGlyph</span>(), <span class="py_key">d</span>)</pre></div>
<img src="../img/threshold.gif" width="240" height="126" />
<h3>spikeGlyph() and halftoneGlyph()</h3>
<p>
SpikeGlyph and halftoneGlyph are two very graphic conversions,
</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> *<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">filterPen</span> <span class="py_res">import</span> <span class="py_key">spikeGlyph</span><br> <br><span class="py_key">segmentLength</span> = <span class="py_num">20</span><br><span class="py_key">spikeLength</span> = <span class="py_num">100</span><br><span class="py_key">spikeGlyph</span>(<span class="py_key">CurrentGlyph</span>(), <span class="py_key">segmentLength</span>, <span class="py_key">spikeLength</span>)</pre></div>
<img src="../img/spike.gif" width="180" height="127" />
<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> *<br><span class="py_res">from</span> <span class="py_key">robofab</span>.<span class="py_key">pens</span>.<span class="py_key">filterPen</span> <span class="py_res">import</span> <span class="py_key">halftoneGlyph</span><br> <br><span class="py_key">halftoneGlyph</span>(<span class="py_key">CurrentGlyph</span>())</pre></div>
<img src="../img/halftone.gif" width="180" height="97" />
</div>
</body></html>