Introduction

Fonts may contain glyphs which are made out of other glyphs. Typical examples include glyphs with diacritics, ligatures, fractions, etc.

Font formats and font editors have special data types to enable the reuse of glyph shapes in a font:

Components

References to other glyphs in the same font.

When a component’s base glyph changes, all references to it are also updated.

Anchors

Invisible points with a position and a name.

Used to position components and glyphs in relation to each other.

Building composed glyphs

There are different ways to build composed glyphs in RoboFont:

Using the Add Glyphs sheet

The Add Glyphs sheet supports a basic syntax for building glyphs using components and anchors.

Using Glyph Construction

The Glyph Construction language offers a more powerful syntax for building glyphs from components. The extension includes the Glyph Builder interface for previewing and building composed glyphs.

Building composed glyphs with a script

glyphConstruction

RoboFont 3 comes with the glyphConstruction module embedded, so you can import it into a script and build glyphs from glyph construction rules.

'''
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()

compileGlyph

In RoboFont 1, you can build accented glyphs using RoboFab’s RFont.compileGlyph.

'''
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)

Upgrading from compileGlyph to glyphConstruction

If you are upgrading from RoboFont 1 to RoboFont 3, you can use the script below to convert your accents data into a string of glyph constructions.

'''accentsDict2GlyphConstruction'''

#: A dictionary with data for building accented glyphs, as typically used with RoboFab's RFont.compileGlyph()
accentsDict = {
    # accented   : [ base, ( (accent1, anchor1), (accent2, anchor2), ... ) ],
    'aogonek'    : [ 'a',  ( ('ogonek', 'bottom'), ) ],
    'agrave'     : [ 'a',  ( ('grave', 'top'), ) ],
    'ccedilla'   : [ 'c',  ( ('cedilla', 'bottom'), ) ],
    'aringacute' : [ 'a',  ( ('ring', 'top'), ('acute', 'top'), ) ],
}

def accentsDict2GlyphConstruction(accentsDict, useSpaces=True):
    '''Converts glyph building recipes from dictionary to Glyph Construction syntax.'''

    # create an empty string to collect all GlyphConstruction rules
    glyphConstruction = ''

    # iterate over the accented glyphs dict
    for accentedGlyph in accentsDict:

        # get base glyph and accents for this accented glyph
        baseGlyph, accents = accentsDict[accentedGlyph]

        # start a glyph construction rule for this glyph:
        # accentedGlyph = baseGlyph + (some accents)
        glyphConstruction += '%s = %s + ' % (accentedGlyph, baseGlyph)

        # iterate over all accents in accented glyph, using a counter
        for i, (accentName, anchor) in enumerate(accents):
            # if accent is not the first, add a '+' before it
            if not i == 0:
                glyphConstruction += ' + '
            # add accent name and anchor name to glyph construction rule
            glyphConstruction += '%s@%s' % (accentName, anchor)

        # done with this accented glyph; go to the next line
        glyphConstruction += '\n'

    # remove all spaces
    if not useSpaces:
        glyphConstruction = glyphConstruction.replace(' ', '')

    # done!
    return glyphConstruction

# convert accents dict to glyph construction
glyphConstruction = accentsDict2GlyphConstruction(accentsDict, useSpaces=False)
print(glyphConstruction)

Useful extensions

Last edited on 11/06/2019