Spaces:
Paused
Paused
| """ | |
| Interpolate OpenType Layout tables (GDEF / GPOS / GSUB). | |
| """ | |
| from fontTools.ttLib import TTFont | |
| from fontTools.varLib import models, VarLibError, load_designspace, load_masters | |
| from fontTools.varLib.merger import InstancerMerger | |
| import os.path | |
| import logging | |
| from copy import deepcopy | |
| from pprint import pformat | |
| log = logging.getLogger("fontTools.varLib.interpolate_layout") | |
| def interpolate_layout(designspace, loc, master_finder=lambda s: s, mapped=False): | |
| """ | |
| Interpolate GPOS from a designspace file and location. | |
| If master_finder is set, it should be a callable that takes master | |
| filename as found in designspace file and map it to master font | |
| binary as to be opened (eg. .ttf or .otf). | |
| If mapped is False (default), then location is mapped using the | |
| map element of the axes in designspace file. If mapped is True, | |
| it is assumed that location is in designspace's internal space and | |
| no mapping is performed. | |
| """ | |
| if hasattr(designspace, "sources"): # Assume a DesignspaceDocument | |
| pass | |
| else: # Assume a file path | |
| from fontTools.designspaceLib import DesignSpaceDocument | |
| designspace = DesignSpaceDocument.fromfile(designspace) | |
| ds = load_designspace(designspace) | |
| log.info("Building interpolated font") | |
| log.info("Loading master fonts") | |
| master_fonts = load_masters(designspace, master_finder) | |
| font = deepcopy(master_fonts[ds.base_idx]) | |
| log.info("Location: %s", pformat(loc)) | |
| if not mapped: | |
| loc = {name: ds.axes[name].map_forward(v) for name, v in loc.items()} | |
| log.info("Internal location: %s", pformat(loc)) | |
| loc = models.normalizeLocation(loc, ds.internal_axis_supports) | |
| log.info("Normalized location: %s", pformat(loc)) | |
| # Assume single-model for now. | |
| model = models.VariationModel(ds.normalized_master_locs) | |
| assert 0 == model.mapping[ds.base_idx] | |
| merger = InstancerMerger(font, model, loc) | |
| log.info("Building interpolated tables") | |
| # TODO GSUB/GDEF | |
| merger.mergeTables(font, master_fonts, ["GPOS"]) | |
| return font | |
| def main(args=None): | |
| """Interpolate GDEF/GPOS/GSUB tables for a point on a designspace""" | |
| from fontTools import configLogger | |
| import argparse | |
| import sys | |
| parser = argparse.ArgumentParser( | |
| "fonttools varLib.interpolate_layout", | |
| description=main.__doc__, | |
| ) | |
| parser.add_argument( | |
| "designspace_filename", metavar="DESIGNSPACE", help="Input TTF files" | |
| ) | |
| parser.add_argument( | |
| "locations", | |
| metavar="LOCATION", | |
| type=str, | |
| nargs="+", | |
| help="Axis locations (e.g. wdth=120", | |
| ) | |
| parser.add_argument( | |
| "-o", | |
| "--output", | |
| metavar="OUTPUT", | |
| help="Output font file (defaults to <designspacename>-instance.ttf)", | |
| ) | |
| parser.add_argument( | |
| "-l", | |
| "--loglevel", | |
| metavar="LEVEL", | |
| default="INFO", | |
| help="Logging level (defaults to INFO)", | |
| ) | |
| args = parser.parse_args(args) | |
| if not args.output: | |
| args.output = os.path.splitext(args.designspace_filename)[0] + "-instance.ttf" | |
| configLogger(level=args.loglevel) | |
| finder = lambda s: s.replace("master_ufo", "master_ttf_interpolatable").replace( | |
| ".ufo", ".ttf" | |
| ) | |
| loc = {} | |
| for arg in args.locations: | |
| tag, val = arg.split("=") | |
| loc[tag] = float(val) | |
| font = interpolate_layout(args.designspace_filename, loc, finder) | |
| log.info("Saving font %s", args.output) | |
| font.save(args.output) | |
| if __name__ == "__main__": | |
| import sys | |
| if len(sys.argv) > 1: | |
| sys.exit(main()) | |
| import doctest | |
| sys.exit(doctest.testmod().failed) | |