Switching to class-based kerning

I'm working on a font which is already largely kerned, using table-based kerning. The main problem, besides the inefficiency with regards to the storage of the kerning of accented glyphs (with which I am not hugely concerned) is that there are many accented glyphs which are not kerned like their base glyphs. This is an obvious use-case for class-based kerning. Right now, I have tried to redo the kerning manually in a class-based fashion in FontForge (this font is developed in FontForge). This, however, is tedious, and if possible, I'd like to avoid it. Is there any way to automatically convert a font's kerning from a table to class-based kerning? (I am willing to have it begin by naïvely putting /A and /Aacute in different classes, etc.; I'd just like to be able to import the pair-based kerning into a class-based kerning feature so I can edit it as classes in FontForge). I would strongly prefer a free and open-source solution for this problem if one exists, but I am happy to hear all suggestions. I've scoured the web for some guidance, but my Google-fu didn't provide me with any solid answers (though I did see some mentions of this problem). Anybody have any tips?

Comments

  • Kent Lew
    Kent Lew Posts: 944
    I’ve written a suite of scripts to assist in this kind of conversion when I’ve been tasked with updating legacy fonts before. The results depend upon the consistency and quality of the original font data, of course. Making such a conversion fool-proof and getting optimal results is non-trivial.
    I don’t know if there are more recent tools that have incorporated routines to do this (Glyphs or FontLab VI, for example). Others will know.
    I’m not in a position to share my tools, since they’re built upon some proprietary bits. But if another, readily available option does not emerge, contact me privately and I might be willing to do a conversion for you, gratis, if the source material is suitable and depending upon my availability.
    Or, if you’re an ambitious coder, I could try to walk you through some of the logic (although that might take even more time. ;-)
  • Fair enough — I do realize that there are some inherent difficulties in converting from table to class (though the reverse is simple enough, of course). I think there was some script to do it with FF as well but this must be 10+ years old now …
  • To be clear, I am not looking to actually produce real classes in a smart way. I just want to convert the format of the kerning. I expect the output to be all one-character classes which I'd then combine manually (which I can already do).
  • Kent Lew
    Kent Lew Posts: 944
    If you really just want one-character classes, then that seems relatively trivial to convert.
    For the classes, just write a script that takes a glyph name and makes a class name based on that (with the whatever relevant prefix you might be necessary; I’m unfamiliar with FontForge) and defines that class with the corresponding single member.
    And then for the kerning, write a script that takes each left class and loops through the kerning pairs and replaces each relevant left glyph reference with the corresponding left class reference. And the same for right classes.
    But this does not seem like a very valuable conversion to me. On the other hand, I am unfamiliar with the tools that FontForge offers for combining classes manually and updating corresponding kerning. Sounds awfully tedious (and fraught with potential mischief) to me.
  • Daniel Benjamin Miller
    edited August 2019
    I've already figured out which characters need to go in which class manually (i.e., which characters should kern the same way as /A, /C, etc.). I can write that script too, I was just wondering if there were already such a script out there. Maybe it's trivial. Anyway I'll only do this tomorrow for time reasons.

    In this case, I have already /A, which in all cases kerns the same way as /Aring for example. And I will combine these and no kerning will change. But I will also add a character which SHOULD kern this way but isn't kerned at all in the current table (A with ring and acute). Etc.
  • Kent Lew
    Kent Lew Posts: 944
    And I will combine these and no kerning will change.

    This is confusing to me. And, again, I am at a disadvantage because I am not familiar with how FontForge handles class kerning.

    When you have /A in its own class and you have /Aring in its own class and you have kern pairs associated with both of these classes, and then you combine the two classes into a single class, then the kern pairs for the subsumed class need to be eliminated.

    So, kerning data will need to change (even if the resulting computed kerning in the rendered font doesn’t change in value).

    Or did you mean something else?

  • Kent Lew said:
    And I will combine these and no kerning will change.

    This is confusing to me. And, again, I am at a disadvantage because I am not familiar with how FontForge handles class kerning.

    When you have /A in its own class and you have /Aring in its own class and you have kern pairs associated with both of these classes, and then you combine the two classes into a single class, then the kern pairs for the subsumed class need to be eliminated.

    So, kerning data will need to change (even if the resulting computed kerning in the rendered font doesn’t change in value).

    Or did you mean something else?

    Sorry if I was unclear. What I mean is that the result doesn't change.
  • Ah, okay.
    Maybe what you meant, then, when you said, “I expect the output to be all one-character classes which I'd then combine manually (which I can already do)” is that you just needed the kerning to be converted to classes with classes only consisting of the base member, and you would add the additional members manually later.
    But, in fact, that would not be a practical approach to conversion, in my opinion.
    Without identifying the class membership beforehand, you run the risk of losing exceptions if you delete all others. Or you end up with a bunch of destined-to-become-redundant pairs that need to be found and eliminated later.
    Unless, perhaps FontForge’s class kerning manager is robust enough to present options when expanding classes?
    If you have the single-member class @L_A: ['A'] and the kern pairs
        @L_A C -25
        Aring C -25
    and then you go to add Aring to the @L_A class, will FontForge then ask you what you want to do with the existing Aring C pair? (MetricsMachine does something like that.)
  • Kent Lew
    Kent Lew Posts: 944
    edited September 2019
    I think a more efficient approach starts by evaluating and constructing the classes; then identifying which flat pairs should lend their values to new class-based pairs; and then evaluating all pairs and eliminating those that have been made redundant by the new class pairs, retaining the exceptions.
    If you’ve already assembled class lists, then that streamlines the first step.
    In my tool, I utilize an analysis based on a reverse component map to identify those that are candidates for combining into classes.
    Of course, this requires the accented glyphs to be composites of component glyphs. But I had already made a tool to take decomposed outlines and recompose them into composites where appropriate.
    One could approach this also from the standpoint of Unicode decomposition rules, but that makes certain assumptions about glyph shapes which I considered risky for the data I was working with at that time.
    Neither of these approaches to generating “smart” classes is fool-proof. Both will miss typical candidates for classifying (like ae). The component-map approach will miss certain candidates, while the Unicode-decomp approach may well add inappropriate candidates. The i classes are typically problematic and require manual intervention. Etcetera.