def run(self, destDir, progress): paths = self.controller.get(["ufo"]) report = Report() tempDir = os.path.join(destDir, "temp") if not os.path.exists(tempDir): os.makedirs(tempDir) tempExportPaths = self._generateCallback(tempDir, progress, report) progress.update("Merging Tables...") report.writeTitle("Merged Fonts:") report.newLine() tableNames = [item["tableName"] for item in self.tableList if item["add"]] for fontIndex, path in enumerate(paths): font = RFont(path, document=False, showInterface=False) binarySourcepath = font.lib.get("com.typemytype.robofont.binarySource") tempExportPath = tempExportPaths[fontIndex] if binarySourcepath: binaryIs Type = os.path.splitext(binarySourcepath)[1].lower() in [".ttf", ".otf"] tempIsOpenType = os.path.splitext(tempExportPath)[1].lower() in [".ttf", ".otf"] if binaryIsOpenType and tempIsOpenType: if os.path.exists(binarySourcepath) and os.path.exists(tempExportPath): binarySource = TTFont(binarySourcepath) tempFont = TTFont(tempExportPath) fileName = os.path.basename(tempExportPath) if not self.controller.keepFileNames(): fileName = "%s-%s%s" % (font.info.familyName, font.info.styleName, os.path.splitext(tempExportPath)[1]) path = os.path.join(destDir, fileName) report.writeTitle(os.path.basename(path), "'") report.write("source: %s" % tempExportPath) report.write("binary source: %s" % binarySourcepath) report.newLine() report.indent() for table in tableNames: if table in binarySource: report.write("merge %s table" % table) tempFont[table] = binarySource[table] report.write("save to %s" % path) tempFont.save(path) report.dedent() report.newLine() tempFont.close() binarySource.close() if not font.hasInterface(): font.close() reportPath = os.path.join(destDir, "Binary Merge Report.txt") report.save(reportPath) if not getDefault("Batch.Debug", False): if os.path.exists(tempDir): shutil.rmtree(tempDir)
def update_tables(font_path, revision): font = TTFont(font_path) font['head'].fontRevision = float(revision) if 'CFF ' in font: cff = font['CFF '].cff cff_font = cff[cff.fontNames[0]] top_dict = cff_font.rawDict top_dict['version'] = revision top_dict['FullName'] = FULL_NAME top_dict['FamilyName'] = FAMILY_NAME cff.fontNames = [PS_NAME] VERSION_STRING = 'Version {};{}'.format(revision, VENDOR) UNIQUE_ID = '{};{};{}'.format(revision, VENDOR, PS_NAME) name_strings = { 1: FAMILY_NAME, 3: UNIQUE_ID, 4: FULL_NAME, 5: VERSION_STRING, 6: PS_NAME, } name_table = font['name'] for nameID, string in name_strings.items(): name_table.setName(string, nameID, 3, 1, 0x409) # Windows only font.save(font_path) font.close() log.info('Updated font tables.')
def main(): infile = sys.argv[1] outfile = sys.argv[2] jsonSources = sys.argv[3:] font = TTFont(infile) i = 0 while i + 1 < len(jsonSources): sourcetype = jsonSources[i] sourcedata = jsonSources[i + 1] if sourcetype == '-r': # raw, the sourcedata is the json data = json.loads(sourcedata) elif sourcetype == '-f': # file, the sourcedata is a json file name with open(sourcedata) as f: data = json.load(f) else: raise ValueError( 'unknown json source type "{0}"'.format(sourcetype)) writeData(font, data) i += 2 clean(font) font.save(outfile) font.close()
def fix_naming(font_path): font = TTFont(font_path) italic = True if not "ITALIC" in font_path.upper(): italic = False family_name = "Fraunces" if not italic: style_name = "Roman" else: style_name = "Italic" name_dict = { 1: family_name, 4: family_name, 6: f"{family_name}-{style_name}", 16: family_name, 17: style_name } if italic: name_dict[2] = style_name name_dict[4] = f"{family_name} {style_name}" for name_id, name_string in name_dict.items(): font["name"].setName(name_string, name_id, 3, 1, 0x409) #get current ID3, rsplit on ; add id6 old_name = font["name"].getName(3, 3, 1, 0x409).toUnicode() new_name = f'{old_name.rsplit(";",1)[0]};{name_dict[6]}' font["name"].setName(new_name, 3, 3, 1, 0x409) font.save(font_path) font.close() print("Fixed NameIDs")
def installFont(self, path): """ Install a font with a given path. """ success, error = self._dummyContext.installFont(path) self._installedFontPaths.add(path) self._addInstruction("installFont", path) from fontTools.ttLib import TTFont, TTLibError try: font = TTFont(path) psName = font["name"].getName(6, 1, 0) if psName is None: psName = font["name"].getName(6, 3, 1) font.close() except IOError: raise DrawBotError("Font '%s' does not exist." % path) except TTLibError: raise DrawBotError("Font '%s' is not a valid font." % path) if psName is not None: psName = psName.toUnicode() if not success: warnings.warn("install font: %s" % error) return psName
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()
def cleanTTF(ttfFile, outfile): # now open in fontTools ftfont = TTFont(ttfFile) # the ttf contains NAME table IDs with platformID="1", these should be removed name = ftfont['name'] names = [] for record in name.names: if record.platformID == 1: continue names.append(record) name.names = names # remove non-standard 'FFTM' the FontForge time stamp table del ftfont['FFTM'] # issue #40 let Adobe InDesign show the font in the Arabic section of the font menu. # This essentially says the only codepage that "is considered functional" is Arabic. # https://www.microsoft.com/typography/otspec/os2.htm#cpr ftfont['OS/2'].ulCodePageRange1 = 64 ftfont['OS/2'].ulCodePageRange2 = 0 # 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()
def extractFontFromOpenType( pathOrFile, destination, doGlyphOrder=True, doGlyphs=True, doInfo=True, doKerning=True, customFunctions=[], doInstructions=True, ): source = TTFont(pathOrFile) if doInfo: extractOpenTypeInfo(source, destination) if doGlyphs: extractOpenTypeGlyphs(source, destination) if doGlyphOrder: extractGlyphOrder(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) if doInstructions: extractInstructions(source, destination) source.close()
def font_import(filename, font_id=-1, lang="en"): #language localization if lang == "zhs": #simplified chinese message_title = "进度" message_text = "已加载字体文件:" elif lang == "zht": #traditional chinese message_title = "進度" message_text = "已加載字型文件:" else: message_title = "Progress" message_text = "Loaded font file: " messagebox.showinfo(message_title, message_text + filename) #open font with given number ttf = TTFont(filename, 0, allowVID=0, ignoreDecompileErrors=True, fontNumber=font_id) #get chars from cmap chars = chain.from_iterable( [y + (Unicode[y[0]], ) for y in x.cmap.items()] for x in ttf["cmap"].tables) return chars #close font ttf.close()
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()
def import_from_otf(self, otfpath): """Import color data (CPAL/COLR) from a font file. otfpath: Path of the font file""" font = TTFont(otfpath) if not (font.has_key("COLR") and font.has_key("CPAL")): print("ERROR: No COLR and CPAL table present in %s" % otfpath) else: print("Reading palette data ...") cpal = table_C_P_A_L_("CPAL") cpal.decompile(font["CPAL"].data, font) for j in range(len(cpal.palettes)): palette = cpal.palettes[j] _palette = {} for i in range(len(palette)): color = palette[i] _palette[str(i)] = "#%02x%02x%02x%02x" % ( color.red, color.green, color.blue, color.alpha) self.palettes.append(_palette) colr = table_C_O_L_R_("COLR") colr.decompile(font["COLR"].data, font) print("Reading layer data ...") for glyphname in colr.ColorLayers: layers = colr[glyphname] _glyph = ColorGlyph(self) _glyph.basename = glyphname for layer in layers: _glyph.layers.append(layer.name) _glyph.colors.append(layer.colorID) self[glyphname] = _glyph print("Done.") font.close()
def installFont(self, path): """ Install a font with a given path and the postscript font name will be returned. The postscript font name can be used to set the font as the active font. Fonts are installed only for the current process. Fonts will not be accesible outside the scope of drawBot. All installed fonts will automatically be uninstalled when the script is done. .. showcode:: /../examples/installFont.py """ success, error = self._dummyContext.installFont(path) self._installedFontPaths.add(path) self._addInstruction("installFont", path) from fontTools.ttLib import TTFont, TTLibError try: font = TTFont(path) psName = font["name"].getName(6, 1, 0) if psName is None: psName = font["name"].getName(6, 3, 1) font.close() except IOError: raise DrawBotError("Font '%s' does not exist." % path) except TTLibError: raise DrawBotError("Font '%s' is not a valid font." % path) if psName is not None: psName = psName.toUnicode() if not success: warnings.warn("install font: %s" % error) return psName
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)
def ttCount(input, options): ttf = TTFont(input, fontNumber=options.fontNumber, lazy=True) reader = ttf.reader hasPrep = 'prep' in reader.tables hasFpgm = 'fpgm' in reader.tables glyf_program_counts = 0 glyf_names = ttf.getGlyphSet().keys() for glyf_name in glyf_names: glyf = ttf['glyf'].glyphs[glyf_name] glyf.expand(ttf['glyf']) if hasattr(ttf['glyf'].glyphs[glyf_name], "program"): prog = ttf['glyf'].glyphs[glyf_name].program if (hasattr(prog, "bytecode") and len(prog.bytecode) > 0) or (hasattr(prog, "assembly") and len(prog.assembly) > 0): glyf_program_counts += 1 #print ("%s %s" % (glyf, hasattr(ttf['glyf'].glyphs[glyf_name], "program"))) hasSomeGlyfCode = glyf_program_counts > 0 globalAnswer = hasPrep or hasFpgm or hasSomeGlyfCode print ("%s: %s, prep = %s, fpgm = %s, glyf = %s [%d/%d]" % (input, yes_or_no(globalAnswer), yes_or_no(hasPrep), yes_or_no(hasFpgm), yes_or_no(hasSomeGlyfCode), glyf_program_counts, len(glyf_names))) ttf.close()
def makeWeb(args): font = TTFont(args.file) base, ext = os.path.splitext(args.file) font.flavor = "woff" font.save(os.path.join(args.dir, base + ".woff")) font.close()
def getSFNTData(pathOrFile, unsortGlyfLoca=False, glyphBBox="", alt255UInt16=False): font = TTFont(pathOrFile) tableChecksums = {} tableData = {} tableOrder = [i for i in sorted(font.keys()) if len(i) == 4] if unsortGlyfLoca: assert "loca" in tableOrder loca = tableOrder.index("loca") glyf = tableOrder.index("glyf") tableOrder.insert(glyf, tableOrder.pop(loca)) for tag in tableOrder: tableChecksums[tag] = font.reader.tables[tag].checkSum tableData[tag] = transformTable(font, tag, glyphBBox=glyphBBox, alt255UInt16=alt255UInt16) totalData = "".join([tableData[tag][1] for tag in tableOrder]) compData = brotli.compress(totalData, brotli.MODE_FONT) if len(compData) >= len(totalData): compData = totalData font.close() del font return tableData, compData, tableOrder, tableChecksums
def _autohint(self, otf, fmt): logger.info(f"Autohinting {self.name}.{fmt.value}") if fmt == Format.TTF: from io import BytesIO from ttfautohint import ttfautohint buf = BytesIO() otf.save(buf) otf.close() data = ttfautohint(in_buffer=buf.getvalue(), no_info=True) otf = TTFont(BytesIO(data)) # Set bit 3 on head.flags # https://font-bakery.readthedocs.io/en/latest/fontbakery/profiles/googlefonts.html#com.google.fonts/check/integer_ppem_if_hinted head = otf["head"] head.flags |= 1 << 3 elif fmt == Format.OTF: from tempfile import TemporaryDirectory from psautohint.__main__ import main as psautohint with TemporaryDirectory() as d: path = Path(d) / "tmp.otf" otf.save(path) with TemporaryLogLevel(logging.ERROR): psautohint([str(path)]) otf.close() otf = TTFont(path) return otf
def cmap_dump(self): font = TTFont(self.fontfile) #TODO(ahmetcelik) cmap in format 12 should be used if it exists cmapTable = font['cmap'].getcmap(3, 10) if not cmapTable: cmapTable = font['cmap'].getcmap(3, 1) assert cmapTable,'Unicode cmap table required' cmap = cmapTable.cmap # unicode table codepoints = [] glyphs = [] for code, name in cmap.iteritems(): id = font.getGlyphID(name) glyphs.append(id) codepoints.append(code) if self.debug: print id,name,code font.close() cp_dumper = Dumper(self.folder + '/codepoints') cp_dumper.dump_array(codepoints, 'I', '>') cp_dumper.close() gid_dumper = Dumper(self.folder + '/gids') gid_dumper.dump_array(glyphs, 'H', '>') gid_dumper.close()
def __zero_charset_fmt(self,output): font = TTFont(output) cffTableOffset = font.reader.tables['CFF '].offset cffTable = font['CFF '].cff assert len(cffTable.fontNames) == 1 #only one font should be present charsetOffset = cffTable[cffTable.fontNames[0]].rawDict['charset'] numGlyphs = font['maxp'].numGlyphs inner_file = font.reader.file inner_file.seek(cffTableOffset+charsetOffset) format = readCard8(inner_file); if format != 2 and format != 1: return None record_len = 4 if format == 2 else 3 seenGlyphCount = 0 size = 0 while seenGlyphCount < numGlyphs: inner_file.seek(2,io.SEEK_CUR) if format == 2: nLeft = readCard16(inner_file) else: #format 1 nLeft = readCard8(inner_file) seenGlyphCount += nLeft + 1 size += 1 font.close() filler = Filler(output) filler.fill(cffTableOffset+charsetOffset+1, record_len*size, '\x00') filler.close()
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()
def decompileBinaryToObject(pathOrFile, compress=True, excludeFeatures=None): from fontTools.ttLib import TTFont from feaTools2.objects import Tables from feaTools2.parsers.binaryParser import parseTable # load font closeFont = True if isinstance(pathOrFile, TTFont): font = pathOrFile closeFont = False else: font = TTFont(pathOrFile) # decompile tables = Tables() if "GSUB" in font: table = tables["GSUB"] parseTable(table, font["GSUB"].table, "GSUB", excludeFeatures=excludeFeatures) if compress: table.compress() # close if closeFont: font.close() # done return tables
def parse_font(url, word_list): # 破解自定义字典,换回真实数据 # {100416: 'zero', 100418: 'period', 100419: 'two', 100420: 'eight', 100421: 'six', 100422: 'three', # 100423: 'seven', 100424: 'nine', 100425: 'five', 100426: 'one', 100427: 'four'} word_map = { 'period': '.', 'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5', 'six': '6', 'seven': '7', 'eight': '8', 'nine': '9' } resp = requests.get(url) font = TTFont(BytesIO(resp.content)) cmap = font.getBestCmap() font.close() res = "" for word in word_list: En = cmap[int(word[2:])] res += word_map[En] return res
def _autohint(self, otf, fmt): logger.info(f"Autohinting {self.name}.{fmt.value}") if fmt == Format.TTF: from io import BytesIO from ttfautohint import ttfautohint buf = BytesIO() otf.save(buf) otf.close() data = ttfautohint(in_buffer=buf.getvalue(), no_info=True) otf = TTFont(BytesIO(data)) elif fmt == Format.OTF: from tempfile import TemporaryDirectory from psautohint.__main__ import main as psautohint with TemporaryDirectory() as d: path = Path(d) / "tmp.otf" otf.save(path) with TemporaryLogLevel(logging.ERROR): psautohint([str(path)]) otf.close() otf = TTFont(path) return otf
def cmap_dump(self): font = TTFont(self.fontfile) #TODO(ahmetcelik) cmap in format 12 should be used if it exists cmapTable = font['cmap'].getcmap(3, 10) if not cmapTable: cmapTable = font['cmap'].getcmap(3, 1) assert cmapTable, 'Unicode cmap table required' cmap = cmapTable.cmap # unicode table codepoints = [] glyphs = [] for code, name in cmap.iteritems(): id = font.getGlyphID(name) glyphs.append(id) codepoints.append(code) if self.debug: print id, name, code font.close() cp_dumper = Dumper(self.folder + '/codepoints') cp_dumper.dump_array(codepoints, 'I', '>') cp_dumper.close() gid_dumper = Dumper(self.folder + '/gids') gid_dumper.dump_array(glyphs, 'H', '>') gid_dumper.close()
def get_font_code(url, encry_text): #字典,同伙FontCreator 软件打开字体文件得到解密字典 WORS_MAP = { 'period': '.', 'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5', 'six': '6', 'seven': '7', 'eight': '8', 'nine': '9' } #通过TTFont解密字体文件 res = requests.get(url, headers=headers) font = TTFont(BytesIO(res.content)) cmap = font.getBestCmap() font.close() #解密字体 word_count = '' for flag in encry_text.split(";"): #去掉多余字符 ch = cmap.get(int(flag[2:])) word_count += WORS_MAP.get(ch, '') return word_count
def makeWeb(args): """If we are building a web version then try to minimise file size""" font = TTFont(args.file, recalcTimestamp=False) # removed compatibility glyphs that of little use on the web ranges = ( (0xfb50, 0xfbb1), (0xfbd3, 0xfd3d), (0xfd50, 0xfdf9), (0xfdfc, 0xfdfc), (0xfe70, 0xfefc), ) cmap = font['cmap'].buildReversed() unicodes = set([min(cmap[c]) for c in cmap]) for r in ranges: unicodes -= set(range(r[0], r[1] + 1)) options = subset.Options() options.set(layout_features='*', name_IDs='*', drop_tables=['DSIG']) subsetter = subset.Subsetter(options=options) subsetter.populate(unicodes=unicodes) subsetter.subset(font) base, ext = os.path.splitext(args.file) for flavor in ("woff", "woff2"): font.flavor = flavor font.save(args.dir + "/" + base + "." + flavor) font.close()
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)
class TestClosureTaker(unittest.TestCase): def setUp(self): """Loads font and initializes ClosureTaker """ self.font = TTFont('test_data/NotoSans-Regular_subset.ttf') self.closureTaker = ClosureTaker(self.font) def test_c(self): """Takes closure of character 'c' Expected result is array: [3] """ self.closureTaker.clear() self.closureTaker.add_glyph_names(['c']) gids = self.closureTaker.closure() self.assertTrue(gids == [3], 'Closure of c is [c]') def test_clear(self): """Takes closure of cleared input lists Expected result is array: [] """ self.closureTaker.clear() gids = self.closureTaker.closure() self.assertTrue(gids == [], 'Closure of empty is []') def tearDown(self): """Closes font """ self.font.close()
def get_font(url): """ 字数反爬 解析字体 """ response = requests.get(url) font = TTFont(BytesIO(response.content)) cmap = font.getBestCmap() font.close() return cmap
def read_metadata(font): ttf = TTFont(font, lazy=True) try: ttf.getGlyphNames() except Exception: logging.error('Not a vaild font: ' + request['url']) return None reader = ttf.reader metadata = { 'table_sizes': {tag: reader.tables[tag].length for tag in sorted(reader.keys())}, 'names': _read_names(ttf, (_NAME_ID_VERSION, _NAME_ID_POSTSCRIPT_NAME, _NAME_ID_LICENSE_URL)), 'OS2': _read_os2(ttf), 'post': _read_post(ttf), 'fvar': _read_fvar(ttf), 'counts': _read_codepoint_glyph_counts(ttf), } ttf.close() return {k: v for k, v in metadata.items() if v is not None}
def generateWoff2(self, verbosity=0): woff2_list = [] os.makedirs(self.assetdir, exist_ok=True) for subname, (subrange, unicodes) in self.urdict.items(): if verbosity == 2: print("Processing", subname) subs = Subsetter() font = TTFont(self.fontfile) subs.populate(unicodes=unicodes) subs.subset(font) cmap = font.getBestCmap() glyphcount = len(font.getGlyphOrder()) - 1 if cmap: outfile = os.path.join(self.assetdir, self.basename + "." + subname + ".woff2") font.flavor = 'woff2' font.save(outfile) woff2_list.append((outfile, subrange)) if verbosity == 1: print("Generated", outfile) elif verbosity == 2: print(" Generated", outfile) print(" Found", glyphcount, "glyphs for", len(cmap), "out of", len(unicodes), "unicodes") else: if verbosity == 2: print(" Found no glyphs for any of", len(unicodes), "unicodes") font.close() return woff2_list
def check_fonts(self): """Check each request to extract metadata about fonts""" start = monotonic.monotonic() try: from fontTools.ttLib import TTFont for request_id in self.requests: try: request = self.requests[request_id] if 'body' in request: sniff_type = self.sniff_file_content(request['body']) if sniff_type is not None and sniff_type in [ 'OTF', 'TTF', 'WOFF', 'WOFF2' ]: tables = None ttf = TTFont(request['body'], lazy=True) reader = ttf.reader tags = sorted(reader.keys()) for tag in tags: entry = reader.tables[tag] if tables is None: tables = {} tables[tag] = entry.length ttf.close() if tables is not None: self.font_results[request_id] = { 'table_sizes': tables } except Exception: pass except Exception: pass self.font_time = monotonic.monotonic() - start
def import_from_otf(self, otfpath): """Import color data (CPAL/COLR) from a font file. otfpath: Path of the font file""" font = TTFont(otfpath) if not (font.has_key("COLR") and font.has_key("CPAL")): print("ERROR: No COLR and CPAL table present in %s" % otfpath) else: print("Reading palette data ...") cpal = table_C_P_A_L_("CPAL") cpal.decompile(font["CPAL"].data, font) for j in range(len(cpal.palettes)): palette = cpal.palettes[j] _palette = {} for i in range(len(palette)): color = palette[i] _palette[str(i)] = "#%02x%02x%02x%02x" % ( color.red, color.green, color.blue, color.alpha ) self.palettes.append(_palette) colr = table_C_O_L_R_("COLR") colr.decompile(font["COLR"].data, font) print("Reading layer data ...") for glyphname in colr.ColorLayers: layers = colr[glyphname] _glyph = ColorGlyph(self) _glyph.basename = glyphname for layer in layers: _glyph.layers.append(layer.name) _glyph.colors.append(layer.colorID) self[glyphname] = _glyph print("Done.") font.close()
def __zero_cmaps(self,output): font = TTFont(output) old_cmap_method = change_method(_c_m_a_p.table__c_m_a_p, _decompile_in_table_cmap,'decompile') old_12_method = change_method(_c_m_a_p.cmap_format_12_or_13,_decompile_in_cmap_format_12_13, 'decompile') old_4_method = change_method(_c_m_a_p.cmap_format_4,_decompile_in_cmap_format_4, 'decompile') cmap_offset = font.reader.tables['cmap'].offset cmapTables = font['cmap'] cmap12 = cmapTables.getcmap(3, 10) #format 12 cmap4 = cmapTables.getcmap(3, 1) #format 4 ranges_to_zero = [] if cmap12: ranges_to_zero.append((cmap_offset+cmap12.offset+16,cmap12.length-16)) #if cmap4: # ranges_to_zero.append((cmap_offset+cmap4.offset+14,cmap4.length-14)) change_method(_c_m_a_p.cmap_format_12_or_13,old_12_method,'decompile') change_method(_c_m_a_p.cmap_format_4,old_4_method,'decompile') change_method(_c_m_a_p.table__c_m_a_p,old_cmap_method,'decompile') font.close() #if len(ranges_to_zero)<2: #return if both doesn't exist # return for block in ranges_to_zero: filler = Filler(output) filler.fill(block[0], block[1], '\x00') filler.close()
def parse_detial(self, response): font = TTFont(BytesIO(response.body)) cmap = font.getBestCmap() font.close() self.font_dic[response.url] = cmap return self.processing_data(cmap, response.meta)
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"
def get_font(url): time.sleep(1) response = requests.get(url) font = TTFont(BytesIO(response.content)) web_font_relation = font.getBestCmap() font.close() return web_font_relation
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()
def main(file_name): excluded_chars = ["????", "SPACE", "NO-BREAK SPACE"] font = TTFont(file_name) for cmap in font["cmap"].tables: char_list = sorted(cmap.cmap.items()) for item in char_list: item_description = Unicode[item[0]] if item_description not in excluded_chars: print hex(item[0]), item_description font.close()
def makeWeb(args): """If we are building a web version then try to minimise file size""" font = TTFont(args.file) base, ext = os.path.splitext(args.file) for flavor in ("woff", "woff2"): font.flavor = flavor font.save(args.dir + "/" + base + "." + flavor) font.close()
def _export_colr(self, otfpath): font = TTFont(otfpath) if (font.has_key("COLR") and font.has_key("CPAL")): print(" WARNING: Replacing existing COLR and CPAL tables in %s" % otfpath) print(" Writing palette data ...") cpal = table_C_P_A_L_("CPAL") cpal.version = 0 cpal.numPaletteEntries = len(self.palettes[0]) cpal.palettes = [] for j in range(len(self.palettes)): palette = self.palettes[j] _palette = [] # keep a map of old to new indices (palette indices are # not saved in font) if j == 0: reindex = {0xffff: 0xffff} count = 0 for i in sorted(palette.keys(), key=lambda k: int(k)): _color = Color() _color.red = int(palette[i][1:3], 16) _color.green = int(palette[i][3:5], 16) _color.blue = int(palette[i][5:7], 16) if len(palette[i]) >= 9: _color.alpha = int(palette[i][7:9], 16) else: _color.alpha = 0xff if j == 0: reindex[int(i)] = count count += 1 _palette.append(_color) print(" Appending palette", _palette) #print("ReIndex:", reindex) cpal.palettes.append(_palette) print(" Writing layer data ...") colr = table_C_O_L_R_("COLR") colr.version = 0 colr.ColorLayers = {} for glyphname in self.keys(): _layer_records = [] for i in range(len(self[glyphname].layers)): glyph = self[glyphname] _layer_records.append( LayerRecord(glyph.layers[i], reindex[glyph.colors[i]]) ) colr[glyphname] = _layer_records # save font["CPAL"] = cpal font["COLR"] = colr font.save(otfpath[:-4] + "_colr" + otfpath[-4:]) font.close()
def getInformation(fontfile, tags): # TODO(bstell) check if font already opened font = TTFont(fontfile) dict_of_data = {} for tag in tags: assert tag in FontInfo.TAGS result = FontInfo.TAGS[tag]['fn'](font) if result: dict_of_data[tag] = result font.close() return dict_of_data
def ttDump(input, output, options): print('Dumping "%s" to "%s"...' % (input, output)) ttf = TTFont(input, 0, verbose=options.verbose, allowVID=options.allowVID, ignoreDecompileErrors=options.ignoreDecompileErrors, fontNumber=options.fontNumber) ttf.saveXML(output, tables=options.onlyTables, skipTables=options.skipTables, splitTables=options.splitTables, disassembleInstructions=options.disassembleInstructions) ttf.close()
def can_display_text_using_font(text, font_path): ttf = TTFont(font_path, 0, verbose=0, allowVID=0, ignoreDecompileErrors=True, fontNumber=-1) chars = chain.from_iterable([y + (Unicode[y[0]],) for y in x.cmap.items()] for x in ttf["cmap"].tables) chars = {unichr(x[0]) for x in chars} for char in text: if unicode(char) not in chars: ttf.close() return False ttf.close() return True
def ttDump(input): output = tempfile.TemporaryFile(suffix=".ttx") ttf = TTFont(input, 0, allowVID=False, quiet=None, ignoreDecompileErrors=True, fontNumber=-1) ttf.saveXML(output, tables= [], skipTables= [], splitTables=False, disassembleInstructions=True, bitmapGlyphDataFormat='raw') ttf.close() return output
def getInformation(fontfile, tags): # TODO(bstell) check if font already opened font = TTFont(fontfile) dict_of_data = collections.OrderedDict() for tag, fn in FontInfo.TAGS.iteritems(): if tag in tags: if tag == 'SHA1': result = FontInfo.TAGS[tag]['fn'](fontfile) else: result = FontInfo.TAGS[tag]['fn'](font) if result: dict_of_data[tag] = result font.close() return dict_of_data
def ttDump(input, output, options): log.info('Dumping "%s" to "%s"...', input, output) if options.unicodedata: setUnicodeData(options.unicodedata) ttf = TTFont(input, 0, allowVID=options.allowVID, ignoreDecompileErrors=options.ignoreDecompileErrors, fontNumber=options.fontNumber) ttf.saveXML(output, tables=options.onlyTables, skipTables=options.skipTables, splitTables=options.splitTables, disassembleInstructions=options.disassembleInstructions, bitmapGlyphDataFormat=options.bitmapGlyphDataFormat) ttf.close()
def makeCss(infiles, outfile): """Builds a CSS file for the entire font family.""" css = "" for f in infiles.split(): base = os.path.splitext(os.path.basename(f))[0] font = TTFont(f) css += genCSS(font, base) font.close() out = open(outfile, "w") out.write(css) out.close()
def extractFontFromOpenType(pathOrFile, destination, doGlyphs=True, doInfo=True, doKerning=True, customFunctions=[]): source = TTFont(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()
def save_font(bytecode, fontfile): font_roundtrip = TTFont(fontfile) bytecodeContainer = BytecodeContainer(font_roundtrip) for key in bytecode.keys(): # we don't want GS initialize instructions if key == 'prep': del bytecode[key][:17] program_tag = key instruction = bytecodeContainer.constructInstructions(program_tag, bytecode[key]) bytecodeContainer.tag_to_programs[program_tag] = Program(instruction) bytecodeContainer.updateTTFont(font_roundtrip) roundtrip_filename = "{0}_roundtrip.ttf".format(fontfile.split(".ttf")[0]) font_roundtrip.save(roundtrip_filename) font_roundtrip.close()
def ttDump(input, output, options): if not options.quiet: print('Dumping "%s" to "%s"...' % (input, output)) ttf = TTFont(input, 0, verbose=options.verbose, allowVID=options.allowVID, quiet=options.quiet, ignoreDecompileErrors=options.ignoreDecompileErrors, fontNumber=options.fontNumber) ttf.saveXML(output, quiet=options.quiet, tables=options.onlyTables, skipTables=options.skipTables, splitTables=options.splitTables, disassembleInstructions=options.disassembleInstructions, bitmapGlyphDataFormat=options.bitmapGlyphDataFormat) ttf.close()
def namelist_from_font(file_name, out=None): if out is None: out = sys.stdout excluded_chars = ["????", "SPACE", "NO-BREAK SPACE"] font = TTFont(file_name) charcodes = set() for cmap in font["cmap"].tables: if not cmap.isUnicode(): continue charcodes.update(cp for cp,name in cmap.cmap.items()) charcodes = sorted(charcodes) for charcode in charcodes: hexchar, char, item_description = _format_codepoint(charcode) if item_description not in excluded_chars: print(hexchar, char, item_description, file=out) font.close()
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()