Пример #1
1
def convertToOTF(ttfPath, dest, report):
    temp = tempfile.mkstemp(suffix=".otf")[1]

    font = RFont(ttfPath, document=False, showInterface=False)
    font.kerning.clear()
    for attr in font.info.asDict().keys():
        if attr not in defaultFontInfoAttributes:
            setattr(font.info, attr, None)

    result = font.generate(path=temp, format="otf", decompose=False, checkOutlines=False, autohint=False, releaseMode=True, glyphOrder=font.glyphOrder)
    if not font.hasInterface():
        font.close()
    report.write(result)

    sourceFont = TTFont(temp)
    sourceFontWithTables = TTFont(ttfPath)
    for table in ["loca", "OS/2", "cmap", "name", "GSUB", "GPOS", "GDEF", "kern"]:
        if table in sourceFontWithTables:
            sourceFont[table] = sourceFontWithTables[table]

    sourceFont.save(dest)

    result = OTFAutohint(dest)
    report.writeItems(result)

    os.remove(temp)
Пример #2
0
def ttCompile(input, output, options):
	print('Compiling "%s" to "%s"...' % (input, output))
	ttf = TTFont(options.mergeFile,
			recalcBBoxes=options.recalcBBoxes,
			verbose=options.verbose, allowVID=options.allowVID)
	ttf.importXML(input)
	try:
		ttf.save(output)
	except OTLOffsetOverflowError as e:
		# XXX This shouldn't be here at all, it should be as close to the
		# OTL code as possible.
		overflowRecord = e.value
		print("Attempting to fix OTLOffsetOverflowError", e)
		lastItem = overflowRecord 
		while 1:
			ok = 0
			if overflowRecord.itemName == None:
				ok = fixLookupOverFlows(ttf, overflowRecord)
			else:
				ok = fixSubTableOverFlows(ttf, overflowRecord)
			if not ok:
				raise

			try:
				ttf.save(output)
				break
			except OTLOffsetOverflowError as e:
				print("Attempting to fix OTLOffsetOverflowError", e)
				overflowRecord = e.value
				if overflowRecord == lastItem:
					raise

	if options.verbose:
		import time
		print("finished at", time.strftime("%H:%M:%S", time.localtime(time.time())))
Пример #3
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())
Пример #4
0
def test_check_unique_glyphnames():
  """ Font contains unique glyph names? """
  import io
  from fontbakery.profiles.universal import com_google_fonts_check_unique_glyphnames as check

  test_font_path = TEST_FILE("nunito/Nunito-Regular.ttf")
  test_font = TTFont(test_font_path)
  status, _ = list(check(test_font))[-1]
  assert status == PASS

  # Fonttools renames duplicate glyphs with #1, #2, ... on load.
  # Code snippet from https://github.com/fonttools/fonttools/issues/149.
  glyph_names = test_font.getGlyphOrder()
  glyph_names[2] = glyph_names[3]
  # Load again, we changed the font directly.
  test_font = TTFont(test_font_path)
  test_font.setGlyphOrder(glyph_names)
  test_font['post']  # Just access the data to make fonttools generate it.
  test_file = io.BytesIO()
  test_font.save(test_file)
  test_font = TTFont(test_file)
  status, message = list(check(test_font))[-1]
  assert status == FAIL
  assert "space" in message

  # Upgrade to post format 3.0 and roundtrip data to update TTF object.
  test_font = TTFont(test_font_path)
  test_font.setGlyphOrder(glyph_names)
  test_font["post"].formatType = 3.0
  test_file = io.BytesIO()
  test_font.save(test_file)
  test_font = TTFont(test_file)
  status, message = list(check(test_font))[-1]
  assert status == SKIP
Пример #5
0
def test_check_valid_glyphnames():
  """ Glyph names are all valid? """
  import io
  from fontbakery.profiles.universal import com_google_fonts_check_valid_glyphnames as check

  test_font_path = TEST_FILE("nunito/Nunito-Regular.ttf")
  test_font = TTFont(test_font_path)
  status, _ = list(check(test_font))[-1]
  assert status == PASS

  bad_name1 = "a" * 32
  bad_name2 = "3cents"
  bad_name3 = ".threecents"
  good_name1 = "b" * 31
  test_font.glyphOrder[2] = bad_name1
  test_font.glyphOrder[3] = bad_name2
  test_font.glyphOrder[4] = bad_name3
  test_font.glyphOrder[5] = good_name1
  status, message = list(check(test_font))[-1]
  assert status == FAIL
  assert bad_name1 in message
  assert bad_name2 in message
  assert bad_name3 in message
  assert good_name1 not in message

  # Upgrade to post format 3.0 and roundtrip data to update TTF object.
  test_font = TTFont(test_font_path)
  test_font["post"].formatType = 3.0
  test_file = io.BytesIO()
  test_font.save(test_file)
  test_font = TTFont(test_file)
  status, message = list(check(test_font))[-1]
  assert status == SKIP
Пример #6
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]

    if len(args) < 2:
        print("usage: merge_woff_metadata.py METADATA.xml "
              "INPUT.woff [OUTPUT.woff]", file=sys.stderr)
        return 1

    metadata_file = args[0]
    with open(metadata_file, 'rb') as f:
        metadata = f.read()

    infile = args[1]
    if len(args) > 2:
        outfile = args[2]
    else:
        filename, ext = os.path.splitext(infile)
        outfile = makeOutputFileName(filename, None, ext)

    font = TTFont(infile)

    if font.flavor not in ("woff", "woff2"):
        print("Input file is not a WOFF or WOFF2 font", file=sys.stderr)
        return 1

    data = font.flavorData

    # this sets the new WOFF metadata
    data.metaData = metadata

    font.save(outfile)
Пример #7
0
def generate(font, extension):
    """ Clean GSUB lookups and merge them from the feature files """
    for lookup in font.gsub_lookups:
        font.removeLookup(lookup)
    
    font.mergeFeature('%s/%s_features.fea' %(feafiles, style))

    font.selection.all()
    font.autoHint()

    if extension == 'ttf':
#        font.em = 2048
        font.round()
        font.autoInstr()

    path = '%s/%s.%s' %(build, font.fontname, extension)
    tmp_path = '%s.tmp.%s' %(font.fontname, extension)

    font.generate(tmp_path)

    tmp_font = TTFont(tmp_path)
#    tmp_font['OS/2'].sxHeight, tmp_font['OS/2'].sCapHeight = getHeights(font)
    tmp_font.save(path)
    tmp_font.close()
    os.remove(tmp_path)
Пример #8
0
    def __init__(self, sourcePath, location, DEBUG=False):
        self.instancePath = tempfile.mkstemp()[1]
        tempPath = sourcePath.replace('.ttf', '-instance.ttf')
        
        cmds = ['python', pathToFontToolsMutator, sourcePath]
        for k, v in location.items():
            cmds.append('%s=%s' %(k, v))
        proc = subprocess.Popen(cmds, stdout=subprocess.PIPE)
        out = proc.communicate()[0]

        if DEBUG:
            print '---'
            print ' '.join(cmds)
            print '---'
            print out

        myUUID = str(uuid.uuid4()).replace('-', '')
        f = TTFont(tempPath)
        self.fontName = 'VF'+str(myUUID)
        
        f['name'].setName(self.fontName, 6, 1, 0, 0) # Macintosh
        f['name'].setName(self.fontName, 6, 3, 1, 0x409) # Windows
        
        os.remove(tempPath)
        
        f.save(self.instancePath)
def main(fontTargetPath, fontBracePath, braceGlyphsString):
    try:
        fontTarget = TTFont(fontTargetPath)
        fontBrace = TTFont(fontBracePath)
    except IOError as e:
        print e
        exit()
    except TTLibError as e:
        print e
        exit()

    braceGlyphsList = braceGlyphsString.split(",")
    print braceGlyphsList
    # print "Replacing brace glyphs in " + fontTargetPath + " with those from " + fontBracePath

    for glyphVariationsName in fontBrace['gvar'].variations:
        if glyphVariationsName in braceGlyphsList:
            fontTarget['gvar'].variations[glyphVariationsName] = fontBrace['gvar'].variations[glyphVariationsName]
            print "Replaced glyphVariation " + glyphVariationsName

    # We replace TTGlyphs after as updating glyphVariations otherwise an erorr is raised
    for TTGlyphName in fontBrace['glyf'].glyphs:
        if glyphVariationsName in braceGlyphsList:
            fontTarget['glyf'].glyphs[TTGlyphName] = fontBrace['glyf'].glyphs[TTGlyphName]
            print "Replaced TTGlyph " + TTGlyphName

    if __name__ == "__main__":
        fontTarget.save(fontTargetPath)
Пример #10
0
        def handle_font(font_name):
            font = TTFont(font_name)
            orig_size = os.path.getsize(font_name)

            if decompress:
                from fontTools import subset
                options = subset.Options()
                options.desubroutinize = True
                subsetter = subset.Subsetter(options=options)
                subsetter.populate(glyphs=font.getGlyphOrder())
                subsetter.subset(font)

            if verbose:
                print("Compressing font through iterative_encode:")
            out_name = "%s.compressed%s" % os.path.splitext(font_name)

            compreffor = Compreffor(font, verbose=verbose, **comp_kwargs)
            compreffor.compress()

            # save compressed font
            font.save(out_name)

            if generate_cff:
                # save CFF version
                font["CFF "].cff.compile(open("%s.cff" % os.path.splitext(out_name)[0], "w"), None)

            comp_size = os.path.getsize(out_name)
            print("Compressed to %s -- saved %s" % 
                    (os.path.basename(out_name), human_size(orig_size - comp_size)))

            if check:
                test_compression_integrity(filename, out_name)
                test_call_depth(out_name)
def generateFont(font, outfile):
    flags  = ("opentype", "dummy-dsig", "round", "omit-instructions")

    font.selection.all()
    font.correctReferences()
    font.selection.none()

    # fix some common font issues
    validateGlyphs(font)

    tmpfile = mkstemp(suffix=os.path.basename(outfile))[1]
    font.generate(tmpfile, flags=flags)
    font.close()

    # now open in fontTools
    from fontTools.ttLib import TTFont
    ftfont = TTFont(tmpfile)

    # force compiling tables by fontTools, saves few tens of KBs
    for tag in ftfont.keys():
        if hasattr(ftfont[tag], "compile"):
            ftfont[tag].compile(ftfont)

    ftfont.save(outfile)
    ftfont.close()
    os.remove(tmpfile)
Пример #12
0
def build(args):
    font, features = merge(args)

    build_encoded(font, features)

    with tempfile.NamedTemporaryFile(mode="r", suffix=args.out_file) as tmp:
        font.generate(tmp.name, flags=["round", "opentype"])
        ttfont = TTFont(tmp.name)

    try:
        builder.addOpenTypeFeatures(ttfont, features)
    except:
        with tempfile.NamedTemporaryFile(mode="w+", delete=False) as tmp:
            tmp.write(features.asFea())
            print("Failed! Inspect temporary file: %r" % tmp.name)
        raise

    # Filter-out useless Macintosh names
    ttfont["name"].names = [n for n in ttfont["name"].names if n.platformID != 1]

    # https://github.com/fontforge/fontforge/pull/3235
    # fontDirectionHint is deprecated and must be set to 2
    ttfont["head"].fontDirectionHint = 2
    # unset bits 6..10
    ttfont["head"].flags &= ~0x7e0

    # Drop useless table with timestamp
    if "FFTM" in ttfont:
        del ttfont["FFTM"]

    ttfont.save(args.out_file)
Пример #13
0
    def run(self):
        font = TTFont(self.in_font)
        gs = font.getGlyphSet()
        glyf = font["glyf"]
        hmtx = font["hmtx"]
        for gname, (adw, lsb) in hmtx.metrics.items():
            # https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/ttLib/tables/_g_l_y_f.py#L189-L192
            # __getitem__ internally calls table__g_l_y_f.expand which is essential to obtain xMin
            g = glyf[gname]
            # obtain recalculated xMin from glyph's control bounds
            g.recalcBounds(glyf)
            hmtx.metrics[gname] = (adw, g.xMin)
        if self.update_vmtx:
            from fontTools.pens.boundsPen import BoundsPen
            vmtx = font["vmtx"]
            for gname, (adh, tsb) in vmtx.metrics.items():
                g = glyf[gname]
                # obtain yMax
                g.recalcBounds(glyf)
                pen = BoundsPen(gs)
                g.draw(pen, glyf)
                if pen.bounds is None:
                    continue
                left, bottom, right, top = pen.bounds
                vmtx.metrics[gname] = (adh, top + tsb - g.yMax)

        font.save(self.out_font)

        return 0
Пример #14
0
class MyFontTools(object):
    def __init__(self, fontfile):
        self.font = TTFont(fontfile)

    def cmap_format_gbk2utf8(self):
        cmap = self.font['cmap']
        outtables = []
        for table in cmap.tables:
            if table.format in [4, 12, 13, 14]:
                outtables.append(table)
                
            # Convert ot format4
            if table.getEncoding() in SUPPORT_CONVERT_FROM_ENCODE:
                for gbk_code in table.cmap.keys():
                    uni_code= convert_from_gbk(gbk_code)
                    if gbk_code != uni_code:
                        table.cmap[uni_code] = table.cmap.pop(gbk_code)

                newtable = CmapSubtable.newSubtable(4)
                newtable.platformID = self.to_platformID
                newtable.platEncID = self.to_platEncID
                newtable.language = table.language
                newtable.cmap = table.cmap
                outtables.append(newtable)
        cmap.tables = outtables

    def vhea_fixed(self):
        self.font['vhea'].tableVersion=1.0


    def save(self, outfile):
        import pdb;pdb.set_trace()
        self.font.save(outfile)
Пример #15
0
def saveFont(glyphs, outputFileName, asXML, pixelSize, descent, fontName, copyrightYear, creator, version):
    f = TTFont()

    vectorizedGlyphs = {glyph : [vectorizeGlyph(glyphs[glyph][0], pixelSize, descent), glyphs[glyph][1]] for glyph in glyphs}
    unicodes = [code for glyph in glyphs for code in glyphs[glyph][1]]

    # Populate basic tables (there are a few dependencies so order matters)
    makeTable_glyf(f, vectorizedGlyphs)
    makeTable_maxp(f)
    makeTable_loca(f)
    makeTable_head(f)
    makeTable_hmtx(f)
    makeTable_hhea(f, pixelSize, descent)
    makeTable_OS2(f, pixelSize, descent, min(unicodes), max(unicodes))
    makeTable_cmap(f, glyphs)
    makeTable_name(f, fontName, "Regular", copyrightYear, creator, version)
    makeTable_post(f, pixelSize, descent)

    if asXML:
        # We have to compile the TTFont manually when saving as TTX
        # (to auto-calculate stuff here and there)
        f["glyf"].compile(f)
        f["maxp"].compile(f)
        f["loca"].compile(f)
        f["head"].compile(f)
        f["hmtx"].compile(f)
        f["hhea"].compile(f)
        f["OS/2"].compile(f)
        f["cmap"].compile(f)
        f["name"].compile(f)
        f["post"].compile(f)
        print "PLEASE NOTE: When exporting directly to XML, the checkSumAdjustment value in the head table will be 0."
        f.saveXML(outputFileName)
    else:
        f.save(outputFileName)
def main(fontTargetPath, fontBracePath):
    try:
        fontTarget = TTFont(fontTargetPath)
        fontBrace = TTFont(fontBracePath)
    except IOError as e:
        print e
        exit()
    except TTLibError as e:
        print e
        exit()

    print "Replacing brace glyphs in " + fontTargetPath + " with those from " + fontBracePath

    excludedGlyphs = ['.notdef', 'space']

    for glyphVariationsName in fontBrace['gvar'].variations:
        if glyphVariationsName in excludedGlyphs: continue
        fontTarget['gvar'].variations[glyphVariationsName] = fontBrace['gvar'].variations[glyphVariationsName]
        print "Replaced glyphVariation " + glyphVariationsName

    # We replace TTGlyphs after as updating glyphVariations otherwise an erorr is raised
    for TTGlyphName in fontBrace['glyf'].glyphs:
        if TTGlyphName in excludedGlyphs: continue
        fontTarget['glyf'].glyphs[TTGlyphName] = fontBrace['glyf'].glyphs[TTGlyphName]
        print "Replaced TTGlyph " + TTGlyphName

    if __name__ == "__main__":
        fontTarget.save(fontTargetPath)
Пример #17
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()
Пример #18
0
def main(args=None):
    parser = argparse.ArgumentParser(
        description="Use fontTools to compile OpenType feature files (*.fea).")
    parser.add_argument(
        "input_fea", metavar="FEATURES", help="Path to the feature file")
    parser.add_argument(
        "input_font", metavar="INPUT_FONT", help="Path to the input font")
    parser.add_argument(
        "-o", "--output", dest="output_font", metavar="OUTPUT_FONT",
        help="Path to the output font.")
    parser.add_argument(
        "-t", "--tables", metavar="TABLE_TAG", choices=Builder.supportedTables,
        nargs='+', help="Specify the table(s) to be built.")
    parser.add_argument(
        "-v", "--verbose", help="increase the logger verbosity. Multiple -v "
        "options are allowed.", action="count", default=0)
    options = parser.parse_args(args)

    levels = ["WARNING", "INFO", "DEBUG"]
    configLogger(level=levels[min(len(levels) - 1, options.verbose)])

    output_font = options.output_font or makeOutputFileName(options.input_font)
    log.info("Compiling features to '%s'" % (output_font))

    font = TTFont(options.input_font)
    addOpenTypeFeatures(font, options.input_fea, tables=options.tables)
    font.save(output_font)
Пример #19
0
 def compile_font(self, path, suffix, temp_dir):
     ttx_filename = os.path.basename(path)
     savepath = os.path.join(temp_dir, ttx_filename.replace('.ttx', suffix))
     font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
     font.importXML(path)
     font.save(savepath, reorderTables=None)
     return font, savepath
Пример #20
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()
Пример #21
0
def vtt_merge(infile, outfile=None, **kwargs):
    ufo = infile
    if not os.path.exists(ufo) or not os.path.isdir(ufo):
        raise VTTLibArgumentError("No such directory: '%s'" % ufo)

    check_ufo_version(ufo)

    if not outfile:
        outfile = os.path.splitext(infile)[0] + ".ttf"
    if not os.path.exists(outfile):
        raise VTTLibArgumentError("'%s' not found" % outfile)

    font = TTFont(outfile)
    if font.sfntVersion not in ("\x00\x01\x00\x00", "true"):
        raise VTTLibArgumentError("Not a TrueType font (bad sfntVersion)")

    for ttx in glob.glob(os.path.join(ufo, "data", TTX_DATA_FOLDER, "*.ttx")):
        identifier = os.path.splitext(os.path.basename(ttx))[0]
        try:
            tag = identifierToTag(identifier)
        except:
            continue
        else:
            if tag not in VTT_TABLES:
                continue
        font.importXML(ttx)

    read_maxp_data(ufo, font)

    font.save(outfile)
Пример #22
0
def process(infile, outfile, layer):
    font = TTFont(infile)
    glyf = font["glyf"]

    glyphNamesToKeep = []
    if layer == "letters":
        for glyphName in font.getGlyphNames():
            if glyphName not in _LAYER2_GLYPHS and glyphName not in _LAYER3_GLYPHS:
                glyphNamesToKeep.append(glyphName)
    elif layer == "diacritics":
        glyphNamesToKeep = _LAYER2_GLYPHS
    elif layer == "quranic-signs":
        glyphNamesToKeep = _LAYER3_GLYPHS

    for glyphName in font.getGlyphNames():
        if glyphName not in glyphNamesToKeep:
            glyph = glyf[glyphName]
            if glyphName in ("uni0670.medi", "uni06E5.medi", "uni06E6.medi") and layer == "letters":
                # We want to keep the kashida part of those glyphs.
                components = []
                for component in glyph.components:
                    if component.glyphName != glyphName.split(".")[0]:
                        components.append(component)
                glyph.components = components
            else:
                # This will cause FontTools not to output any outlines for that
                # glyph.
                glyph.numberOfContours = 0

    font.save(outfile)
Пример #23
0
def test_check_069():
  """ Is there any unused data at the end of the glyf table? """
  from fontbakery.specifications.glyf import com_google_fonts_check_069 as check

  test_font_path = os.path.join("data", "test", "nunito", "Nunito-Regular.ttf")

  test_font = TTFont(test_font_path)
  status, _ = list(check(test_font))[-1]
  assert status == PASS

  # Always start with a fresh copy, as fT works lazily. Accessing certain data
  # can prevent the test from working because we rely on uninitialized
  # behavior.
  test_font = TTFont(test_font_path)
  test_font["loca"].locations.pop()
  test_file = io.BytesIO()
  test_font.save(test_file)
  test_font = TTFont(test_file)
  status, message = list(check(test_font))[-1]
  assert status == FAIL
  assert message.code == "unreachable-data"

  test_font = TTFont(test_font_path)
  test_font["loca"].locations.append(50000)
  test_file = io.BytesIO()
  test_font.save(test_file)
  test_font = TTFont(test_file)
  status, message = list(check(test_font))[-1]
  assert status == FAIL
  assert message.code == "missing-data"
Пример #24
0
    def componentize_ttf(self):
        """
        Loads a TrueType font and iterates thru a dictionary of composites
        data. Remakes some glyphs in the glyf table from being made of
        countours to being made of components.

        Saves the modified font in a new location if an output path was
        provided, otherwise overwrites the original one.

        Updates a count of the glyphs that got componentized.
        """
        font = TTFont(self.opts.font_path)
        glyf_table = font['glyf']

        for gname in self.composites_data:
            if gname not in glyf_table:
                continue
            if not all([cname in glyf_table for cname in self.composites_data[
                    gname].names]):
                continue

            components = self.assemble_components(self.composites_data[gname])

            glyph = glyf_table[gname]
            glyph.__dict__.clear()
            setattr(glyph, "components", components)
            glyph.numberOfContours = -1
            self.comp_count += 1

        if self.opts.output_path:
            font.save(os.path.realpath(self.opts.output_path))
        else:
            font.save(self.opts.font_path)
def _optimizeForEOT(sourcePath, destPath):
    source = TTFont(sourcePath)
    # fix naming
    nameTable = source["name"]
    familyName = nameTable.getName(1, 3, 1)
    styleName = nameTable.getName(2, 3, 1)
    if familyName:
        familyName = familyName.string
    else:
        familyName = "Untitled"
    if styleName:
        styleName = styleName.string
    else:
        styleName = "Regular"

    records = []
    for record in nameTable.names:
        # ignore preferred naming
        if record.nameID not in [16, 17]:
            if record.nameID == 4:
                s = "%s %s" % (familyName, styleName)
                if record.platformID == 3 and record.platEncID in (0, 1):
                    record.string = _winStr(s)
                else:
                    record.string = _macStr(s)
        records.append(record)

    nameTable.names = records

    # set embedding bit
    os2 = source["OS/2"]
    os2.fsType = 4
    source.save(destPath)
    source.close()
Пример #26
0
def main(args=None):
    configLogger(logger=log)

    parser = argparse.ArgumentParser()
    parser.add_argument("input", nargs='+', metavar="INPUT")
    parser.add_argument("-o", "--output")
    parser.add_argument("-e", "--max-error", type=float, default=MAX_ERR)
    parser.add_argument("--post-format", type=float, default=POST_FORMAT)
    parser.add_argument(
        "--keep-direction", dest='reverse_direction', action='store_false')
    parser.add_argument("--face-index", type=int, default=0)
    parser.add_argument("--overwrite", action='store_true')
    options = parser.parse_args(args)

    if options.output and len(options.input) > 1:
        if not os.path.isdir(options.output):
            parser.error("-o/--output option must be a directory when "
                         "processing multiple fonts")

    for path in options.input:
        if options.output and not os.path.isdir(options.output):
            output = options.output
        else:
            output = makeOutputFileName(path, outputDir=options.output,
                                        extension='.ttf',
                                        overWrite=options.overwrite)

        font = TTFont(path, fontNumber=options.face_index)
        otf_to_ttf(font,
                   post_format=options.post_format,
                   max_err=options.max_error,
                   reverse_direction=options.reverse_direction)
        font.save(output)
Пример #27
0
def ttCompile(input, output, options):
	if not options.quiet:
		print 'Compiling "%s" to "%s"...' % (input, output)
	ttf = TTFont(options.mergeFile,
			recalcBBoxes=options.recalcBBoxes,
			verbose=options.verbose, allowVID=options.allowVID)
	ttf.importXML(input, quiet=options.quiet)
	try:
		ttf.save(output)
	except OTLOffsetOverflowError, e:
		# XXX This shouldn't be here at all, it should be as close to the
		# OTL code as possible.
		overflowRecord = e.value
		print "Attempting to fix OTLOffsetOverflowError", e
		lastItem = overflowRecord 
		while 1:
			ok = 0
			if overflowRecord.itemName == None:
				ok = fixLookupOverFlows(ttf, overflowRecord)
			else:
				ok = fixSubTableOverFlows(ttf, overflowRecord)
			if not ok:
				raise

			try:
				ttf.save(output)
				break
			except OTLOffsetOverflowError, e:
				print "Attempting to fix OTLOffsetOverflowError", e
				overflowRecord = e.value
				if overflowRecord == lastItem:
					raise
Пример #28
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()
Пример #29
0
def patch(filepath):
    print "Patching '%s' ..." % filepath,
    base, ext = filepath.rsplit(".", 1)
    font = TTFont(filepath)
    patch_cmap(font)
    font.save("%s_patch.%s" % (base, ext))
    font.close()
    print "OK"
Пример #30
0
def main(args=None):
    log = compreffor.log
    timer = compreffor.timer
    timer.reset()

    options = parse_arguments(args)

    # consume kwargs that are not passed on to 'compress' function
    infile = options.pop('infile')
    outfile = options.pop('outfile')
    decompress = options.pop('decompress')
    generate_cff = options.pop('generate_cff')
    check = options.pop('check')
    verbose = options.pop('verbose')

    if verbose == 1:
        level = logging.INFO
    elif verbose > 1:
        level = logging.DEBUG
    else:
        level = logging.WARNING

    configLogger(logger=log, level=level)

    orig_size = os.path.getsize(infile)

    font = TTFont(infile)

    if decompress:
        log.info("Decompressing font with FontTools Subsetter")
        with timer("decompress the font"):
            compreffor.decompress(font)

    log.info("Compressing font through %s Compreffor",
             "pure-Python" if options['method_python'] else "C++")

    compreffor.compress(font, **options)

    with timer("compile and save compressed font"):
        font.save(outfile)

    if generate_cff:
        cff_file = os.path.splitext(outfile)[0] + ".cff"
        with open(cff_file, 'wb') as f:
            font['CFF '].cff.compile(f, None)
        log.info("Saved CFF data to '%s'" % os.path.basename(cff_file))

    if check:
        log.info("Checking compression integrity and call depth")
        passed = compreffor.check(infile, outfile)
        if not passed:
            return 1

    comp_size = os.path.getsize(outfile)
    log.info("Compressed to '%s' -- saved %s" %
             (os.path.basename(outfile), human_size(orig_size - comp_size)))
    log.debug("Total time: %gs", timer.time())
Пример #31
0
def main(args=None):
    parser = argparse.ArgumentParser(
        description="Use fontTools to compile OpenType feature files (*.fea).")
    parser.add_argument("input_fea",
                        metavar="FEATURES",
                        help="Path to the feature file")
    parser.add_argument("input_font",
                        metavar="INPUT_FONT",
                        help="Path to the input font")
    parser.add_argument("-o",
                        "--output",
                        dest="output_font",
                        metavar="OUTPUT_FONT",
                        help="Path to the output font.")
    parser.add_argument("-t",
                        "--tables",
                        metavar="TABLE_TAG",
                        choices=Builder.supportedTables,
                        nargs='+',
                        help="Specify the table(s) to be built.")
    parser.add_argument("-v",
                        "--verbose",
                        help="increase the logger verbosity. Multiple -v "
                        "options are allowed.",
                        action="count",
                        default=0)
    parser.add_argument("--traceback",
                        help="show traceback for exceptions.",
                        action="store_true")
    options = parser.parse_args(args)

    levels = ["WARNING", "INFO", "DEBUG"]
    configLogger(level=levels[min(len(levels) - 1, options.verbose)])

    output_font = options.output_font or makeOutputFileName(options.input_font)
    log.info("Compiling features to '%s'" % (output_font))

    font = TTFont(options.input_font)
    try:
        addOpenTypeFeatures(font, options.input_fea, tables=options.tables)
    except FeatureLibError as e:
        if options.traceback:
            raise
        log.error(e)
    font.save(output_font)
Пример #32
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)
Пример #33
0
def ttCompile(input, output, options):
    log.info('Compiling "%s" to "%s"...' % (input, output))
    if options.useZopfli:
        from fontTools.ttLib import sfnt
        sfnt.USE_ZOPFLI = True
    ttf = TTFont(options.mergeFile,
                 flavor=options.flavor,
                 recalcBBoxes=options.recalcBBoxes,
                 recalcTimestamp=options.recalcTimestamp,
                 allowVID=options.allowVID)
    ttf.importXML(input)

    if not options.recalcTimestamp:
        # use TTX file modification time for head "modified" timestamp
        mtime = os.path.getmtime(input)
        ttf['head'].modified = timestampSinceEpoch(mtime)

    ttf.save(output)
Пример #34
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("font")
    parser.add_argument("new_name")
    parser.add_argument("-o", "--out")
    args = parser.parse_args()

    font = TTFont(args.font)
    current_name = font_familyname(font)
    rename_font(font, args.new_name)

    if args.out:
        out = args.out
    else:
        out = args.font.replace(current_name.replace(" ", ""),
                                args.new_name.replace(" ", ""))
    print("Saving font: {}".format(out))
    font.save(out)
Пример #35
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 = 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)
Пример #36
0
def main():
    description = "Removes unwanted tables from one or more font files"
    parser = argparse.ArgumentParser(description=description)

    parser.add_argument("-t",
                        "--tables",
                        type=str,
                        help="One or more comma separated table names")
    parser.add_argument("FONTPATH", nargs="+", help="One or more font files")

    args = parser.parse_args()

    tables = parse_tables(args.tables) if args.tables else None

    for fontpath in args.FONTPATH:
        ttfont = TTFont(fontpath)
        remove_tables(ttfont, tables)
        ttfont.save(fontpath)
Пример #37
0
def expose_ttc(src, dest):
    with open(src, "rb") as f:
        f.seek(8)
        count = unpack(">L", f.read(4))
    for index in range(count):
        font = TTFont(src, fontNumber=index)
        if font.sfntVersion == "OTTO":
            ext = ".otf"
        elif font.sfntVersion == "\0\1\0\0":
            ext = ".ttf"
        elif font.sfntVersion == "wOFF":
            ext = ".woff"
        elif font.sfntVersion == "wOF2":
            ext = ".woff2"
        else:
            ext = ""
        name = font["name"].getDebugName(6) + ext  # 6: postscript name
        font.save(join(dest, name))
Пример #38
0
def test_check_180():
    """Does the number of glyphs in the loca table match the maxp table?"""
    from fontbakery.specifications.loca import com_google_fonts_check_180 as check

    test_font_path = os.path.join("data", "test", "nunito",
                                  "Nunito-Regular.ttf")

    test_font = TTFont(test_font_path)
    status, _ = list(check(test_font))[-1]
    assert status == PASS

    test_font = TTFont(test_font_path)
    test_font["loca"].locations.pop()
    test_file = io.BytesIO()
    test_font.save(test_file)
    test_font = TTFont(test_file)
    status, _ = list(check(test_font))[-1]
    assert status == FAIL
Пример #39
0
def rename_font_family(path):
    """
    Adds suffix to font family it doesn't conflict with font installed on
    system, which could be in incorrect version.
    """
    font = TTFont(path)
    name_table = font['name']

    name = name_table.getName(nameID=1, platformID=3, platEncID=1, langID=0x409)
    assert name

    name = name.toUnicode()
    assert name.startswith('Font Awesome')

    name = name + ' (CopyQ)'
    name = name_table.setName(name, nameID=1, platformID=3, platEncID=1, langID=0x409)

    font.save(path)
Пример #40
0
        def handle_font(font_name):
            font = TTFont(font_name)

            td = font['CFF '].cff.topDictIndex[0]
            no_subrs = lambda fd: hasattr(fd, 'Subrs') and len(fd.Subrs) > 0
            priv_subrs = (hasattr(td, 'FDArray')
                          and any(no_subrs(fd) for fd in td.FDArray))
            if len(td.GlobalSubrs) > 0 or priv_subrs:
                print("Warning: There are subrs in %s" % font_name)

            orig_size = os.path.getsize(font_name)

            if decompress:
                from fontTools import subset
                options = subset.Options()
                options.desubroutinize = True
                subsetter = subset.Subsetter(options=options)
                subsetter.populate(glyphs=font.getGlyphOrder())
                subsetter.subset(font)

            out_name = "%s.compressed%s" % os.path.splitext(font_name)

            compreff(font, verbose=verbose, **comp_kwargs)

            # save compressed font
            start_time = time.time()
            font.save(out_name)
            if verbose:
                print("Compiled and saved (took %gs)" %
                      (time.time() - start_time))

            if generate_cff:
                # save CFF version
                font['CFF '].cff.compile(
                    open("%s.cff" % os.path.splitext(out_name)[0], 'w'), None)

            comp_size = os.path.getsize(out_name)
            print("Compressed to %s -- saved %s" %
                  (os.path.basename(out_name),
                   human_size(orig_size - comp_size)))

            if check:
                test_compression_integrity(filename, out_name)
                test_call_depth(out_name)
Пример #41
0
def main(args=None):

	if args is None:
		import sys
		args = sys.argv[1:]

	varfilename = args[0]
	locargs = args[1:]
	outfile = os.path.splitext(varfilename)[0] + '-instance.ttf'

	loc = {}
	for arg in locargs:
		tag,val = arg.split('=')
		assert len(tag) <= 4
		loc[tag.ljust(4)] = float(val)
	print("Location:", loc)

	print("Loading GX font")
	varfont = TTFont(varfilename)

	fvar = varfont['fvar']
	axes = {a.axisTag:(a.minValue,a.defaultValue,a.maxValue) for a in fvar.axes}
	# TODO Round to F2Dot14?
	loc = normalizeLocation(loc, axes)
	# Location is normalized now
	print("Normalized location:", loc)

	gvar = varfont['gvar']
	for glyphname,variations in gvar.variations.items():
		coordinates,_ = _GetCoordinates(varfont, glyphname)
		for var in variations:
			scalar = supportScalar(loc, var.axes)
			if not scalar: continue
			# TODO Do IUP / handle None items
			coordinates += GlyphCoordinates(var.coordinates) * scalar
		_SetCoordinates(varfont, glyphname, coordinates)

	print("Removing GX tables")
	for tag in ('fvar','avar','gvar'):
		if tag in varfont:
			del varfont[tag]

	print("Saving instance font", outfile)
	varfont.save(outfile)
Пример #42
0
def convertToTTF(otfPath, dest, report):
    temp = tempfile.mkstemp(suffix=".ttf")[1]
    tempDest = tempfile.mkstemp(suffix=".ttf")[1]

    font = OpenFont(otfPath, showUI=False)
    font.lib[shouldAddPointsInSplineConversionLibKey] = 1
    font.kerning.clear()

    for attr in font.info.asDict().keys():
        if attr not in defaultFontInfoAttributes:
            setattr(font.info, attr, None)

    result = font.generate(path=temp,
                           format="ttf",
                           decompose=False,
                           checkOutlines=False,
                           autohint=False,
                           releaseMode=True,
                           glyphOrder=font.glyphOrder)
    font.close()
    report.write(result)

    sourceFont = TTFont(temp)
    sourceFontWithTables = TTFont(otfPath)

    for table in [
            "loca", "OS/2", "cmap", "name", "GSUB", "GPOS", "GDEF", "kern"
    ]:
        if table in sourceFontWithTables:
            sourceFont[table] = sourceFontWithTables[table]
    fixMetrics(sourceFont)
    sourceFont.save(tempDest)

    sourceFont.close()
    del sourceFont
    sourceFontWithTables.close()
    del sourceFontWithTables

    autohintOptions = getExtensionDefault(settingsIdentifier, defaultOptions)
    result = TTFAutohint(tempDest, dest, autohintOptions)
    report.writeItems(result)

    os.remove(temp)
    os.remove(tempDest)
Пример #43
0
def main():
  argparser = argparse.ArgumentParser(
    description='Rename family and/or styles of font'
  )
  a = lambda *args, **kwargs: argparser.add_argument(*args, **kwargs)
  a('-o', '--output', metavar='<file>',
    help='Output font file. Defaults to input file (overwrite)')
  a('--family', metavar='<name>',
    help='Rename family to <name>')
  a('--style', metavar='<name>',
    help='Rename style to <name>')
  a('--google-style', action='store_true',
    help='Rename style names to Google Fonts standards')
  a('input', metavar='<file>',
    help='Input font file')
  args = argparser.parse_args()

  infile = args.input
  outfile = args.output or infile

  font = TTFont(infile, recalcBBoxes=False, recalcTimestamp=False)
  editCount = 0
  try:
    if args.family:
      editCount += 1
      setFamilyName(font, args.family)

    if args.style:
      editCount += 1
      setStyleName(font, args.style)

    if args.google_style:
      editCount += 1
      renameStylesGoogleFonts(font)

    if editCount == 0:
      print("no rename options provided", file=sys.stderr)
      argparser.print_help(sys.stderr)
      sys.exit(1)
      return

    font.save(outfile)
  finally:
    font.close()
def main():
    filename = sys.argv[1]

    font = TTFont(filename, recalcBBoxes=False)
    fontName = font["name"]

    originalFontUniqueID = fontName.getName(3, 1, 0, 0).toUnicode()
    originalFontFullname = fontName.getName(4, 1, 0, 0).toUnicode()
    originalFontPreferredStyle = fontName.getName(17, 1, 0, 0).toUnicode()

    for entry in fontName.names:
        nameID = entry.nameID
        platformID = entry.platformID
        platEncID = entry.platEncID
        langID = entry.langID

        if langID in [1028, 1041, 2052, 3076]:
            string = (entry.toUnicode().replace(
                " CL",
                " CL Nerd Font").replace(" TC", " TC Nerd Font").replace(
                    " J", " J Nerd Font").replace(" SC",
                                                  " SC Nerd Font").replace(
                                                      " HC", " HC Nerd Font"))
            fontName.setName(string, nameID, platformID, platEncID, langID)

        elif nameID in [1, 16]:
            string = originalFontUniqueID.replace(
                f" {originalFontPreferredStyle}", " Nerd Font")
            fontName.setName(string, nameID, platformID, platEncID, langID)

        elif nameID == 3:
            string = originalFontUniqueID.replace(
                f" {originalFontPreferredStyle}",
                f" Nerd Font {originalFontPreferredStyle}",
            )
            fontName.setName(string, nameID, platformID, platEncID, langID)

        elif nameID == 6:
            fontName.setName(originalFontFullname, nameID, platformID,
                             platEncID, langID)

    font.save(filename)
    font.close()
Пример #45
0
def main(args=None):
    parser = argparse.ArgumentParser()
    parser.add_argument("input", metavar="INPUT")
    parser.add_argument("-o", "--output")
    parser.add_argument("-e", "--max-error", type=float, default=MAX_ERR)
    parser.add_argument("--post-format", type=float, default=POST_FORMAT)
    parser.add_argument("--keep-direction",
                        dest='reverse_direction',
                        action='store_false')
    options = parser.parse_args(args)

    output = options.output or makeOutputFileName(
        options.input, outputDir=None, extension='.ttf')
    font = TTFont(options.input)
    otf_to_ttf(font,
               post_format=options.post_format,
               max_err=options.max_error,
               reverse_direction=options.reverse_direction)
    font.save(output)
Пример #46
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("font", help="Path to font")
    parser.add_argument("-o", "--out", help="Output path for fixed font")
    parser.add_argument(
        "--include-source-fixes",
        action="store_true",
        help="Fix font issues that should be fixed in the source files.",
    )
    args = parser.parse_args()

    font = TTFont(args.font)

    fix_font(font, args.include_source_fixes)

    if args.out:
        font.save(args.out)
    else:
        font.save(font.reader.file.name + ".fix")
Пример #47
0
def ttCompile(input, output, options):
	if not options.quiet:
		print('Compiling "%s" to "%s"...' % (input, output))
	ttf = TTFont(options.mergeFile,
			recalcBBoxes=options.recalcBBoxes,
			recalcTimestamp=options.recalcTimestamp,
			verbose=options.verbose, allowVID=options.allowVID)
	ttf.importXML(input, quiet=options.quiet)

	if not options.recalcTimestamp:
		# use TTX file modification time for head "modified" timestamp
		mtime = os.path.getmtime(input)
		ttf['head'].modified = timestampSinceEpoch(mtime)

	ttf.save(output)

	if options.verbose:
		import time
		print("finished at", time.strftime("%H:%M:%S", time.localtime(time.time())))
def main():
    args = parser.parse_args()

    for font_path in args.fonts:
        nametable = nametable_from_filename(font_path)
        font = TTFont(font_path)
        font_filename = ntpath.basename(font_path)

        font['name'] = nametable
        style = font_filename[:-4].split('-')[-1]
        font['OS/2'].usWeightClass = set_usWeightClass(style)
        font['OS/2'].fsSelection = set_fsSelection(font['OS/2'].fsSelection,
                                                   style)
        win_style = font['name'].getName(2, 3, 1,
                                         1033).string.decode('utf_16_be')
        font['head'].macStyle = set_macStyle(win_style)

        font.save(font_path + '.fix')
        print('font saved %s.fix' % font_path)
Пример #49
0
def subsetFontFT(path, unicodes, quran=False):
    from fontTools import subset

    font = TTFont(path, recalcTimestamp=False)

    options = subset.Options()
    options.set(layout_features='*',
                name_IDs='*',
                name_languages='*',
                notdef_outline=True,
                glyph_names=True)
    subsetter = subset.Subsetter(options=options)
    subsetter.populate(unicodes=unicodes)
    subsetter.subset(font)

    if quran:
        font["OS/2"].sTypoAscender = font["hhea"].ascent = font["head"].yMax

    font.save(path)
Пример #50
0
def hinting_stats(font):
    """
    Return file size differences for a hinted font compared to an dehinted version of same file
    """
    from io import BytesIO
    from dehinter.font import dehint
    from fontTools.ttLib import TTFont
    from fontTools.subset import main as pyftsubset
    from fontbakery.profiles.shared_conditions import (is_ttf, is_cff, is_cff2)

    hinted_size = os.stat(font).st_size
    ttFont = TTFont(font)

    if is_ttf(ttFont):
        dehinted_buffer = BytesIO()
        dehint(ttFont, verbose=False)
        ttFont.save(dehinted_buffer)
        dehinted_buffer.seek(0)
        dehinted_size = len(dehinted_buffer.read())
    elif is_cff(ttFont) or is_cff2(ttFont):
        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
        os.remove(tmp)

    else:
        return None

    return {
        "dehinted_size": dehinted_size,
        "hinted_size": hinted_size,
    }
Пример #51
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)
Пример #52
0
    def install_fonts():
        """
        Install fonts to ~/.fonts.
        The fonts being installed is Titillium Web ~
        https://fonts.google.com/specimen/Titillium+Web
        Open Source Approved fonts.
        # TODO support for SystemWide Installation
        :return: True if installation successful, else False
        """
        sys_font_dir = os.path.join(os.path.expanduser('~'), '.fonts')
        if not os.path.exists(sys_font_dir):
            os.makedirs(sys_font_dir)

        try:
            from fontTools.ttLib import TTFont
        except ModuleNotFoundError as e:
            logging.error(
                "Error Installing the fonts. "
                "You might have to manually install the fonts"
                "Titillium Web : "
                "https://fonts.google.com/specimen/Titillium+Web "
                "Error: {}".format(e)
            )
            return False

        font_dir = os.path.join(os.path.abspath(
            os.path.dirname(os.path.dirname(__file__))), 'ui', 'fonts')
        try:
            fonts = os.listdir(font_dir)
            for i in fonts:
                font = TTFont(os.path.join(font_dir, i))
                font.save(os.path.join(sys_font_dir, i))
            return True
        except Exception as e:
            logging.error(
                "Error Installing the fonts. "
                "You might have to manually install the fonts"
                "Titillium Web : "
                "https://fonts.google.com/specimen/Titillium+Web "
                "Error: {}".format(e)
            )
            return False
Пример #53
0
def main():
    parser = argparse.ArgumentParser(
        description=
        "Create a version of Amiri with colored marks using COLR/CPAL tables.")
    parser.add_argument("infile",
                        metavar="INFILE",
                        type=str,
                        help="input font to process")
    parser.add_argument("outfile",
                        metavar="OUTFILE",
                        type=str,
                        help="output font to write")

    args = parser.parse_args()

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

    rename(font)

    font.save(args.outfile)
Пример #54
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]

    if len(args) < 1:
        print("usage: gzip.py " "INPUT.ttx [OUTPUT.ttf]", file=sys.stderr)
        return 1

    infile = args[0]
    if len(args) > 1:
        outfile = args[1]
    else:
        outfile = makeOutputFileName(infile, None, ".ttf")

    font = TTFont()
    font.importXML(infile)

    svg = font["SVG "]
    svg.compressed = True
    font.save(outfile)
Пример #55
0
def main():
  argparser = argparse.ArgumentParser(description='Fix names in variable font')
  a = lambda *args, **kwargs: argparser.add_argument(*args, **kwargs)
  a('-o', '--output', metavar='<file>',
    help='Output font file. Defaults to input file (overwrite)')
  a('input', metavar='<file>',
    help='Input font file')
  args = argparser.parse_args()

  infile = args.input
  outfile = args.output or infile

  font = TTFont(infile, recalcBBoxes=False, recalcTimestamp=False)

  fullName = fix_fullname(font)
  fix_unique_id(font, fullName)
  clear_subfamily_name(font)

  font.save(outfile)
  font.close()
Пример #56
0
def main(args=None):
    """Optimize the layout tables of an existing font."""
    from argparse import ArgumentParser

    from fontTools import configLogger

    parser = ArgumentParser(
        prog="otlLib.optimize",
        description=main.__doc__,
        formatter_class=RawTextHelpFormatter,
    )
    parser.add_argument("font")
    parser.add_argument("-o",
                        metavar="OUTPUTFILE",
                        dest="outfile",
                        default=None,
                        help="output file")
    parser.add_argument(
        "--gpos-compression-level",
        help=COMPRESSION_LEVEL.help,
        default=COMPRESSION_LEVEL.default,
        choices=list(range(10)),
        type=int,
    )
    logging_group = parser.add_mutually_exclusive_group(required=False)
    logging_group.add_argument("-v",
                               "--verbose",
                               action="store_true",
                               help="Run more verbosely.")
    logging_group.add_argument("-q",
                               "--quiet",
                               action="store_true",
                               help="Turn verbosity off.")
    options = parser.parse_args(args)

    configLogger(level=(
        "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO"))

    font = TTFont(options.font)
    compact(font, options.gpos_compression_level)
    font.save(options.outfile or options.font)
Пример #57
0
def encode_glyph(ttf_path: str, glyph_name: str, unicode: str):
    font = TTFont(ttf_path)
    go = font.getGlyphOrder()
    if glyph_name not in go:
        font.close()
        print(f"Glyph '{glyph_name}' not in font, skipping.")
        return

    if unicode.startswith("U+"):
        try:
            unicode_number = int(unicode[2:], 16)
        except:
            font.close()
            print(f"Could not parse Unicode value '{glyph_name}', "
                  "it must start with 'U+' followed by the value as "
                  "a hexadecimal number.")
            return

        tsiv = font["TSIV"]
        data = tsiv.data.decode()
        # data = data.split("\0")
        lines = data.splitlines()
        seen_glyph_def = False
        for i, line in enumerate(lines):
            if line.strip().startswith("DEF_GLYPH"):
                seen_glyph_def = True
                continue

            if not seen_glyph_def:
                continue

            index = go.index(glyph_name)
            entry = (f'DEF_GLYPH "{glyph_name}" ID {index} '
                     f"UNICODE {unicode_number} TYPE BASE END_GLYPH")
            lines.insert(i, entry)
            print(f"Inserting entry at line {i}: \n    {entry}")
            set_TSIV(tsiv, lines)
            font.save(ttf_path)
            break

    font.close()
Пример #58
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("font_path")
    parser.add_argument("-f",
                        "--remove-incompatible-hinting",
                        action="store_true")
    args = parser.parse_args()

    font = TTFont(args.font_path)
    if "TSI1" not in font:
        print("Font is not VTT hinted")
        return
    glyph_names = font.getGlyphOrder()

    incompatible_glyphs = []
    for gid, glyph_name in enumerate(glyph_names):
        try:
            data = get_glyph_assembly(font, glyph_name)
        except KeyError:
            pass
        try:
            program, components = make_glyph_program(data, glyph_name)
        except:
            incompatible_glyphs.append((gid, glyph_name))

    if not incompatible_glyphs:
        print("All glyphs compile")
        return
    print("Following glyphs cannot compile using vttLib:")
    print("GlyphID GlyphName")
    for gid, glyph_name in incompatible_glyphs:
        print(gid, glyph_name)

    if not args.remove_incompatible_hinting:
        return
    if args.remove_incompatible_hinting:
        for _, glyph_name in incompatible_glyphs:
            font['TSI1'].glyphPrograms[glyph_name] = ""
            font['TSI3'].glyphPrograms[glyph_name] = ""
    font.save(args.font_path + ".fix")
    print("Incompatible glyph hints have been removed")
Пример #59
0
def rexify(font, out):
    '''
    Rexify font.

    This will take all inaccessible glyphs from the font,
    place them in a PUA, and modify the CMAPs so that these
    glyphs are publicly accessible.

    This will also generate the required tables for ReX.
    '''

    # Make glyphs accessible.
    ttfont = TTFont(font, recalcBBoxes=False)
    make_accessible(ttfont)
    ttfont.save(out + os.path.basename(font))

    gen_constants(ttfont, out)
    gen_glyphs(ttfont, out)
    gen_kerning(ttfont, out)
    gen_symbols(ttfont, out)
    gen_variants(ttfont, out)
Пример #60
0
def main():
    filepath = sys.argv[1]
    tt = TTFont(filepath)

    # remove & replace last item in AXES to work for italic font
    if "Italic" in filepath:
        AXES.pop()
        AXES.append(
            dict(
                tag="ital",
                name="Italic",
                ordering=4,
                values=[
                    dict(nominalValue=1, name="Italic"),
                ],
            ))

    buildStatTable(tt, AXES)
    update_fvar(tt)
    tt.save(filepath)
    print(f"Added STAT table to {filepath}")