A collection of simple scripts to do things to fonts.

Set fixed width in all glyphs

Set a fixed width in all glyphs in the current font.

# get the current font
font = CurrentFont()

# iterate over all glyphs in the font
for glyph in font:

    # set glyph width
    glyph.width = 400

Set a fixed width in all selected glyphs in the current font. Enable undo/redo.

# define a width value
value = 400

# get the current font
font = CurrentFont()

# iterate over all selected glyphs in the font
for glyph in font.selectedGlyphs:

    # wraps the glyph width change in an undo context
    with glyph.undo():

        # set glyph width
        glyph.width = value

Modify existing font info

Setting a font info is as easy as setting a value. The new value will override the old one.

# get the current font
font = CurrentFont()

# edit some font info
font.info.familyName = "My Font"
font.info.ascender = 650
font.info.openTypeOS2Selection = [2, 4]

If you need to modify a mutable container, like adding a bit flag to the openTypeOS2Selection, be aware that you cannot modify it in-place. To update the Info object, the new value needs to be set, as in this example:

# get the current font
font = CurrentFont()

# set
font.info.openTypeOS2Selection = [2, 4]

# get
selection = font.info.openTypeOS2Selection

# edit
selection.append(8)

# reset
font.info.openTypeOS2Selection = selection

print(font.info.openTypeOS2Selection)
# >>> [2, 4, 8]

Set infos in all open fonts

Set font infos from a dictionary into all open fonts.

# a dictionary with font infos
infoDict = {
    # attribute : data,
    'openTypeNameDesigner' : 'Claude Garamond',
    'year' : 1532,
    'copyright' : 'Copyright (c) 1532 Claude Garamond.',
    'note' : 'bonjour le monde',
}

# for each open font
for font in AllFonts():
    # iterate over all attributes and values
    for attr, value in infoDict.items():
        # set font info data
        setattr(font.info, attr, value)

# done!

Copy font infos from one font to another

Copy font info data from one open font to another.

# get the source font by name
f1 = AllFonts().getFontsByStyleName('Regular')[0]

# get the target font by name
f2 = AllFonts().getFontsByStyleName('Bold')[0]

# a list of font.info attributes to copy
attributes = [
    'familyName',
    'xHeight',
    'openTypeNameDesigner',
]

# copy font.info data from f1 to f2
for attr in attributes:
    # get value from source font
    value = getattr(f1.info, attr)
    # set value in target font
    setattr(f2.info, attr, value)

Batch generate fonts for all UFOs in folder

Batch generate OTFs from a folder of UFOs.

  1. open a dialog to select a folder
  2. open each UFO in folder (without the UI)
  3. generate OpenType-CFF font from UFO
import os
from vanilla.dialogs import getFolder

# select folder
folder = getFolder('Select a folder with UFOs')[0]

# iterate over all files in folder
for f in os.listdir(folder):

    # skip files which are not .ufos
    if os.path.splitext(f)[-1] != '.ufo':
        continue

    # get full ufo path
    ufoPath = os.path.join(folder, f)

    # open ufo (without UI) # use 'showUI' in RF 1.8
    font = OpenFont(ufoPath, showInterface=False)

    # make otf path
    otfPath = ufoPath.replace('.ufo', '.otf')

    # generate otf font
    font.generate(path=otfPath, format='otf', decompose=True, checkOutlines=True, releaseMode=True)

    # close the ufo
    font.close()

Import a font into a layer of the current font

Import glyphs from a second font into a layer of the current font.

# get the current font
font1 = CurrentFont()

# open a second font (without the UI)
font2 = OpenFont(showInterface=False)

# create target layer
layerName = f"{font2.info.familyName} {font2.info.styleName}"
dstLayer = font1.newLayer(layerName)

# loop over all glyphs in the second font
for glyph in font2:

    # add the glyph to the layer
    dstLayer[glyph.name] = glyph

# done!

Building accented glyphs

Build accented glyphs in RoboFont3 using Glyph Construction.

from glyphConstruction import ParseGlyphConstructionListFromString, GlyphConstructionBuilder

# define glyph constructions
txt = '''\
?agrave = a + grave@center,top
aacute = a + acute@center,top
'''

# get the actual glyph constructions from text
constructions = ParseGlyphConstructionListFromString(txt)

# get the current font
font = CurrentFont()

# collect glyphs to ignore if they already exist in the font
ignoreExisting = [L.split('=')[0].strip()[1:] for L in txt.split('\n') if L.startswith('?')]

# iterate over all glyph constructions
for construction in constructions:

    # build a construction glyph
    constructionGlyph = GlyphConstructionBuilder(construction, font)

    # if the construction for this glyph was preceded by `?`
    # and the glyph already exists in the font, skip it
    if constructionGlyph.name in font and constructionGlyph.name in ignoreExisting:
        continue

    # get the destination glyph in the font
    glyph = font.newGlyph(constructionGlyph.name, clear=True)

    # draw the construction glyph into the destination glyph
    constructionGlyph.draw(glyph.getPen())

    # copy construction glyph attributes to the destination glyph
    glyph.name = constructionGlyph.name
    glyph.unicode = constructionGlyph.unicode
    glyph.width = constructionGlyph.width
    glyph.markColor = 1, 1, 0, 0.5

    # if no unicode was given, try to set it automatically
    if glyph.unicode is None:
        glyph.autoUnicodes()

Build accented glyphs in RoboFont1 using RoboFab’s font.compileGlyph.

# get current font
font = CurrentFont()

# a dictionary of glyph constructions
accentsDict = {
    # accented glyph : [base glyph, [(accent, anchor)]],
    'agrave' : ['a', [('grave', 'top')]],
    'aacute' : ['a', [('acute', 'top')]],
    # ...add more accented glyphs here...
}

# iterate over all accented glyphs
for accentedGlyph in accentsDict.keys():

    # get base glyph and accents/anchors
    baseGlyph, accents = accentsDict[accentedGlyph]

    # build accented glyph using components
    font.compileGlyph(accentedGlyph, baseGlyph, accents)

Scale a font

Scale different types of data in a font:

  • glyph contours and metrics
  • anchors
  • font guides and glyph guides
  • kerning
  • font dimensions
font = CurrentFont()

newUpm = 100
oldUpm = font.info.unitsPerEm
factor = newUpm / oldUpm

for layer in font.layers:

    for glyph in layer:

        for contour in glyph:
            contour.scaleBy(factor)

        for anchor in glyph.anchors:
            anchor.scaleBy(factor)

        for guideline in glyph.guidelines:
            guideline.scaleBy(factor)

        glyph.width *= factor

font.kerning.scaleBy(factor)

for guideline in font.guidelines:
    guideline.scaleBy(factor)

for attr in ['unitsPerEm', 'descender', 'xHeight', 'capHeight', 'ascender']:
    oldValue = getattr(font.info, attr)
    newValue = oldValue * factor
    setattr(font.info, attr, newValue)

font.changed()
Last edited on 01/09/2021