Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| from typing import Optional | |
| from fontTools.annotations import KerningPair, KerningDict, KerningGroups, IntFloat | |
| StrDict = dict[str, str] | |
| def lookupKerningValue( | |
| pair: KerningPair, | |
| kerning: KerningDict, | |
| groups: KerningGroups, | |
| fallback: IntFloat = 0, | |
| glyphToFirstGroup: Optional[StrDict] = None, | |
| glyphToSecondGroup: Optional[StrDict] = None, | |
| ) -> IntFloat: | |
| """Retrieve the kerning value (if any) between a pair of elements. | |
| The elments can be either individual glyphs (by name) or kerning | |
| groups (by name), or any combination of the two. | |
| Args: | |
| pair: | |
| A tuple, in logical order (first, second) with respect | |
| to the reading direction, to query the font for kerning | |
| information on. Each element in the tuple can be either | |
| a glyph name or a kerning group name. | |
| kerning: | |
| A dictionary of kerning pairs. | |
| groups: | |
| A set of kerning groups. | |
| fallback: | |
| The fallback value to return if no kern is found between | |
| the elements in ``pair``. Defaults to 0. | |
| glyphToFirstGroup: | |
| A dictionary mapping glyph names to the first-glyph kerning | |
| groups to which they belong. Defaults to ``None``. | |
| glyphToSecondGroup: | |
| A dictionary mapping glyph names to the second-glyph kerning | |
| groups to which they belong. Defaults to ``None``. | |
| Returns: | |
| The kerning value between the element pair. If no kerning for | |
| the pair is found, the fallback value is returned. | |
| Note: This function expects the ``kerning`` argument to be a flat | |
| dictionary of kerning pairs, not the nested structure used in a | |
| kerning.plist file. | |
| Examples:: | |
| >>> groups = { | |
| ... "public.kern1.O" : ["O", "D", "Q"], | |
| ... "public.kern2.E" : ["E", "F"] | |
| ... } | |
| >>> kerning = { | |
| ... ("public.kern1.O", "public.kern2.E") : -100, | |
| ... ("public.kern1.O", "F") : -200, | |
| ... ("D", "F") : -300 | |
| ... } | |
| >>> lookupKerningValue(("D", "F"), kerning, groups) | |
| -300 | |
| >>> lookupKerningValue(("O", "F"), kerning, groups) | |
| -200 | |
| >>> lookupKerningValue(("O", "E"), kerning, groups) | |
| -100 | |
| >>> lookupKerningValue(("O", "O"), kerning, groups) | |
| 0 | |
| >>> lookupKerningValue(("E", "E"), kerning, groups) | |
| 0 | |
| >>> lookupKerningValue(("E", "O"), kerning, groups) | |
| 0 | |
| >>> lookupKerningValue(("X", "X"), kerning, groups) | |
| 0 | |
| >>> lookupKerningValue(("public.kern1.O", "public.kern2.E"), | |
| ... kerning, groups) | |
| -100 | |
| >>> lookupKerningValue(("public.kern1.O", "F"), kerning, groups) | |
| -200 | |
| >>> lookupKerningValue(("O", "public.kern2.E"), kerning, groups) | |
| -100 | |
| >>> lookupKerningValue(("public.kern1.X", "public.kern2.X"), kerning, groups) | |
| 0 | |
| """ | |
| # quickly check to see if the pair is in the kerning dictionary | |
| if pair in kerning: | |
| return kerning[pair] | |
| # ensure both or no glyph-to-group mappings are provided | |
| if (glyphToFirstGroup is None) != (glyphToSecondGroup is None): | |
| raise ValueError( | |
| "Must provide both 'glyphToFirstGroup' and 'glyphToSecondGroup', or neither." | |
| ) | |
| # create glyph to group mapping | |
| if glyphToFirstGroup is None: | |
| glyphToFirstGroup = {} | |
| glyphToSecondGroup = {} | |
| for group, groupMembers in groups.items(): | |
| if group.startswith("public.kern1."): | |
| for glyph in groupMembers: | |
| glyphToFirstGroup[glyph] = group | |
| elif group.startswith("public.kern2."): | |
| for glyph in groupMembers: | |
| glyphToSecondGroup[glyph] = group | |
| # ensure type safety for mappings | |
| assert glyphToFirstGroup is not None | |
| assert glyphToSecondGroup is not None | |
| # get group names and make sure first and second are glyph names | |
| first, second = pair | |
| firstGroup = secondGroup = None | |
| if first.startswith("public.kern1."): | |
| firstGroup = first | |
| firstGlyph = None | |
| else: | |
| firstGroup = glyphToFirstGroup.get(first) | |
| firstGlyph = first | |
| if second.startswith("public.kern2."): | |
| secondGroup = second | |
| secondGlyph = None | |
| else: | |
| secondGroup = glyphToSecondGroup.get(second) | |
| secondGlyph = second | |
| # make an ordered list of pairs to look up | |
| pairs = [ | |
| (a, b) | |
| for a in (firstGlyph, firstGroup) | |
| for b in (secondGlyph, secondGroup) | |
| if a is not None and b is not None | |
| ] | |
| # look up the pairs and return any matches | |
| for pair in pairs: | |
| if pair in kerning: | |
| return kerning[pair] | |
| # use the fallback value | |
| return fallback | |
| if __name__ == "__main__": | |
| import doctest | |
| doctest.testmod() | |