SuffixAutomator for one-to-one substitutions

Michael Rafailyk
Michael Rafailyk Posts: 165
edited March 12 in Type Design Software
Hello! Type design applications are smart enough and automatically generate most features based on character suffixes. But sometimes it is necessary to write something custom, so I wrote a small automation for this.

Features
  • Automate a substitution for an OpenType features.
  • Make a receipts for generating composites.
  • Wrap substituted characters into classes.
  • Reverse substitution direction.
  • Capitalize / decapitalization source / substituted characters.
  • Sort the characters list.
Links

SuffixAutomator in action.
Project page on GitHub with feature explanation.

Preview


Comments

  • Grzegorz Luk (gluk)
    Grzegorz Luk (gluk) Posts: 161
    edited July 2023
    nice tool!
    btw. if i can give you some advice - feature "decapitalize" is quite limited in use, because such problems occur:
      sub ae by Ae.alt;
      sub germandbls by Germandbls.alt;
    instead
      sub ae by AE.alt;
      sub germandbls by uni1E9E.alt;
    a better solution would be a "lowercase" feature using a table of names. For my own use I made one (limited to glyphs I use in my production):
    tU2L={
    'Aring':'aring',
    'uni0216':'uni0217',
    'Ograve':'ograve',
    'Uring':'uring',
    'Edieresis':'edieresis',
    'Obreve':'obreve',
    'Ccedilla':'ccedilla',
    'uni020A':'uni020B',
    'Kcommaaccent':'kcommaaccent',
    'Zdotaccent':'zdotaccent',
    'Hcircumflex':'hcircumflex',
    'Otilde':'otilde',
    'Ccaron':'ccaron',
    'Gcircumflex':'gcircumflex',
    'Oslash':'oslash',
    'Ecircumflex':'ecircumflex',
    'Uacute':'uacute',
    'Cacute':'cacute',
    'Gcaron':'gcaron',
    'Ccircumflex':'ccircumflex',
    'Dcroat':'dcroat',
    'Ecaron':'ecaron',
    'Omacron':'omacron',
    'D':'d',
    'uni0208':'uni0209',
    'Lcaron':'lcaron',
    'uni0206':'uni0207',
    'H':'h',
    'uni0204':'uni0205',
    'F':'f',
    'Ydieresis':'ydieresis',
    'L':'l',
    'uni0200':'uni0201',
    'Amacron':'amacron',
    'P':'p',
    'T':'t',
    'X':'x',
    'Aogonek':'aogonek',
    'Udieresis':'udieresis',
    'uni01F8':'uni01F9',
    'Scircumflex':'scircumflex',
    'uni0202':'uni0203',
    'Rcaron':'rcaron',
    'Agrave':'agrave',
    'Jcircumflex':'jcircumflex',
    'Umacron':'umacron',
    'Edotaccent':'edotaccent',
    'uni022E':'uni022F',
    'Egrave':'egrave',
    'Eogonek':'eogonek',
    'uni0214':'uni0215',
    'Utilde':'utilde',
    'uni0210':'uni0211',
    'uni0212':'uni0213',
    'Ntilde':'ntilde',
    'Ucircumflex':'ucircumflex',
    'Atilde':'atilde',
    'Sacute':'sacute',
    'Gcommaaccent':'gcommaaccent',
    'Ncommaaccent':'ncommaaccent',
    'Gbreve':'gbreve',
    'Zcaron':'zcaron',
    'Odieresis':'odieresis',
    'Scommaaccent':'scommaaccent',
    'Ebreve':'ebreve',
    'Acircumflex':'acircumflex',
    'uni021E':'uni021F',
    'uni021A':'uni021B',
    'uni0228':'uni0229',
    'Oslashacute':'oslashacute',
    'C':'c',
    'G':'g',
    'Imacron':'imacron',
    'Rcommaaccent':'rcommaaccent',
    'K':'k',
    'O':'o',
    'S':'s',
    'W':'w',
    'Eth':'eth',
    'Hbar':'hbar',
    'Uhungarumlaut':'uhungarumlaut',
    'Ocircumflex':'ocircumflex',
    'Igrave':'igrave',
    'Zacute':'zacute',
    'uni020E':'uni020F',
    'uni0232':'uni0233',
    'AE':'ae',
    'Dcaron':'dcaron',
    'Uogonek':'uogonek',
    'Lslash':'lslash',
    'Scaron':'scaron',
    'Ycircumflex':'ycircumflex',
    'uni01CD':'uni01CE',
    'Iacute':'iacute',
    'AEacute':'aeacute',
    'uni020C':'uni020D',
    'uni1E9E':'germandbls',
    'B':'b',
    'Iogonek':'iogonek',
    'J':'j',
    'N':'n',
    'R':'r',
    'V':'v',
    'Z':'z',
    'Idieresis':'idieresis',
    'OE':'oe',
    'Tcaron':'tcaron',
    'Nacute':'nacute',
    'Lcommaaccent':'lcommaaccent',
    'Ugrave':'ugrave',
    'uni0226':'uni0227',
    'Abreve':'abreve',
    'Racute':'racute',
    'Itilde':'itilde',
    'uni01E8':'uni01E9',
    'Yacute':'yacute',
    'Lacute':'lacute',
    'Ibreve':'ibreve',
    'uni01E2':'uni01E3',
    'Ubreve':'ubreve',
    'Gdotaccent':'gdotaccent',
    'Adieresis':'adieresis',
    'Ohungarumlaut':'ohungarumlaut',
    'uni01EA':'uni01EB',
    'Cdotaccent':'cdotaccent',
    'Scedilla':'scedilla',
    'Aacute':'aacute',
    'uni01EC':'uni01ED',
    'Icircumflex':'icircumflex',
    'uni01CF':'uni01D0',
    'Emacron':'emacron',
    'Eacute':'eacute',
    'A':'a',
    'Wcircumflex':'wcircumflex',
    'E':'e',
    'I':'i',
    'M':'m',
    'Tcedilla':'tcedilla',
    'Tbar':'tbar',
    'Q':'q',
    'U':'u',
    'Y':'y',
    'Ncaron':'ncaron',
    'uni01D1':'uni01D2',
    'uni01D3':'uni01D4',
    'Oacute':'oacute',
    'Thorn':'thorn',
    'Wgrave':'wgrave',
    'Wacute':'wacute',
    'Wdieresis':'wdieresis',
    'uni1E86':'uni1E87',
    'uni1E8E':'uni1E8F',
    'uni1EBC':'uni1EBD',
    'Ygrave':'ygrave',
    'uni1EF8':'uni1EF9',
    'uni01F4':'uni01F5',
    'Ldot':'ldot',
    'IJ':'ij',
    'Tcommaaccent':'tcommaaccent',
    'uni1E88':'uni1E89'
    }
  • Michael Rafailyk
    Michael Rafailyk Posts: 165
    edited July 2023
    @Grzegorz Luk (gluk) it's a good point, thank you!

    Just upload an update. I cover it using exceptions.
    If the first two letters of the character name is AE OE IJ NJ (in both lower and upper cases) the first two letters both will be converted.
    If the first three letters of the character name is uni or UNI, the conversion doesn't happens.

    This is how capitalize and decapitalize now works with exceptions (I marked them with red):

  • Michael Rafailyk
    Michael Rafailyk Posts: 165
    edited July 2023
    @Grzegorz Luk (gluk) I also noticed that your table cover case conversion on the Unicode level like from uni021A to uni021B.

    Interesting. It's really a bit more difficult to implement, however it's also possible with a few numeral and alphabetic rules. Not sure if I will implement it, because developers usually use friendly glyph names.

    Also, most type design application do it all automatically, covering correct unicode name conversion. So this tool is for some non-standard decisions when type design application can't handle with your non-standard suffix.
  • ... I also noticed that your table cover case conversion on the Unicode level like from uni021A to uni021B....developers usually use friendly glyph names...

    as I mentioned above, my solution is very custom to my production, for some glyphs I use uniXXXX names, like uni1E9E - LATIN CAPITAL LETTER SHARP S (lowercase is germandbls)
  • Michael Rafailyk
    Michael Rafailyk Posts: 165
    edited July 2023
    Any reasons or requirements of using the production names in your process?
    Is it some external text feature file that should not contain the friendly/nice names?
    I mean, usually applications automatically convert the glyph names to production names at the export.
  • I think I gave you an example: uni1E9E. I use this name for CAPITAL LETTER SHARP S (and probably many other typedrawers :) and my application don't convert it automatically in any frendly name.
    I could probably change it, but I prefer to use my own scripts for this conversion
  • I understand. Thanks for sharing your experience!