Пример #1
0
def find_and_replace_ttx(ttx_path, find_string, replace_string, tables=['name']):
    count = 0

    # 1. modify 'name' table
    if 'name' in tables:
        tree  = parse(ttx_path)
        root  = tree.getroot()
        for child in root.find('name'):
            if child.text.find(find_string) != -1:
                new_text = child.text.replace(find_string, replace_string)
                child.text = new_text
                count += 1
        tree.write(ttx_path)

    # 2. modify 'CFF ' table
    if 'CFF ' in tables:
        CFF_elements = ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight']
        tt_font = TTFont()
        tt_font.importXML(ttx_path)
        font_dict = tt_font['CFF '].cff.topDictIndex.items[0]
        for element in CFF_elements:
            text = getattr(font_dict, element)
            if text.find(find_string) != -1:
                new_text = text.replace(find_string, replace_string)
                setattr(font_dict, element, new_text)
                count += 1
        tt_font.saveXML(ttx_path)

    # done
    return count
Пример #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, 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
Пример #3
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
Пример #4
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
Пример #5
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)
Пример #6
0
 def test_bit6_draw_to_pen_issue1771(self):
     # https://github.com/fonttools/fonttools/issues/1771
     font = TTFont(sfntVersion="\x00\x01\x00\x00")
     # glyph00003 contains a bit 6 flag on the first point,
     # which triggered the issue
     font.importXML(GLYF_TTX)
     glyfTable = font['glyf']
     pen = RecordingPen()
     glyfTable["glyph00003"].draw(pen, glyfTable=glyfTable)
     expected = [('moveTo', ((501, 1430),)),
                 ('lineTo', ((683, 1430),)),
                 ('lineTo', ((1172, 0),)),
                 ('lineTo', ((983, 0),)),
                 ('lineTo', ((591, 1193),)),
                 ('lineTo', ((199, 0),)),
                 ('lineTo', ((12, 0),)),
                 ('lineTo', ((501, 1430),)),
                 ('closePath', ()),
                 ('moveTo', ((249, 514),)),
                 ('lineTo', ((935, 514),)),
                 ('lineTo', ((935, 352),)),
                 ('lineTo', ((249, 352),)),
                 ('lineTo', ((249, 514),)),
                 ('closePath', ())]
     self.assertEqual(pen.value, expected)
Пример #7
0
def test_max_ctx_calc_features_ttx(file_name, max_context):
    ttx_path = os.path.join(os.path.dirname(__file__),
                            'data', '{}.ttx'.format(file_name))
    font = TTFont()
    font.importXML(ttx_path)

    assert maxCtxFont(font) == max_context
Пример #8
0
def test_max_ctx_calc_features_ttx(file_name, max_context):
    ttx_path = os.path.join(os.path.dirname(__file__), 'data',
                            '{}.ttx'.format(file_name))
    font = TTFont()
    font.importXML(ttx_path)

    assert maxCtxFont(font) == max_context
Пример #9
0
def main(args):
        #assume input is .ttx file
        #TODO:input is .ttf file
        input = args[0]
        ttf = TTFont()
        ttf.importXML(input,quiet=True)

        bytecode_font = BytecodeFont()
        constructCVTTable(ttf['cvt '].values)
        # TODO:for now just analyze the font program file, later
        # should add the prep and all the glyphs
        body = Body(bytecode_font, 'fpgm', ttf)

        constructInstructions(body)
        constructSuccessor(body)
        constructPredecessor(body)
        
        current_state = Environment()
        executor = AbstractExecutor(bytecode_font)

        instruction = body.instructions[0]
        
        while instruction in body.successors:
            executor.execute(instruction, current_state)
            instruction.prettyPrint()
            instruction = body.successors[instruction][0]

        for key,value in bytecode_font.function_table.items():
            print('Function #{0}:'.format(key))
            for instruction in value:
                instruction.prettyPrint()
Пример #10
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)
Пример #11
0
def main():
    if EXT == 'ttf':
        # convert source to xml
        print('[+] Loading {}..'.format(args.filename))
        font = TTFont(args.filename)
        font.saveXML(OUT_TTX)

        # parsing XML
        print('[+] Generating {} file...'.format(OUT_TTX))
        font_tree = ET.parse(OUT_TTX)
        font_root = font_tree.getroot()

        for letter in font_root.iter('map'):
            if letter.attrib['name'] in subs.keys():
                letter.set('code', hex(ord(subs[letter.attrib['name']])))

        font_tree.write(OUT_TTX)

        # convert to ttf
        print('[+] Generating {} file...'.format(OUT_TTF))
        font = TTFont()
        font.importXML(OUT_TTX)
        font.save(OUT_TTF)

    elif EXT == 'ttx':
        # load the xml
        font_root = ET.parse(args.filename).getroot()
        for letter in asci:
            for item in font_root.iter('map'):
                if item.attrib['code'] == hex(ord(letter)):
                    subs[item.attrib['name']] = letter

    if args.t:
        print('\n' + ''.join(subs[letter] if letter in subs.keys() else letter
                             for letter in args.t))
Пример #12
0
def test_ttcompile_timestamp_calcs(inpath, outpath1, outpath2, tmpdir):
    inttx = os.path.join("Tests", "ttx", "data", inpath)
    outttf1 = tmpdir.join(outpath1)
    outttf2 = tmpdir.join(outpath2)
    options = ttx.Options([], 1)
    # build with default options = do not recalculate timestamp
    ttx.ttCompile(inttx, str(outttf1), options)
    # confirm that font was built
    assert outttf1.check(file=True)
    # confirm that timestamp is same as modified time on ttx file
    mtime = os.path.getmtime(inttx)
    epochtime = timestampSinceEpoch(mtime)
    ttf = TTFont(str(outttf1))
    assert ttf["head"].modified == epochtime

    # reset options to recalculate the timestamp and compile new font
    options.recalcTimestamp = True
    ttx.ttCompile(inttx, str(outttf2), options)
    # confirm that font was built
    assert outttf2.check(file=True)
    # confirm that timestamp is more recent than modified time on ttx file
    mtime = os.path.getmtime(inttx)
    epochtime = timestampSinceEpoch(mtime)
    ttf = TTFont(str(outttf2))
    assert ttf["head"].modified > epochtime

    # --no-recalc-timestamp will keep original timestamp
    options.recalcTimestamp = False
    ttx.ttCompile(inttx, str(outttf2), options)
    assert outttf2.check(file=True)
    inttf = TTFont()
    inttf.importXML(inttx)
    assert inttf["head"].modified == TTFont(str(outttf2))["head"].modified
Пример #13
0
def load_ttx(ttx):
    f = StringIO()
    f.write(ttx)
    f.seek(0)
    font = TTFont()
    font.importXML(f)
    return font
Пример #14
0
def load_ttx(ttx):
    f = UnicodeIO()
    f.write(ttx)
    f.seek(0)
    font = TTFont()
    font.importXML(f)
    return font
Пример #15
0
def test_virtualGlyphId():
    otfpath = os.path.join(DATA_DIR, "TestVGID-Regular.otf")
    ttxpath = os.path.join(DATA_DIR, "TestVGID-Regular.ttx")

    otf = TTFont(otfpath)

    ttx = TTFont()
    ttx.importXML(ttxpath)

    with open(ttxpath, encoding="utf-8") as fp:
        xml = normalize_TTX(fp.read()).splitlines()

    for font in (otf, ttx):
        GSUB = font["GSUB"].table
        assert GSUB.LookupList.LookupCount == 37
        lookup = GSUB.LookupList.Lookup[32]
        assert lookup.LookupType == 8
        subtable = lookup.SubTable[0]
        assert subtable.LookAheadGlyphCount == 1
        lookahead = subtable.LookAheadCoverage[0]
        assert len(lookahead.glyphs) == 46
        assert "glyph00453" in lookahead.glyphs

        out = io.StringIO()
        font.saveXML(out)
        outxml = normalize_TTX(out.getvalue()).splitlines()
        assert xml == outxml
Пример #16
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())))
Пример #17
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
Пример #18
0
def test_ttcompile_timestamp_calcs(inpath, outpath1, outpath2, tmpdir):
    inttx = os.path.join("Tests", "ttx", "data", inpath)
    outttf1 = tmpdir.join(outpath1)
    outttf2 = tmpdir.join(outpath2)
    options = ttx.Options([], 1)
    # build with default options = do not recalculate timestamp
    ttx.ttCompile(inttx, str(outttf1), options)
    # confirm that font was built
    assert outttf1.check(file=True)
    # confirm that timestamp is same as modified time on ttx file
    mtime = os.path.getmtime(inttx)
    epochtime = timestampSinceEpoch(mtime)
    ttf = TTFont(str(outttf1))
    assert ttf["head"].modified == epochtime

    # reset options to recalculate the timestamp and compile new font
    options.recalcTimestamp = True
    ttx.ttCompile(inttx, str(outttf2), options)
    # confirm that font was built
    assert outttf2.check(file=True)
    # confirm that timestamp is more recent than modified time on ttx file
    mtime = os.path.getmtime(inttx)
    epochtime = timestampSinceEpoch(mtime)
    ttf = TTFont(str(outttf2))
    assert ttf["head"].modified > epochtime

    # --no-recalc-timestamp will keep original timestamp
    options.recalcTimestamp = False
    ttx.ttCompile(inttx, str(outttf2), options)
    assert outttf2.check(file=True)
    inttf = TTFont()
    inttf.importXML(inttx)
    assert inttf["head"].modified == TTFont(str(outttf2))["head"].modified
Пример #19
0
def find_and_replace_ttx(ttx_path, find_string, replace_string, tables=['name']):
    count = 0

    # 1. modify 'name' table
    if 'name' in tables:
        tree  = parse(ttx_path)
        root  = tree.getroot()
        for child in root.find('name'):
            if child.text.find(find_string) != -1:
                new_text = child.text.replace(find_string, replace_string)
                child.text = new_text
                count += 1
        tree.write(ttx_path)

    # 2. modify 'CFF ' table
    if 'CFF ' in tables:
        CFF_elements = ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight']
        tt_font = TTFont()
        tt_font.importXML(ttx_path)
        font_dict = tt_font['CFF '].cff.topDictIndex.items[0]
        for element in CFF_elements:
            text = getattr(font_dict, element)
            if text.find(find_string) != -1:
                new_text = text.replace(find_string, replace_string)
                setattr(font_dict, element, new_text)
                count += 1
        tt_font.saveXML(ttx_path)

    # done
    return count
Пример #20
0
 def _open_font(master_path, master_finder=lambda s: s):
     font = TTFont()
     font.importXML(master_path)
     buf = BytesIO()
     font.save(buf, reorderTables=False)
     buf.seek(0)
     font = TTFont(buf, lazy=True)  # reopen in lazy mode, to reproduce #1808
     return font
Пример #21
0
def ttf_path(tmp_path):
    # $(dirname $0)/../ttLib/data
    ttLib_data = pathlib.Path(__file__).parent.parent / "ttLib" / "data"
    font = TTFont()
    font.importXML(ttLib_data / "TestTTF-Regular.ttx")
    font_path = tmp_path / "TestTTF-Regular.ttf"
    font.save(font_path)
    return font_path
Пример #22
0
 def setUp(self):
     font = TTFont(None,
                   lazy=False,
                   recalcBBoxes=True,
                   verbose=False,
                   allowVID=False)
     font.importXML(self.operator.path, quiet=True)
     self.font = font
Пример #23
0
 def setUp(self):
     # TODO: Need somebody to check this options
     font = TTFont(None,
                   lazy=False,
                   recalcBBoxes=True,
                   verbose=False,
                   allowVID=False)
     font.importXML(self.path, quiet=True)
     self.font = font
Пример #24
0
 def test_recalc_empty(self):
     font = TTFont()
     font.importXML(os.path.join(DATA_DIR, '_h_h_e_a_recalc_empty.ttx'))
     hhea = font['hhea']
     hhea.recalc(font)
     self.assertEqual(hhea.advanceWidthMax, 600)
     self.assertEqual(hhea.minLeftSideBearing, 0)
     self.assertEqual(hhea.minRightSideBearing, 0)
     self.assertEqual(hhea.xMaxExtent, 0)
Пример #25
0
def isTTX(pathOrFile):
    from fontTools.ttLib import TTFont
    try:
        font = TTFont()
        font.importXML(pathOrFile)
        del font
    except Exception:
        return False
    return True
Пример #26
0
def isTTX(pathOrFile):
    from fontTools.ttLib import TTFont
    try:
        font = TTFont()
        font.importXML(pathOrFile)
        del font
    except Exception:
        return False
    return True
Пример #27
0
 def test_recalc_empty(self):
     font = TTFont()
     font.importXML(os.path.join(DATA_DIR, '_v_h_e_a_recalc_empty.ttx'))
     vhea = font['vhea']
     vhea.recalc(font)
     self.assertEqual(vhea.advanceHeightMax, 900)
     self.assertEqual(vhea.minTopSideBearing, 0)
     self.assertEqual(vhea.minBottomSideBearing, 0)
     self.assertEqual(vhea.yMaxExtent, 0)
Пример #28
0
 def test_draw_vs_drawpoints(self):
     font = TTFont(sfntVersion="\x00\x01\x00\x00")
     font.importXML(GLYF_TTX)
     glyfTable = font['glyf']
     pen1 = RecordingPen()
     pen2 = RecordingPen()
     glyfTable["glyph00003"].draw(pen1, glyfTable)
     glyfTable["glyph00003"].drawPoints(PointToSegmentPen(pen2), glyfTable)
     self.assertEqual(pen1.value, pen2.value)
Пример #29
0
 def test_recalc_empty(self):
     font = TTFont()
     font.importXML(os.path.join(DATA_DIR, '_h_h_e_a_recalc_empty.ttx'))
     hhea = font['hhea']
     hhea.recalc(font)
     self.assertEqual(hhea.advanceWidthMax, 600)
     self.assertEqual(hhea.minLeftSideBearing, 0)
     self.assertEqual(hhea.minRightSideBearing, 0)
     self.assertEqual(hhea.xMaxExtent, 0)
Пример #30
0
def isTTX(pathOrFile):
    from fontTools.ttLib import TTFont, TTLibError
    try:
        font = TTFont()
        font.importXML(pathOrFile)
        del font
    except TTLibError:
        return False
    return True
Пример #31
0
 def test_compile_empty_table(self):
     font = TTFont(sfntVersion="\x00\x01\x00\x00")
     font.importXML(GLYF_TTX)
     glyfTable = font['glyf']
     # set all glyphs to zero contours
     glyfTable.glyphs = {glyphName: Glyph() for glyphName in font.getGlyphOrder()}
     glyfData = glyfTable.compile(font)
     self.assertEqual(glyfData, b"\x00")
     self.assertEqual(list(font["loca"]), [0] * (font["maxp"].numGlyphs+1))
Пример #32
0
def isTTX(pathOrFile):
    from fontTools.ttLib import TTFont, TTLibError
    try:
        font = TTFont()
        font.importXML(pathOrFile)
        del font
    except TTLibError:
        return False
    return True
Пример #33
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)
	ttf.save(output)

	if options.verbose:
		import time
		print("finished at", time.strftime("%H:%M:%S", time.localtime(time.time())))
Пример #34
0
def test_sfntVersionFromTTX():
    # https://github.com/fonttools/fonttools/issues/2370
    font = TTFont()
    assert font.sfntVersion == "\x00\x01\x00\x00"
    ttx = io.StringIO(ttxOTF)
    # Font is "empty", TTX file will determine sfntVersion
    font.importXML(ttx)
    assert font.sfntVersion == "OTTO"
    ttx = io.StringIO(ttxTTF)
    # Font is not "empty", sfntVersion in TTX file will be ignored
    font.importXML(ttx)
    assert font.sfntVersion == "OTTO"
Пример #35
0
    def test_FDSelect_format_4(self):
        ttx_path = self.getpath('TestFDSelect4.ttx')
        font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
        font.importXML(ttx_path)

        self.temp_dir()
        save_path = os.path.join(self.tempdir, 'TestOTF.otf')
        font.save(save_path)

        font2 = TTFont(save_path)
        topDict2 = font2["CFF2"].cff.topDictIndex[0]
        self.assertEqual(topDict2.FDSelect.format, 4)
        self.assertEqual(topDict2.FDSelect.gidArray, [0, 0, 1])
Пример #36
0
    def conv_otf(self):
        from fontTools.ttLib import TTFont, newTable

        info("creating squished font, pls wait")
        mul = 1.1
        font = TTFont(self.otf_src)
        baseAsc = font["OS/2"].sTypoAscender
        baseDesc = font["OS/2"].sTypoDescender
        font["hhea"].ascent = round(baseAsc * mul)
        font["hhea"].descent = round(baseDesc * mul)
        font["OS/2"].usWinAscent = round(baseAsc * mul)
        font["OS/2"].usWinDescent = round(baseDesc * mul) * -1

        xfn = "softchat.xml"
        font.saveXML(xfn, tables=["name"])
        with open(xfn, "r", encoding="utf-8") as f:
            xml = f.read()

        xml = xml.replace("Noto Sans", "Squished Noto Sans")
        xml = xml.replace("NotoSans", "SquishedNotoSans")
        with open(xfn, "w", encoding="utf-8") as f:
            f.write(xml)

        font["name"] = newTable("name")
        font.importXML(xfn)
        os.unlink(xfn)

        try:
            del font["post"].mapping["Delta#1"]
        except:
            pass

        for fp in self.otf_mod:
            try:
                fdir = fp.rsplit(os.sep, 1)[0]
                os.makedirs(fdir, exist_ok=True)
                with open(fp, "wb") as f:
                    f.write(b"h")

                os.unlink(fp)
                break
            except:
                fp = None

        if not fp:
            err = "could not write modified font to any of the following locations:"
            raise Exception("\n  ".join([err] + self.otf_mod))

        self.otf_mod = fp
        info(f"writing {self.otf_mod}")
        font.save(self.otf_mod)
Пример #37
0
    def test_recalc_timestamp_otf(self):
        ttxpath = self.getpath("TestOTF-Regular.ttx")
        font = TTFont()
        font.importXML(ttxpath)
        modified = font['head'].modified
        _, fontpath = self.compile_font(ttxpath, ".otf")
        subsetpath = self.temp_path(".otf")

        # by default, the subsetter does not recalculate the modified timestamp
        subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
        self.assertEqual(modified, TTFont(subsetpath)['head'].modified)

        subset.main([fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"])
        self.assertLess(modified, TTFont(subsetpath)['head'].modified)
Пример #38
0
 def test_CFF_deepcopy(self):
     """Test that deepcopying a TTFont with a CFF table does not recurse
     infinitely."""
     ttx_path = os.path.join(
         os.path.dirname(__file__),
         "..",
         "varLib",
         "data",
         "master_ttx_interpolatable_otf",
         "TestFamily2-Master0.ttx",
     )
     font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
     font.importXML(ttx_path)
     copy.deepcopy(font)
Пример #39
0
 def test_blend_programToCommands(self):
     ttx_path = self.getpath('TestCFF2Widths.ttx')
     ttf_font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
     ttf_font.importXML(ttx_path)
     fontGlyphList = ttf_font.getGlyphOrder()
     topDict = ttf_font['CFF2'].cff.topDictIndex[0]
     charstrings = topDict.CharStrings
     for glyphName in fontGlyphList:
         cs = charstrings[glyphName]
         cs.decompile()
         cmds = programToCommands(cs.program,
                                  getNumRegions=cs.getNumRegions)
         program = commandsToProgram(cmds)
         self.assertEqual(program, cs.program)
Пример #40
0
 def test_CFF_deepcopy(self):
     """Test that deepcopying a TTFont with a CFF table does not recurse
     infinitely."""
     ttx_path = os.path.join(
         os.path.dirname(__file__),
         "..",
         "varLib",
         "data",
         "master_ttx_interpolatable_otf",
         "TestFamily2-Master0.ttx",
     )
     font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
     font.importXML(ttx_path)
     copy.deepcopy(font)
Пример #41
0
    def test_recalc_timestamp_otf(self):
        ttxpath = self.getpath("TestOTF-Regular.ttx")
        font = TTFont()
        font.importXML(ttxpath)
        modified = font['head'].modified
        _, fontpath = self.compile_font(ttxpath, ".otf")
        subsetpath = self.temp_path(".otf")

        # by default, the subsetter does not recalculate the modified timestamp
        subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
        self.assertEqual(modified, TTFont(subsetpath)['head'].modified)

        subset.main([fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"])
        self.assertLess(modified, TTFont(subsetpath)['head'].modified)
Пример #42
0
def ttx2otf(ttx_path, otf_path=None):
    """Generate an ``.otf`` font from a ``.ttx`` file.

    :param str ttx_path: Path of the .ttx font source.
    :param str otf_path: Path of the target .otf font.

    """
    # make otf path
    if not otf_path:
        otf_path = '%s.otf' % os.path.splitext(ttx_path)[0]
    # save otf font
    tt = TTFont()
    tt.importXML(ttx_path)
    tt.save(otf_path)
Пример #43
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)
    ttf.save(output)

    if options.verbose:
        import time
        print("finished at",
              time.strftime("%H:%M:%S", time.localtime(time.time())))
Пример #44
0
def ttx2otf(ttx_path, otf_path=None):
    """Generate an .otf font from a .ttx file.

    ttx_path: Path of the .ttx font source.
    otf_path: Path of the target .otf font.

    """
    # make otf path
    if not otf_path:
        otf_path = '%s.otf' % os.path.splitext(ttx_path)[0]
    # save otf font
    with SuppressPrint():
        tt = TTFont()
        tt.verbose = False
        tt.importXML(ttx_path)
        tt.save(otf_path)
Пример #45
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)
	ttf.importXML(input)

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

	ttf.save(output)
Пример #46
0
def extractFontFromTTX(pathOrFile, destination, doGlyphs=True, doInfo=True, doKerning=True, customFunctions=[]):
    from fontTools.ttLib import TTFont, TTLibError
    source = TTFont()
    source.importXML(pathOrFile)
    if doInfo:
        extractOpenTypeInfo(source, destination)
    if doGlyphs:
        extractOpenTypeGlyphs(source, destination)
    if doKerning:
        kerning, groups = extractOpenTypeKerning(source, destination)
        destination.groups.update(groups)
        destination.kerning.clear()
        destination.kerning.update(kerning)
    for function in customFunctions:
        function(source, destination)
    source.close()
Пример #47
0
def ttx2otf(ttx_path, otf_path=None):
    """Generate an .otf font from a .ttx file.

    ttx_path: Path of the .ttx font source.
    otf_path: Path of the target .otf font.

    """
    # make otf path
    if not otf_path:
        otf_path = '%s.otf' % os.path.splitext(ttx_path)[0]
    # save otf font
    with SuppressPrint():
        tt = TTFont()
        tt.verbose = False
        tt.importXML(ttx_path)
        tt.save(otf_path)
Пример #48
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)
Пример #49
0
    def test_topDict_set_Encoding(self):
        ttx_path = self.getpath('TestOTF.ttx')
        font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
        font.importXML(ttx_path)

        topDict = font["CFF "].cff.topDictIndex[0]
        encoding = [".notdef"] * 256
        encoding[0x20] = "space"
        topDict.Encoding = encoding
        
        self.temp_dir()
        save_path = os.path.join(self.tempdir, 'TestOTF.otf')
        font.save(save_path)

        font2 = TTFont(save_path)
        topDict2 = font2["CFF "].cff.topDictIndex[0]
        self.assertEqual(topDict2.Encoding[32], "space")
Пример #50
0
    def test_recalc_max_context(self):
        ttxpath = self.getpath("Lobster.subset.ttx")
        font = TTFont()
        font.importXML(ttxpath)
        max_context = font['OS/2'].usMaxContext
        _, fontpath = self.compile_font(ttxpath, ".otf")
        subsetpath = self.temp_path(".otf")

        # by default, the subsetter does not recalculate the usMaxContext
        subset.main([fontpath, "--drop-tables+=GSUB,GPOS",
                               "--output-file=%s" % subsetpath])
        self.assertEqual(max_context, TTFont(subsetpath)['OS/2'].usMaxContext)

        subset.main([fontpath, "--recalc-max-context",
                               "--drop-tables+=GSUB,GPOS",
                               "--output-file=%s" % subsetpath])
        self.assertEqual(0, TTFont(subsetpath)['OS/2'].usMaxContext)
Пример #51
0
    def test_recalc_bounds_otf(self):
        ttxpath = self.getpath("TestOTF-Regular.ttx")
        font = TTFont()
        font.importXML(ttxpath)
        head = font['head']
        bounds = [head.xMin, head.yMin, head.xMax, head.yMax]

        _, fontpath = self.compile_font(ttxpath, ".otf")
        subsetpath = self.temp_path(".otf")

        # by default, the subsetter does not recalculate the bounding box
        subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
        head = TTFont(subsetpath)['head']
        self.assertEqual(bounds, [head.xMin, head.yMin, head.xMax, head.yMax])

        subset.main([fontpath, "--recalc-bounds", "--output-file=%s" % subsetpath, "*"])
        head = TTFont(subsetpath)['head']
        bounds = [132, 304, 365, 567]
        self.assertEqual(bounds, [head.xMin, head.yMin, head.xMax, head.yMax])
Пример #52
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())))
Пример #53
0
 def test_blend_round_trip(self):
     ttx_path = self.getpath('TestSparseCFF2VF.ttx')
     ttf_font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
     ttf_font.importXML(ttx_path)
     fontGlyphList = ttf_font.getGlyphOrder()
     topDict = ttf_font['CFF2'].cff.topDictIndex[0]
     charstrings = topDict.CharStrings
     for glyphName in fontGlyphList:
         cs = charstrings[glyphName]
         cs.decompile()
         cmds = programToCommands(cs.program, getNumRegions=cs.getNumRegions)
         cmds_g = generalizeCommands(cmds)
         cmds = specializeCommands(cmds_g, generalizeFirst=False)
         program = commandsToProgram(cmds)
         self.assertEqual(program, cs.program)
         program = specializeProgram(program, getNumRegions=cs.getNumRegions)
         self.assertEqual(program, cs.program)
         program_g = generalizeProgram(program, getNumRegions=cs.getNumRegions)
         program = commandsToProgram(cmds_g)
         self.assertEqual(program, program_g)
Пример #54
0
def _open_font(path, master_finder):
	# load TTFont masters from given 'path': this can be either a .TTX or an
	# OpenType binary font; or if neither of these, try use the 'master_finder'
	# callable to resolve the path to a valid .TTX or OpenType font binary.
	from fontTools.ttx import guessFileType

	master_path = os.path.normpath(path)
	tp = guessFileType(master_path)
	if tp is None:
		# not an OpenType binary/ttx, fall back to the master finder.
		master_path = master_finder(master_path)
		tp = guessFileType(master_path)
	if tp in ("TTX", "OTX"):
		font = TTFont()
		font.importXML(master_path)
	elif tp in ("TTF", "OTF", "WOFF", "WOFF2"):
		font = TTFont(master_path)
	else:
		raise VarLibError("Invalid master path: %r" % master_path)
	return font
Пример #55
0
 def compile_font(self, path, suffix):
     savepath = self.temp_path(suffix=suffix)
     font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
     font.importXML(path)
     font.save(savepath, reorderTables=None)
     return font, savepath
Пример #56
0
def process(jobs, options):
    for (input, origin) in jobs:
        tt = TTFont()
        tt.importXML(input, quiet=None)
        bc = BytecodeContainer(tt)

        if (options.allGlyphs):
            glyphs = filter(lambda x: x != 'fpgm' and x != 'prep', bc.tag_to_programs.keys())
        else:
            glyphs = map(lambda x: 'glyf.'+x, options.glyphs)

        if options.outputIR or options.reduceFunctions:
            ae, called_functions = analysis(bc, glyphs)

        if (options.outputPrep):
            print ("PREP:")
            if (options.outputIR):
                if 'prep' in bc.tag_to_programs:
                    bc.print_IR(bc.IRs['prep'])
                else:
                    print ("  <no prep>")
            else:
                bc.tag_to_programs['prep'].body.pretty_print()
            print ()
        if (options.outputFunctions):
            for key, value in bc.function_table.items():
                print ("Function #%d:" % (key))
                if (options.outputIR):
                    tag = "fpgm_%s" % key
                    if tag in bc.IRs:
                        bc.print_IR(bc.IRs[tag])
                    else:
                        print ("  <not executed, no IR>")
                else:
                    value.body.pretty_print()
                print ()
        if (options.outputGlyfPrograms):
            for glyph in glyphs:
                print ("%s:" % glyph)
                if (options.outputIR):
                    bc.print_IR(bc.IRs[glyph])
                else:
                    bc.tag_to_programs[glyph].body.pretty_print()
                print ()

        if (options.outputCallGraph):
            print ("called function set:")
            print (called_functions)
            print ("call graph (function, # calls to):")
            for item in ae.global_function_table.items():
                print (item)

        if (options.outputState):
            ae.environment.pretty_print()
        if (options.outputCVT):
            print("CVT = ", ae.environment.cvt)
        if (options.outputMaxStackDepth):
            print("Max Stack Depth =", ae.maximum_stack_depth)
        if (options.reduceFunctions):
            function_set = bc.function_table.keys()
            unused_functions = [item for item in function_set if item not in called_functions]
          
            bc.removeFunctions(unused_functions)
            bc.updateTTFont(tt)
            output = "Reduced"+origin
            if (options.outputXML):
                output = makeOutputFileName(output, ".ttx")
                tt.saveXML(output)
            else:
                output = makeOutputFileName(output, ".ttf")
                tt.save(output)
        if type(input) is file:
            input.close()
Пример #57
0
def makeLookup1():
    # make a variation of the shell TTX data
    f = open(shellSourcePath)
    ttxData = f.read()
    f.close()
    ttxData = ttxData.replace("__familyName__", "gsubtest-lookup1")
    tempShellSourcePath = shellSourcePath + ".temp"
    f = open(tempShellSourcePath, "wb")
    f.write(ttxData)
    f.close()
    
    # compile the shell
    shell = TTFont(sfntVersion="OTTO")
    shell.importXML(tempShellSourcePath)
    shell.save(shellTempPath)
    os.remove(tempShellSourcePath)
    
    # load the shell
    shell = TTFont(shellTempPath)
    
    # grab the PASS and FAIL data
    hmtx = shell["hmtx"]
    glyphSet = shell.getGlyphSet()
    
    failGlyph = glyphSet["F"]
    failGlyph.decompile()
    failGlyphProgram = list(failGlyph.program)
    failGlyphMetrics = hmtx["F"]
    
    passGlyph = glyphSet["P"]
    passGlyph.decompile()
    passGlyphProgram = list(passGlyph.program)
    passGlyphMetrics = hmtx["P"]
    
    # grab some tables
    hmtx = shell["hmtx"]
    cmap = shell["cmap"]
    
    # start the glyph order
    existingGlyphs = [".notdef", "space", "F", "P"]
    glyphOrder = list(existingGlyphs)
    
    # start the CFF
    cff = shell["CFF "].cff
    globalSubrs = cff.GlobalSubrs
    topDict = cff.topDictIndex[0]
    topDict.charset = existingGlyphs
    private = topDict.Private
    charStrings = topDict.CharStrings
    charStringsIndex = charStrings.charStringsIndex
    
    features = sorted(mapping)

    # build the outline, hmtx and cmap data
    cp = baseCodepoint
    for index, tag in enumerate(features):
    
    	# tag.pass
    	glyphName = "{0!s}.pass".format(tag)
    	glyphOrder.append(glyphName)
    	addGlyphToCFF(
    		glyphName=glyphName,
    		program=passGlyphProgram,
    		private=private,
    		globalSubrs=globalSubrs,
    		charStringsIndex=charStringsIndex,
    		topDict=topDict,
            charStrings=charStrings
    	)
    	hmtx[glyphName] = passGlyphMetrics
     
    	for table in cmap.tables:
    		if table.format == 4:
    			table.cmap[cp] = glyphName
    		else:
    			raise NotImplementedError, "Unsupported cmap table format: {0:d}".format(table.format)
    	cp += 1
    
    	# tag.fail
    	glyphName = "{0!s}.fail".format(tag)
    	glyphOrder.append(glyphName)
    	addGlyphToCFF(
    		glyphName=glyphName,
    		program=failGlyphProgram,
    		private=private,
    		globalSubrs=globalSubrs,
    		charStringsIndex=charStringsIndex,
    		topDict=topDict,
            charStrings=charStrings
    	)
    	hmtx[glyphName] = failGlyphMetrics
     
    	for table in cmap.tables:
    		if table.format == 4:
    			table.cmap[cp] = glyphName
    		else:
    			raise NotImplementedError, "Unsupported cmap table format: {0:d}".format(table.format)

        # bump this up so that the sequence is the same as the lookup 3 font
    	cp += 3

    # set the glyph order
    shell.setGlyphOrder(glyphOrder)
    
    # start the GSUB
    shell["GSUB"] = newTable("GSUB")
    gsub = shell["GSUB"].table = GSUB()
    gsub.Version = 1.0
    
    # make a list of all the features we will make
    featureCount = len(features)
    
    # set up the script list
    scriptList = gsub.ScriptList = ScriptList()
    scriptList.ScriptCount = 1
    scriptList.ScriptRecord = []
    scriptRecord = ScriptRecord()
    scriptList.ScriptRecord.append(scriptRecord)
    scriptRecord.ScriptTag = "DFLT"
    script = scriptRecord.Script = Script()
    defaultLangSys = script.DefaultLangSys = DefaultLangSys()
    defaultLangSys.FeatureCount = featureCount
    defaultLangSys.FeatureIndex = range(defaultLangSys.FeatureCount)
    defaultLangSys.ReqFeatureIndex = 65535
    defaultLangSys.LookupOrder = None
    script.LangSysCount = 0
    script.LangSysRecord = []
    
    # set up the feature list
    featureList = gsub.FeatureList = FeatureList()
    featureList.FeatureCount = featureCount
    featureList.FeatureRecord = []
    for index, tag in enumerate(features):
        # feature record
        featureRecord = FeatureRecord()
        featureRecord.FeatureTag = tag
        feature = featureRecord.Feature = Feature()
        featureList.FeatureRecord.append(featureRecord)
        # feature
        feature.FeatureParams = None
        feature.LookupCount = 1
        feature.LookupListIndex = [index]
    
    # write the lookups
    lookupList = gsub.LookupList = LookupList()
    lookupList.LookupCount = featureCount
    lookupList.Lookup = []
    for tag in features:
        # lookup
        lookup = Lookup()
        lookup.LookupType = 1
        lookup.LookupFlag = 0
        lookup.SubTableCount = 1
        lookup.SubTable = []
        lookupList.Lookup.append(lookup)
        # subtable
        subtable = SingleSubst()
        subtable.Format = 2
        subtable.LookupType = 1
        subtable.mapping = {
            "{0!s}.pass".format(tag) : "{0!s}.fail".format(tag),
            "{0!s}.fail".format(tag) : "{0!s}.pass".format(tag),
        }
        lookup.SubTable.append(subtable)
    
    path = outputPath % 1 + ".otf"
    if os.path.exists(path):
    	os.remove(path)
    shell.save(path)
    
    # get rid of the shell
    if os.path.exists(shellTempPath):
        os.remove(shellTempPath)
Пример #58
0
 def test_fromXML(self):
     font = TTFont(sfntVersion='OTTO')
     font.importXML(CFF_TTX)
     cffTable = font['CFF ']
     cffData = cffTable.compile(font)
     self.assertEqual(cffData, self.cffData)
Пример #59
0
 def setUp(self):
     # TODO: Need somebody to check this options
     font = TTFont(None, lazy=False, recalcBBoxes=True,
                   verbose=False, allowVID=False)
     font.importXML(self.path, quiet=True)
     self.font = font