Пример #1
0
def main():
    parser = argparse.ArgumentParser(description='something something webfonts')
    parser.add_argument('files', metavar='FILE', nargs='*')
    args = parser.parse_args()
    for file in args.files:

        font = TTFont(file)



#for glyphName in font.getGlyphOrder():
#    glyphTable = font["glyf"]
#    glyph = glyphTable.glyphs.get(glyphName)
#    glyph.expand(glyphTable)
 
        glyphs = font.getGlyphSet()
        for key in glyphs.keys():
            value = glyphs[key]
            print("glyp width: " + key + ", " + str(value.width))
            # glyph.recalcBounds(glyphTable)

        hmtxTable = font['hmtx']
        correct_advance = (hmtxTable.metrics['A'][0], 0)
        for key, value in hmtxTable.metrics.items():
            print("advance: " + key + ", " + str(value))
            hmtxTable.metrics[key] = correct_advance

        name = os.path.splitext(file)[0]
        font.flavor = "woff"
        font.save(name + ".woff")

        font.flavor = "woff2"
        font.save(name + ".woff2")
Пример #2
0
def upload_to_ia(force=set()):
    s = get_session()
    item = s.get_item("NotoFonts")
    hashdict = {f["name"]: f["md5"] for f in item.files}

    fonts_modified = False
    for path in tqdm(sorted(pathset)):
        filename = path.name
        file = open(path, "rb").read()
        hash = md5(file).hexdigest()
        if "fonts" not in force:
            try:
                if hashdict[filename] == hash:
                    print("SKIPPING: " + filename)
                    continue
            except KeyError:
                pass
        fonts_modified = True
        print("WORKING: " + filename)
        upload_paths = []
        ttf = TTFont(path)
        print("  CONVERTING TO woff2...")
        ttf.flavor = "woff2"
        woff2_path = "upload/" + path.with_suffix(".woff2").name
        try:
            ttf.save(open(woff2_path, "wb"))
            upload_paths.append(woff2_path)
        except TTLibError:
            print("could not convert to woff2")
        print("  CONVERTING TO woff...")
        ttf.flavor = "woff"
        woff_path = "upload/" + path.with_suffix(".woff").name
        ttf.save(open(woff_path, "wb"))
        upload_paths.append(woff_path)
        print("  UPLOADING...")
        r = item.upload(files=[*upload_paths, str(path)], retries=100)
        for upath in [woff2_path, woff_path]:
            remove(upath)
    if "css" in force or fonts_modified:
        from generate_css import build_all_css

        print("  GENERATING CSS...")
        build_all_css()
        css_files = glob("*.css")
        for path in [Path(p) for p in sorted(css_files)]:
            filename = path.name
            file = open(path, "rb").read()
            hash = md5(file).hexdigest()
            # if "css" not in force:
            try:
                if hashdict[filename] == hash:
                    print("SKIPPING: " + filename)
                    continue
            except KeyError:
                pass
            print("  UPLOADING " + filename)
            r = item.upload(files=css_files, retries=100)
Пример #3
0
    def generateWoff2(self, verbosity=0):
        woff2_list = []
        os.makedirs(self.assetdir, exist_ok=True)
        for subname, (subrange, unicodes) in self.urdict.items():
            if verbosity == 2: print("Processing", subname)
            subs = Subsetter()
            font = TTFont(self.fontfile)
            subs.populate(unicodes=unicodes)
            subs.subset(font)
            cmap = font.getBestCmap()
            glyphcount = len(font.getGlyphOrder()) - 1
            if cmap:

                basefile = self.basename + "." + subname
                outfile = os.path.join(self.assetdir, basefile + ".woff2")
                font.flavor = 'woff2'
                font.save(outfile)
                if verbosity == 1:
                    print("Generated", outfile)
                elif verbosity == 2:
                    print("  Generated", outfile)
                    print("  Found", glyphcount, "glyphs for", len(cmap),
                          "out of", len(unicodes), "unicodes")

                outfile = os.path.join(self.assetdir, basefile + ".woff")
                font.flavor = 'woff'
                font.save(outfile)

                if verbosity == 1:
                    print("Generated", outfile)
                elif verbosity == 2:
                    print("  Generated", outfile)
                    print("  Found", glyphcount, "glyphs for", len(cmap),
                          "out of", len(unicodes), "unicodes")

                outfile = os.path.join(self.assetdir, basefile + ".ttf")
                font.flavor = ''
                font.save(outfile)

                woff2_list.append((os.path.join(self.assetdir,
                                                basefile), subrange))

                if verbosity == 1:
                    print("Generated", outfile)
                elif verbosity == 2:
                    print("  Generated", outfile)
                    print("  Found", glyphcount, "glyphs for", len(cmap),
                          "out of", len(unicodes), "unicodes")
            else:
                if verbosity == 2:
                    print("  Found no glyphs for any of", len(unicodes),
                          "unicodes")
            font.close()
        return woff2_list
Пример #4
0
def main():
    parser = argparse.ArgumentParser(description='convert TTFs to webfonts')
    parser.add_argument('files', metavar='FILE', nargs='*')
    args = parser.parse_args()
    for file in args.files:
        font = TTFont(file)

        name = os.path.splitext(file)[0]
        font.flavor = "woff"
        font.save(name + ".woff")

        font.flavor = "woff2"
        font.save(name + ".woff2")
Пример #5
0
def convert_font(input_path, output_path, flavor):
    '''
    フォントの形式を選択して出力する。
    '''
    font = TTFont(input_path)
    font.flavor = flavor
    font.save(output_path)
Пример #6
0
def makeWeb(args):
    font = TTFont(args.file)

    base, ext = os.path.splitext(args.file)
    font.flavor = "woff"
    font.save(os.path.join(args.dir, base + ".woff"))
    font.close()
Пример #7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("fonts",
                        nargs="+",
                        help="One or more TTF or OTF fonts")
    parser.add_argument("--output-dir",
                        help="The output dir for the compressed fonts")

    args = parser.parse_args()

    if args.output_dir:
        outputDir = pathlib.Path(args.output_dir).resolve()
        outputDir.mkdir(parents=True, exist_ok=True)
    else:
        outputDir = None

    for p in args.fonts:
        p = pathlib.Path(p).resolve()
        parentFolder = outputDir if outputDir is not None else p.parent
        fileName = p.stem + ".woff2"
        outputPath = parentFolder / fileName
        print("source:", p)
        print("destination:", outputPath)
        f = TTFont(p)
        f.flavor = "woff2"
        f.save(outputPath)
Пример #8
0
def webfonts(infont, type):
    font = TTFont(infont, recalcBBoxes=0)
    woffFileName = makeOutputFileName(
        infont, outputDir=None, extension='.' + type)
    font.flavor = type
    font.save(woffFileName, reorderTables=False)
    font.close()
Пример #9
0
    def post(self):
        fontdata = self.request.POST.get('font', None)

        # Need to use isinstance as cgi.FieldStorage always evaluates to False.
        # See http://bugs.python.org/issue19097
        if not isinstance(fontdata, cgi.FieldStorage):
            self.redirect('/font_conversion.html?' +  urllib.urlencode(
                {'err_msg': 'Please select a font'}))
            return

        #TODO(bstell) make this work correctly.
        font_type = 'woff'
        name = os.path.splitext(os.path.basename(fontdata.filename))[0]

        try:
            font = TTFont(fontdata.file)
        except:
            self.redirect('/font_conversion.html?' +  urllib.urlencode(
                {'err_msg': 'failed to parse font'}))
            return

        self.response.headers['Content-Type'] = 'application/font-woff'
        self.response.headers['Content-Disposition'] = \
            'attachment; filename={0}.{1}'.format(name, font_type)
        font.flavor = font_type
        output = StringIO.StringIO()
        font.save(output)
        self.response.out.write(output.getvalue())
Пример #10
0
def makeWeb(args):
    """If we are building a web version then try to minimise file size"""

    font = TTFont(args.file)

    # removed compatibility glyphs that of little use on the web
    ranges = (
            (0xfb50, 0xfbb1),
            (0xfbd3, 0xfd3d),
            (0xfd50, 0xfdf9),
            (0xfdfc, 0xfdfc),
            (0xfe70, 0xfefc),
            )

    cmap = font['cmap'].buildReversed()
    unicodes = set([min(cmap[c]) for c in cmap])
    for r in ranges:
        unicodes -= set(range(r[0], r[1] + 1))

    options = subset.Options()
    options.set(layout_features='*', name_IDs='*', drop_tables=['DSIG'])
    subsetter = subset.Subsetter(options=options)
    subsetter.populate(unicodes=unicodes)
    subsetter.subset(font)

    base, ext = os.path.splitext(args.file)
    for flavor in ("ttf", "woff", "woff2"):
        if flavor is not "ttf":
            font.flavor = flavor
        font.save(args.dir + "/" + base + "." + flavor)
    font.close()
Пример #11
0
def makeWeb(args):
    """If we are building a web version then try to minimise file size"""

    font = TTFont(args.file, recalcTimestamp=False)

    # removed compatibility glyphs that of little use on the web
    ranges = (
        (0xfb50, 0xfbb1),
        (0xfbd3, 0xfd3d),
        (0xfd50, 0xfdf9),
        (0xfdfc, 0xfdfc),
        (0xfe70, 0xfefc),
    )

    cmap = font['cmap'].buildReversed()
    unicodes = set([min(cmap[c]) for c in cmap])
    for r in ranges:
        unicodes -= set(range(r[0], r[1] + 1))

    options = subset.Options()
    options.set(layout_features='*', name_IDs='*', drop_tables=['DSIG'])
    subsetter = subset.Subsetter(options=options)
    subsetter.populate(unicodes=unicodes)
    subsetter.subset(font)

    base, ext = os.path.splitext(args.file)
    for flavor in ("woff", "woff2"):
        font.flavor = flavor
        font.save(args.dir + "/" + base + "." + flavor)
    font.close()
Пример #12
0
def webfonts(infont, type):
    font = TTFont(infont, recalcBBoxes=0)
    # Generate WOFF2
    woffFileName = makeOutputFileName(infont, outputDir=None, extension='.' + type)
    print("Processing %s => %s" % (infont, woffFileName))
    font.flavor = type
    font.save(woffFileName, reorderTables=False)
    font.close()
Пример #13
0
def makeWeb(args):
    """If we are building a web version then try to minimise file size"""

    font = TTFont(args.file)

    base, ext = os.path.splitext(args.file)
    for flavor in ("woff", "woff2"):
        font.flavor = flavor
        font.save(args.dir + "/" + base + "." + flavor)
    font.close()
Пример #14
0
def main(args=None):
    parser = ArgumentParser(description="Pre-process UFO files")
    parser.add_argument("input")
    parser.add_argument("flavor")
    parser.add_argument("output")

    options = parser.parse_args(args)

    font = TTFont(options.input)
    font.flavor = options.flavor
    font.save(options.output)
Пример #15
0
def generateInstances(config, args):

    # Create the output path if it doesn't exist.
    if not os.path.exists(args.outputPath):
        os.makedirs(args.outputPath)

    for style in tqdm(config, ascii=True, leave=False):
        font = TTFont(args.source)

        # Instantiate the font and update the name table.
        instantiateFont(font, style["axes"], inplace=True, overlap=True)
        updateNames(font, style)

        family = style.get("prefFamily")
        if family == None:
            family = style.get("family")

        subfamily = style.get("subfamily")
        prefSubfamily = style.get("prefSubfamily")
        if prefSubfamily == None:
            prefSubfamily = subfamily

        prefSubfamily = prefSubfamily.replace(" ", "")

        # Perform additional table fixups.
        font["head"].macStyle = getMacStyle(subfamily)
        font["OS/2"].fsSelection = makeSelection(font["OS/2"].fsSelection,
                                                 subfamily)

        # Override weight if requested.
        weightOverride = style.get("weightOverride")
        if weightOverride != None:
            font["OS/2"].usWeightClass = weightOverride

        # Override width if requested.
        widthOverride = style.get("widthOverride")
        if widthOverride != None:
            font["OS/2"].usWidthClass = widthOverride

        dropVariationTables(font)

        # Fix contour overlap issues on macOS.
        if args.fixContour == True:
            setOverlapFlags(font)

        ext = args.format if args.format is not None else "ttf"
        filename = getPostscriptName(style) + f".{ext}"
        outputPath = os.path.join(args.outputPath, filename)

        font.flavor = args.format
        font.save(outputPath)
Пример #16
0
def decompress(input_file, output_file):
	"""Decompress WOFF2 font to OpenType font.

	Args:
		input_file: a file path, file or file-like object (open in binary mode)
			containing a compressed WOFF2 font.
		output_file: a file path, file or file-like object where to save the
			decompressed OpenType font.
	"""
	log.info("Processing %s => %s" % (input_file, output_file))

	font = TTFont(input_file, recalcBBoxes=False, recalcTimestamp=False)
	font.flavor = None
	font.flavorData = None
	font.save(output_file, reorderTables=True)
Пример #17
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    if len(args) < 1:
        print("One argument, the input filename, must be provided.", file=sys.stderr)
        sys.exit(1)

    filename = args[0]
    outfilename = make_output_name(filename)

    print("Processing %s => %s" % (filename, outfilename))

    font = TTFont(filename, recalcBBoxes=False, recalcTimestamp=False)
    font.flavor = None
    font.save(outfilename, reorderTables=True)
Пример #18
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]
    if len(args) < 1:
        print("One argument, the input filename, must be provided.", file=sys.stderr)
        return 1

    filename = args[0]
    outfilename = makeOutputFileName(filename, outputDir=None, extension='.woff2')

    print("Processing %s => %s" % (filename, outfilename))

    font = TTFont(filename, recalcBBoxes=False, recalcTimestamp=False)
    font.flavor = "woff2"
    font.save(outfilename, reorderTables=False)
Пример #19
0
def buildCOLRv1(designspacePath,
                ttfPath,
                outTTFPath,
                saveWoff2,
                neutralOnly=False):
    import pathlib

    ttfPath = pathlib.Path(ttfPath)
    if outTTFPath is None:
        outTTFPath = ttfPath.parent / (ttfPath.stem + "-colrv1" +
                                       ttfPath.suffix)
    else:
        outTTFPath = pathlib.Path(outTTFPath)
    ttf = TTFont(ttfPath)

    axisTags = [axis.axisTag for axis in ttf["fvar"].axes]
    axisTagToIndex = {tag: index for index, tag in enumerate(axisTags)}
    globalAxisNames = {
        axis.axisTag
        for axis in ttf["fvar"].axes if not axis.flags & 0x0001
    }
    assert globalAxisNames == {
        axisTag
        for axisTag in axisTags if axisTag[0] != "V"
    }

    vcFont = VarCoFont(designspacePath)

    # Update the glyf table to contain bounding boxes for color glyphs
    estimateCOLRv1BoundingBoxes(vcFont, ttf, neutralOnly)

    vcData, varStore = prepareVariableComponentData(vcFont, axisTags,
                                                    globalAxisNames,
                                                    neutralOnly)
    colrGlyphs = buildCOLRGlyphs(vcData, axisTagToIndex)
    ttf["COLR"] = buildCOLR(colrGlyphs, varStore=varStore)

    ttf.save(outTTFPath)

    ttf = TTFont(outTTFPath, lazy=True)  # Load from scratch

    if saveWoff2:
        outWoff2Path = outTTFPath.parent / (outTTFPath.stem + ".woff2")
        ttf.flavor = "woff2"
        ttf.save(outWoff2Path)
Пример #20
0
def buildVarC(
    designspacePath, ttfPath, outTTFPath, doTTX, saveWoff2, neutralOnly=False
):
    import pathlib

    registerCustomTableClass("VarC", "rcjktools.table_VarC", "table_VarC")
    ttfPath = pathlib.Path(ttfPath)
    if outTTFPath is None:
        outTTFPath = ttfPath.parent / (ttfPath.stem + "-varc" + ttfPath.suffix)
    else:
        outTTFPath = pathlib.Path(outTTFPath)
    ttf = TTFont(ttfPath)

    axisTags = [axis.axisTag for axis in ttf["fvar"].axes]
    globalAxisNames = {axisTag for axisTag in axisTags if axisTag[0] != "V"}
    vcFont = VarCoFont(designspacePath)
    vcData, allLocations, neutralGlyphNames = vcFont.extractVarCoData(
        globalAxisNames, neutralOnly
    )
    if neutralGlyphNames:
        gvarTable = ttf["gvar"]
        for glyphName in neutralGlyphNames:
            del gvarTable.variations[glyphName]

    buildVarCTable(ttf, vcData, allLocations)

    if doTTX:
        outTTXPath = outTTFPath.parent / (outTTFPath.stem + "-before.ttx")
        ttf.saveXML(outTTXPath, tables=["VarC"])

    ttf.save(outTTFPath)

    ttf = TTFont(outTTFPath, lazy=True)  # Load from scratch

    if doTTX:
        outTTXPath = outTTFPath.parent / (outTTFPath.stem + "-after.ttx")
        ttf.saveXML(outTTXPath, tables=["VarC"])

    if saveWoff2:
        outWoff2Path = outTTFPath.parent / (outTTFPath.stem + ".woff2")
        ttf.flavor = "woff2"
        ttf.save(outWoff2Path)
Пример #21
0
def compress(input_file, output_file, transform_tables=None):
	"""Compress OpenType font to WOFF2.

	Args:
		input_file: a file path, file or file-like object (open in binary mode)
			containing an OpenType font (either CFF- or TrueType-flavored).
		output_file: a file path, file or file-like object where to save the
			compressed WOFF2 font.
		transform_tables: Optional[Iterable[str]]: a set of table tags for which
			to enable preprocessing transformations. By default, only 'glyf'
			and 'loca' tables are transformed. An empty set means disable all
			transformations.
	"""
	log.info("Processing %s => %s" % (input_file, output_file))

	font = TTFont(input_file, recalcBBoxes=False, recalcTimestamp=False)
	font.flavor = "woff2"

	if transform_tables is not None:
		font.flavorData = WOFF2FlavorData(
			data=font.flavorData, transformedTables=transform_tables
		)

	font.save(output_file, reorderTables=False)
Пример #22
0
                text = 'OFL v1.1'
            record.string = text
            names.append(record)
        # keep every thing else except Descriptor, Sample Text
        elif nameID not in (10, 19):
            names.append(record)

name.names = names

# FFTM is FontForge specific, remove it
del(font['FFTM'])
# force compiling GPOS/GSUB tables by fontTools, saves few tens of KBs
for tag in ('GPOS', 'GSUB'):
    font[tag].compile(font)

font.save(outfont)
# Generate WOFF
woffFileName = makeOutputFileName(infont, outputDir=None, extension='.woff')
print("Processing %s => %s" % (infont, woffFileName))
font.flavor = "woff"
font.save(woffFileName, reorderTables=False)
# Generate WOFF2
woff2FileName = makeOutputFileName(infont, outputDir=None, extension='.woff2')
print("Processing %s => %s" % (infont, woff2FileName))
font.flavor = "woff2"
font.save(woff2FileName, reorderTables=False)

font.close()

os.remove(tmpfont)
Пример #23
0
    return [n for n in ttf['name'].names if n.nameID == nameID][0].toUnicode()


os.chdir(fontsdir)
for infont in os.listdir(os.getcwd()):
    if not fontExtension.search(infont):
        continue
    print(infont)
    outwoff = fontExtension.sub('.woff', infont)
    outwoff2 = fontExtension.sub('.woff2', infont)
    try:
        ttf = TTFont(infont)
    except:
        print("Error opening {}".format(infont))
        continue
    ttf.flavor = 'woff'
    ttf.save(outwoff)
    ttf.flavor = 'woff2'
    ttf.save(outwoff2)

    axes = OrderedDict()
    if 'STAT' in ttf and hasattr(ttf['STAT'], 'table'):
        axes['order'] = [
            a.AxisTag for a in sorted(ttf['STAT'].table.DesignAxisRecord.Axis,
                                      key=lambda a: a.AxisOrdering)
        ]

    if 'fvar' in ttf:
        for axis in ttf['fvar'].axes:
            axes[axis.axisTag] = {
                'name':
Пример #24
0
                        ttf, instance.nameID if hasattr(instance, 'nameID')
                        else instance.subfamilyNameID),
                })
    return axes


for fontfile in glob.glob(infiles):
    fontfilebase = os.path.basename(fontfile)[:-4]
    outbase = os.path.join(outdir, fontfilebase)

    ttf = TTFont(fontfile, recalcBBoxes=False)

    #list axes
    fileAxes[fontfilebase] = getVarAxes(ttf)

    if 'DSIG' in ttf:
        del (ttf['DSIG'])

    wofffile = outbase + ".woff"
    ttf.flavor = 'woff'
    ttf.save(wofffile)

#using binary here because json.dumps returns raw bytes
with io.open(os.path.join(outdir, 'axes.json'), 'wb') as axesfile:
    jsonbytes = json.dumps(fileAxes, indent=2, ensure_ascii=False)
    if not isinstance(jsonbytes, bytes):
        jsonbytes = jsonbytes.encode('utf-8')
    axesfile.write(jsonbytes)

sys.exit(0)
Пример #25
0
 def convert(self, source_path: Path, target_path: Path) -> None:
     f = TTFont(source_path)
     f.flavor = "woff2"
     f.save(target_path)
Пример #26
0
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import print_function
from fontTools.ttLib import TTFont, sfnt
from os.path import splitext
import sys

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("usage: python %s filename" % sys.argv[0], file=sys.stderr)
        sys.exit(1)
    filename = sys.argv[1]
    basename = splitext(filename)[0]

    sfnt.USE_ZOPFLI = True
    for flavor in ["woff", "woff2"]:
        outfilename = "%s.%s" % (basename, flavor)
        print("Processing %s => %s" % (filename, outfilename))
        font = TTFont(filename, recalcBBoxes=False, recalcTimestamp=False)
        for t in font.keys():
            if hasattr(font[t], "compile"):
                font[t].compile(font)
        font.flavor = flavor
        font.save(outfilename, reorderTables=False)
Пример #27
0
def compile_fonts(flavors=['woff', 'woff2']):
    import json
    import hashlib
    from fontTools.ttLib import TTFont
    import fontTools.subset
    
    tim = sc.textdata.tim()
    
    font_face_decls = []
    
    if not fonts_output_dir.exists():
        fonts_output_dir.mkdir()
    
    font_data = get_fonts_data()
    fonts_seen = set()
    font_keys = set()
    
    def get_font_details(font_name):
        font_name = font_name.lower()
        result = {}
        result.update(font_data['defaults'])
        for key, value in sorted(font_data["families"].items(), key=lambda t: len(t[0]), reverse=True):
            if font_name.startswith(key.lower()):
                fonts_seen.add(key)
                result["key"] = key
                leftovers = font_name[len(key): ]
                
                if not value:
                    return None
                if isinstance(value, str):
                    result["family"] = value
                    font_keys.add((key, value))
                elif isinstance(value, list):
                    result["subset"] = value
                elif isinstance(value, dict):
                    result["subset"] = [value]
                elif not value:
                    pass
                break
        else:
            logger.error('Font file %s does not have a matching entry in fonts.json', font_name)
            return None
        
        for key, weight in sorted(font_data["weights"].items(), key=lambda t: len(t[0]), reverse=True):
            if key in leftovers:
                result["weight"] = weight
                break
        else:
            result["weight"] = "normal"
        
        for key, style in sorted(font_data["styles"].items(), key=lambda t: len(t[0]), reverse=True):
            if key in leftovers:
                result["style"] = style
                break
        else:
            result["style"] = "normal"
        return result
    
    seen = {}
    
    compiled_fonts = set(fonts_output_dir.glob('**/*'))
    valid_compiled_fonts = set()
    
    
    extra_global_subset_glyphs = ''.join(sorted(set(get_glyphs_from_table_data() + get_glyphs_from_template_data())))
    
    for file in sorted(fonts_dir.glob('**/*')):
        changed = False
        nonfree = "nonfree" in file.parts
        if file in compiled_fonts:
            continue
        if file.suffix not in {'.ttf', '.otf', '.woff', '.woff2'}:
            continue
        
        base_name = sanitize_font_name(file.stem)
        if base_name in seen:
            logger.error('Font file %s is too similiar to other file %s, skipping', file, seen[base_name])
        seen[base_name] = file
        
        with file.open('rb') as f:
            font_binary_data = f.read()
        md5 = hashlib.md5(font_binary_data)
        
        font_details = get_font_details(file.stem)
        
        if not font_details:
            continue
        
        if font_details['subset']:
            extra_subset_commands = ['--layout-features+=liga,dlig,smcp,c2sc,onum',
                                     '--desubroutinize']
            if font_details['weight'] in {'bold', 'semibold'}:
                weight = 'bold'
            elif font_details['style'] in {'italic'}:
                weight = 'italic'
            else:
                weight = 'normal'
            for subset_details in font_details['subset']:
                subset_languages = subset_details['subset_languages']
                subset_unicodes = set()
                
                if subset_languages == '*': # global subset
                    subset_unicodes.update(extra_global_subset_glyphs)
                    subset_unicodes.update(tim.get_codepoints_used(lang_uid=None, weight_or_style=weight))
                
                else:
                    if isinstance(subset_languages, str):
                        subset_languages = [subset_languages]
                    
                    for language in subset_languages:
                        codepoints = tim.get_codepoints_used(lang_uid=language, weight_or_style=weight)
                        if codepoints is None:
                            logger.error('Error in fonts.json, language uid "{}" not found in TIM'.format(language))
                        else:
                            subset_unicodes.update(codepoints)
                subset_text = ''.join(subset_unicodes)
                subset_text = ''.join(sorted(subset_text.lower() + subset_text.upper()))
                subset_md5 = md5.copy()
                subset_md5.update(subset_text.encode(encoding='utf8'))
                subset_md5.update(''.join(extra_subset_commands).encode(encoding='utf8'))
                
                if False: #nonfree and not sc.config.app['debug']:
                    outname = ''
                else:
                    outname = name_to_var(subset_details['name']) + '_'
                
                
                outname += weight.replace('normal', 'regular')
                if subset_languages != '*':
                    outname += '_' + '_'.join(subset_languages)
                outname += '_' + subset_md5.hexdigest()[:12]
                base_outfile = fonts_output_dir / outname
                
                suffix = font_details['save_as'][0]
                
                primary_out_file = base_outfile.with_suffix('.' + suffix)
                valid_compiled_fonts.add(primary_out_file)
                if not primary_out_file.exists():
                    changed = True
                    with NamedTemporaryFile('w+t') as subset_text_file:
                        subset_text_file.write(subset_text)
                        subset_text_file.flush()
                        fontTools.subset.main(args=[str(file), 
                                        #'--layout-features=*',
                                        #'--glyph-names',
                                        #'--symbol-cmap',
                                        #'--legacy-cmap',
                                        #'--notdef-glyph',
                                        #'--notdef-outline',
                                        #'--recommended-glyphs',
                                        #'--name-IDs=*',
                                        #'--name-legacy',
                                        #'--name-languages=*',
                                        '--output-file={}'.format(str(primary_out_file)),
                                        '--text-file={}'.format(subset_text_file.name), 
                                        '--flavor={}'.format(suffix)] + extra_subset_commands)
                font = None
                size = {}
                for flavor in font_details['save_as'][1:]:
                    suffix = '.{}'.format(flavor)
                    outfile = base_outfile.with_suffix(suffix)
                    valid_compiled_fonts.add(outfile)
                    if not outfile.exists():
                        changed = True
                        if font is None:
                            font = TTFont(str(primary_out_file))
                        font.flavor = flavor
                        font.save(file=str(outfile))
                    size[flavor] = sizeof_fmt(outfile.stat().st_size)

                font_face_decls.append(font_face_template.format(url='/fonts/compiled/{}'.format(outname), 
                                                                 family=subset_details['name'], 
                                                                 weight=font_details['weight'], 
                                                                 style=font_details['style'],
                                                                 size=size,
                                                                 ))
        else:
            size = {}
            md5sum = md5.hexdigest()[:12]
            outname = md5sum if (nonfree and not sc.config.app['debug']) else "{}_{}".format(base_name, md5sum)
            base_outfile = fonts_output_dir / outname
            
            font = None
            for flavor in flavors:
                suffix = '.{}'.format(flavor)
                outfile = base_outfile.with_suffix(suffix)
                valid_compiled_fonts.add(outfile)
                if not outfile.exists():
                    changed = True
                    if outfile.suffix == file.suffix:
                        with outfile.open('wb') as f:
                            f.write(font_binary_data)
                    else:
                        if font is None:
                            font = TTFont(str(file))
                        font.flavor = flavor
                        font.save(file=str(outfile))
                size[flavor] = sizeof_fmt(outfile.stat().st_size)
        
            if font_details:
                font_face_decls.append(font_face_template.format(url='/fonts/compiled/{}'.format(outname), size=size, **font_details))
        if changed:
            print('Processed {!s}'.format(file.name))
    unneeded_fonts = compiled_fonts - valid_compiled_fonts
    if unneeded_fonts:
        print('Removing {} unused compiled fonts'.format(len(unneeded_fonts)))
        for file in unneeded_fonts:
            file.unlink()
    
    def details_to_variable(details):
        if isinstance(details, list):
            raise TypeError('details should not be a list')
        if isinstance(details, str):
            name = details
            variable = name_to_var(name)
        else:
            if 'var' in details:
                variable = details['var']
                name = details['name']
            else:
              name = details['name']
              variable = name_to_var(name)
        return {"variable": variable, "name": name}
    
    variable_decls = []
    for key, details in sorted(font_data["families"].items()):
        if details:
          variable_decls.extend(details_to_variable(details) for details in (details if isinstance(details, list) else [details]))

    with (sc.static_dir / 'css' / 'fonts' / 'fonts-auto.scss').open('w') as f:
        f.write(font_header)

        f.writelines("${variable}: '{name}';\n".format(**e) for e in variable_decls)
        f.writelines(font_face_decls)
    
    for key in set(font_data["families"]) - fonts_seen:
        logger.error('Font family mapping matches no font file: {} ({})'.format(key, font_data["families"][key]))
Пример #28
0
]
font['cmap'].tables = [
    table for table in font['cmap'].tables if table.platformID != 1
]

# fix OS/2 and hhea metrics
glyf = font['glyf']
ascent = int(
    max(glyf[c].yMax for c in font.getGlyphOrder()
        if hasattr(glyf[c], "yMax")))
descent = -int(
    min(glyf[c].yMin
        for c in font.getGlyphOrder() if hasattr(glyf[c], "yMin")))

font['OS/2'].usWinAscent = ascent
font['OS/2'].usWinDescent = descent

font['hhea'].ascent = ascent
font['hhea'].descent = -descent

# save TTF
font.save(font_file, reorderTables=None)

# save WOFF
font.flavor = 'woff'
font.save(os.path.join('woff', font_name + '.woff'), reorderTables=None)

# save WOFF2
font.flavor = 'woff2'
font.save(os.path.join('woff2', font_name + '.woff2'), reorderTables=None)
Пример #29
0
        string = string.replace(value, data[value])  # 将编码按照映射表进行替换
    return string


with urllib.request.urlopen(
        'http://piaofang.maoyan.com/?ver=normal') as f:  # 爬去地址
    html = BeautifulSoup(
        f.read(), "html.parser")  # 使用BeautifulSoup用html.parser解析器进行html解析
font = html.find(id="js-nuwa")  # 读取存放字体文件的css内容
font = re.search(r'(?<=,)\S*(?=\))', str(font))  # 用正则表达式找出woff的base64字符串
if not font:
    print('未发现字体')
    exit()
font = base64.b64decode(font.group())  # base64解码成二进制文件
with open(basedir + 'temp.woff', 'wb') as f:
    f.write(font)  # 保存二进制到脚本根目录
font = TTFont(basedir + 'temp.woff', recalcBBoxes=False,
              recalcTimestamp=False)  # Pillow不支持用woff生成文字图片
font.flavor = None
font.save(basedir + 'temp.ttf', reorderTables=True)  # 将字体文件从woff转换成ttf

for n in html.find_all('ul', 'canTouch'):
    print(
        n.find('li', 'c1').b.string,
        distinguish(n.find('li', 'c1').find('i', 'cs').string),
        distinguish(n.find('li', 'c2').b.i.string),
        distinguish(n.find('li', 'c3').i.string),
        distinguish(n.find('li', 'c4').i.string),
        distinguish(n.find('li', 'c5').span.i.string),
    )
Пример #30
0
        # We round-trip through a buffer to workaround PIL not
        # resetting the dpi value.
        data = im.tobytes()
        im = Image.frombytes(im.mode, im.size, data)
        if dst.exists():
            dstIm = Image.open(dst)
            if data == dstIm.tobytes():
                # Don't save when the image data is the same, some
                # meta data may still have changed, making us do
                # unwanted commits.
                print("-- same image, skipping", dst)
                continue
        im.save(dst)

print("Subsetting fonts...")
for src in sorted(docsSourceFonts.glob("*.woff2")):
    dst = docsFonts / src.name
    font = TTFont(src)
    subsetter = Subsetter()
    unicodes = set(ord(c) for c in markdownSource)
    subsetter.populate(unicodes=unicodes)
    subsetter.subset(font)

    if dst.exists():
        existing = TTFont(dst, lazy=True)
        if sorted(font.getBestCmap()) == sorted(existing.getBestCmap()):
            print("-- same cmap, skipping", dst)
            continue
    font.flavor = "woff2"
    font.save(dst)
Пример #31
0
def compile_fonts(flavors=["woff", "woff2"]):
    import json
    import hashlib
    from fontTools.ttLib import TTFont
    import fontTools.subset

    tim = sc.textdata.tim()

    font_face_decls = []

    if not fonts_output_dir.exists():
        fonts_output_dir.mkdir()

    font_data = get_fonts_data()
    fonts_seen = set()
    font_keys = set()

    def get_font_details(font_name):
        font_name = font_name.lower()
        result = {}
        result.update(font_data["defaults"])
        for key, value in sorted(font_data["families"].items(), key=lambda t: len(t[0]), reverse=True):
            if font_name.startswith(key.lower()):
                fonts_seen.add(key)
                result["key"] = key
                leftovers = font_name[len(key) :]

                if not value:
                    return None
                if isinstance(value, str):
                    result["family"] = value
                    font_keys.add((key, value))
                elif isinstance(value, list):
                    result["subset"] = value
                elif isinstance(value, dict):
                    result["subset"] = [value]
                elif not value:
                    pass
                break
        else:
            logger.error("Font file %s does not have a matching entry in fonts.json", font_name)
            return None

        for key, weight in sorted(font_data["weights"].items(), key=lambda t: len(t[0]), reverse=True):
            if key in leftovers:
                result["weight"] = weight
                break
        else:
            result["weight"] = "normal"

        for key, style in sorted(font_data["styles"].items(), key=lambda t: len(t[0]), reverse=True):
            if key in leftovers:
                result["style"] = style
                break
        else:
            result["style"] = "normal"
        return result

    seen = {}

    compiled_fonts = set(fonts_output_dir.glob("**/*"))
    valid_compiled_fonts = set()

    extra_global_subset_glyphs = get_glyphs_from_table_data()

    for file in sorted(fonts_dir.glob("**/*")):
        changed = False
        nonfree = "nonfree" in file.parts
        if file in compiled_fonts:
            continue
        if file.suffix not in {".ttf", ".otf", ".woff", ".woff2"}:
            continue

        base_name = sanitize_font_name(file.stem)
        if base_name in seen:
            logger.error("Font file %s is too similiar to other file %s, skipping", file, seen[base_name])
        seen[base_name] = file

        with file.open("rb") as f:
            font_binary_data = f.read()
        md5 = hashlib.md5(font_binary_data)

        font_details = get_font_details(file.stem)

        if not font_details:
            continue

        if font_details["subset"]:
            extra_subset_commands = ["--layout-features+=liga,dlig,smcp,c2sc,onum", "--desubroutinize"]
            if font_details["weight"] in {"bold", "semibold"}:
                weight = "bold"
            elif font_details["style"] in {"italic"}:
                weight = "italic"
            else:
                weight = "normal"
            for subset_details in font_details["subset"]:
                subset_languages = subset_details["subset_languages"]
                subset_unicodes = set()

                if subset_languages == "*":  # global subset
                    subset_unicodes.update(extra_global_subset_glyphs)
                    subset_unicodes.update(tim.get_codepoints_used(lang_uid=None, weight_or_style=weight))

                else:
                    if isinstance(subset_languages, str):
                        subset_languages = [subset_languages]

                    for language in subset_languages:
                        codepoints = tim.get_codepoints_used(lang_uid=language, weight_or_style=weight)
                        if codepoints is None:
                            logger.error('Error in fonts.json, language uid "{}" not found in TIM'.format(language))
                        else:
                            subset_unicodes.update(codepoints)
                subset_text = "".join(subset_unicodes)
                subset_text = "".join(sorted(subset_text.lower() + subset_text.upper()))
                subset_md5 = md5.copy()
                subset_md5.update(subset_text.encode(encoding="utf8"))
                subset_md5.update("".join(extra_subset_commands).encode(encoding="utf8"))

                if False:  # nonfree and not sc.config.app['debug']:
                    outname = ""
                else:
                    outname = name_to_var(subset_details["name"]) + "_"

                outname += weight.replace("normal", "regular")
                if subset_languages != "*":
                    outname += "_" + "_".join(subset_languages)
                outname += "_" + subset_md5.hexdigest()[:12]
                base_outfile = fonts_output_dir / outname

                suffix = font_details["save_as"][0]

                primary_out_file = base_outfile.with_suffix("." + suffix)
                valid_compiled_fonts.add(primary_out_file)
                if not primary_out_file.exists():
                    changed = True
                    with NamedTemporaryFile("w+t") as subset_text_file:
                        subset_text_file.write(subset_text)
                        subset_text_file.flush()
                        fontTools.subset.main(
                            args=[
                                str(file),
                                #'--layout-features=*',
                                #'--glyph-names',
                                #'--symbol-cmap',
                                #'--legacy-cmap',
                                #'--notdef-glyph',
                                #'--notdef-outline',
                                #'--recommended-glyphs',
                                #'--name-IDs=*',
                                #'--name-legacy',
                                #'--name-languages=*',
                                "--output-file={}".format(str(primary_out_file)),
                                "--text-file={}".format(subset_text_file.name),
                                "--flavor={}".format(suffix),
                            ]
                            + extra_subset_commands
                        )
                font = None
                size = {}
                for flavor in font_details["save_as"][1:]:
                    suffix = ".{}".format(flavor)
                    outfile = base_outfile.with_suffix(suffix)
                    valid_compiled_fonts.add(outfile)
                    if not outfile.exists():
                        changed = True
                        if font is None:
                            font = TTFont(str(primary_out_file))
                        font.flavor = flavor
                        font.save(file=str(outfile))
                    size[flavor] = sizeof_fmt(outfile.stat().st_size)

                font_face_decls.append(
                    font_face_template.format(
                        url="/fonts/compiled/{}".format(outname),
                        family=subset_details["name"],
                        weight=font_details["weight"],
                        style=font_details["style"],
                        size=size,
                    )
                )
        else:
            size = {}
            md5sum = md5.hexdigest()[:12]
            outname = md5sum if (nonfree and not sc.config.app["debug"]) else "{}_{}".format(base_name, md5sum)
            base_outfile = fonts_output_dir / outname

            font = None
            for flavor in flavors:
                suffix = ".{}".format(flavor)
                outfile = base_outfile.with_suffix(suffix)
                valid_compiled_fonts.add(outfile)
                if not outfile.exists():
                    changed = True
                    if outfile.suffix == file.suffix:
                        with outfile.open("wb") as f:
                            f.write(font_binary_data)
                    else:
                        if font is None:
                            font = TTFont(str(file))
                        font.flavor = flavor
                        font.save(file=str(outfile))
                size[flavor] = sizeof_fmt(outfile.stat().st_size)

            if font_details:
                font_face_decls.append(
                    font_face_template.format(url="/fonts/compiled/{}".format(outname), size=size, **font_details)
                )
        if changed:
            print("Processed {!s}".format(file.name))
    unneeded_fonts = compiled_fonts - valid_compiled_fonts
    if unneeded_fonts:
        print("Removing {} unused compiled fonts".format(len(unneeded_fonts)))
        for file in unneeded_fonts:
            file.unlink()

    def details_to_variable(details):
        if isinstance(details, list):
            raise TypeError("details should not be a list")
        if isinstance(details, str):
            name = details
            variable = name_to_var(name)
        else:
            if "var" in details:
                variable = details["var"]
                name = details["name"]
            else:
                name = details["name"]
                variable = name_to_var(name)
        return {"variable": variable, "name": name}

    variable_decls = []
    for key, details in sorted(font_data["families"].items()):
        if details:
            variable_decls.extend(
                details_to_variable(details) for details in (details if isinstance(details, list) else [details])
            )

    with (sc.static_dir / "css" / "fonts" / "fonts-auto.scss").open("w") as f:
        f.write(font_header)

        f.writelines("${variable}: '{name}';\n".format(**e) for e in variable_decls)
        f.writelines(font_face_decls)

    for key in set(font_data["families"]) - fonts_seen:
        logger.error("Font family mapping matches no font file: {} ({})".format(key, font_data["families"][key]))
Пример #32
0
def WOFF2Builder(sourcePath, destinationPath):
    font = TTFont(sourcePath)
    font.flavor = "woff2"
    font.save(destinationPath)
Пример #33
0
def woff_size(font: TTFont, path: Path) -> int:
    font.flavor = "woff2"
    woff_path = path.with_suffix(".woff2")
    font.save(woff_path)
    return woff_path.stat().st_size
Пример #34
0
import os
import sys
from fontTools.ttLib import TTFont

dir = './'
if len(sys.argv) > 1:
    dir = sys.argv[1]

if dir[-1] != '/':
    dir += '/'

for file in os.listdir(dir):
    if file.endswith('.ttf'):
        f = TTFont(dir + file)
        f.flavor = 'woff2'
        f.save(dir + file[:-4] + '.woff2')