Spaces:
Runtime error
Runtime error
File size: 4,836 Bytes
d9f69e5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
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()
|