Exemple #1
0
def subsetFont(base64, subset):
    # tmp file names
    tmpInputFontName = tmpFileName(".ttf")
    tmpOutputFontName = tmpFileName(".woff")

    # remove data header from base64
    fontbase64 = base64.split(",")[1]

    with open(tmpInputFontName, "wb") as f:
        fontinput = f.write(fontbase64.decode('base64'))
        f.close()

    # open the font with fontTools
    font = TTFont(tmpInputFontName)

    options = Options()
    options.desubroutinize = True

    # export the font as woff for web use
    options.with_zopfli = True
    options.flavor = "woff"

    subsetter = Subsetter(options=options)
    subsetter.populate(text=subset)
    subsetter.subset(font)

    save_font(font, tmpOutputFontName, options)

    subsettedFont = open(tmpOutputFontName, "rb").read().encode("base64")

    os.unlink(tmpOutputFontName)
    os.unlink(tmpInputFontName)

    return {'subset': subsettedFont}
Exemple #2
0
    def __generateForWeight(self, weight: str, font: Font) -> None:
        package = self.__core.package
        base_dir = self.__core.directories.webfonts
        output_dir = base_dir.joinpath(f"./{package.version}/{weight}")
        font_path = self.__core.findFontfilePath(font)

        output_dir.mkdir(parents=True, exist_ok=True)
        metadata = self.__generateMetadata()

        fake = Faker()
        fake.seed(package.id)
        subset_fontname: str = fake.name()

        options = Options()
        options.font_number = font.number
        options.hinting = False
        options.desubroutinize = True
        options.drop_tables += [
            'FFTM', 'PfEd', 'TeX', 'BDF', 'cvt', 'fpgm', 'prep', 'gasp',
            'VORG', 'CBDT', 'CBLC', 'sbix'
        ]
        for ignored in ['rvrn', 'locl']:
            options.layout_features.remove(ignored)

        for unicodes_file in FILE_DIR.UNICODE_TEXT.glob('./**/*.txt'):
            idx = unicodes_file.stem
            unicodes: List[str] = []

            with open(unicodes_file, 'r') as unicode_read_io:
                for line in unicode_read_io.readlines():
                    unicodes.extend(parse_unicodes(line.split('#')[0]))

            with load_font(font_path, options) as ttfont:
                subsetter = Subsetter(options=options)
                subsetter.populate(unicodes=unicodes)
                subsetter.subset(ttfont)

                for record in ttfont['name'].names:
                    if record.nameID == NAME_ID.COPYRIGHT:
                        record.string = '\n'.join(package.copyrights)
                    elif record.nameID in FAMILY_RELATED_NAME_ID:
                        record.string = subset_fontname

                woff_file = output_dir.joinpath(f"{idx}.woff")
                with open(woff_file, 'wb') as woff_write_io:
                    options.flavor = 'woff'
                    ttfont.flavorData = WOFFFlavorData()
                    ttfont.flavorData.metaData = metadata
                    save_font(ttfont, woff_write_io, options)

                woff2_file = output_dir.joinpath(f"{idx}.woff2")
                with open(woff2_file, 'wb') as woff2_write_io:
                    options.flavor = 'woff2'
                    ttfont.flavorData = WOFF2FlavorData()
                    ttfont.flavorData.metaData = metadata
                    save_font(ttfont, woff2_write_io, options)
Exemple #3
0
def subset(fontfile, outfile_basename, glyphs):
    options = Options()

    # Fonttools has this "feature" that if you enable 'dlig', it will also give
    # you glyphs that you did not ask for, but if you do not enable 'dlig',
    # then discretionary ligatures do not render properly.
    # See https://github.com/behdad/fonttools/issues/43.
    # As a workaround, only enable 'dlig' if there are glyphs for discretionary
    # ligatures.
    dligs = set(glyphs).intersection([
        'c_b', 'c_h', 'c_k', 'c_p', 'ct', 'g_i', 'q_u', 's_b', 's_h', 's_k',
        's_p', 'st'
    ])
    if len(dligs) > 0:
        options.layout_features.append('dlig')
    else:
        # Due to a bug in Fonttools, options are actually global, so the
        # remnants of the previous instance are visible here.
        # See https://github.com/behdad/fonttools/issues/413.
        if 'dlig' in options.layout_features:
            options.layout_features.remove('dlig')

    # Same for small caps, it needs to be enabled explicitly. Luckily, only the
    # glyphs in the list get included, no extra ones.
    if any(g.endswith('.smcp') for g in glyphs):
        options.layout_features.append('smcp')
        options.layout_features.append('c2sc')
    else:
        if 'smcp' in options.layout_features:
            options.layout_features.remove('smcp')
        if 'c2sc' in options.layout_features:
            options.layout_features.remove('c2sc')

    # Fonts that went through the FontForge roundtrip will have subroutinized
    # programs in the CFF table. This presumably reduces file size for full
    # fonts, but on subsetted fonts it hurts file size and compressability, so
    # desubroutinize.
    options.desubroutinize = True

    font = load_font(fontfile, options)

    subsetter = Subsetter(options=options)
    subsetter.populate(glyphs=glyphs)
    subsetter.subset(font)

    prune_cmaps(font)

    options.flavor = "woff"
    save_font(font, outfile_basename + ".woff", options)

    options.flavor = "woff2"
    save_font(font, outfile_basename + ".woff2", options)

    font.close()
Exemple #4
0
def subset(fontfile, outfile_basename, glyphs):
    options = Options()

    # Fonttools has this feature that if you enable 'dlig', it will also give
    # you glyphs that you did not ask for, but if you do not enable 'dlig',
    # then discretionary ligatures do not render properly.
    # See https://github.com/behdad/fonttools/issues/43.
    # As a workaround, only enable 'dlig' if there are glyphs for discretionary
    # ligatures.
    # TODO: This should be fixed, consider upgrading.
    # https://github.com/fonttools/fonttools/commit/022536212be4cf022a2cb9a286fec8be1931d19b.
    dligs = set(glyphs).intersection(['c_b', 'c_h', 'c_k', 'c_p', 'ct', 'g_i',
                                      'q_u', 's_b', 's_h', 's_k', 's_p', 'st'])
    if len(dligs) > 0:
        options.layout_features.append('dlig')
    else:
        # Due to a bug in Fonttools, options are actually global, so the
        # remnants of the previous instance are visible here.
        # See https://github.com/behdad/fonttools/issues/413.
        if 'dlig' in options.layout_features:
            options.layout_features.remove('dlig')

    # Same for small caps, it needs to be enabled explicitly. Luckily, only the
    # glyphs in the list get included, no extra ones.
    if any(g.endswith('.smcp') for g in glyphs):
        options.layout_features.append('smcp')
        options.layout_features.append('c2sc')
    else:
        if 'smcp' in options.layout_features:
            options.layout_features.remove('smcp')
        if 'c2sc' in options.layout_features:
            options.layout_features.remove('c2sc')

    # Fonts that went through the FontForge roundtrip will have subroutinized
    # programs in the CFF table. This presumably reduces file size for full
    # fonts, but on subsetted fonts it hurts file size and compressability, so
    # desubroutinize.
    options.desubroutinize = True

    font = load_font(fontfile, options)

    subsetter = Subsetter(options = options)
    subsetter.populate(glyphs = glyphs)
    subsetter.subset(font)

    prune_cmaps(font)

    options.flavor = "woff"
    save_font(font, outfile_basename + ".woff", options)

    options.flavor = "woff2"
    save_font(font, outfile_basename + ".woff2", options)

    font.close()
Exemple #5
0
def subset(fontfile, outfile_basename, glyphs):
    options = Options()

    # Fonttools has this "feature" that if you enable 'dlig', it will also give
    # you glyphs that you did not ask for, but if you do not enable 'dlig',
    # then discretionary ligatures do not render properly.
    # See https://github.com/behdad/fonttools/issues/43.
    # As a workaround, only enable 'dlig' if there are glyphs for discretionary
    # ligatures.
    dligs = set(glyphs).intersection(["c_b", "c_h", "c_k", "c_p", "ct", "g_i", "q_u", "s_b", "s_h", "s_k", "s_p", "st"])
    if len(dligs) > 0:
        options.layout_features.append("dlig")
    else:
        # Due to a bug in Fonttools, options are actually global, so the
        # remnants of the previous instance are visible here.
        # See https://github.com/behdad/fonttools/issues/413.
        if "dlig" in options.layout_features:
            options.layout_features.remove("dlig")

    # Same for small caps, it needs to be enabled explicitly. Luckily, only the
    # glyphs in the list get included, no extra ones.
    if any(g.endswith(".smcp") for g in glyphs):
        options.layout_features.append("smcp")
        options.layout_features.append("c2sc")
    else:
        if "smcp" in options.layout_features:
            options.layout_features.remove("smcp")
        if "c2sc" in options.layout_features:
            options.layout_features.remove("c2sc")

    # Fonts that went through the FontForge roundtrip will have subroutinized
    # programs in the CFF table. This presumably reduces file size for full
    # fonts, but on subsetted fonts it hurts file size and compressability, so
    # desubroutinize.
    options.desubroutinize = True

    font = load_font(fontfile, options)

    subsetter = Subsetter(options=options)
    subsetter.populate(glyphs=glyphs)
    subsetter.subset(font)

    prune_cmaps(font)

    options.flavor = "woff"
    save_font(font, outfile_basename + ".woff", options)

    options.flavor = "woff2"
    save_font(font, outfile_basename + ".woff2", options)

    font.close()
Exemple #6
0
def subsetFont(fontPath, subset):
    tmpOutputFontName = os.path.dirname(
        os.path.abspath(__file__)) + "/tmp/" + str(uuid.uuid4()) + ".woff"

    font = TTFont(fontPath)

    options = Options()
    options.desubroutinize = True

    options.with_zopfli = True
    options.flavor = "woff"

    subsetter = Subsetter(options=options)
    subsetter.populate(text=subset)
    subsetter.subset(font)

    save_font(font, tmpOutputFontName, options)
    subsettedFont = 'data:;base64,' + open(tmpOutputFontName,
                                           "rb").read().encode("base64")

    cleanUp([tmpOutputFontName])

    print subsettedFont.replace('\n', '')