`_
26 | - `The Mac OSX section on Python.org `_
27 |
--------------------------------------------------------------------------------
/Docs/Examples/talks/session6_08.py:
--------------------------------------------------------------------------------
1 | # robothon 2006
2 | # merge two fonts
3 |
4 | from robofab.world import SelectFont, NewFont
5 | from robofab.pens.digestPen import DigestPointPen
6 | from sets import Set
7 |
8 | font1 = SelectFont("Select base font")
9 | font2 = SelectFont("Select alternate font")
10 |
11 | font1Names = Set(font1.keys())
12 | font2Names = Set(font2.keys())
13 |
14 | commonNames = font1Names & font2Names
15 | uncommonNames = font2Names - font1Names
16 |
17 | for glyphName in commonNames:
18 | glyph1 = font1[glyphName]
19 | pointPen = DigestPointPen()
20 | glyph1.drawPoints(pointPen)
21 | digest1 = pointPen.getDigest()
22 |
23 | glyph2 = font2[glyphName]
24 | pointPen = DigestPointPen()
25 | glyph2.drawPoints(pointPen)
26 | digest2 = pointPen.getDigest()
27 |
28 | if digest1 != digest2:
29 | print '> alt >', glyphName
30 | glyph3 = font1.insertGlyph(glyph2, name=glyphName+'.alt')
31 | glyph3.mark = 1
32 | glyph3.update()
33 |
34 | for glyphName in uncommonNames:
35 | print '>', glyphName
36 | glyph = font1.insertGlyph(font2[glyphName])
37 | glyph.mark = 60
38 | glyph.update()
39 |
40 | font1.update()
--------------------------------------------------------------------------------
/Scripts/RoboFabUtils/RobustBatchGenerate.py:
--------------------------------------------------------------------------------
1 | # a more robust batch generator that only has one font open at the time.
2 |
3 | from robofab.interface.all.dialogs import GetFolder
4 | from robofab.world import RFont, OpenFont
5 | import os
6 |
7 | def collectSources(root):
8 | files = []
9 | ext = ['.vfb']
10 | names = os.listdir(root)
11 | for n in names:
12 | if os.path.splitext(n)[1] in ext:
13 | files.append(os.path.join(root, n))
14 | return files
15 |
16 | # A little function for making folders. we'll need it later.
17 | def makeFolder(path):
18 | #if the path doesn't exist, make it!
19 | if not os.path.exists(path):
20 | os.makedirs(path)
21 |
22 | def makeDestination(root):
23 | macPath = os.path.join(root, 'FabFonts', 'ForMac')
24 | makeFolder(macPath)
25 | return macPath
26 |
27 | def generateOne(f, dstDir):
28 | print "generating %s"%f.info.postscriptFullName
29 | f.generate('mactype1', dstDir)
30 |
31 |
32 | f = GetFolder()
33 |
34 | if f is not None:
35 | paths = collectSources(f)
36 | dstDir = makeDestination(f)
37 |
38 | for f in paths:
39 | font = None
40 | try:
41 | font = OpenFont(f)
42 | generateOne(font, dstDir)
43 |
44 | finally:
45 | if font is not None:
46 | font.close(False)
47 |
48 |
49 | print 'done'
--------------------------------------------------------------------------------
/Lib/robofab/plistFromTree.py:
--------------------------------------------------------------------------------
1 | """Small helper module to parse Plist-formatted data from trees as created
2 | by xmlTreeBuilder.
3 | """
4 |
5 |
6 | __all__ = "readPlistFromTree"
7 |
8 |
9 | from plistlib import PlistParser
10 |
11 |
12 | def readPlistFromTree(tree):
13 | """Given a (sub)tree created by xmlTreeBuilder, interpret it
14 | as Plist-formatted data, and return the root object.
15 | """
16 | parser = PlistTreeParser()
17 | return parser.parseTree(tree)
18 |
19 |
20 | class PlistTreeParser(PlistParser):
21 |
22 | def parseTree(self, tree):
23 | element, attributes, children = tree
24 | self.parseElement(element, attributes, children)
25 | return self.root
26 |
27 | def parseElement(self, element, attributes, children):
28 | self.handleBeginElement(element, attributes)
29 | for child in children:
30 | if isinstance(child, tuple):
31 | self.parseElement(child[0], child[1], child[2])
32 | else:
33 | if not isinstance(child, unicode):
34 | # ugh, xmlTreeBuilder returns utf-8 :-(
35 | child = unicode(child, "utf-8")
36 | self.handleData(child)
37 | self.handleEndElement(element)
38 |
39 |
40 | if __name__ == "__main__":
41 | from xmlTreeBuilder import buildTree
42 | tree = buildTree("xxx.plist", stripData=0)
43 | print readPlistFromTree(tree)
44 |
--------------------------------------------------------------------------------
/Docs/Examples/talks/interpol_08.py:
--------------------------------------------------------------------------------
1 | # robothon06
2 | # interpolate two fonts with a series of factors.
3 | # for each factor create a new font file.
4 |
5 | import os
6 | from robofab.world import SelectFont, NewFont
7 | from robofab.interface.all.dialogs import AskString, GetFolder
8 |
9 | font1 = SelectFont("Select font 1")
10 | font2 = SelectFont("Select font 2")
11 | where = GetFolder("Select a folder to save the interpolations")
12 |
13 | instances = [
14 | ("Light", 0),
15 | ("NotTooLight", 0.25),
16 | ("Regular", 0.5),
17 | ("Demi", 0.75),
18 | ("Medium", 1),
19 | ]
20 |
21 | for thing in instances:
22 | name, value = thing
23 | print "generating", name, value
24 | dst = NewFont()
25 | # this interpolates the glyphs
26 | dst.interpolate(value, font1, font2, doProgress=True)
27 | # this interpolates the kerning
28 | # comment this line out of you're just testing
29 | #dst.kerning.interpolate(font1.kerning, font2.kerning, value)
30 | dst.info.familyName = "MyBigFamily"
31 | dst.info.styleName = name
32 | dst.info.autoNaming()
33 | dst.update()
34 | fileName = dst.info.familyName + "-" + dst.info.styleName + ".vfb"
35 | path = os.path.join(where, fileName)
36 | print 'saving at', path
37 | dst.save(path)
38 | dst.close()
39 |
--------------------------------------------------------------------------------
/Data/DemoFont.ufo/glyphs/R_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Tools/installFontLab/installerScript.py:
--------------------------------------------------------------------------------
1 | # This is a automatically generated installer script for FontLab
2 | # Generated on %(timeStamp)s
3 | # scriptVersion: %(scriptVersion)s
4 |
5 | p = "%(appLogPath)s"
6 | log(p,"-" * 50)
7 | log(p,"hello, this is application: %(appName)s")
8 | log(p,"Running script version: %(scriptVersion)s")
9 | log(p,"Platform:"+platform.platform())
10 | resultData = []
11 | resultData.append("application:\t%(appName)s")
12 | print "I will log to", "%(appLogPath)s"
13 | print "I will save my results to", "%(resultsPath)s"
14 | print "I will test for these modules:", "%(moduleData)s"
15 | from FL import *
16 | log(p,"FontLab version "+fl.version)
17 | resultData.append("version:\t"+fl.version)
18 |
19 | installedAlready = False
20 |
21 | for moduleName, data in %(moduleData)s.items():
22 | print "---", moduleName, data
23 | try:
24 | print "---", __import__(moduleName, globals(), locals(), [], -1)
25 | resultData.append("found:\t"+moduleName)
26 | except ImportError:
27 | resultData.append("mustLoad:\t"+moduleName)
28 |
29 | sitePackagesCandidates = findSitePackages()
30 | for candidate in findSitePackages():
31 | resultData.append("path:\t"+candidate)
32 | log(p,"site-packages found at: "+candidate)
33 |
34 | f = open("%(resultsPath)s", 'wb')
35 | f.write("\n".join(resultData))
36 | f.close()
37 | log(p,'done!')
--------------------------------------------------------------------------------
/Docs/Examples/talks/session6_07.py:
--------------------------------------------------------------------------------
1 | # robothon 2006
2 | # a more robust batch generator that only has one font open at the time.
3 |
4 | from robofab.interface.all.dialogs import GetFolder
5 | from robofab.world import RFont, OpenFont
6 | import os
7 |
8 | def collectSources(root):
9 | files = []
10 | ext = ['.vfb']
11 | names = os.listdir(root)
12 | for n in names:
13 | if os.path.splitext(n)[1] in ext:
14 | files.append(os.path.join(root, n))
15 | return files
16 |
17 | # A little function for making folders. we'll need it later.
18 | def makeFolder(path):
19 | # if the path doesn't exist, make it!
20 | if not os.path.exists(path):
21 | os.makedirs(path)
22 |
23 | def makeDestination(root):
24 | macPath = os.path.join(root, 'FabFonts', 'ForMac')
25 | makeFolder(macPath)
26 | return macPath
27 |
28 | def generateOne(f, dstDir):
29 | print "generating %s"%f.info.fullName
30 | f.generate('otfcff', dstDir)
31 |
32 | f = GetFolder()
33 |
34 | if f is not None:
35 | paths = collectSources(f)
36 | dstDir = makeDestination(f)
37 | for f in paths:
38 | font = None
39 | print f
40 | try:
41 | font = OpenFont(f)
42 | generateOne(font, dstDir)
43 | finally:
44 | if font is not None:
45 | font.close(False)
46 | print 'done'
47 |
--------------------------------------------------------------------------------
/Scripts/RoboFabUFO/SelectedGlyphsToUFO.py:
--------------------------------------------------------------------------------
1 | #FLM: Export selected glyphs to UFO
2 |
3 |
4 | """
5 | Dump the selected glyph to a .glif as part of a UFO.
6 | It saves the .glif through a GlyphSet and updates the contents.plist.
7 |
8 | EvB 08
9 | """
10 |
11 |
12 | from robofab.glifLib import GlyphSet
13 | from robofab.world import CurrentFont, CurrentGlyph
14 | from robofab.interface.all.dialogs import Message, GetFileOrFolder
15 | from robofab.tools.glyphNameSchemes import glyphNameToShortFileName
16 | import os
17 |
18 | f = CurrentFont()
19 | g = CurrentGlyph()
20 |
21 | f.save()
22 |
23 | ufoPath = None
24 | ufoPath = f.path.replace(".vfb", ".ufo")
25 | if not os.path.exists(ufoPath):
26 | ufoPath = GetFileOrFolder("Select a UFO to save the GLIF in:")
27 | if ufoPath.find(".ufo") == -1:
28 | Message("You need to select an UFO. Quitting.")
29 | ufoPath = None
30 |
31 | if ufoPath is not None:
32 | todo = f.selection
33 | print "selection", todo
34 | if g is not None:
35 | todo.append(g.name)
36 | for c in todo:
37 | g = f[c]
38 | path = os.path.join(os.path.dirname(ufoPath), os.path.basename(ufoPath), "glyphs")
39 | print "saving glyph %s in %s"%(g.name, path)
40 | gs = GlyphSet(path, glyphNameToFileNameFunc=glyphNameToShortFileName)
41 | gs.writeGlyph(g.name, g, g.drawPoints)
42 | gs.writeContents()
43 |
44 | print 'done'
--------------------------------------------------------------------------------
/Data/DemoFont.ufo/glyphs/A_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Docs/Examples/talks/session2_09.py:
--------------------------------------------------------------------------------
1 | # robothon06
2 | # rasterise the shape in glyph "A"
3 | # and draw boxes in a new glyph named "A.silly"
4 |
5 | from robofab.world import CurrentFont, CurrentGlyph
6 |
7 | sourceGlyph = "a"
8 |
9 | f = CurrentFont()
10 | source = f[sourceGlyph]
11 |
12 | # find out how big the shape is from the glyph.box attribute
13 | xMin, yMin, xMax, yMax = source.box
14 |
15 | # create a new glyph
16 | dest = f.newGlyph(sourceGlyph+".silly")
17 | dest.width = source.width
18 |
19 | # get a pen to draw in the new glyph
20 | myPen = dest.getPen()
21 |
22 | # a function which draws a rectangle at a specified place
23 | def drawRect(pen, x, y, size=50):
24 | pen.moveTo((x-.5*size, y-.5*size))
25 | pen.lineTo((x+.5*size, y-.5*size))
26 | pen.lineTo((x+.5*size, y+.5*size))
27 | pen.lineTo((x-.5*size, y+.5*size))
28 | pen.closePath()
29 |
30 | # the size of the raster unit
31 | resolution = 30
32 |
33 | # draw from top to bottom
34 | yValues = range(yMin, yMax, resolution)
35 | yValues.reverse()
36 |
37 | # go for it!
38 | for y in yValues:
39 | for x in range(xMin, xMax, resolution):
40 | # check the source glyph is white or black at x,y
41 | if source.pointInside((x, y)):
42 | drawRect(myPen, x, y, resolution-5)
43 | # update for each line if you like the animation
44 | # otherwise move the update() out of the loop
45 | dest.update()
46 |
--------------------------------------------------------------------------------
/Scripts/RoboFabIntro/intro_SimpleDrawing.py:
--------------------------------------------------------------------------------
1 | #FLM: RoboFab Intro, Simple Drawing
2 |
3 | #
4 | #
5 | # demo of drawing with RoboFab
6 | #
7 | #
8 |
9 | import robofab
10 | from robofab.world import CurrentFont, CurrentGlyph
11 |
12 | # (make sure you have a font opened in FontLab)
13 |
14 |
15 |
16 | f = CurrentFont()
17 | if f == None:
18 | Message("You should open a font first, there's nothing to look at now!")
19 | else:
20 | newGlyph = f.newGlyph('demoDrawGlyph', clear=True)
21 | newGlyph.width = 1000
22 |
23 | # The drawing is done through a specialised pen object.
24 | # There are pen objects for different purposes, this one
25 | # will draw in a FontLab glyph. The point of this is that
26 | # Robofab glyphs all respond to the standard set of
27 | # pen methods, and it is a simple way to re-interpret the
28 | # glyph data.
29 |
30 | # Make a new pen with the new glyph we just made
31 | pen = newGlyph.getPen()
32 |
33 | # Tell the pen to draw things
34 | pen.moveTo((100, 100))
35 | pen.lineTo((800, 100))
36 | pen.curveTo((1000, 300), (1000, 600), (800, 800))
37 | pen.lineTo((100, 800))
38 | pen.lineTo((100, 100))
39 |
40 | # Done drawing: close the path
41 | pen.closePath()
42 |
43 | # Robofab objects still need to tell FontLab to update.
44 | newGlyph.update()
45 | f.update()
46 |
47 | # go check the font, it should now contain a new glyph named
48 | # "demoDrawGlyph" and it should look like a square.
49 |
--------------------------------------------------------------------------------
/Docs/Examples/howtos/fontlabRemote_03.py:
--------------------------------------------------------------------------------
1 | # robofab manual
2 | # Fontlabremote howto
3 | # usage examples
4 |
5 | #FLM: Remove overlap from Remote Glyph.
6 |
7 | from robofab.world import OpenFont
8 | from robofab.tools.remote import transmitGlyph, receiveGlyph, runFontLabRemote
9 |
10 | # Pick a UFO font:
11 | f = OpenFont()
12 |
13 | print "Number of contours before", len(f['A'])
14 |
15 | # call FontLab to make a new font
16 | startNewFontCode = """from robofab.world import NewFont
17 | f = NewFont()
18 | f.info.fullName = 'Temporary Font generated by RoboFab Remote'"""
19 |
20 | print runFontLabRemote(startNewFontCode)
21 |
22 | # send a glyph to FontLab,
23 | # it will be inserted in the CurrentFont.
24 | transmitGlyph(f['A'])
25 | f.removeGlyph('A')
26 |
27 | # send instructions to remove overlap for this glyph
28 | overlapCode = """from robofab.world import CurrentFont
29 | from robofab.tools.remote import transmitGlyph
30 | f = CurrentFont()
31 | f["A"].removeOverlap()
32 | f.update()
33 | transmitGlyph(f['A'])
34 | """
35 |
36 | # send the code and catch the output
37 | x = runFontLabRemote(overlapCode)
38 | # interpret the output
39 | receiveGlyph(x, f)
40 | print "Number of contours after: ", len(f['A'])
41 |
42 | # send instructions to FontLab to close the font again.
43 | closeFontCode = """from robofab.world import CurrentFont
44 | f = CurrentFont()
45 | f.close(None)
46 | """
47 | print runFontLabRemote(closeFontCode)
48 | print 'done!'
49 |
--------------------------------------------------------------------------------
/Data/DemoFont.ufo/glyphs/O_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | RoboFab
2 | =======
3 | RoboFab is a Python library with objects that deal with data usually associated with fonts and type design. RoboFab has support for the [UFO font format](http://unifiedfontobject.org).
4 |
5 | This library has been replaced with [fontParts](https://github.com/robofab-developers/fontParts).
6 |
7 | No further development is planned for RoboFab.
8 |
9 | ###Documentation
10 |
11 | Documentation for RoboFab lives at [RoboDocs](http://www.robodocs.info/roboFabDocs/source/index.html)
12 |
13 | Some how-to and older documentation can be found at [RoboFab.com](http://robofab.com)
14 |
15 | ###The Developers
16 |
17 | RoboFab is developed and maintained by Tal Leming, Erik van Blokland, Just van Rossum (in no particular order)
18 |
19 | ###Contact
20 |
21 | Email the RoboFab Consortium at
22 | i n f o (at) r o b o f a b (dot) o r g
23 |
24 | ###Copyrights
25 |
26 | This package is distributed under the BSD license. See the [license](LICENSE.txt). RoboFab is built in [Python](http://www.python.org). Parts of RoboFab use [fontTools](http://sourceforge.net/projects/fonttools/), an OpenSource font toolkit by Just van Rossum. Parts of the RoboFab library are built to work with code from [FontLab](http://www.fontlab.com), which is a product of Pyrus Inc. Parts of RoboFab implement the Property List file format in XML, copyright [Apple Computer](http://www.apple.com). Parts of RoboFab implement tables and names from PostScript and the OpenType FDK, copyright [Adobe](http://www.adobe.com).
27 |
--------------------------------------------------------------------------------
/Lib/robofab/tools/glyphNameSchemes.py:
--------------------------------------------------------------------------------
1 | """A separate module for glyphname to filename functions.
2 |
3 | glyphNameToShortFileName() generates a non-clashing filename for systems with
4 | filename-length limitations.
5 | """
6 |
7 | MAXLEN = 31
8 |
9 | def glyphNameToShortFileName(glyphName, glyphSet):
10 | """Alternative glyphname to filename function.
11 |
12 | Features a garuanteed maximum filename for really long glyphnames, and clash testing.
13 | - all non-ascii characters are converted to "_" (underscore), including "."
14 | - all glyphnames which are too long are truncated and a hash is added at the end
15 | - the hash is generated from the whole glyphname
16 | - finally, the candidate glyphname is checked against the contents.plist
17 | and a incrementing number is added at the end if there is a clash.
18 | """
19 | import binascii, struct, string
20 | ext = ".glif"
21 | ok = string.ascii_letters + string.digits + " _"
22 | h = binascii.hexlify(struct.pack(">l", binascii.crc32(glyphName)))
23 | n = ''
24 | for c in glyphName:
25 | if c in ok:
26 | if c != c.lower():
27 | n += c + "_"
28 | else:
29 | n += c
30 | else:
31 | n += "_"
32 | if len(n + ext) < MAXLEN:
33 | return n + ext
34 | count = 0
35 | candidate = n[:MAXLEN - len(h + ext)] + h + ext
36 | if glyphSet is not None:
37 | names = glyphSet.getReverseContents()
38 | while candidate.lower() in names:
39 | candidate = n[:MAXLEN - len(h + ext + str(count))] + h + str(count) + ext
40 | count += 1
41 | return candidate
42 |
--------------------------------------------------------------------------------
/Tools/autoDistroBuilder.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | if len(sys.argv) == 2:
4 | # we're called as a shellscript
5 | # assume the path is the second argument
6 | testBuildFolder = sys.argv[1]
7 | else:
8 | testBuildFolder = "/Users/erik/Develop/svn.robofab.com/randomOtherDifferentDirectory"
9 |
10 |
11 | """
12 |
13 | Build a robofab distro from SVN
14 | Store it in a new directory not in the robofab tree
15 | Write an html page.
16 |
17 | """
18 |
19 | from buildRoboFabDistroFromSVN import buildProducts, buildDownloadPage
20 |
21 | robofabProducts = {
22 | 'RoboFab_%s_plusAllDependencies':[
23 | ("http://svn.robofab.com/trunk", "RoboFab"),
24 | ("http://svn.typesupply.com/packages/vanilla/trunk", "Vanilla"),
25 | ("http://svn.typesupply.com/packages/dialogKit/trunk", "DialogKit"),
26 | ("https://fonttools.svn.sourceforge.net/svnroot/fonttools/trunk/", "FontTools")
27 | ],
28 | 'RoboFab_%s_plusFontTools':[
29 | ("http://svn.robofab.com/trunk", "RoboFab"),
30 | ("https://fonttools.svn.sourceforge.net/svnroot/fonttools/trunk/", "FontTools")
31 | ],
32 | 'RoboFab_%s_only':[
33 | ("http://svn.robofab.com/trunk", "RoboFab"),
34 | ],
35 | }
36 |
37 | filenames, revision = buildProducts(robofabProducts, buildFolder=testBuildFolder, deleteBuilds=True, verbose=False)
38 |
39 | #print "writing html"
40 | buildDownloadPage(testBuildFolder, new=filenames, changeSet=revision)
41 |
42 | #print "filenames", filenames
43 | #print "done"
--------------------------------------------------------------------------------
/Docs/Examples/talks/session6_04.py:
--------------------------------------------------------------------------------
1 | # robothon06
2 | # ask for a folder
3 | # find (nested) fontlab files in the folder
4 | # open the fonts
5 | # Demonstrates: recursive function,, dialog, os module
6 |
7 | import os.path
8 | from robofab.interface.all.dialogs import GetFolder
9 | from robofab.world import OpenFont
10 |
11 | # this function looks for fontlab files in a folder
12 | def walk(someFolder, extension):
13 | extension = extension.lower()
14 | files = []
15 | # the os module has tools to deal with
16 | # the operating system. This returns a list of names
17 | # of stuff in the folder you feed it:
18 | names = os.listdir(someFolder)
19 | for n in names:
20 | p = os.path.join(someFolder, n)
21 | # if this new thing is a folder itself,
22 | # call this function again, but now with the
23 | # new path to check that as well. This is
24 | # called recursion.
25 | if os.path.isdir(p):
26 | # add the results of the other folder
27 | # to the list
28 | files += walk(p, extension)
29 | continue
30 | # is it a file with the extension we want?
31 | # add it then!
32 | if n.lower().find(extension) <> -1:
33 | files.append(p)
34 | return files
35 |
36 | yourFolder = GetFolder("Search a folder:")
37 | if yourFolder is not None:
38 | fontPaths = walk(yourFolder, ".vfb")
39 | for path in fontPaths:
40 | OpenFont(path)
41 |
--------------------------------------------------------------------------------
/Docs/Examples/howtos/buildingAccents_02.py:
--------------------------------------------------------------------------------
1 | # robofab manual
2 | # Buildingaccents howto
3 | # attribute examples
4 |
5 | # a script to generate all necessary accented characters.
6 | # this assumes all anchor points are set correctly.
7 | # including doublelayer accents. so, add anchorpoints
8 | # on the accents too!
9 | # (c) evb
10 |
11 | from robofab.world import CurrentFont
12 | from robofab.tools.toolsAll import readGlyphConstructions
13 |
14 | f = CurrentFont()
15 |
16 | import string
17 |
18 | theList = [
19 | # caps
20 | 'AEacute',
21 | 'AEmacron',
22 | 'Aacute',
23 | 'Abreve',
24 | # add all the accents you want in this list
25 | ]
26 |
27 | con = readGlyphConstructions()
28 | theList.sort()
29 |
30 | def accentify(f, preflight=False):
31 | print 'start accentification', f.info.fullName
32 | slots = con.keys()
33 | slots.sort()
34 | for k in theList:
35 | if k[-3:] in [".sc"]:
36 | isSpecial = True
37 | tag = k[-3:]
38 | name = k[:-3]
39 | else:
40 | isSpecial = False
41 | tag = ""
42 | name = k
43 | parts = con.get(name, None)
44 | if parts is None:
45 | print k, "not defined?"
46 | continue
47 | base = parts[0]
48 | accents = parts[1:]
49 | f.generateGlyph(k, preflight=preflight)
50 | f[k].mark = 100 + randint(-20, 20)
51 | f[k].autoUnicodes()
52 | f[k].update()
53 | f.update()
54 |
55 | accentify(f)
56 | print 'done'
57 |
--------------------------------------------------------------------------------
/Scripts/RoboFabIntro/intro_FontObject.py:
--------------------------------------------------------------------------------
1 | #FLM: RoboFab Intro, The Font Object
2 |
3 | #
4 | #
5 | # demo of the RoboFab font object
6 | #
7 | #
8 |
9 | import robofab
10 |
11 | # Let's talk to some of the font objects.
12 | # CurrentFont and CurrentGlyph are similar to
13 | # the RoboFog functions. They return a font
14 | # or Glyph object respectively. It will be the
15 | # front most font or the front most glyph.
16 | from robofab.world import CurrentFont, CurrentGlyph
17 |
18 | # This is a brief intro into Robofabs all singing and
19 | # dancing dialog class. It will produce simple
20 | # dialogs in almost any environment, FontLab, Python IDE, W.
21 | from robofab.interface.all.dialogs import Message
22 |
23 | # (make sure you have a font opened in FontLab)
24 |
25 | f = CurrentFont()
26 | # so now f is the name of a font object for the current font.
27 |
28 | if f == None:
29 | # let's see what dialog can do, a warning
30 | Message("You should open a font first, there's nothing to look at now!")
31 | else:
32 | # and another dialog.
33 | Message("The current font is %s"%(f.info.postscriptFullName))
34 |
35 | # let's have a look at some of the attributes a RoboFab Font object has
36 | print "the number of glyphs:", len(f)
37 |
38 | # some of the attributes map straight to the FontLab Font class
39 | # We just straightened the camelCase here and there
40 | print "full name of this font:", f.info.postscriptFullName
41 | print "list of glyph names:", f.keys()
42 | print 'ascender:', f.info.ascender
43 | print 'descender:', f.info.descender
44 |
--------------------------------------------------------------------------------
/Docs/source/objects/libs.rst:
--------------------------------------------------------------------------------
1 | RLib
2 | ====
3 |
4 | .. image:: ../../images/fontLib.gif
5 |
6 | Usage
7 | -----
8 |
9 | .. showcode:: ../../examples/objects/RLib_00.py
10 |
11 | .. code::
12 |
13 | < RLib for Salmiak-Regular >
14 | ['org.robofog.ufoExport.date',
15 | 'org.robofog.ufoExport.encoding.current',
16 | 'org.robofog.ufoExport.font.italicOffset',
17 | 'org.robofog.ufoExport.sourcePath']
18 |
19 | Description
20 | -----------
21 |
22 | ``RFont`` and ``RGlyph`` objects get lib objects when they're created, so you don't have to explicxitly make one. Lib objects behave like normal dictionaries.
23 |
24 | Where is this data stored?
25 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
26 |
27 | In RoboFab 1.0 and FontLab 4.6.1, the lib is saved inside the (FontLab native attributes!) ``glyph.customdata`` and ``font.customdata`` in the ``.vfb`` file.
28 |
29 | .. note::
30 |
31 | A bug in FontLab 4.6.1 prevents the ``glyph.lib`` from being used: when data is stored in this field, the font can no longer be edited. FontLab Studio 5 introduces a new attribute customdict which is exclusively for storing Python data. Early tests indicate that RoboFab storage of lib data can move to this attribute, but further testing and introduction of the MacOS version are needed before RoboFab's Lib support can move to it. In UFO based fonts the libs are stored as ``.plist`` in the UFO. Have a look at :doc:`how to use the lib <../howtos/use_lib>`.
32 |
33 | Methods
34 | -------
35 |
36 | .. py:function:: keys()
37 |
38 | Return a list of the keys. Normal dictionary stuff.
39 |
--------------------------------------------------------------------------------
/Scripts/RoboFabIntro/demo_MakeCameoFont.py:
--------------------------------------------------------------------------------
1 | # FLM: Make Cameo Font
2 |
3 | """Make a cameo font. Pretty simple."""
4 |
5 | from robofab.world import CurrentFont
6 | from robofab.interface.all.dialogs import Message
7 |
8 | buffer = 30
9 | scaleValue = .9
10 |
11 | f = CurrentFont()
12 | # clear all kerning
13 | f.kerning.clear()
14 | #determine top and bottom of the box
15 | t = f.info.unitsPerEm + f.info.descender + buffer
16 | b = f.info.descender - buffer
17 | #first decompose any components
18 | for g in f:
19 | g.decompose()
20 | #then proceed with the cameo operation
21 | for g in f:
22 | #catch negative sidebearings
23 | if g.leftMargin < 0:
24 | g.leftMargin = 0
25 | if g.rightMargin < 0:
26 | g.rightMargin = 0
27 | #scale the glyph and sidebearings
28 | leftMargin = int(round((g.rightMargin * scaleValue) + buffer))
29 | rightMargin = int(round((g.rightMargin * scaleValue) + buffer))
30 | g.scale((scaleValue, scaleValue), (int(round(g.width/2)), 0))
31 | g.leftMargin = leftMargin
32 | g.rightMargin = rightMargin
33 | #determine the left and the right of the box
34 | l = 0
35 | r = g.width
36 | #draw the box using flPen
37 | p = g.getPen()
38 | p.moveTo((l, b))
39 | p.lineTo((l, t))
40 | p.lineTo((r, t))
41 | p.lineTo((r, b))
42 | p.closePath()
43 | #correct path direction
44 | g.correctDirection()
45 | #update the glyph
46 | g.update()
47 | #update the font
48 | f.update()
49 | #tell me when it is over
50 | Message('The highly complex "Cameo Operation" is now complete. Please examine the results and be thankful that RoboFab is on your side.')
--------------------------------------------------------------------------------
/Docs/source/objects/RInfo.rst:
--------------------------------------------------------------------------------
1 | RInfo
2 | =====
3 |
4 | .. image:: ../../images/RInfo.gif
5 |
6 | Usage
7 | -----
8 |
9 | .. showcode:: ../../examples/objects/RInfo_00.py
10 |
11 | .. code::
12 |
13 | MyFont Regular
14 | Huib van Krimpen
15 | Jan van Krimpen
16 | LTTR
17 | 1000
18 | 307
19 | #etc.
20 |
21 | Description
22 | -----------
23 |
24 | ``RInfo`` contains all names, numbers, URL's, dimensions, values, etc. that would otherwise clutter up the font object. You don't have to create a ``RInfo`` object yourself, ``RFont`` makes one when it is created. In FontLab the ``RInfo`` data is tunneled to the appropriate places in the FontLab font. In UFO land the data ends up in ``info.plist``. In all implementations ``RInfo`` doesn't check the validity of the entries, it just provides storage or access to them.
25 |
26 | Complete list of attributes
27 | ---------------------------
28 |
29 | RoboFab version 1.2 implements new ``RInfo`` objects with extended attributes. The old attributes still work, but print a deprecation warning when they're accessed. Scripts written with UFO1 attributes should work. The specification of UFO2 has its own site, `UnifiedFontObject.org`_. The ``objectsRF.RInfo`` object implements all attributes listed, the ``objectsFL`` implementation misses a couple as the fields are not supported in FontLab. Please have a look at the `overview of the UFO2 font.info attributes`_.
30 |
31 | .. _UnifiedFontObject.org: http://unifiedFontObject.org/
32 | .. _overview of the UFO2 font.info attributes: http://unifiedfontobject.org/versions/ufo2/fontinfo.html
33 |
--------------------------------------------------------------------------------
/Lib/robofab/test/test_objectsFL.py:
--------------------------------------------------------------------------------
1 | """This test suite for various FontLab-specific tests."""
2 |
3 |
4 | import FL # needed to quickly raise ImportError if run outside of FL
5 |
6 |
7 | import os
8 | import tempfile
9 | import unittest
10 |
11 | from robofab.world import NewFont
12 | from robofab.test.testSupport import getDemoFontPath, getDemoFontGlyphSetPath
13 | from robofab.tools.glifImport import importAllGlifFiles
14 | from robofab.pens.digestPen import DigestPointPen
15 | from robofab.pens.adapterPens import SegmentToPointPen
16 |
17 |
18 | def getDigests(font):
19 | digests = {}
20 | for glyphName in font.keys():
21 | pen = DigestPointPen()
22 | font[glyphName].drawPoints(pen)
23 | digests[glyphName] = pen.getDigest()
24 | return digests
25 |
26 |
27 | class FLTestCase(unittest.TestCase):
28 |
29 | def testUFOVersusGlifImport(self):
30 | font = NewFont()
31 | font.readUFO(getDemoFontPath(), doProgress=False)
32 | d1 = getDigests(font)
33 | font.close(False)
34 | font = NewFont()
35 | importAllGlifFiles(font.naked(), getDemoFontGlyphSetPath(), doProgress=False)
36 | d2 = getDigests(font)
37 | self.assertEqual(d1, d2)
38 | font.close(False)
39 |
40 | def testTwoUntitledFonts(self):
41 | font1 = NewFont()
42 | font2 = NewFont()
43 | font1.unitsPerEm = 1024
44 | font2.unitsPerEm = 2048
45 | self.assertNotEqual(font1.unitsPerEm, font2.unitsPerEm)
46 | font1.update()
47 | font2.update()
48 | font1.close(False)
49 | font2.close(False)
50 |
51 |
52 | if __name__ == "__main__":
53 | from robofab.test.testSupport import runTests
54 | runTests()
55 |
--------------------------------------------------------------------------------
/Docs/_themes/roboFabTheme/search.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 | {% set title = _('Search') %}
3 | {% set script_files = script_files + ['_static/searchtools.js'] %}
4 | {% block extrahead %}
5 |
8 | {{ super() }}
9 | {% endblock %}
10 | {% block body %}
11 | {{ _('Search') }}
12 |
13 |
14 |
15 | {% trans %}Please activate JavaScript to enable the search
16 | functionality.{% endtrans %}
17 |
18 |
19 |
20 | {% trans %}From here you can search these documents. Enter your search
21 | words into the box below and click "search". Note that the search
22 | function will automatically search for all of the words. Pages
23 | containing fewer words won't appear in the result list.{% endtrans %}
24 |
25 | {% if search_performed %}
26 | {{ _('Search Results') }}
27 | {% if not search_results %}
28 | {{ _('Your search did not match any results.') }}
29 | {% endif %}
30 | {% endif %}
31 |
32 | {% if search_results %}
33 |
34 | {% for href, caption, context in search_results %}
35 | - {{ caption }}
36 |
{{ context|e }}
37 |
38 | {% endfor %}
39 |
40 | {% endif %}
41 |
42 | {% endblock %}
--------------------------------------------------------------------------------
/Docs/build-docs.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 | import subprocess
4 |
5 | baseFolder = os.path.dirname(__file__)
6 | sourceFolder = os.path.join(baseFolder, 'source')
7 | buildFolder = os.path.join(baseFolder, '_build')
8 | logFile = os.path.join(baseFolder, 'sphinx-log.txt')
9 | doctreesFolder = os.path.join(buildFolder, 'doctrees')
10 | htmlFolder = os.path.join(buildFolder, 'html')
11 |
12 | # delete build folder
13 | if os.path.exists(buildFolder):
14 | shutil.rmtree(buildFolder)
15 |
16 | # options
17 | # http://sphinx-doc.org/man/sphinx-build.html
18 | # or in Terminal: sphinx-build -h
19 | commands = [
20 | '/usr/local/bin/sphinx-build',
21 | '-a', # build all files (not just new and changed)
22 | '-b', 'html', # builder: html / pdf / epub / text / etc.
23 | '-Q', # suppress console warnings and errors
24 | '-d', doctreesFolder,
25 | '-w', logFile, # write warnings and errors to file
26 | sourceFolder,
27 | htmlFolder
28 | ]
29 |
30 | # build docs
31 | p = subprocess.Popen(commands)
32 | stdout, stderr = p.communicate()
33 |
34 | # rewrite html for object map
35 | objectMapHtmlPath = os.path.join(os.path.join(htmlFolder, 'objects'), 'model.html')
36 | objectMapHtmlFile = open(objectMapHtmlPath, 'r')
37 | objectMapHtml = objectMapHtmlFile.read()
38 |
39 | findHtml = '
'
40 | replaceHtml = ''
41 |
42 | objectMapHtml = objectMapHtml.replace(findHtml, replaceHtml)
43 | objectMapHtmlFile = open(objectMapHtmlPath, 'w')
44 | objectMapHtmlFile.write(objectMapHtml)
45 |
--------------------------------------------------------------------------------
/Tools/versionSniffer.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | This script can be run as a FontLab macro.
4 | It prints version numbers of the application, python,
5 | and the contents of the relevant site-packages folder.
6 | Can be useful in finding out what you have installed where.
7 |
8 | erik@letterror.com 10_2011
9 | v 1.1 # removes assert
10 |
11 | """
12 |
13 | try:
14 | print "\n", "-"*40
15 | from FL import*
16 | print "fontlab version", fl.version
17 | except ImportError:
18 | print "probably not in FontLab."
19 |
20 | print "\n", "-"*40
21 | import sys, os
22 | print "python version", sys.version
23 |
24 | def findSitePackages():
25 | folderName = "site-packages"
26 | paths = {}
27 | for s in sys.path:
28 | if s.find(folderName)!=-1:
29 | root = os.path.join(s.split(folderName)[0], folderName)
30 | paths[root] = True
31 | safe = []
32 | return paths.keys()
33 |
34 | def dumpSitePackages(root):
35 | for n in os.listdir(root):
36 | if os.path.splitext(n)[-1] == ".pth":
37 | linkPath = os.path.join(root, n)
38 | print "\n", "-"*40
39 | print "\t", n.encode('ascii')
40 | print "\t", linkPath.encode('ascii')
41 |
42 | f = open(linkPath, 'r')
43 | d = f.read()
44 | f.close()
45 | print "\tcontents:"
46 | for l in d.split("\n"):
47 | print "\t\t", l.encode("ascii")
48 |
49 | for sp in findSitePackages():
50 | print "\n", "-"*40
51 | print "site-packages is at", sp
52 |
53 | dumpSitePackages(sp)
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Tools/installFontLab/installerFunctions.py:
--------------------------------------------------------------------------------
1 | """ These are the functions we want to use in FontLab."""
2 |
3 | import sys, os, time, platform
4 |
5 | def log(path, entry, verbose=True):
6 | """Write stuff into log files"""
7 | try:
8 | f = open(path, 'a')
9 | except IOError:
10 | print "Error writing to log."
11 | print entry
12 | return
13 | from time import localtime, strftime
14 | t = strftime("%a, %d %b %Y %H:%M:%S", localtime())
15 | if type(entry) != str:
16 | entry = str(entry)
17 | f.write("\n"+t+" "+entry)
18 | f.close()
19 | if verbose:
20 | print entry
21 |
22 | def findSitePackages():
23 | """Try to find the site-packages folder for the current python."""
24 | folderName = "site-packages"
25 | paths = {}
26 | for s in sys.path:
27 | if s.find(folderName)!=-1:
28 | root = os.path.join(s.split(folderName)[0], folderName)
29 | paths[root] = True
30 | return paths.keys()
31 |
32 | def writePathFile(pathFilePath, modulePaths):
33 | """Write the *.pth file to site-packages."""
34 | print "writing the modulePaths path to", pathFilePath
35 | try:
36 | f = open(pathFilePath, 'w')
37 | f.write("\n".join(modulePaths))
38 | f.close()
39 | except IOError:
40 | import traceback
41 | cla, exc, trbk = sys.exc_info()
42 | excName = cla.__name__
43 | try:
44 | excArgs = exc.__dict__["args"]
45 | except KeyError:
46 | excArgs = ""
47 | excTb = traceback.format_tb(trbk, 2)
48 | log(excName)
49 | #log(excArgs)
50 | log(excTb)
51 |
52 |
--------------------------------------------------------------------------------
/Docs/source/intro/gettingstarted.rst:
--------------------------------------------------------------------------------
1 | Getting Started with RoboFab
2 | ============================
3 |
4 | Installing
5 | ----------
6 |
7 | Installing RoboFab is pretty straightforward as installing Python libraries go. But considering this might be the first time you do this, here are a couple of things to pay attention to. First, have a look at the :doc:`installation notes `.
8 |
9 | Some remarks for FontLab 4.6 users on Mac OSX
10 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 |
12 | - In MacOSX, you need to have admin permissions to install robofab in MacOS 9 Python.
13 | - If you've downloaded the MacOSX diskimage installer, first copy the entire thing to a nice, accessible place on your harddisk. The ``install.py`` script makes a link to the folder it's in, so if you were to run the install script from the mounted diskimage, RoboFab would be gone after you unmount the diskimage.
14 |
15 | FontLab Macros
16 | --------------
17 |
18 | RoboFab has some example scripts that show how it can be used in FontLab. In the RoboFab folder, there's a folder named ``Scripts``. In it are two folders that you can drag to FontLab's ``Macros`` folder. After restarting the application the ``Utils`` and ``RoboFabIntro`` folder will have been added to the macro list.
19 |
20 | Then what?
21 | ^^^^^^^^^^
22 |
23 | It depends on your proficiency in scripting and operating fonteditors like FontLab. Some :doc:`notes on scripting <../howtos/scripting>` are available in the how to section. There's :doc:`this manual <../index>` which offers documentation, examples and background. Help with operating your font editor of choice is not available from this site or from the RoboFab developers. Read the manual.
24 |
--------------------------------------------------------------------------------
/Data/DemoFont.ufo/glyphs/B_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Docs/source/intro/summary.rst:
--------------------------------------------------------------------------------
1 | Executive Summary
2 | =================
3 |
4 | RoboFab is the result of over 6 man-years of concentrated coding. The package combines a solid Pythonic API with over 40 standardized classes of objects for font and glyph related data. With RoboFab installed, the scripter will find it easier to produce scripts, API standardization means fewer things to remember or look up -- eventhough RoboFab comes with extensive documentation and example code.
5 |
6 | The Font/Glyph/Contour/Point model can be tailored to the needs of the scripter, manipulating data from glyph to glyph or font to font and addressing the outline data point by point, as offcurve/oncurve segments or as conventional knots with incoming / oncurve / outgoing attributes. RoboFab's Kerning object delivers the kerning data as a standard Python dictionary object. The Lib objects will soon take advantage of FontLab's new PythonDict field for storing Python data inside FontLab .vfb sources.
7 |
8 | RoboFab's pen objects (an implementation of fontTools' pen classes) provide a powerful method to interface with glyph data, either for actual drawing (for instance on screen, or some sort of vector based file format), complex comparisons, transformations and filtering.
9 |
10 | RoboFab offers a large selection of standardised UI dialogs, ranging from plain messaging to very powerful font and glyph retrieval functionality.
11 |
12 | RoboFab also brings extensive support for import and export of glyph and font data to UFO, an open industry standard based on XML. UFO makes it possible to, for instance, store text versions of glyphs and fonts in large SQL databases and apply standard text source management tools (such as cvs, diff) to glyphsets.
13 |
--------------------------------------------------------------------------------
/Data/DemoFont.ufo/glyphs/G_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | RoboFab License Agreement
2 |
3 | Copyright (c) 2003-2013, The RoboFab Developers:
4 | Erik van Blokland
5 | Tal Leming
6 | Just van Rossum
7 |
8 | All rights reserved.
9 |
10 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
11 |
12 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
13 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
14 | Neither the name of the The RoboFab Developers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 |
17 | Up to date info on RoboFab:
18 | http://robofab.com/
19 |
20 | This is the BSD license:
21 | http://www.opensource.org/licenses/BSD-3-Clause
22 |
23 |
--------------------------------------------------------------------------------
/Scripts/RoboFabIntro/intro_GeneratingFonts.py:
--------------------------------------------------------------------------------
1 | #FLM: RoboFab Intro, Generating Fonts
2 |
3 | #
4 | #
5 | # demo generating fonts with robofab
6 | #
7 | #
8 |
9 |
10 | # Generating fonts with RoboFab is super easy! Let's have a look.
11 | # (you will need to have a font open in FontLab)
12 |
13 | from robofab.world import CurrentFont
14 | import os
15 |
16 | # A little function for making folders. we'll need it later.
17 | def makeFolder(path):
18 | #if the path doesn't exist, make it!
19 | if not os.path.exists(path):
20 | os.makedirs(path)
21 |
22 | # We need to have a font open for this demo to work
23 | font = CurrentFont()
24 | # This will tell us what folder the font is in
25 | fontPath = os.path.dirname(font.path)
26 |
27 | # We'll put the fonts into a folder called "FabFonts" next the .vfb file
28 | macPath = os.path.join(fontPath, 'FabFonts', 'ForMac')
29 | pcPath = os.path.join(fontPath, 'FabFonts', 'ForPC')
30 | bothPath = os.path.join(fontPath, 'FabFonts', 'ForBoth')
31 |
32 | # Now, we'll use that little function we made earlier to make the folders
33 | makeFolder(macPath)
34 | makeFolder(pcPath)
35 | makeFolder(bothPath)
36 |
37 | # A dict of all the font types we want to output
38 | fontTypes = { 'mac' : ['mactype1', 'macttf', 'macttdfont'],
39 | 'pc' : ['pctype1', 'pcmm'],
40 | 'both' : ['otfcff', 'otfttf']
41 | }
42 |
43 | # Finally, let's generate the fonts!
44 | for macType in fontTypes['mac']:
45 | print "generating %s..."%macType
46 | font.generate(macType, macPath)
47 | for pcType in fontTypes['pc']:
48 | print "generating %s..."%pcType
49 | font.generate(pcType, pcPath)
50 | for bothType in fontTypes['both']:
51 | print "generating %s..."%bothType
52 | font.generate(bothType, bothPath)
53 | print 'Done!'
54 |
55 | # Wow! Could it be any easier than that?
56 |
--------------------------------------------------------------------------------
/Scripts/RoboFabIntro/demo_AlignBPoints.py:
--------------------------------------------------------------------------------
1 | #FLM: Align Two Nodes
2 |
3 | """Align bPoints horizontally, vertically or both."""
4 |
5 | from robofab.world import CurrentGlyph
6 | from robofab.interface.all.dialogs import TwoChecks
7 |
8 | glyph = CurrentGlyph()
9 |
10 | sel = []
11 |
12 | #gather selected bPoints
13 | for contour in glyph.contours:
14 | if contour.selected:
15 | for bPoint in contour.bPoints:
16 | if bPoint.selected:
17 | sel.append(bPoint)
18 |
19 | if len(sel) != 0:
20 | xL = []
21 | yL = []
22 |
23 | #store up all coordinates for use later
24 | for bPoint in sel:
25 | x, y = bPoint.anchor
26 | xL.append(x)
27 | yL.append(y)
28 |
29 | if len(xL) > 1:
30 | w = TwoChecks("Horizontal", "Vertical", 0, 0)
31 | if w == None or w == 0:
32 | #the user doesn't want to align anything
33 | pass
34 | else:
35 | #find the center among all those bPoints
36 | minX = min(xL)
37 | maxX = max(xL)
38 | minY = min(yL)
39 | maxY = max(yL)
40 | cX = int(round((minX + maxX)/2))
41 | cY = int(round((minY + maxY)/2))
42 |
43 | #set the undo
44 | try:
45 | fl.SetUndo()
46 | except:
47 | pass
48 |
49 | #determine what the user wants to do
50 | noY = False
51 | noX = False
52 | if w == 1:
53 | #the user wants to align y
54 | noX = True
55 | elif w == 2:
56 | #the user wants to align x
57 | noY = True
58 | elif w == 3:
59 | #the user wants to align x and y
60 | pass
61 |
62 |
63 | for bPoint in sel:
64 | #get the move value for the bPoint
65 | aX, aY = bPoint.anchor
66 | mX = cX - aX
67 | mY = cY - aY
68 | if noY:
69 | #don't move the y
70 | mY = 0
71 | if noX:
72 | #don't move the x
73 | mX = 0
74 | bPoint.move((mX, mY))
75 | glyph.update()
76 |
--------------------------------------------------------------------------------
/TestData/TestFont1 (UFO1).ufo/lib.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | org.robofab.opentype.classes
6 | @myClass = [A B];
7 |
8 | org.robofab.opentype.featureorder
9 |
10 | liga
11 |
12 | org.robofab.opentype.features
13 |
14 | liga
15 | feature liga {
16 | sub A A by b;
17 | } liga;
18 |
19 |
20 | org.robofab.postScriptHintData
21 |
22 | blueFuzz
23 | 1
24 | blueScale
25 | 0.039625
26 | blueShift
27 | 7
28 | blueValues
29 |
30 |
31 | 500
32 | 510
33 |
34 |
35 | familyBlues
36 |
37 |
38 | 500
39 | 510
40 |
41 |
42 | familyOtherBlues
43 |
44 |
45 | -260
46 | -250
47 |
48 |
49 | forceBold
50 |
51 | hStems
52 |
53 | 100
54 | 120
55 |
56 | otherBlues
57 |
58 |
59 | -260
60 | -250
61 |
62 |
63 | vStems
64 |
65 | 80
66 | 90
67 |
68 |
69 | org.robofab.testFontLibData
70 | Foo Bar
71 |
72 |
73 |
--------------------------------------------------------------------------------
/Docs/source/talks/index.rst:
--------------------------------------------------------------------------------
1 | Step-by-step
2 | ============
3 |
4 | These are chapters about scripting in Python, where and how to make your code and how to use RoboFab objects. Illustrated with many examples. These documents started out as conference notes for the Robothon09 Conference. They have been updated for UFO2.
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 | :hidden:
9 |
10 | editors.rst
11 | python_basics.rst
12 | session1.rst
13 | session2.rst
14 | session3.rst
15 | interpolation.rst
16 | session6.rst
17 | session4.rst
18 | dialogkit.rst
19 |
20 | Sections
21 | --------
22 |
23 | - :doc:`01: Editors `: Where to use RoboFab, where to edit.
24 | - :doc:`02: Basic Python `: Some rules, syntax.
25 | - :doc:`03: Font object, Info object `: Introduction to Font and Info objects, with examples.
26 | - :doc:`04: Glyph object and Pen object `: Introduction to Glyph and Pen objects.
27 | - :doc:`05: Kerning object and glyph building `: Introduction to the Kerning object, and a closer look at building glyphs from parts.
28 | - :doc:`06: Interpolation `: Scripting for interpolation.
29 | - :doc:`07: Production `: Scripting for production.
30 | - :doc:`08: NoneLab `: Adventures in NoneLab, scripting outside the box.
31 | - :doc:`09: Dialog Kit `: Interface toolkit for FontLab.
32 |
33 | Additional resources
34 | --------------------
35 |
36 | The `Unified Font Object Specification site`_ featuring the UFO 2 extension.
37 |
38 | Find dozens of useful packages at the `TypeSupply.com public code repository`_, for instance DialogKit, Defcon, UFO2FDK and many more.
39 |
40 | .. _Unified Font Object Specification site : http://unifiedfontobject.org/
41 | .. _TypeSupply.com public code repository : http://code.typesupply.com/
42 |
--------------------------------------------------------------------------------
/Scripts/RoboFabIntro/demo_InterpolPreview.py:
--------------------------------------------------------------------------------
1 | #FLM: Interpol Preview
2 |
3 | """This script draws all incremental interpolations
4 | between 1% and 99% of a selected glyph into a new font.
5 | It requires two open source fonts in FontLab."""
6 |
7 | from robofab.interface.all.dialogs import SelectFont, OneList, ProgressBar
8 | from robofab.world import NewFont
9 |
10 | src1 = SelectFont('Select source font one:')
11 | if src1:
12 | src2 = SelectFont('Select source font two:')
13 | if src2:
14 | # collect a list of all compatible glyphs
15 | common = []
16 | for glyphName in src1.keys():
17 | if src2.has_key(glyphName):
18 | if src1[glyphName].isCompatible(src2[glyphName]):
19 | common.append(glyphName)
20 | common.sort()
21 | selName = OneList(common, 'Select a glyph:')
22 | if selName:
23 | dest = NewFont()
24 | g1 = src1[selName]
25 | g2 = src2[selName]
26 | count = 1
27 | bar = ProgressBar('Interpolating...', 100)
28 | # add the sourec one glyph for reference
29 | dest.newGlyph(selName + '_000')
30 | dest[selName + '_000'].width = src1[selName].width
31 | dest[selName + '_000'].appendGlyph(src1[selName])
32 | dest[selName + '_000'].mark = 1
33 | dest[selName + '_000'].update()
34 | # add a new glyph and interpolate it
35 | while count != 100:
36 | factor = count * .01
37 | newName = selName + '_' + `count`.zfill(3)
38 | gD = dest.newGlyph(newName)
39 | gD.interpolate(factor, g1, g2)
40 | gD.update()
41 | bar.tick()
42 | count = count + 1
43 | # add the source two glyph for reference
44 | dest.newGlyph(selName + '_100')
45 | dest[selName + '_100'].width = src2[selName].width
46 | dest[selName + '_100'].appendGlyph(src2[selName])
47 | dest[selName + '_100'].mark = 1
48 | dest[selName + '_100'].update()
49 | dest.update()
50 | bar.close()
51 |
--------------------------------------------------------------------------------
/Scripts/RoboFabUFO/SelectedGlyphsToUFOForAllFonts.py:
--------------------------------------------------------------------------------
1 | #FLM: Selected glyphs from all fonts to UFO
2 |
3 |
4 | """
5 | Get the name of the current glyph,
6 | then for each open font, export that glyph to UFO.
7 | It saves the .glif through a GlyphSet and updates the contents.plist.
8 |
9 | This script is useful when you're working on several interpolation
10 | masters as separate vfb source files.
11 |
12 | EvB 08
13 | """
14 |
15 |
16 | from robofab.glifLib import GlyphSet
17 | from robofab.world import CurrentFont, CurrentGlyph, AllFonts
18 | from robofab.interface.all.dialogs import Message, GetFileOrFolder
19 | from robofab.tools.glyphNameSchemes import glyphNameToShortFileName
20 | import os
21 |
22 | f = CurrentFont()
23 | g = CurrentGlyph()
24 |
25 | f.save()
26 |
27 | todo = f.selection
28 | print "selection", todo
29 | if g is not None:
30 | todo.append(g.name)
31 |
32 | for f in AllFonts():
33 | ufoPath = None
34 | print "f.path", f, f.path
35 | if f.path is None:
36 | # huh, in case there is a ghost font.
37 | print "skipping", f
38 | continue
39 | ufoPath = f.path.replace(".vfb", ".ufo")
40 | if not os.path.exists(ufoPath):
41 | ufoPath = GetFileOrFolder("Select a UFO to save the GLIF in:")
42 | if ufoPath.find(".ufo") == -1:
43 | Message("You need to select an UFO. Quitting.")
44 | ufoPath = None
45 | if ufoPath is None:
46 | continue
47 | for c in todo:
48 | if c not in f:
49 | print "font is missing", c
50 | continue
51 | g = f[c]
52 | path = os.path.join(os.path.dirname(ufoPath), os.path.basename(ufoPath), "glyphs")
53 | print "saving glyph %s in %s"%(g.name, path)
54 | gs = GlyphSet(path, glyphNameToFileNameFunc=glyphNameToShortFileName)
55 | gs.writeGlyph(g.name, g, g.drawPoints)
56 | gs.writeContents()
57 |
58 | print 'done'
--------------------------------------------------------------------------------
/Scripts/RoboFabUFO/ExportSelectedGlyphsToUFOForAllFonts.py:
--------------------------------------------------------------------------------
1 | #FLM: Selected glyphs from all fonts to UFO
2 |
3 |
4 | """
5 | Get the name of the current glyph,
6 | then for each open font, export that glyph to UFO.
7 | It saves the .glif through a GlyphSet and updates the contents.plist.
8 |
9 | This script is useful when you're working on several interpolation
10 | masters as separate vfb source files.
11 |
12 | EvB 08
13 | """
14 |
15 |
16 | from robofab.glifLib import GlyphSet
17 | from robofab.world import CurrentFont, CurrentGlyph, AllFonts
18 | from robofab.interface.all.dialogs import Message, GetFileOrFolder
19 | from robofab.tools.glyphNameSchemes import glyphNameToShortFileName
20 | import os
21 |
22 | f = CurrentFont()
23 | g = CurrentGlyph()
24 |
25 | f.save()
26 |
27 | todo = f.selection
28 | print "selection", todo
29 | if g is not None:
30 | todo.append(g.name)
31 |
32 | for f in AllFonts():
33 | ufoPath = None
34 | print "f.path", f, f.path
35 | if f.path is None:
36 | # huh, in case there is a ghost font.
37 | print "skipping", f
38 | continue
39 | ufoPath = f.path.replace(".vfb", ".ufo")
40 | if not os.path.exists(ufoPath):
41 | ufoPath = GetFileOrFolder("Select a UFO to save the GLIF in:")
42 | if ufoPath.find(".ufo") == -1:
43 | Message("You need to select an UFO. Quitting.")
44 | ufoPath = None
45 | if ufoPath is None:
46 | continue
47 | for c in todo:
48 | if c not in f:
49 | print "font is missing", c
50 | continue
51 | g = f[c]
52 | path = os.path.join(os.path.dirname(ufoPath), os.path.basename(ufoPath), "glyphs")
53 | print "saving glyph %s in %s"%(g.name, path)
54 | gs = GlyphSet(path, glyphNameToFileNameFunc=glyphNameToShortFileName)
55 | gs.writeGlyph(g.name, g, g.drawPoints)
56 | gs.writeContents()
57 |
58 | print 'done'
--------------------------------------------------------------------------------
/Docs/source/howtos/index.rst:
--------------------------------------------------------------------------------
1 | How To's
2 | ========
3 |
4 | .. toctree::
5 | :maxdepth: 1
6 | :hidden:
7 |
8 | ot_features.rst
9 | building_accents.rst
10 | fontlab_remote.rst
11 | generating_fonts.rst
12 | glifnames.rst
13 | lowlevel.rst
14 | interpolate.rst
15 | makeufo.rst
16 | scripting.rst
17 | world.rst
18 | understanding_contours.rst
19 | glyphmath.rst
20 | use_pens.rst
21 | use_lib.rst
22 | use_transformations.rst
23 |
24 | This section provides some cases on how to use the RoboFab objects in everyday type design work.
25 |
26 | - :doc:`OpenType Features in UFO `: How to import, export and work with features in UFO.
27 | - :doc:`Building accents `: Use RoboFab to build accented glyphs with components.
28 | - :doc:`FontLab Remote `: Use AppleEvents to control FontLab in Mac OSX
29 | - :doc:`Generate Fonts `: How to generate fonts with RoboFab in FontLab.
30 | - :doc:`Glyphnames versus GLIF-names `: How to use Robofab's glyph naming schemes for UFO export.
31 | - :doc:`How to get to FontLab stuff `: The naked methods and attributes.
32 | - :doc:`How to interpolate `: How to do interpolation with RoboFab objects.
33 | - :doc:`How to make a UFO `: Export and import UFO's in FontLab
34 | - :doc:`Scripting `: Simple examples.
35 | - :doc:`The world module `: What on earth is it for?
36 | - :doc:`Understanding Contours `: How contours, segments and points work.
37 | - :doc:`Using Glyph Math `: Applying math operators on glyph objects.
38 | - :doc:`Using Pens `: Playing with pen objects.
39 | - :doc:`Using the lib `: Make the ``glyph.lib`` and ``font.lib`` work for you.
40 | - :doc:`Using transformations `: Matrix transformations in RoboFab.
41 |
--------------------------------------------------------------------------------
/Scripts/Contributed/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | The code in the Contributions folder is covered, like the rest of RoboFab,
3 | by the BSD license, unless stated otherwise in the code itself.
4 |
5 |
6 | RoboFab License Agreement
7 |
8 | Copyright (c) 2005-2012, The RoboFab Developers:
9 | Erik van Blokland
10 | Tal Leming
11 | Just van Rossum
12 |
13 | All rights reserved.
14 |
15 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
16 |
17 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
18 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
19 | Neither the name of the The RoboFab Developers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 |
22 | Up to date info on RoboFab:
23 | http://robofab.com/
24 |
25 | This is the BSD license:
26 | http://www.opensource.org/licenses/BSD-3-Clause
27 |
28 |
--------------------------------------------------------------------------------
/Docs/source/objects/psHintsGlyph.rst:
--------------------------------------------------------------------------------
1 | PostScript glyph hint values
2 | ============================
3 |
4 | Usage
5 | -----
6 |
7 | .. code::
8 |
9 | # example of accessing the hint data.
10 | # from robofab.world import CurrentFont
11 |
12 | Description
13 | -----------
14 |
15 | ``PostScriptGlyphHintValues`` is the class of the object found at ``aGlyph.psHints``. It has a couple of attributes of its own which give you access to the glyph level PostScript hint information.
16 |
17 | The ``PostScriptGlyphHintValues`` objects, in FontLab and NoneLab flavor, can respond to ``add``, ``sub``, ``mul``, ``rmul``, ``div`` and ``rdiv``, so you can do math with them, for instance interpolations. Available since `ChangeSet 44`_.
18 |
19 | .. _ChangeSet 44: http://code.robofab.com/changeset/44
20 |
21 | Attributes
22 | ^^^^^^^^^^
23 |
24 | .. py:attribute:: hHints
25 |
26 | List of (position, width) tuples for horizontal.
27 |
28 | .. py:attribute:: vHints
29 |
30 | List of (position, width) tuples.
31 |
32 | Methods
33 | ^^^^^^^
34 |
35 | .. py:function:: copy()
36 |
37 | Returns a copy of the object. Both in FontLab and NoneLab the copy will be an ``objectsRF.PostScriptFontHintValues``.
38 |
39 | .. py:function:: round()
40 |
41 | Round the values to ints as much as the nature of the values allows.
42 |
43 | .. note::
44 |
45 | - ``blueScale`` is not rounded, it is a float.
46 | - ``forceBold`` is set to ``False`` if ``-0.5 < value < 0.5``. Otherwise it will be ``True``.
47 | - ``blueShift``, ``blueFuzz`` are rounded to integers.
48 | - ``stems`` are rounded to integers.
49 | - ``blues`` are rounded to integers.
50 |
51 | .. py:function:: asDict()
52 |
53 | Returns a dictionary with all attributes and values of this object.
54 |
55 | .. py:function:: fromDict(aDict)
56 |
57 | Rhis will look for familiar attributes in ``aDict`` and assign the value to the object.
58 |
59 | .. py:function:: update(anotherPSHintsObject)
60 |
61 | This will copy values from the other object.
62 |
--------------------------------------------------------------------------------
/Lib/robofab/tools/objectDumper.py:
--------------------------------------------------------------------------------
1 | """Simple and ugly way to print some attributes and properties of an object to stdout.
2 | FontLab doesn't have an object browser and sometimes we do need to look inside"""
3 |
4 | from pprint import pprint
5 |
6 | def classname(object, modname):
7 | """Get a class name and qualify it with a module name if necessary."""
8 | name = object.__name__
9 | if object.__module__ != modname:
10 | name = object.__module__ + '.' + name
11 | return name
12 |
13 | def _objectDumper(object, indent=0, private=False):
14 | """Collect a dict with the contents of the __dict__ as a quick means of peeking inside
15 | an instance. Some RoboFab locations do not support PyBrowser and still need debugging."""
16 | data = {}
17 | data['__class__'] = "%s at %d"%(classname(object.__class__, object.__module__), id(object))
18 | for k in object.__class__.__dict__.keys():
19 | if private and k[0] == "_":
20 | continue
21 | x = object.__class__.__dict__[k]
22 | if hasattr(x, "fget"): #other means of recognising a property?
23 | try:
24 | try:
25 | value = _objectDumper(x.fget(self), 1)
26 | except:
27 | value = x.fget(self)
28 | data[k] = "[property, %s] %s"%(type(x.fget(self)).__name__, value)
29 | except:
30 | data[k] = "[property] (Error getting property value)"
31 | for k in object.__dict__.keys():
32 | if private and k[0] == "_":
33 | continue
34 | try:
35 | data[k] = "[attribute, %s] %s"%(type(object.__dict__[k]).__name__, `object.__dict__[k]`)
36 | except:
37 | data[k] = "[attribute] (Error getting attribute value)"
38 | return data
39 |
40 | def flattenDict(dict, indent=0):
41 | t = []
42 | k = dict.keys()
43 | k.sort()
44 | print
45 | print '---RoboFab Object Dump---'
46 | for key in k:
47 | value = dict[key]
48 | t.append(indent*"\t"+"%s: %s"%(key, value))
49 | t.append('')
50 | return "\r".join(t)
51 |
52 | def dumpObject(object, private=False):
53 | print pprint(_objectDumper(object, private=private))
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Docs/source/objects/RPoint.rst:
--------------------------------------------------------------------------------
1 | RPoint
2 | ======
3 |
4 | .. image:: ../../images/RPoint.gif
5 |
6 | Usage
7 | -----
8 |
9 | .. showcode:: ../../examples/objects/RPoint_00.py
10 |
11 | .. code::
12 |
13 |
14 |
15 | Description
16 | -----------
17 |
18 | ``RPoint`` is perhaps the smallest object in RoboFab objects. It represents one single point with a particular coordinate in a contour. It is used to access off-curve and on-curve points alike. It's cousin, :doc:`bPoint` also provides access to incoming and outgoing bcps. ``RPoint`` is exclusively only one single point.
19 |
20 | Understanding Contours and outlines
21 | -----------------------------------
22 |
23 | The way outline data is organised in RoboFab, and how the various objects relate is described here: :doc:`understanding contours <../howtos/understanding_contours>`.
24 |
25 | Attributes
26 | ----------
27 |
28 | .. py:attribute:: x
29 |
30 | The ``x`` coordinate of this point.
31 |
32 | .. py:attribute:: y
33 |
34 | The ``y`` coordinate of this point.
35 |
36 | .. py:attribute:: type
37 |
38 | The ``type`` of this point.
39 |
40 | .. py:attribute:: selected
41 |
42 | Boolean for selection state, i.e. ``True`` or ``False``.
43 |
44 | UFO only attributes
45 | -------------------
46 |
47 | .. py:attribute:: name
48 |
49 | The name of the point (UFO only).
50 |
51 | Methods
52 | -------
53 |
54 | .. py:function:: copy()
55 |
56 | Return a deepcopy of the object.
57 |
58 | .. py:function:: move((x, y))
59 |
60 | Move the anchor of the ``bPoint`` to ``(x,y)``. The relative coordinates of the ``bcpIn`` and ``bcpOut`` will remain the same, which means that in fact, they move the same distance.
61 |
62 | .. py:function:: round()
63 |
64 | Round the coordinates to whole integers.
65 |
66 | .. py:function:: select(state=True)
67 |
68 | Select this point.
69 |
70 | .. py:function:: transform(matrix)
71 |
72 | Transform this point. Use a Transform matrix object to mess with the point.
73 |
74 | .. seealso:: :doc:`how to use transformations <../howtos/use_transformations>`.
75 |
--------------------------------------------------------------------------------