| """ |
| 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) |