def main(args): if len(args) < 3: sys.exit("usage: kern_table.py ufo ttf output_ttf") ufo_path = args[0] font_path = args[1] output_path = args[2] ufo = Font(ufo_path) font = TTFont(font_path) print("parsing %s to add legacy kern table to %s" % (ufo_path, font_path)) kerning = flatten_kerning(ufo) print("total kerning pairs: %i" % len(kerning)) key_kerning = flatten_kerning(ufo, key_glyphs_only=True) print("kerning pairs kept: %i" % len(key_kerning)) kern = newTable("kern") kern.version = 0 subtable = KernTable_format_0() subtable.coverage = 1 subtable.version = 0 subtable.kernTable = {} subtable.kernTable.update(key_kerning) kern.kernTables = [subtable] font["kern"] = kern print("writing font with legacy kern table to %s" % output_path) font.save(output_path)
def test_decompileBadGlyphId(self, font): subtable = KernTable_format_0() subtable.decompile( b'\x00' + b'\x00' + b'\x00' + b'\x1a' + b'\x00' + b'\x00' + b'\x00' + b'\x02' + b'\x00' * 6 + b'\x00' + b'\x01' + b'\x00' + b'\x03' + b'\x00' + b'\x01' + b'\x00' + b'\x01' + b'\xFF' + b'\xFF' + b'\x00' + b'\x02', font) assert subtable[("B", "D")] == 1 assert subtable[("B", "glyph65535")] == 2
def test_decompileBadGlyphId(self): subtable = KernTable_format_0() subtable.apple = False subtable.decompile( b'\x00' * 6 + b'\x00' + b'\x02' + b'\x00' * 6 + b'\x00' + b'\x01' + b'\x00' + b'\x03' + b'\x00' + b'\x01' + b'\x00' + b'\x01' + b'\xFF' + b'\xFF' + b'\x00' + b'\x02', MockFont()) self.assertEqual(subtable[("glyph00001", "glyph00003")], 1) self.assertEqual(subtable[("glyph00001", "glyph65535")], 2)
def test_toXML_single_format_0(self, font, version, expected): kern = newTable("kern") kern.version = version apple = version == 1.0 st = KernTable_format_0(apple) kern.kernTables = [st] st.coverage = 0 if apple else 1 st.tupleIndex = 0 if apple else None st.kernTable = {('E', 'M'): -40, ('E', 'c'): 40, ('F', 'o'): -50} xml = getXML(kern.toXML, font) assert xml == expected
def test_compile_single_format_0(self, font, version, expected): kern = newTable("kern") kern.version = version apple = version == 1.0 st = KernTable_format_0(apple) kern.kernTables = [st] st.coverage = (0 if apple else 1) st.tupleIndex = 0 if apple else None st.kernTable = {('E', 'M'): -40, ('E', 'c'): 40, ('F', 'o'): -50} data = kern.compile(font) assert data == expected
def BuildFuColonKernSubtable(font, left, right): cmap = font['cmap'].getBestCmap() nums = [cmap[ord(i)] for i in "0123456789"] fuColon = cmap[ord(":")] kernPairs = {(fuColon, n): right for n in nums} if left: kernPairs.update({(n, fuColon): right for n in nums}) subtable = KernTable_format_0() subtable.coverage = 0b00000001 subtable.format = 0 subtable.kernTable = kernPairs return subtable
def test_getkern(self): table = newTable("kern") table.version = 0 table.kernTables = [] assert table.getkern(0) is None st0 = KernTable_format_0() table.kernTables.append(st0) assert table.getkern(0) is st0 assert table.getkern(4) is None st1 = KernTable_format_unkown(4) table.kernTables.append(st1)
def test_compileOverflowingSubtable(self, overflowing_font): font = overflowing_font kern = newTable("kern") kern.version = 0 st = KernTable_format_0(0) kern.kernTables = [st] st.coverage = 1 st.tupleIndex = None st.kernTable = { (a, b): 0 for (a, b) in itertools.product(font.getGlyphOrder(), repeat=2) } assert len(st.kernTable) == 11025 data = kern.compile(font) assert data == KERN_VER_0_FMT_0_OVERFLOWING_DATA
def test_check_kern_table(): """ Is there a "kern" table declared in the font? """ check = CheckTester(opentype_profile, "com.google.fonts/check/kern_table") # Our reference Mada Regular is known to be good # (does not have a 'kern' table): ttFont = TTFont(TEST_FILE("mada/Mada-Regular.ttf")) # So it must PASS the check: assert_PASS(check(ttFont), 'with a font without a "kern" table...') # add a basic 'kern' table: kern = ttFont["kern"] = newTable("kern") kern.version = 0 subtable = KernTable_format_0() subtable.coverage = 1 subtable.version = 0 subtable.kernTable = {("A", "V"): -50} kern.kernTables = [subtable] # and make sure the check emits an INFO message: assert_results_contain(check(ttFont), INFO, 'kern-found', 'with a font containing a "kern" table...') # and a FAIL message when a non-character glyph is used. subtable.kernTable.update({("A", "four.dnom"): -50}) assert_results_contain(check(ttFont), FAIL, 'kern-non-character-glyphs', 'The following glyphs should not be used...') # and a WARN message when a non-character glyph is used. subtable = KernTable_format_unkown(2) kern.kernTables = [subtable] assert_results_contain(check(ttFont), WARN, 'kern-unknown-format', 'The "kern" table does not have any format-0 subtable...')
def processFont(path, d, flatKernData): font = TTFont(path) oldD, f = os.path.split(path) new = os.path.join(d, f) name = font['name'].getName(6, 1, 0, 0).string # Make a flat kerning table if flatKernData is not None: newKern = ttLib.newTable("kern") newKern.version = 0 newKern.kernTables = [KernTable_format_0()] flat = flatKernData[name] sortedKeys = flat.keys() sortedKeys.sort() left = '' i = 0 for key in sortedKeys: if left == '': left = key[0] kern_table = {key: flat[key]} count = _flat_kern_count(left, sortedKeys) i += 1 elif i + 1 < len(sortedKeys) and left != sortedKeys[i + 1][0]: if count + _flat_kern_count(sortedKeys[i + 1][0], sortedKeys) > 10920: kern_table[key] = flat[key] t = len(newKern.kernTables) - 1 table = newKern.kernTables[t] table.kernTable = kern_table table.version = 0 table.coverage = 1 table.apple = False newKern.kernTables.append(KernTable_format_0()) left = '' else: kern_table[key] = flat[key] left = sortedKeys[i + 1][0] count = _flat_kern_count(sortedKeys[i + 1][0], sortedKeys) + count i += 1 elif len(sortedKeys) == i + 1: kern_table[key] = flat[key] t = len(newKern.kernTables) - 1 table = newKern.kernTables[t] table.kernTable = kern_table table.version = 0 table.coverage = 1 table.apple = False i += 1 else: kern_table[key] = flat[key] i += 1 # Add this table back to the font font.tables["kern"] = newKern # Fix the ugly id string versionClean(font) nameTableTweak(font) makeDSIG(font) font.save(new)
def BuildGenericKernSubtable(font, cyrillic): scriptDflt = [ scr for scr in font['GPOS'].table.ScriptList.ScriptRecord if scr.ScriptTag == 'DFLT' ] scriptDfltFeaList = [ font['GPOS'].table.FeatureList.FeatureRecord[i] for i in scriptDflt[0].Script.DefaultLangSys.FeatureIndex ] kernFeaList = [ fea.Feature for fea in scriptDfltFeaList if fea.FeatureTag == 'kern' ] kernLutList = [ font['GPOS'].table.LookupList.Lookup[i] for fea in kernFeaList for i in fea.LookupListIndex ] kernPairStList = sum( [lut.SubTable for lut in kernLutList if lut.LookupType == 2], []) kernExtLutList = sum( [lut.SubTable for lut in kernLutList if lut.LookupType == 9], []) kernPairStList += [ lut.ExtSubTable for lut in kernExtLutList if lut.ExtensionLookupType == 2 ] # letters in Adobe Latin 1 and Adobe Cyrillic 1 kernSubset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿıŁłŒœŠšŸŽžƒ" if cyrillic: kernSubset += "ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѢѣѲѳѴѵҐґ" cmap = font['cmap'].getBestCmap() kernGlyph = {*[cmap[ord(ch)] for ch in kernSubset]} kernPairs = {} for st in kernPairStList: if st.Format == 1: coverage = st.Coverage.glyphs for i in range(st.PairSetCount): first = coverage[i] if first not in kernGlyph: continue pairSet = st.PairSet[i] for pairRec in pairSet.PairValueRecord: second = pairRec.SecondGlyph if second not in kernGlyph: continue value = pairRec.Value1.XAdvance if value: kernPairs[(first, second)] = value elif st.Format == 2: coverage = st.Coverage.glyphs classDef1 = st.ClassDef1.classDefs classDef2 = st.ClassDef2.classDefs for first in coverage: if first not in kernGlyph: continue firstClass = classDef1.get(first, 0) class1Record = st.Class1Record[firstClass] for second in coverage: if second not in kernGlyph: continue secondClass = classDef2.get(second, 0) class2Record = class1Record.Class2Record[secondClass] value = class2Record.Value1.XAdvance if value: kernPairs[(first, second)] = value subtable = KernTable_format_0() subtable.coverage = 0b00000001 subtable.format = 0 subtable.kernTable = kernPairs return subtable