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:
parent
a80c6d2c8a
commit
617945dcf1
3
Scripts/ReadMe.txt
Normal file
3
Scripts/ReadMe.txt
Normal file
@ -0,0 +1,3 @@
|
||||
RoboFab Scripts
|
||||
|
||||
These are some folders with scripts that can be run in FontLab.
|
72
Scripts/RoboFabIntro/demo_AlignBPoints.py
Normal file
72
Scripts/RoboFabIntro/demo_AlignBPoints.py
Normal 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()
|
14
Scripts/RoboFabIntro/demo_CorrectDirection.py
Normal file
14
Scripts/RoboFabIntro/demo_CorrectDirection.py
Normal 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()
|
27
Scripts/RoboFabIntro/demo_FindCompatibleGlyphs.py
Normal file
27
Scripts/RoboFabIntro/demo_FindCompatibleGlyphs.py
Normal 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)
|
22
Scripts/RoboFabIntro/demo_GlyphAppender.py
Normal file
22
Scripts/RoboFabIntro/demo_GlyphAppender.py
Normal 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()
|
24
Scripts/RoboFabIntro/demo_GlyphMath.py
Normal file
24
Scripts/RoboFabIntro/demo_GlyphMath.py
Normal 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()
|
50
Scripts/RoboFabIntro/demo_InterpolPreview.py
Normal file
50
Scripts/RoboFabIntro/demo_InterpolPreview.py
Normal 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()
|
16
Scripts/RoboFabIntro/demo_InvertSelectedSegments.py
Normal file
16
Scripts/RoboFabIntro/demo_InvertSelectedSegments.py
Normal 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()
|
50
Scripts/RoboFabIntro/demo_MakeCameoFont.py
Normal file
50
Scripts/RoboFabIntro/demo_MakeCameoFont.py
Normal 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.')
|
12
Scripts/RoboFabIntro/demo_PrintKerningCounts.py
Normal file
12
Scripts/RoboFabIntro/demo_PrintKerningCounts.py
Normal 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])
|
29
Scripts/RoboFabIntro/demo_PrintMeasuments.py
Normal file
29
Scripts/RoboFabIntro/demo_PrintMeasuments.py
Normal 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)
|
14
Scripts/RoboFabIntro/demo_RoundKerning.py
Normal file
14
Scripts/RoboFabIntro/demo_RoundKerning.py
Normal 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)
|
31
Scripts/RoboFabIntro/demo_UFORemoveOverlap.py
Normal file
31
Scripts/RoboFabIntro/demo_UFORemoveOverlap.py
Normal 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)
|
32
Scripts/RoboFabIntro/intro_008.py
Normal file
32
Scripts/RoboFabIntro/intro_008.py
Normal 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()
|
||||
|
||||
|
60
Scripts/RoboFabIntro/intro_AccentBuilder.py
Normal file
60
Scripts/RoboFabIntro/intro_AccentBuilder.py
Normal 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!
|
||||
|
67
Scripts/RoboFabIntro/intro_ContoursSegmentsPoints.py
Normal file
67
Scripts/RoboFabIntro/intro_ContoursSegmentsPoints.py
Normal 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()
|
||||
|
94
Scripts/RoboFabIntro/intro_FontAndGlyphLib.py
Normal file
94
Scripts/RoboFabIntro/intro_FontAndGlyphLib.py
Normal 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.
|
43
Scripts/RoboFabIntro/intro_FontObject.py
Normal file
43
Scripts/RoboFabIntro/intro_FontObject.py
Normal 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
|
75
Scripts/RoboFabIntro/intro_FoundrySettings.py
Normal file
75
Scripts/RoboFabIntro/intro_FoundrySettings.py
Normal 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!
|
55
Scripts/RoboFabIntro/intro_GeneratingFonts.py
Normal file
55
Scripts/RoboFabIntro/intro_GeneratingFonts.py
Normal 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?
|
34
Scripts/RoboFabIntro/intro_GlyphObject.py
Normal file
34
Scripts/RoboFabIntro/intro_GlyphObject.py
Normal 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.
|
24
Scripts/RoboFabIntro/intro_GlyphProperties.py
Normal file
24
Scripts/RoboFabIntro/intro_GlyphProperties.py
Normal 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.
|
88
Scripts/RoboFabIntro/intro_Groups.py
Normal file
88
Scripts/RoboFabIntro/intro_Groups.py
Normal 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!
|
30
Scripts/RoboFabIntro/intro_InterpolateFonts.py
Normal file
30
Scripts/RoboFabIntro/intro_InterpolateFonts.py
Normal 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'
|
64
Scripts/RoboFabIntro/intro_Kerning.py
Normal file
64
Scripts/RoboFabIntro/intro_Kerning.py
Normal 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()
|
||||
|
48
Scripts/RoboFabIntro/intro_SimpleDrawing.py
Normal file
48
Scripts/RoboFabIntro/intro_SimpleDrawing.py
Normal 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.
|
24
Scripts/RoboFabIntro/intro_StartHere.py
Normal file
24
Scripts/RoboFabIntro/intro_StartHere.py
Normal 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.
|
36
Scripts/RoboFabUFO/DumpOneGlyphToGlif.py
Normal file
36
Scripts/RoboFabUFO/DumpOneGlyphToGlif.py
Normal 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'
|
44
Scripts/RoboFabUFO/DumpOneGlyphToUFO.py
Normal file
44
Scripts/RoboFabUFO/DumpOneGlyphToUFO.py
Normal 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'
|
19
Scripts/RoboFabUFO/ExportFontToUFO.py
Normal file
19
Scripts/RoboFabUFO/ExportFontToUFO.py
Normal 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!'
|
11
Scripts/RoboFabUFO/ImportFontFromUFO.py
Normal file
11
Scripts/RoboFabUFO/ImportFontFromUFO.py
Normal 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!'
|
32
Scripts/RoboFabUFO/ImportOneGlyphFromUFO.py
Normal file
32
Scripts/RoboFabUFO/ImportOneGlyphFromUFO.py
Normal 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()
|
39
Scripts/RoboFabUFO/ImportUFOBatch.py
Normal file
39
Scripts/RoboFabUFO/ImportUFOBatch.py
Normal 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!'
|
12
Scripts/RoboFabUFO/SVG_Generate.py
Normal file
12
Scripts/RoboFabUFO/SVG_Generate.py
Normal 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"
|
15
Scripts/RoboFabUFO/SVG_Import.py
Normal file
15
Scripts/RoboFabUFO/SVG_Import.py
Normal 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"
|
20
Scripts/RoboFabUtils/FontToUfo.py
Normal file
20
Scripts/RoboFabUtils/FontToUfo.py
Normal 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)
|
31
Scripts/RoboFabUtils/GenerateKernProof.py
Normal file
31
Scripts/RoboFabUtils/GenerateKernProof.py
Normal 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)
|
||||
|
26
Scripts/RoboFabUtils/RewriteDemoFont.py
Normal file
26
Scripts/RoboFabUtils/RewriteDemoFont.py
Normal 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
|
||||
|
49
Scripts/RoboFabUtils/RobustBatchGenerate.py
Normal file
49
Scripts/RoboFabUtils/RobustBatchGenerate.py
Normal 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'
|
15
Scripts/RoboFabUtils/Start_FL_Remote.py
Executable file
15
Scripts/RoboFabUtils/Start_FL_Remote.py
Executable 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 *
|
||||
|
28
Scripts/RoboFabUtils/TestFontEquality.py
Normal file
28
Scripts/RoboFabUtils/TestFontEquality.py
Normal 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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user