예제 #1
0
def build(
		documentPath,
		outputUFOFormatVersion=2,
		roundGeometry=True,
		verbose=True,
		logPath=None,
		progressFunc=None,
		):
	"""

		Simple builder for UFO designspaces.

	"""
	from mutatorMath.ufo.document import DesignSpaceDocumentReader
	import os, glob
	if os.path.isdir(documentPath):
		# process all *.designspace documents in this folder
		todo = glob.glob(os.path.join(documentPath, "*.designspace"))
	else:
		# process the 
		todo = [documentPath]
	results = []
	for path in todo:
		reader = DesignSpaceDocumentReader(
				path,
		        ufoVersion=outputUFOFormatVersion,
		        roundGeometry=roundGeometry,
		        verbose=verbose,
		        logPath=logPath,
				progressFunc=progressFunc
		        )
		reader.process()
		results.append(reader.results)
	reader = None
	return results
예제 #2
0
파일: __init__.py 프로젝트: SayCV/tools-FDK
def build(
		documentPath=None,
		outputUFOFormatVersion=2,
		roundGeometry=True,
		verbose=True,
		logPath=None):
	"""

		Simple builder for UFO designspaces.

	"""
	from mutatorMath.ufo.document import DesignSpaceDocumentReader
	import os
	if documentPath is None:
		documentPath = os.path.join(os.getcwd(), "designspace.xml")
	if not os.path.exists(documentPath):
		print("Can not find document at \"%s\""%documentPath)
		return 0
	reader = DesignSpaceDocumentReader(
			documentPath,
	        ufoVersion=outputUFOFormatVersion,
	        roundGeometry=True,
	        verbose=verbose,
	        logPath=logPath)
	results = reader.process()
	return results
예제 #3
0
def build(
    documentPath,
    outputUFOFormatVersion=2,
    roundGeometry=True,
    verbose=True,
    logPath=None,
    progressFunc=None,
):
    """

		Simple builder for UFO designspaces.

	"""
    from mutatorMath.ufo.document import DesignSpaceDocumentReader
    import os, glob
    if os.path.isdir(documentPath):
        # process all *.designspace documents in this folder
        todo = glob.glob(os.path.join(documentPath, "*.designspace"))
    else:
        # process the
        todo = [documentPath]
    results = []
    for path in todo:
        reader = DesignSpaceDocumentReader(path,
                                           ufoVersion=outputUFOFormatVersion,
                                           roundGeometry=roundGeometry,
                                           verbose=verbose,
                                           logPath=logPath,
                                           progressFunc=progressFunc)
        reader.process()
        results.append(reader.results)
    reader = None
    return results
예제 #4
0
    def run_from_designspace(self,
                             designspace_path,
                             interpolate=False,
                             masters_as_instances=False,
                             instance_data=None,
                             interpolate_binary_layout=False,
                             **kwargs):
        """Run toolchain from a MutatorMath design space document.

        Args:
            designspace_path: Path to designspace document.
            interpolate: If True output instance fonts, otherwise just masters.
            masters_as_instances: If True, output master fonts as instances.
            instance_data: Data to be applied to instance UFOs, as returned from
                glyphsLib's parsing function (ignored unless interpolate is True).
            interpolate_binary_layout: Interpolate layout tables from compiled
                master binaries.
            kwargs: Arguments passed along to run_from_ufos.

        Raises:
            TypeError: "variable" output is incompatible with arguments
                "interpolate", "masters_as_instances", and
                "interpolate_binary_layout".
        """

        if "variable" in kwargs.get("output", ()):
            for argname in ("interpolate", "masters_as_instances",
                            "interpolate_binary_layout"):
                if locals()[argname]:
                    raise TypeError(
                        '"%s" argument incompatible with "variable" output' %
                        argname)

        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo import build as build_designspace
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        ufos = []
        if not interpolate or masters_as_instances:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos.extend(reader.getSourcePaths())
        if interpolate:
            logger.info('Interpolating master UFOs from designspace')
            results = build_designspace(designspace_path,
                                        outputUFOFormatVersion=3)
            if instance_data is not None:
                ufos.extend(apply_instance_data(instance_data))
            else:
                for result in results:
                    ufos.extend(result.values())

        interpolate_layout_from = (designspace_path
                                   if interpolate_binary_layout else None)

        self.run_from_ufos(ufos,
                           designspace_path=designspace_path,
                           is_instance=(interpolate or masters_as_instances),
                           interpolate_layout_from=interpolate_layout_from,
                           **kwargs)
예제 #5
0
def go(docName,logFile,ufoVersion=3,roundGeometry=True):
    testRoot = app.config['UPLOAD_DIR']
    documentPath = os.path.join(testRoot, docName)
    sourcePath =testRoot
    instancePath = testRoot
    logPath = os.path.join(testRoot, logFile)
    doc = DesignSpaceDocumentReader(documentPath, ufoVersion, roundGeometry=roundGeometry, verbose=True, logPath=logPath)
    doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)
    close() #doc.close() ?? #It might be a bug on mutatorMath. There is no known inbuilt way of doing this. Ex: doc.Close() or doc.Flush() etc.https://github.com/LettError/MutatorMath/issues/10 
예제 #6
0
def epoch(args):
    reader = DesignSpaceDocumentReader(args.designspace, ufoVersion=3)
    paths = reader.getSourcePaths() + [args.designspace]
    # We want to check the original masters in the source not build directory.
    paths = [os.path.join(args.source, os.path.basename(p)) for p in paths]
    # Not all masters exist in the source directory.
    paths = [p for p in paths if os.path.exists(p)]
    epoch = max([os.stat(p).st_mtime for p in paths])

    return str(int(epoch))
예제 #7
0
    def run_from_designspace(self,
                             designspace_path,
                             interpolate=False,
                             masters_as_instances=False,
                             instance_data=None,
                             interpolate_binary_layout=False,
                             **kwargs):
        """Run toolchain from a MutatorMath design space document.

        Args:
            designspace_path: Path to designspace document.
            interpolate: If True output instance fonts, otherwise just masters.
            masters_as_instances: If True, output master fonts as instances.
            instance_data: Data to be applied to instance UFOs, as returned from
                glyphsLib's parsing function.
            interpolate_binary_layout: Interpolate layout tables from compiled
                master binaries.
            kwargs: Arguments passed along to run_from_ufos.
        """

        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo import build as build_designspace
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        ufos = []
        if not interpolate or masters_as_instances:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos.extend(reader.getSourcePaths())
        if interpolate:
            logger.info('Interpolating master UFOs from designspace')
            results = build_designspace(designspace_path,
                                        outputUFOFormatVersion=3)
            if instance_data is not None:
                ufos.extend(apply_instance_data(instance_data))
            else:
                for result in results:
                    ufos.extend(result.values())

        interpolate_layout_from = (designspace_path
                                   if interpolate_binary_layout else None)

        self.run_from_ufos(ufos,
                           designspace_path=designspace_path,
                           is_instance=(interpolate or masters_as_instances),
                           interpolate_layout_from=interpolate_layout_from,
                           **kwargs)
예제 #8
0
    def run_from_designspace(
            self, designspace_path, interpolate=False, **kwargs):
        """Run toolchain from a MutatorMath design space document to OpenType
        binaries.
        """

        if interpolate:
            print('>> Interpolating master UFOs from design space')
            results = build_designspace(
                designspace_path, outputUFOFormatVersion=3)
            ufos = []
            for result in results:
                ufos.extend(result.values())
        else:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos = reader.getSourcePaths()
        self.run_from_ufos(ufos, is_instance=True, **kwargs)
예제 #9
0
    def run_from_designspace(
            self, designspace_path, interpolate=False, **kwargs):
        """Run toolchain from a MutatorMath design space document to OpenType
        binaries.
        """

        if interpolate:
            print('>> Interpolating master UFOs from design space')
            results = build_designspace(
                designspace_path, outputUFOFormatVersion=3)
            ufos = []
            for result in results:
                ufos.extend(result.values())
        else:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos = reader.getSourcePaths()
        self.run_from_ufos(ufos, is_instance=True, **kwargs)
예제 #10
0
def testOuroborosKerning(rootPath, cleanUp=True):
    # that works, let's do it via MutatorMath
    path1, path2, path3 = makeTestFonts(rootPath)
    documentPath = os.path.join(rootPath, 'kerningTest.designspace')
    logPath = os.path.join(rootPath,"kerningTest.log")
    try:
        testLogFile = open(logPath, 'w')
        testLogFile.close()
    except:
        print("Can't make a logfile.")

    doc = DesignSpaceDocumentWriter(documentPath, verbose=True)
    doc.addSource(
            path1,
            name="master_1", 
            location=dict(width=0), 
            copyLib=True,
            copyGroups=True,
            copyInfo=True, 
            copyFeatures=True,
            )
    doc.addSource(
            path2,
            name="master_2", 
            location=dict(width=1000), 
            copyLib=False,
            copyGroups=False,
            copyInfo=False, 
            copyFeatures=False,
            )
    doc.startInstance(fileName=path3,
            familyName="TestInstance",
            styleName="Regular",
            location=dict(width=100)
            )
    doc.writeKerning(location=dict(width=500))
    doc.endInstance()
    doc.save()

    # execute the designspace. Kerning errors should be tripped by the 
    doc = DesignSpaceDocumentReader(documentPath, 2, roundGeometry=True, verbose=True, logPath=logPath, progressFunc=testingProgressFunc)
    doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)

    # did we log the error?
    report = u"""invalidInstance.ufo:\nThese kerning pairs failed validation and have been removed:\nglyphOne, public.kern2.@MMK_R_two (-400) conflicts with public.kern1.@MMK_L_one, glyphThree (-250)\npublic.kern1.@MMK_L_one, glyphThree (-250) conflicts with glyphOne, public.kern2.@MMK_R_two (-400)"""
    log = open(logPath, 'r')
    logText = log.read()
    log.close()
    #print logText
    #assert report in logText

    if cleanUp:
        # remove the mess
        shutil.rmtree(path1)
        shutil.rmtree(path2)
        shutil.rmtree(path3)

    return True
예제 #11
0
    def run_from_designspace(
            self, designspace_path, interpolate=False,
            masters_as_instances=False, instance_data=None,
            interpolate_binary_layout=False, **kwargs):
        """Run toolchain from a MutatorMath design space document.

        Args:
            designspace_path: Path to designspace document.
            interpolate: If True output instance fonts, otherwise just masters.
            masters_as_instances: If True, output master fonts as instances.
            instance_data: Data to be applied to instance UFOs, as returned from
                glyphsLib's parsing function.
            interpolate_binary_layout: Interpolate layout tables from compiled
                master binaries.
            kwargs: Arguments passed along to run_from_ufos.
        """

        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo import build as build_designspace
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        ufos = []
        if not interpolate or masters_as_instances:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos.extend(reader.getSourcePaths())
        if interpolate:
            self.info('Interpolating master UFOs from designspace')
            results = build_designspace(
                designspace_path, outputUFOFormatVersion=3)
            if instance_data is not None:
                ufos.extend(apply_instance_data(instance_data))
            else:
                for result in results:
                    ufos.extend(result.values())

        interpolate_layout_from = (
            designspace_path if interpolate_binary_layout else None)

        self.run_from_ufos(
            ufos, designspace_path=designspace_path,
            is_instance=(interpolate or masters_as_instances),
            interpolate_layout_from=interpolate_layout_from, **kwargs)
예제 #12
0
    def run_from_designspace(
            self, designspace_path, interpolate=False,
            masters_as_instances=False, **kwargs):
        """Run toolchain from a MutatorMath design space document to OpenType
        binaries.
        """
        from mutatorMath.ufo import build as build_designspace
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        ufos = []
        if not interpolate or masters_as_instances:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos.extend(reader.getSourcePaths())
        if interpolate:
            print('>> Interpolating master UFOs from design space')
            results = build_designspace(
                designspace_path, outputUFOFormatVersion=3)
            for result in results:
                ufos.extend(result.values())
        self.run_from_ufos(
            ufos, is_instance=(interpolate or masters_as_instances), **kwargs)
예제 #13
0
    def generate_temp_masters(self, designspace_path):
        """Makes a new designspace file and generates instances at the
           same location as the masters that have a subset of the glyphset"""
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        logfile = tempfile.NamedTemporaryFile(delete=True).name
        temp_ds_path, master_paths = self.build_temp_designspace(
            designspace_path)
        logger.info("Generating temp UFO master(s)...")
        ds_doc_reader = DesignSpaceDocumentReader(temp_ds_path,
                                                  ufoVersion=2,
                                                  roundGeometry=True,
                                                  verbose=False,
                                                  logPath=logfile)
        ds_doc_reader.process(makeGlyphs=True, makeKerning=True, makeInfo=True)
        # Delete temp designspace file
        if os.path.exists(temp_ds_path):
            os.remove(temp_ds_path)
        base_folder = os.path.dirname(os.path.abspath(designspace_path))
        master_paths = [os.path.join(base_folder, p) for p in master_paths]
        return master_paths
def test_apply_instance_data(tmpdir, instance_names):
    font = glyphsLib.GSFont(TESTFILE_PATH)
    instance_dir = "instances"
    designspace = glyphsLib.to_designspace(font, instance_dir=instance_dir)
    path = str(tmpdir / (font.familyName + '.designspace'))
    write_designspace_and_UFOs(designspace, path)
    builder = DesignSpaceDocumentReader(designspace.path, ufoVersion=3)
    if instance_names is None:
        # generate all instances
        builder.process()
        include_filenames = None
    else:
        # generate only selected instances
        for name in instance_names:
            builder.readInstance(("stylename", name))
        # make relative filenames from paths returned by MutatorMath
        include_filenames = {os.path.relpath(instance_path, str(tmpdir))
                             for instance_path in builder.results.values()}

    ufos = apply_instance_data(designspace.path,
                               include_filenames=include_filenames)

    for filename in include_filenames or ():
        assert os.path.isdir(str(tmpdir / filename))
    assert len(ufos) == len(builder.results)
    assert isinstance(ufos[0], defcon.Font)
예제 #15
0
def testOuroborosKerning(rootPath, cleanUp=True):
    # that works, let's do it via MutatorMath
    path1, path2, path3 = makeTestFonts(rootPath)
    documentPath = os.path.join(rootPath, 'kerningTest.designspace')

    doc = DesignSpaceDocumentWriter(documentPath, verbose=True)
    doc.addSource(
        path1,
        name="master_1",
        location=dict(width=0),
        copyLib=True,
        copyGroups=True,
        copyInfo=True,
        copyFeatures=True,
    )
    doc.addSource(
        path2,
        name="master_2",
        location=dict(width=1000),
        copyLib=False,
        copyGroups=False,
        copyInfo=False,
        copyFeatures=False,
    )
    doc.startInstance(fileName=path3,
                      familyName="TestInstance",
                      styleName="Regular",
                      location=dict(width=100))
    doc.writeKerning(location=dict(width=500))
    doc.endInstance()
    doc.save()

    # execute the designspace. Kerning errors should be tripped by the
    doc = DesignSpaceDocumentReader(documentPath,
                                    2,
                                    roundGeometry=True,
                                    verbose=True,
                                    progressFunc=testingProgressFunc)
    doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)

    if cleanUp:
        # remove the mess
        shutil.rmtree(path1)
        shutil.rmtree(path2)
        shutil.rmtree(path3)

    return True

    def test1():
        """
예제 #16
0
def doit(args):
    global logger
    logger = args.logger

    designspace_path = args.designspace_path
    instance_font_name = args.instanceName
    instance_attr = args.instanceAttr
    instance_val = args.instanceVal
    output_path_prefix = args.output
    calc_glyphs = args.forceInterpolation
    build_folder = args.folder
    round_instances = args.roundInstances

    if instance_font_name and (instance_attr or instance_val):
        args.logger.log('--instanceName is mutually exclusive with --instanceAttr or --instanceVal','S')
    if (instance_attr and not instance_val) or (instance_val and not instance_attr):
        args.logger.log('--instanceAttr and --instanceVal must be used together', 'S')
    if (build_folder and (instance_font_name or instance_attr or instance_val
                          or output_path_prefix or calc_glyphs)):
        args.logger.log('--folder cannot be used with options: -i, -a, -v, -o, --forceInterpolation', 'S')

    args.logger.log('Interpolating master UFOs from designspace', 'P')
    if not build_folder:
        if not os.path.isfile(designspace_path):
            args.logger.log('A designspace file (not a folder) is required', 'S')
        reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3,
                                           roundGeometry=round_instances,
                                           progressFunc=progress_func)
        # assignment to an internal object variable is a kludge, probably should use subclassing instead
        reader._instanceWriterClass = InstanceWriterCF(output_path_prefix, calc_glyphs, args.weightfix)
        if calc_glyphs:
            args.logger.log('Interpolating glyphs where an instance font location matches a master', 'P')
        if instance_font_name or instance_attr:
            key_attr = instance_attr if instance_val else 'name'
            key_val = instance_val if instance_attr else instance_font_name
            reader.readInstance((key_attr, key_val))
        else:
            reader.readInstances()
    else:
        # The below uses a utility function that's part of mutatorMath
        #  It will accept a folder and processes all designspace files there
        args.logger.log('Interpolating glyphs where an instance font location matches a master', 'P')
        build_designspace(designspace_path,
                          outputUFOFormatVersion=3, roundGeometry=round_instances,
                          progressFunc=progress_func)

    if not severe_error:
        args.logger.log('Done', 'P')
    else:
        args.logger.log('Done with severe error', 'S')
예제 #17
0
def makeInstances(stepsWeight, stepsWidth):
    doc = DesignSpaceDocumentWriter(designSpacePath, verbose=True)

    doc.addSource(os.path.join(mutatorSansFolder,
                               "MutatorSansLightCondensed.ufo"),
                  name="LightCondensed",
                  location=dict(weight=0, width=0),
                  copyInfo=True,
                  familyName="MutatorSans",
                  styleName="LightCondensed")

    doc.addSource(os.path.join(mutatorSansFolder, "MutatorSansLightWide.ufo"),
                  name="LightWide",
                  location=dict(weight=0, width=1))

    doc.addSource(os.path.join(mutatorSansFolder,
                               "MutatorSansBoldCondensed.ufo"),
                  name="BoldCondensed",
                  location=dict(weight=1, width=0))

    doc.addSource(os.path.join(mutatorSansFolder, "MutatorSansBoldWide.ufo"),
                  name="BoldWide",
                  location=dict(weight=1, width=1))

    for i in range(stepsWeight):
        wt = i * 1.0 / (stepsWeight - 1)
        for j in range(stepsWidth):
            wd = j * 1.0 / (stepsWidth - 1)
            doc.startInstance(fileName=os.path.join(
                ufosFolder, "MutatorSansInstance_%s-%s.ufo" %
                (int(wt * 1000), int(wd * 1000))),
                              familyName="MutatorSansExample",
                              styleName="%s-%s" %
                              (int(wt * 1000), int(wd * 1000)),
                              location=dict(weight=wt, width=wd))
            doc.endInstance()

    doc.save()

    doc = DesignSpaceDocumentReader(designSpacePath,
                                    3,
                                    roundGeometry=True,
                                    verbose=False)
    doc.process(makeGlyphs=True, makeKerning=False, makeInfo=False)
예제 #18
0
    def interpolate_instance_ufos(self,
                                  designspace,
                                  include=None,
                                  round_instances=False):
        """Interpolate master UFOs with MutatorMath and return instance UFOs.

        Args:
            designspace: a DesignSpaceDocument object containing sources and
                instances.
            include (str): optional regular expression pattern to match the
                DS instance 'name' attribute and only interpolate the matching
                instances.
            round_instances (bool): round instances' coordinates to integer.
        Returns:
            list of defcon.Font objects corresponding to the UFO instances.
        Raises:
            FontmakeError: if any of the sources defines a custom 'layer', for
                this is not supported by MutatorMath.
        """
        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        if any(source.layerName is not None for source in designspace.sources):
            raise FontmakeError(
                "MutatorMath doesn't support DesignSpace sources with 'layer' "
                "attribute")

        # TODO: replace mutatorMath with ufoProcessor?
        builder = DesignSpaceDocumentReader(designspace.path,
                                            ufoVersion=3,
                                            roundGeometry=round_instances,
                                            verbose=True)
        logger.info("Interpolating master UFOs from designspace")
        if include is not None:
            instances = self._search_instances(designspace, pattern=include)
            for instance_name in instances:
                builder.readInstance(("name", instance_name))
            filenames = set(instances.values())
        else:
            builder.readInstances()
            filenames = None  # will include all instances
        logger.info("Applying instance data from designspace")
        instance_ufos = apply_instance_data(designspace,
                                            include_filenames=filenames)
        return instance_ufos
예제 #19
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    if not args:
        args = ["-u"]

    mkot_options = ''

    if '-u' in args:
        print(__usage__)
        return
    if '-h' in args:
        print(__help__)
        return
    if '--mkot' in args:
        index = args.index('--mkot')
        args.pop(index)
        mkot_options = parse_makeotf_options(args.pop(index))

    (dsPath,) = args
    glyphSetsDiffer, master_paths = testGlyphSetsCompatible(dsPath)

    if glyphSetsDiffer:
        allowDecimalCoords = False
        logFile = tempfile.NamedTemporaryFile(delete=True).name
        tempDSPath, master_paths = buildTempDesignSpace(dsPath)
        print("Generating temp UFO master(s)...")
        ds_doc_reader = DesignSpaceDocumentReader(
            tempDSPath, ufoVersion=2, roundGeometry=(not allowDecimalCoords),
            verbose=False, logPath=logFile)
        ds_doc_reader.process(makeGlyphs=True, makeKerning=True, makeInfo=True)

    print("Building local otf's for master font paths...")
    curDir = os.getcwd()
    dsDir = os.path.dirname(dsPath)
    for master_path in master_paths:
        master_path = os.path.join(dsDir, master_path)
        masterDir = os.path.dirname(master_path)
        ufoName = os.path.basename(master_path)
        if ufoName.endswith(kTempUFOExt):
            otfName = ufoName[:-len(kTempUFOExt)]
            # copy the features.fea file from the original UFO master
            fea_file_path_from = os.path.join(
                master_path[:-len(kTempUFOExt)] + '.ufo', kFeaturesFile)
            fea_file_path_to = os.path.join(master_path, kFeaturesFile)
            if os.path.exists(fea_file_path_from):
                shutil.copyfile(fea_file_path_from, fea_file_path_to)
        else:
            otfName = os.path.splitext(ufoName)[0]
        otfName = otfName + ".otf"
        os.chdir(masterDir)
        cmd = "makeotf -f \"%s\" -o \"%s\" -r -nS %s 2>&1" % (
            ufoName, otfName, mkot_options)
        log = runShellCmd(cmd)
        if ("FATAL" in log) or ("Failed to build" in log):
            print(log)

        if "Built" not in str(log):
            print("Error building OTF font for", master_path, log)
            print("makeotf cmd was '%s' in %s." % (cmd, masterDir))
        else:
            print("Built OTF font for", master_path)
            compatibilizePaths(otfName)
            if ufoName.endswith(kTempUFOExt):
                shutil.rmtree(ufoName)
        os.chdir(curDir)

    if glyphSetsDiffer and os.path.exists(tempDSPath):
        os.remove(tempDSPath)
예제 #20
0
    def run_from_designspace(self,
                             designspace_path,
                             interpolate=False,
                             masters_as_instances=False,
                             instance_data=None,
                             interpolate_binary_layout=False,
                             round_instances=False,
                             **kwargs):
        """Run toolchain from a MutatorMath design space document.

        Args:
            designspace_path: Path to designspace document.
            interpolate: If True output instance fonts, otherwise just masters.
            masters_as_instances: If True, output master fonts as instances.
            instance_data: Data to be applied to instance UFOs, as returned from
                glyphsLib's parsing function (ignored unless interpolate is True).
            interpolate_binary_layout: Interpolate layout tables from compiled
                master binaries.
            round_instances: apply integer rounding when interpolating with
                MutatorMath.
            kwargs: Arguments passed along to run_from_ufos.

        Raises:
            TypeError: "variable" output is incompatible with arguments
                "interpolate", "masters_as_instances", and
                "interpolate_binary_layout".
        """

        if "variable" in kwargs.get("output", ()):
            for argname in ("interpolate", "masters_as_instances",
                            "interpolate_binary_layout"):
                if locals()[argname]:
                    raise TypeError(
                        '"%s" argument incompatible with "variable" output' %
                        argname)

        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo import build as build_designspace
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        ufos = []
        if not interpolate or masters_as_instances:
            reader = DesignSpaceDocumentReader(designspace_path, ufoVersion=3)
            ufos.extend(reader.getSourcePaths())
        if interpolate:
            logger.info('Interpolating master UFOs from designspace')
            _, ilocs = self._designspace_locations(designspace_path)
            for ipath in ilocs.keys():
                # mutatorMath does not remove the existing instance UFOs
                # so we do it ourselves, or else strange things happen...
                # https://github.com/googlei18n/fontmake/issues/372
                if ipath.endswith(".ufo") and os.path.isdir(ipath):
                    logger.debug("Removing %s" % ipath)
                    shutil.rmtree(ipath)
            results = build_designspace(designspace_path,
                                        outputUFOFormatVersion=3,
                                        roundGeometry=round_instances)
            if instance_data is not None:
                ufos.extend(apply_instance_data(instance_data))
            else:
                for result in results:
                    ufos.extend(result.values())

        interpolate_layout_from = (designspace_path
                                   if interpolate_binary_layout else None)

        self.run_from_ufos(ufos,
                           designspace_path=designspace_path,
                           is_instance=(interpolate or masters_as_instances),
                           interpolate_layout_from=interpolate_layout_from,
                           **kwargs)
예제 #21
0
    def interpolate_instance_ufos_mutatormath(
        self,
        designspace,
        include=None,
        round_instances=False,
        expand_features_to_instances=False,
    ):
        """Interpolate master UFOs with MutatorMath and return instance UFOs.

        Args:
            designspace: a DesignSpaceDocument object containing sources and
                instances.
            include (str): optional regular expression pattern to match the
                DS instance 'name' attribute and only interpolate the matching
                instances.
            round_instances (bool): round instances' coordinates to integer.
            expand_features_to_instances: parses the master feature file, expands all
                include()s and writes the resulting full feature file to all instance
                UFOs. Use this if you share feature files among masters in external
                files. Otherwise, the relative include paths can break as instances
                may end up elsewhere. Only done on interpolation.
        Returns:
            list of defcon.Font objects corresponding to the UFO instances.
        Raises:
            FontmakeError: if any of the sources defines a custom 'layer', for
                this is not supported by MutatorMath.
            ValueError: "expand_features_to_instances" is True but no source in the
                designspace document is designated with '<features copy="1"/>'.
        """
        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        if any(source.layerName is not None for source in designspace.sources):
            raise FontmakeError(
                "MutatorMath doesn't support DesignSpace sources with 'layer' "
                "attribute")

        with temporarily_disabling_axis_maps(
                designspace.path) as temp_designspace_path:
            builder = DesignSpaceDocumentReader(
                temp_designspace_path,
                ufoVersion=3,
                roundGeometry=round_instances,
                verbose=True,
            )
            logger.info("Interpolating master UFOs from designspace")
            if include is not None:
                instances = self._search_instances(designspace,
                                                   pattern=include)
                for instance_name in instances:
                    builder.readInstance(("name", instance_name))
                filenames = set(instances.values())
            else:
                builder.readInstances()
                filenames = None  # will include all instances

        logger.info("Applying instance data from designspace")
        instance_ufos = apply_instance_data(designspace,
                                            include_filenames=filenames)

        if expand_features_to_instances:
            logger.debug("Expanding features to instance UFOs")
            master_source = next(
                (s for s in designspace.sources if s.copyFeatures), None)
            if not master_source:
                raise ValueError(
                    "No source is designated as the master for features.")
            else:
                master_source_font = builder.sources[master_source.name][0]
                master_source_features = parseLayoutFeatures(
                    master_source_font).asFea()
                for instance_ufo in instance_ufos:
                    instance_ufo.features.text = master_source_features
                    instance_ufo.save()

        return instance_ufos
예제 #22
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    if not args:
        args = ["-u"]

    mkot_options = ''

    if '-u' in args:
        print(__usage__)
        return
    if '-h' in args:
        print(__help__)
        return
    if '--mkot' in args:
        index = args.index('--mkot')
        args.pop(index)
        mkot_options = parse_makeotf_options(args.pop(index))

    (dsPath,) = args
    glyphSetsDiffer, master_paths = testGlyphSetsCompatible(dsPath)

    if glyphSetsDiffer:
        allowDecimalCoords = False
        logFile = tempfile.NamedTemporaryFile(delete=True).name
        tempDSPath, master_paths = buildTempDesignSpace(dsPath)
        print("Generating temp UFO master(s)...")
        ds_doc_reader = DesignSpaceDocumentReader(
            tempDSPath, ufoVersion=2, roundGeometry=(not allowDecimalCoords),
            verbose=False, logPath=logFile)
        ds_doc_reader.process(makeGlyphs=True, makeKerning=True, makeInfo=True)

    print("Building local otf's for master font paths...")
    curDir = os.getcwd()
    dsDir = os.path.dirname(dsPath)
    for master_path in master_paths:
        master_path = os.path.join(dsDir, master_path)
        masterDir = os.path.dirname(master_path)
        ufoName = os.path.basename(master_path)
        if ufoName.endswith(kTempUFOExt):
            otfName = ufoName[:-len(kTempUFOExt)]
            # copy the features.fea file from the original UFO master
            fea_file_path_from = os.path.join(
                master_path[:-len(kTempUFOExt)] + '.ufo', kFeaturesFile)
            fea_file_path_to = os.path.join(master_path, kFeaturesFile)
            if os.path.exists(fea_file_path_from):
                shutil.copyfile(fea_file_path_from, fea_file_path_to)
        else:
            otfName = os.path.splitext(ufoName)[0]
        otfName = otfName + ".otf"
        os.chdir(masterDir)
        cmd = "makeotf -nshw -f \"%s\" -o \"%s\" -r -nS %s 2>&1" % (
            ufoName, otfName, mkot_options)
        log = runShellCmd(cmd)
        if ("FATAL" in log) or ("Failed to build" in log):
            print(log)

        if "Built" not in str(log):
            print("Error building OTF font for", master_path, log)
            print("makeotf cmd was '%s' in %s." % (cmd, masterDir))
        else:
            print("Built OTF font for", master_path)
            compatibilizePaths(otfName)
            if ufoName.endswith(kTempUFOExt):
                shutil.rmtree(ufoName)
        os.chdir(curDir)

    if glyphSetsDiffer and os.path.exists(tempDSPath):
        os.remove(tempDSPath)
예제 #23
0
from designSpaceDocument import DesignSpaceDocument, SourceDescriptor, InstanceDescriptor, AxisDescriptor
from mutatorMath.ufo.document import DesignSpaceDocumentWriter, DesignSpaceDocumentReader

path = u"/Users/SO/Desktop/Typemade/TypeDesign/FB/Amstelvar/Amstelvar-SO/sources/Amstelvar-Roman-so.designspace"
doc = DesignSpaceDocumentReader(path, ufoVersion=3)
doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)
print 'done'
예제 #24
0
    #	dict(fileName="instances/Amstelvar-Italic-opsz144-wght900-wdth50.ufo", location=dict(wght=900, wdth=75, opsz=144), styleName="opsz144-wght900-wdth50", familyName=familyName, postScriptFontName=None, styleMapFamilyName=None, styleMapStyleName=None),

    #	dict(fileName="instances/Amstelvar-Italic-opsz144-wdth125.ufo", location=dict(wght=400, wdth=125, opsz=144), styleName="opsz144-wdth125", familyName=familyName, postScriptFontName=None, styleMapFamilyName=None, styleMapStyleName=None),
    #	dict(fileName="instances/Amstelvar-Italic-opsz144-wdth075.ufo", location=dict(wght=400, wdth=80, opsz=144), styleName="opsz144-wdth075", familyName=familyName, postScriptFontName=None, styleMapFamilyName=None, styleMapStyleName=None),
    #	dict(fileName="instances/Amstelvar-Italic-opsz144-wdth50.ufo", location=dict(wght=400, wdth=75, opsz=144), styleName="opsz144-wdth50", familyName=familyName, postScriptFontName=None, styleMapFamilyName=None, styleMapStyleName=None),
]
for instance in instances:
    doc.startInstance(**instance)
    doc.writeInfo()
    doc.writeKerning()
    doc.endInstance()

doc.save()
# read and process the designspace
doc = DesignSpaceDocumentReader(tmpDesignSpace,
                                ufoVersion=2,
                                roundGeometry=False,
                                verbose=False)
print("Reading DesignSpace...")
doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)
os.remove(tmpDesignSpace)  # clean up

# update the instances with the source fonts
# print str(instances) + ' instances! '
for instance in instances:
    fileName = os.path.basename(instance["fileName"])
    source_path = os.path.join(src_dir, fileName)
    instance_path = os.path.join(instance_dir, fileName)
    source_font = Font(source_path)
    instance_font = Font(instance_path)
    # insert the source glyphs in the instance font
    for glyph in source_font:
예제 #25
0
    def run_from_designspace(self,
                             designspace_path,
                             interpolate=False,
                             masters_as_instances=False,
                             interpolate_binary_layout=False,
                             round_instances=False,
                             **kwargs):
        """Run toolchain from a MutatorMath design space document.

        Args:
            designspace_path: Path to designspace document.
            interpolate: If True output all instance fonts, otherwise just
                masters. If the value is a string, only build instance(s) that
                match given name. The string is compiled into a regular
                expression and matched against the "name" attribute of
                designspace instances using `re.fullmatch`.
            masters_as_instances: If True, output master fonts as instances.
            interpolate_binary_layout: Interpolate layout tables from compiled
                master binaries.
            round_instances: apply integer rounding when interpolating with
                MutatorMath.
            kwargs: Arguments passed along to run_from_ufos.

        Raises:
            TypeError: "variable" output is incompatible with arguments
                "interpolate", "masters_as_instances", and
                "interpolate_binary_layout".
        """

        if "variable" in kwargs.get("output", ()):
            for argname in ("interpolate", "masters_as_instances",
                            "interpolate_binary_layout"):
                if locals()[argname]:
                    raise TypeError(
                        '"%s" argument incompatible with "variable" output' %
                        argname)

        from glyphsLib.interpolation import apply_instance_data
        from mutatorMath.ufo.document import DesignSpaceDocumentReader

        ufos = []
        reader = DesignSpaceDocumentReader(designspace_path,
                                           ufoVersion=3,
                                           roundGeometry=round_instances,
                                           verbose=True)
        if not interpolate or masters_as_instances:
            ufos.extend(reader.getSourcePaths())
        if interpolate:
            logger.info('Interpolating master UFOs from designspace')
            if isinstance(interpolate, basestring):
                instances = self._search_instances(designspace_path,
                                                   pattern=interpolate)
                for instance_name in instances:
                    reader.readInstance(("name", instance_name))
                filenames = set(instances.values())
            else:
                reader.readInstances()
                filenames = None  # will include all instances
            logger.info('Applying instance data from designspace')
            ufos.extend(
                apply_instance_data(designspace_path,
                                    include_filenames=filenames))

        if interpolate_binary_layout is False:
            interpolate_layout_from = interpolate_layout_dir = None
        else:
            interpolate_layout_from = designspace_path
            if isinstance(interpolate_binary_layout, basestring):
                interpolate_layout_dir = interpolate_binary_layout
            else:
                interpolate_layout_dir = None

        self.run_from_ufos(ufos,
                           designspace_path=designspace_path,
                           is_instance=(interpolate or masters_as_instances),
                           interpolate_layout_from=interpolate_layout_from,
                           interpolate_layout_dir=interpolate_layout_dir,
                           **kwargs)
예제 #26
0
def testMutingOptions(rootPath, cleanUp=True):
    # that works, let's do it via MutatorMath
    # path1 and path2 are masters. path3 is the instance
    path1, path2, path3 = makeTestFonts(rootPath)
    documentPath = os.path.join(rootPath, 'mutingTest.designspace')

    doc = DesignSpaceDocumentWriter(documentPath, verbose=True)
    doc.addSource(path1,
                  name="master_1",
                  location=dict(width=0),
                  copyLib=True,
                  copyGroups=True,
                  copyInfo=True,
                  copyFeatures=True,
                  muteKerning=True)
    doc.addSource(
        path2,
        name="master_2",
        location=dict(width=1000),
        copyLib=False,
        copyGroups=False,
        copyInfo=False,
        copyFeatures=False,
        muteInfo=True,
        mutedGlyphNames=['glyphThree']  # mute glyphThree in master 1
    )
    doc.startInstance(fileName=path3,
                      familyName="TestInstance",
                      styleName="Regular",
                      location=dict(width=500))
    doc.writeGlyph('glyphFour', mute=True)  # mute glyphFour in the instance
    doc.writeKerning()
    doc.writeInfo()
    doc.endInstance()
    doc.save()

    # execute the designspace.
    doc = DesignSpaceDocumentReader(documentPath,
                                    2,
                                    roundGeometry=True,
                                    verbose=True,
                                    progressFunc=testingProgressFunc)
    doc.process(makeGlyphs=True, makeKerning=True, makeInfo=True)

    # look at the results
    m1 = Font(path1)
    m2 = Font(path2)
    r = Font(path3)
    #
    # the glyphThree master was muted in the second master
    # so the instance glyphThree should be the same as the first master:
    assert r['glyphThree'].bounds == m1['glyphThree'].bounds
    # we muted glyphFour in the instance.
    # so it should not be part of the instance UFO:
    assert "glyphFour" not in r
    # font.info is muted for master2, so the instance has to have the values from master 1
    assert r.info.unitsPerEm == m1.info.unitsPerEm
    # kerning is muted for master1, so the instance has to have the kerning from master 2
    assert r.kerning[('glyphOne', 'glyphOne')] == m2.kerning[('glyphOne',
                                                              'glyphOne')]

    if cleanUp:
        # remove the mess
        try:
            shutil.rmtree(path1)
            shutil.rmtree(path2)
            shutil.rmtree(path3)
        except:
            pass

    return True
예제 #27
0
def testGeometry(rootPath, cleanUp=True):
    # that works, let's do it via MutatorMath
    path1, path2, path3, path4, path5 = makeTestFonts(rootPath)
    documentPath = os.path.join(rootPath, 'geometryTest.designspace')

    doc = DesignSpaceDocumentWriter(documentPath, verbose=True)
    doc.addSource(
            path1,
            name="master_1", 
            location=dict(width=0), 
            copyLib=True,
            copyGroups=True,
            copyInfo=True, 
            copyFeatures=True,
            )
    doc.addSource(
            path2,
            name="master_2", 
            location=dict(width=1000), 
            copyLib=False,
            copyGroups=False,
            copyInfo=False, 
            copyFeatures=False,
            )
    doc.startInstance(fileName=path3,
            familyName="TestInstance",
            styleName="Regular",
            location=dict(width=500)
            )
    doc.endInstance()
    doc.startInstance(fileName=path4,
            familyName="TestInstance",
            styleName="Anisotropic1",
            location=dict(width=(0, 1000))
            )
    doc.endInstance()
    doc.startInstance(fileName=path5,
            familyName="TestInstance",
            styleName="Anisotropic2",
            location=dict(width=(1000, 0))
            )
    doc.endInstance()
    doc.save()

    # execute the designspace.
    doc = DesignSpaceDocumentReader(documentPath, 2, roundGeometry=True, verbose=True, progressFunc=testingProgressFunc)
    doc.process(makeGlyphs=True, makeKerning=False, makeInfo=True)

    r1 = Font(path3)
    assert r1['glyphOne'].bounds == (0, 0, 300, 300)

    r2 = Font(path4)
    assert r2['glyphOne'].bounds == (0, 0, 100, 500)

    r3 = Font(path5)
    assert r3['glyphOne'].bounds == (0, 0, 500, 100)

    if cleanUp:
        # remove the mess
        shutil.rmtree(path1)
        shutil.rmtree(path2)
        shutil.rmtree(path3)

    return True