diff --git a/Scripts/ReadMe.txt b/Scripts/ReadMe.txt new file mode 100644 index 000000000..bb6b7a399 --- /dev/null +++ b/Scripts/ReadMe.txt @@ -0,0 +1,3 @@ +RoboFab Scripts + +These are some folders with scripts that can be run in FontLab. \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_AlignBPoints.py b/Scripts/RoboFabIntro/demo_AlignBPoints.py new file mode 100644 index 000000000..73420c519 --- /dev/null +++ b/Scripts/RoboFabIntro/demo_AlignBPoints.py @@ -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() diff --git a/Scripts/RoboFabIntro/demo_CorrectDirection.py b/Scripts/RoboFabIntro/demo_CorrectDirection.py new file mode 100644 index 000000000..5839fefa5 --- /dev/null +++ b/Scripts/RoboFabIntro/demo_CorrectDirection.py @@ -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() \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_FindCompatibleGlyphs.py b/Scripts/RoboFabIntro/demo_FindCompatibleGlyphs.py new file mode 100644 index 000000000..cb5cf63e1 --- /dev/null +++ b/Scripts/RoboFabIntro/demo_FindCompatibleGlyphs.py @@ -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) \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_GlyphAppender.py b/Scripts/RoboFabIntro/demo_GlyphAppender.py new file mode 100644 index 000000000..fb6e536d7 --- /dev/null +++ b/Scripts/RoboFabIntro/demo_GlyphAppender.py @@ -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() diff --git a/Scripts/RoboFabIntro/demo_GlyphMath.py b/Scripts/RoboFabIntro/demo_GlyphMath.py new file mode 100644 index 000000000..ac059530f --- /dev/null +++ b/Scripts/RoboFabIntro/demo_GlyphMath.py @@ -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() \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_InterpolPreview.py b/Scripts/RoboFabIntro/demo_InterpolPreview.py new file mode 100644 index 000000000..a92057ebd --- /dev/null +++ b/Scripts/RoboFabIntro/demo_InterpolPreview.py @@ -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() diff --git a/Scripts/RoboFabIntro/demo_InvertSelectedSegments.py b/Scripts/RoboFabIntro/demo_InvertSelectedSegments.py new file mode 100644 index 000000000..f66634740 --- /dev/null +++ b/Scripts/RoboFabIntro/demo_InvertSelectedSegments.py @@ -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() \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_MakeCameoFont.py b/Scripts/RoboFabIntro/demo_MakeCameoFont.py new file mode 100644 index 000000000..2dde4acfc --- /dev/null +++ b/Scripts/RoboFabIntro/demo_MakeCameoFont.py @@ -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.') \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_PrintKerningCounts.py b/Scripts/RoboFabIntro/demo_PrintKerningCounts.py new file mode 100644 index 000000000..367ff6c6e --- /dev/null +++ b/Scripts/RoboFabIntro/demo_PrintKerningCounts.py @@ -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]) \ No newline at end of file diff --git a/Scripts/RoboFabIntro/demo_PrintMeasuments.py b/Scripts/RoboFabIntro/demo_PrintMeasuments.py new file mode 100644 index 000000000..a4bbebaa9 --- /dev/null +++ b/Scripts/RoboFabIntro/demo_PrintMeasuments.py @@ -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) diff --git a/Scripts/RoboFabIntro/demo_RoundKerning.py b/Scripts/RoboFabIntro/demo_RoundKerning.py new file mode 100644 index 000000000..78868b69c --- /dev/null +++ b/Scripts/RoboFabIntro/demo_RoundKerning.py @@ -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) diff --git a/Scripts/RoboFabIntro/demo_UFORemoveOverlap.py b/Scripts/RoboFabIntro/demo_UFORemoveOverlap.py new file mode 100644 index 000000000..464cfe3dd --- /dev/null +++ b/Scripts/RoboFabIntro/demo_UFORemoveOverlap.py @@ -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) diff --git a/Scripts/RoboFabIntro/intro_008.py b/Scripts/RoboFabIntro/intro_008.py new file mode 100644 index 000000000..f1c4cb579 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_008.py @@ -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() + + diff --git a/Scripts/RoboFabIntro/intro_AccentBuilder.py b/Scripts/RoboFabIntro/intro_AccentBuilder.py new file mode 100644 index 000000000..8f66f2d1f --- /dev/null +++ b/Scripts/RoboFabIntro/intro_AccentBuilder.py @@ -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! + diff --git a/Scripts/RoboFabIntro/intro_ContoursSegmentsPoints.py b/Scripts/RoboFabIntro/intro_ContoursSegmentsPoints.py new file mode 100644 index 000000000..463288649 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_ContoursSegmentsPoints.py @@ -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() + diff --git a/Scripts/RoboFabIntro/intro_FontAndGlyphLib.py b/Scripts/RoboFabIntro/intro_FontAndGlyphLib.py new file mode 100644 index 000000000..fa433bd04 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_FontAndGlyphLib.py @@ -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. diff --git a/Scripts/RoboFabIntro/intro_FontObject.py b/Scripts/RoboFabIntro/intro_FontObject.py new file mode 100644 index 000000000..5db7d0baa --- /dev/null +++ b/Scripts/RoboFabIntro/intro_FontObject.py @@ -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 diff --git a/Scripts/RoboFabIntro/intro_FoundrySettings.py b/Scripts/RoboFabIntro/intro_FoundrySettings.py new file mode 100644 index 000000000..469f22f84 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_FoundrySettings.py @@ -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! diff --git a/Scripts/RoboFabIntro/intro_GeneratingFonts.py b/Scripts/RoboFabIntro/intro_GeneratingFonts.py new file mode 100644 index 000000000..5722d831c --- /dev/null +++ b/Scripts/RoboFabIntro/intro_GeneratingFonts.py @@ -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? diff --git a/Scripts/RoboFabIntro/intro_GlyphObject.py b/Scripts/RoboFabIntro/intro_GlyphObject.py new file mode 100644 index 000000000..b8512fecf --- /dev/null +++ b/Scripts/RoboFabIntro/intro_GlyphObject.py @@ -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. \ No newline at end of file diff --git a/Scripts/RoboFabIntro/intro_GlyphProperties.py b/Scripts/RoboFabIntro/intro_GlyphProperties.py new file mode 100644 index 000000000..4772f0e35 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_GlyphProperties.py @@ -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. diff --git a/Scripts/RoboFabIntro/intro_Groups.py b/Scripts/RoboFabIntro/intro_Groups.py new file mode 100644 index 000000000..3a9877d48 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_Groups.py @@ -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! diff --git a/Scripts/RoboFabIntro/intro_InterpolateFonts.py b/Scripts/RoboFabIntro/intro_InterpolateFonts.py new file mode 100644 index 000000000..a6500b51b --- /dev/null +++ b/Scripts/RoboFabIntro/intro_InterpolateFonts.py @@ -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' \ No newline at end of file diff --git a/Scripts/RoboFabIntro/intro_Kerning.py b/Scripts/RoboFabIntro/intro_Kerning.py new file mode 100644 index 000000000..328fbb5d8 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_Kerning.py @@ -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() + diff --git a/Scripts/RoboFabIntro/intro_SimpleDrawing.py b/Scripts/RoboFabIntro/intro_SimpleDrawing.py new file mode 100644 index 000000000..8d042bf38 --- /dev/null +++ b/Scripts/RoboFabIntro/intro_SimpleDrawing.py @@ -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. diff --git a/Scripts/RoboFabIntro/intro_StartHere.py b/Scripts/RoboFabIntro/intro_StartHere.py new file mode 100644 index 000000000..ac0e2ff9d --- /dev/null +++ b/Scripts/RoboFabIntro/intro_StartHere.py @@ -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. diff --git a/Scripts/RoboFabUFO/DumpOneGlyphToGlif.py b/Scripts/RoboFabUFO/DumpOneGlyphToGlif.py new file mode 100644 index 000000000..e12021049 --- /dev/null +++ b/Scripts/RoboFabUFO/DumpOneGlyphToGlif.py @@ -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' \ No newline at end of file diff --git a/Scripts/RoboFabUFO/DumpOneGlyphToUFO.py b/Scripts/RoboFabUFO/DumpOneGlyphToUFO.py new file mode 100644 index 000000000..cfeb07d28 --- /dev/null +++ b/Scripts/RoboFabUFO/DumpOneGlyphToUFO.py @@ -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' \ No newline at end of file diff --git a/Scripts/RoboFabUFO/ExportFontToUFO.py b/Scripts/RoboFabUFO/ExportFontToUFO.py new file mode 100644 index 000000000..f6d410bc2 --- /dev/null +++ b/Scripts/RoboFabUFO/ExportFontToUFO.py @@ -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!' diff --git a/Scripts/RoboFabUFO/ImportFontFromUFO.py b/Scripts/RoboFabUFO/ImportFontFromUFO.py new file mode 100644 index 000000000..ec7d8fa6a --- /dev/null +++ b/Scripts/RoboFabUFO/ImportFontFromUFO.py @@ -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!' diff --git a/Scripts/RoboFabUFO/ImportOneGlyphFromUFO.py b/Scripts/RoboFabUFO/ImportOneGlyphFromUFO.py new file mode 100644 index 000000000..3b3c8033e --- /dev/null +++ b/Scripts/RoboFabUFO/ImportOneGlyphFromUFO.py @@ -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() diff --git a/Scripts/RoboFabUFO/ImportUFOBatch.py b/Scripts/RoboFabUFO/ImportUFOBatch.py new file mode 100644 index 000000000..576d1ae62 --- /dev/null +++ b/Scripts/RoboFabUFO/ImportUFOBatch.py @@ -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!' diff --git a/Scripts/RoboFabUFO/SVG_Generate.py b/Scripts/RoboFabUFO/SVG_Generate.py new file mode 100644 index 000000000..63e82cb1d --- /dev/null +++ b/Scripts/RoboFabUFO/SVG_Generate.py @@ -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" \ No newline at end of file diff --git a/Scripts/RoboFabUFO/SVG_Import.py b/Scripts/RoboFabUFO/SVG_Import.py new file mode 100644 index 000000000..d45659e5a --- /dev/null +++ b/Scripts/RoboFabUFO/SVG_Import.py @@ -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" \ No newline at end of file diff --git a/Scripts/RoboFabUtils/FontToUfo.py b/Scripts/RoboFabUtils/FontToUfo.py new file mode 100644 index 000000000..dd28b6969 --- /dev/null +++ b/Scripts/RoboFabUtils/FontToUfo.py @@ -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 []" + 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) diff --git a/Scripts/RoboFabUtils/GenerateKernProof.py b/Scripts/RoboFabUtils/GenerateKernProof.py new file mode 100644 index 000000000..6275e712d --- /dev/null +++ b/Scripts/RoboFabUtils/GenerateKernProof.py @@ -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) + diff --git a/Scripts/RoboFabUtils/RewriteDemoFont.py b/Scripts/RoboFabUtils/RewriteDemoFont.py new file mode 100644 index 000000000..feb49fec3 --- /dev/null +++ b/Scripts/RoboFabUtils/RewriteDemoFont.py @@ -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 + diff --git a/Scripts/RoboFabUtils/RobustBatchGenerate.py b/Scripts/RoboFabUtils/RobustBatchGenerate.py new file mode 100644 index 000000000..ac8c1ae66 --- /dev/null +++ b/Scripts/RoboFabUtils/RobustBatchGenerate.py @@ -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' \ No newline at end of file diff --git a/Scripts/RoboFabUtils/Start_FL_Remote.py b/Scripts/RoboFabUtils/Start_FL_Remote.py new file mode 100755 index 000000000..e1f6822ec --- /dev/null +++ b/Scripts/RoboFabUtils/Start_FL_Remote.py @@ -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 * + diff --git a/Scripts/RoboFabUtils/TestFontEquality.py b/Scripts/RoboFabUtils/TestFontEquality.py new file mode 100644 index 000000000..6aeb30493 --- /dev/null +++ b/Scripts/RoboFabUtils/TestFontEquality.py @@ -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 + + \ No newline at end of file