This repository has been archived on 2025-10-02. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
inter-font/misc/pylib/robofab/tools/remote.py
Rasmus Andersson 8234b62ab7 Speeds up font compilation by around 200%
Cython is used to compile some hot paths into native Python extensions.
These hot paths were identified through running ufocompile with the hotshot
profiler and then converting file by file to Cython, starting with the "hottest"
paths and continuing until returns were deminishing. This means that only a few
Python files were converted to Cython.

Closes #23
Closes #20 (really this time)
2017-09-04 11:12:34 -04:00

175 lines
No EOL
4.4 KiB
Python
Executable file

"""Remote control for MacOS FontLab.
initFontLabRemote() registers a callback for appleevents and
runFontLabRemote() sends the code from a different application,
such as a Mac Python IDE or Python interpreter.
"""
from robofab.world import world
if world.inFontLab and world.mac is not None:
from Carbon import AE as _AE
else:
import sys
from aetools import TalkTo
class FontLab(TalkTo):
pass
__all__ = ['initFontLabRemote', 'runFontLabRemote']
def _executePython(theAppleEvent, theReply):
import aetools
import cStringIO
import traceback
import sys
parms, attrs = aetools.unpackevent(theAppleEvent)
source = parms.get("----")
if source is None:
return
stdout = cStringIO.StringIO()
#print "<executing remote command>"
save = sys.stdout, sys.stderr
sys.stdout = sys.stderr = stdout
namespace = {}
try:
try:
exec source in namespace
except:
traceback.print_exc()
finally:
sys.stdout, sys.stderr = save
output = stdout.getvalue()
aetools.packevent(theReply, {"----": output})
_imported = False
def initFontLabRemote():
"""Call this in FontLab at startup of the application to switch on the remote."""
print "FontLabRemote is on."
_AE.AEInstallEventHandler("Rfab", "exec", _executePython)
if world.inFontLab and world.mac is not None:
initFontLabRemote()
def runFontLabRemote(code):
"""Call this in the MacOS Python IDE to make FontLab execute the code."""
fl = FontLab("FLab", start=1)
ae, parms, attrs = fl.send("Rfab", "exec", {"----": code})
output = parms.get("----")
return output
# GlyphTransmit
# Convert a glyph to a string using digestPen, transmit string, unpack string with pointpen.
#
def Glyph2String(glyph):
from robofab.pens.digestPen import DigestPointPen
import pickle
p = DigestPointPen(glyph)
glyph.drawPoints(p)
info = {}
info['name'] = glyph.name
info['width'] = glyph.width
info['points'] = p.getDigest()
return str(pickle.dumps(info))
def String2Glyph(gString, penClass, font):
import pickle
if gString is None:
return None
info = pickle.loads(gString)
name = info['name']
if not name in font.keys():
glyph = font.newGlyph(name)
else:
glyph = font[name]
pen = penClass(glyph)
for p in info['points']:
if p == "beginPath":
pen.beginPath()
elif p == "endPath":
pen.endPath()
else:
pt, type = p
pen.addPoint(pt, type)
glyph.width = info['width']
glyph.update()
return glyph
_makeFLGlyph = """
from robofab.world import CurrentFont
from robofab.tools.remote import receiveGlyph
code = '''%s'''
receiveGlyph(code, CurrentFont())
"""
def transmitGlyph(glyph):
from robofab.world import world
if world.inFontLab and world.mac is not None:
# we're in fontlab, on a mac
print Glyph2String(glyph)
pass
else:
remoteProgram = _makeFLGlyph%Glyph2String(glyph)
print "remoteProgram", remoteProgram
return runFontLabRemote(remoteProgram)
def receiveGlyph(glyphString, font=None):
from robofab.world import world
if world.inFontLab and world.mac is not None:
# we're in fontlab, on a mac
from robofab.pens.flPen import FLPointPen
print String2Glyph(glyphString, FLPointPen, font)
pass
else:
from robofab.pens.rfUFOPen import RFUFOPointPen
print String2Glyph(glyphString, RFUFOPointPen, font)
#
# command to tell FontLab to open a UFO and save it as a vfb
def os9PathConvert(path):
"""Attempt to convert a unix style path to a Mac OS9 style path.
No support for relative paths!
"""
if path.find("/Volumes") == 0:
# it's on the volumes list, some sort of external volume
path = path[len("/Volumes")+1:]
elif path[0] == "/":
# a dir on the root volume
path = path[1:]
new = path.replace("/", ":")
return new
_remoteUFOImportProgram = """
from robofab.objects.objectsFL import NewFont
import os.path
destinationPathVFB = "%(destinationPathVFB)s"
font = NewFont()
font.readUFO("%(sourcePathUFO)s", doProgress=True)
font.update()
font.save(destinationPathVFB)
print font, "done"
font.close()
"""
def makeVFB(sourcePathUFO, destinationPathVFB=None):
"""FontLab convenience function to import a UFO and save it as a VFB"""
import os
fl = FontLab("FLab", start=1)
if destinationPathVFB is None:
destinationPathVFB = os.path.splitext(sourcePathUFO)[0]+".vfb"
src9 = os9PathConvert(sourcePathUFO)
dst9 = os9PathConvert(destinationPathVFB)
code = _remoteUFOImportProgram%{'sourcePathUFO': src9, 'destinationPathVFB':dst9}
ae, parms, attrs = fl.send("Rfab", "exec", {"----": code})
output = parms.get("----")
return output