def _dump_table_kerning(font): """Some fonts still contain kern tables. Most modern fonts include kerning in the GPOS table""" kerns = DFontTableIMG(font, "kerns", renderable=True) if not 'kern' in font.ttfont: return kerns logger.warn('Font contains kern table. Newer fonts are GPOS only') for table in font.ttfont['kern'].kernTables: for kern in table.kernTable: left = font.glyph(kern[0]) right = font.glyph(kern[1]) kerns.append({ 'left': left, 'right': right, 'value': table.kernTable[kern], 'string': left.characters + right.characters, 'description': u'{}+{} | {}'.format(left.name, right.name, left.features), 'features': left.features + right.features, 'htmlfeatures': u'{}, {}'.format(', '.join(left.features), ', '.join(right.features)) }) return kerns
def dump_glyphs(font): """Dump info for each glyph in a font Parameters ---------- font: DFont Returns ------- DFontTableIMG Each row in the table is represented as a dict. [ {'glyph': A, 'area': 1000, string': 'A', 'description': "A | ()", 'features': []}, {'glyph': B, 'area': 1100, string': 'B', 'description': "B | ()", 'features': []}, ... ] """ glyphset = font.ttfont.getGlyphSet() table = DFontTableIMG(font, "glyphs", renderable=True) for name, glyph in sorted(font.glyphset.items()): table.append({ "glyph": glyph, "area": glyph_area(glyphset, name), "string": glyph.characters, 'features': glyph.features, 'htmlfeatures': u', '.join(glyph.features) }) table.report_columns(["glyph", "area", "string"]) table.sort(key=lambda k: k["glyph"].characters) return table
def dump_gdef(font): """Dump a font's GDEF table. Function will return two tables, one for base glyphs, the other for mark glyphs.""" table_base = DFontTableIMG(font, "gdef_base", renderable=True) table_mark = DFontTableIMG(font, "gdef_mark", renderable=True) if "GDEF" not in font.ttfont: return (table_base, table_mark) gdef_classes = font.ttfont['GDEF'].table.GlyphClassDef.classDefs for glyph_name, class_ in gdef_classes.items(): glyph = font.glyph(glyph_name) if class_ == 1: table_base.append({ "glyph": glyph, "class": GDEF_CLASSES[class_], "string": glyph.characters, 'features': glyph.features, }) elif class_ == 3: table_mark.append({ "glyph": glyph, "class": GDEF_CLASSES[class_], "string": glyph.characters, 'features': glyph.features, }) for tbl in (table_base, table_mark): tbl.report_columns(["glyph", "class"]) tbl.sort(key=lambda k: k["class"]) return (table_base, table_mark)
def _dump_gpos_kerning(font): """Dump a font's GPOS kerning. TODO (Marc Foley) Flattening produced too much output. Perhaps it's better to keep the classes and map each class to a single glyph? Perhaps it would be better to combine our efforts and help improve https://github.com/adobe-type-tools/kern-dump which has similar functionality?""" if 'GPOS' not in font.ttfont: logger.warning("Font doesn't have GPOS table. No kerns found") return [] kerning_lookup_indexes = _kerning_lookup_indexes(font.ttfont) if not kerning_lookup_indexes: logger.warning("Font doesn't have a GPOS kern feature") return [] kern_table = [] for lookup_idx in kerning_lookup_indexes: lookup = font.ttfont['GPOS'].table.LookupList.Lookup[lookup_idx] for sub_table in lookup.SubTable: if hasattr(sub_table, 'ExtSubTable'): sub_table = sub_table.ExtSubTable if hasattr(sub_table, 'PairSet'): _flatten_pair_kerning(sub_table, kern_table) if hasattr(sub_table, 'ClassDef2'): _flatten_class_kerning(sub_table, kern_table) _kern_table = DFontTableIMG(font, "kerning", renderable=True) for left, right, val in kern_table: left = font.glyph(left) right = font.glyph(right) _kern_table.append({ 'left': left, 'right': right, 'value': val, 'string': left.characters + right.characters, 'description': u'{}+{} | {}'.format(left.name, right.name, left.features), "features": left.features + right.features, 'htmlfeatures': u'{}, {}'.format(', '.join(left.features), ', '.join(right.features)) }) _kern_table.report_columns(["left", "right", "string", "value"]) return _kern_table
def _gen_table(self, name, anchors1, anchors2, anc1_is_combining=False, anc2_is_combining=False): """Return a flattened table consisting of mark1_glyphs with their attached mark2_glyphs. Returns ------- dump_table: list [ {'mark1_glyph': 'a', 'base_x': 300, 'base_y': 450, 'mark2_glyph': 'acutecomb', 'mark_x': 0, 'mark_y': 550}, {'mark1_glyph': 'a', 'base_x': 300, 'base_y': 450, 'mark2_glyph': 'gravecomb', 'mark_x': 0, 'mark_y': 550}, ] """ table = DFontTableIMG(self._font, name, renderable=True) for l_idx in range(len(anchors1)): for m_group in anchors1[l_idx]: for anchor in anchors1[l_idx][m_group]: if anc1_is_combining and not anchor['glyph'].combining: continue if m_group not in anchors2[l_idx]: continue for anchor2 in anchors2[l_idx][m_group]: if anc2_is_combining and not anchor2['glyph'].combining: continue table.append({ 'base_glyph': anchor['glyph'], 'base_x': anchor['x'], 'base_y': anchor['y'], 'mark_glyph': anchor2['glyph'], 'mark_x': anchor2['x'], 'mark_y': anchor2['y'], 'string': anchor['glyph'].characters + \ anchor2['glyph'].characters, 'description': u'{} + {} | {}'.format( anchor['glyph'].name, anchor2['glyph'].name, anchor['glyph'].features ), 'features': anchor['glyph'].features + \ anchor['glyph'].features, 'htmlfeatures': u'{}, {}'.format( ', '.join(anchor['glyph'].features), ', '.join(anchor2['glyph'].features) ) }) table.report_columns([ "base_glyph", "base_x", "base_y", "mark_glyph", "mark_x", "mark_y" ]) return table
def dump_glyph_metrics(font): """Dump the metrics for each glyph in a font Parameters ---------- font: DFont Returns ------- DFontTableIMG Each row in the table is represented as a dict. [ {'glyph': A, 'lsb': 50, 'rsb': 50, 'adv': 200, 'string': 'A', 'description': "A | ()"}, {'glyph': B, 'lsb': 80, 'rsb': 50, 'adv': 230, 'string': 'B', 'description': "B | ()"}, ... ] """ table = DFontTableIMG(font, "metrics", renderable=True) glyf = {} if 'glyf' in font.ttfont: glyf = font.ttfont['glyf'] for name, glyph in font.glyphset.items(): adv, lsb = font.ttfont["hmtx"][name] rsb = 0 if name in glyf and glyf[name].numberOfContours != 0: rsb = adv - glyf[name].xMax table.append({ 'glyph': glyph, 'lsb': lsb, 'rsb': rsb, 'adv': adv, 'string': glyph.characters, 'description': u'{} | {}'.format(glyph.name, glyph.features), 'features': glyph.features, 'htmlfeatures': u', '.join(glyph.features) }) table.report_columns(["glyph", "rsb", "lsb", "adv"]) return table
def dump_glyph_metrics(font): """Dump the metrics for each glyph in a font Parameters ---------- font: DFont Returns ------- DFontTableIMG Each row in the table is represented as a dict. [ {'glyph': A, 'lsb': 50, 'rsb': 50, 'adv': 200, 'string': 'A', 'description': "A | ()"}, {'glyph': B, 'lsb': 80, 'rsb': 50, 'adv': 230, 'string': 'B', 'description': "B | ()"}, ... ] """ table = DFontTableIMG(font, "metrics", renderable=True) glyphset = font.ttfont.getGlyphSet() for name, glyph in font.glyphset.items(): adv = font.ttfont["hmtx"][name][0] if "glyf" in font.ttfont.keys(): try: lsb = font.ttfont["glyf"][name].xMin rsb = adv - font.ttfont['glyf'][name].xMax except AttributeError: lsb = 0 rsb = 0 elif "CFF " in font.ttfont.keys(): try: bounds = font.ttfont["CFF "].cff.values( )[0].CharStrings[name].calcBounds(glyphset) lsb = bounds[0] rsb = adv - bounds[-2] except TypeError: lsb = 0 rsb = 0 else: raise Exception("Only ttf and otf fonts are supported") table.append({ 'glyph': glyph, 'lsb': lsb, 'rsb': rsb, 'adv': adv, 'string': glyph.characters, 'description': u'{} | {}'.format(glyph.name, glyph.features), 'features': glyph.features, 'htmlfeatures': u', '.join(glyph.features) }) table.report_columns(["glyph", "rsb", "lsb", "adv"]) return table