In reading the documentation, it appears that KernOn strategically decides which kern pair is the "default" based on the most common value.
However, I often find that KernOn makes a mistake in setting the default kerning for a pair based on pairs that are not present in the corpora.
For example, I have a kern group "UC_A" which, when paired with "UC_J", has 7 pairs with a negative kern applied, and 31 absent kerns (due to not being present in the corpora). As a result, the default kern assigned to the UC_A/UC_J group is "0".
However, my sense is that /A/J should be the defining glyphs for the default. In my case, it is -85. So that should become the default kern value assigned to the kern class.
IMO, there are two potential solutions.
1) Allow for a default glyph to be set in each kern group. This would be used as the default kern value for the entire group and all exceptions would be set against that value.
2) Non-corpora pairs should be ignored during the optimization stage of the KernOn process. Perhaps by setting the kern value to Null / None. This way those pairs will use the default class kern value rather than just 0.
Key glyph for a kern pair / ignore non-corpora pairs
- Tim Ahrens
- Site Admin
- Posts: 474
- Joined: 11 Jul 2019
Re: Key glyph for a kern pair / ignore non-corpora pairs
It’s a bit difficult to tell without seeing the font.
First, it seems you are using manual kerning groups?
Are you sure you need a kerning group for the left side of the J (I assume /J and /Jcircumflex)? It may be better to leave it away.
Generally, I believe the way forward is rather to adjust the automatic class kerning so that it is closer to kerning groups set by humans. I don’t even think manual kerning groups are the way to go, I just added this possibility so as to please some users who really want it, and because it was fairly easy to implement (both in the engine and the UI). Stay tuned!
First, it seems you are using manual kerning groups?
Are you sure you need a kerning group for the left side of the J (I assume /J and /Jcircumflex)? It may be better to leave it away.
It would be easy to completely ignore all pairs that are not in the corpora (i.e. non-existing pairs). In fact, that would make the class kerning generation faster and more efficient. If we say, the resulting kerning for non-existing pairs is completely irrelevant then the algorithm could even auto-create groups with glyphs that have completely different shapes, by merging groups that have no pairs in common. Under that premise, that would be very efficient, even if it may lead to really nonsensical pairs. I am concerned about creating implicit pairs, though. We cannot be sure that the non-existing pairs will really never occur, and I don’t want to take too much of a risk of generating completely wrong pairs. This is probably the reason why the algorithm picks 0 as the class-class value. If you want you can send me the font, then I can check more thoroughly.
This is an interesting idea, it would allow for even more manual intervention than allowing for manually set kerning groups. I am pretty sure that it would generally lead to less efficient kerning, though. More importantly, the added UI complexity would be significant. As a user, I certainly wouldn’t want to maintain this data on top of everything else.
Generally, I believe the way forward is rather to adjust the automatic class kerning so that it is closer to kerning groups set by humans. I don’t even think manual kerning groups are the way to go, I just added this possibility so as to please some users who really want it, and because it was fairly easy to implement (both in the engine and the UI). Stay tuned!
Re: Key glyph for a kern pair / ignore non-corpora pairs
> First, it seems you are using manual kerning groups?
Yes. I have my own kern groups set because I found that the auto kern groups would often create more groups than I felt were necessary to achieve good results. So in an effort to reduce the footprint of the class-class kern mapping, I merged some groups together, allowing variation via exceptions. For example, I find that it beneficial for /a and the accented /a glyphs to be in separate groups, but I don't find that /u and the accented /u need to be in separate groups because the width of the letter ensures that the default /u kern is sufficient in a vast majority of scenarios.
The reason why I have a kern group for the left side of the /J is like you said—there's multiple letters (/J ,/Jcircumflex, /Jacute) which will need a kern against letters like /V and /W, so might as well group them together to ensure that all of them are treated equivalently. The same issue would occur with the /A variants against all the /T variants.
> I am concerned about creating implicit pairs, though. We cannot be sure that the non-existing pairs will really never occur, and I don’t want to take too much of a risk of generating completely wrong pairs. This is probably the reason why the algorithm picks 0 as the class-class value.
Interesting. I actually think about it the opposite way. It feels to me that the current approach distrusts the accuracy of the kern group membership and says that if there's no kern data available, it is better to set the kern to 0 than to trust that the glyph is in the right group.
However, if we assume that our kern groups (whether auto generated, or manual assigned) are good and can be trusted, then all glyphs within that kern group should perform similarly against the same glyph (or class).
/A/W should perform similarly to /Ẫ/Ẅ, right? However, the latter, being non-corpora, is assigned a 0 whereas the former is assigned a -233. The only way, then, to get KernOn to understand that the default value for the /A/W class kerns should be -233 is to go in and manually set the kern to "auto" for all members of the group. As you can expect from a font with broad Latin coverage, there's a *lot* of members of the UC_A group and they overpower the corpora glyphs in almost every scenario:
AÁĂẮẶẰẲẴÂẤẬẦẨẪÄẠÀẢĀĄÅǺÃ
> This is an interesting idea, it would allow for even more manual intervention than allowing for manually set kerning groups. I am pretty sure that it would generally lead to less efficient kerning, though. More importantly, the added UI complexity would be significant. As a user, I certainly wouldn’t want to maintain this data on top of everything else.
That's fair. I'm not against the way that KernOn is determining efficient kerning (in fact, it makes sense if you have 1 glyph that is at -40 and 10 at -100 to make -100 the default!), I just don't want the overwhelming set of /0s to determine the default kern value!
>Generally, I believe the way forward is rather to adjust the automatic class kerning so that it is closer to kerning groups set by humans. I don’t even think manual kerning groups are the way to go, I just added this possibility so as to please some users who really want it, and because it was fairly easy to implement (both in the engine and the UI). Stay tuned!
It would be interesting (at some later point when I'm not under deadline stress :) ) to test the number of kern classes generated by KernOn versus the ones I manually set and see which is more efficient. I am not sure which would be the winner.
But like I said before, I think that there should be more trust in the quality of the kern groups and to ignore the non-corpora pairs entirely. If they are of such rarity to not warrant a pair, then they shouldn't affect the default kern class created. And as a fallback, if there's a kern group created that somehow only has non-corpora members (unlikely, but possible?) then that default can be 0.
Not to put pressure on you, but this issue is the final blocker preventing me from finishing this font project, so I'd definitely be interested a resolution! :D
Yes. I have my own kern groups set because I found that the auto kern groups would often create more groups than I felt were necessary to achieve good results. So in an effort to reduce the footprint of the class-class kern mapping, I merged some groups together, allowing variation via exceptions. For example, I find that it beneficial for /a and the accented /a glyphs to be in separate groups, but I don't find that /u and the accented /u need to be in separate groups because the width of the letter ensures that the default /u kern is sufficient in a vast majority of scenarios.
The reason why I have a kern group for the left side of the /J is like you said—there's multiple letters (/J ,/Jcircumflex, /Jacute) which will need a kern against letters like /V and /W, so might as well group them together to ensure that all of them are treated equivalently. The same issue would occur with the /A variants against all the /T variants.
> I am concerned about creating implicit pairs, though. We cannot be sure that the non-existing pairs will really never occur, and I don’t want to take too much of a risk of generating completely wrong pairs. This is probably the reason why the algorithm picks 0 as the class-class value.
Interesting. I actually think about it the opposite way. It feels to me that the current approach distrusts the accuracy of the kern group membership and says that if there's no kern data available, it is better to set the kern to 0 than to trust that the glyph is in the right group.
However, if we assume that our kern groups (whether auto generated, or manual assigned) are good and can be trusted, then all glyphs within that kern group should perform similarly against the same glyph (or class).
/A/W should perform similarly to /Ẫ/Ẅ, right? However, the latter, being non-corpora, is assigned a 0 whereas the former is assigned a -233. The only way, then, to get KernOn to understand that the default value for the /A/W class kerns should be -233 is to go in and manually set the kern to "auto" for all members of the group. As you can expect from a font with broad Latin coverage, there's a *lot* of members of the UC_A group and they overpower the corpora glyphs in almost every scenario:
AÁĂẮẶẰẲẴÂẤẬẦẨẪÄẠÀẢĀĄÅǺÃ
> This is an interesting idea, it would allow for even more manual intervention than allowing for manually set kerning groups. I am pretty sure that it would generally lead to less efficient kerning, though. More importantly, the added UI complexity would be significant. As a user, I certainly wouldn’t want to maintain this data on top of everything else.
That's fair. I'm not against the way that KernOn is determining efficient kerning (in fact, it makes sense if you have 1 glyph that is at -40 and 10 at -100 to make -100 the default!), I just don't want the overwhelming set of /0s to determine the default kern value!
>Generally, I believe the way forward is rather to adjust the automatic class kerning so that it is closer to kerning groups set by humans. I don’t even think manual kerning groups are the way to go, I just added this possibility so as to please some users who really want it, and because it was fairly easy to implement (both in the engine and the UI). Stay tuned!
It would be interesting (at some later point when I'm not under deadline stress :) ) to test the number of kern classes generated by KernOn versus the ones I manually set and see which is more efficient. I am not sure which would be the winner.
But like I said before, I think that there should be more trust in the quality of the kern groups and to ignore the non-corpora pairs entirely. If they are of such rarity to not warrant a pair, then they shouldn't affect the default kern class created. And as a fallback, if there's a kern group created that somehow only has non-corpora members (unlikely, but possible?) then that default can be 0.
Not to put pressure on you, but this issue is the final blocker preventing me from finishing this font project, so I'd definitely be interested a resolution! :D
- Tim Ahrens
- Site Admin
- Posts: 474
- Joined: 11 Jul 2019
Re: Key glyph for a kern pair / ignore non-corpora pairs
Thanks for your detailed comments, this is getting rather interesting. This whole subject of class kerning is a really complex and potentially messy task even though one might expect it to be well-suited for an algorithm.
After the exchange today, I feel there are two approaches to class kerning:
After the exchange today, I feel there are two approaches to class kerning:
- Setting the kerning classes based on glyph shapes. This is what humans usually do. As a result, implicit pairs can be considered an opportunity, not a risk, as they add sensible support for additional glyph-glyph pairs that are not in the corpus. Picking the class kerning value should to be done carefully, of course, but it is less of a hairy subject.
- Considering class kerning to be purely data compression. This is the approach I took with Kern On but it may change. Kern On does not look at the shapes at all during this final phase. The assumption is that shape similarity is expressed through similar kerning values, and I may have been a bit too optimistic there. If data compression is the main reasoning, and the whole algorithm is built for that, we can get rather impressive results in terms of what it can fit into the given kB size, as the computer makes better decisions than the human could do, as it strictly calculates the data size used by different options. The big downside seems to be that implicit pairs have to be considered a risk, not an opportunity, which may lead to class kerning values that humans would recognize as non-optimal. (I’d still be interested in seeing your original example with A and J myself, so as to better understand what is going on. Maybe it even turns out to be a small slip in the code that can be fixed.)
Re: Key glyph for a kern pair / ignore non-corpora pairs
Thanks Tim. I think you might be over-complicating things, though.
For scenarios where Kern-On is generating the class kerning, it makes sense to take a pure data-compression approach to establishing the default kern classes. No human is reviewing the class kerns in such detail, so whatever is the most efficient is the best way to go. I do think it would be good to incorporate glyph shape-based decisions that see non-corpora pairs as opportunities, but that is not a requirement in the short term. You can pursue it in your own time.
However, for scenarios where the existing designers' class kerns are preserved (like my situation), I think that taking an approach that optimizes for corpora kerns and sees non-corpora kerns as opportunities (by ignoring them) is the better approach. It assumes that the designer has made the right decision as to how to set the class kerns and sets the defaults from there. And if there's bad decisions made, they will become obvious & corrected during a kern review and will be fixed before the font is finalized.
Obviously I don't have access to your code, but I think it could be relatively straightforward to essentially add an alternate optimization path to ignore non-corpora pairs (essentially treating them as "auto") when building the finalized kerning.
Anyway, if you can't get to it for a few days, that would be fine, but I do need a solution soon. Either in the way I've suggested, or somehow being able to set all kern pairs in the font to be "auto" to bypass the problem.
For scenarios where Kern-On is generating the class kerning, it makes sense to take a pure data-compression approach to establishing the default kern classes. No human is reviewing the class kerns in such detail, so whatever is the most efficient is the best way to go. I do think it would be good to incorporate glyph shape-based decisions that see non-corpora pairs as opportunities, but that is not a requirement in the short term. You can pursue it in your own time.
However, for scenarios where the existing designers' class kerns are preserved (like my situation), I think that taking an approach that optimizes for corpora kerns and sees non-corpora kerns as opportunities (by ignoring them) is the better approach. It assumes that the designer has made the right decision as to how to set the class kerns and sets the defaults from there. And if there's bad decisions made, they will become obvious & corrected during a kern review and will be fixed before the font is finalized.
Obviously I don't have access to your code, but I think it could be relatively straightforward to essentially add an alternate optimization path to ignore non-corpora pairs (essentially treating them as "auto") when building the finalized kerning.
Anyway, if you can't get to it for a few days, that would be fine, but I do need a solution soon. Either in the way I've suggested, or somehow being able to set all kern pairs in the font to be "auto" to bypass the problem.
- Tim Ahrens
- Site Admin
- Posts: 474
- Joined: 11 Jul 2019
Re: Key glyph for a kern pair / ignore non-corpora pairs
I doubt we will get a very quick solution within a few days.
Maybe you can send me the file with the original example of A and J? Then I can better understand what is really happening, and maybe I can implement a quick, hard-coded tweak for you.
Maybe you can send me the file with the original example of A and J? Then I can better understand what is really happening, and maybe I can implement a quick, hard-coded tweak for you.
- Tim Ahrens
- Site Admin
- Posts: 474
- Joined: 11 Jul 2019
Re: Key glyph for a kern pair / ignore non-corpora pairs
Thank you for sending the file.
What happened is that the A has special spacing (superiors) on the right side. I assume this is not intentional? I am wondering how this happened. When you set special spacing for a letter you will get a little warning dialog so as to ensure you do not do this unintentionally.
This means that in the belly of the UC_A-UC_J class kerning pair, the A is the odd one out, this is why the value of the A-J glyph pair is not chosen as the class kerning value of UC_A-UC_J.
Setting the right side of the A to standard kerning (like the accented A’s) will lead to more consistent glyph-glyph pair values in the UC_A-UC_J class kerning pair, and you will get more sensible results. I hope the KO mechanism is not as broken as it appeared at first.
What happened is that the A has special spacing (superiors) on the right side. I assume this is not intentional? I am wondering how this happened. When you set special spacing for a letter you will get a little warning dialog so as to ensure you do not do this unintentionally.
This means that in the belly of the UC_A-UC_J class kerning pair, the A is the odd one out, this is why the value of the A-J glyph pair is not chosen as the class kerning value of UC_A-UC_J.
Setting the right side of the A to standard kerning (like the accented A’s) will lead to more consistent glyph-glyph pair values in the UC_A-UC_J class kerning pair, and you will get more sensible results. I hope the KO mechanism is not as broken as it appeared at first.