Skip to content

Instantly share code, notes, and snippets.

@anthrotype
Created March 20, 2020 19:08
Show Gist options
  • Select an option

  • Save anthrotype/c11515065a4aa6549f9d5f2dfdcf8f23 to your computer and use it in GitHub Desktop.

Select an option

Save anthrotype/c11515065a4aa6549f9d5f2dfdcf8f23 to your computer and use it in GitHub Desktop.
from fontTools import designspaceLib
import ufo2ft
import ufoLib2
UPEM = 1000
WIDTH = UPEM // 2
FAMILY_NAME = "MyAwesomeVariableFont"
def _draw_outline(pen, commands):
for operator, operands in commands:
getattr(pen, operator)(*operands)
def _make_ufo(family_name, style_name, glyphs, upem=UPEM):
ufo = ufoLib2.Font()
ufo.info.familyName = family_name
ufo.info.styleName = style_name
ufo.info.unitsPerEm = upem
glyph_order = []
for glyph_data in glyphs:
glyph_name = glyph_data["name"]
g = ufo.newGlyph(glyph_name)
g.width = glyph_data.get("width", WIDTH)
g.unicode = glyph_data.get("unicode")
_draw_outline(g.getPen(), glyph_data.get("outline", []))
glyph_order.append(glyph_name)
ufo.glyphOrder = glyph_order
return ufo
if __name__ == "__main__":
import sys
# first, build the source UFO masters, making sure the glyph outlines are
# interpolatable: i.e. same contour length and segment types, possibly
# different point coordinates
rg_ufo = _make_ufo(
FAMILY_NAME,
"Regular",
glyphs=[
dict(name="space", unicode=0x0020),
dict(
name="a",
unicode=0x0061,
width=600,
outline=[
("moveTo", ((200, 0),)),
("lineTo", ((200, 500),)),
("lineTo", ((400, 500),)),
("lineTo", ((400, 0),)),
("closePath", ()),
],
),
],
)
bd_ufo = _make_ufo(
family_name=FAMILY_NAME,
style_name="Bold",
glyphs=[
dict(name="space", unicode=0x0020),
dict(
name="a",
unicode=0x0061,
width=600,
outline=[
("moveTo", ((100, 0),)),
("lineTo", ((100, 550),)),
("lineTo", ((500, 550),)),
("lineTo", ((500, 0),)),
("closePath", ()),
],
),
],
)
cd_ufo = _make_ufo(
family_name=FAMILY_NAME,
style_name="Condensed",
glyphs=[
dict(name="space", unicode=0x0020),
dict(
name="a",
unicode=0x0061,
width=400,
outline=[
("moveTo", ((100, 0),)),
("lineTo", ((100, 500),)),
("lineTo", ((300, 500),)),
("lineTo", ((300, 0),)),
("closePath", ()),
],
),
],
)
cdbd_ufo = _make_ufo(
family_name=FAMILY_NAME,
style_name="CondensedBold",
glyphs=[
dict(name="space", unicode=0x0020),
dict(
name="a",
unicode=0x0061,
width=400,
outline=[
("moveTo", ((50, 0),)),
("lineTo", ((50, 550),)),
("lineTo", ((350, 550),)),
("lineTo", ((350, 0),)),
("closePath", ()),
],
),
],
)
# create a new designspace document
designspace = designspaceLib.DesignSpaceDocument()
# define axes names, tags and min/default/max
for axis_data in [
dict(name="Weight", tag="wght", minimum=400, default=400, maximum=700),
dict(name="Width", tag="wdth", minimum=50, default=100, maximum=100),
]:
designspace.addAxisDescriptor(**axis_data)
# assign each master a location in the designspace. Ensure that at least
# one master is at the default location along all the axes as defined above;
# this will be treated as the 'neutral' or default master.
for location, ufo in [
({"Weight": 400, "Width": 100}, rg_ufo), # this is our default master
({"Weight": 700, "Width": 100}, bd_ufo),
({"Weight": 400, "Width": 50}, cd_ufo),
({"Weight": 700, "Width": 50}, cdbd_ufo),
]:
# the source.name is an optional identifier only used for error messages;
# it could be omitted if you like
source_name = f"{ufo.info.familyName}-{ufo.info.styleName}"
designspace.addSourceDescriptor(name=source_name, location=location, font=ufo)
# optionally, define the location and style name of named instances
for style_name, location in [
("Regular", {"Weight": 400, "Width": 100}),
("Medium", {"Weight": 500, "Width": 100}),
("SemiBold", {"Weight": 600, "Width": 100}),
("Bold", {"Weight": 700, "Width": 100}),
("Condensed", {"Weight": 400, "Width": 75}),
("Condensed Medium", {"Weight": 500, "Width": 75}),
("Condensed SemiBold", {"Weight": 600, "Width": 75}),
("Condensed Bold", {"Weight": 700, "Width": 75}),
("UltraCondensed", {"Weight": 400, "Width": 50}),
("UltraCondensed Medium", {"Weight": 500, "Width": 50}),
("UltraCondensed SemiBold", {"Weight": 600, "Width": 50}),
("UltraCondensed Bold", {"Weight": 700, "Width": 50}),
]:
designspace.addInstanceDescriptor(styleName=style_name, location=location)
# print(designspace.tostring().decode())
# build a variable TTFont from the designspace document
vf = ufo2ft.compileVariableTTF(designspace)
try:
outfile = sys.argv[1]
except IndexError:
sys.exit("error: must provide an output file")
vf.save(outfile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment