Created
March 20, 2020 19:08
-
-
Save anthrotype/c11515065a4aa6549f9d5f2dfdcf8f23 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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