def ttFont(font): from fontTools.ttLib import TTFont return TTFont(font)
from fontTools.ttLib import TTFont font = TTFont(r'iconfont_9eb9a50.woff') font.saveXML('font.xml')
def check_ttx_dump(self, font, expected_ttx, tables, suffix): """Ensure the TTX dump is the same after saving and reloading the font.""" path = self.temp_path(suffix=suffix) font.save(path) self.expect_ttx(TTFont(path), expected_ttx, tables)
def proc_font(soup, selector): titles = soup.select(selector) wotfs = soup.select('head > style') wotflist = str(wotfs[0]).split('\n') maoyanwotf = wotflist[5].replace(' ', '').replace('url(\'//', '').replace( 'format(\'woff\');', '').replace('\')', '') r = requests.get('http://' + maoyanwotf) with open("demo.woff", "wb") as code: code.write(r.content) font = TTFont("demo.woff") font.saveXML('to.xml') # 加载字体模板 num = [8, 6, 2, 1, 4, 3, 0, 9, 5, 7] data = [] new_font = [] xmlfilepath_temp = os.path.abspath("temp.xml") domobj_temp = xmldom.parse(xmlfilepath_temp) elementobj_temp = domobj_temp.documentElement subElementObj = elementobj_temp.getElementsByTagName("TTGlyph") for i in range(len(subElementObj)): rereobj = re.compile(r"name=\"(.*)\"") find_list = rereobj.findall(str(subElementObj[i].toprettyxml())) data.append( str(subElementObj[i].toprettyxml()).replace(find_list[0], '').replace("\n", '')) # 根据字体模板解码本次请求下载的字体 xmlfilepath_find = os.path.abspath("to.xml") domobj_find = xmldom.parse(xmlfilepath_find) elementobj_find = domobj_find.documentElement tunicode = elementobj_find.getElementsByTagName("TTGlyph") for i in range(len(tunicode)): th = tunicode[i].toprettyxml() report = re.compile(r"name=\"(.*)\"") find_this = report.findall(th) get_code = th.replace(find_this[0], '').replace("\n", '') for j in range(len(data)): if operator.eq(get_code, data[j]): new_font.append(num[j]) font = TTFont("demo.woff") font_list = font.getGlyphNames() font_list.remove('glyph00000') font_list.remove('x') # 匹配 star_woff = re.findall(re.compile(r">(.*)<"), str(titles[0]))[0].split(';') k = 0 # 用于记录小数点的位置,匹配的时候需要把小数点去掉 data = '' # 用于保存数字,因为原本函数只能一个字一个字输出,我将其变成字符串拼接起来了 for i in star_woff: k = k + 1 getthis = i.upper() for j in range(len(font_list)): if operator.eq(getthis.replace(".", ""), font_list[j].replace("uni", "")): data = data + str(new_font[j]) if operator.eq( k, ((re.findall(re.compile(r">(.*)<"), str(titles[0]))[0].find('.')) / 5)): data = data + '.' return data
# 获取字体坐标 # get font axis def getAxis(font): uni_list = font.getGlyphOrder()[2:] font_axis = [] for uni in uni_list: axis = [] for i in font['glyf'][uni].coordinates: axis.append(i) font_axis.append(axis) return font_axis # 获取对比字体文件 base_font = TTFont('font\\maoyan.woff') uni_base_list = base_font.getGlyphOrder()[2:] base_axis = getAxis(base_font) base_font = None # 使用该函数获取当前页面动态字体 # get current font by use this function def getFont(response): font_url = 'http:' + re.search(r"url\('(.*\.woff)'\)", response).group(1) print('download:\t' + font_url) font_file = requests.get(font_url).content writeFont(font_file) return parseFont()
async def fontTest(letter): test = TTFont("./temp/Roboto-Medium.ttf") for table in test["cmap"].tables: if ord(letter) in table.cmap.keys(): return True
BIG_TEXT_SIDE_MARGIN = MARGIN * 2 BIG_TEXT_BOTTOM_MARGIN = MARGIN * 4.5 GRID_VIEW = False # Change this to "True" for a grid overlay # Handel the "--output" flag # For example: $ python3 documentation/image1.py --output documentation/image1.png parser = argparse.ArgumentParser() parser.add_argument("--output", metavar="PNG", help="where to write the PNG file") args = parser.parse_args() # Load the font with the parts of fonttools that are imported with the line: # from fontTools.ttLib import TTFont # Docs Link: https://fonttools.readthedocs.io/en/latest/ttLib/ttFont.html ttFont = TTFont(FONT_PATH) # Constants that are worked out dynamically MY_URL = subprocess.check_output("git remote get-url origin", shell=True).decode() MY_HASH = subprocess.check_output("git rev-parse --short HEAD", shell=True).decode() FONT_NAME = ttFont["name"].getDebugName(4) FONT_VERSION = "v%s" % floatToFixedToStr(ttFont["head"].fontRevision, 16) # Draws a grid def grid(): stroke(1, 0, 0, 0.75) strokeWidth(2) STEP_X, STEP_Y = 0, 0
import sys from fontTools.ttLib import TTFont filename = sys.argv[1] ttFont = TTFont(filename) modified = [] for glyphname in ttFont['glyf'].keys(): try: asm = ttFont['TSI1'].glyphPrograms[glyphname] if "OFFSET" in asm: asm = "USEMYMETRICS[]\r" + '\r'.join( [line for line in asm.split('\r') if 'OFFSET' in line]) ttFont['TSI1'].glyphPrograms[glyphname] = asm modified.append(glyphname) else: print(f"Skip '{glyphname}'") except: print(f"No program for '{glyphname}'") ttFont.save(filename.split('.ttf')[0] + "-alt.ttf") print(f"These glyphs were modified by the script:\n{', '.join(modified)}")
#!/usr/bin/env python # -*- coding: utf-8 -*- from fontTools.ttLib import TTFont # font = TTFont(r'E:/201809291213-tyc-num.woff') font = TTFont(r'E:/201809291213-tyc-num.otf') print font.tables font['cmap'].tables[0].ttFont.getGlyphOrder() font['name'].names
from fontTools.ttLib.ttFont import newTable from fontmake import __main__ from fontTools.ttLib import TTFont, newTable import shutil, subprocess, glob from pathlib import Path print("[Rampart] Generating TTFs") __main__.main(( "-g", "sources/RampartOne.glyphs", "-o", "ttf", )) for font in Path("master_ttf").glob("*.ttf"): modifiedFont = TTFont(font) print("[" + str(font).split("/")[1][:-4] + "] Adding stub DSIG") modifiedFont["DSIG"] = newTable("DSIG") #need that stub dsig modifiedFont["DSIG"].ulVersion = 1 modifiedFont["DSIG"].usFlag = 0 modifiedFont["DSIG"].usNumSigs = 0 modifiedFont["DSIG"].signatureRecords = [] print("[" + str(font).split("/")[1][:-4] + "] Making other changes") modifiedFont["name"].addMultilingualName({'ja': 'ランパート One'}, modifiedFont, nameID=1, windows=True, mac=False) modifiedFont["name"].addMultilingualName({'ja': 'Regular'}, modifiedFont,
" (The file format will be PNG, regardless of the image file name supplied)" ) sys.exit(0) from fontTools.ttLib import TTFont from reportlab.lib import colors from reportlab.graphics.shapes import Path path = sys.argv[1] glyphName = sys.argv[2] if (len(sys.argv) > 3): imageFile = sys.argv[3] else: imageFile = "%s.png" % glyphName font = TTFont( path) # it would work just as well with fontTools.t1Lib.T1Font gs = font.getGlyphSet() pen = ReportLabPen(gs, Path(fillColor=colors.red, strokeWidth=5)) g = gs[glyphName] g.draw(pen) w, h = g.width, 1000 from reportlab.graphics import renderPM from reportlab.graphics.shapes import Group, Drawing, scale # Everything is wrapped in a group to allow transformations. g = Group(pen.path) g.translate(0, 200) g.scale(0.3, 0.3) d = Drawing(w, h)
import base64 import pytesseract from PIL import Image, ImageDraw, ImageFont base64_str = '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' with open('font.woff', 'wb') as f: bin_data = base64.decodebytes(base64_str.encode()) f.write(bin_data) from fontTools.ttLib import TTFont font = TTFont('font.woff') # font.save('test.xml') # print(font.keys()) text = '餼鑶麣麣' im = Image.new("RGB", (300, 50), (255, 255, 255)) dr = ImageDraw.Draw(im) font = ImageFont.truetype('font.woff', 18) dr.text((10, 5), text, font=font, fill='#000000') # im.show() im.save('t.png') image = Image.open('t.png') text = pytesseract.image_to_string(image) print(text)
def compileTTXToPath(ttxPath, ttPath): font = TTFont() font.importXML(ttxPath) font.save(ttPath, reorderTables=False)
def superfamily_ttFonts(superfamily): from fontTools.ttLib import TTFont result = [] for family in superfamily: result.append([TTFont(f) for f in family]) return result
def cli(fonts, support, autonyms, users, output, mode, include_historical, include_constructed, strict_support, strict_iso, verbose, version): """ Pass in one or more fonts to check their languages support """ if version: import sys sys.exit("Fontlang version: %s" % __version__) logging.getLogger().setLevel(logging.DEBUG if verbose else logging.WARNING) if fonts == (): print("Provide at least one path to a font or --help for more " "information") # A dict with each file and its results for done and weak, e.g. # { 'filea.otf': { 'done': {..}, 'weak': {..} }, 'fileb.otf: .. } results = {} for font in fonts: _font = TTFont(font, lazy=True) cmap = _font["cmap"] chars = [chr(c) for c in cmap.getBestCmap().keys()] Lang = Languages(strict_iso) langs = Lang.get_support_from_chars(chars, include_historical, include_constructed) done = {} weak = {} done_statuses = ["done", "strong"] # plus "status" not in dict level = SUPPORTLEVELS[support] # Sort the results for this font by db status for script in langs: if script not in done: done[script] = {} if script not in weak: weak[script] = {} if level not in langs[script]: continue for iso, l in langs[script][level].items(): if "todo_status" not in l or l["todo_status"] in done_statuses: done[script][iso] = l else: weak[script][iso] = l results[font] = {} if strict_support: if done: results[font]["done"] = done if weak: results[font]["weak"] = weak else: merged = {} if done: merged = done if weak: if merged == {}: merged = weak else: for script, data in weak.items(): if script in merged: merged[script].update(weak[script]) else: merged[script] = weak[script] results[font]["done"] = merged _font.close() # Mode for comparison of several files if mode == "individual": for font in fonts: title = "%s has %s support for:" % (os.path.basename(font), level.lower()) print_to_cli(results[font], title, autonyms, users, script, strict_iso) data = results elif mode == "union": union = {} for font in fonts: res = results[font] if "done" in res: if "done" not in union: union["done"] = {} for iso, lang in res["done"].items(): if iso not in union["done"]: union["done"][iso] = lang if "weak" in res: if "weak" not in union: union["weak"] = {} for iso, lang in res["weak"].items(): if iso not in union["weak"]: union["weak"][iso] = lang title = "Fonts %s together have %s support for:" % \ (", ".join([os.path.basename(f) for f in fonts]), level.lower()) print_to_cli(union, title, autonyms, users, script, strict_iso) # Wrap in "single file" 'union' top level, which will be removed when # writing the data data = {"union": union} elif mode == "intersection": print("intersection") intersection = results[fonts[0]] for font in fonts[1:]: res = results[font] intersection = prune_intersect(intersection, res, "done") intersection = prune_intersect(intersection, res, "weak") title = "Fonts %s all have common %s support for:" % \ (", ".join([os.path.basename(f) for f in fonts]), level.lower()) print_to_cli(intersection, title, autonyms, users, script, strict_iso) # Wrap in "single file" 'intersection' top level, which will be removed # when writing the data data = {"intersection": intersection} if output: write_yaml(output, data)
def test_decompile_toXML_lazy(self): mvar = newTable('MVAR') font = TTFont(lazy=True) mvar.decompile(MVAR_DATA, font) self.assertEqual(getXML(mvar.toXML), MVAR_XML)
def getXml(item): font = TTFont(item) font.saveXML('50819d54.xml')
async def fontTest(letter): test = TTFont("resources/Roboto-Medium.ttf") for table in test['cmap'].tables: if ord(letter) in table.cmap.keys(): return True
def test_setupTable_gasp(self): compiler = OutlineTTFCompiler(self.ufo) compiler.otf = TTFont() compiler.setupTable_gasp() self.assertTrue('gasp' in compiler.otf) self.assertEqual(compiler.otf['gasp'].gaspRange, {7: 10, 65535: 15})
#! /usr/bin/env python from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * from fontTools.ttLib import TTFont import sys if len(sys.argv) < 2: print("usage: subset-fpgm.py fontfile.ttf func-number...") sys.exit(1) fontfile = sys.argv[1] func_nums = [int(x) for x in sys.argv[2:]] font = TTFont(fontfile) fpgm = font['fpgm'] # Parse fpgm asm = fpgm.program.getAssembly() funcs = {} stack = [] tokens = iter(asm) for token in tokens: if token.startswith("PUSH") or token.startswith("NPUSH"): for token in tokens: try: num = int(token) stack.append(num) except ValueError: break if token.startswith("FDEF"): num = stack.pop()
# -*- coding: utf-8 -*- # @Time : 2019/7/24 12:03 import re import json import time import os import requests from lxml import etree from fontTools.ttLib import TTFont # 从本地读取字体文件 ttfond = TTFont("./SDK/iconfont_9eb9a50.woff") def get_cmap_dict(): """ :return: 关系映射表 """ # 从本地读取关系映射表【从网站下载的woff字体文件】 best_cmap = ttfond["cmap"].getBestCmap() # 循环关系映射表将数字替换成16进制 best_cmap_dict = {} for key, value in best_cmap.items(): best_cmap_dict[hex(key)] = value return best_cmap_dict # 'num_1', '0xe604': 'num_2', '0xe605': 'num_3' def get_num_cmap(): """ :return: 返回num和真正的数字映射关系 """ num_map = {
def update_attribs(font, **kwargs): for table in font.keys(): for k in kwargs: if hasattr(font[table], k): print(f"Setting {k} to {kwargs[k]}") setattr(font[table], k, kwargs[k]) def update_names(font, **kwargs): nametable = font["name"] for k in kwargs: print(f"Setting {k} to {kwargs[k]}") nametable.setName(kwargs[k], *tuple(map(int, k.split(",")))) for name_id in range(256, 308): font['name'].removeNames(name_id) vf = TTFont(sys.argv[1]) out_dir = mkdir(sys.argv[2]) for inst in instances: print(f"Making {inst['filename']}") instance = instantiateVariableFont(vf, inst["axes"]) update_attribs(instance, **inst["attribs"]) update_names(instance, **inst["names"]) del instance['STAT'] out_path = os.path.join(sys.argv[2], inst["filename"]) instance.save(out_path)
os.path.relpath( x, start=(os.path.dirname(opts.output) if opts.output else '.')) for x in opts.infonts ] fonts = [] tts = [] for i in range(len(opts.infonts)): while len(opts.engine) <= i: opts.engine.append(opts.engine[-1]) while len(opts.script) <= i: opts.script.append(opts.script[-1]) fonts.append( make_shaper(opts.engine[i], opts.infonts[i], 0, opts.rtl, feats, opts.script[i], opts.lang)) tts.append(TTFont(opts.infonts[i].encode('utf_8'))) reader = texttypes[opts.texttype](opts.text, spliton) count = 0 errors = 0 log = None for label, words, lang, feats in reader: if words[0] is None: continue count += 1 wcount = 0 for s in words: wcount += 1 if opts.verbose: sys.stdout.write("{}\r".format(wcount)) sys.stdout.flush() gls = [[
#!/usr/bin/env python from fontTools.ttLib import TTFont from fontTools.unicode import Unicode from fontTools.ttLib.tables._c_m_a_p import CmapSubtable font = TTFont("blizzard_global.ttf") cmap = font['cmap'] glyf = font["glyf"] t = cmap.getcmap(3, 1).cmap s = font.getGlyphSet() units_per_em = font['head'].unitsPerEm def generate(text): spaces = { 1: " ", 2: " ", 71: " ", 128: " ", 142: " ", 171: " ", 223: "", 256: " ", 284: " ", 426: " ", 461: "ㅤ", 512: " ", }
def opentype(infont, outdir, type, feature, version): font = fontforge.open(infont) if args.type == 'otf': outfont = infont.replace(".sfd", ".otf") flags = ("opentype", "round", "omit-instructions", "dummy-dsig") else: outfont = infont.replace(".sfd", ".ttf") flags = ("opentype", "round", "omit-instructions", "dummy-dsig") outfont = os.path.join(outdir, outfont) print("Generating %s => %s" % (infont, outfont)) tmpfont = mkstemp(suffix=os.path.basename(outfont))[1] # Remove all GSUB lookups for lookup in font.gsub_lookups: font.removeLookup(lookup) # Remove all GPOS lookups for lookup in font.gpos_lookups: font.removeLookup(lookup) # Merge the new featurefile font.mergeFeature(feature) font.version = version font.appendSFNTName('English (US)', 'Version', 'Version ' + version + '.0+' + time.strftime('%Y%m%d')) font.selection.all() font.correctReferences() font.simplify() font.selection.none() # fix some common font issues validateGlyphs(font) font.generate(tmpfont, flags=flags) font.close() # now open in fontTools font = TTFont(tmpfont, recalcBBoxes=0) # our 'name' table is a bit bulky, and of almost no use in for web fonts, # so we strip all unnecessary entries. name = font['name'] names = [] for record in name.names: platID = record.platformID langID = record.langID nameID = record.nameID # we keep only en_US entries in Windows and Mac platform id, every # thing else is dropped if (platID == 1 and langID == 0) or (platID == 3 and langID == 1033): if nameID == 13: # the full OFL text is too much, replace it with a simple # string if platID == 3: # MS strings are UTF-16 encoded text = 'OFL v1.1'.encode('utf_16_be') else: text = 'OFL v1.1' record.string = text names.append(record) # keep every thing else except Descriptor, Sample Text elif nameID not in (10, 19): names.append(record) name.names = names font['OS/2'].version = 4 # https://www.microsoft.com/typography/otspec/os2.htm#fst font['OS/2'].fsType = 0 if args.type == 'ttf': fixGasp(font) fixXAvgCharWidth(font) # FFTM is FontForge specific, remove it del (font['FFTM']) # force compiling GPOS/GSUB tables by fontTools, saves few tens of KBs # for tag in ('GPOS', 'GSUB'): # font[tag].compile(font) font.save(outfont) font.close() os.remove(tmpfont)
from itertools import chain import sys from fontTools.ttLib import TTFont from fontTools.unicode import Unicode font = TTFont(sys.argv[1]) for cmap in font['cmap'].tables: if cmap.isUnicode(): if ord('的') in cmap.cmap: print('Exist') print('end')
from parsel import Selector a = '𘞩𘞭𘞩𘞨𘞧𘞮' from fontTools.ttLib import TTFont font_type = "hLHpMjjJ" font_url = "https://qidian.gtimg.com/qd_anti_spider/%s.woff" % font_type woff = requests.get(font_url).content with open('fonts.woff', 'wb') as f: f.write(woff) online_fonts = TTFont('fonts.woff') online_fonts.saveXML("text.xml") _dict = online_fonts.getBestCmap() print("字典:", _dict) _dic = { "six": "6", "three": "3", "period": ".", "eight": "8", "zero": "0", "five": "5", "nine": "9",
ttf.close() print("token: " + str(token)) print("Eq string: " + eqstr) glyph2code = {} code2sym = {} code2sym[32] = ' ' print("analyzing ttf file: " + ttffile) cmd = 'rm -rf ttx_out && mkdir ttx_out && ttx -t glyf -g -d ttx_out ' + ttffile print("running system command: " + cmd) os.system(cmd) font = TTFont(ttffile) #print(font['cmap'].tables) codeTable = None # get mapping from cmap_format_0, but all of them should be fine I guess for table in font['cmap'].tables: if (table.format == 0): codeTable = table print(table) for code in table.cmap: print("code: 0x{0:x} ({1}) - {2}".format(code, chr(code), table.cmap[code])) glyph2code[table.cmap[code]] = code for glyph in font['glyf'].glyphs:
def direction_run(args: argparse.Namespace) -> None: """ Displays the direction of the outermost contour(s) of one or more glyphs in a font. Results are expressed as either "clockwise" or "counter-clockwise". The report includes the x, y scaling factors for transfomed components of composite glyphs. This scaling *may* reverse the path direction that is reported for the decomposed outline. """ fontpath: str = args.fontpath glyphname: str = args.glyphname # -------------------- # CLI arg validations # -------------------- validate_fontpath(fontpath) tt = TTFont(fontpath) skia_path: pathops.Path if glyphname: validate_glyph_in_font(glyphname, tt) skia_path = ttfont_glyph_to_skia_path(glyphname, tt) # transformed components can change path direction # in the decomposed paths # (e.g. 180 degree Y-axis rotation = mirroring) # add base component glyph name and transform values # to the report if this is present glyph = tt["glyf"][glyphname] components_with_transforms: Sequence[Tuple] = [] if glyph.isComposite(): components_with_transforms = _get_components_with_transforms(glyph) print( direction_result( glyphname, skia_path.clockwise, len(list(skia_path.contours)), components_with_transforms=components_with_transforms, nocolor=args.nocolor, )) else: glyph_names = tt.getGlyphOrder() for local_glyphname in glyph_names: glyph = tt["glyf"][local_glyphname] components_with_transforms = [] # transformed components can change path direction # in the decomposed paths # (e.g. 180 degree Y-axis rotation = mirroring) # add base component glyph name and transform values # to the report if this is present if glyph.isComposite(): components_with_transforms = _get_components_with_transforms( glyph) skia_path = ttfont_glyph_to_skia_path(local_glyphname, tt) # type: ignore print( direction_result( str(local_glyphname), skia_path.clockwise, len(list(skia_path.contours)), components_with_transforms=components_with_transforms, nocolor=args.nocolor, ))
def defont(font): f = TTFont(font) gs = f.getGlyphSet() keys = list(gs.keys()) keys.sort() coorset = {} for key in keys: # For each glyph, pull out a flattened, sorted representation of the glyph's component(s) gly = gs[key] raw_glyph = gly._glyph coords = flatten_coords(raw_glyph) # Using that base representation of the glyph, stick it into # a list coorset.setdefault(tuple(coords), []).append((key, gly)) # Now we have to extract the map of # unicode codepoints to the internal font symbol names. unicode_plat = None for table in f['cmap'].tables: # Platform ID 0 is "Unicode", whatever that means. # there's also a 'platEncID' parameter, but I haven't been able # to figure out what it refers to at all. if table.platformID == 0: unicode_plat = table # Since the map is codepoint->name, we flip it. inverse_map = {value: key for key, value in unicode_plat.cmap.items()} # Filter the codepoint lists. # Note that I'm not sure how to handle duplicate items that # have no entry in the mapping table. I'm just ignoring items for which # that is true at the moment. # It seems to work. items = [] for key, value in coorset.items(): if len(value) > 1: syms = [item[0] for item in value] cps = [inverse_map[key] for key in syms if key in inverse_map] # We have to sort the codepoints, because we want to convert down to the simpler entries. # A-Za-z is within the ascii table, so we are converting from high codepoints (> 1000) to # the ascii entries. Going the other way is how you /add/ the replacement cipher. cps.sort() # Filtering. if len(cps) < 2: continue items.append((cps, syms)) items.sort() convmap = {} for codepoints, symbols in items: convs = " <- ".join([chr(cp) for cp in codepoints]) for cp in codepoints[1:]: convmap[chr(cp)] = chr(codepoints[0]) return convmap