Add custom parameter through Core API?

I have this so close to being figured out, but I’ve found that it is only partially set in the font.

I’m working to add the custom parameter Axes through a remote glyphs script. This is related to, but a separate step from, the script I describe here: "Instance as master" through Core API? - #7 by thundernixon

Here’s my code so far (for the relevant portions):

from Glyphs import *
import sys
import os
import objc

# this allows you to run the script from the command line, passing in a glyphs file as an argument
relPath = sys.argv[-1]
directory = os.getcwd()
fullPath = str(directory + "/" + relPath)

# open font with no UI
doc = Glyphs.openDocumentWithContentsOfFile_display_(fullPath, False)
font = doc.font()

# describe your variable axis names and tags
fontAxes = {
	"Weight": "wght",
	"Negative": "NEGA"
}

# add them to the font. This could be another customParam – just add the value, then param name.
font.setCustomParameter_forKey_(fontAxes, "Axes")
print(font.customParameterForKey_("Axes"))

# if you'd rather not save to the source font, make a new filename
buildPath = fullPath.replace(".glyphs", "-build.glyphs")

# save and close font
font.save(buildPath)
doc.close()

This prints <GSCustomParameter: 0x600006da0ed0> Axes:{ Negative = NEGA; Weight = wght;}, seemingly confirming that the custom parameter has been set. Additionally, a parameter appears in the font info:

However, until I double-click that field, then click “okay,” the font masters don’t gain a “Negative” interpolation value field.

image

What step am I missing in adding and setting these Axes?

Based on the thread “Scripting GSAnnotation()”, I’ve tried to create a new custom parameter and add it just before setting it:

newParam = GSCustomParameter.alloc().init()
font.addCustomParameter_(newParam)
font.setCustomParameter_forKey_(fontAxes, "Axes") # existing code

However, this gives the following error:

Traceback (most recent call last):
  File "sources/scripts/helpers/prep-designspace.py", line 87, in <module>
    newParam = GSCustomParameter.alloc().init()
NameError: name 'GSCustomParameter' is not defined

Ha, I really thought I had this one with just the setCustomParameter_forKey_ method, but it seems like it’s just one or two lines out of reach… Thanks for any pointers!

Is that because your script is running from outside of Glyphs?
When I run print GSCustomParameter I get <objective-c class GSCustomParameter at 0x1028d7650>, meaning it is available in Glyphs …

Also, usually I would do the settings before adding it to the font. I don’t know if that is a must, though.

Hi Mark, thanks for the comment!

I am specifically running this from the command line, so I can adjust a font source in the build process, rather than directly editing the source (it’s designed by someone else, and I’m hoping to preserve the original as much as possible, and also trying to prevent manual edits from needing to happen more than once).

Unlike adjust the masters (original thread), however, I could manually add this parameter in the font info in my current case (assuming that’s what you meant by “usually I would do the settings before adding it to the font.”).

However, it seems likely that I’ll want to remotely add and set font custom parameters in the future, so I would still be happy to figure this one out.

My guess was that you might need to call something like import GlyphsApp or so, maybe that’s why it complains about that GSCustomParameter is not available. But it’s really just a guess.

The other thing was just about the order, But I see now that I misread something, so please ignore that :slight_smile:

So, I believe I am calling in the Glyphs app core API in my first line,

from Glyphs import *

and based on answers on the forum so far, I don’t think I can directly use the Glyphs Python API in remote scripts. So, there are PyObjC methods to do things, rather than straightforward Python API methods.

Interestingly, I’m realizing that even when I try to set custom parameters through the regular Python API, they only partially set … but don’t actually add new interpolation value fields to the font masters.

font = Glyphs.font

fontAxes = {
	"Weight": "wght",
	"Negative": "NEGA"
}

font.customParameters['Axes'] = fontAxes

# this Python API approach also doesn't quite work :/

Is there something extra that must be done to set an Axes custom parameter in a font and have it take effect?

Could it be because the parameter is actually an NSArray? Since it is not wrapped and pythonified properly yet, you may need to do some pyobjc hacking:

axesInfo = (
	NSDictionary.dictionaryWithObjects_forKeys_(("Weight","wght"), ("Name", "Tag")),
	NSDictionary.dictionaryWithObjects_forKeys_(("Width","wdth"), ("Name", "Tag")),
)
parameterArray = NSMutableArray.arrayWithCapacity_(len(axesInfo))
parameterArray.addObjectsFromArray_(axesInfo)

Font.customParameters["Axes"] = parameterArray
1 Like

The external bridge does not make all classes available. There is a function ‘Glyphs.objectForName()’ (something like this, I’m not at the Mac to check this).

I think there is a notification missing that triggers the update of the master UI. I’ll have to try this myself.

1 Like

The code to add an Axes parameter can be written like this:

fontAxes = [
	{"Name": "Weight", "Tag": "wght"},
	{"Name": "Negative", "Tag": "NEGA"}
]
Font.customParameters["Axes"] = fontAxes

To add Axes from outside the app through the external script:

from Foundation import NSMutableDictionary, NSMutableArray
fontAxes = NSMutableArray.arrayWithArray_([
	NSMutableDictionary.dictionaryWithDictionary_({
		"Name": "Weight", "Tag": "wght"
	}),
	NSMutableDictionary.dictionaryWithDictionary_({
		"Name": "Negative", "Tag": "NEGA"
	})
])
font.setCustomParameter_forKey_(fontAxes, "Axes")
1 Like

Amazing, this works great! Thanks so much for your help.