Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kerning group exceptions bug in Kernschmelze #10

Open
arialcrime opened this issue Feb 13, 2017 · 6 comments
Open

Kerning group exceptions bug in Kernschmelze #10

arialcrime opened this issue Feb 13, 2017 · 6 comments

Comments

@arialcrime
Copy link

Hello,

I have been using Kernschmelze (0.7) recently and came across the following problem:
In a 2 master setup I had the same kerning groups in both. One of the masters also included an exception for one glyph that was missing in the other. After “schmelzing” the two, I ended up with an exception in the second master too, but instead of having the standard value of the class, it has the value 0.

Is this on purpose? How would I go about to end up with the correct value in the second master?

Thanks in advance!

@Mark2Mark
Copy link
Collaborator

Hi,

Thanks for reporting.

Putting the (empty) value 0 in there is on purpose in order to make the masters compatible for interpolation. Both masters need to have any values, but part of the plugin’s job is to fill these up for you. At least that was the idea.

What would you exactly expect to happen on that particular example? What do you mean with »standard value of the class«?
Do you mean it shouldn’t come up with 0 but a certain value that the other master has set for that exception?

Did I address all your questions?

@Mark2Mark Mark2Mark self-assigned this Feb 13, 2017
@arialcrime
Copy link
Author

Hi Mark,

Thanks for the quick reply.
The basic idea of the plugin makes sense, and adding zero pairs which do not exist in a master is also very helpful to ensure master compatibility.

In the particular case, /T is kerned to a class of g-like shapes (value = -90) with the exception of /gcircumflex (value = -20) in one master. The other master also included kerning between /T and the group (-50), but does not have the exception.

The problem now is that instead of using the value from “/T to group” (-50) for the exception in the second master, it got zero as the value.

But maybe this goes beyond the concept of Kernschmelze being a helper to Kernkraft.

@Mark2Mark
Copy link
Collaborator

Mark2Mark commented Feb 13, 2017

This has actually nothing to do with being a helper to Kernkraft. They can be used independently from each other.

Anyway, for your example it cannot use the value from “/T to group” (-50), because the source master doesn’t have a “/T to group” stored for /T/gcircumflex. Hence in the target master, it doesn’t find that combination in the kerning entires and puts the zero value there.

Kerning is stored in Glyphs in four different ways:
Group—Group
NonGroup—NonGroup
NonGroup—Group
Group—NonGroup
While NonGroups are basically the exceptions. The script can only read and apply these.

Does this make sense? Or did I not understand your example properly?

@axani
Copy link

axani commented Feb 22, 2017

Hi Mark,

we dealt with this at our end and are currently trying an alogrithm, that may be interesting for this issue:

for master_index, (master_id, kerning_data) in enumerate(this_font.kerning.iteritems()):
    for left_side_raw, kerning_values in kerning_data.iteritems():
        left_side = makeNiceName(this_font, left_side_raw) # Returns glyphname or classname
        left_glyph = this_font.glyphs[left_side] if not left_side.startswith('@') else this_font.glyphs[left_side[7:]]
        if left_side not in kerning_test_dict.keys():
            # Rebuilding the kerning dict with readable names (no glyph ids)
            kerning_test_dict[left_side] = {}

        for right_side_raw, val in kerning_values.iteritems():
            right_side = makeNiceName(this_font, right_side_raw)
            # right_glyph is None when it is not a glyph, but a group
            right_glyph = this_font.glyphs[right_side] if not right_side.startswith('@') else this_font.glyphs[right_side[7:]]

            if right_side not in kerning_test_dict[left_side].keys():
                # Rebuild the right side with own data structure
                # Basically all masters will have their data at one place. Unlike the native glyphs app kerning dict 
                # At the beginning I set everything to None or 0.0. This may be overwritten later when there are actual values.
                kerning_test_dict[left_side][right_side] = {
                    'current': [None for m in this_font.masters], 
                    'recommended': [0.0 for m in this_font.masters],
                    'base_glyph': None,
                    'left_glyph': left_glyph.name,
                }
                # Use group kerning value as recommended value when it is present
                if right_glyph and right_glyph.leftKerningKey:
                    group_val = this_font.kerningForPair(master_id, left_side, right_glyph.leftKerningKey)
                    kerning_test_dict[left_side][right_side]['recommended'] = [group_val for m in this_font.masters]

            # Overwrite the None value with the actual value 
            kerning_test_dict[left_side][right_side]['current'][master_index] = val

            # If a value is 0, it is interpreted as suspicious and I look into it
            if val == 0:
                # So check if the glyph has a left kerning group that is another glyph from the font
                # Example: Ä has a 0 value but is part of the A group that has a value
                if right_glyph.leftKerningGroup and this_font.glyphs[right_glyph.leftKerningGroup]:
                    # Get Kerningvalue the baseglyph of the group the (right) glyph was found
                    recommended_value = this_font.kerningForPair(master_id, left_side, this_font.glyphs[right_glyph.leftKerningGroup].leftKerningKey)
                    kerning_test_dict[left_side][right_side]['base_glyph'] = right_glyph.leftKerningGroup
                    if recommended_value < 10000: # it is 9.22337203685e+18 if there is no kerning for kerninggroup ...
                        # ... so only add a recommended value if there is a (realistic) value
                        kerning_test_dict[left_side][right_side]['recommended'][master_index] = recommended_value
                elif right_glyph.name == right_glyph.leftKerningKey:
                    # Kerning should actually be 0 because glyph is in no group and has itself as kerning key
                    kerning_test_dict[left_side][right_side]['recommended'][master_index] = val

            else:
                # Overwrite recommended value with actual value
                kerning_test_dict[left_side][right_side]['recommended'][master_index] = val

After this I go on with this kerning_test_dict. But I guess you get the picture.

We are currently testing if this catches all problems. So let me know, if you see some issues with this snippet (or if you want to take a look at the whole script).

@carrois
Copy link
Collaborator

carrois commented Feb 22, 2017 via email

@Mark2Mark
Copy link
Collaborator

Hi @axani Filip,

Thanks for the proposal. I cannot wrap my head around the issue, since I still don’t really get the problem. If I don’t know the problem, I have difficulties to seek for / accept a solution. Can you please clarify what your attempt is? If I understand the mechanic, I am happy to merge your code.

@Mark2Mark Mark2Mark removed their assignment Feb 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants