Best way to remove glyph from RFont?



  • Maybe a stupid question,
    But I'm not sure:
    is this a "proper" way to do that?

    glyphname = "a"
    f = CurrentFont()
    f.removeGlyph(glyphname)
    

    I'm asking this question because I'm not sure if it will remove the glyph "a" form all of the font's data(like components, kerning groups, kerning etc?)

    Thanks in advance



  • Rafał — the bottom of this page has a few code snippets that show how to remove the glyph from the font, kerning, and groups. I just rewrote them all into one script.

    C


  • admin

    the glyph can appear in the OpenType features code too – that’s a bit harder to solve with a script. simply removing it can break isometry between substitution classes, and the features will not compile.

    see also: feaPyFoFum


  • admin

    and here’s how to remove all components of a given glyph:

    font = CurrentFont()
    
    glyphName = 'a'
    
    for glyph in font:
        if not glyph.components:
            continue
        for component in glyph.components:
            if component.baseGlyph == glyphName:
                glyph.removeComponent(component)
                glyph.markColor = 1, 0, 0, 0.3
    

  • admin

    small note: removeGlyph is deprecated use: del font["a"]

    This does not remove the glyph from kerning or groups. The UFO spec allows to have group and kerning without having the glyph available in the UFO.



  • I found that the the "remove from groups" script listed on the "Adding and Removing glyphs" page didn't quite work, because you cannot directly remove an item from a tuple, and groups are tuples.

    Instead, I needed to first convert the group tuple to a list, remove the glyph, and convert back to a tuple.

    # iterate over all groups in the font
        for groupName in f.groups.keys():
    
            # get the group
            group = f.groups[groupName]
            groupList = list(f.groups[groupName])
    
            # if glyph is in the group, remove it
            if glyphName in group:
                print('removing %s from group %s...' % (glyphName, groupName))
                groupList.remove(glyphName)
                f.groups[groupName] = tuple(groupList)
    

    Please correct me if I'm wrong about this, but it was erroring for me earlier, and seems to work well now.

    It would also be worth updating that piece of the docs to reflect Frederick's latest comment about del font[glyphName].



  • Actually, I'm finding that the glyph "placeholders" still hang around after I've gone through the steps in the docs to remove them from font, groups, kerning, and components.

    21a3153a-0b69-4f11-a1a4-ecc2120bd795-image.png

    Where do these glyphs come from, and how can I properly remove them?


  • admin

    You should also remove them from font.glyphOrder RoboFont builds up the template (placeholder) glyphs from a given glyph order.


  • admin

    @ThunderNixon ✔︎ docs updated. thanks for your comments!



  • @frederik Awesome, thanks!



  • @frederik

    also remove them from font.glyphOrder

    Strangely, my script is able to remove most of the glyphs I ask it to, but it misses a few in glyphOrder. Can you see what I'm doing wrong here?

    (The script below removes all lowercase glyphs in a font, but misses b d h n p r u v w lslash)

    f = CurrentFont()
    
    # copy space-separated glyph names here
    glyphsToRemove = "a agrave aacute acircumflex atilde adieresis aring amacron abreve aogonek b c ccedilla cacute ccircumflex cdotaccent ccaron d dcaron e egrave eacute ecircumflex edieresis emacron ebreve edotaccent eogonek ecaron f g gcircumflex gbreve gdotaccent gcommaaccent h hcircumflex i igrave iacute icircumflex idieresis itilde imacron ibreve iogonek j jcircumflex k kcommaaccent l lacute lcommaaccent lcaron m n ntilde nacute ncommaaccent ncaron o ograve oacute ocircumflex otilde odieresis omacron obreve ohungarumlaut p q r racute rcommaaccent rcaron s sacute scircumflex scedilla scaron scommaaccent t tcommaaccent tcaron u ugrave uacute ucircumflex udieresis utilde umacron ubreve uring uhungarumlaut uogonek v w wcircumflex wgrave wacute wdieresis x y yacute ydieresis ycircumflex ygrave z zacute zdotaccent zcaron ae eth oslash thorn dcroat hbar ij ldot lslash eng oe tbar"
    
    # clean up the rest of the data
    for glyphToRemove in glyphsToRemove.split(" "):
    
        # remove from keys
        if glyphToRemove in f.keys():
            del f[glyphToRemove]
    
        # remove from glyphOrder 
        for glyphName in f.glyphOrder:
            if glyphName == glyphToRemove:
                del f.glyphOrder[glyphName]
    
        # GROUPS ------------------------------------------------------------
    
        # iterate over all groups in the font
        for groupName in f.groups.keys():
    
            # get the group
            group = f.groups[groupName]
            groupList = list(f.groups[groupName])
    
            # if glyph is in the group, remove it
            if glyphToRemove in group:
                print('removing %s from group %s...' % (glyphToRemove, groupName))
                groupList.remove(glyphToRemove)
                f.groups[groupName] = tuple(groupList)
    
        # KERNING -----------------------------------------------------------
    
        # iterate over all kerning pairs in the font
        for kerningPair in f.kerning.keys():
    
            # if glyph is in the kerning pair, remove it
            if glyphToRemove in kerningPair:
                print('removing kerning pair (%s, %s)...' % kerningPair)
                del f.kerning[kerningPair]
    
        # COMPONENTS --------------------------------------------------------
    
        # iterate over all glyphs in the font
        for glyph in f:
    
            # skip glyphs which don’t have components
            if not glyph.components:
                continue
    
            # iterate over all components in glyph
            for component in glyph.components:
    
                # if the base glyph is the glyph to be removed
                if component.baseGlyph == glyphToRemove:
                    # delete the component
                    glyph.removeComponent(component)
    
    


  • Actually, hmm. I'm finding that the script in the docs for removing-glyphs-from-kerning doesn't seem to be removing kern pairs.

    For example, this is failing to remove data around the a kerning:

    font = CurrentFont()
    
    # the glyph to be removed
    glyphName = 'a'
    
    # iterate over all kerning pairs in the font
    for kerningPair in font.kerning.keys():
    
        # if the glyph is in the kerning pair:
        if glyphName in kerningPair:
    
            # remove the kerning pair
            print('removing kerning pair (%s, %s)...' % kerningPair)
            del font.kerning[kerningPair]
    

    Even after running that, I still have all of the kern1 and kern2 data from a in the UFO.


  • admin

    don’t change the font.glyphOrder inside a loop, mainly as the glyphOrder is not the actual list you are editing but a copy of it.

    glyphOrder = font.glyphOrder
    
    for glyphName in glyphsToRemove.split:
    
        if glyphName in glyphOrder:
            glyphOrder.remove(glyphName)
    
    font.glyphOrder = glyphOrder
    

  • admin

    and I cannot reproduce the kerning issue...
    are you sure the 'a' is not in some group kerning?