def main(): global doNotSave start = time.time() doNotSave = False filename = sys.argv[-1] font = GSFont(filename) # Store classes and features classes = parseOpenType(font.classes, [], " ") features = parseOpenType(font.features, [], "\n") # Gets number of axes and stores in a dictionary fontAxes = getAxes(font) # Set origin master to determine which layers are used in the duplicate glyph VfOrigin = getVfOrigin(font) weightDict = { "Thin": 100, "ExtraLight": 200, "UltraLight": 200, "Light": 300, "Normal": 400, "Regular": 400, "Medium": 500, "DemiBold": 600, "SemiBold": 600, "Bold": 700, "UltraBold": 800, "ExtraBold": 800, "Black": 900, "Heavy": 900, } # Checks all masters and updates fontAxes dictionary min/max values # Checks all instances and stores scaled min/def/max values # TODO add ability to check virtual master ranges parseAxesValues(font, fontAxes, VfOrigin, weightDict) needsDup = [] logged = {} noComponents = {} # Recursively goes through all glyphs and determines if they will need a duplicate glyph needsDup = getBracketGlyphs(font, needsDup, logged, noComponents) substitution = "import os\nimport sys\nimport fontTools\nfrom fontTools.ttLib import TTFont\nfrom fontTools.varLib.featureVars import addFeatureVariations\n\nfontPath = sys.argv[-1]\n\nf = TTFont(fontPath)\n\ncondSubst = [\n" substitution = setupBracketGlyphs(font, needsDup, features, classes, VfOrigin, logged, fontAxes, substitution) updateOpenType(font, font.classes, classes, " ") updateOpenType(font, font.features, features, "\n") saveFont(font, filename, start, substitution)
def main(): args = parser.parse_args() for font_path in args.font: font = GSFont(font_path) print('Copyright: "{}"'.format(font.copyright)) print('VendorID: "{}"'.format(customparam(font, "vendorID"))) print('fsType: {}'.format(customparam(font, "fsType"))) print('license: "{}"'.format(customparam(font, "license"))) print('licenseURL: "{}"'.format(customparam(font, "licenseURL")))
def main(): parser = argparse.ArgumentParser(description="Build Rana Kufi.") parser.add_argument("glyphs", help="input Glyphs source file") parser.add_argument("version", help="font version") parser.add_argument("otf", help="output OTF file") args = parser.parse_args() font = GSFont(args.glyphs) prepare(font) instance = font.instances[0] # XXX otf = build(instance, args) otf.save(args.otf)
def build(args): font = GSFont(args.file) # Set metadata major, minor = args.version.split(".") font.versionMajor, font.versionMinor = int(major), int(minor) font.copyright = font.copyright.format(year=datetime.now().year) builder = UFOBuilder( font, propagate_anchors=False, write_skipexportglyphs=True, store_editor_state=False, ) for master in builder.masters: if master.info.styleName == args.master: ufo = master break anchors = {} curs = [] curs.append("lookupflag RightToLeft IgnoreMarks;") for glyph in ufo: for anchor in glyph.anchors: if anchor.name in ("entry", "exit"): anchors.setdefault(glyph.name, [None, None]) anchors[glyph.name][0 if anchor.name == "entry" else 1] = anchor for glyph, (entry, exit_) in anchors.items(): curs.append( f"pos cursive {glyph} {_dumpAnchor(entry)} {_dumpAnchor(exit_)};") curs = "\n".join(curs) + "\n" ufo.features.text = ufo.features.text.replace("# Automatic Code Cursive", curs) compileTTF(ufo, inplace=True, flattenComponents=True, useProductionNames=False).save(args.out_file)
def main(): parser = argparse.ArgumentParser(description="Build Rana Kufi.") parser.add_argument("glyphs", help="input Glyphs source file") parser.add_argument("otf", help="output OTF file") parser.add_argument("--debug", help="Save debug files", action="store_true") args = parser.parse_args() font = GSFont(args.glyphs) prepare(font) otf = buildVF(font, args) otf.save(args.otf)
def main(): parser = argparse.ArgumentParser(description="Build Rana Kufi.") parser.add_argument("glyphs", help="input Glyphs source file") parser.add_argument("version",help="font version") parser.add_argument("otf", help="output OTF file") parser.add_argument("cidinfo",help="output CID info file") parser.add_argument("cidmap", help="output CID map file") args = parser.parse_args() font = GSFont(args.glyphs) prepare(font) instance = font.instances[0] # XXX otf, cidinfo, cidmap = build(instance, args) with open(args.cidinfo, "w") as fp: fp.write(cidinfo) with open(args.cidmap, "w") as fp: fp.write(cidmap) otf.save(args.otf)
def main(): from argparse import ArgumentParser from pathlib import Path parser = ArgumentParser(description="Build Qahiri font.") parser.add_argument("input", help="input Glyphs source file", type=Path) parser.add_argument("version", help="font version", type=float) parser.add_argument("output", help="output font file", type=Path) args = parser.parse_args() isTTF = False if args.output.suffix == ".ttf": isTTF = True font = GSFont(args.input) prepare(font, isTTF) instance = font.instances[0] # XXX otf = build(instance, isTTF, args.version) otf.save(args.output)
def buildVF(opts): font = GSFont(opts.glyphs) glyphOrder = buildAltGlyphs(font) prepare(font) for instance in font.instances: print(f" MASTER {instance.name}") build(instance, opts, glyphOrder) if instance.name == "Regular": regular = instance ds = DesignSpaceDocument() for i, axisDef in enumerate(font.axes): axis = ds.newAxisDescriptor() axis.tag = axisDef.axisTag axis.name = axisDef.name axis.maximum = max(x.axes[i] for x in font.instances) axis.minimum = min(x.axes[i] for x in font.instances) axis.default = regular.axes[i] ds.addAxis(axis) for instance in font.instances: source = ds.newSourceDescriptor() source.font = instance.font source.familyName = instance.familyName source.styleName = instance.name source.name = instance.fullName source.location = { a.name: instance.axes[i] for i, a in enumerate(ds.axes) } ds.addSource(source) print(f" MERGE {font.familyName}") otf, _, _ = merge(ds) subroutinize(otf) if not opts.debug: otf["post"].formatType = 3.0 return otf
def main(): font = GSFont(SOURCE_PATH) glyph_list = [] # parse definitions file, define ColorDefinitions object cfp = ColorFileParser(KEY_PATH) color_defs = cfp.parse() # parse source code for color settings # and create GlyphObj objects with color attributes for glyph in font.glyphs: # integer for GlyphsApp color if present # None if color is absent glyph_color = glyph.color # string glyph_name = glyph.name # list of strings glyph_unicode = glyph.unicode # date / time formatted as 2019-01-18 15:04:57 if present # None if no edits have been made to the glyph # glyph_changetime = glyph.lastChange if glyph_color is not None: color = Color(glyph_color) gco = GlyphColorObj(glyph_name, glyph_unicode, color, color_defs) else: # default state if no color detected is WHITE gco = GlyphColorObj(glyph_name, glyph_unicode, Color.WHITE, color_defs) glyph_list.append(gco) for glyphobj in glyph_list: print("[{} {}] : {} {}".format(glyphobj.name, glyphobj.unicode_hex, glyphobj.color_name, glyphobj.value))
import sys import os import re import time import copy from glyphsLib import GSFont from glyphsLib import GSGlyph from glyphsLib import GSLayer filename = sys.argv[-1] font = GSFont(filename) delMasters = [] delInstances = [] font.familyName = "Cabin Condensed" i = 0 for master in font.masters: if re.match('.*Condensed.*', master.name) == None: for glyph in font.glyphs: for layer in glyph.layers: if layer.layerId == master.id or layer.associatedMasterId == master.id: del glyph.layers[layer.layerId] font.kerning.pop(master.id) delMasters.append(i) i = i - 1 else: master.name = re.sub(' *Condensed *', '', master.name) i = i + 1
# Make a .glyphs file with only brace glyphs, export these files in Glyphs App as variable fonts, and the build script will swap these out in the final VF import sys import re from glyphsLib import GSFont from glyphsLib import GSGlyph from glyphsLib import GSLayer file = sys.argv[1] font = GSFont(file) print "\tPreparing %s" % file # Append Italic to font family naame if Italics style = sys.argv[2] if style == "Italic": font.familyName = "%s %s" % (font.familyName, style) # Clear all features font.features = [] font.classes = [] font.featurePrefixes = [] # Remove Rename Glyphs custom parameter for instance in font.instances: for customParam in instance.customParameters: if customParam.name == "Rename Glyphs": del customParam # Find brace glyphs listOfBraceGlyphs = [] for eachGlyph in font.glyphs:
#!/usr/bin/env python3 import sys from glyphsLib import GSFont font = GSFont(sys.argv[1]) glyphs = [g.layers[0] for g in font.glyphs if len(g.layers[0].anchors) > 0] for g in glyphs: print("Anchors %s {" % g.parent.name) for a in g.anchors: print(" %s <%i %i>" % (a.name, *a.position)) print("};\n")
import sys from glyphsLib import GSFont filename = sys.argv[-1] font = GSFont(filename) # get font name, remove spaces varFontName = font.familyName.replace(' ', '') + '-VF' print(varFontName) sys.exit(0)
""" Set metrics in all masters of a Glyphs source to easily adjust metrics with a minimum of clicking and typing. Update values, then run once. USAGE: You must have glyphsLib installed, for instance via `pip install glyphsLib`. Then, run this via the terminal, adding the path to a Glyphs source: python3 sources/scripts/set-metrics.py sources/LibreCaslonText.glyphs """ from glyphsLib import GSFont import sys filepath = sys.argv[1] font = GSFont(filepath) for master in font.masters: master.customParameters["hheaAscender"] = 1940 master.customParameters["hheaDescender"] = -520 master.customParameters["hheaLineGap"] = 0 master.customParameters["typoAscender"] = 1940 master.customParameters["typoDescender"] = -520 master.customParameters["typoLineGap"] = 0 master.customParameters["winAscent"] = 1696 master.customParameters["winDescent"] = 531 font.save(filepath)
# Create build glyphs file : # Turn on Export for Bracket Glyphs and disable non ttf instances # Add extra opentype code for rvrn glyphs that are substituted by another feature as well so that there is a logical path to allow resubstitution, these are manually defined. import sys from glyphsLib import GSFont from glyphsLib import GSGlyph file = sys.argv[1] font = GSFont(file) print("\tPreparing %s" % file) # List of Glyphs which should have export enabled - in the Glyphs App static fonts export these are not active but get swapped with a custom parameter, for the VFs though they needs to be exported italicBracketGlyphs = [ "cedi.rvrn", "colonsign.rvrn", "guarani.rvrn", "cent.rvrn", "dollar.rvrn", "dollar.tf.rvrn", "cent.tf.rvrn", "naira.rvrn", "peseta.rvrn", "won.rvrn", "peso.rvrn", "curvedStemParagraphSignOrnament.rvrn", "paragraph.rvrn" ] uprightBracketGlyphs = italicBracketGlyphs + [ "apple.rvrn", "Adieresis.rvrn", "Odieresis.rvrn", "Udieresis.rvrn", "Adieresis.titl.rvrn", "Odieresis.titl.rvrn", "Udieresis.titl.rvrn", ] # Extra FEA code so that the glyphs swapped by rvrn can be substituted again by another opentype feature
import sys import os import re from glyphsLib import GSFont from glyphsLib import GSGlyph filename = sys.argv[-1] font = GSFont(filename) nonExportGlyphs = [] baseIndex = 0 for glyph in font.glyphs: for layer in glyph.layers: if re.match('.*\}.*', layer.name) != None: layer.name = 'Brace Off' elif re.match('.*\].*', layer.name) != None: layer.name = 'Bracket Off' font.familyName = "Hepta Slab Hairline" font.instances[0].active = True del font.instances[1:] font.save(filename)
# Make a .glyphs file with only brace glyphs, export these files in Glyphs App as variable fonts, and the build script will swap these out in the final VF import sys import re from glyphsLib import GSFont from glyphsLib import GSGlyph from glyphsLib import GSLayer file = sys.argv[1] font = GSFont(file) print("\tPreparing %s" % file) # Append Italic to font family naame if Italics style = sys.argv[2] if style == "Italic": font.familyName = "%s %s" % (font.familyName, style) # Clear all features font.features = [] font.classes = [] font.featurePrefixes = [] # Remove Rename Glyphs custom parameter for instance in font.instances: for customParam in instance.customParameters: if customParam.name == "Rename Glyphs": del customParam # Find brace glyphs listOfBraceGlyphs = [] for eachGlyph in font.glyphs:
def main(args=None): """Test for interpolatability issues between fonts""" import argparse parser = argparse.ArgumentParser( "fonttools varLib.interpolatable", description=main.__doc__, ) parser.add_argument( "--json", action="store_true", help="Output report in JSON format", ) parser.add_argument("inputs", metavar="FILE", type=str, nargs="+", help="Input TTF/UFO files") args = parser.parse_args(args) glyphs = None # glyphs = ['uni08DB', 'uniFD76'] # glyphs = ['uni08DE', 'uni0034'] # glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina'] from os.path import basename fonts = [] names = [] if len(args.inputs) == 1: if args.inputs[0].endswith('.designspace'): from fontTools.designspaceLib import DesignSpaceDocument designspace = DesignSpaceDocument.fromfile(args.inputs[0]) args.inputs = [master.path for master in designspace.sources] elif args.inputs[0].endswith('.glyphs'): from glyphsLib import GSFont, to_ufos gsfont = GSFont(args.inputs[0]) fonts.extend(to_ufos(gsfont)) names = [ '%s-%s' % (f.info.familyName, f.info.styleName) for f in fonts ] args.inputs = [] elif args.inputs[0].endswith('.ttf'): from fontTools.ttLib import TTFont font = TTFont(args.inputs[0]) if 'gvar' in font: # Is variable font gvar = font['gvar'] # Gather all "master" locations locs = set() for variations in gvar.variations.values(): for var in variations: loc = [] for tag, val in sorted(var.axes.items()): loc.append((tag, val[1])) locs.add(tuple(loc)) # Rebuild locs as dictionaries new_locs = [{}] for loc in sorted(locs, key=lambda v: (len(v), v)): names.append(str(loc)) l = {} for tag, val in loc: l[tag] = val new_locs.append(l) locs = new_locs del new_locs # locs is all master locations now for loc in locs: fonts.append( font.getGlyphSet(location=loc, normalized=True)) args.inputs = [] for filename in args.inputs: if filename.endswith(".ufo"): from fontTools.ufoLib import UFOReader fonts.append(UFOReader(filename)) else: from fontTools.ttLib import TTFont fonts.append(TTFont(filename)) names.append(basename(filename).rsplit(".", 1)[0]) if hasattr(fonts[0], 'getGlyphSet'): glyphsets = [font.getGlyphSet() for font in fonts] else: glyphsets = fonts problems = test(glyphsets, glyphs=glyphs, names=names) if args.json: import json print(json.dumps(problems)) else: for glyph, glyph_problems in problems.items(): print(f"Glyph {glyph} was not compatible: ") for p in glyph_problems: if p["type"] == "missing": print(" Glyph was missing in master %s" % p["master"]) if p["type"] == "open_path": print(" Glyph has an open path in master %s" % p["master"]) if p["type"] == "path_count": print(" Path count differs: %i in %s, %i in %s" % (p["value_1"], p["master_1"], p["value_2"], p["master_2"])) if p["type"] == "node_count": print( " Node count differs in path %i: %i in %s, %i in %s" % ( p["path"], p["value_1"], p["master_1"], p["value_2"], p["master_2"], )) if p["type"] == "node_incompatibility": print( " Node %o incompatible in path %i: %s in %s, %s in %s" % ( p["node"], p["path"], p["value_1"], p["master_1"], p["value_2"], p["master_2"], )) if p["type"] == "contour_order": print(" Contour order differs: %s in %s, %s in %s" % ( p["value_1"], p["master_1"], p["value_2"], p["master_2"], )) if p["type"] == "wrong_start_point": print(" Contour start point differs: %s, %s" % ( p["master_1"], p["master_2"], )) if problems: return problems
# Create build glyphs file : # Turn on Export for Bracket Glyphs and disable non ttf instances # Add extra opentype code for rvrn glyphs that are substituted by another feature as well so that there is a logical path to allow resubstitution, these are manually defined. import sys from glyphsLib import GSFont from glyphsLib import GSGlyph file = sys.argv[1] font = GSFont(file) print "\tPreparing %s" % file # List of Glyphs which should have export enabled - in the Glyphs App static fonts export these are not active but get swapped with a custom parameter, for the VFs though they needs to be exported italicBracketGlyphs = [ "cedi.rvrn", "colonsign.rvrn", "guarani.rvrn", "cent.rvrn", "dollar.rvrn", "dollar.tf.rvrn", "cent.tf.rvrn", "naira.rvrn", "peseta.rvrn", "won.rvrn", "peso.rvrn", "curvedStemParagraphSignOrnament.rvrn", "paragraph.rvrn" ] uprightBracketGlyphs = italicBracketGlyphs + [
# -*- coding: utf-8 -*- # # This script demonstrates how to iterate through glyphs in a GlyphsApp *.glyphs source file # and parse glyph-specific metadata # # Dependencies for this script can be installed with: # # $ pip3 install --upgrade glyphsLib # from glyphsLib import GSFont SOURCE_PATH = "../glyphs_source/GenericSans-GreenHighlight.glyphs" font = GSFont(SOURCE_PATH) for glyph in font.glyphs: # integer for GlyphsApp color if present # None if color is absent glyph_color = glyph.color # string glyph_name = glyph.name # list of strings glyph_unicode = glyph.unicode # date / time formatted as 2019-01-18 15:04:57 if present # None if no edits have been made to the glyph glyph_changetime = glyph.lastChange print("{} - {} - {} - {}".format(glyph_name, glyph_unicode, glyph_color,
import sys import os import re import time import copy from glyphsLib import GSFont from glyphsLib import GSGlyph from glyphsLib import GSLayer filename = sys.argv[-1] font = GSFont(filename) delMasters = [] delInstances = [] delAxes = [] i = 0 for master in font.masters: if re.match('.*Oblique.*', master.name) != None: for glyph in font.glyphs: delLayers = [] for layer in glyph.layers: if layer.layerId == master.id or layer.associatedMasterId == master.id: delLayers.append(layer.layerId) for layerId in delLayers: del glyph.layers[layerId] delMasters.append(i) i = i - 1 else: for glyph in font.glyphs: delLayers = []
import sys from glyphsLib import GSFont def settransformedcomponents(f): glyphs = [] # Collect glyphs for glyph in f.glyphs: for layer in glyph.layers: for i, component in enumerate(layer.components): if component.transform[0] != 1 or component.transform[3] != 1: if [glyph, len(layer.components), i] not in glyphs: glyphs.append([glyph, len(layer.components), i]) # Adjust transform for glyph, component_count, i in glyphs: for layer in glyph.layers: if component_count == len(layer.components): if layer.components[i].transform[0] == 1: layer.components[i].transform[0] = 0.999 if layer.components[i].transform[3] == 1: layer.components[i].transform[3] = 0.999 if __name__ == "__main__": font = GSFont(sys.argv[-1]) settransformedcomponents(font) font.save(sys.argv[-1])