Skip to content

Instantly share code, notes, and snippets.

@m4rc1e
Last active April 8, 2017 14:20
Show Gist options
  • Save m4rc1e/8b9a6e5678c6628eae7e682d4de63220 to your computer and use it in GitHub Desktop.
Save m4rc1e/8b9a6e5678c6628eae7e682d4de63220 to your computer and use it in GitHub Desktop.
"""
Generate variable fonts with fontmake from .glyphs sources.
Script traverses a directory tree and will generate var fonts if it
encounters a .glyphs file with at least 2 masters and more than 3
instances, if directory matches the repository GF-Checklist spec:
https://github.com/googlefonts/gf-docs/blob/master/ProjectChecklist.md
"""
import glyphsLib
import os
from os.path import basename
import sys
import shutil
import re
SOURCE_FOLDERS = [
'source',
'sources',
]
METADATA_CATEGORIES = {
'SERIF': 'Serif',
'SANS_SERIF': 'Sans Serif',
'DISPLAY': 'Display',
'HANDWRITING': 'Handwriting',
'MONOSPACE': 'Monospace',
}
def git_url(copyright):
'''Return the url from a string
e.g:
Copyright the ABC Project Authors (https://www.github.com/mrc/sans) ->
https://www.github.com/mrc/sans
'''
try:
return re.search(r'http[a-zA-Z0-9\:\.\/]{1,256}', copyright).group(0)
except:
all
return 'None'
def find_mm_compatible_glyphs_files(path):
"""Traverse dir tree and generate ttf flavoured variable fonts from
MM compatible .glyphs files."""
families = []
for root, dirs, files in os.walk(path, topdown=False):
for f in files:
if '.glyphs' in f and basename(root) in SOURCE_FOLDERS:
glyphs_path = os.path.join(root,f)
try:
with open(glyphs_path, 'rb') as glyphs_file:
glyphs_source = glyphsLib.load(glyphs_file)
master_count = len(glyphs_source['fontMaster'])
instance_count = len(glyphs_source['instances'])
# Get fonts which successfully use MM
if master_count >= 2 and instance_count >= 3 and \
master_count != instance_count:
print 'Adding: %s' % root
families.append((glyphs_path, glyphs_source))
except: # TODO error log and catch these exceptions betters
print 'Cannot add %s' % f
all
return families
def rename_fonts(path):
for f in os.listdir(path):
if f.endswith('.ttf'):
new_f = f.replace('VTBeta', 'VFBeta')
new_f = new_f.replace('-VF.ttf', '.ttf')
old_name = os.path.join(path, f)
new_name = os.path.join(path, new_f)
os.rename(old_name, new_name)
def cleanup_folders(vf_family_dir_name):
"""Remove fontmake gen folders and rename variable_ttf folder
to familyname"""
if not os.path.isdir(vf_family_dir_name):
os.rename('variable_ttf', vf_family_dir_name)
else:
new_files = os.listdir('variable_ttf')
for f in new_files:
os.rename(
os.path.join('variable_ttf', f),
os.path.join(vf_family_dir_name, f),
)
shutil.rmtree('variable_ttf')
# Remove temp folders needed to generate variable fonts
shutil.rmtree('master_ufo')
shutil.rmtree('master_ttf_interpolatable')
def create_early_access_file(path):
"""Early Access files are used in https://fonts.google.com/earlyaccess
to determine faily catagory"""
early_acc_filename = 'EARLY_ACCESS.category'
early_acc_path = os.path.join(path, early_acc_filename)
if not early_acc_filename in os.listdir(path):
print 'Writing EARLY_ACCESS.category %s' % early_acc_path
with open(early_acc_path, 'w') as acc:
acc.write('Sans Serif')
def cp_file(src, dest):
"""If a file does not exist, copy it"""
if not os.path.exists(dest):
shutil.copyfile(src, dest)
def create_description_file(glyphs_source, path):
"""Create basic html doc from glyphs source.
May need hand editing if the copyright does not contain a url"""
with open('DESCRIPTION.en_us_temp.html', 'r') as tmp_doc:
desc_txt = tmp_doc.read()
desc_txt = desc_txt.replace(
'{{ designer }}', glyphs_source['designer']
)
proj_url = git_url(glyphs_source['copyright'])
desc_txt = desc_txt.replace('{{ git_url }}', proj_url)
desc_file = os.path.join(path, 'DESCRIPTION.en_us.html')
with open(desc_file, 'w') as desc_doc:
desc_doc.write(desc_txt)
def gen_vf_project(glyphs_path, glyphs_source, ofl_path):
"""Generate .glyph file into VF font project, based on
https://github.com/google/fonts/pull/724"""
family_name = glyphs_source['familyName']
vf_family_name = family_name + ' VF Beta'
# Generate variable font via cmdline fontmake
os.system(
"fontmake -g '%s' -o variable --family-name='%s'"
% (glyphs_path, vf_family_name)
)
ofl_family_dir = family_name.lower().replace(' ', '')
vf_family_dir = ofl_family_dir + 'vfbeta'
rename_fonts('variable_ttf')
cleanup_folders(vf_family_dir)
create_early_access_file(vf_family_dir)
create_description_file(glyphs_source, vf_family_dir)
ofl_txt = os.path.join(ofl_path, ofl_family_dir, 'OFL.txt')
vf_ofl_txt = os.path.join(vf_family_dir, 'OFL.txt')
cp_file(ofl_txt, vf_ofl_txt)
def main(path, ofl_path):
mm_families = find_mm_compatible_glyphs_files(path)
for glyphs_path, glyphs_source in mm_families:
gen_vf_project(glyphs_path, glyphs_source, ofl_path)
if __name__ == '__main__':
if len(sys.argv) != 3:
print 'ERROR: include tree path to .glyphs sources and ofl dir'
else:
main(sys.argv[1], sys.argv[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment