예제 #1
0
    def run_fontmake(self, source, args):
        if "output_dir" in args:
            original_output_dir = args["output_dir"]
            tmpdir = tempfile.TemporaryDirectory()
            args["output_dir"] = tmpdir.name
        args["flatten_components"] = self.config["flattenComponents"]

        if source.endswith(".glyphs"):
            FontProject().run_from_glyphs(source, **args)
        elif source.endswith(".designspace"):
            FontProject().run_from_designspace(source, **args)
        elif source.endswith(".ufo"):
            FontProject().run_from_ufos([source], **args)
        else:
            raise ValueError("Can't build from unknown source file: %s" %
                             source)
        if "output_path" in args:
            return [args["output_path"]]
        else:
            # Move it to where it should be...
            file_names = os.listdir(args["output_dir"])
            for file_name in file_names:
                shutil.move(os.path.join(args["output_dir"], file_name),
                            original_output_dir)
            tmpdir.cleanup()
            args["output_dir"] = original_output_dir
            return [os.path.join(original_output_dir, x) for x in file_names]
예제 #2
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-c', '--compatible', action='store_true')
    parser.add_argument('-i', '--interpolate', action='store_true',
                        help='interpolate masters (Glyphs source only)')
    parser.add_argument('--mti-source')
    parser.add_argument('--use-afdko', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject()

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    if not sum(1 for p in [glyphs_path, ufo_paths] if p) == 1:
        raise ValueError('Exactly one source type required (Glyphs or UFO).')

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    else:
        excluded = 'interpolate'
        if args[excluded]:
            raise ValueError(
                '"%s" argument only available for Glyphs source' % excluded)
        del args[excluded]
        project.run_from_ufos(ufo_paths, **args)
예제 #3
0
 def test_build_otfs(self, mock_build_ttfs, mock_build_otfs):
     project = FontProject()
     self.assertFalse(mock_build_otfs.called)
     self.assertFalse(mock_build_ttfs.called)
     project.run_from_ufos("path to ufo", output=('otf', 'ttf'))
     self.assertTrue(mock_build_ttfs.called)
     self.assertTrue(mock_build_otfs.called)
예제 #4
0
파일: test.py 프로젝트: dcecile/bitfontmake
def test_bit_font(bit_font):
    print(bit_font)
    font = convert_to_font(bit_font)
    font.save(path=f'master_ufo/{bit_font.info.family_name}.ufo',
              formatVersion=3)
    project = FontProject()
    project.build_ttfs([font], remove_overlaps=True)
예제 #5
0
 def test_run_from_ufos(self, mock_build_variable_font, mock_build_interpolatable_ttfs):
     project = FontProject()
     self.assertFalse(mock_build_interpolatable_ttfs.called)
     self.assertFalse(mock_build_variable_font.called)
     project.run_from_ufos("path to ufo", output=('variable'), designspace_path="design space")
     self.assertTrue(mock_build_interpolatable_ttfs.called)
     self.assertTrue(mock_build_variable_font.called)
 def build_fontmake(self,
                    designspace_path,
                    output=['variable'],
                    output_dir=None,
                    remove_overlaps=False,
                    interpolate=False,
                    autohint=None):
     if not os.path.isdir(output_dir):
         os.makedirs(output_dir)
     project = FontProject()
     fontmake_args = {
         'output': output,
         'output_path': None,
         'output_dir': output_dir,
         # 'feature_writers': None,
         'interpolate': interpolate,
         'remove_overlaps': remove_overlaps,
         'overlaps_backend': 'booleanOperations',
         'autohint': autohint,
         'use_production_names': False
     }
     if 'variable' in output:
         fontmake_args['optimize_gvar'] = True
     if 'otf' in output:
         fontmake_args['optimize_cff'] = CFFOptimization.SUBROUTINIZE
     print(
         project.run_from_designspace(designspace_path=designspace_path,
                                      **fontmake_args))
def makeVanillaFamily(family, *output, newName=" "):
    # if family not in pan_european_fonts:
    #     print("Please note that these fonts may lack")
    #     print("basic figures and punctuation.")
    path, folder = getFile(".designspace", family)
    designSpace = openDesignSpace(path)
    destination = folder + "/" + "Instances"
    ### test if mti
    for file in os.listdir(folder):
        if file.endswith(".plist"):
            # INJECT COMPILED TABLE IN FONTS
            ufoWithMTIfeatures2font(family, output)
            if newName != " ":
                renameFonts(family, newName)
            return
    fp = FontProject()
    fonts = fp.run_from_designspace(expand_features_to_instances=True,
                                    use_mutatormath=False,
                                    designspace_path=path,
                                    interpolate=True,
                                    output=("otf"),
                                    output_dir=destination)
    ufolist = list()
    for ufo in os.listdir(os.path.join(folder, "instance_ufos")):
        if ufo[-4:] == ".ufo":
            ufolist.append(ufo)
    instancesFolder = family + "/instance_ufos"
    ufo2font(instancesFolder, ufolist, output, fromInstances=True)
    if newName != " ":
        renameFonts(family, newName)
예제 #8
0
 def test_build_otfs(self, mock_build_ttfs, mock_build_otfs):
     project = FontProject()
     self.assertFalse(mock_build_otfs.called)
     self.assertFalse(mock_build_ttfs.called)
     project.run_from_ufos("path to ufo", output=('otf', 'ttf'))
     self.assertTrue(mock_build_ttfs.called)
     self.assertTrue(mock_build_otfs.called)
예제 #9
0
 def test_variable_output_filename(self, mock_designspace_locations, mock_TTFont_save, mock_varLib_build):
     project = FontProject()
     mock_designspace_locations.return_value = {'master1': 'location1'}, None
     mock_varLib_build.return_value = TTFont(), None, None
     project.build_variable_font('path/to/designspace.designspace')
     self.assertTrue(mock_TTFont_save.called)
     self.assertTrue(mock_TTFont_save.call_count == 1)
     self.assertEqual(mock_TTFont_save.call_args, mock.call('variable_ttf/designspace-VF.ttf'))
예제 #10
0
def main():
    parser = ArgumentParser()
    parser.add_argument('glyphs_path', metavar='GLYPHS_PATH')
    parser.add_argument('-c', '--compatible', action='store_true')
    parser.add_argument('-i', '--interpolate', action='store_true')
    args = parser.parse_args()

    project = FontProject()
    project.run_all(args.glyphs_path, args.interpolate, args.compatible)
def makeOtfFamily(family, newName=" ", onlyOtf=False):
    if family not in pan_european_fonts:
        print("Please note that non-latin OTF fonts can't have")
        print("the figures and punctuation from Latin merged in it")
    output = "otf"
    path, folder = getFile(".designspace", family)
    designSpace = openDesignSpace(path)
    destination = folder + "/" + "Instances"
    ### test if mti
    for file in os.listdir(folder):
        if file.endswith(".plist"):
            # INJECT COMPILED TABLE IN FONTS
            ufoWithMTIfeatures2font(family, output)
            if newName != " ":
                renameFonts(family, newName)
            return
    if onlyOtf is True:
        fp = FontProject()
        fonts = fp.run_from_designspace(expand_features_to_instances=True,
                                        use_mutatormath=False,
                                        designspace_path=path,
                                        interpolate=True,
                                        output=("otf"),
                                        output_dir=destination)
    ufolist = list()
    for ufo in os.listdir(os.path.join(folder, "instance_ufos")):
        if ufo[-4:] == ".ufo":
            ufolist.append(ufo)
    instancesFolder = family + "/instance_ufos"
    ufo2font(instancesFolder, ufolist, output, fromInstances=True)
    if newName != " ":
        renameFonts(family, newName)


### TEST FUNCTIONS ###
# mastersUfos2fonts("NotoSansThaana", "otf")
# makeTTFInstancesFromVF("NotoSerifSinhala")
# makeTTFInstancesFromVF("NotoSansArabic")
# subsetFonts("NotoNaskhArabic", "Core_Arabic")
# designSpace2Instances("NotoSansVai", "otf", "ttf")
# ufoWithMTIfeatures2font("NotoNastaliqUrdu", "ttf")
# subsetFonts("NotoSans", "CyrillicPro", familyNewName = "Avocado Sans", flavor=["ttf"])
# subsetFonts("NotoNaskhArabicUI", "Core_Arabic")
# subsetFonts("NotoSans", "SecureSet")
# mastersUfos2fonts("NotoSansThaana", "woff2")
# renameFonts("NotoMusic", "Tomato Soup", 'otf')
# mergeFonts("NotoSans","NotoNastaliqUrdu")
# designSpace2Var("NotoSerifThai")
# makeTTFInstancesFromVF("NotoSerif")
# makeOneInstanceFromVF("NotoSansThaana", {'wght': 190.0})
# mastersUfos2fonts("NotoSansThaana", "ttf")
# ufosToGlyphs("NotoSansThaana")
# ufo2font("NotoSans", ["NotoSans-Bold.ufo"], "ttf")
# designSpace2Instances("NotoSansNko", "ttf", secureSet=False)
# mergeFonts("NotoSansThaana", "NotoSerifHebrew")
# addSecureSet("NotoSansArabic", "ttf")
예제 #12
0
 def test_run_from_ufos(self, mock_build_variable_font,
                        mock_build_interpolatable_ttfs):
     project = FontProject()
     self.assertFalse(mock_build_interpolatable_ttfs.called)
     self.assertFalse(mock_build_variable_font.called)
     project.run_from_ufos("path to ufo",
                           output=('variable'),
                           designspace_path="design space")
     self.assertTrue(mock_build_interpolatable_ttfs.called)
     self.assertTrue(mock_build_variable_font.called)
예제 #13
0
def main():
    parser = ArgumentParser()
    parser.add_argument('glyphs_path', metavar='GLYPHS_PATH')
    parser.add_argument('-c', '--compatible', action='store_true')
    parser.add_argument('-i', '--interpolate', action='store_true')
    args = parser.parse_args()

    project = FontProject()
    project.run_all(
        args.glyphs_path, args.interpolate, args.compatible)
예제 #14
0
 def test_variable_output_filename(self, mock_designspace_locations,
                                   mock_TTFont_save, mock_varLib_build):
     project = FontProject()
     mock_designspace_locations.return_value = {
         'master1': 'location1'
     }, None
     mock_varLib_build.return_value = TTFont(), None, None
     project.build_variable_font('path/to/designspace.designspace')
     self.assertTrue(mock_TTFont_save.called)
     self.assertTrue(mock_TTFont_save.call_count == 1)
     self.assertEqual(mock_TTFont_save.call_args,
                      mock.call('variable_ttf/designspace-VF.ttf'))
예제 #15
0
 def test_variable_output_filename(self, mock_DesignSpaceDocument_fromfile,
                                   mock_TTFont_save, mock_varLib_build):
     project = FontProject()
     path = "path/to/designspace.designspace"
     doc = DesignSpaceDocument()
     doc.path = path
     mock_DesignSpaceDocument_fromfile.return_value = doc
     mock_varLib_build.return_value = TTFont(), None, None
     project.build_variable_font(path)
     self.assertTrue(mock_TTFont_save.called)
     self.assertTrue(mock_TTFont_save.call_count == 1)
     self.assertEqual(mock_TTFont_save.call_args,
                      mock.call("variable_ttf/designspace-VF.ttf"))
예제 #16
0
파일: __main__.py 프로젝트: itmard/fontmake
def main():
    parser = ArgumentParser()
    parser.add_argument('glyphs_path', metavar='GLYPHS_PATH')
    parser.add_argument('-c', '--compatible', action='store_true')
    parser.add_argument('-i', '--interpolate', action='store_true')
    parser.add_argument('--use_mti', action='store_true')
    parser.add_argument('--gdef_path')
    parser.add_argument('--gpos_path')
    parser.add_argument('--gsub_path')
    args = vars(parser.parse_args())

    glyphs_path = args.pop('glyphs_path')
    project = FontProject()
    project.run_all(glyphs_path, **args)
예제 #17
0
def build_fonts(ufo_path):
    try:
        fp = FontProject()
        fp.run_from_ufos(ufo_path, output=BUILD_FILE_TYPE)
    except Exception as e:
        lock.acquire()
        print(" ")
        print("[ERROR] The fontmake compile for " + ufo_path +
              " failed with the following error"
              ":" + os.linesep)
        sys.stdout.flush()
        traceback.print_exc()
        print(str(e))
        sys.stdout.flush()
        lock.release()
예제 #18
0
def compile_font(extension, action):
    with temporary_cwd():
        bit_font = open_bit_font(request.stream)
        font = convert_to_font(bit_font)
        project = FontProject()
        action(project)([font], remove_overlaps=True)
        font_filename = f'{get_font_name(font)}.{extension}'
        return send_file(open(f'master_{extension}/{font_filename}', 'rb'),
                         as_attachment=True,
                         attachment_filename=font_filename)
예제 #19
0
def build_variable(
    designspacePath,
    stylespacePath=None,
    out=None,
    verbose="ERROR",
):
    """
    Builds a variable font from a designspace using fontmake.
    Post applies the STAT table using a stylespace if given.

    *designspacePath* a `string` of the path to the designspace
    *stylespacePath* a `string` of the path to the stylespace
    *out* a `string` of the path where the varible font should be saved
    *verbose* sets the verbosity level for fontmake. Defaults to "ERROR"
    """

    if out is None:
        out = os.path.splitext(
            os.path.basename(designspacePath))[0] + "-VF.ttf"

    else:
        if not os.path.exists(os.path.split(out)[0]):
            os.mkdir(os.path.split(out)[0])

    print("🏗  Constructing variable font")
    fp = FontProject(verbose=verbose)
    fp.build_variable_font(designspacePath,
                           output_path=out,
                           useProductionNames=True)

    if stylespacePath is not None:
        print("🏗  Adding STAT table")
        ds = DesignSpaceDocument.fromfile(designspacePath)
        additional_locations = ds.lib.get("org.statmake.additionalLocations",
                                          {})
        font = fontTools.ttLib.TTFont(out)
        stylespace = Stylespace.from_file(stylespacePath)
        apply_stylespace_to_variable_font(stylespace, font,
                                          additional_locations)
        font.save(out)

    print("✅ Built variable font")
예제 #20
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument('-o',
                        '--output',
                        nargs='+',
                        default=('otf', 'ttf'),
                        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable'))
    parser.add_argument('-i',
                        '--interpolate',
                        action='store_true',
                        help='interpolate masters (Glyphs source only)')
    parser.add_argument('--mti-source')
    parser.add_argument('--use-afdko', action='store_true')
    parser.add_argument('--timing', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if not sum(1
               for p in [glyphs_path, ufo_paths, designspace_path] if p) == 1:
        raise ValueError('Exactly one source type required (Glyphs or UFO).')

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    elif designspace_path:
        project.run_from_designspace(designspace_path, **args)

    else:
        excluded = 'interpolate'
        if args[excluded]:
            raise ValueError(
                '"%s" argument only available for Glyphs or Designspace source'
                % excluded)
        del args[excluded]

    if ufo_paths:
        project.run_from_ufos(ufo_paths, **args)
예제 #21
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument('-o', '--output', nargs='+', default=('otf', 'ttf'),
                        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable'))
    parser.add_argument('-i', '--interpolate', action='store_true',
                        help='interpolate masters (Glyphs source only)')
    parser.add_argument('--mti-source')
    parser.add_argument('--use-afdko', action='store_true')
    parser.add_argument('--timing', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if not sum(1 for p in [glyphs_path, ufo_paths, designspace_path] if p) == 1:
        raise ValueError('Exactly one source type required (Glyphs or UFO).')

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    elif designspace_path:
        project.run_from_designspace(designspace_path, **args)

    else:
        excluded = 'interpolate'
        if args[excluded]:
            raise ValueError(
                '"%s" argument only available for Glyphs or Designspace source'
                % excluded)
        del args[excluded]

    if ufo_paths:
        project.run_from_ufos(ufo_paths, **args)
예제 #22
0
def build(args):
    designspace = os.path.join(args.build, args.designspace)

    os.environ["SOURCE_DATE_EPOCH"] = epoch(args)

    autohint = None
    if args.release:
        autohint = ""

    project = FontProject(verbose="WARNING")
    if args.ufo:
        project.run_from_ufos([args.ufo],
                              output=args.output,
                              remove_overlaps=False,
                              reverse_direction=False,
                              subroutinize=args.release,
                              autohint=autohint)
    else:
        project.run_from_designspace(designspace,
                                     output=args.output,
                                     subroutinize=args.release,
                                     autohint=autohint)
예제 #23
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument('-o',
                        '--output',
                        nargs='+',
                        default=('otf', 'ttf'),
                        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable',
                                 'variable'))

    parser.add_argument('-i',
                        '--interpolate',
                        action='store_true',
                        help='interpolate masters (for Glyphs or MutatorMath '
                        'sources only)')
    parser.add_argument('-M',
                        '--masters-as-instances',
                        action='store_true',
                        help='treat masters as instances')
    parser.add_argument('-a',
                        '--autohint',
                        nargs='?',
                        const="",
                        help='can provide arguments to ttfautohint, quoted')
    parser.add_argument('--mti-source')
    parser.add_argument('--family-name',
                        help='Family name to use for masters,'
                        ' and to filter output instances by')
    parser.add_argument('--use-afdko', action='store_true')
    parser.add_argument('--keep-direction',
                        dest="reverse_direction",
                        action='store_false',
                        help='Do not reverse contour '
                        'direction when output is ttf or ttf-interpolatable')
    parser.add_argument('--keep-overlaps',
                        dest="remove_overlaps",
                        action='store_false',
                        help='Do not remove any overlap.')
    group1 = parser.add_mutually_exclusive_group(required=False)
    group1.add_argument(
        '--production-names',
        dest='use_production_names',
        action='store_true',
        help='Rename glyphs with '
        'production names if available otherwise use uninames.')
    group1.add_argument('--no-production-names',
                        dest='use_production_names',
                        action='store_false')
    group2 = parser.add_mutually_exclusive_group(required=False)
    group2.add_argument('--subset',
                        dest='subset',
                        action='store_true',
                        help='Subset font using export '
                        'flags set by glyphsLib')
    group2.add_argument('--no-subset', dest='subset', action='store_false')
    group3 = parser.add_mutually_exclusive_group(required=False)
    group3.add_argument('-s',
                        '--subroutinize',
                        action='store_true',
                        help='Optimize CFF table using compreffor (default)')
    group3.add_argument('-S',
                        '--no-subroutinize',
                        dest='subroutinize',
                        action='store_false')
    parser.add_argument('-e',
                        '--conversion-error',
                        type=float,
                        default=None,
                        metavar='ERROR',
                        help="Maximum approximation error for"
                        " cubic to quadratic conversion measured in EM")
    parser.set_defaults(use_production_names=None,
                        subset=None,
                        subroutinize=True)
    parser.add_argument('--timing', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if not sum(1
               for p in [glyphs_path, ufo_paths, designspace_path] if p) == 1:
        parser.error('Exactly one source type required (Glyphs, UFO, or '
                     'MutatorMath).')

    def exclude_args(parser, args, excluded_args):
        exclusive_msg = '"{}" argument only available for {} source'
        exclusive_src = {
            'interpolate': 'Glyphs or MutatorMath',
            'family_name': 'Glyphs'
        }
        for excluded in excluded_args:
            if args[excluded]:
                parser.error(
                    exclusive_msg.format(excluded, exclusive_src[excluded]))
            del args[excluded]

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    elif designspace_path:
        exclude_args(parser, args, ['family_name'])
        project.run_from_designspace(designspace_path, **args)

    else:
        exclude_args(parser, args, ['family_name', 'interpolate'])

    if ufo_paths:
        project.run_from_ufos(ufo_paths,
                              is_instance=args.pop('masters_as_instances'),
                              **args)
예제 #24
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument('-o',
                        '--output',
                        nargs='+',
                        default=('otf', 'ttf'),
                        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable',
                                 'variable'))

    parser.add_argument(
        '-i',
        '--interpolate',
        action='store_true',
        help='Interpolate masters (for Glyphs or MutatorMath sources only)')
    parser.add_argument('-M',
                        '--masters-as-instances',
                        action='store_true',
                        help='Output masters as instances')
    parser.add_argument(
        '--family-name',
        help='Family name to use for masters, and to filter output instances')

    parser.add_argument('--mti-source')
    parser.add_argument(
        '--interpolate-binary-layout',
        action='store_true',
        help='Interpolate layout tables from compiled master binaries. '
        'Requires Glyphs or MutatorMath source.')
    parser.add_argument('--use-afdko', action='store_true')

    parser.add_argument('-a',
                        '--autohint',
                        nargs='?',
                        const='',
                        help='Run ttfautohint. Can provide arguments, quoted')
    parser.add_argument(
        '--keep-direction',
        dest='reverse_direction',
        action='store_false',
        help='Do not reverse contour direction when output is ttf or '
        'ttf-interpolatable')
    parser.add_argument('--keep-overlaps',
                        dest='remove_overlaps',
                        action='store_false',
                        help='Do not remove any overlap.')

    group1 = parser.add_mutually_exclusive_group(required=False)
    group1.add_argument(
        '--production-names',
        dest='use_production_names',
        action='store_true',
        help='Rename glyphs with production names if available otherwise use '
        'uninames.')
    group1.add_argument('--no-production-names',
                        dest='use_production_names',
                        action='store_false')

    group2 = parser.add_mutually_exclusive_group(required=False)
    group2.add_argument('--subset',
                        dest='subset',
                        action='store_true',
                        help='Subset font using export flags set by glyphsLib')
    group2.add_argument('--no-subset', dest='subset', action='store_false')

    group3 = parser.add_mutually_exclusive_group(required=False)
    group3.add_argument('-s',
                        '--subroutinize',
                        action='store_true',
                        help='Optimize CFF table using compreffor (default)')
    group3.add_argument('-S',
                        '--no-subroutinize',
                        dest='subroutinize',
                        action='store_false')
    parser.add_argument(
        '-e',
        '--conversion-error',
        type=float,
        default=None,
        metavar='ERROR',
        help='Maximum approximation error for cubic to quadratic conversion '
        'measured in EM')

    parser.set_defaults(use_production_names=None,
                        subset=None,
                        subroutinize=True)

    parser.add_argument('--timing', action='store_true')
    parser.add_argument('--verbose', default='INFO')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'),
                          verbose=args.pop('verbose'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if sum(1 for p in [glyphs_path, ufo_paths, designspace_path] if p) != 1:
        parser.error('Exactly one source type required (Glyphs, UFO, or '
                     'MutatorMath).')

    def exclude_args(parser, args, excluded_args, source_name):
        msg = '"%s" argument only available for %s source'
        for excluded in excluded_args:
            if args[excluded]:
                parser.error(msg % (excluded, source_name))
            del args[excluded]

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)
        return

    exclude_args(parser, args, ['family_name'], 'Glyphs')
    if designspace_path:
        project.run_from_designspace(designspace_path, **args)
        return

    exclude_args(parser, args, ['interpolate', 'interpolate_binary_layout'],
                 'Glyphs or MutatorMath')
    project.run_from_ufos(ufo_paths,
                          is_instance=args.pop('masters_as_instances'),
                          **args)
예제 #25
0
def main(args=None):
    parser = ArgumentParser()
    parser.add_argument("--version", action="version", version=__version__)
    inputGroup = parser.add_argument_group(
        title="Input arguments",
        description="The following arguments are mutually exclusive.",
    )
    xInputGroup = inputGroup.add_mutually_exclusive_group(required=True)
    xInputGroup.add_argument("-g",
                             "--glyphs-path",
                             metavar="GLYPHS",
                             help="Path to .glyphs source file")
    xInputGroup.add_argument(
        "-u",
        "--ufo-paths",
        nargs="+",
        metavar="UFO",
        help="One or more paths to UFO files",
    )
    xInputGroup.add_argument(
        "-m",
        "--mm-designspace",
        metavar="DESIGNSPACE",
        help="Path to .designspace file",
    )

    outputGroup = parser.add_argument_group(title="Output arguments")
    outputGroup.add_argument(
        "-o",
        "--output",
        nargs="+",
        default=("otf", "ttf"),
        metavar="FORMAT",
        help="Output font formats. Choose between: %(choices)s. "
        "Default: otf, ttf",
        choices=(
            "ufo",
            "otf",
            "ttf",
            "ttf-interpolatable",
            "otf-interpolatable",
            "variable",
            "variable-cff2",
        ),
    )
    outputSubGroup = outputGroup.add_mutually_exclusive_group()
    outputSubGroup.add_argument(
        "--output-path",
        default=None,
        help="Output font file path. Only valid when the output is a single "
        "file (e.g. input is a single UFO or output is variable font)",
    )
    outputSubGroup.add_argument(
        "--output-dir",
        default=None,
        help="Output folder. By default, output folders are created in the "
        "current working directory, grouping output fonts by format.",
    )
    outputGroup.add_argument(
        "-i",
        "--interpolate",
        nargs="?",
        default=False,
        const=True,
        metavar="INSTANCE_NAME",
        help="Interpolate masters and generate all the instances defined. "
        "To only interpolate a specific instance (or instances) that "
        'match a given "name" attribute, you can pass as argument '
        "the full instance name or a regular expression. "
        'E.g.: -i "Noto Sans Bold"; or -i ".* UI Condensed". '
        "(for Glyphs or MutatorMath sources only). ",
    )
    outputGroup.add_argument(
        "-M",
        "--masters-as-instances",
        action="store_true",
        help="Output masters as instances",
    )
    outputGroup.add_argument(
        "--family-name",
        help="Family name to use for masters, and to filter output instances",
    )
    outputGroup.add_argument(
        "--round-instances",
        dest="round_instances",
        action="store_true",
        help="Apply integer rounding to all geometry when interpolating",
    )
    outputGroup.add_argument(
        "--designspace-path",
        default=None,
        help="Path to output designspace file (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--master-dir",
        default=None,
        help='Directory where to write master UFO. Default: "./master_ufo". '
        'If value is "{tmp}", a temporary directory is created and '
        "removed at the end (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--instance-dir",
        default=None,
        help="Directory where to write instance UFOs. Default: "
        '"./instance_ufo". If value is "{tmp}", a temporary directory '
        "is created and removed at the end (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--validate-ufo",
        action="store_true",
        help="Enable ufoLib validation on reading/writing UFO files. It is "
        "disabled by default",
    )

    contourGroup = parser.add_argument_group(title="Handling of contours")
    contourGroup.add_argument(
        "--keep-overlaps",
        dest="remove_overlaps",
        action="store_false",
        help="Do not remove any overlap.",
    )
    contourGroup.add_argument(
        "--overlaps-backend",
        dest="overlaps_backend",
        metavar="BACKEND",
        choices=("booleanOperations", "pathops"),
        default="booleanOperations",
        help="Select library to remove overlaps. Choose between: %(choices)s "
        "(default: %(default)s)",
    )
    contourGroup.add_argument(
        "--keep-direction",
        dest="reverse_direction",
        action="store_false",
        help="Do not reverse contour direction when output is ttf or "
        "ttf-interpolatable",
    )
    contourGroup.add_argument(
        "-e",
        "--conversion-error",
        type=float,
        default=None,
        metavar="ERROR",
        help="Maximum approximation error for cubic to quadratic conversion "
        "measured in EM",
    )
    contourGroup.add_argument(
        "-a",
        "--autohint",
        nargs="?",
        const="",
        help="Run ttfautohint. Can provide arguments, quoted",
    )
    contourGroup.add_argument(
        "--cff-round-tolerance",
        type=float,
        default=None,
        metavar="FLOAT",
        help="Restrict rounding of point coordinates in CFF table to only "
        "those floats whose absolute difference from their integral part "
        "is less than or equal to the tolerance. By default, all floats "
        "are rounded to integer (tolerance 0.5); 0 disables rounding.",
    )
    contourGroup.add_argument(
        "--optimize-cff",
        type=lambda s: CFFOptimization(int(s)),
        default=CFFOptimization.SUBROUTINIZE,
        help="0 disables all optimizations; 1 specializes the CFF charstring "
        "operators; 2 (default) also enables subroutinization",
    )

    layoutGroup = parser.add_argument_group(
        title="Handling of OpenType Layout")
    layoutGroup.add_argument(
        "--interpolate-binary-layout",
        nargs="?",
        default=False,
        const=True,
        metavar="MASTER_DIR",
        help="Interpolate layout tables from compiled master binaries. "
        "Requires Glyphs or MutatorMath source.",
    )
    layoutGroup.add_argument(
        "--feature-writer",
        metavar="CLASS",
        action="append",
        dest="feature_writer_specs",
        help="string specifying a feature writer class to load, either "
        "built-in or from an external module, optionally initialized with "
        "the given keyword arguments. The class and module names are "
        "separated by '::'. The option can be repeated multiple times "
        "for each writer class. A special value of 'None' will disable "
        "all automatic feature generation. The option overrides both the "
        "default ufo2ft writers and those specified in the UFO lib.",
    )

    feaCompilerGroup = layoutGroup.add_mutually_exclusive_group(required=False)
    feaCompilerGroup.add_argument(
        "--use-afdko",
        action="store_true",
        help="Use makeOTF instead of feaLib to compile FEA.",
    )
    feaCompilerGroup.add_argument(
        "--mti-source",
        help="Path to mtiLib .txt feature definitions (use instead of FEA)",
    )

    glyphnamesGroup = parser.add_mutually_exclusive_group(required=False)
    glyphnamesGroup.add_argument(
        "--production-names",
        dest="use_production_names",
        action="store_true",
        help="Rename glyphs with production names if available otherwise use "
        "uninames.",
    )
    glyphnamesGroup.add_argument("--no-production-names",
                                 dest="use_production_names",
                                 action="store_false")

    subsetGroup = parser.add_mutually_exclusive_group(required=False)
    subsetGroup.add_argument(
        "--subset",
        dest="subset",
        action="store_true",
        help="Subset font using export flags set by glyphsLib",
    )
    subsetGroup.add_argument("--no-subset",
                             dest="subset",
                             action="store_false")

    subroutinizeGroup = parser.add_mutually_exclusive_group(required=False)
    subroutinizeGroup.add_argument(
        "-s",
        "--subroutinize",
        action="store_true",
        help="Optimize CFF table using compreffor (default) [DEPRECATED: use "
        "--optimize-cff option instead]",
    )
    subroutinizeGroup.add_argument("-S",
                                   "--no-subroutinize",
                                   dest="subroutinize",
                                   action="store_false")

    parser.set_defaults(use_production_names=None,
                        subset=None,
                        subroutinize=None)

    logGroup = parser.add_argument_group(title="Logging arguments")
    logGroup.add_argument("--timing",
                          action="store_true",
                          help="Print the elapsed time for each steps")
    logGroup.add_argument(
        "--verbose",
        default="INFO",
        metavar="LEVEL",
        choices=("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"),
        help="Configure the logger verbosity level. Choose between: "
        "%(choices)s. Default: INFO",
    )
    args = vars(parser.parse_args(args))

    specs = args.pop("feature_writer_specs")
    if specs is not None:
        args["feature_writers"] = _loadFeatureWriters(parser, specs)

    glyphs_path = args.pop("glyphs_path")
    ufo_paths = args.pop("ufo_paths")
    designspace_path = args.pop("mm_designspace")
    input_format = ("Glyphs" if glyphs_path else
                    "designspace" if designspace_path else "UFO") + " source"

    if INTERPOLATABLE_OUTPUTS.intersection(args["output"]):
        if not (glyphs_path or designspace_path):
            parser.error(
                "Glyphs or designspace source required for variable font")
        exclude_args(
            parser,
            args,
            [
                "interpolate", "masters_as_instances",
                "interpolate_binary_layout"
            ],
            "variable output",
        )

    try:
        project = FontProject(
            timing=args.pop("timing"),
            verbose=args.pop("verbose"),
            validate_ufo=args.pop("validate_ufo"),
        )

        if glyphs_path:
            with _make_tempdirs(parser, args):
                project.run_from_glyphs(glyphs_path, **args)
            return

        exclude_args(
            parser,
            args,
            [
                "family_name",
                "mti_source",
                "designspace_path",
                "master_dir",
                "instance_dir",
            ],
            input_format,
        )
        if designspace_path:
            project.run_from_designspace(designspace_path, **args)
            return

        exclude_args(
            parser,
            args,
            ["interpolate", "interpolate_binary_layout", "round_instances"],
            input_format,
        )
        project.run_from_ufos(ufo_paths,
                              is_instance=args.pop("masters_as_instances"),
                              **args)
    except FontmakeError as e:
        import sys

        sys.exit("fontmake: error: %s" % e)
예제 #26
0
def write_binary_fonts(path, hand):
    ufo_path = write_ufo_font(path, foundational)
    builder = FontProject(verbose="ERROR")
    builder._output_dir = lambda *args, **kwargs: path
    builder.run_from_ufos([ufo_path], output=("otf", "ttf"), remove_overlaps=False)
예제 #27
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument(
        '-o', '--output', nargs='+', default=('otf', 'ttf'),
        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable', 'variable'))

    parser.add_argument(
        '-i', '--interpolate', action='store_true',
        help='Interpolate masters (for Glyphs or MutatorMath sources only)')
    parser.add_argument(
        '-M', '--masters-as-instances', action='store_true',
        help='Output masters as instances')
    parser.add_argument(
        '--family-name',
        help='Family name to use for masters, and to filter output instances')

    parser.add_argument(
        '--mti-source')
    parser.add_argument(
        '--interpolate-binary-layout', action='store_true',
        help='Interpolate layout tables from compiled master binaries. '
             'Requires Glyphs or MutatorMath source.')
    parser.add_argument(
        '--use-afdko', action='store_true')

    parser.add_argument(
        '-a', '--autohint', nargs='?', const='',
        help='Run ttfautohint. Can provide arguments, quoted')
    parser.add_argument(
        '--keep-direction', dest='reverse_direction', action='store_false',
        help='Do not reverse contour direction when output is ttf or '
             'ttf-interpolatable')
    parser.add_argument(
        '--keep-overlaps', dest='remove_overlaps', action='store_false',
        help='Do not remove any overlap.')

    group1 = parser.add_mutually_exclusive_group(required=False)
    group1.add_argument(
        '--production-names', dest='use_production_names', action='store_true',
        help='Rename glyphs with production names if available otherwise use '
             'uninames.')
    group1.add_argument(
        '--no-production-names', dest='use_production_names',
        action='store_false')

    group2 = parser.add_mutually_exclusive_group(required=False)
    group2.add_argument(
        '--subset', dest='subset', action='store_true',
        help='Subset font using export flags set by glyphsLib')
    group2.add_argument(
        '--no-subset', dest='subset', action='store_false')

    group3 = parser.add_mutually_exclusive_group(required=False)
    group3.add_argument(
        '-s', '--subroutinize', action='store_true',
        help='Optimize CFF table using compreffor (default)')
    group3.add_argument(
        '-S', '--no-subroutinize', dest='subroutinize', action='store_false')
    parser.add_argument(
        '-e', '--conversion-error', type=float, default=None, metavar='ERROR',
        help='Maximum approximation error for cubic to quadratic conversion '
             'measured in EM')

    parser.set_defaults(use_production_names=None, subset=None,
                        subroutinize=True)

    parser.add_argument('--timing', action='store_true')
    parser.add_argument('--verbose', default='INFO')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'),
                          verbose=args.pop('verbose'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if sum(1 for p in [glyphs_path, ufo_paths, designspace_path] if p) != 1:
        parser.error('Exactly one source type required (Glyphs, UFO, or '
                     'MutatorMath).')

    def exclude_args(parser, args, excluded_args, source_name):
        msg = '"%s" argument only available for %s source'
        for excluded in excluded_args:
            if args[excluded]:
                parser.error(msg % (excluded, source_name))
            del args[excluded]

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)
        return

    exclude_args(parser, args, ['family_name'], 'Glyphs')
    if designspace_path:
        project.run_from_designspace(designspace_path, **args)
        return

    exclude_args(
        parser, args, ['interpolate', 'interpolate_binary_layout'],
        'Glyphs or MutatorMath')
    project.run_from_ufos(
        ufo_paths, is_instance=args.pop('masters_as_instances'), **args)
예제 #28
0
    shutil.rmtree("instances", ignore_errors=True)
    os.makedirs("instances")
if os.path.exists("master_ttf"):
    shutil.rmtree("master_ttf", ignore_errors=True)
    os.makedirs("master_ttf")
if os.path.exists("master_ufo"):
    shutil.rmtree("master_ufo", ignore_errors=True)
    os.makedirs("master_ufo")
if os.path.exists("master_ttf_interpolatable"):
    shutil.rmtree("master_ttf_interpolatable", ignore_errors=True)
    os.makedirs("master_ttf_interpolatable")

if not os.path.exists("fonts"):
    os.makedirs("fonts")

project = FontProject()
project.run_from_ufos(
    romans,
    output=("ttf-interpolatable"
            ),  # FIXME this also build master_ttf and should not.
    remove_overlaps=False,
    reverse_direction=False,
    use_production_names=False)

#designSpace = "sources/Amstelvar-NewCharset/Amstelvar-Roman-006.designspace"
designSpace = "sources/Amstelvar-NewCharset/Amstelvar-Roman-009.designspace"

#outfile = "Amstelvar-Roman-VF.ttf"
outfile = "fonts/Amstelvar-Roman-VF.ttf"

finder = lambda s: s.replace("sources/Amstelvar-NewCharset/Roman/",
def designSpace2Instances(family, *output, newName=" ", secureSet=True):
    if len(output) == 1 and "otf" in output:
        makeOtfFamily(family, newName=newName, onlyOtf=True)
        return
    securetSetIsIncluded = pan_european_fonts
    if "otf" in output:
        makeOtfFamily(family, newName=newName)
    mergeable = ["ttf", "woff2", "woff"]
    if family not in securetSetIsIncluded:
        temp = list(set(mergeable) & set(output))
        if len(temp) == 0:
            output = ["ttf"]
        else:
            output = temp
    if "ttf" not in output:
        output.append("ttf")
    path, folder = getFile(".designspace", family)
    designSpace = openDesignSpace(path)
    destination = folder + "/" + "Instances"
    ###
    ### test if mti
    for file in os.listdir(folder):
        if file.endswith(".plist"):
            print("Make fonts with Mti files")
            # INJECT COMPILED TABLE IN FONTS
            ufoWithMTIfeatures2font(family, output)
            if secureSet is True:
                for i in output:
                    addSecureSet(family, output)
            if newName != " ":
                renameFonts(family, newName)
            if "woff" in output:
                destination = os.path.join(folder, "fonts/WOFF")
                if not os.path.exists(destination):
                    os.makedirs(destination)
                for ttf in os.listdir(os.path.join(folder, "fonts/TTF")):
                    if ttf.endswith("ttf"):
                        woff = ttLib.TTFont(
                            os.path.join(folder, "fonts/TTF", ttf))
                        woff.flavor = "woff"
                        woff.save(os.path.join(destination,
                                               ttf[:-4] + ".woff"))
            if "woff2" in output:
                destination = os.path.join(folder, "fonts/WOFF2")
                if not os.path.exists(destination):
                    os.makedirs(destination)
                for ttf in os.listdir(os.path.join(folder, "fonts/TTF")):
                    if ttf.endswith("ttf"):
                        woff = ttLib.TTFont(
                            os.path.join(folder, "fonts/TTF", ttf))
                        woff.flavor = "woff2"
                        woff.save(
                            os.path.join(destination, ttf[:-4] + ".woff2"))
            return

    fp = FontProject()
    fonts = fp.run_from_designspace(expand_features_to_instances=True,
                                    use_mutatormath=False,
                                    designspace_path=path,
                                    interpolate=True,
                                    output=("otf"),
                                    output_dir=destination)
    ufolist = list()
    for ufo in os.listdir(os.path.join(folder, "instance_ufos")):
        if ufo[-4:] == ".ufo":
            ufolist.append(ufo)
    instancesFolder = family + "/instance_ufos"

    if "ttf" in output:
        ufo2font(instancesFolder, ufolist, "ttf", fromInstances=True)
        if secureSet:
            addSecureSet(family, output)

    if "woff" in output:
        destination = os.path.join(folder, "fonts/WOFF")
        if not os.path.exists(destination):
            os.makedirs(destination)
        for ttf in os.listdir(os.path.join(folder, "fonts/TTF")):
            if ttf.endswith("ttf"):
                woff = ttLib.TTFont(os.path.join(folder, "fonts/TTF", ttf))
                woff.flavor = "woff"
                woff.save(os.path.join(destination, ttf[:-4] + ".woff"))

    if "woff2" in output:
        destination = os.path.join(folder, "fonts/WOFF2")
        if not os.path.exists(destination):
            os.makedirs(destination)
        for ttf in os.listdir(os.path.join(folder, "fonts/TTF")):
            if ttf.endswith("ttf"):
                woff = ttLib.TTFont(os.path.join(folder, "fonts/TTF", ttf))
                woff.flavor = "woff2"
                woff.save(os.path.join(destination, ttf[:-4] + ".woff2"))

    if newName != " ":
        renameFonts(family, newName)
예제 #30
0
def main(args=None):
    parser = ArgumentParser()
    parser.add_argument("--version", action="version", version=__version__)
    inputGroup = parser.add_argument_group(
        title="Input arguments (flags)",
        description=
        "The following arguments are mutually exclusive (pick only one):",
    )
    xInputGroup = inputGroup.add_mutually_exclusive_group()
    xInputGroup.add_argument("-g",
                             "--glyphs-path",
                             metavar="GLYPHS",
                             help="Path to .glyphs source file")
    xInputGroup.add_argument(
        "-u",
        "--ufo-paths",
        nargs="+",
        metavar="UFO",
        help="One or more paths to UFO files",
    )
    xInputGroup.add_argument(
        "-m",
        "--mm-designspace",
        metavar="DESIGNSPACE",
        help="Path to .designspace file",
    )
    positionalInputs = parser.add_argument_group(
        title="Input arguments (positonal)",
        description=
        "Alternatively, guess source format from filename extension",
    )
    positionalInputs.add_argument(
        "posargs",
        nargs="*",
        metavar="INPUTS",
        help="Either one *.designspace or *.glyphs file, or one or more *.ufo",
    )

    outputGroup = parser.add_argument_group(title="Output arguments")
    outputGroup.add_argument(
        "-o",
        "--output",
        nargs="+",
        default=("otf", "ttf"),
        metavar="FORMAT",
        help=
        "Output font formats. Choose 1 or more from: %(choices)s. Default: otf, ttf. "
        "(No file paths).",
        choices=(
            "ufo",
            "otf",
            "otf-cff2",
            "ttf",
            "ttf-interpolatable",
            "otf-interpolatable",
            "variable",
            "variable-cff2",
        ),
    )
    outputSubGroup = outputGroup.add_mutually_exclusive_group()
    outputSubGroup.add_argument(
        "--output-path",
        default=None,
        help="Output font file path. Only valid when the output is a single "
        "file (e.g. input is a single UFO or output is variable font)",
    )
    outputSubGroup.add_argument(
        "--output-dir",
        default=None,
        help="Output folder. By default, output folders are created in the "
        "current working directory, grouping output fonts by format.",
    )
    outputGroup.add_argument(
        "-i",
        "--interpolate",
        nargs="?",
        default=False,
        const=True,
        metavar="INSTANCE_NAME",
        help="Interpolate masters and generate all the instances defined. "
        "To only interpolate a specific instance (or instances) that "
        'match a given "name" attribute, you can pass as argument '
        "the full instance name or a regular expression. "
        'E.g.: -i "Noto Sans Bold"; or -i ".* UI Condensed". '
        "(for Glyphs or MutatorMath sources only). ",
    )
    outputGroup.add_argument(
        "--use-mutatormath",
        action="store_true",
        help=(
            "Use MutatorMath to generate instances (supports extrapolation and "
            "anisotropic locations)."),
    )
    outputGroup.add_argument(
        "-M",
        "--masters-as-instances",
        action="store_true",
        help="Output masters as instances",
    )
    outputGroup.add_argument(
        "--family-name",
        help="Family name to use for masters, and to filter output instances",
    )
    outputGroup.add_argument(
        "--round-instances",
        dest="round_instances",
        action="store_true",
        help="Apply integer rounding to all geometry when interpolating",
    )
    outputGroup.add_argument(
        "--designspace-path",
        default=None,
        help="Path to output designspace file (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--master-dir",
        default=None,
        help='Directory where to write master UFO. Default: "./master_ufo". '
        'If value is "{tmp}", a temporary directory is created and '
        "removed at the end (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--instance-dir",
        default=None,
        help="Directory where to write instance UFOs. Default: "
        '"./instance_ufo". If value is "{tmp}", a temporary directory '
        "is created and removed at the end (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--no-write-skipexportglyphs",
        action="store_false",
        dest="write_skipexportglyphs",
        help=
        "Do not store the glyph export flags in the 'public.skipExportGlyphs' "
        "key of designspace/UFO lib, but use the old private glyph lib key "
        "'com.schriftgestaltung.Glyphs.Export' (for Glyphs sources only).",
    )
    outputGroup.add_argument(
        "--validate-ufo",
        action="store_true",
        help="Enable ufoLib validation on reading/writing UFO files. It is "
        "disabled by default",
    )
    outputGroup.add_argument(
        "--check-compatibility",
        action="store_true",
        help="Check if the source files are interpolatable. It is "
        "disabled by default, but enabled when building variable fonts "
        "or what the 'Enforce Compatibility Check' custom parameter is "
        "set on a Glyphs file",
    )
    outputGroup.add_argument(
        "--expand-features-to-instances",
        action="store_true",
        help="Resolves all include()s in the master feature file and writes "
        "the full feature file to all instance UFOs. Only valid when "
        "interpolating. Use if you share feature files of masters in "
        "external files, as instances can end up elsewhere.",
    )
    outputGroup.add_argument(
        "--no-generate-GDEF",
        dest="generate_GDEF",
        action="store_false",
        help=
        "Do not auto-generate a GDEF table, but keep an existing one intact.",
    )

    contourGroup = parser.add_argument_group(title="Handling of contours")
    contourGroup.add_argument(
        "--keep-overlaps",
        dest="remove_overlaps",
        action="store_false",
        help="Do not remove any overlap.",
    )
    contourGroup.add_argument(
        "--overlaps-backend",
        dest="overlaps_backend",
        metavar="BACKEND",
        choices=("booleanOperations", "pathops"),
        default="booleanOperations",
        help="Select library to remove overlaps. Choose between: %(choices)s "
        "(default: %(default)s)",
    )
    contourGroup.add_argument(
        "--keep-direction",
        dest="reverse_direction",
        action="store_false",
        help="Do not reverse contour direction when output is ttf or "
        "ttf-interpolatable",
    )
    contourGroup.add_argument(
        "-e",
        "--conversion-error",
        type=float,
        default=None,
        metavar="ERROR",
        help="Maximum approximation error for cubic to quadratic conversion "
        "measured in EM",
    )
    contourGroup.add_argument(
        "-f",
        "--flatten-components",
        dest="flatten_components",
        action="store_true",
        help="Flatten nested components to single level.",
    )
    contourGroup.add_argument(
        "-a",
        "--autohint",
        nargs="?",
        const="",
        help="Run ttfautohint. Can provide arguments, quoted",
    )
    contourGroup.add_argument(
        "--cff-round-tolerance",
        type=float,
        default=None,
        metavar="FLOAT",
        help="Restrict rounding of point coordinates in CFF table to only "
        "those floats whose absolute difference from their integral part "
        "is less than or equal to the tolerance. By default, all floats "
        "are rounded to integer (tolerance 0.5); 0 disables rounding.",
    )
    contourGroup.add_argument(
        "--optimize-cff",
        type=lambda s: CFFOptimization(int(s)),
        default=CFFOptimization.SUBROUTINIZE,
        help="0 disables all optimizations; 1 specializes the CFF charstring "
        "operators; 2 (default) also enables subroutinization",
    )
    contourGroup.add_argument(
        "--subroutinizer",
        default=None,
        choices=["compreffor", "cffsubr"],
        help="name of the library to use for compressing CFF charstrings. "
        "Choose between: %(choices)s. By default compreffor is used for CFF 1, "
        "and cffsubr for CFF2. NOTE: compreffor doesn't support CFF2.",
    )
    contourGroup.add_argument(
        "--no-optimize-gvar",
        dest="optimize_gvar",
        action="store_false",
        help="Do not perform IUP optimization on variable font's 'gvar' table. "
        "(only works with 'variable' TrueType-flavored output)",
    )
    contourGroup.add_argument(
        "--filter",
        metavar="CLASS",
        action="append",
        dest="filter_specs",
        help="string specifying a filter class to load, either "
        "built-in or from an external module, optionally initialized with "
        "the given keyword arguments. The class and module names are "
        "separated by '::'. The option can be repeated multiple times "
        "for each filter class. The option overrides the filters specified "
        "in the UFO lib.",
    )

    layoutGroup = parser.add_argument_group(
        title="Handling of OpenType Layout")
    layoutGroup.add_argument(
        "--interpolate-binary-layout",
        nargs="?",
        default=False,
        const=True,
        metavar="MASTER_DIR",
        help="Interpolate layout tables from compiled master binaries. "
        "Requires Glyphs or MutatorMath source.",
    )
    layoutGroup.add_argument(
        "--feature-writer",
        metavar="CLASS",
        action="append",
        dest="feature_writer_specs",
        help="string specifying a feature writer class to load, either "
        "built-in or from an external module, optionally initialized with "
        "the given keyword arguments. The class and module names are "
        "separated by '::'. The option can be repeated multiple times "
        "for each writer class. A special value of 'None' will disable "
        "all automatic feature generation. The option overrides both the "
        "default ufo2ft writers and those specified in the UFO lib.",
    )
    layoutGroup.add_argument(
        "--debug-feature-file",
        metavar="FILE",
        type=FileType("w", encoding="utf-8"),
        default=None,
        help=(
            "Path were to dump OpenType features text to debug auto-generated "
            "features (kern, mark, mkmk, etc.)."),
    )

    feaCompilerGroup = layoutGroup.add_mutually_exclusive_group(required=False)
    feaCompilerGroup.add_argument(
        "--mti-source",
        help="mtiLib feature definition .plist file path (use instead of FEA)",
    )

    glyphnamesGroup = parser.add_mutually_exclusive_group(required=False)
    glyphnamesGroup.add_argument(
        "--production-names",
        dest="use_production_names",
        action="store_true",
        help="Rename glyphs with production names if available otherwise use "
        "uninames.",
    )
    glyphnamesGroup.add_argument("--no-production-names",
                                 dest="use_production_names",
                                 action="store_false")

    subsetGroup = parser.add_mutually_exclusive_group(required=False)
    subsetGroup.add_argument(
        "--subset",
        dest="subset",
        action="store_true",
        help="Subset font using export flags set by glyphsLib",
    )
    subsetGroup.add_argument("--no-subset",
                             dest="subset",
                             action="store_false")

    subroutinizeGroup = parser.add_mutually_exclusive_group(required=False)
    subroutinizeGroup.add_argument(
        "-s",
        "--subroutinize",
        action="store_true",
        help="Optimize CFF table using compreffor (default) [DEPRECATED: use "
        "--optimize-cff option instead]",
    )
    subroutinizeGroup.add_argument("-S",
                                   "--no-subroutinize",
                                   dest="subroutinize",
                                   action="store_false")

    parser.set_defaults(use_production_names=None,
                        subset=None,
                        subroutinize=None)

    logGroup = parser.add_argument_group(title="Logging arguments")
    logGroup.add_argument("--timing",
                          action="store_true",
                          help="Print the elapsed time for each steps")
    logGroup.add_argument(
        "--verbose",
        default="INFO",
        metavar="LEVEL",
        choices=("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"),
        help="Configure the logger verbosity level. Choose between: "
        "%(choices)s. Default: INFO",
    )

    args = vars(parser.parse_args(args))

    specs = args.pop("feature_writer_specs")
    if specs is not None:
        args["feature_writers"] = _loadFeatureWriters(parser, specs)

    specs = args.pop("filter_specs")
    if specs is not None:
        args["filters"] = _loadFilters(parser, specs)

    inputs = parse_mutually_exclusive_inputs(parser, args)

    if INTERPOLATABLE_OUTPUTS.intersection(args["output"]):
        if not (inputs.glyphs_path or inputs.designspace_path):
            parser.error(
                "Glyphs or designspace source required for variable font")
        exclude_args(
            parser,
            args,
            [
                "interpolate",
                "masters_as_instances",
                "interpolate_binary_layout",
                "use_mutatormath",
            ],
            "variable output",
        )
    else:
        exclude_args(parser,
                     args, ["optimize_gvar"],
                     "static output",
                     positive=False)

    if args.get("use_mutatormath"):
        for module in ("defcon", "mutatorMath"):
            try:
                __import__(module)
            except ImportError:
                parser.error(
                    f"{module} module not found; reinstall fontmake with the "
                    "[mutatormath] extra")

    PRINT_TRACEBACK = args.get("verbose", "INFO") == "DEBUG"
    try:
        project = FontProject(
            timing=args.pop("timing"),
            verbose=args.pop("verbose"),
            validate_ufo=args.pop("validate_ufo"),
        )

        if inputs.glyphs_path:
            with _make_tempdirs(parser, args):
                project.run_from_glyphs(inputs.glyphs_path, **args)
            return

        exclude_args(
            parser,
            args,
            [
                "family_name",
                "mti_source",
                "designspace_path",
                "master_dir",
                "instance_dir",
            ],
            inputs.format_name,
        )
        exclude_args(parser,
                     args, ["write_skipexportglyphs"],
                     inputs.format_name,
                     positive=False)
        if inputs.designspace_path:
            project.run_from_designspace(inputs.designspace_path, **args)
            return

        exclude_args(
            parser,
            args,
            [
                "interpolate",
                "use_mutatormath",
                "interpolate_binary_layout",
                "round_instances",
                "expand_features_to_instances",
                "check_compatibility",
            ],
            inputs.format_name,
        )
        project.run_from_ufos(inputs.ufo_paths,
                              is_instance=args.pop("masters_as_instances"),
                              **args)
    except FontmakeError as e:
        if PRINT_TRACEBACK:
            logging.exception(e)
            sys.exit(1)
        sys.exit(f"fontmake: Error: {str(e)}")
    finally:
        debug_feature_file = args.get("debug_feature_file")
        if debug_feature_file is not None:
            debug_feature_file.close()
예제 #31
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument(
        '-o', '--output', nargs='+', default=('otf', 'ttf'),
        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable', 'variable'))

    parser.add_argument('-i', '--interpolate', action='store_true',
                        help='interpolate masters (for Glyphs or MutatorMath '
                             'sources only)')
    parser.add_argument('-M', '--masters-as-instances', action='store_true',
                        help='treat masters as instances')
    parser.add_argument('-a', '--autohint', nargs='?', const="",
                        help='can provide arguments to ttfautohint, quoted')
    parser.add_argument('--mti-source')
    parser.add_argument('--family-name', help='Family name to use for masters,'
                        ' and to filter output instances by')
    parser.add_argument('--use-afdko', action='store_true')
    parser.add_argument('--keep-direction', dest="reverse_direction",
                        action='store_false', help='Do not reverse contour '
                        'direction when output is ttf or ttf-interpolatable')
    parser.add_argument('--keep-overlaps', dest="remove_overlaps",
                        action='store_false',
                        help='Do not remove any overlap.')
    group1 = parser.add_mutually_exclusive_group(required=False)
    group1.add_argument('--production-names', dest='use_production_names',
                        action='store_true', help='Rename glyphs with '
                        'production names if available otherwise use uninames.')
    group1.add_argument('--no-production-names', dest='use_production_names',
                        action='store_false')
    group2 = parser.add_mutually_exclusive_group(required=False)
    group2.add_argument('--subset', dest='subset',
                        action='store_true', help='Subset font using export '
                        'flags set by glyphsLib')
    group2.add_argument('--no-subset', dest='subset', action='store_false')
    group3 = parser.add_mutually_exclusive_group(required=False)
    group3.add_argument('-s', '--subroutinize', action='store_true',
                        help='Optimize CFF table using compreffor (default)')
    group3.add_argument('-S', '--no-subroutinize', dest='subroutinize',
                        action='store_false')
    parser.add_argument('-e', '--conversion-error', type=float, default=None,
                        metavar='ERROR', help="Maximum approximation error for"
                        " cubic to quadratic conversion measured in EM")
    parser.set_defaults(use_production_names=None, subset=None,
                        subroutinize=True)
    parser.add_argument('--timing', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if not sum(1 for p in [glyphs_path, ufo_paths, designspace_path] if p) == 1:
        parser.error('Exactly one source type required (Glyphs, UFO, or '
                     'MutatorMath).')

    def exclude_args(parser, args, excluded_args):
        exclusive_msg = '"{}" argument only available for {} source'
        exclusive_src = {'interpolate': 'Glyphs or MutatorMath',
                         'family_name': 'Glyphs'}
        for excluded in excluded_args:
            if args[excluded]:
                parser.error(exclusive_msg.format(
                    excluded,
                    exclusive_src[excluded]))
            del args[excluded]

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    elif designspace_path:
        exclude_args(parser, args, ['family_name'])
        project.run_from_designspace(designspace_path, **args)

    else:
        exclude_args(parser, args, ['family_name', 'interpolate'])

    if ufo_paths:
        project.run_from_ufos(
            ufo_paths, is_instance=args.pop('masters_as_instances'), **args)
예제 #32
0
def main(args=None):
    parser = ArgumentParser()
    parser.add_argument('--version', action='version', version=__version__)
    inputGroup = parser.add_argument_group(
        title='Input arguments',
        description='The following arguments are mutually exclusive.')
    xInputGroup = inputGroup.add_mutually_exclusive_group(required=True)
    xInputGroup.add_argument('-g',
                             '--glyphs-path',
                             metavar='GLYPHS',
                             help='Path to .glyphs source file')
    xInputGroup.add_argument('-u',
                             '--ufo-paths',
                             nargs='+',
                             metavar='UFO',
                             help='One or more paths to UFO files')
    xInputGroup.add_argument('-m',
                             '--mm-designspace',
                             metavar='DESIGNSPACE',
                             help='Path to .designspace file')

    outputGroup = parser.add_argument_group(title='Output arguments')
    outputGroup.add_argument(
        '-o',
        '--output',
        nargs='+',
        default=('otf', 'ttf'),
        metavar="FORMAT",
        help='Output font formats. Choose between: %(choices)s. '
        'Default: otf, ttf',
        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable', 'variable'))
    outputSubGroup = outputGroup.add_mutually_exclusive_group()
    outputSubGroup.add_argument(
        '--output-path',
        default=None,
        help="Output font file path. Only valid when the output is a single "
        "file (e.g. input is a single UFO or output is variable font)")
    outputSubGroup.add_argument(
        '--output-dir',
        default=None,
        help="Output folder. By default, output folders are created in the "
        "current working directory, grouping output fonts by format.")
    outputGroup.add_argument(
        '-i',
        '--interpolate',
        nargs="?",
        default=False,
        const=True,
        metavar="INSTANCE_NAME",
        help='Interpolate masters and generate all the instances defined. '
        'To only interpolate a specific instance (or instances) that '
        'match a given "name" attribute, you can pass as argument '
        'the full instance name or a regular expression. '
        'E.g.: -i "Noto Sans Bold"; or -i ".* UI Condensed". '
        '(for Glyphs or MutatorMath sources only). ')
    outputGroup.add_argument('-M',
                             '--masters-as-instances',
                             action='store_true',
                             help='Output masters as instances')
    outputGroup.add_argument(
        '--family-name',
        help='Family name to use for masters, and to filter output instances')
    outputGroup.add_argument(
        '--round-instances',
        dest='round_instances',
        action='store_true',
        help='Apply integer rounding to all geometry when interpolating')
    outputGroup.add_argument(
        '--designspace-path',
        default=None,
        help='Path to output designspace file (for Glyphs sources only).')
    outputGroup.add_argument(
        '--master-dir',
        default=None,
        help='Directory where to write master UFO. Default: "./master_ufo". '
        'If value is "{tmp}", a temporary directory is created and '
        'removed at the end (for Glyphs sources only).')
    outputGroup.add_argument(
        '--instance-dir',
        default=None,
        help='Directory where to write instance UFOs. Default: '
        '"./instance_ufo". If value is "{tmp}", a temporary directory '
        'is created and removed at the end (for Glyphs sources only).')

    contourGroup = parser.add_argument_group(title='Handling of contours')
    contourGroup.add_argument('--keep-overlaps',
                              dest='remove_overlaps',
                              action='store_false',
                              help='Do not remove any overlap.')
    contourGroup.add_argument(
        '--keep-direction',
        dest='reverse_direction',
        action='store_false',
        help='Do not reverse contour direction when output is ttf or '
        'ttf-interpolatable')
    contourGroup.add_argument(
        '-e',
        '--conversion-error',
        type=float,
        default=None,
        metavar='ERROR',
        help='Maximum approximation error for cubic to quadratic conversion '
        'measured in EM')
    contourGroup.add_argument(
        '-a',
        '--autohint',
        nargs='?',
        const='',
        help='Run ttfautohint. Can provide arguments, quoted')
    contourGroup.add_argument(
        '--cff-round-tolerance',
        type=float,
        default=None,
        metavar='FLOAT',
        help='Restrict rounding of point coordinates in CFF table to only '
        'those floats whose absolute difference from their integral part '
        'is less than or equal to the tolerance. By default, all floats '
        'are rounded to integer (tolerance 0.5); 0 disables rounding.')

    layoutGroup = parser.add_argument_group(
        title='Handling of OpenType Layout')
    layoutGroup.add_argument(
        '--interpolate-binary-layout',
        nargs="?",
        default=False,
        const=True,
        metavar="MASTER_DIR",
        help='Interpolate layout tables from compiled master binaries. '
        'Requires Glyphs or MutatorMath source.')
    layoutGroup.add_argument(
        "--feature-writer",
        metavar="CLASS",
        action="append",
        dest="feature_writer_specs",
        help="string specifying a feature writer class to load, either "
        "built-in or from an external module, optionally initialized with "
        "the given keyword arguments. The class and module names are "
        "separated by '::'. The option can be repeated multiple times "
        "for each writer class. A special value of 'None' will disable "
        "all automatic feature generation. The option overrides both the "
        "default ufo2ft writers and those specified in the UFO lib.")

    feaCompilerGroup = layoutGroup.add_mutually_exclusive_group(required=False)
    feaCompilerGroup.add_argument(
        '--use-afdko',
        action='store_true',
        help='Use makeOTF instead of feaLib to compile FEA.')
    feaCompilerGroup.add_argument(
        '--mti-source',
        help='Path to mtiLib .txt feature definitions (use instead of FEA)')

    glyphnamesGroup = parser.add_mutually_exclusive_group(required=False)
    glyphnamesGroup.add_argument(
        '--production-names',
        dest='use_production_names',
        action='store_true',
        help='Rename glyphs with production names if available otherwise use '
        'uninames.')
    glyphnamesGroup.add_argument('--no-production-names',
                                 dest='use_production_names',
                                 action='store_false')

    subsetGroup = parser.add_mutually_exclusive_group(required=False)
    subsetGroup.add_argument(
        '--subset',
        dest='subset',
        action='store_true',
        help='Subset font using export flags set by glyphsLib')
    subsetGroup.add_argument('--no-subset',
                             dest='subset',
                             action='store_false')

    subroutinizeGroup = parser.add_mutually_exclusive_group(required=False)
    subroutinizeGroup.add_argument(
        '-s',
        '--subroutinize',
        action='store_true',
        help='Optimize CFF table using compreffor (default)')
    subroutinizeGroup.add_argument('-S',
                                   '--no-subroutinize',
                                   dest='subroutinize',
                                   action='store_false')

    parser.set_defaults(use_production_names=None,
                        subset=None,
                        subroutinize=True)

    logGroup = parser.add_argument_group(title='Logging arguments')
    logGroup.add_argument('--timing',
                          action='store_true',
                          help="Print the elapsed time for each steps")
    logGroup.add_argument(
        '--verbose',
        default='INFO',
        metavar='LEVEL',
        choices=('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'),
        help='Configure the logger verbosity level. Choose between: '
        '%(choices)s. Default: INFO')
    args = vars(parser.parse_args(args))

    specs = args.pop("feature_writer_specs")
    if specs is not None:
        args["feature_writers"] = _loadFeatureWriters(parser, specs)

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    input_format = ("Glyphs" if glyphs_path else
                    "designspace" if designspace_path else "UFO") + " source"

    if 'variable' in args['output']:
        if not (glyphs_path or designspace_path):
            parser.error(
                'Glyphs or designspace source required for variable font')
        exclude_args(parser, args, [
            'interpolate', 'masters_as_instances', 'interpolate_binary_layout'
        ], "variable output")

    try:
        project = FontProject(timing=args.pop('timing'),
                              verbose=args.pop('verbose'))

        if glyphs_path:
            with _make_tempdirs(parser, args):
                project.run_from_glyphs(glyphs_path, **args)
            return

        exclude_args(parser, args, [
            'family_name', 'mti_source', 'designspace_path', 'master_dir',
            'instance_dir'
        ], input_format)
        if designspace_path:
            project.run_from_designspace(designspace_path, **args)
            return

        exclude_args(
            parser, args,
            ['interpolate', 'interpolate_binary_layout', 'round_instances'],
            input_format)
        project.run_from_ufos(ufo_paths,
                              is_instance=args.pop('masters_as_instances'),
                              **args)
    except FontmakeError as e:
        import sys
        sys.exit("fontmake: error: %s" % e)
예제 #33
0
def build_variable(
    designspacePath,
    stylespacePath=None,
    out=None,
    verbose="ERROR",
):
    """
    Builds a variable font from a designspace using fontmake.
    Post applies the STAT table using a stylespace if given.

    *designspacePath* a `string` of the path to the designspace
    *stylespacePath* a `string` of the path to the stylespace
    *out* a `string` of the path where the varible font should be saved
    *verbose* sets the verbosity level for fontmake. Defaults to "ERROR"
    """

    if out is None:
        out = os.path.splitext(
            os.path.basename(designspacePath))[0] + "-VF.ttf"

    else:
        if not os.path.exists(os.path.split(out)[0]):
            os.mkdir(os.path.split(out)[0])

    print("🏗  Constructing variable font")
    fp = FontProject(verbose=verbose)
    fp.build_variable_font(designspacePath,
                           output_path=out,
                           useProductionNames=True)

    if stylespacePath is not None:
        print("🏗  Adding STAT table")
        ds = DesignSpaceDocument.fromfile(designspacePath)
        additional_locations = ds.lib.get("org.statmake.additionalLocations",
                                          {})
        font = fontTools.ttLib.TTFont(out)
        stylespace = Stylespace.from_file(stylespacePath)
        apply_stylespace_to_variable_font(stylespace, font,
                                          additional_locations)
        font.save(out)

    font = fontTools.ttLib.TTFont(out)

    print("🏗  Add gasp table")
    gasp = fontTools.ttLib.newTable("gasp")
    gasp.gaspRange = {0xFFFF: 15}
    font["gasp"] = gasp

    print("🏗  Fix prep table")
    program = fontTools.ttLib.tables.ttProgram.Program()

    assembly = ['PUSHW[]', '511', 'SCANCTRL[]', 'PUSHB[]', '4', 'SCANTYPE[]']
    program.fromAssembly(assembly)
    prep = fontTools.ttLib.newTable("prep")
    prep.program = program
    font["prep"] = prep

    print("🏗  Add dsig table")
    dsig = fontTools.ttLib.newTable("DSIG")
    dsig.ulVersion = 1
    dsig.usFlag = 0
    dsig.usNumSigs = 0
    dsig.signatureRecords = []
    font["DSIG"] = dsig

    print("🏗  Set fsType to 0")
    font["OS/2"].fsType = 0

    font.save(out)

    print("✅ Built variable font")
예제 #34
0
from pathlib import Path

SCRIPTING_DIR = Path(__file__).parent

INPUT_DIR = SCRIPTING_DIR / "eac"
UFO_PATH = INPUT_DIR / "variants" / "variants.ufo"
FEA_PATH = INPUT_DIR / "otl.fea"

OUTPUT_DIR = SCRIPTING_DIR / "products"
FAMILY_NAME = "Sandbox EAC"
FORMAT = "otf"

ufo = defcon.Font(path=UFO_PATH)

ufo.info.familyName = FAMILY_NAME
ufo.info.styleName = "Regular"

project = FontProject()

font_name = project._font_name(ufo)
output_path = project._output_path(font_name, FORMAT, output_dir=OUTPUT_DIR)

project.run_from_ufos(
    [ufo],
    output=[FORMAT],
    # For .save_otfs:
    remove_overlaps=False,
    output_path=output_path,
    debug_feature_file=(OUTPUT_DIR / "debug.fea").open("w")
)
예제 #35
0
파일: __main__.py 프로젝트: brawer/fontmake
def main(args=None):
    parser = ArgumentParser()
    parser.add_argument('--version', action='version', version=__version__)
    inputGroup = parser.add_argument_group(
        title='Input arguments',
        description='The following arguments are mutually exclusive.')
    xInputGroup = inputGroup.add_mutually_exclusive_group(required=True)
    xInputGroup.add_argument(
        '-g', '--glyphs-path', metavar='GLYPHS',
        help='Path to .glyphs source file')
    xInputGroup.add_argument(
        '-u', '--ufo-paths', nargs='+', metavar='UFO',
        help='One or more paths to UFO files')
    xInputGroup.add_argument(
        '-m', '--mm-designspace', metavar='DESIGNSPACE',
        help='Path to .designspace file')

    outputGroup = parser.add_argument_group(title='Output arguments')
    outputGroup.add_argument(
        '-o', '--output', nargs='+', default=('otf', 'ttf'), metavar="FORMAT",
        help='Output font formats. Choose between: %(choices)s. '
             'Default: otf, ttf',
        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable', 'variable'))
    outputGroup.add_argument(
        '-i', '--interpolate', action='store_true',
        help='Interpolate masters (for Glyphs or MutatorMath sources only)')
    outputGroup.add_argument(
        '-M', '--masters-as-instances', action='store_true',
        help='Output masters as instances')
    outputGroup.add_argument(
        '--family-name',
        help='Family name to use for masters, and to filter output instances')

    contourGroup = parser.add_argument_group(title='Handling of contours')
    contourGroup.add_argument(
        '--keep-overlaps', dest='remove_overlaps', action='store_false',
        help='Do not remove any overlap.')
    contourGroup.add_argument(
        '--keep-direction', dest='reverse_direction', action='store_false',
        help='Do not reverse contour direction when output is ttf or '
             'ttf-interpolatable')
    contourGroup.add_argument(
        '-e', '--conversion-error', type=float, default=None, metavar='ERROR',
        help='Maximum approximation error for cubic to quadratic conversion '
             'measured in EM')
    contourGroup.add_argument(
        '-a', '--autohint', nargs='?', const='',
        help='Run ttfautohint. Can provide arguments, quoted')

    layoutGroup = parser.add_argument_group(title='Handling of OpenType Layout')
    layoutGroup.add_argument(
        '--interpolate-binary-layout', action='store_true',
        help='Interpolate layout tables from compiled master binaries. '
             'Requires Glyphs or MutatorMath source.')
    layoutGroup.add_argument(
        '--use-afdko', action='store_true',
        help='Use makeOTF instead of feaLib to compile FEA.')
    layoutGroup.add_argument(
        '--mti-source',
        help='Path to mtiLib .txt feature definitions (use instead of FEA)')
    layoutGroup.add_argument(
        '--kern-writer-module', metavar="MODULE", dest='kern_writer_class',
        type=PyClassType('KernFeatureWriter'),
        help='Module containing a custom `KernFeatureWriter` class.')
    layoutGroup.add_argument(
        '--mark-writer-module', metavar="MODULE", dest='mark_writer_class',
        type=PyClassType('MarkFeatureWriter'),
        help='Module containing a custom `MarkFeatureWriter` class.')

    glyphnamesGroup = parser.add_mutually_exclusive_group(required=False)
    glyphnamesGroup.add_argument(
        '--production-names', dest='use_production_names', action='store_true',
        help='Rename glyphs with production names if available otherwise use '
             'uninames.')
    glyphnamesGroup.add_argument(
        '--no-production-names', dest='use_production_names',
        action='store_false')

    subsetGroup = parser.add_mutually_exclusive_group(required=False)
    subsetGroup.add_argument(
        '--subset', dest='subset', action='store_true',
        help='Subset font using export flags set by glyphsLib')
    subsetGroup.add_argument(
        '--no-subset', dest='subset', action='store_false')

    subroutinizeGroup = parser.add_mutually_exclusive_group(required=False)
    subroutinizeGroup.add_argument(
        '-s', '--subroutinize', action='store_true',
        help='Optimize CFF table using compreffor (default)')
    subroutinizeGroup.add_argument(
        '-S', '--no-subroutinize', dest='subroutinize', action='store_false')

    parser.set_defaults(use_production_names=None, subset=None,
                        subroutinize=True)

    logGroup = parser.add_argument_group(title='Logging arguments')
    logGroup.add_argument(
        '--timing', action='store_true',
        help="Print the elapsed time for each steps")
    logGroup.add_argument(
        '--verbose', default='INFO', metavar='LEVEL',
        choices=('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'),
        help='Configure the logger verbosity level. Choose between: '
             '%(choices)s. Default: INFO')
    args = vars(parser.parse_args(args))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')

    if 'variable' in args['output']:
        if not (glyphs_path or designspace_path):
            parser.error(
                'Glyphs or designspace source required for variable font')
        for argname in ('interpolate', 'masters_as_instances',
                        'interpolate_binary_layout'):
            if args[argname]:
                parser.error('--%s option invalid for variable font'
                             % argname.replace("_", "-"))

    project = FontProject(timing=args.pop('timing'),
                          verbose=args.pop('verbose'))

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)
        return

    exclude_args(parser, args, ['family_name'], 'Glyphs')
    if designspace_path:
        project.run_from_designspace(designspace_path, **args)
        return

    exclude_args(
        parser, args, ['interpolate', 'interpolate_binary_layout'],
        'Glyphs or MutatorMath')
    project.run_from_ufos(
        ufo_paths, is_instance=args.pop('masters_as_instances'), **args)
예제 #36
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument('-o', '--output', nargs='+', default=('otf', 'ttf'),
                        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable'))
    parser.add_argument('-i', '--interpolate', action='store_true',
                        help='interpolate masters (for Glyphs or MutatorMath '
                             'sources only)')
    parser.add_argument('-mi', '--masters-as-instances', action='store_true',
                        help='treat masters as instances')
    parser.add_argument('-a', '--autohint', nargs='?',
                        help='can provide arguments to ttfautohint, quoted')
    parser.add_argument('--mti-source')
    parser.add_argument('--family-name', help='Family name to use for masters,'
                        ' and to filter output instances by')
    parser.add_argument('--use-afdko', action='store_true')
    parser.add_argument('--keep-direction', dest="reverse_direction",
                        action='store_false', help='Do not reverse contour '
                        'direction when output is ttf or ttf-interpolatable')
    parser.add_argument('--keep-overlaps', dest="remove_overlaps",
                        action='store_false',
                        help='Do not remove any overlap.')
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--production-names', dest='use_production_names',
                       action='store_true', help='Rename glyphs with '
                       'production names if available otherwise use uninames.')
    group.add_argument('--no-production-names', dest='use_production_names',
                       action='store_false',
                       help='Do not rename glyphs with production names. '
                       'Keeps original glyph names')
    parser.set_defaults(use_production_names=None)
    parser.add_argument('--timing', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if not sum(1 for p in [glyphs_path, ufo_paths, designspace_path] if p) == 1:
        parser.error('Exactly one source type required (Glyphs, UFO, or '
                     'MutatorMath).')

    def exclude_args(parser, args, excluded_args):
        exclusive_msg = '"{}" argument only available for {} source'
        exclusive_src = {'interpolate': 'Glyphs or MutatorMath',
                         'family_name': 'Glyphs'}
        for excluded in excluded_args:
            if args[excluded]:
                parser.error(exclusive_msg.format(
                    excluded,
                    exclusive_src[excluded]))
            del args[excluded]

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    elif designspace_path:
        exclude_args(parser, args, ['family_name'])
        project.run_from_designspace(designspace_path, **args)

    else:
        exclude_args(parser, args, ['family_name', 'interpolate'])

    if ufo_paths:
        project.run_from_ufos(
            ufo_paths, is_instance=args.pop('masters_as_instances'), **args)
예제 #37
0
makeTTF = True
makeWOFF = True

baseDir = os.path.split(__file__)[0]

if makeTTF:

    # gather UFOs from build script parent folder
    paths = []
    for filename in os.listdir(os.path.abspath(baseDir)):
        if filename.endswith('.ufo'):
            paths.append(filename)

    # make fontmake project
    project = FontProject()
    project.run_from_ufos(paths,
                          output=("ttf"),
                          remove_overlaps=False,
                          reverse_direction=False,
                          use_production_names=False)

if makeWOFF:

    #define woff and woff2 tools
    sfnt2woffPath = 'sfnt2woff-zopfli'
    sfnt2woff2Path = 'woff2_compress'
    returnedInfo = os.system(sfnt2woffPath)
    returnedInfo2 = os.system(sfnt2woff2Path)
    # hack for hardcoded absolute paths as fallback, sorry!
    if returnedInfo == 32512:
예제 #38
0
def getRunArguments():
    u"""Arguments to be passed to a fontmake project run. The values below
    make Decovar build without errors. See also fontmake.__main__.py."""

    args = {
        'subset': None,
        'use_production_names': False,
        #'mark_writer_class': None,
        'reverse_direction': False,
        #'kern_writer_class': None,
        'interpolate_binary_layout': False,
        'remove_overlaps': True,
        'autohint': None,
        'conversion_error': None,
        #'no_round': False,
        'masters_as_instances': True,
        'interpolate': True,
        'use_afdko': False,
        'subroutinize': True,
        'output':['ttf'],
    }
    return args

project = FontProject()

args = getRunArguments()

print(project.run_from_designspace(designspace_path=DS_PATH, **args))

# fontPath = 'otf/' + DS_PATH.replace('.designspace', '.otf')
# os.system('open %s' % fontPath)
예제 #39
0
def main():
    parser = ArgumentParser()
    parser.add_argument('-g', '--glyphs-path')
    parser.add_argument('-u', '--ufo-paths', nargs='+')
    parser.add_argument('-m', '--mm-designspace')
    parser.add_argument('-o',
                        '--output',
                        nargs='+',
                        default=('otf', 'ttf'),
                        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable'))
    parser.add_argument('-i',
                        '--interpolate',
                        action='store_true',
                        help='interpolate masters (for Glyphs or MutatorMath '
                        'sources only)')
    parser.add_argument('-mi',
                        '--masters-as-instances',
                        action='store_true',
                        help='treat masters as instances')
    parser.add_argument('-a',
                        '--autohint',
                        nargs='?',
                        help='can provide arguments to ttfautohint, quoted')
    parser.add_argument('--mti-source')
    parser.add_argument('--family-name',
                        help='Family name to use for masters,'
                        ' and to filter output instances by')
    parser.add_argument('--use-afdko', action='store_true')
    parser.add_argument('--keep-direction',
                        dest="reverse_direction",
                        action='store_false',
                        help='Do not reverse contour '
                        'direction when output is ttf or ttf-interpolatable')
    parser.add_argument('--keep-overlaps',
                        dest="remove_overlaps",
                        action='store_false',
                        help='Do not remove any overlap.')
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--production-names',
                       dest='use_production_names',
                       action='store_true',
                       help='Rename glyphs with '
                       'production names if available otherwise use uninames.')
    group.add_argument('--no-production-names',
                       dest='use_production_names',
                       action='store_false',
                       help='Do not rename glyphs with production names. '
                       'Keeps original glyph names')
    parser.set_defaults(use_production_names=None)
    parser.add_argument('--timing', action='store_true')
    args = vars(parser.parse_args())

    project = FontProject(timing=args.pop('timing'))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')
    if not sum(1
               for p in [glyphs_path, ufo_paths, designspace_path] if p) == 1:
        parser.error('Exactly one source type required (Glyphs, UFO, or '
                     'MutatorMath).')

    def exclude_args(parser, args, excluded_args):
        exclusive_msg = '"{}" argument only available for {} source'
        exclusive_src = {
            'interpolate': 'Glyphs or MutatorMath',
            'family_name': 'Glyphs'
        }
        for excluded in excluded_args:
            if args[excluded]:
                parser.error(
                    exclusive_msg.format(excluded, exclusive_src[excluded]))
            del args[excluded]

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)

    elif designspace_path:
        exclude_args(parser, args, ['family_name'])
        project.run_from_designspace(designspace_path, **args)

    else:
        exclude_args(parser, args, ['family_name', 'interpolate'])

    if ufo_paths:
        project.run_from_ufos(ufo_paths,
                              is_instance=args.pop('masters_as_instances'),
                              **args)
예제 #40
0
def main(args=None):
    parser = ArgumentParser()
    parser.add_argument('--version', action='version', version=__version__)
    inputGroup = parser.add_argument_group(
        title='Input arguments',
        description='The following arguments are mutually exclusive.')
    xInputGroup = inputGroup.add_mutually_exclusive_group(required=True)
    xInputGroup.add_argument(
        '-g', '--glyphs-path', metavar='GLYPHS',
        help='Path to .glyphs source file')
    xInputGroup.add_argument(
        '-u', '--ufo-paths', nargs='+', metavar='UFO',
        help='One or more paths to UFO files')
    xInputGroup.add_argument(
        '-m', '--mm-designspace', metavar='DESIGNSPACE',
        help='Path to .designspace file')

    outputGroup = parser.add_argument_group(title='Output arguments')
    outputGroup.add_argument(
        '-o', '--output', nargs='+', default=('otf', 'ttf'), metavar="FORMAT",
        help='Output font formats. Choose between: %(choices)s. '
             'Default: otf, ttf',
        choices=('ufo', 'otf', 'ttf', 'ttf-interpolatable', 'variable'))
    outputGroup.add_argument(
        '-i', '--interpolate', action='store_true',
        help='Interpolate masters (for Glyphs or MutatorMath sources only)')
    outputGroup.add_argument(
        '-M', '--masters-as-instances', action='store_true',
        help='Output masters as instances')
    outputGroup.add_argument(
        '--family-name',
        help='Family name to use for masters, and to filter output instances')

    contourGroup = parser.add_argument_group(title='Handling of contours')
    contourGroup.add_argument(
        '--keep-overlaps', dest='remove_overlaps', action='store_false',
        help='Do not remove any overlap.')
    contourGroup.add_argument(
        '--keep-direction', dest='reverse_direction', action='store_false',
        help='Do not reverse contour direction when output is ttf or '
             'ttf-interpolatable')
    contourGroup.add_argument(
        '-e', '--conversion-error', type=float, default=None, metavar='ERROR',
        help='Maximum approximation error for cubic to quadratic conversion '
             'measured in EM')
    contourGroup.add_argument(
        '-a', '--autohint', nargs='?', const='',
        help='Run ttfautohint. Can provide arguments, quoted')

    layoutGroup = parser.add_argument_group(title='Handling of OpenType Layout')
    layoutGroup.add_argument(
        '--interpolate-binary-layout', action='store_true',
        help='Interpolate layout tables from compiled master binaries. '
             'Requires Glyphs or MutatorMath source.')
    layoutGroup.add_argument(
        '--kern-writer-module', metavar="MODULE", dest='kern_writer_class',
        type=PyClassType('KernFeatureWriter'),
        help='Module containing a custom `KernFeatureWriter` class.')
    layoutGroup.add_argument(
        '--mark-writer-module', metavar="MODULE", dest='mark_writer_class',
        type=PyClassType('MarkFeatureWriter'),
        help='Module containing a custom `MarkFeatureWriter` class.')
    feaCompilerGroup = layoutGroup.add_mutually_exclusive_group(required=False)
    feaCompilerGroup.add_argument(
        '--use-afdko', action='store_true',
        help='Use makeOTF instead of feaLib to compile FEA.')
    feaCompilerGroup.add_argument(
        '--mti-source',
        help='Path to mtiLib .txt feature definitions (use instead of FEA)')

    glyphnamesGroup = parser.add_mutually_exclusive_group(required=False)
    glyphnamesGroup.add_argument(
        '--production-names', dest='use_production_names', action='store_true',
        help='Rename glyphs with production names if available otherwise use '
             'uninames.')
    glyphnamesGroup.add_argument(
        '--no-production-names', dest='use_production_names',
        action='store_false')

    subsetGroup = parser.add_mutually_exclusive_group(required=False)
    subsetGroup.add_argument(
        '--subset', dest='subset', action='store_true',
        help='Subset font using export flags set by glyphsLib')
    subsetGroup.add_argument(
        '--no-subset', dest='subset', action='store_false')

    subroutinizeGroup = parser.add_mutually_exclusive_group(required=False)
    subroutinizeGroup.add_argument(
        '-s', '--subroutinize', action='store_true',
        help='Optimize CFF table using compreffor (default)')
    subroutinizeGroup.add_argument(
        '-S', '--no-subroutinize', dest='subroutinize', action='store_false')

    parser.set_defaults(use_production_names=None, subset=None,
                        subroutinize=True)

    logGroup = parser.add_argument_group(title='Logging arguments')
    logGroup.add_argument(
        '--timing', action='store_true',
        help="Print the elapsed time for each steps")
    logGroup.add_argument(
        '--verbose', default='INFO', metavar='LEVEL',
        choices=('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'),
        help='Configure the logger verbosity level. Choose between: '
             '%(choices)s. Default: INFO')
    args = vars(parser.parse_args(args))

    glyphs_path = args.pop('glyphs_path')
    ufo_paths = args.pop('ufo_paths')
    designspace_path = args.pop('mm_designspace')

    if 'variable' in args['output']:
        if not (glyphs_path or designspace_path):
            parser.error(
                'Glyphs or designspace source required for variable font')
        for argname in ('interpolate', 'masters_as_instances',
                        'interpolate_binary_layout'):
            if args[argname]:
                parser.error('--%s option invalid for variable font'
                             % argname.replace("_", "-"))

    project = FontProject(timing=args.pop('timing'),
                          verbose=args.pop('verbose'))

    if glyphs_path:
        project.run_from_glyphs(glyphs_path, **args)
        return

    exclude_args(parser, args, ['family_name', 'mti_source'], 'Glyphs')
    if designspace_path:
        project.run_from_designspace(designspace_path, **args)
        return

    exclude_args(
        parser, args, ['interpolate', 'interpolate_binary_layout'],
        'Glyphs or MutatorMath')
    project.run_from_ufos(
        ufo_paths, is_instance=args.pop('masters_as_instances'), **args)
예제 #41
0
def _build_otf(ufo, output_dir):
    ufos = ufo if isinstance(ufo, list) else [ufo]
    FontProject().save_otfs(ufos, output_dir=output_dir, optimize_cff=2)