Example #1
0
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
Example #2
0
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
Example #3
0
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)
Example #4
0
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
Example #5
0
    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
Example #6
0
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
Example #7
0
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