Ejemplo n.º 1
0
def buildGlyphOrderAndAlias(fontPath, root):
    """
    Using the font's glyphOrder and postscriptNames, generates a
    GlyphOrderAndAliasDB file.

    *fontPath* is a `string` path to a UFO
    *root* is the directory to save the GlyphOrderAndAliasDB to
    """

    font = Font(fontPath)
    order = font.glyphOrder
    mapping = font.lib["public.postscriptNames"]
    path = os.path.join(root, "GlyphOrderAndAliasDB")
    with open(path, "w") as f:
        for name in order:
            if name in font.keys():
                glyph = font[name]
                finalName = mapping[name]
                if len(glyph.unicodes) > 1:
                    unicodes = [f"uni{uni:04X}" for uni in glyph.unicodes]
                    out = f"{finalName}\t{name}\t{','.join(unicodes)}\n"
                else:
                    out = f"{finalName}\t{name}\n"
                f.write(out)
        f.write("\n")
Ejemplo n.º 2
0
        glyphs = []
        for name in alternates:
            if name in font.keys():
                glyphs.append(name)
        if len(glyphs) > 1:
            for count, _ in enumerate(glyphs):
                line = rotate(glyphs, count)
                sub = f"    sub {line[0]} from [{' '.join(line)}];"
                aalt.append(sub)

    aalt.append("} aalt;")

    with open(outPath, "w") as f:
        f.write("\n".join(aalt))


if __name__ == "__main__":
    import argparse
    description = "Make a aalt feature from a UFO"
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument("fontPath", help="The path to a UFO file")
    parser.add_argument("-o", "--out", help="Output path")
    args = parser.parse_args()
    font = Font(args.fontPath)
    outPath = args.out

    if not outPath:
        outPath = os.path.split(args.fontPath)[0] + "aalt.fea"

    build_aalt(font, outPath)
Ejemplo n.º 3
0
def prep(designspacePath, version):
    """
    Runs all of the checks and corrections and generates the report.

    Uses https://github.com/LettError/DesignspaceProblems to check and
    report on issues with the design space.

    *designspacePath* is a `string` of the path to the designspace file
    *version* is a `string` that is the version to set the font to
    """

    # Checking to see if there are any large issues with the designspace
    # file before doing anything
    dsc = DesignSpaceChecker(designspacePath)
    assert not dsc.hasStructuralProblems()

    ds = DesignSpaceDocument.fromfile(designspacePath)
    sources = [source.path for source in ds.sources]

    print("🏗  Opening sources")
    fonts = [Font(path) for path in sources]

    print("🏗  Checking family name")
    assert checkFamilyName(fonts)

    print("🏗  Removing non-exporting glyphs")
    decomposeNonExportingGlyphs(fonts)

    print("🏗  Clearing guides")
    for font in fonts:
        clearGuides(font)

    print("🏗  Removing glyphs that aren't in every font")
    makeSourceFontsGlyphCompatible(fonts)

    print("🏗  Removing non-compatible glyphs")
    makeCompatible(fonts)

    print("🏗  Making kerning compatible")
    kerningCompatibility(fonts)

    print("🏗  Sorting glyph order to be common")
    sortGlyphOrder(fonts)

    print("🏗  Setting production names")
    setProductionNames(fonts)

    print("🏗  Setting version")
    if version:
        setVersion(fonts, version)


    print("🏗  Closing and saving sources")
    for font in fonts:
        font.close(save=True)

    print("🏗  Checking full design space")
    dsc.checkEverything()
    report["Designspace check"] = dsc.problems

    print("🏗  Writing report")
    report_path = os.path.join(os.path.split(designspacePath)[0],
                               "varfontprep-report.txt")
    writeReport(report_path)

    print("✅ Done preparing sources")
Ejemplo n.º 4
0
    By default it makes a copy of the designspace and sources, so your
    working files are never overwritten. This may be overridden.
    """
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument("designspacePath",
                        help="The path to a designspace file")
    parser.add_argument("-o", "--overwrite", action="store_true",
                        help="Overwrite source files in place.")
    parser.add_argument("-v", "--version",
                        help="Version to set in files")
    args = parser.parse_args()
    designspacePath = args.designspacePath

    if not args.overwrite:
        print("🏗  Copying files")

        ds = DesignSpaceDocument.fromfile(designspacePath)
        font = Font(ds.sources[0].path)
        fn = font.info.familyName.replace(" ", "_").lower()
        font.close()

        now = datetime.datetime.now()
        fn += "-varfontprep-" + now.strftime("%Y_%m_%d-%H_%M_%S")

        directory, file = os.path.split(designspacePath)
        root = os.path.join(directory, fn)

        designspacePath = copyFiles(designspacePath, root)

    prep(designspacePath, args.version)
Ejemplo n.º 5
0
def buildInstances(designspacePath, root, name_map):
    """
    Generates and cleans up the instances for building the static fonts.

    This sets a variety of font info related values (blueScale, weight class,
    panose, and fixed pitch)

    It also cleans up the standard ps stems, sets the font features to be
    nothing, and removes overlap.

    For each instance it generates the fontinfo, kern.fea, and features files

    *designspace* is a designspace object
    *root* is the root directory where the file structure has been built
    *name_map* is the name mapping dictionary
    """

    overlapGlyphs = [
        "Aogonek", "Aring", "Aringacute", "Ccedilla", "Ccedillaacute",
        "Dcroat", "Ecedillabreve", "Eng", "Eogonek", "Eth", "Hbar", "Iogonek",
        "Lslash", "Lslash.sans", "Nhookleft", "Ohorn", "Ohornacute",
        "Ohorndot", "Ohorngrave", "Ohornhook", "Ohorntilde", "Oogonek",
        "Oslash", "Oslashacute", "Q", "Scedilla", "Tbar", "Tcedilla", "Uhorn",
        "Uhornacute", "Uhorndot", "Uhorngrave", "Uhornhook", "Uhorntilde",
        "Uogonek", "aogonek", "aogonek.italic", "aogonek.simple", "aringacute",
        "aringacute.italic", "aringacute.simple", "ccedilla",
        "ccedilla.italic", "ccedillaacute", "ccedillaacute.italic", "dcroat",
        "ecedillabreve", "ecedillabreve.italic", "eogonek", "equal_equal.code",
        "hbar", "iogonek", "iogonek.italic", "iogonek.mono", "iogonek.simple",
        "lslash", "lslash.italic", "lslash.mono", "lslash.sans",
        "lslash.simple", "nhookleft", "notequal", "notequal.case",
        "numbersign_numbersign.code", "numbersign_numbersign_numbersign.code",
        "numbersign_numbersign_numbersign_numbersign.code", "ohorn",
        "ohornacute", "ohorndot", "ohorngrave", "ohornhook", "ohorntilde",
        "oogonek", "oslash", "oslashacute", "ringacute", "ringacute.case",
        "scedilla", "scedilla.italic", "tbar", "tcedilla", "uhorn",
        "uhorn.italic", "uhornacute", "uhornacute.italic", "uhorndot",
        "uhorndot.italic", "uhorngrave", "uhorngrave.italic", "uhornhook",
        "uhornhook.italic", "uhorntilde", "uhorntilde.italic", "uogonek",
        "uogonek.italic"
    ]

    doc = DesignSpaceProcessor()
    doc.useVarlib = True
    doc.roundGeometry = True
    doc.read(designspacePath)
    for i in doc.instances:
        fn, sn, _, _, _ = name_map[(i.familyName, i.styleName)]
        path = os.path.join(
            root,
            fn.strip().replace(" ", ""),
            sn.strip().replace(" ", ""),
            os.path.split(i.filename)[1].strip().replace(" ", ""))
        i.path = path
    print("🏗  Generating instance UFOs")
    doc.generateUFO()

    ufos = getFiles(root, ".ufo")
    fonts = [Font(ufo) for ufo in ufos]

    print("🏗  Getting blueScale")
    blueScale = getBlueScale(fonts)

    print("🏗  Setting values, removing overlap, writing files")
    length = len(fonts)
    printProgressBar(0, length, prefix='  ', suffix='Complete', length=50)
    for i, font in enumerate(fonts):
        font_dir = os.path.split(font.path)[0]

        # Font info
        # Get and set PS Font Full Name and PS Font Name
        _, _, fullname, ps, _ = name_map[(font.info.familyName,
                                          font.info.styleName)]
        font.info.postscriptFontName = ps
        font.info.postscriptFullName = fullname

        # Get weight value based on fullname
        # 'Regular' is not part of the fullname so we do a try/except
        # that will throw an IndexError if the fullname is a Regular
        # style ("Recursive Mono Csl", "Recursive Mono Lnr",
        # "Recursive Sans Csl", or "Recursive Sans Lnr"). We know then
        # that the font weight value should be 400. Likewise, if the
        # fourth item in the name is "Italic", the weight should be
        # 400, so we catch that here too.
        try:
            weight = fullname.split()[4]
            if weight == "Italic":
                weight = "Regular"
        except IndexError:
            weight = "Regular"

        # Set weight class
        font.info.openTypeOS2WeightClass = weightMap[weight][0]

        splitFn = fullname.split()
        # Set the Italic angle
        if "Italic" in splitFn:
            font.info.italicAngle = -15

        # Set Panose
        fillInPanoseValues(font, weight)

        # Set fixed pitch if font is Mono
        if "Mono" in splitFn or "Mn" in splitFn:
            font.info.postscriptIsFixedPitch = True

        # Fix standard stems
        fixStandardStems(font)

        # Set blueScale
        font.info.postscriptBlueScale = blueScale

        # Remove the font features, as this is wholely external and
        # causes issues with making TTFs
        font.features.text = ""

        # Font cleanup
        # Remove overlap in the font
        for name in overlapGlyphs:
            font[name].decompose()
        for glyph in font:
            glyph.removeOverlap()
        font.save(font.path)

        # External files
        # Write out the `fontinfo` file
        buildFontInfo(font.info.styleName, font_dir)

        # Write out the kerning feature file
        path = os.path.join(font_dir, "kern.fea")
        writeKerning(font, path)

        # Write out the font feature file
        writeFeature(font)

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

    print("✅ Made UFO instances")
    batchCheckOutlines(root)