Is there a headless version of Glyphsapp to export fonts with Glyphs using a shell script?
I just replied to Marc by email. There is no headless version (yet? The app depends on many resources like GlyphData and plugins. Loading all of them each time you call it, would be quite slow).
But you can control the normal app with AppleScript. I just had a look at it and improved a few minor things. Iâll post some sample code later. And it is possibel to run apple script from Python, too.
That means you need an apple server. It might be possibel to build a version that runs on Linux but that would mean a few weeks of work that I canât spare at the moment.
Requiring the operating system to be OS X is no trouble.
The startup time issue is a valid concern, but in itself its just nice-to-have and is what the daemon model is for. The way Mac OS X works, running Glyphs on a desktop is running it as a daemon, which, as you say, can be controlled via the AppleScript API using a Python shell script. Would be great if you can post your AppleScript code in https://github.com/schriftgestalt/GlyphsSDK
My question is actually about running Glyphs âheadless,â on a Mac OS X machine without a GUI, such as Travis CI
When the operating system is GNU, then thereâs a virtual X Window System server for machines without physical displays which can be used on Travis CI for rendering X GUIs, and xdotool to fake X mouse/keyboard input events.
But, Iâm not aware of anything like that for Mac OS X, and, lacking such generic tooling, I wonder if there is or could be a âheadlessâ version.
Perhaps this could be similar to FontForgeâs headless version - when you install FF on OS X with brew install fontforge
then run fontforge
you get the embedded Python interpreterâs >>>
prompt with the fontforge module pre-loaded (no need to run import fontforge
) so that you can do things like fontforge compile-my-project.py source-file.sfd
that donât involve a GUI.
In writing this Iâm also reminded of how TextMate (https://github.com/textmate/textmate) has, since 2005, had a little shell utility tool to go with its GUI (http://blog.macromates.com/2005/textmate-shell-utility-tmmate/)
I seem to remember there was some âGlyphs Project Fileâ stuff, and it seems natural to me that project files would have a headless program to operate them with.
If you run on macOS, you could just ignore the UI and tread the app as a headless daemon.
here is a sample script:
tell application "Glyphs"
set doc to document 1
set aFont to font of doc
repeat with aInstance in instances of aFont
if active of aInstance then
generate aInstance
end if
end repeat
end tell
Thanks Georg!
Here is a different example:
tell application "Glyphs"
set doc to document 1
set aFont to font of doc
set aInstance to instance 1 of aFont
set ResultFolder to POSIX file (do shell script "dirname " & quoted form of POSIX path of ((file of doc) as alias)) as alias
log name of aInstance as string
generate aInstance to ResultFolder as OTF
end tell
There are a few options to the generate
command. They are mentioned in Glyphs Scripting Dictionary.
Hey Georg,
My knowledge of Applescript is flakey at best. I keep recieving Syntax Errors.
Iâm running El Capitan and your scripts are being run through âScript Editorâ.
Cheers
Marc
Iâm having some success with the first sample. Iâll get back to you if I run into further problems. Once again, thank you for this.
I wrote the script in 10.10.5 and it works on 10.11.6, too. Maybe you copied some hidden chars with it.
click on the square button in the lower left and then on Replies. Then run or compile the script again. But if it is not even compiling, then there is some typo somewhere.
Script Editor usually helps you find the problematic line. Try the Compile button first.
I have no issues with generating an instance via an applescript but is there any documentation on generating a variable font with an appleScript?
Additionally, how would one run the scripts in the top bar (i.e. Script > Insert Instances, etc.) from an appleScript or is there a better way to do this?
I managed to cobble together a script that can do this through clicks using âsystem servicesâ, but I have been unable to find a way to set an export destination
tell application "Finder"
activate
open (POSIX path of ((path to me as text) & "::")) & "HeptaSlab-Build.glyphs" as POSIX file using application file "Glyphs Cutting Edge.app" of folder "Applications" of startup disk
tell application "System Events" to tell process "Glyphs" to ÂŹ
tell menu bar item 3 of menu bar 1
click
tell menu item 15 of menu 1
click
end tell
keystroke return
end tell
end tell
Just to get some context: Why are you doing it in AppleScript?
I am not tied to using AppleScript, in fact I would prefer not to use it at all. I wanted to automate the export process for a project Iâm working on, so that if I make any edits to the source file I can run something like a build.sh to get my final .ttf
Ideally I wanted to make a build script to:
- duplicate my file
- run one of my scripts from the Glyphs scripts folder on the new file
- export the variable font
- run some google fonts scripts
- convert to ttx, add an xml patch
- convert to ttf
I was thinking I needed AppleScript for the 3rd step and maybe the 2nd step
Then you should not use Apple Script. Have a look at the folder Glyphs remote scripts
in the GlyphsSDK repo. The following script should get you started.
#!/usr/bin/env python
# encoding: utf-8
import sys
import os
from Glyphs import *
from Foundation import NSURL
def main():
font = currentDocument.font()
fontCopy = font.copy()
# run the script with exec(), make sure that the script can get to the right font object. Depends what the script is doing.
variationFontPlugin = Glyphs.objectWithClassName_("GlyphsFileFormatVariationFonts") #.fileFormatInstances()
variationFontPlugin.setFont_(fontCopy)
destination = NSURL.fileURLWithPath_("/Users/georg/Stuff/")
print variationFontPlugin.writeVARTables_error_(destination, None)
# you know the rest
if __name__ == '__main__':
main()
Great, thanks for this!
I will take a look at the repo
I am trying to do sth similar in Objective-C. I seem to get the exporter via [[NSClassFromString(@"GlyphsFileFormatVariationFonts") alloc] init];
but the GlyphsFileFormatVariationFonts
that it returns is not a known object to the compiler and hence I cannot access its methods. I cannot find it in the GlyphsCore headers either.
Basically I try to make it run writeVARTables:error:
or _exportToURL:error
(as written in the GlyphsApp python wrapper (the leading underscore there confuses me, I tried with and without when reforming to obj-c)).
You need to add a @interface
defining the method. This would replace the header (that you donât have) and tell the compiler what the object can do.
@interface GlyphsFileFormatVariationFonts (private)
- (BOOL)writeVARTables:(NSString *)TTFPath destination:(NSURL *)DestinationURL instance:(GSInstance *)instance error:(NSError **)error;
@end
(the API seems to have changed since I posted the code)
if that is not working because it doesnât know the GlyphsFileFormatVariationFonts class, use NSObject instead.
@interface NSObject (private)
âŠ
Oh, I was pretty close, I tried that before:
// Whoever reads this: don't use it :D
@interface GlyphsFileFormatVariationFonts : NSObject
-(id)exportToURL:(NSURL*)destination error:(NSError*)error;
-(void)setFont:(GSFont*)font;
@end
Thank you!
What does TTFPath
take? The filename like @"afont.ttf"
and what/why does it need a GSInstance (I tried to just use the first one)?
GlyphsFileFormatVariationFonts *exporter = [[NSClassFromString(@"GlyphsFileFormatVariationFonts") alloc] init];
[exporter setFont:[thisFont copy]];
NSURL *destination = [NSURL fileURLWithPath:(@"/Users/Mark/Desktop/")];
NSError *error = [NSError new];
BOOL result = [exporter writeVARTables:@"testste.ttf" destination:destination instance:[thisFont.instances firstObject] error:&error];
What I notice:
- the compiler only shuts up if I declare it like so:
@interface GlyphsFileFormatVariationFonts : NSObject
or like you said with@interface NSObject (private)
- It looks like I also must define the
setFont:
method - When I set the font, it only works partially* when I create the copy directly in the argument of setFont:, not when I create a font copy as a variable before and use that
*) partially means, that it doesnât work yet, but at least in that case I get the Error as such: `Domain=GSGlyphsDomain Code=987 âPlease define an âAxesâ parameter in Font Info > Fontâ UserInfo={NSLocalizedDescription=Please define an âAxesâ parameter in Font Info > Font}``
(The font has an âAxesâ parameter, so somewhere it gets lost.