Fontlab: how to import OT features from external fea file using python macro

butterick's picture

I know how to compile OT features from inside a python macro:


33203 being the code for the menu command OTCompile.

Fontlab also provides codes for the menu commands OTFeaturesNew (33222), which resets the features, and OTFeaturesOpen (33210), which gets features from a file.

The problem with OTFeaturesNew (33222) is that it pops an alert asking if you really want to remove all OT data.
The problem with OTFeaturesOpen (33210) is that it pops a dialog to select the file.

I would like to be able to:

+ reset the OT features WITHOUT popping an alert (ie. silently)
+ get features from a specific fea file WITHOUT popping a dialog

Can it be done?

Jens Kutilek's picture


resetting the features is possible if you don't use the command codes, but set the python attributes directly:

fl.font.ot_classes = "" # to clear the lower right part of the OT panel

Loading feature code from a text file can probably be done, but it would be a bit more complicated. In principle, open a text file using python, detect the lines where one feature's code starts and ends, and add the feature to the font like this:

fl.font.features.append(Feature(myFeatureTag, myFeatureCode))


fl.font.features.append(Feature("liga", "feature liga\n  {\n  sub f i by f_i;\n  } liga;\n"))


butterick's picture

Not bad, but this will only work for feature records, right? And there's more to the fea file than feature records (notably: class definitions and 'languagesystem' statements).

eigi's picture


Class definitions and 'languagesystem' statements go to the lower right part of the OpenType panel. This is accessable via the ot_classes attribute of the font object as one big string.


butterick's picture

Ah, thank you. I see how to do this now.

butterick's picture
from import CurrentFont
import os, re

font = CurrentFont()

# reset OT features - thank you Jens
font.naked().ot_classes = "" 

# open fea file
feaFile = open({path to fea file}, 'r')
feaCode =

# read ot_classses from file - from beginning of file to first feature declaration
otClassesPattern = re.compile('^.*?(?=\nfeature )', re.DOTALL)
otClasses =

# set ot_classses
font.naked().ot_classes = otClasses

# read features from file & add to font
tagList = []
tagPattern = re.compile('feature\s*(?P<tag>\w\w\w\w)\s*{', re.DOTALL)
for match in tagPattern.finditer(feaCode):

for tag in tagList:
    featurePattern = re.compile('feature\s+%s\s*{.*?}\s*%s;' % (tag, tag), re.DOTALL)
    featureCode =
    font.naked().features.append(Feature(tag, featureCode))

# delete kern feature if it exists - thank you Karsten
for featureIndex in range(len(font.naked().features)-1,-1,-1):
    if font.naked().features[featureIndex].tag == "kern":
    	  del font.naked().features[featureIndex]

# make new kern feature & append to feature list 
kernFeature = font.naked().MakeKernFeature()

# recompile OT features

Mark Simonson's picture

Maybe I'm missing something, but if you just want your features in an external file (which is maybe not the only thing you're wanting to do), you can just put something like this at the bottom right pane of the OT panel:


The .fea file would be in the same directory as the .vfb file in this example.

butterick's picture

Good idea. That's simple and works for getting the features into the font. But it doesn't display the underyling fea source code in the OT panel, which I prefer so I can try different things without having to modify the official features file.

Mark Simonson's picture

Well, you can easily change things in the external file, save and then hit compile in FontLab. It's really only one extra step (saving in the text editor), if you don't count switching between programs.

Also, you can duplicate the external file, and "include" that instead, if you want to try different things out without messing with your official features file. It also works with more than one file (each on a separate "include" line), so you can break things out logically among multiple .fea files if you wish.

Syndicate content Syndicate content