Copying uppercase to lowercase (including kerning), and auto-add unicodes

  • I'm copying uppercase to lowercase for an all-caps font.

    So far, Glyph Construction has made this (seemingly) very easy, with a simple setup like this:

    a = A
    b = B
    c = C
    ccedilla = Ccedilla
    # etc etc

    However, the kerning isn't getting copied in this method.

    I've also found that unicodes aren't added unless I do something like this:

    a = A|0061
    aacute = Aacute|00E1
    abreve = Abreve|0103
    # etc

    But creating those recipes is a deeper can of worms, and I'm hoping there's a way to avoid excessive manual work in finding and adding those unicodes.

    This leaves me with two main questions:

    1. What might be an efficient (ideally scripted) way to copy kerning from uppercase to lowercase, including any applicable kerning data?

    2. Is there a simple way to loop through glyphs to auto-add unicodes, based on their names, OR is there a way to make Glyph Builder auto-add unicodes?

  • I used the AGL, some python string manipulations, and text editor text-selection tricks to hack my way to a better set of glyph construction recipes. So, I have a working set of unicodes as a sort of answer to question 2 from above.

    Still, I'd love to find a better way for future situations!

  • admin

    you could also try using double unicodes… it may solve 1 & 2 without any scripting.

    (ps. there’s also glyph.autoUnicodes() to generate unicodes for glyphs with AGL-names)

  • Here's a little demo script that will copy kerning.

    copyMap = {
    	"A" : "a"
    font = CurrentFont()
    # Add to kerning groups.
    side1GroupNames = font.groups.side1KerningGroups.keys()
    side2GroupNames = font.groups.side2KerningGroups.keys()
    for sourceGlyphName, destinationGlyphName in copyMap.items():
    	for groupName in font.groups.findGlyph(sourceGlyphName):
    		if groupName in side1GroupNames or groupName in side2GroupNames:
    			group = list(font.groups[groupName])
    			font.groups[groupName] = group
    # Copy kerning values.
    kerningToAdd = {}
    for (side1, side2), value in font.kerning.items():
    	if side1 not in copyMap and side2 not in copyMap:
    	side1 = copyMap.get(side1, side1)
    	side2 = copyMap.get(side2, side2)
    	kerningToAdd[side1, side2] = value

  • I would also go the dual-Unicode route.
    If you cannot do that for religious reasons, I recommend using kerning groups to combine upper- and lowercase glyphs, then you also have upper-to-lower (and vice-versa) situations covered.
    There is some caveats with i and Turkish for example. If you google "Dilemma of the Dotted i", you’ll find what I mean.

  • admin

    here’s a script to add lowercase unicodes to uppercase glyphs using glyphNameFormatter:

    from glyphNameFormatter.reader import N2n, n2u
    f = CurrentFont()
    for glyphName in f.keys():
        glyphNameLC = N2n(glyphName)
        if glyphName == glyphNameLC:
        unicodeLC = n2u(glyphNameLC)
        if unicodeLC not in f[glyphName].unicodes:
            f[glyphName].unicodes += (unicodeLC,)
        print(glyphName, f[glyphName].unicodes)

    as @frederik reminded me: for this approach to work it’s necessary to turn Release Mode ON when generating fonts. (double unicodes are added using the FDK’s GOADB file)

  • There is some amazing help in this thread – thank you, everyone!

    The double-unicode font works like a charm when exported through fontmake, then used in InDesign or dragged into Axis-Praxis. Awesome!

    @gferreira the script was extremely helpful, but it missed a few glyphs:

    Idotaccent (304,)
    Gcommaaccent (290,)
    Kcommaaccent (310,)
    Lcommaaccent (315,)
    Ncommaaccent (325,)
    Rcommaaccent (342,)

    The Idotaccent is due to the dilemma @frankrolf cited (thanks for pointing me to some good info, Frank! I'll be digging into that after kerning). However, it seems that most commaaccent glyphs might be outside the reach of the glyphNameFormatter ...

    This seems to work for adding lowercase unicodes to glyphs that your script didn't catch:

    f = CurrentFont()
    # add specific lowercase unicodes
    f['Gcommaaccent'].unicodes = f['Gcommaaccent'].unicodes + ("0123",)
    f['Kcommaaccent'].unicodes = f['Kcommaaccent'].unicodes + ("0137",)
    f['Lcommaaccent'].unicodes = f['Lcommaaccent'].unicodes + ("013C",)
    f['Ncommaaccent'].unicodes = f['Ncommaaccent'].unicodes + ("0146",)
    f['Rcommaaccent'].unicodes = f['Rcommaaccent'].unicodes + ("0157",)
    # check for single unicodes in selected glyphs (can be run separately to find single-unicode glyphs)
    for g in f.selectedGlyphNames:
        if len(f[g].unicodes) <= 1:
            print(g, f[g].unicodes)

  • @tal said in Copying uppercase to lowercase (including kerning), and auto-add unicodes:

    Here's a little demo script that will copy kerning.

    Hmm, at least initially, when run, that causes an error:

    File "lib/fontObjects/doodleKerning.pyc", line 13, in _set_dirty
    mm4.MetricsMachineError: Glyph a is in more than one side 1 group.

    For now, I'll do some (partially) manual things in MetricsMachine to sort out kerning. I'll loop back with a suggested fix if I can loop back and figure something out!