Spaces:
Running
Running
""" | |
Conversion functions. | |
""" | |
# adapted from the UFO spec | |
def convertUFO1OrUFO2KerningToUFO3Kerning(kerning, groups, glyphSet=()): | |
# gather known kerning groups based on the prefixes | |
firstReferencedGroups, secondReferencedGroups = findKnownKerningGroups(groups) | |
# Make lists of groups referenced in kerning pairs. | |
for first, seconds in list(kerning.items()): | |
if first in groups and first not in glyphSet: | |
if not first.startswith("public.kern1."): | |
firstReferencedGroups.add(first) | |
for second in list(seconds.keys()): | |
if second in groups and second not in glyphSet: | |
if not second.startswith("public.kern2."): | |
secondReferencedGroups.add(second) | |
# Create new names for these groups. | |
firstRenamedGroups = {} | |
for first in firstReferencedGroups: | |
# Make a list of existing group names. | |
existingGroupNames = list(groups.keys()) + list(firstRenamedGroups.keys()) | |
# Remove the old prefix from the name | |
newName = first.replace("@MMK_L_", "") | |
# Add the new prefix to the name. | |
newName = "public.kern1." + newName | |
# Make a unique group name. | |
newName = makeUniqueGroupName(newName, existingGroupNames) | |
# Store for use later. | |
firstRenamedGroups[first] = newName | |
secondRenamedGroups = {} | |
for second in secondReferencedGroups: | |
# Make a list of existing group names. | |
existingGroupNames = list(groups.keys()) + list(secondRenamedGroups.keys()) | |
# Remove the old prefix from the name | |
newName = second.replace("@MMK_R_", "") | |
# Add the new prefix to the name. | |
newName = "public.kern2." + newName | |
# Make a unique group name. | |
newName = makeUniqueGroupName(newName, existingGroupNames) | |
# Store for use later. | |
secondRenamedGroups[second] = newName | |
# Populate the new group names into the kerning dictionary as needed. | |
newKerning = {} | |
for first, seconds in list(kerning.items()): | |
first = firstRenamedGroups.get(first, first) | |
newSeconds = {} | |
for second, value in list(seconds.items()): | |
second = secondRenamedGroups.get(second, second) | |
newSeconds[second] = value | |
newKerning[first] = newSeconds | |
# Make copies of the referenced groups and store them | |
# under the new names in the overall groups dictionary. | |
allRenamedGroups = list(firstRenamedGroups.items()) | |
allRenamedGroups += list(secondRenamedGroups.items()) | |
for oldName, newName in allRenamedGroups: | |
group = list(groups[oldName]) | |
groups[newName] = group | |
# Return the kerning and the groups. | |
return newKerning, groups, dict(side1=firstRenamedGroups, side2=secondRenamedGroups) | |
def findKnownKerningGroups(groups): | |
""" | |
This will find kerning groups with known prefixes. | |
In some cases not all kerning groups will be referenced | |
by the kerning pairs. The algorithm for locating groups | |
in convertUFO1OrUFO2KerningToUFO3Kerning will miss these | |
unreferenced groups. By scanning for known prefixes | |
this function will catch all of the prefixed groups. | |
These are the prefixes and sides that are handled: | |
@MMK_L_ - side 1 | |
@MMK_R_ - side 2 | |
>>> testGroups = { | |
... "@MMK_L_1" : None, | |
... "@MMK_L_2" : None, | |
... "@MMK_L_3" : None, | |
... "@MMK_R_1" : None, | |
... "@MMK_R_2" : None, | |
... "@MMK_R_3" : None, | |
... "@MMK_l_1" : None, | |
... "@MMK_r_1" : None, | |
... "@MMK_X_1" : None, | |
... "foo" : None, | |
... } | |
>>> first, second = findKnownKerningGroups(testGroups) | |
>>> sorted(first) == ['@MMK_L_1', '@MMK_L_2', '@MMK_L_3'] | |
True | |
>>> sorted(second) == ['@MMK_R_1', '@MMK_R_2', '@MMK_R_3'] | |
True | |
""" | |
knownFirstGroupPrefixes = ["@MMK_L_"] | |
knownSecondGroupPrefixes = ["@MMK_R_"] | |
firstGroups = set() | |
secondGroups = set() | |
for groupName in list(groups.keys()): | |
for firstPrefix in knownFirstGroupPrefixes: | |
if groupName.startswith(firstPrefix): | |
firstGroups.add(groupName) | |
break | |
for secondPrefix in knownSecondGroupPrefixes: | |
if groupName.startswith(secondPrefix): | |
secondGroups.add(groupName) | |
break | |
return firstGroups, secondGroups | |
def makeUniqueGroupName(name, groupNames, counter=0): | |
# Add a number to the name if the counter is higher than zero. | |
newName = name | |
if counter > 0: | |
newName = "%s%d" % (newName, counter) | |
# If the new name is in the existing group names, recurse. | |
if newName in groupNames: | |
return makeUniqueGroupName(name, groupNames, counter + 1) | |
# Otherwise send back the new name. | |
return newName | |
def test(): | |
""" | |
No known prefixes. | |
>>> testKerning = { | |
... "A" : { | |
... "A" : 1, | |
... "B" : 2, | |
... "CGroup" : 3, | |
... "DGroup" : 4 | |
... }, | |
... "BGroup" : { | |
... "A" : 5, | |
... "B" : 6, | |
... "CGroup" : 7, | |
... "DGroup" : 8 | |
... }, | |
... "CGroup" : { | |
... "A" : 9, | |
... "B" : 10, | |
... "CGroup" : 11, | |
... "DGroup" : 12 | |
... }, | |
... } | |
>>> testGroups = { | |
... "BGroup" : ["B"], | |
... "CGroup" : ["C"], | |
... "DGroup" : ["D"], | |
... } | |
>>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning( | |
... testKerning, testGroups, []) | |
>>> expected = { | |
... "A" : { | |
... "A": 1, | |
... "B": 2, | |
... "public.kern2.CGroup": 3, | |
... "public.kern2.DGroup": 4 | |
... }, | |
... "public.kern1.BGroup": { | |
... "A": 5, | |
... "B": 6, | |
... "public.kern2.CGroup": 7, | |
... "public.kern2.DGroup": 8 | |
... }, | |
... "public.kern1.CGroup": { | |
... "A": 9, | |
... "B": 10, | |
... "public.kern2.CGroup": 11, | |
... "public.kern2.DGroup": 12 | |
... } | |
... } | |
>>> kerning == expected | |
True | |
>>> expected = { | |
... "BGroup": ["B"], | |
... "CGroup": ["C"], | |
... "DGroup": ["D"], | |
... "public.kern1.BGroup": ["B"], | |
... "public.kern1.CGroup": ["C"], | |
... "public.kern2.CGroup": ["C"], | |
... "public.kern2.DGroup": ["D"], | |
... } | |
>>> groups == expected | |
True | |
Known prefixes. | |
>>> testKerning = { | |
... "A" : { | |
... "A" : 1, | |
... "B" : 2, | |
... "@MMK_R_CGroup" : 3, | |
... "@MMK_R_DGroup" : 4 | |
... }, | |
... "@MMK_L_BGroup" : { | |
... "A" : 5, | |
... "B" : 6, | |
... "@MMK_R_CGroup" : 7, | |
... "@MMK_R_DGroup" : 8 | |
... }, | |
... "@MMK_L_CGroup" : { | |
... "A" : 9, | |
... "B" : 10, | |
... "@MMK_R_CGroup" : 11, | |
... "@MMK_R_DGroup" : 12 | |
... }, | |
... } | |
>>> testGroups = { | |
... "@MMK_L_BGroup" : ["B"], | |
... "@MMK_L_CGroup" : ["C"], | |
... "@MMK_L_XGroup" : ["X"], | |
... "@MMK_R_CGroup" : ["C"], | |
... "@MMK_R_DGroup" : ["D"], | |
... "@MMK_R_XGroup" : ["X"], | |
... } | |
>>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning( | |
... testKerning, testGroups, []) | |
>>> expected = { | |
... "A" : { | |
... "A": 1, | |
... "B": 2, | |
... "public.kern2.CGroup": 3, | |
... "public.kern2.DGroup": 4 | |
... }, | |
... "public.kern1.BGroup": { | |
... "A": 5, | |
... "B": 6, | |
... "public.kern2.CGroup": 7, | |
... "public.kern2.DGroup": 8 | |
... }, | |
... "public.kern1.CGroup": { | |
... "A": 9, | |
... "B": 10, | |
... "public.kern2.CGroup": 11, | |
... "public.kern2.DGroup": 12 | |
... } | |
... } | |
>>> kerning == expected | |
True | |
>>> expected = { | |
... "@MMK_L_BGroup": ["B"], | |
... "@MMK_L_CGroup": ["C"], | |
... "@MMK_L_XGroup": ["X"], | |
... "@MMK_R_CGroup": ["C"], | |
... "@MMK_R_DGroup": ["D"], | |
... "@MMK_R_XGroup": ["X"], | |
... "public.kern1.BGroup": ["B"], | |
... "public.kern1.CGroup": ["C"], | |
... "public.kern1.XGroup": ["X"], | |
... "public.kern2.CGroup": ["C"], | |
... "public.kern2.DGroup": ["D"], | |
... "public.kern2.XGroup": ["X"], | |
... } | |
>>> groups == expected | |
True | |
>>> from .validators import kerningValidator | |
>>> kerningValidator(kerning) | |
(True, None) | |
Mixture of known prefixes and groups without prefixes. | |
>>> testKerning = { | |
... "A" : { | |
... "A" : 1, | |
... "B" : 2, | |
... "@MMK_R_CGroup" : 3, | |
... "DGroup" : 4 | |
... }, | |
... "BGroup" : { | |
... "A" : 5, | |
... "B" : 6, | |
... "@MMK_R_CGroup" : 7, | |
... "DGroup" : 8 | |
... }, | |
... "@MMK_L_CGroup" : { | |
... "A" : 9, | |
... "B" : 10, | |
... "@MMK_R_CGroup" : 11, | |
... "DGroup" : 12 | |
... }, | |
... } | |
>>> testGroups = { | |
... "BGroup" : ["B"], | |
... "@MMK_L_CGroup" : ["C"], | |
... "@MMK_R_CGroup" : ["C"], | |
... "DGroup" : ["D"], | |
... } | |
>>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning( | |
... testKerning, testGroups, []) | |
>>> expected = { | |
... "A" : { | |
... "A": 1, | |
... "B": 2, | |
... "public.kern2.CGroup": 3, | |
... "public.kern2.DGroup": 4 | |
... }, | |
... "public.kern1.BGroup": { | |
... "A": 5, | |
... "B": 6, | |
... "public.kern2.CGroup": 7, | |
... "public.kern2.DGroup": 8 | |
... }, | |
... "public.kern1.CGroup": { | |
... "A": 9, | |
... "B": 10, | |
... "public.kern2.CGroup": 11, | |
... "public.kern2.DGroup": 12 | |
... } | |
... } | |
>>> kerning == expected | |
True | |
>>> expected = { | |
... "BGroup": ["B"], | |
... "@MMK_L_CGroup": ["C"], | |
... "@MMK_R_CGroup": ["C"], | |
... "DGroup": ["D"], | |
... "public.kern1.BGroup": ["B"], | |
... "public.kern1.CGroup": ["C"], | |
... "public.kern2.CGroup": ["C"], | |
... "public.kern2.DGroup": ["D"], | |
... } | |
>>> groups == expected | |
True | |
""" | |
if __name__ == "__main__": | |
import doctest | |
doctest.testmod() | |