def _gdef(font_before, font_after, type_): base_before = getattr(font_before, type_) base_after = getattr(font_after, type_) base_before_h = {i['glyph'].key: i for i in base_before} base_after_h = {i['glyph'].key: i for i in base_after} missing = _subtract_items(base_before_h, base_after_h) new = _subtract_items(base_after_h, base_before_h) new = DiffTable(f"{type_} new", font_before, font_after, data=new, renderable=True) new.report_columns(["glyph"]) new.sort(key=lambda k: k["glyph"].width, reverse=True) missing = DiffTable(f"{type_} missing", font_before, font_after, data=missing, renderable=True) missing.report_columns(["glyph"]) missing.sort(key=lambda k: k["glyph"].width, reverse=True) return { "new": new, "missing": missing, }
def diff_attribs(font_before, font_after, scale_upm=True): """Find attribute differences between two fonts. Rows are matched by using attrib. Parameters ---------- font_before: DFont font_after: DFont scale_upms: Scale values in relation to the font's upms. See readme for example. Returns ------- dict { "modified": [diff_table] } """ attribs_before = font_before.attribs attribs_after = font_after.attribs upm_before = font_before.ttfont['head'].unitsPerEm upm_after = font_after.ttfont['head'].unitsPerEm attribs_before_h = {i['attrib']: i for i in attribs_before} attribs_after_h = {i['attrib']: i for i in attribs_after} modified = _modified_attribs(attribs_before_h, attribs_after_h, upm_before, upm_after, scale_upm=scale_upm) modified = DiffTable("attribs modified", font_before, font_after, data=modified) modified.report_columns(["table", "attrib", "value_a", "value_b"]) modified.sort(key=lambda k: k["table"]) return {'modified': modified}
def diff_cbdt_glyphs(font_before, font_after, thresh=4, render_path=None, html_output=False): cbdt_before = read_cbdt(font_before.ttfont) cbdt_after = read_cbdt(font_after.ttfont) chars_before = {r["string"]: str(r["glyph"]) for r in font_before.glyphs} chars_after = {r["string"]: str(r["glyph"]) for r in font_after.glyphs} modified = [] for char in set(chars_before) & set(chars_after): glyph_name_before = chars_before[char] glyph_name_after = chars_after[char] if glyph_name_before in cbdt_before and glyph_name_after in cbdt_after: diff = _diff_images(cbdt_before[glyph_name_before], cbdt_after[glyph_name_after]) if diff > thresh: modified.append({ "glyph before": glyph_name_before, "glyph after": glyph_name_after, "string": char, "diff": diff, "image": f"<img src='{render_path}/{glyph_name_before}.gif'>", }) modified = DiffTable("cbdt glyphs modified", font_before, font_after, data=modified, renderable=True) if render_path and html_output: modified.report_columns( ["glyph before", "glyph after", "diff", "string", "image"]) else: modified.report_columns( ["glyph before", "glyph after", "diff", "string"]) modified.sort(key=lambda k: abs(k["diff"]), reverse=True) return {"modified": modified}
def diff_metrics(font_before, font_after, thresh=1, scale_upms=True): """Find metrics differences between two fonts. Rows are matched by each using glyph key, which consists of the glyph's characters and OT features. Parameters ---------- font_before: DFont font_after: DFont thresh: Ignore modified metrics under this value scale_upms: Scale values in relation to the font's upms. See readme for example. Returns ------- dict { "new": [diff_table], "missing": [diff_table], "modified": [diff_table] } """ metrics_before = font_before.metrics metrics_after = font_after.metrics upm_before = font_before.ttfont['head'].unitsPerEm upm_after = font_after.ttfont['head'].unitsPerEm metrics_before_h = {i['glyph'].key: i for i in metrics_before} metrics_after_h = {i['glyph'].key: i for i in metrics_after} modified = _modified_metrics(metrics_before_h, metrics_after_h, thresh, upm_before, upm_after, scale_upms) modified = DiffTable("metrics modified", font_before, font_after, data=modified, renderable=True) modified.report_columns(["glyph", "diff_adv"]) modified.sort(key=lambda k: k["diff_adv"], reverse=True) return {'modified': modified}
def diff_glyphs(font_before, font_after, thresh=0.00, scale_upms=True, render_diffs=False): """Find glyph differences between two fonts. Rows are matched by glyph key, which consists of the glyph's characters and OT features. Parameters ---------- font_before: DFont font_after: DFont thresh: Ignore differences below this value scale_upms: Scale values in relation to the font's upms. See readme for example. render_diffs: Boolean If True, diff glyphs by rendering them. Return ratio of changed pixels. If False, diff glyphs by calculating the surface area of each glyph. Return ratio of changed surface area. Returns ------- dict { "new": DiffTable, "missing": DiffTable, "modified": DiffTable } """ glyphs_before = font_before.glyphs glyphs_after = font_after.glyphs glyphs_before_h = {r['glyph'].key: r for r in glyphs_before} glyphs_after_h = {r['glyph'].key: r for r in glyphs_after} missing = _subtract_items(glyphs_before_h, glyphs_after_h) new = _subtract_items(glyphs_after_h, glyphs_before_h) modified = _modified_glyphs(glyphs_before_h, glyphs_after_h, thresh, scale_upms=scale_upms, render_diffs=render_diffs) new = DiffTable("glyphs new", font_before, font_after, data=new, renderable=True) new.report_columns(["glyph", "area", "string"]) new.sort(key=lambda k: k["glyph"].name) missing = DiffTable("glyphs missing", font_before, font_after, data=missing, renderable=True) missing.report_columns(["glyph", "area", "string"]) missing.sort(key=lambda k: k["glyph"].name) modified = DiffTable("glyphs modified", font_before, font_after, data=modified, renderable=True) modified.report_columns(["glyph", "diff", "string"]) modified.sort(key=lambda k: abs(k["diff"]), reverse=True) return { 'new': new, 'missing': missing, 'modified': modified }
def diff_nametable(font_before, font_after): """Find nametable differences between two fonts. Rows are matched by attribute id. Parameters ---------- font_before: DFont font_after: DFont Returns ------- DiffTable """ nametable_before = font_before.names nametable_after = font_after.names names_before_h = {i['id']: i for i in nametable_before} names_after_h = {i['id']: i for i in nametable_after} missing = _subtract_items(names_before_h, names_after_h) new = _subtract_items(names_after_h, names_before_h) modified = _modified_names(names_before_h, names_after_h) new = DiffTable("names new", font_before, font_after, data=new) new.report_columns(["id", "string"]) new.sort(key=lambda k: k["id"]) missing = DiffTable("names missing", font_before, font_after, data=missing) missing.report_columns(["id", "string"]) missing.sort(key=lambda k: k["id"]) modified = DiffTable("names modified", font_before, font_after, data=modified) modified.report_columns(["id", "string_a", "string_b"]) modified.sort(key=lambda k: k["id"]) return { 'new': new, 'missing': missing, 'modified': modified, }
def diff_marks(font_before, font_after, marks_before, marks_after, name=None, thresh=4, scale_upms=True): """diff mark positioning. Marks are flattened first. Rows are matched by each base glyph's + mark glyph's key Parameters ---------- font_before: DFont font_after: DFont marks_before: diff_table marks_after: diff_table thresh: Ignore differences below this value scale_upms: Scale values in relation to the font's upms. See readme for example. Returns ------- dict { "new": [diff_table], "missing": [diff_table], "modified": [diff_table] } """ upm_before = font_before.ttfont['head'].unitsPerEm upm_after = font_after.ttfont['head'].unitsPerEm charset_before = set( [font_before.glyph(g).key for g in font_before.glyphset]) charset_after = set([font_after.glyph(g).key for g in font_after.glyphset]) marks_before_h = { i['base_glyph'].key + i['mark_glyph'].key: i for i in marks_before if i['base_glyph'].key in charset_after and i['mark_glyph'].key in charset_after } marks_after_h = { i['base_glyph'].key + i['mark_glyph'].key: i for i in marks_after if i['base_glyph'].key in charset_before and i['mark_glyph'].key in charset_before } missing = _subtract_items(marks_before_h, marks_after_h) new = _subtract_items(marks_after_h, marks_before_h) modified = _modified_marks(marks_before_h, marks_after_h, thresh, upm_before, upm_after, scale_upms=True) new = DiffTable(name + "_new", font_before, font_after, data=new, renderable=True) new.report_columns( ["base_glyph", "base_x", "base_y", "mark_glyph", "mark_x", "mark_y"]) new.sort(key=lambda k: abs(k["base_x"]) - abs(k["mark_x"]) + \ abs(k["base_y"]) - abs(k["mark_y"])) missing = DiffTable(name + "_missing", font_before, font_after, data=missing, renderable=True) missing.report_columns( ["base_glyph", "base_x", "base_y", "mark_glyph", "mark_x", "mark_y"]) missing.sort(key=lambda k: abs(k["base_x"]) - abs(k["mark_x"]) + \ abs(k["base_y"]) - abs(k["mark_y"])) modified = DiffTable(name + "_modified", font_before, font_after, data=modified, renderable=True) modified.report_columns(["base_glyph", "mark_glyph", "diff_x", "diff_y"]) modified.sort(key=lambda k: abs(k["diff_x"]) + abs(k["diff_y"]), reverse=True) return { "new": new, "missing": missing, "modified": modified, }
def diff_kerning(font_before, font_after, thresh=2, scale_upms=True): """Find kerning differences between two fonts. Class kerns are flattened and then tested for differences. Rows are matched by the left and right glyph keys. Some fonts use a kern table instead of gpos kerns, test these if no gpos kerns exist. This problem exists in Open Sans v1. Parameters ---------- font_before: DFont font_after: DFont thresh: Ignore differences below this value scale_upms: Scale values in relation to the font's upms. See readme for example. Returns ------- dict { "new": [diff_table], "missing": [diff_table], "modified": [diff_table] } """ kern_before = font_before.kerns kern_after = font_after.kerns upm_before = font_before.ttfont['head'].unitsPerEm upm_after = font_after.ttfont['head'].unitsPerEm charset_before = set( [font_before.glyph(g).key for g in font_before.glyphset]) charset_after = set([font_after.glyph(g).key for g in font_after.glyphset]) kern_before_h = { i['left'].key + i['right'].key: i for i in kern_before if i['left'].key in charset_after and i['right'].key in charset_after } kern_after_h = { i['left'].key + i['right'].key: i for i in kern_after if i['left'].key in charset_before and i['right'].key in charset_before } missing = _subtract_items(kern_before_h, kern_after_h) missing = [i for i in missing if abs(i["value"]) >= 1] new = _subtract_items(kern_after_h, kern_before_h) new = [i for i in new if abs(i["value"]) >= 1] modified = _modified_kerns(kern_before_h, kern_after_h, thresh, upm_before, upm_after, scale_upms=scale_upms) missing = DiffTable("kerns missing", font_before, font_after, data=missing, renderable=True) missing.report_columns(["left", "right", "value", "string"]) missing.sort(key=lambda k: abs(k["value"]), reverse=True) new = DiffTable("kerns new", font_before, font_after, data=new, renderable=True) new.report_columns(["left", "right", "value", "string"]) new.sort(key=lambda k: abs(k["value"]), reverse=True) modified = DiffTable("kerns modified", font_before, font_after, data=modified, renderable=True) modified.report_columns(["left", "right", "diff", "string"]) modified.sort(key=lambda k: abs(k["diff"]), reverse=True) return { 'new': new, 'missing': missing, 'modified': modified, }