Exemple #1
0
 def autohint(self, folder, hintedFolder):
     print("START")
     for ft in os.listdir(folder):
         print(folder, ft)
         ftpath = os.path.join(folder, ft)
         hintedFontPath = os.path.join(hintedFolder, ft)
         if not os.path.exists(hintedFolder):
             os.makedirs(hintedFolder)
         try:
             ttfautohint.ttfautohint(in_file=ftpath, out_file=hintedFontPath)
         except:
             print("Not possible to autohint the fonts")
Exemple #2
0
    def _autohint(self, otf, fmt):
        logger.info(f"Autohinting {self.name}.{fmt.value}")
        if fmt == Format.TTF:
            from io import BytesIO

            from ttfautohint import ttfautohint

            buf = BytesIO()
            otf.save(buf)
            otf.close()
            data = ttfautohint(in_buffer=buf.getvalue(), no_info=True)
            otf = TTFont(BytesIO(data))
        elif fmt == Format.OTF:
            from tempfile import TemporaryDirectory

            from psautohint.__main__ import main as psautohint

            with TemporaryDirectory() as d:
                path = Path(d) / "tmp.otf"
                otf.save(path)
                with TemporaryLogLevel(logging.ERROR):
                    psautohint([str(path)])
                otf.close()
                otf = TTFont(path)
        return otf
Exemple #3
0
    def _autohint(self, otf, fmt):
        logger.info(f"Autohinting {self.name}.{fmt.value}")
        if fmt == Format.TTF:
            from io import BytesIO

            from ttfautohint import ttfautohint

            buf = BytesIO()
            otf.save(buf)
            otf.close()
            data = ttfautohint(in_buffer=buf.getvalue(), no_info=True)
            otf = TTFont(BytesIO(data))

            # Set bit 3 on head.flags
            # https://font-bakery.readthedocs.io/en/latest/fontbakery/profiles/googlefonts.html#com.google.fonts/check/integer_ppem_if_hinted
            head = otf["head"]
            head.flags |= 1 << 3
        elif fmt == Format.OTF:
            from tempfile import TemporaryDirectory

            from psautohint.__main__ import main as psautohint

            with TemporaryDirectory() as d:
                path = Path(d) / "tmp.otf"
                otf.save(path)
                with TemporaryLogLevel(logging.ERROR):
                    psautohint([str(path)])
                otf.close()
                otf = TTFont(path)
        return otf
Exemple #4
0
    def test_in_and_out_file_paths(self, tmpdir, unhinted):
        in_file = tmpdir / "unhinted.ttf"
        out_file = tmpdir / "hinted.ttf"

        with in_file.open("wb") as f:
            unhinted.save(f)

        n = ttfautohint(in_file=str(in_file), out_file=str(out_file))

        assert n > 0
Exemple #5
0
def main(args=None):
    options = ttfautohint.options.parse_args(args)

    # `parse_args` can return None instead of raising SystemExit on invalid
    # arguments, when `args` are passed. When it's called with args=None
    # (e.g. from a console script's `main()`), SystemExit is propagated.
    if options is None:
        return 2

    logging.basicConfig(
        level=("DEBUG" if options["debug"] else
               "INFO" if options["verbose"] else "WARNING"),
        format="%(name)s: %(levelname)s: %(message)s",
    )

    try:
        ttfautohint.ttfautohint(**options)
    except ttfautohint.TAError as e:
        log.error(e)
        return e.rv
Exemple #6
0
def hinting_stats(font):
    """
    Return file size differences for a hinted font compared to an dehinted version of same file
    """
    from ttfautohint import ttfautohint, libttfautohint
    from io import BytesIO
    from fontTools.ttLib import TTFont
    from fontTools.subset import main as pyftsubset
    from fontbakery.profiles.shared_conditions import (is_ttf,
                                                       is_cff,
                                                       is_cff2)

    if is_ttf(TTFont(font)):
        original_buffer = BytesIO()
        TTFont(font).save(original_buffer)
        dehinted_buffer = ttfautohint(in_buffer=original_buffer.getvalue(),
                                      dehint=True)
        dehinted_size = len(dehinted_buffer)
        version = libttfautohint.version_string

    elif is_cff(TTFont(font)) or is_cff2(TTFont(font)):
        ext = os.path.splitext(font)[1]
        tmp = font.replace(ext, "-tmp-dehinted%s" % ext)
        args = [font,
                "--no-hinting",
                "--glyphs=*",
                "--ignore-missing-glyphs",
                "--no-notdef-glyph",
                "--no-recommended-glyphs",
                "--no-layout-closure",
                "--layout-features=*",
                "--no-desubroutinize",
                "--name-languages=*",
                "--glyph-names",
                "--no-prune-unicode-ranges",
                "--output-file=%s" % tmp]
        pyftsubset(args)

        dehinted_size = os.stat(tmp).st_size
        version = "" # TODO If there is a way, extract the psautohint version used?
        os.remove(tmp)

    else:
        return None

    return {
        "dehinted_size": dehinted_size,
        "hinted_size": os.stat(font).st_size,
        "version": version
    }
def ttfautohint_stats(font):
  from ttfautohint import ttfautohint, libttfautohint
  from io import BytesIO
  from fontTools.ttLib import TTFont
  from fontbakery.profiles.shared_conditions import is_ttf

  if not is_ttf(TTFont(font)):
    return None

  original_buffer = BytesIO()
  TTFont(font).save(original_buffer)
  dehinted_buffer = ttfautohint(in_buffer=original_buffer.getvalue(),
                                dehint=True)
  return {
    "dehinted_size": len(dehinted_buffer),
    "hinted_size": os.stat(font).st_size,
    "version": libttfautohint.version_string
  }
def ttfautohint_stats(font):
    from ttfautohint import ttfautohint, libttfautohint
    from io import BytesIO
    from fontTools.ttLib import TTFont
    from fontbakery.profiles.shared_conditions import is_ttf

    if not is_ttf(TTFont(font)):
        return None

    original_buffer = BytesIO()
    TTFont(font).save(original_buffer)
    dehinted_buffer = ttfautohint(in_buffer=original_buffer.getvalue(),
                                  dehint=True)
    return {
        "dehinted_size": len(dehinted_buffer),
        "hinted_size": os.stat(font).st_size,
        "version": libttfautohint.version_string
    }
Exemple #9
0
    def autohint(self, filename):
        from ttfautohint.options import parse_args as ttfautohint_parse_args
        from ttfautohint import ttfautohint

        ttfautohint(**ttfautohint_parse_args([filename, filename]))
def splitFont(
    outputDirectory=f"RecMono{fontOptions['Family Name']}".replace(" ", ""),
    newName="Rec Mono",
):

    # access font as TTFont object
    varfont = ttLib.TTFont(fontPath)

    fontFileName = os.path.basename(fontPath)

    outputSubDir = f"fonts/{outputDirectory}"

    for instance in fontOptions["Fonts"]:

        print(
            "\n--------------------------------------------------------------------------------------\n"
            + instance)

        instanceFont = instancer.instantiateVariableFont(
            varfont,
            {
                "wght": fontOptions["Fonts"][instance]["wght"],
                "CASL": fontOptions["Fonts"][instance]["CASL"],
                "MONO": fontOptions["Fonts"][instance]["MONO"],
                "slnt": fontOptions["Fonts"][instance]["slnt"],
                "CRSV": fontOptions["Fonts"][instance]["CRSV"],
            },
        )

        # UPDATE NAME ID 6, postscript name
        currentPsName = getFontNameID(instanceFont, 6)
        newPsName = (currentPsName\
            .replace("Sans", "")\
            .replace(oldName,newName.replace(" ", "") + fontOptions['Family Name'].replace(" ",""))\
            .replace("LinearLight", instance.replace(" ", "")))
        setFontNameID(instanceFont, 6, newPsName)

        # UPDATE NAME ID 4, full font name
        currentFullName = getFontNameID(instanceFont, 4)
        newFullName = (currentFullName\
            .replace("Sans", "")\
            .replace(oldName, newName + " " + fontOptions['Family Name'])\
            .replace(" Linear Light", instance))\
            .replace(" Regular", "")
        setFontNameID(instanceFont, 4, newFullName)

        # UPDATE NAME ID 3, unique font ID
        currentUniqueName = getFontNameID(instanceFont, 3)
        newUniqueName = (currentUniqueName.replace(currentPsName, newPsName))
        setFontNameID(instanceFont, 3, newUniqueName)

        # ADD name 2, style linking name
        newStyleLinkingName = instance
        setFontNameID(instanceFont, 2, newStyleLinkingName)
        setFontNameID(instanceFont, 17, newStyleLinkingName)

        # UPDATE NAME ID 1, Font Family name
        currentFamName = getFontNameID(instanceFont, 1)
        newFamName = (newFullName.replace(f" {instance}", ""))
        setFontNameID(instanceFont, 1, newFamName)
        setFontNameID(instanceFont, 16, newFamName)

        newFileName = fontFileName\
            .replace(oldName, (newName + fontOptions['Family Name']).replace(" ", ""))\
            .replace("_VF_", "-" + instance.replace(" ", "") + "-")

        # make dir for new fonts
        pathlib.Path(outputSubDir).mkdir(parents=True, exist_ok=True)

        # -------------------------------------------------------
        # save instance font

        outputPath = f"{outputSubDir}/{newFileName}"

        # save font
        instanceFont.save(outputPath)

        # -------------------------------------------------------
        # Code font special stuff in post processing

        # freeze in rvrn & stylistic set features with pyftfeatfreeze
        pyftfeatfreeze.main([
            f"--features=rvrn,{','.join(fontOptions['Features'])}", outputPath,
            outputPath
        ])

        if fontOptions['Code Ligatures']:
            # swap dlig2calt to make code ligatures work in old code editor apps
            dlig2calt(outputPath, inplace=True)

        # if casual, merge with casual PL; if linear merge w/ Linear PL
        if fontOptions["Fonts"][instance]["CASL"] > 0.5:
            mergePowerlineFont(outputPath,
                               "./font-data/NerdfontsPL-Regular Casual.ttf")
        else:
            mergePowerlineFont(outputPath,
                               "./font-data/NerdfontsPL-Regular Linear.ttf")

        # TODO, maybe: make VF for powerline font, then instantiate specific CASL instance before merging

        # -------------------------------------------------------
        # OpenType Table fixes

        monoFont = ttLib.TTFont(outputPath)

        # drop STAT table to allow RIBBI style naming & linking on Windows
        try:
            del monoFont["STAT"]
        except KeyError:
            print("Font has no STAT table.")

        # In the post table, isFixedPitched flag must be set in the code fonts
        monoFont['post'].isFixedPitch = 1

        # In the OS/2 table Panose bProportion must be set to 9
        monoFont["OS/2"].panose.bProportion = 9

        # Also in the OS/2 table, xAvgCharWidth should be set to 600 rather than 612 (612 is an average of glyphs in the "Mono" files which include wide ligatures).
        monoFont["OS/2"].xAvgCharWidth = 600

        # Code to fix fsSelection adapted from:
        # https://github.com/googlefonts/gftools/blob/a0b516d71f9e7988dfa45af2d0822ec3b6972be4/Lib/gftools/fix.py#L764

        old_selection = fs_selection = monoFont["OS/2"].fsSelection

        # turn off all bits except for bit 7 (USE_TYPO_METRICS)
        fs_selection &= 1 << 7

        if instance == "Italic":

            monoFont["head"].macStyle = 0b10
            # In the OS/2 table Panose bProportion must be set to 11 for "oblique boxed" (this is partially a guess)
            monoFont["OS/2"].panose.bLetterForm = 11

            # set Italic bit
            fs_selection |= 1 << 0

        if instance == "Bold":
            monoFont['OS/2'].fsSelection = 0b100000
            monoFont["head"].macStyle = 0b1

            # set Bold bit
            fs_selection |= 1 << 5

        if instance == "Bold Italic":
            monoFont['OS/2'].fsSelection = 0b100001
            monoFont["head"].macStyle = 0b11

            # set Italic & Bold bits
            fs_selection |= 1 << 0
            fs_selection |= 1 << 5

        monoFont["OS/2"].fsSelection = fs_selection

        monoFont.save(outputPath)

        # TTF autohint

        ttfautohint_options.update(in_file=outputPath,
                                   out_file=outputPath,
                                   hint_composites=True)

        ttfautohint.ttfautohint()

        print(f"\n→ Font saved to '{outputPath}'\n")

        print('Features are ', fontOptions['Features'])
Exemple #11
0
def makeSFNT(root, outputPath, kind="otf"):
    """
    Generates otf or ttf fonts using the Adobe FDK.

    This also autohints the generated fonts either with psautohint (cff) or
    ttfautohint (ttf)

    *root* is the root to find the source files in
    *outputPath* is the path to save the generated fonts to
    *kind* is either 'otf' or 'ttf'.
    """

    if kind == "ttf":
        source = "ttf"
    else:
        source = "ufo"

    # make sure output dir contains no files
    files = getFiles(outputPath, kind)
    if len(files) != 0:
        for file in files:
            os.remove(file)

    print(f"🏗  Initial {kind.upper()} building")
    files = getFiles(root, source)
    outputFile = os.path.join(outputPath, "makeotf_output.txt")
    if os.path.exists(outputFile):
        os.remove(outputFile)

    printProgressBar(0, len(files), prefix='  ', suffix='Complete', length=50)
    for i, file in enumerate(files):

        # Set the makeotf parameters
        # -r is release mode
        # -nshw quiets the "glyph not hinted" warnings, as we
        #  have yet to run the autohinter (we do that after fonts)
        #  are built

        args = ["makeotf", "-f", file, "-o", outputPath, "-r", "-nshw"]
        run = subprocess.run(args,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT,
                             universal_newlines=True)
        with open(outputFile, "a") as f:
            f.write(run.stdout)

        printProgressBar(i + 1,
                         len(files),
                         prefix='  ',
                         suffix='Complete',
                         length=50)

    print(f"🏗  {kind.upper()} table fixing")
    files = getFiles(outputPath, kind)
    printProgressBar(0, len(files), prefix='  ', suffix='Complete', length=50)
    for i, file in enumerate(files):
        font = TTFont(file)
        nameTableTweak(font)
        makeDSIG(font)
        font.save(file)
        printProgressBar(i + 1,
                         len(files),
                         prefix='  ',
                         suffix='Complete',
                         length=50)

    print(f"🏗  {kind.upper()} autohinting")
    files = getFiles(outputPath, kind)

    outputFile = os.path.join(outputPath, "autohint_output.txt")
    if os.path.exists(outputFile):
        os.remove(outputFile)

    printProgressBar(0, len(files), prefix='  ', suffix='Complete', length=50)
    for i, file in enumerate(files):
        if kind is "otf":
            args = ["psautohint", file]
            run = subprocess.run(args,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT,
                                 universal_newlines=True)
            with open(outputFile, "a") as f:
                f.write(run.stdout)
        elif kind is "ttf":
            ttfautohint_options.update(in_file=file,
                                       out_file=file,
                                       hint_composites=True)
            with open(outputFile, "a") as f:
                with redirect_stdout(f), redirect_stderr(f):
                    ttfautohint.ttfautohint()

        printProgressBar(i + 1,
                         len(files),
                         prefix='  ',
                         suffix='Complete',
                         length=50)
Exemple #12
0
def autohint_font(ttfont, **options):
    buf = BytesIO()
    ttfont.save(buf)
    data = ttfautohint(in_buffer=buf.getvalue(), **options)
    return TTFont(BytesIO(data))