def test_compile_decompile_4_empty(self): subtable = self.makeSubtable(4, 3, 1, 0) subtable.cmap = {} font = ttLib.TTFont() font.setGlyphOrder([]) data = subtable.compile(font) subtable2 = CmapSubtable.newSubtable(4) subtable2.decompile(data, font) self.assertEqual(subtable2.cmap, {})
def test_compile_2(self): subtable = self.makeSubtable(2, 1, 2, 0) subtable.cmap = {c: "cid%05d" % c for c in range(32, 8192)} font = ttLib.TTFont() font.setGlyphOrder([".notdef"] + list(subtable.cmap.values())) data = subtable.compile(font) subtable2 = CmapSubtable.newSubtable(2) subtable2.decompile(data, font) self.assertEqual(subtable2.cmap, subtable.cmap)
def convert_cmap_subtables_to_v4(font): cmap = font['cmap'] outtables = [] for table in cmap.tables: newtable = CmapSubtable.newSubtable(4) newtable.platformID = table.platformID newtable.platEncID = table.platEncID newtable.language = table.language newtable.cmap = table.cmap outtables.append(newtable) font['cmap'].tables = outtables
def test_compile_2_rebuild_rev_glyph_order(self): for fmt in [2, 4, 12]: subtable = self.makeSubtable(fmt, 1, 2, 0) subtable.cmap = {c: "cid%05d" % c for c in range(32, 8192)} font = ttLib.TTFont() font.setGlyphOrder([".notdef"] + list(subtable.cmap.values())) font._reverseGlyphOrderDict = { } # force first KeyError branch in subtable.compile() data = subtable.compile(font) subtable2 = CmapSubtable.newSubtable(fmt) subtable2.decompile(data, font) self.assertEqual(subtable2.cmap, subtable.cmap, str(fmt))
def add_cmap_format_4(font): """Add cmap format 4 table for Windows support, based on the format 12 cmap.""" cmap = get_font_cmap(font) newtable = CmapSubtable.newSubtable(4) newtable.platformID = 3 newtable.platEncID = 1 newtable.language = 0 # Format 4 only has unicode values 0x0000 to 0xFFFF newtable.cmap = {cp: name for cp, name in cmap.items() if cp <= 0xFFFF} font['cmap'].tables.append(newtable)
def convert_cmap_subtables_to_v4(font): """Converts all cmap subtables to format 4. Returns a list of tuples (format, platformID, platEncID) of the tables which needed conversion.""" cmap = font['cmap'] outtables = [] converted = [] for table in cmap.tables: if table.format != 4: converted.append((table.format, table.platformID, table.platEncID)) newtable = CmapSubtable.newSubtable(4) newtable.platformID = table.platformID newtable.platEncID = table.platEncID newtable.language = table.language newtable.cmap = table.cmap outtables.append(newtable) font['cmap'].tables = outtables return converted
def convert_cmap_subtables_to_v4(font): cmap = font['cmap'] outtables = [] fixit = False for table in cmap.tables: if table.format != 4: print(('Converted format {} cmap subtable' ' with Platform ID = {} and Encoding ID = {}' ' to format 4.').format(table.format, table.platformID, table.platEncID)) fixit = True newtable = CmapSubtable.newSubtable(4) newtable.platformID = table.platformID newtable.platEncID = table.platEncID newtable.language = table.language newtable.cmap = table.cmap outtables.append(newtable) font['cmap'].tables = outtables return fixit
def cmap_format_gbk2utf8(self): cmap = self.font['cmap'] outtables = [] for table in cmap.tables: if table.format in [4, 12, 13, 14]: outtables.append(table) # Convert ot format4 if table.getEncoding() in SUPPORT_CONVERT_FROM_ENCODE: for gbk_code in table.cmap.keys(): uni_code= convert_from_gbk(gbk_code) if gbk_code != uni_code: table.cmap[uni_code] = table.cmap.pop(gbk_code) newtable = CmapSubtable.newSubtable(4) newtable.platformID = self.to_platformID newtable.platEncID = self.to_platEncID newtable.language = table.language newtable.cmap = table.cmap outtables.append(newtable) cmap.tables = outtables
# characters to Unicode... TODO: Extend this script to do that. from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * from fontTools.ttLib import TTFont from fontTools.ttLib.tables._c_m_a_p import CmapSubtable import sys if len(sys.argv) != 3: print("usage: cmap-format.py fontfile.ttf outfile.ttf") sys.exit(1) fontfile = sys.argv[1] outfile = sys.argv[2] font = TTFont(fontfile) cmap = font['cmap'] outtables = [] for table in cmap.tables: if table.format in [4, 12, 13, 14]: outtables.append(table) # Convert ot format4 newtable = CmapSubtable.newSubtable(4) newtable.platformID = table.platformID newtable.platEncID = table.platEncID newtable.language = table.language newtable.cmap = table.cmap outtables.append(newtable) cmap.tables = outtables font.save(outfile)
def test_decompile_4(self): subtable = CmapSubtable.newSubtable(4) font = ttLib.TTFont() font.setGlyphOrder([]) subtable.decompile(b'\0' * 3 + b'\x10' + b'\0' * 12, font)
def test_decompile_12(self): subtable = CmapSubtable.newSubtable(12) font = ttLib.TTFont() font.setGlyphOrder([]) subtable.decompile(b'\0' * 7 + b'\x10' + b'\0' * 8, font)
def makeSubtable(self, cmapFormat, platformID, platEncID, langID): subtable = CmapSubtable.newSubtable(cmapFormat) subtable.platformID, subtable.platEncID, subtable.language = ( platformID, platEncID, langID) return subtable
def modernizeZycon(fontPath, newFontPath): origFont = ttLib.TTFont(fontPath) if origFont['name'].getDebugName(1) != u'\x00Zycon': # name was broken raise ValueError('%s is not the old Zycon font' % fontPath) # Reduce the file size by subsetting to the glyphs that are actually used. subsetpath = tempfile.mktemp(suffix='.ttf') ttxpath = tempfile.mktemp(suffix='.ttx') subset.main([ fontPath, '--notdef-glyph', '--notdef-outline', '--glyphs=space,' + ','.join(sorted(GLYPHS.keys())), '--output-file=%s' % subsetpath ]) font = ttLib.TTFont(subsetpath) # Replace the name table. # TODO: Negotiate licensing terms between Font Bureau and Unicode, # so this font can be included into the upcoming OpenType test suite. font['name'].names = [] setName( font, 0, u'Copyright ©1993–2016 by The Font Bureau, Inc. ' + u'with Reserved Font Name “Zycon”') setName(font, 1, 'Zycon') setName(font, 2, 'Regular') setName(font, 5, 'Version 1.8') setName(font, 6, 'Zycon-Regular') setName(font, 9, 'David Berlow') setName(font, 14, 'https://opensource.org/licenses/OFL-1.1') setName(font, 19, makeSampleText(), encoding=10) setName(font, 256, 'Toggle 1') setName(font, 257, 'Toggle 2') setName(font, 258, 'Toggle 3') setName(font, 259, 'Toggle 4') setName(font, 260, 'Motion 1') setName(font, 261, 'Motion 2') del font['hdmx'] # Isn’t there a better way to rename glyphs with fontTools? font.saveXML(ttxpath) with open(ttxpath, 'r') as ttxFile: ttx = ttxFile.read() for old, new in GLYPHS.items(): ttx = ttx.replace('"%s"' % old, '"%s"' % new) with open(ttxpath, 'w') as out: out.write(ttx) font = ttLib.TTFont() font.importXML(ttxpath) cmap4 = CmapSubtable.newSubtable(4) cmap4.platformID, cmap4.platEncID, cmap4.language = 3, 1, 0 cmap4.cmap = {0x20: 'space'} cmap12 = CmapSubtable.newSubtable(12) cmap12.platformID, cmap12.platEncID, cmap12.language = 3, 10, 0 cmap12.cmap = {0x20: 'space'} for glyph in GLYPHS.values(): if glyph.startswith('uni'): cmap4.cmap[int(glyph[3:], 16)] = glyph cmap12.cmap[int(glyph[3:], 16)] = glyph elif glyph.startswith('u'): cmap12.cmap[int(glyph[1:], 16)] = glyph font['cmap'].tables = [cmap4, cmap12] empty = font['glyf']['.notdef'] emptyMetrics = font['hmtx']['.notdef'] font['glyf']['.notdef'] = font['glyf']['space'] font['hmtx']['.notdef'] = font['hmtx']['space'] font['glyf']['space'] = empty font['hmtx']['space'] = [880, 0] font.save(newFontPath)
# legacy subtable to a Unicode one. In those cases, use the # getEncoding() of subtable and use that encoding to map the # characters to Unicode... TODO: Extend this script to do that. from fontTools.ttLib import TTFont from fontTools.ttLib.tables._c_m_a_p import CmapSubtable import sys if len(sys.argv) != 3: print("usage: cmap-format.py fontfile.ttf outfile.ttf") sys.exit(1) fontfile = sys.argv[1] outfile = sys.argv[2] font = TTFont(fontfile) cmap = font['cmap'] outtables = [] for table in cmap.tables: if table.format in [4, 12, 13, 14]: outtables.append(table) # Convert ot format4 newtable = CmapSubtable.newSubtable(4) newtable.platformID = table.platformID newtable.platEncID = table.platEncID newtable.language = table.language newtable.cmap = table.cmap outtables.append(newtable) cmap.tables = outtables font.save(outfile)
def test_ensureDecompiled(lazy): # test that no matter the lazy value, ensureDecompiled decompiles all tables font = TTFont() font.importXML(os.path.join(DATA_DIR, "TestTTF-Regular.ttx")) # test font has no OTL so we add some, as an example of otData-driven tables addOpenTypeFeaturesFromString( font, """ feature calt { sub period' period' period' space by ellipsis; } calt; feature dist { pos period period -30; } dist; """ ) # also add an additional cmap subtable that will be lazily-loaded cm = CmapSubtable.newSubtable(14) cm.platformID = 0 cm.platEncID = 5 cm.language = 0 cm.cmap = {} cm.uvsDict = {0xFE00: [(0x002e, None)]} font["cmap"].tables.append(cm) # save and reload, potentially lazily buf = io.BytesIO() font.save(buf) buf.seek(0) font = TTFont(buf, lazy=lazy) # check no table is loaded until/unless requested, no matter the laziness for tag in font.keys(): assert not font.isLoaded(tag) if lazy is not False: # additional cmap doesn't get decompiled automatically unless lazy=False; # can't use hasattr or else cmap's maginc __getattr__ kicks in... cm = next(st for st in font["cmap"].tables if st.__dict__["format"] == 14) assert cm.data is not None assert "uvsDict" not in cm.__dict__ # glyf glyphs are not expanded unless lazy=False assert font["glyf"].glyphs["period"].data is not None assert not hasattr(font["glyf"].glyphs["period"], "coordinates") if lazy is True: # OTL tables hold a 'reader' to lazily load when lazy=True assert "reader" in font["GSUB"].table.LookupList.__dict__ assert "reader" in font["GPOS"].table.LookupList.__dict__ font.ensureDecompiled() # all tables are decompiled now for tag in font.keys(): assert font.isLoaded(tag) # including the additional cmap cm = next(st for st in font["cmap"].tables if st.__dict__["format"] == 14) assert cm.data is None assert "uvsDict" in cm.__dict__ # expanded glyf glyphs lost the 'data' attribute assert not hasattr(font["glyf"].glyphs["period"], "data") assert hasattr(font["glyf"].glyphs["period"], "coordinates") # and OTL tables have read their 'reader' assert "reader" not in font["GSUB"].table.LookupList.__dict__ assert "Lookup" in font["GSUB"].table.LookupList.__dict__ assert "reader" not in font["GPOS"].table.LookupList.__dict__ assert "Lookup" in font["GPOS"].table.LookupList.__dict__
def swaper(self): ftpathList, swaped, unicodesInt = [], [], [] propLF = [ "zero.lf", "one.lf", "two.lf", "three.lf", "four.lf", "five.lf", "six.lf", "seven.lf", "eight.lf", "nine.lf", ] propOSF = [ "zero.osf", "one.osf", "two.osf", "three.osf", "four.osf", "five.osf", "six.osf", "seven.osf", "eight.osf", "nine.osf", ] tabOSF = [ "zero.tosf", "one.tosf", "two.tosf", "three.tosf", "four.tosf", "five.tosf", "six.tosf", "seven.tosf", "eight.tosf", "nine.tosf", ] salt = [ 'I.salt', 'IJ.salt', 'Iacute.salt', 'Ibreve.salt', 'uni01CF.salt', 'Icircumflex.salt', 'uni0208.salt', 'Idieresis.salt', 'uni1E2E.salt', 'Idotaccent.salt', 'uni1ECA.salt', 'Igrave.salt', 'uni1EC8.salt', 'uni020A.salt', 'Imacron.salt', 'Iogonek.salt', 'Itilde.salt', 'uni1E2C.salt', 'J.salt', 'Jcircumflex.salt', 'uni01C7.salt', 'uni01CA.salt', 'uniA7F7.salt', 'uni0406.salt', 'uni0407.salt', 'uni0408.salt', 'uni04C0.salt', 'uni04CF.salt', 'uni037F.salt', 'Iota.salt', 'Iotatonos.salt', 'Iotadieresis.salt', 'uni1F38.salt', 'uni1F39.salt', 'uni1F3A.salt', 'uni1F3B.salt', 'uni1F3C.salt', 'uni1F3D.salt', 'uni1F3E.salt', 'uni1F3F.salt', 'uni1FDA.salt', 'uni1FDB.salt', 'uni1FD8.salt', 'uni1FD9.salt', 'uni1D35.salt', 'uni1D36.salt' ] unicodeIJ = [ 73, 306, 205, 300, 463, 206, 520, 207, 7726, 304, 7882, 204, 7880, 522, 298, 302, 296, 7724, 74, 308, 455, 458, 42999, 1030, 1031, 1032, 1216, 1231, 895, 921, 906, 938, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999, 8154, 8155, 8152, 8153, 7477, 7478 ] unicodesFig = [i for i in range(48, 58)] for path in self.fonts2merge_list: if os.path.basename(path).split("-")[0] in self.lgcfonts: ftpathList.append(path) tosfOsfLinningFonts = [ "NotoSans", "NotoSans-Italic", "NotoSerif", "NotoSerif-Italic", "NotoSansDisplay-Italic", "NotoSansDisplay", "NotoSerifDisplay", "NotoSerifDisplay-Italic" ] altIJFonts = [ "NotoSans", "NotoSans-Italic", "NotoSansDisplay", "NotoSansDisplay-Italic" ] if self.repoNames[0] in tosfOsfLinningFonts: if "tosf" in self.swapedstyles: swaped = tabOSF elif "osf" in self.swapedstyles: swaped = propOSF elif "plf" in self.swapedstyles: swaped = propLF if len(swaped) > 0: unicodesInt = unicodesFig if "Sans" in self.contrast: lgc = set(altIJFonts) & set(self.repoNames) if "altIJ" in self.swapedstyles and len(lgc) > 0: swaped = swaped + salt unicodesInt = unicodesInt + unicodeIJ for path in ftpathList: ft = ttLib.TTFont(path) cmap = ft['cmap'] go = ft.getGlyphOrder() outtables = [] for table in cmap.tables: modif = table.cmap for uni in unicodesInt: if uni in modif: if swaped[unicodesInt.index(uni)] in go: modif[uni] = swaped[unicodesInt.index(uni)] newtable = CmapSubtable.newSubtable(table.format) newtable.platformID = table.platformID newtable.platEncID = table.platEncID newtable.language = table.language newtable.cmap = modif outtables.append(newtable) cmap.tables = [] cmap.tables = outtables newpath = path.replace(".ttf", "_edited.ttf") ft.save(newpath) self.fonts2merge_list = self.listReplacer( path, newpath, self.fonts2merge_list)
def makeSubtable(self, cmapFormat, platformID, platEncID, langID): subtable = CmapSubtable.newSubtable(cmapFormat) subtable.platformID, subtable.platEncID, subtable.language = (platformID, platEncID, langID) return subtable