Mass renaming glyphs in fontforge with python

2023-09-02

I've got a book that I've roughly typeset in XeTeX, and out of curiosity I decided to port it to Groff. I wanted to see how similar I could get it to look and I started typesetting in MS Song since that looked like what XeTeX had picked (for this project my tex file didn't specify a font).

I soon noticed that XeTeX had used a very similar but slightly different font, Fandol Song. TeXlive had installed an OTF copy of Fandol Song at /usr/share/texlive/texmf-dist/fonts/opentype/public/fandol/FandolSong-Regular.otf, so I used the install-font.sh script from the creator of the groff mom macros to prepare it for use with Groff, but Groff complained that all of my CJK glyphs couldn't be found:

groff -mzh -Kutf8 -Tps main.tr > main.ps
troff: main.tr:12: warning: can't find special character 'u53CD'
troff: main.tr:12: warning: can't find special character 'u5012'
troff: main.tr:12: warning: can't find special character 'u8BF4'
troff: main.tr:12: warning: can't find special character 'u662F'
troff: main.tr:12: warning: can't find special character 'u5F97'
troff: main.tr:12: warning: can't find special character 'u4E86'
troff: main.tr:12: warning: can't find special character 'u6D41'
troff: main.tr:12: warning: can't find special character 'u884C'
troff: main.tr:12: warning: can't find special character 'u6027'
troff: main.tr:12: warning: can't find special character 'u611F'
troff: main.tr:12: warning: can't find special character 'u5192'

Eventually I traced the problem down to the format of the glyph names: my other CJK fonts seem to use a glyph name like "uni4E86" for the glyph representing unicode codepoint U+4E86 (了), whereas TeX's FandolSong file had a glyph name like "GB1.2580", with 2580 corresponding to the Character ID used for 了 in the Adobe-GB1-6 character collection.

I'm sure this isn't the proper way to fix this, but I opted to just run a fontforge script using the python API to explicitly reset the glyph name for each character in the CJK Unified Ideographs unicode block which spans U+4E00 - U+9FFF:

myfont = fontforge.open("/usr/share/texlive/texmf-dist/fonts/opentype/public/fandol/FandolSong-Regular.otf")
sel = myfont.selection.all()

for glyph in sel.byGlyphs:
  if 0x4e00 <= glyph.unicode <= 0x9fff:
    glyph.glyphname = f"uni{glyph.unicode:04X}"

myfont.save("/tmp/FandolSongR.ttf")

Useful links: