The scripts folder for FontLab as they shipped with Fab 1.1.1.

git-svn-id: http://svn.robofab.com/trunk@22 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
This commit is contained in:
Erik van Blokland 2008-01-16 08:14:00 +00:00
parent a80c6d2c8a
commit 617945dcf1
41 changed files with 1479 additions and 0 deletions

3
Scripts/ReadMe.txt Normal file
View File

@ -0,0 +1,3 @@
RoboFab Scripts
These are some folders with scripts that can be run in FontLab.

View File

@ -0,0 +1,72 @@
#FLM: Align Two Nodes
"""Align bPoints horizontally, vertically or both."""
from robofab.world import CurrentGlyph
from robofab.interface.all.dialogs import TwoChecks
glyph = CurrentGlyph()
sel = []
#gather selected bPoints
for contour in glyph.contours:
if contour.selected:
for bPoint in contour.bPoints:
if bPoint.selected:
sel.append(bPoint)
if len(sel) != 0:
xL = []
yL = []
#store up all coordinates for use later
for bPoint in sel:
x, y = bPoint.anchor
xL.append(x)
yL.append(y)
if len(xL) > 1:
w = TwoChecks("Horizontal", "Vertical", 0, 0)
if w == None or w == 0:
#the user doesn't want to align anything
pass
else:
#find the center among all those bPoints
minX = min(xL)
maxX = max(xL)
minY = min(yL)
maxY = max(yL)
cX = int(round((minX + maxX)/2))
cY = int(round((minY + maxY)/2))
#set the undo
fl.SetUndo()
#determine what the user wants to do
noY = False
noX = False
if w == 1:
#the user wants to align y
noX = True
elif w == 2:
#the user wants to align x
noY = True
elif w == 3:
#the user wants to align x and y
pass
for bPoint in sel:
#get the move value for the bPoint
aX, aY = bPoint.anchor
mX = cX - aX
mY = cY - aY
if noY:
#don't move the y
mY = 0
if noX:
#don't move the x
mX = 0
bPoint.move((mX, mY))
glyph.update()

View File

@ -0,0 +1,14 @@
"""Correct contour direction for all glyphs in the font"""
from robofab.world import OpenFont
from robofab.interface.all.dialogs import ProgressBar
font = OpenFont()
bar = ProgressBar('Correcting contour direction...', len(font))
for glyph in font:
bar.label(glyph.name)
glyph.correctDirection()
glyph.update()
bar.tick()
font.update()
bar.close()

View File

@ -0,0 +1,27 @@
#
#
# make a list of which glyphs in this font could theoretically
# interpolate with each other.
#
#
from robofab.world import CurrentFont
from robofab.pens.digestPen import DigestPointPen, DigestPointStructurePen
compatibles = {}
f = CurrentFont()
for c in f:
p = DigestPointStructurePen()
c.drawPoints(p)
d = p.getDigest()
if not compatibles.has_key(d):
compatibles[d] = []
compatibles[d].append(c.name)
print
print 'In %s, these glyphs could interpolate:'%(f.info.fullName)
for d, names in compatibles.items():
if len(names) > 1:
print ", ".join(names)

View File

@ -0,0 +1,22 @@
#FLM: Glyph Appender
"""Add a glyph to the current glyph"""
from robofab.world import CurrentFont, CurrentGlyph
from robofab.interface.all.dialogs import SelectGlyph
glyph = CurrentGlyph()
font = CurrentFont()
# select a glyph to add
selected = SelectGlyph(font)
# make sure that we are not trying add the current glyph to itself
if selected.name != glyph.name:
# preserve the current state
fl.SetUndo()
# add the selected glyph to the current glyph
glyph.appendGlyph(selected)
# always update the glyph!
glyph.update()
# and, just to be safe, update the font...
font.update()

View File

@ -0,0 +1,24 @@
#FLM: Fun with GlyphMath
# this example is meant to run with the RoboFab Demo Font
# as the Current Font. So, if you're doing this in FontLab
# import the Demo Font UFO first.
from robofab.world import CurrentFont
from random import random
f = CurrentFont()
condensedLight = f["a#condensed_light"]
wideLight = f["a#wide_light"]
wideBold = f["a#wide_bold"]
diff = wideLight - condensedLight
destination = f.newGlyph("a#deltaexperiment")
destination.clear()
x = wideBold + (condensedLight-wideLight)*random()
destination.appendGlyph( x)
destination.width = x.width
destination.update()
f.update()

View File

@ -0,0 +1,50 @@
#FLM: Interpol Preview
"""This script draws all incremental interpolations
between 1% and 99% of a selected glyph into a new font.
It requires two open source fonts in FontLab."""
from robofab.interface.all.dialogs import SelectFont, OneList, ProgressBar
from robofab.world import NewFont
src1 = SelectFont('Select source font one:')
if src1:
src2 = SelectFont('Select source font two:')
if src2:
# collect a list of all compatible glyphs
common = []
for glyphName in src1.keys():
if src2.has_key(glyphName):
if src1[glyphName].isCompatible(src2[glyphName]):
common.append(glyphName)
common.sort()
selName = OneList(common, 'Select a glyph:')
if selName:
dest = NewFont()
g1 = src1[selName]
g2 = src2[selName]
count = 1
bar = ProgressBar('Interpolating...', 100)
# add the sourec one glyph for reference
dest.newGlyph(selName + '_000')
dest[selName + '_000'].width = src1[selName].width
dest[selName + '_000'].appendGlyph(src1[selName])
dest[selName + '_000'].mark = 1
dest[selName + '_000'].update()
# add a new glyph and interpolate it
while count != 100:
factor = count * .01
newName = selName + '_' + `count`.zfill(3)
gD = dest.newGlyph(newName)
gD.interpolate(factor, g1, g2)
gD.update()
bar.tick()
count = count + 1
# add the source two glyph for reference
dest.newGlyph(selName + '_100')
dest[selName + '_100'].width = src2[selName].width
dest[selName + '_100'].appendGlyph(src2[selName])
dest[selName + '_100'].mark = 1
dest[selName + '_100'].update()
dest.update()
bar.close()

View File

@ -0,0 +1,16 @@
#FLM: Invert Selection
"""Invert the selected segments in the current glyph"""
from robofab.world import CurrentGlyph
glyph = CurrentGlyph()
for contour in glyph.contours:
notSelected = []
for segment in contour.segments:
if not segment.selected:
notSelected.append(segment.index)
contour.selected = False
for index in notSelected:
contour[index].selected = True
glyph.update()

View File

@ -0,0 +1,50 @@
# FLM: Make Cameo Font
"""Make a cameo font. Pretty simple."""
from robofab.world import CurrentFont
from robofab.interface.all.dialogs import Message
buffer = 30
scaleValue = .9
f = CurrentFont()
# clear all kerning
f.kerning.clear()
#determine top and bottom of the box
t = f.info.unitsPerEm + f.info.descender + buffer
b = f.info.descender - buffer
#first decompose any components
for g in f:
g.decompose()
#then proceed with the cameo operation
for g in f:
#catch negative sidebearings
if g.leftMargin < 0:
g.leftMargin = 0
if g.rightMargin < 0:
g.rightMargin = 0
#scale the glyph and sidebearings
leftMargin = int(round((g.rightMargin * scaleValue) + buffer))
rightMargin = int(round((g.rightMargin * scaleValue) + buffer))
g.scale((scaleValue, scaleValue), (int(round(g.width/2)), 0))
g.leftMargin = leftMargin
g.rightMargin = rightMargin
#determine the left and the right of the box
l = 0
r = g.width
#draw the box using flPen
p = g.getPen()
p.moveTo((l, b))
p.lineTo((l, t))
p.lineTo((r, t))
p.lineTo((r, b))
p.closePath()
#correct path direction
g.correctDirection()
#update the glyph
g.update()
#update the font
f.update()
#tell me when it is over
Message('The highly complex "Cameo Operation" is now complete. Please examine the results and be thankful that RoboFab is on your side.')

View File

@ -0,0 +1,12 @@
#FLM: Kerning Counter
"""print kerning counts for glyphs selected in the font window"""
from robofab.world import CurrentFont
font = CurrentFont()
selectedGlyphs = font.selection
kerning = font.kerning
counts = kerning.occurrenceCount(selectedGlyphs)
for glyphName in selectedGlyphs:
print "%s: %s pairs"%(glyphName, counts[glyphName])

View File

@ -0,0 +1,29 @@
#FLM: Print Measurments
"""print the distance and angle between two selected points"""
from robofab.world import CurrentGlyph
import math
glyph = CurrentGlyph()
selectedPoints = []
for contour in glyph.contours:
if contour.selected:
for segment in contour.segments:
if segment.selected:
onCurve = segment.onCurve
point = (onCurve.x, onCurve.y)
if point not in selectedPoints:
selectedPoints.append(point)
if len(selectedPoints) == 2:
xList = [x for x, y in selectedPoints]
yList = [y for x, y in selectedPoints]
xList.sort()
yList.sort()
xDiff = xList[1] - xList[0]
yDiff = yList[1] - yList[0]
ang = round(math.atan2(yDiff, xDiff)*180/math.pi, 3)
print "x:%s y:%s a:%s"%(xDiff, yDiff, ang)

View File

@ -0,0 +1,14 @@
"""round all kerning values to increments of a specified value"""
value = 100
from robofab.world import CurrentFont
font = CurrentFont()
kerning = font.kerning
startCount = len(kerning)
kerning.round(value)
font.update()
print 'finished rounding kerning by %s.'%value
print 'you started with %s kerning pairs.'%startCount
print 'you now have %s kerning pairs.'%len(kerning)

View File

@ -0,0 +1,31 @@
#FLM: UFO Remove Overlap
"""
Remove overlap on all glyphs in a .ufo font.
This script sis more than a little silly, but it
demonstrates how objectsRF and objectsFL can
work hand in hand.
"""
from robofab.objects.objectsRF import OpenFont
from robofab.objects.objectsFL import NewFont
from robofab.interface.all.dialogs import ProgressBar
ufoFont = OpenFont(note="Select a .ufo")
if ufoFont:
bar = ProgressBar('Removing Overlap...', len(ufoFont))
flFont = NewFont()
flGlyph = flFont.newGlyph('OverlapRemover')
for ufoGlyph in ufoFont:
flPen = flGlyph.getPointPen()
ufoGlyph.drawPoints(flPen)
flGlyph.removeOverlap()
ufoPen = ufoGlyph.getPointPen()
ufoGlyph.clear()
flGlyph.drawPoints(ufoPen)
flGlyph.clear()
bar.tick()
flFont.close(save=0)
bar.close()
ufoFont.save(doProgress=True)

View File

@ -0,0 +1,32 @@
#FLM: 010 FontLab to RoboFab and Back
# In which an adventurous glyph of your choice
# makes a trip into RoboFab land,
# and returns safely home after various inspections
# and modifications.
from robofab.world import CurrentGlyph, CurrentFont
c = CurrentGlyph()
f = CurrentFont()
from robofab.objects.objectsRF import RGlyph
d = RGlyph()
# woa! d is now a rf version of a fl glyph!
d.appendGlyph(c)
d.width = 100
c.printDump()
d.printDump()
e = f.newGlyph('copyTest')
# dump the rf glyph back to a fl glyph!
e.appendGlyph(d)
# see, it still takes its own kind as well
e.appendGlyph(f['a'])
e.printDump()

View File

@ -0,0 +1,60 @@
#FLM: RoboFab Intro, Building Accented Glyphs
#
#
# demo building accented glyphs with robofab
#
#
# RoboFab sports very simple, yet very simple automatic
# accented glyph compiling. The accentBuilder module has
# several tools that handle these operations splendidly.
# Why don't we have a look?
# (you will need to have a font open in FontLab)
from robofab.world import CurrentFont
# accentBuilder lives in robofab.tools
from robofab.tools.accentBuilder import AccentTools
font = CurrentFont()
# The first thing that you need is a list of accented glyphs
# that you want to compile. This is a very short one for
# demonstration purposes. There are some more extensive
# lists located in robofab.gString
myList = ['aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', 'aring']
# AccentTools is the class that contains the most important methods.
# It takes a font and the list of accented glyphs as arguments.
accentTool = AccentTools(font, myList)
# These accented glyphs are compiled using anchors. Anchors are
# simple reference points in the glyph. These anchors are used
# to align the various components when the accented glyph is compiled.
# AccentTools looks at the glyph names in your list of accented glyphs
# and references an internal glyph construction database to determine
# where the anchors need to be placed. So, we need to tell AccentTools
# to position the anchors appropriately. We have very flexible control
# of how the anchors are positioned in relation to the glyph.
# So, build the needed anchors!
accentTool.buildAnchors(ucXOffset=30, ucYOffset=70, lcXOffset=20, lcYOffset=50, doProgress=True)
# AccentTools may encounter some problems, for example if some
# necessary glyphs are not present, when adding the anchors.
# We can print these errors by calling:
accentTool.printAnchorErrors()
# Now that we have the anchors in place, we can compile the glyphs.
accentTool.buildAccents(doProgress=True)
# It may also run into some problems, for example if necessary
# anchors are not prest. You can print these errors out as well.
accentTool.printAccentErrors()
# That's it! Now, update the font.
font.update()
# See how easy that is? And, this is just the tip of the iceburg
# with AccentTools. Read the source!

View File

@ -0,0 +1,67 @@
#FLM: RoboFab Intro, Contours, Segments and Points
#
#
# demo of RoboFab contour, segments and points
#
#
# In RoboFab, glyphs are constructed mainly from a list
# of contours. These contours are constructed from lists
# of segments, which are construted from a list of points.
# Kind of makes sense, doesn't it? This demo will briefly
# run through printing some info about the contours in
# a glyph and it will show how to do a few things to contours.
# You should really check out the documentation for a complete
# list of everything that can be done with and to contours,
# segments and points. There are far too many things to list
# in this intro. Ok. Here we go!
from robofab.world import CurrentGlyph
# (you will need t have a font open in FontLab for this demo)
glyph = CurrentGlyph()
# Before we get into changing any of these objects,
# let's print a little info about them.
print "This glyph has %s contours"%len(glyph.contours)
# a glyph has a list of contours
for contour in glyph.contours:
# every contour has an index,
print "-contour index %s"%contour.index
# a direction,
print "--clockwise: %s"%contour.clockwise
# and a list of segments
print "--%s segments"%len(contour.segments)
for segment in contour.segments:
# every segment has an index,
print "---segment %s"%segment.index
# a type,
print "---type: %s"%segment.type
# a list of points,
print "---%s points"%len(segment.points)
# which includes one on curve point,
onCurve = segment.onCurve
print "---onCurve point at: (%s, %s)"%(onCurve.x, onCurve.y)
# and possibly some off curve points
print "---%s offCurve points"%len(segment.offCurve)
# Now, contours, segments and points all have
# unique methods of their own, but for now let's
# just look at contour methods.
for contour in glyph.contours:
# you can move the contour
contour.move((314, 159))
# you can scale the contour
# and you can even set the center
# of the scale
contour.scale((2, .5), center=(100, 100))
# you can reverse the direction
contour.reverseContour()
# and there are many more!
# as always, update the glyph
glyph.update()

View File

@ -0,0 +1,94 @@
#FLM: RoboFab Intro, Font and Glyph Lib
#
#
# demo of font.lib and glyph.lib
#
#
from robofab.world import CurrentFont, CurrentGlyph
# font.lib and glyph.lib are an idea inherited from RoboFog.
# They are spaces to store custom data. font.lib is for
# font-level custom data, glyph.lib is for glyph-level data.
# They're both Python dictionaries.
#
# Now let's talk about your slice of the lib pie.
# Everyone has their own little address space in the lib object.
# This is done by advising to use a naming convention for the
# top level keys in the lib dictionary.
# Your address is defined by inversing your domain name.
# For example, keys used by RoboFab start with "org.robofab",
# LettError keys start with "com.letterror".
# It's pretty simple, and best of all it avoids the problems
# associated with maintaining a registry. This approach
# to naming was pioneered by Java and has been adopted
# by industry luminaries like Apple and RoboFab.
# What you store in your section is completely up to you.
# Enough of that, let's take a look at how to use the thing.
# Make sure you have a font open.
font = CurrentFont()
# Essentially the lib is a dict object, and it has all properties
# of a dict. So, following the naming scheme above, this is how
# you access your section of the lib (but use your address!):
font.lib['org.robofab'] = 'our address in the lib'
font.lib['org.robofab.keepout'] = 'this also belongs to us'
# Like a dict, you can simply store a string in the dict
font.lib['org.robofab'] = 'Hello World'
print font.lib['org.robofab']
# But that is really boring! Let's store a bunch of stuff.
# Here we can go in two directions: we can either store a
# dict right at our address:
font.lib['org.robofab'] = {'An Int':1, 'A Str':'Howdy!', 'A List':['X', 'Y', 'Z'], 'A Dict':{'Robo':'Fab'}}
# Now because we have a nested dict, and we can access
# it like any other dict let's print the stuff we just stored:
print font.lib['org.robofab']['An Int']
print font.lib['org.robofab']['A Str']
print font.lib['org.robofab']['A List']
print font.lib['org.robofab']['A Dict']
# ...or we can avoid deeper nesting, and use our address as a
# key prefix:
font.lib['org.robofab.A'] = "A"
font.lib['org.robofab.B'] = "B"
font.lib['org.robofab.aList'] = [1, 2, 3]
print font.lib['org.robofab.A']
print font.lib['org.robofab.B']
print font.lib['org.robofab.aList']
# It is all sooo easy!
# Every glyph has it's very own lib as well
# and it works just like the font lib
glyph = CurrentGlyph()
glyph.lib['org.robofab'] = {'My glyph is totally':'Awesome'}
print glyph.lib['org.robofab']['My glyph is totally']
# The type of data that can be stored in lib dictionaries is
# limited. Dictionary keys must be strings (or unicode strings),
# values may be dicts, lists, ints, floats, (unicode) strings and
# booleans. There is also a special type to store arbitrary binary
# data: robofab.plistlib.Data. Don't use plain strings for that!
# So, as you can see, this can be a very powerful thing
# to use and you are only limited by your imagination.
# Have fun!
# A Technical Note:
# You "under the hood" type folks out there may be
# wondering where this data is being stored in the
# FontLab file. Well, in all environments, it's stored
# as a Property List* (.plist), which is a simple XML
# format defined by Apple.
# In FontLab, libs are stored in the font.customdata
# and glyph.customdata fields and it is parsed whenever
# the lib is requested. So, don't try to put anything
# else in those fields, otherwise the lib won't work.
# When using UFO/GLIF, font.lib is stored in a file called
# lib.plist in the .ufo folder, glyph.lib is stored as
# part of the .glif file.

View File

@ -0,0 +1,43 @@
#FLM: RoboFab Intro, The Font Object
#
#
# demo of the RoboFab font object
#
#
import robofab
# Let's talk to some of the font objects.
# CurrentFont and CurrentGlyph are similar to
# the RoboFog functions. They return a font
# or Glyph object respectively. It will be the
# front most font or the front most glyph.
from robofab.world import CurrentFont, CurrentGlyph
# This is a brief intro into Robofabs all singing and
# dancing dialog class. It will produce simple
# dialogs in almost any environment, FontLab, Python IDE, W.
from robofab.interface.all.dialogs import Message
# (make sure you have a font opened in FontLab)
f = CurrentFont()
# so now f is the name of a font object for the current font.
if f == None:
# let's see what dialog can do, a warning
Message("You should open a font first, there's nothing to look at now!")
else:
# and another dialog.
Message("The current font is %s"%(f.info.fullName))
# let's have a look at some of the attributes a RoboFab Font object has
print "the number of glyphs:", len(f)
# some of the attributes map straight to the FontLab Font class
# We just straightened the camelCase here and there
print "full name of this font:", f.info.fullName
print "list of glyph names:", f.keys()
print 'ascender:', f.info.ascender
print 'descender:', f.info.descender

View File

@ -0,0 +1,75 @@
#FLM: RoboFab Intro, FoundrySettings.plist
#
#
# demo FoundrySettings.plist
#
#
# Setting all the data strings in the FontLab font header can be a repetitive and
# tedious exercise. RoboFab to the rescue! RoboFab features some nifty tools
# that help automate this process. These tools read a .plist file that you are free
# to edit to include your own standard settings. Currently, the .plist file contains
# these bits of data. We reserve the right to add more in the future.
# -copyright
# -trademark
# -license
# -licenseurl
# -notice
# -ttvendor
# -vendorurl
# -designer
# -designerurl
#
# The foundry settings tools parse this .plist file into a python dictionary that
# can be used to apply the data to fonts. It's really easy to use. Let's check it out!
from robofab.world import CurrentFont
from robofab.tools.toolsFL import makeDataFolder
# all the foundry settings tools live here:
from robofab.tools.toolsAll import readFoundrySettings, getFoundrySetting, setFoundrySetting
import time
import os
# You will need a font open in fontlab for this demo
font = CurrentFont()
# We need to know where the .plist file lives. In the FontLab environment
# it can live in the "RoboFab Data" folder with its friends. makeDataFolder()
# will make the data folder if it doesn't exist and it will return the path
settingsPath = os.path.join(makeDataFolder(), 'FoundrySettings.plist')
# Now, let's load those settings up
# readFoundrySettings(path) will return the data from the .plist as dictionary
mySettings = readFoundrySettings(settingsPath)
# Let's get the current year so that the year string is always up to date
font.info.year = time.gmtime(time.time())[0]
# Apply those settings that we just loaded
font.info.copyright = mySettings['copyright']
font.info.trademark = mySettings['trademark']
font.info.license = mySettings['license']
font.info.licenseURL = mySettings['licenseurl']
font.info.notice = mySettings['notice']
font.info.ttVendor = mySettings['ttvendor']
font.info.vendorURL = mySettings['vendorurl']
font.info.designer = mySettings['designer']
font.info.designerURL = mySettings['designerurl']
# and call the update method
font.update()
# But, Prof. RoboFab, what if I want to change the settings in the .plist file?
# Good question. You can always edit the .plist data by hand, or you can
# do it via a script. It would go a little something like this:
setFoundrySetting('trademark', 'This font is a trademark of Me, Myself and I', settingsPath)
# If you are on OSX, and you have the Apple developers tools installed, you
# can also edit it with /Developer/Applications/Property List Editor.
# And to read only only one setting from the file you can use this handly little method.
font.info.trademark = getFoundrySetting('trademark', settingsPath)
font.update()
# It's that easy!

View File

@ -0,0 +1,55 @@
#FLM: RoboFab Intro, Generating Fonts
#
#
# demo generating fonts with robofab
#
#
# Generating fonts with RoboFab is super easy! Let's have a look.
# (you will need to have a font open in FontLab)
from robofab.world import CurrentFont
import os
# A little function for making folders. we'll need it later.
def makeFolder(path):
#if the path doesn't exist, make it!
if not os.path.exists(path):
os.makedirs(path)
# We need to have a font open for this demo to work
font = CurrentFont()
# This will tell us what folder the font is in
fontPath = os.path.dirname(font.path)
# We'll put the fonts into a folder called "FabFonts" next the .vfb file
macPath = os.path.join(fontPath, 'FabFonts', 'ForMac')
pcPath = os.path.join(fontPath, 'FabFonts', 'ForPC')
bothPath = os.path.join(fontPath, 'FabFonts', 'ForBoth')
# Now, we'll use that little function we made earlier to make the folders
makeFolder(macPath)
makeFolder(pcPath)
makeFolder(bothPath)
# A dict of all the font types we want to output
fontTypes = { 'mac' : ['mactype1', 'macttf', 'macttdfont'],
'pc' : ['pctype1', 'pcmm'],
'both' : ['otfcff', 'otfttf']
}
# Finally, let's generate the fonts!
for macType in fontTypes['mac']:
print "generating %s..."%macType
font.generate(macType, macPath)
for pcType in fontTypes['pc']:
print "generating %s..."%pcType
font.generate(pcType, pcPath)
for bothType in fontTypes['both']:
print "generating %s..."%bothType
font.generate(bothType, bothPath)
print 'Done!'
# Wow! Could it be any easier than that?

View File

@ -0,0 +1,34 @@
#FLM: RoboFab Intro, The Glyph Object
#
#
# demo of the RoboFab glyph object
#
#
import robofab
from robofab.world import CurrentFont, CurrentGlyph
from robofab.interface.all.dialogs import Message
# (make sure you have a font opened in FontLab)
# this code starts out the same as intro_FontObject
f = CurrentFont()
if f == None:
Message("You should open a font first, there's nothing to look at now!")
else:
for g in f:
print "glyphname:", g.name, ", glyph width:", g.width
# so now g is a RoboFab Glyph object
print "this glyph has %d contours" % len(g.contours)
print "this glyph has %d components" % len(g.components)
print "this glyph has %d anchors" % len(g.anchors)
print
# easy huh?
# There are many more attributes and methods.
# Most of these can be used to edit the font data.
# Which makes them not suited for a simple intro as this
# because we don't want to mess up your font.

View File

@ -0,0 +1,24 @@
#FLM: RoboFab Intro, Font and Glyph Lib
#
#
# demo of glyph properties
#
#
from robofab.world import OpenFont
# This is a specific test of some features which are probably
# still only supported in one glyph in the DemoFont.ufo,
# which you can find the robofab/Data/ folder. Here is goes.
f = OpenFont(None, "")
for c in f:
if not c.properties.isEmpty():
print c.properties.dump()
# This prints the available GlyphProperties objects.
# Not very impressive at the moment, but it means
# that at least they're getting stored with the glyphs
# and that they can be read and interpreted.

View File

@ -0,0 +1,88 @@
#FLM: RoboFab Intro, Font Groups
#
#
# demo of RoboFab font groups
#
#
# RoboFab font objects have several objects associated with them
# kerning, info, groups, etc. Let's talk about groups. Groups are,
# well groups of glyph names. These can be useful for lots of things
# like kerning and OpenType features. The number of uses for
# groups is only limited by your imagination. Enough of this
# silly pep talk. Let's check it out.
from robofab.world import CurrentFont
# gString has lots of glyph lists, these two will be useful for this demo
from robofab.gString import uppercase_plain, lowercase_plain
# (you will need t have a font open in FontLab for this demo)
font = CurrentFont()
# First off, let's gather up some glyph names.
# gString's uppercase_plain and lowercase_plain
# lists will do for now. Let's go through these lists
# and see if they contain any glyphs that are in this font.
uppercase = []
lowercase = []
for glyphName in uppercase_plain:
if font.has_key(glyphName):
uppercase.append(glyphName)
for glyphName in lowercase_plain:
if font.has_key(glyphName):
lowercase.append(glyphName)
uppercase.sort()
lowercase.sort()
# And, we'll combine the uppercase glyph names and
# lowercase glyph names that we found into one list
both = uppercase + lowercase
both.sort()
# Just for kicks, let's get the list of glyphs
# that you have selected in the font window as well
selected = font.selection
# Ok, now that we have these lists, what do we do with them?
# Well, we'll store them in font.groups. That object is
# essentially a dictionary that has a few special tricks.
# The dictionary is keyed by the name of the group, and
# the value is the list of the glyphs. Pretty simple.
# Now, let's store these lists away.
groups = font.groups
groups['uppercase'] = uppercase
groups['lowercase'] = lowercase
groups['uppercaseAndLowercase'] = both
groups['selected'] = both
font.update()
# In FontLab the group info is visible in the classes panel.
# if you look there now, you'll (hopefully) see these new
# groups. Wow! Exciting! Amazing! But, what if you want to
# get these lists back? Easy:
groups = font.groups
print 'uppercase:'
print groups['uppercase']
print
print 'lowercase:'
print groups['lowercase']
print
print 'upper and lowercase:'
print groups['uppercaseAndLowercase']
print
print 'selected:'
print groups['selected']
print
# You can even search the groups for the names of groups
# that contain a certain glyph name. It works like this:
groups = font.groups
found = groups.findGlyph('a')
print '"a" is in these groups: %s'%str(found)
# Oh yeah, don't forget to update the font.
font.update()
# Super easy, huh? Now get to it!

View File

@ -0,0 +1,30 @@
#FLM: RoboFab Intro, Interpolating two fonts
# Basic interpolation of two fonts. This is clean
# non-FontLab specific implementation of
# interpolating. This interpolation is strict: it
# adds no points to contours, it does not alter
# the outlines of the extremes in any possible
# way. Note that this works in FontLab as well as
# NoneLab.
#
# In fontlab: select two .vfb files, the result will be a new .vfb
# In NoneLab: select two .ufo files, the result will be a new .ufo
from robofab.world import OpenFont, RFont, RGlyph
from robofab.pens.pointPen import AbstractPointPen
from robofab.interface.all.dialogs import GetFolder
f = OpenFont(None, "First master")
g = OpenFont(None, "Second master")
factor = .5
d = RFont()
d.interpolate(factor, f, g)
path = GetFolder("Select a place to save this UFO")
if path:
d.save(path)
print 'done'

View File

@ -0,0 +1,64 @@
#FLM: RoboFab Intro, Kerning
#
#
# demo of RoboFab kerning.
#
#
# NOTE: this will mess up the kerning in your test font.
from robofab.world import CurrentFont
# (make sure you have a font with some kerning opened in FontLab)
f = CurrentFont()
# If you are familiar with the way RoboFog handled kerning,
# you will feel right at home with RoboFab's kerning implementation.
# As in RoboFog, the kerning object walks like a dict and talks like a
# dict, but it's not a dict. It is a special object that has some features
# build specifically for working with kerning. Let's have a look!
kerning = f.kerning
# A general note about use the kerning object in FontLab. In FontLab, kerning
# data lives in individual glyphs, so to access it at the font level we must go
# through every glyph, gathering kerning pairs as we go. This process occurs
# each time you call font.kerning. So, to speed thinks up, it is best to reference
# it with an assignment. This will keep it from being generated every time you
# you call and attribute or make a change.
# kerning gives you access to some bits of global data
print "%s has %s kerning pairs"%(f.info.fullName, len(kerning))
print "the average kerning value is %s"%kerning.getAverage()
min, max = kerning.getExtremes()
print "the largest kerning value is %s"%max
print "the smallest kerning value is %s"%min
# ok, kerning.getExtremes() may be a little silly, but it could have its uses.
# kerning pairs are accesed as if you are working with a dict.
# (left glyph name, right glyph name)
kerning[('V', 'o')] = -14
print '(V, o)', kerning[('V', 'o')]
# if you want to go through all kerning pairs:
for pair in kerning:
print pair, kerning[pair]
# kerning also has some useful methods. A few examples:
# scale all kerning!
print 'scaling...'
kerning.scale(100)
print "the average kerning value is %s"%kerning.getAverage()
min, max = kerning.getExtremes()
print "the largest kerning value is %s"%max
print "the smallest kerning value is %s"%min
# get a count of pairs that contian certain glyphs
print 'counting...'
count = kerning.occurrenceCount(['A', 'B', 'C'])
for glyphName in count.keys():
print "%s: found in %s pairs"%(glyphName, count[glyphName])
# don't forget to update the font after you have made some changes!
f.update()

View File

@ -0,0 +1,48 @@
#FLM: RoboFab Intro, Simple Drawing
#
#
# demo of drawing with RoboFab
#
#
import robofab
from robofab.world import CurrentFont, CurrentGlyph
# (make sure you have a font opened in FontLab)
f = CurrentFont()
if f == None:
Message("You should open a font first, there's nothing to look at now!")
else:
newGlyph = f.newGlyph('demoDrawGlyph', clear=True)
newGlyph.width = 1000
# The drawing is done through a specialised pen object.
# There are pen objects for different purposes, this one
# will draw in a FontLab glyph. The point of this is that
# Robofab glyphs all respond to the standard set of
# pen methods, and it is a simple way to re-interpret the
# glyph data.
# Make a new pen with the new glyph we just made
pen = newGlyph.getPen()
# Tell the pen to draw things
pen.moveTo((100, 100))
pen.lineTo((800, 100))
pen.curveTo((1000, 300), (1000, 600), (800, 800))
pen.lineTo((100, 800))
pen.lineTo((100, 100))
# Done drawing: close the path
pen.closePath()
# Robofab objects still need to tell FontLab to update.
newGlyph.update()
f.update()
# go check the font, it should now contain a new glyph named
# "demoDrawGlyph" and it should look like a square.

View File

@ -0,0 +1,24 @@
#FLM: RoboFab Intro, Start here!
#
#
# demo of starting up RoboFab
#
#
import robofab
# run this script (or 'macro' as FontLab calls them)
# if it doesn't complain, you're good to go.
#
# If you get an "ImportError" it means that python
# can't find the RoboFab module and that there is
# probably something wrong with the way you
# installed the package.
from robofab.world import world
print world
# This should print something to the "Output" window.
# It should tell you something about the environment
# Robofab thinks it is in.

View File

@ -0,0 +1,36 @@
#FLM: Glyph to Glif, not in UFO
"""Dump the selected glyph to a Glif as a seperate, individual file.
This is not saved through a GlyphSet and any contents.plist in the
same directory will not be updated. If that's what you need use
DumpOneGlyphToUFO.py
"""
from robofab.glifLib import writeGlyphToString
from robofab.world import CurrentFont, CurrentGlyph
from robofab.interface.all.dialogs import PutFile
from robofab.tools.glyphNameSchemes import glyphNameToShortFileName
import os
f = CurrentFont()
g = CurrentGlyph()
if g is not None:
todo = [g.name]
else:
todo = f.selection
for c in todo:
g = f[c]
result = True
data = writeGlyphToString(g.name, g, g.drawPoints)
filename = glyphNameToShortFileName(g.name, None)
file = PutFile("Save this glif as:")
path = os.path.join(os.path.dirname(file), filename)
print "saving to", path
f = open(path, "w")
f.write(data)
f.close()
print 'done'

View File

@ -0,0 +1,44 @@
#FLM: Export Selected Glyph to UFO
"""Dump the selected glyph to a .glif as part of a UFO.
It saves the .glif through a GlyphSet and updates the contents.plist.
"""
from robofab.glifLib import GlyphSet
from robofab.world import CurrentFont, CurrentGlyph
from robofab.interface.all.dialogs import Message, GetFolder
from robofab.tools.glyphNameSchemes import glyphNameToShortFileName
import os
if os.name == "mac":
LOCAL_ENCODING = "macroman"
else:
LOCAL_ENCODING = "latin-1"
f = CurrentFont()
g = CurrentGlyph()
if g is not None:
todo = [g.name]
else:
todo = f.selection
for c in todo:
if f is None:
continue
g = f[c]
result = True
file = GetFolder("Select a UFO to save the GLIF in:")
if file.find(".ufo") == -1:
Message("You need to select an UFO. Quitting.")
else:
path = os.path.join(os.path.dirname(file), os.path.basename(file), "glyphs")
print "saving glyph %s in %s"%(g.name.encode(LOCAL_ENCODING), path)
gs = GlyphSet(path, glyphNameToFileNameFunc=glyphNameToShortFileName)
gs.writeGlyph(g.name, g, g.drawPoints)
gs.writeContents()
print 'done'

View File

@ -0,0 +1,19 @@
#FLM: Export Current Font to UFO Format
"""Export the current font to UFO format.
"""
from robofab.world import CurrentFont
f = CurrentFont()
if f.path is None:
from robofab.interface.all.dialogs import PutFile
path = PutFile("Please choose a name for the .ufo")
if path is None:
path = -1 # signal the code below the user has cancelled
else:
# writeUFO() will firgure out the destination .ufo path
path = None
if path != -1:
f.writeUFO(path, doProgress=True)
print 'DONE!'

View File

@ -0,0 +1,11 @@
#FLM: Import .ufo File into FontLab
from robofab.world import NewFont
from robofab.interface.all.dialogs import GetFolder
path = GetFolder("Please select a .ufo")
if path is not None:
font = NewFont()
font.readUFO(path, doProgress=True)
font.update()
print 'DONE!'

View File

@ -0,0 +1,32 @@
#FLM: Single Glyph from a UFO
"""Import one glyph from a .ufo,
i.e. a single .glif file.
"""
from robofab.world import CurrentFont
from robofab.objects.objectsRF import OpenFont
from robofab.interface.all.dialogs import SelectGlyph, Message
flFont = CurrentFont()
if flFont is None:
Message("Please have a FontLab destination font ready..")
else:
# pick a .ufo
rfFont = OpenFont()
if rfFont is not None:
# pick a glyph in the .ufo
rfGlyph = SelectGlyph(rfFont)
if rfGlyph is not None:
# make a new glyph in the FL font
flGlyph = flFont.newGlyph(rfGlyph.name, clear=True)
# draw the glyph into the FL font
pen = flGlyph.getPointPen()
rfGlyph.drawPoints(pen)
# set the width, unicodes and lib
flGlyph.width = rfGlyph.width
flGlyph.unicodes = rfGlyph.unicodes
flGlyph.lib = rfGlyph.lib
flGlyph.note = rfGlyph.note
flGlyph.update()
flFont.update()

View File

@ -0,0 +1,39 @@
#FLM: Import all UFOs in a folder
from robofab.world import NewFont
from robofab.interface.mac.getFileOrFolder import GetFileOrFolder
from robofab.interface.all.dialogs import GetFolder
import os
def globUFO(dir, filter=None):
"""Collect paths for all ufos in dir.
Check for nested dirs.
Optionally, select only ufos which match a filter string.
"""
ufo = []
names = os.listdir(dir)
for n in names:
p = os.path.join(dir, n)
if n[-4:] == ".ufo":
if filter is not None:
if dir.find(filter) <> -1:
ufo.append(p)
else:
ufo.append(p)
continue
if os.path.isdir(p):
ufo += globUFO(p, filter)
return ufo
dir = GetFolder()
ufo = globUFO(dir)
for path in ufo:
font = NewFont()
font.readUFO(path, doProgress=True)
font.update()
vfbPath = path[:-4] + ".vfb"
font.save(vfbPath)
print 'DONE!'

View File

@ -0,0 +1,12 @@
#FLM: SVG font generate
from robofab.world import CurrentFont
from robofab.tools.toolsSVG import makeSVGFont
import os
f = CurrentFont()
if f is not None:
path = os.path.splitext(f.path)[0]+".svg"
makeSVGFont(f, path, exportKerning=False)
print "done"

View File

@ -0,0 +1,15 @@
#FLM: SVG font import
from robofab.world import CurrentFont, NewFont
from robofab.tools.toolsSVG import SVGFontReader
from robofab.interface.all.dialogs import GetFile
import os
path = GetFile("Select SVG font file.")
if path is not None:
print path
font = NewFont()
reader = SVGFontReader(path, font)
print "done"

View File

@ -0,0 +1,20 @@
"""Use fonttools to open TrueType, Type 1 or OpenType, then write a UFO."""
from robofab.tools.toolsAll import fontToUFO, guessFileType
if len(sys.argv) not in (2, 3):
print "usage: FontToUfo.py <FontFile> [<output UFO file to create>]"
sys.exit(1)
src = sys.argv[1]
if len(sys.argv) == 3:
dst = sys.argv[2]
else:
base, ext = os.path.splitext(src)
dst = base + ".ufo"
fileType = guessFileType(src)
if fileType is None:
print "Can't determine input file type"
sys.exit(1)
print "Converting %s %r to %r" % (fileType, src, dst)
fontToUFO(src, dst)

View File

@ -0,0 +1,31 @@
#FLM: Make Kerning Proof of selection
"""Generate an InDesign 2.0 tagged text file
for every possible glyph combination in the current font."""
from robofab.tools.proof import IDTaggedText
from robofab.world import CurrentFont
f = CurrentFont()
fontSize = 36
id = IDTaggedText(f.info.familyName, f.info.styleName, size=fontSize)
names = f.selection
names.sort()
for l in names:
left = f[l]
for r in names:
right = f[r]
id.addGlyph(left.index)
id.addGlyph(right.index)
id.add(' ')
print 'finished all pairs starting with', left.name
from robofab.interface.all.dialogs import PutFile
path = PutFile("Save the tagged file:", "KerningProofTags.txt")
if path:
id.save(path)

View File

@ -0,0 +1,26 @@
"""Read all glyphs from the demo font, and write them out again.
This is useful for testing round-tripping stability, but also to
update the font when the GLIF format changes. The third application
is to update the contents.plist file in case glyphs have been added
or removed.
"""
import os
from robofab.test.testSupport import getDemoFontPath
from robofab.glifLib import GlyphSet
from robofab.pens.adapterPens import GuessSmoothPointPen
ufoPath = getDemoFontPath()
glyphSet = GlyphSet(os.path.join(ufoPath, "glyphs"))
glyphSet.rebuildContents() # ignore existing contents.plist, rebuild from dir listing
for name in glyphSet.keys():
g = glyphSet[name]
g.drawPoints(None) # force all attrs to be loaded
def drawPoints(pen):
pen = GuessSmoothPointPen(pen)
g.drawPoints(pen)
glyphSet.writeGlyph(name, g, drawPoints)
glyphSet.writeContents() # write out contents.plist

View File

@ -0,0 +1,49 @@
# a more robust batch generator that only has one font open at the time.
from robofab.interface.all.dialogs import GetFolder
from robofab.world import RFont, OpenFont
import os
def collectSources(root):
files = []
ext = ['.vfb']
names = os.listdir(root)
for n in names:
if os.path.splitext(n)[1] in ext:
files.append(os.path.join(root, n))
return files
# A little function for making folders. we'll need it later.
def makeFolder(path):
#if the path doesn't exist, make it!
if not os.path.exists(path):
os.makedirs(path)
def makeDestination(root):
macPath = os.path.join(root, 'FabFonts', 'ForMac')
makeFolder(macPath)
return macPath
def generateOne(f, dstDir):
print "generating %s"%f.info.fullName
f.generate('mactype1', dstDir)
f = GetFolder()
if f is not None:
paths = collectSources(f)
dstDir = makeDestination(f)
for f in paths:
font = None
try:
font = OpenFont(f)
generateOne(font, dstDir)
finally:
if font is not None:
font.close(False)
print 'done'

View File

@ -0,0 +1,15 @@
#FLM: Start FontLab remote
# On MacOS this will make FontLab accept apple events.
# It will assume the event contains a piece of executable
# python code and run it. The results of the python code
# are then returned in the reply.
#
# Check the code in robofab/tools/remote.py for more
# functionality. For instance, it contains several
# functions to send and receive glyphs from outside
# FontLab, offering a way to make your NoneLab Python
# scripts communicate with FontLab.
from robofab.tools.remote import *

View File

@ -0,0 +1,28 @@
from robofab.world import AllFonts
print "Compare all fonts in the AllFonts list with each other:"
af = AllFonts()
results = []
line = []
for n in af:
line.append(`n.info.fullName`)
results.append(line)
for i in range(len(af)):
one = af[i]
line = []
line.append(af[i].info.fullName)
for j in range(len(af)):
other = af[j]
line.append(`one==other`)
if one == other:
print "same: ", one.path, other.path
results.append(line)
for n in results:
print n