Feature Request: Export active Instances as UFO

Is there a quick/comfortable way to do this?
At the moment I use “Generate Instances” which is a real pain in the ass if you need to export more than one Instance as UFO. As far as I know there are mainly two options to add/improve this feature:

###1 – Generate Instances as one file with multiple Masters
This is probably the easiest way to implement it right away… Instead of generating all Instances as separate files, please lets generate just one file and then add all the following generated Instances as a new Master to it. This would then allow to export all of those Instances in just one additional step (via export UFO)

UPDATE: Generate Instances into one Glyphs file.py.zip (1.5 KB)

PS: can you please disable the function that the generated File/Master gets selects the weight/width name based on the Interpolation value! This messes up the naming in all projects which do use different interpolation value scales, which is not uncommon, e.g. using the stem-width as values for weight which makes almost every generated Master named “Light …”

###2 – Make UFO Export handle Instances as well
There are multiple ways to implement this nicely, here just two of them

  • Add Checkbox to export Instances (active) as UFO
  • Or similar to the Master list (in the export window) have a Instance list next to it.

UPDATE: Export Instances as UFO:Glyphs.zip (2.7 KB)

###3 – Is there any other way or anywhere a script lying around which can do that already?
That would be a quick help :slight_smile:

Thanks

(Related: Feature request: master and instance exporting that makes sense)

1 Like

Shouldnt be too hard to code… unless I don’t get what you’re trying to do.

You can script that.
(written in Safari)

for i in Font.instances:
    f = i.interpolatedFont()
    f.save("Path/to/font.ufo")
```

Ok, thanks. Will try to figure it out with a script … just hoped that this would get implemented at some point.

I can partly understand that it is not in the export UI … but nevertheless, it would be great if the “Generating Instances” could be improved! It would be super easy for you to implement and I can’t see any downsides, or am I missing something?

Trying to export .ufo files from the instances - this doesn’t work for me unfortunately (see traceback):
(sorry indents are missing :wink:

import GlyphsApp
Font = Glyphs.font
for index, i in enumerate(Font.instances):
	username = "luke"
	f = i.interpolatedFont()
	f.save("/Users/%s/Desktop/%s%s.ufo:" % (username, i.familyName, i.name))

traceback:
  File "<string>", line 5, in <module>
TypeError: 'NSKVONotifying_GSFont' object is not callable

(edit: added three grave before and after the code block)

Just remove the parentheses after i.interpolatedFont.

Oh, I totally forgot to post an update on this.

Try the following:

import GlyphsApp

UFODir = GetFolder()

for i in Glyphs.font.instances:	
	iF = i.interpolatedFont
	iF.save("{0}/{1} {2}.ufo".format(UFODir, iF.familyName, i.name)) 

nicely written by Robert Pratley (https://github.com/RobertPratley/Glyphs-Scripts/)

And here is what I ended up with (not so nice, but works as well ^^)
Export Instances as UFO.py.zip (1.4 KB)
(with this you can also manipulate the filename on export)

Enjoy :slight_smile:

1 Like

Great!

Maybe someone is willing to help with this? (simply to hot to code today)
Basically the other way around - something like this:
I would like to create a file with 2 masters from 2 .ufo files by using GetFolder().
Afterwards it would be great to set the weight value for the masters e.g.
master1 = 0
master2 = 1000
and create some instances in between with some variable weight values:
master1_instance = 0
intermediate_instance = 300
intermediate_instance2 = 500
master2_instance = 1000

I came up with these lines of weird code, but got stuck in the middle, because my brain is melting…

import GlyphsApp
from vanilla.dialogs import getFile

getFolderwithFiles = getFolder()
if getFolderwithFiles:
	folderPath = getFolderwithFiles[0]

newFont = GSFont()
newFont.familyName = "My New Font"

newMasters = []

for dirname, subdirs, files in os.walk(folderPath):
	if dirname == folderPath:
		pass
	if dirname.split("/")[-1] == "glyphs":
		pass
	else:
		sourceFont = Glyphs.open(dirname, False)
		newMasters.append(sourceFont)
print newMasters

Hey Georg,
I think there is a bug somewhere here …

It seems to me as if the script is executing too fast. ^^
When I’m trying to append the interpolatedFont as a Master it always ends up empty. Is there any way to check if the interpolatedFont is actually there and then append it as a Master … ?

font = Glyphs.fonts[0]
interpolated_font = font.instances[0].interpolatedFont
print interpolated_font
print interpolated_font.masters[0]

until here everything works as expected and then…

font.masters.append(interpolated_font.masters[0])

… an empty Master gets appended.

Even the following is not working, though the generated new font clearly has everything in place.

Glyphs.fonts.append(interpolated_font)
second_font = Glyphs.fonts[0]
font.masters.append(second_font.masters[0])

Any Ideas?

Here is the complete script:
Generate Instances into one Glyphs file.py.zip (1.3 KB)

@Luke
Sorry, that I did not respond to your last post!
But I just don’t know where you got stuck, could you elaborate on a specific problem otherwise it’s really hard to help …

What do you mean by empty master. That then master info is empty? You should make a copy of then master before adding it to a new font as it shouldn’t be in two fonts at once.

@Manuel thank you very much for your reply! I found a code snipped that helped me to get a step further (it’s less hot today :wink: - still need to figure out the best way to sort the masters (maybe weightClass) and add some instances in between - this is were I am at the moment (doesn’t look nice, but works for me):

import GlyphsApp
from vanilla.dialogs import getFolder

master1weight = 0
master2weight = 1000

getFolderwithFiles = getFolder()
if getFolderwithFiles:
	folderPath = getFolderwithFiles[0]
	newMasters = []
	for dirname, subdirs, files in os.walk(folderPath):
		if dirname == folderPath:
			pass
		if dirname.split("/")[-1][-4:] != ".ufo":
			pass
		else:
			newMasters.append(dirname)
	#print newMasters
	
	if len(newMasters) == 2:
		f1 = GSFont(newMasters[0])
		f2 = GSFont(newMasters[1])
		f1.addFontAsNewMaster_(f2.masters[0])
		f1.instances.append(f2.instances[0].copy())
		Glyphs.fonts.append(f1)
		## setting weight values for 2 masters
		Glyphs.font.masters[0].weightValue = master1weight
		Glyphs.font.masters[1].weightValue = master2weight 

by empty I mean that there are no outlines, nothing! only the first master is working as expected, all the appended ones are just empty.



and what do you mean by making a copy, could give an example with code? so, when and how I should make one in order to make it work …

thx

and there is another odd thing… the instances in the new font are still looking exactly the same as in the original, even though the masters are empty!

I tried to just add .copy() to the new masters and instances:

# Add new Masters
for active_instance_font in instances_as_fonts:
	new_font.masters.append(active_instance_font.masters[0].copy())

# Add all original instances
new_font.instances = () # empty Instances first
for instance in all_original_instances:
	new_font.instances.append(instance.copy())

Now the instances are empty as well (which is at least a more expected behaviour with empty masters) … so yes even with this the masters are still empty

Thanks @luke_snider! The mysterious ».addFontAsNewMaster_« did the trick. (its nowhere in the docu)

for active_instance_font in instances_as_fonts:
	new_font.addFontAsNewMaster_(active_instance_font.masters[0])

:smiley:

here is the updated script:
Generate Instances into one Glyphs file.py.zip (1.5 KB)

Adding the master will only add the GSFontMaster object to the master list. You need to add the layers for each glyph, too.
The font object has a method that takes care of it: font.addFontAsNewMaster_(master)

Perfect, thanks Georg! this is what I just found out :slight_smile:

It seems to work really nice now, it’s even taking all the alignment zones, custom parameters, … correctly. :smiley:

Only the brace and bracket layers are all missing :confused:

seems to work for me now. thanks @Manuel

''' makes a multiple master file from 2 ufo (in folder) and adds 3 instances + sets names and weightValues'''
import GlyphsApp
from vanilla.dialogs import getFolder
from operator import itemgetter
from collections import OrderedDict

master1weight = 0
master2weight = 1000
instances = {"Medium":300,"Semibold":500,"Bold":700}

instances = OrderedDict(sorted(instances.items(), key=itemgetter(1)))
for k,v in instances.items():
	print k,v
	
getFolderwithFiles = getFolder()
if getFolderwithFiles:
	folderPath = getFolderwithFiles[0]
	newMasters = []
	for dirname, subdirs, files in os.walk(folderPath):
		if dirname == folderPath:
			pass
		if dirname.split("/")[-1][-4:] != ".ufo":
			pass
		else:
			newMasters.append(dirname)

	# sort the masters (by stylename in .ufo filename)
	sortation = ['Thin', 'Extralight', 'Light', 'Semilight', 'Regular', 'Medium', 'Semibold', 'Demibold', 'Bold', 'Black']
	indices = {c: i for i, c in enumerate(sortation)}

	finalMasterdict = {}
	for k, v in indices.items():
		for a in newMasters:
			if k in a.split("/")[-1]:
				finalMasterdict[v] = a

	if len(finalMasterdict.keys()) == 2:
		master1 = sorted(finalMasterdict.items())[0][1]
		master2 = sorted(finalMasterdict.items())[1][1]
		f1 = GSFont(master1)
		f2 = GSFont(master2)
		f1.addFontAsNewMaster_(f2.masters[0])
		## adding instances
		for i in range(len(instances.keys())+1):
			f1.instances.append(f2.instances[0].copy())
		Glyphs.fonts.append(f1)
		## changing instances
		for i, instance in enumerate(f1.instances):
			if i == 0:
				instance.weightValue = master1weight
			if i == len(instances.keys())+1:
				instance.weightValue = master2weight
			else:
				try:
					instance.weightValue = instances.items()[i-1][1]
					instance.name = str(instances.items()[i-1][0])
					instance.weight = str(instances.items()[i-1][0])
				except IndexError:
					pass
		## setting weight values for 2 masters
		Glyphs.font.masters[0].weightValue = master1weight
		Glyphs.font.masters[1].weightValue = master2weight 
2 Likes

A small (final) update, fixed some things. cheers.

import GlyphsApp
from vanilla.dialogs import getFolder
from operator import itemgetter
from collections import OrderedDict

master1weight = 0
master2weight = 1000
instances = {"Medium":300,"Semibold":500,"Bold":700}
#instances = {"Semilight":450}

instances = OrderedDict(sorted(instances.items(), key=itemgetter(1)))
	
getFolderwithFiles = getFolder()
if getFolderwithFiles:
	folderPath = getFolderwithFiles[0]
	print folderPath
	newMasters = []
	for dirname, subdirs, files in os.walk(folderPath):
		if dirname == folderPath:
			pass
		if dirname.split("/")[-1][-4:] != ".ufo":
			pass
		else:
			newMasters.append(dirname)

	# sort the masters (by stylename in .ufo filename)
	sortation = ['Thin', 'Extralight', 'Light', 'Semilight', 'Regular', 'Medium', 'Semibold', 'Demibold', 'Bold', 'Black']
	indices = {c: i for i, c in enumerate(sortation)}

	finalMasterdict = {}
	for k, v in indices.items():
		for a in newMasters:
			if k in a.split("/")[-1]:
				finalMasterdict[v] = a

	if len(finalMasterdict.keys()) == 2:
		master1 = sorted(finalMasterdict.items())[0][1]
		master2 = sorted(finalMasterdict.items())[1][1]
		f1 = GSFont(master1)
		f2 = GSFont(master2)
		f1.addFontAsNewMaster_(f2.masters[0])
		## adding instances
		for i in range(len(instances.keys())+1):
			f1.instances.append(f2.instances[0].copy())
		Glyphs.fonts.append(f1)
		## setting weight values for 2 masters
		Glyphs.font.masters[0].weightValue = master1weight
		Glyphs.font.masters[1].weightValue = master2weight
		## changing instances weight names and values
		for i, instance in enumerate(f1.instances):
			if i == 0:
				instance.weightValue = master1weight
				instance.name = f1.masters[0].name
			if i == len(f1.instances)-1:
				instance.weightValue = master2weight
				instance.name = f2.masters[0].name
			if i != 0 and i != len(f1.instances)-1:
				instance.weightValue = instances.items()[i-1][1]
				instance.name = str(instances.items()[i-1][0])
				instance.weight = str(instances.items()[i-1][0])
				#CustomParameters
				familyName = f1.familyName
				styleName = str(instances.items()[i-1][0])
				instance.setCustomParameter_forKey_(familyName+"-"+styleName , "postscriptFontName")
				instance.setCustomParameter_forKey_(familyName+" "+styleName , "postscriptFullName")
				instance.setCustomParameter_forKey_(familyName+" "+styleName , "styleMapFamilyName")