Beispiel #1
0
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}
Beispiel #2
0
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}
Beispiel #3
0
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}
Beispiel #4
0
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,
    }
Beispiel #5
0
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,
    }
Beispiel #6
0
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}
Beispiel #7
0
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,
    }
Beispiel #8
0
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,
    }