Generating Woff2 via instance.generate()

I’m trying to generate a full range of files but I’m stuck on woff2. Am I missing something for the argument? The file that gets generated appears to be a woff as it is the same size as a woff.

This is my current function :

instance.generate(Format = "WOFF2", FontPath = os.path.expanduser(web_path + "/" + font.familyName + " - " + font.masters[0].name + ".woff2"), AutoHint = TTF_AutoHint, RemoveOverlap = RemoveOverlap, UseSubroutines = UseSubroutines, UseProductionNames = UseProductionNames)

This is my code ( or rather a little of mine and a lot of examples I plundered online) :

# MenuTitle: Batch Generate Fonts
# -*- coding: utf-8 -*-
__doc__=""" Batch Generate Fonts. """

import os
from robofab.interface.all.dialogs import GetFolder
fileFolder = GetFolder("Pick a directory...")

folderPath = '~/Desktop/TEMP_FONT_INSTANCES'
folderPathRelative = os.path.expanduser(folderPath)
if not os.path.exists(folderPathRelative):
    os.makedirs(folderPathRelative)

otf_path = folderPath + "/otf"
otf_pathRelative = os.path.expanduser(otf_path)
if not os.path.exists(otf_pathRelative):
    os.makedirs(otf_pathRelative)

ttf_path = folderPath + "/ttf"
ttf_pathRelative = os.path.expanduser(ttf_path)
if not os.path.exists(ttf_pathRelative):
    os.makedirs(ttf_pathRelative)

ufo_path = folderPath + "/ufo"
ufo_pathRelative = os.path.expanduser(ufo_path)
if not os.path.exists(ufo_pathRelative):
    os.makedirs(ufo_pathRelative)

web_path = folderPath + "/web"
web_pathRelative = os.path.expanduser(web_path)
if not os.path.exists(web_pathRelative):
    os.makedirs(web_pathRelative)

fileFolder = os.path.expanduser(fileFolder)
fileNames = os.listdir(fileFolder)
OTF_AutoHint = True
TTF_AutoHint = True
RemoveOverlap = True
UseSubroutines = True
UseProductionNames = True

for fileName in fileNames:
	if os.path.splitext(fileName)[1] == ".glyphs":
		font = GSFont(os.path.join(fileFolder, fileName))
		print font.familyName
		for instance in font.instances:
			print "== Exporting OTF --> " + otf_path + "/" + font.familyName + " - " + font.masters[0].name + ".otf"
			instance.generate(Format = "OTF", FontPath = os.path.expanduser(otf_path + "/" + font.familyName + " - " + font.masters[0].name + ".otf"), AutoHint = OTF_AutoHint, RemoveOverlap = RemoveOverlap, UseSubroutines = UseSubroutines, UseProductionNames = UseProductionNames)
		print
		for instance in font.instances:
			print "== Exporting TTF --> " + ttf_path + "/" + font.familyName + " - " + font.masters[0].name + ".ttf"
			instance.generate(Format = "TTF", FontPath = os.path.expanduser(ttf_path + "/" + font.familyName + " - " + font.masters[0].name + ".ttf"), AutoHint = TTF_AutoHint, RemoveOverlap = RemoveOverlap, UseProductionNames = UseProductionNames)
		print
		for instance in font.instances:
			print "== Exporting WOFF --> " + web_path + "/" + font.familyName + " - " + font.masters[0].name + ".woff"
			instance.generate(Format = "WOFF", FontPath = os.path.expanduser(web_path + "/" + font.familyName + " - " + font.masters[0].name + ".woff"), AutoHint = TTF_AutoHint, RemoveOverlap = RemoveOverlap, UseSubroutines = UseSubroutines, UseProductionNames = UseProductionNames)
		print
		for instance in font.instances:
			print "== Exporting WOFF 2 --> " + web_path + "/" + font.familyName + " - " + font.masters[0].name + ".woff2"
			instance.generate(Format = "WOFF2", FontPath = os.path.expanduser(web_path + "/" + font.familyName + " - " + font.masters[0].name + ".woff2"), AutoHint = TTF_AutoHint, RemoveOverlap = RemoveOverlap, UseSubroutines = UseSubroutines, UseProductionNames = UseProductionNames)
		print

The generate() method currently only supports OTF and TTF. I’ll have a look if I can improve this.

OH NO! they are ttfs dressed as woffs. :frowning:

Is it possible to generate woff and woff2 without the GUI?

Yes. But with a bit more effort.

I try to put together some code. And I had a look at the instance.generate() method. It is a bit more work to make that happen.

1 Like

So do you think Glyphs will support this in the next/next few updates? or should I commit to finding an alternative method?

It is possible already but not with the convenient .generare() method. I’ll put some code together (tomorrow).

1 Like

Thank you!

It is simpler than I tough :wink:

instanceFont = Font.instances[2].interpolatedFont
print instance
instanceFont.instances[0].customParameters["Webfont Formats"] = "woff2"
instanceFont.instances[0].generate(Format = "TTF", FontPath = "/Path/To/Fonts/Folder")

If you set the Webfont Formats parameter in your instances manually, you can only need the last line.

1 Like

So a few issues.

When generating woff/2 you don’t have control over the filename. I believe it generates automatically from the family name. Is it possible to adjust for this?

ex.

import os
from robofab.interface.all.dialogs import GetFolder

fileFolder = GetFolder("Pick a directory...")
folderPath = '~/Desktop/TEMP_FONT_INSTANCES'
folderPathRelative = os.path.expanduser(folderPath)
if not os.path.exists(folderPathRelative):
    os.makedirs(folderPathRelative)

web_path = folderPath + "/web"
web_pathRelative = os.path.expanduser(web_path)
if not os.path.exists(web_pathRelative):
    os.makedirs(web_pathRelative)

fileFolder = os.path.expanduser(fileFolder)
fileNames = os.listdir(fileFolder)
OTF_AutoHint = True
TTF_AutoHint = True
RemoveOverlap = True
UseSubroutines = True
UseProductionNames = True

for fileName in fileNames:
	if os.path.splitext(fileName)[1] == ".glyphs":
		for instance in font.instances:
			print "== Exporting WOFF --> " + web_path + "/file_name.woff"
			instance.customParameters["Webfont Formats"] = "woff"
			instance.generate(Format = "TTF", FontPath = os.path.expanduser(web_path + "/file_name.woff"), AutoHint = TTF_AutoHint, RemoveOverlap = RemoveOverlap, UseSubroutines = UseSubroutines, UseProductionNames = UseProductionNames)
		print

Secondly — my script is causing autosaves on the fonts I generate. Is it possible to close/remove them?

your scrip is missing the copy post from my snippet. That is specifically added to prevent changing the original document.
And there is a “fileName” parameter in the instances (check the actual spelling, I’m not at the Mac right now).

Thank you for all your help. :sob:
I can’t find in the API documentation a list of possible custom parameters.
Does this exist, can I generate it? print help(instanceFont.instances[0].customParameters)? How do I check the actual spelling?

To confirm
Copying the instance removes autosave files?
I can define the file name via customParemeters[“File Name or something”] instead of the FontPath?

import os
from robofab.interface.all.dialogs import GetFolder

fileFolder = GetFolder("Pick a directory...")
folderPath = '~/Desktop/TEMP_FONT_INSTANCES'
folderPathRelative = os.path.expanduser(folderPath)
if not os.path.exists(folderPathRelative):
    os.makedirs(folderPathRelative)

web_path = folderPath + "/web"
web_pathRelative = os.path.expanduser(web_path)
if not os.path.exists(web_pathRelative):
    os.makedirs(web_pathRelative)

fileFolder = os.path.expanduser(fileFolder)
fileNames = os.listdir(fileFolder)

for fileName in fileNames:
	if os.path.splitext(fileName)[1] == ".glyphs":
		font = GSFont(os.path.join(fileFolder, fileName))
		saveFileName = font.filepath.lastPathComponent().replace(".ufo", "").replace(".glyphs", "").replace(".vfb", "")
		for instance in font.instances:
			print "== Exporting WOFF --> " + web_path + "/"
			instanceFont = instance.interpolatedFont # Copying the instance remove autosave files
			instanceFont.instances[0].customParameters["Webfont Formats"] = "woff2"
			instanceFont.instances[0].customParameters["File Name"] = saveFileName + ".woff2" # File Name is defined here
			instanceFont.instances[0].generate(Format = "TTF", FontPath = os.path.expanduser(web_path))
		print

Sorry I’m still new to python and glyphs.

The custom parameters are not documented in the python docu but in the appendix of the Handbook. Or just see what is available in the master/instance settings.

Thanks, works like a charm.

import os
from robofab.interface.all.dialogs import GetFolder

fileFolder = GetFolder("Pick a directory...")
folderPath = '~/Desktop/TEMP_FONT_INSTANCES'
folderPathRelative = os.path.expanduser(folderPath)
if not os.path.exists(folderPathRelative):
    os.makedirs(folderPathRelative)

web_path = folderPath + "/web"
web_pathRelative = os.path.expanduser(web_path)
if not os.path.exists(web_pathRelative):
    os.makedirs(web_pathRelative)

fileFolder = os.path.expanduser(fileFolder)
fileNames = os.listdir(fileFolder)

for fileName in fileNames:
	if os.path.splitext(fileName)[1] == ".glyphs":
		font = GSFont(os.path.join(fileFolder, fileName))
		saveFileName = font.filepath.lastPathComponent().replace(".ufo", "").replace(".glyphs", "").replace(".vfb", "")
		for instance in font.instances:
			print "== Exporting WOFF --> " + web_path + "/"
			instanceFont = instance.interpolatedFont # Copying the instance remove autosave files
			instanceFont.instances[0].customParameters["Webfont Formats"] = "woff2"
			instanceFont.instances[0].customParameters["fileName"] = saveFileName # File Name is defined here
			instanceFont.instances[0].generate(Format = "TTF", FontPath = os.path.expanduser(web_path))
		print

Via https://glyphsapp.com/downloads/handbook/Glyphs-Handbook-2.3.pdf p.184

fileName string Name for the font file, without the dot suffix, i.e.,
without ‘.otf’, etc. Gives you the chance to export two versions
of the same font style name without the second file overwriting
the first one

After the last update the script I’ve been working with has stopped working.
The script shown above now errs:

Traceback (most recent call last):
  File "<string>", line 24, in <module>
  File "GlyphsApp/GlyphsApp/__init__.py", line 3634, in <lambda>
  File "GlyphsApp/GlyphsApp/__init__.py", line 3632, in Instance_FontObject
TypeError: 'NSKVONotifying_GSFont' object is not callable

Do you know how I can begin debugging this?

I fixed that already. Will update soon.

1 Like

@GeorgSeifert
Any news on exporting Webfonts like that? I got an rather old script which doesn’t export the webfonts anymore. It did work way back.


When I run this code from Quinn posted above but adding a traceback, I get this:

Traceback (most recent call last):
  File "<string>", line 28, in <module>
  File "GlyphsApp/GlyphsApp/__init__.py", line 4254, in __Instance_Export__
ValueError: NSInvalidArgumentException - -[NSTaggedPointerString count]: unrecognized selector sent to instance 0xa4874c57d14229a5

I tried to export webfonts from Glyphs UI and Glyphs crashed, when I had a CP “Webfont Formats”
(for testing. I sent the report).

When I have the CP [“Webfont Formats” = woff2] in one instance (again for testing) and want to export Webfonts from GUI (Setting to WOFF and WOFF2), I get these errors:
There was a problem converting the PostScript source font. (Light)
and
The file “XYZ-Thin.woff2” couldn’t be opened because there is no such file.

1 Like

The code above is not how you do it:

for instance in Font.instances:
	instance.generate(FontPath=Font.filepath, Format=TTF, Containers=["WOFF", "WOFF2"])
3 Likes

Awesome! Thank you so much! :clap: