git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@163 4cde692c-a291-49d1-8350-778aa11640f8
323 lines
8.7 KiB
Python
323 lines
8.7 KiB
Python
"""Main TTX application, Mac-only"""
|
|
|
|
|
|
#make sure we don't lose events to SIOUX
|
|
import MacOS
|
|
MacOS.EnableAppswitch(-1)
|
|
|
|
def SetWatchCursor():
|
|
import Qd, QuickDraw
|
|
Qd.SetCursor(Qd.GetCursor(QuickDraw.watchCursor).data)
|
|
|
|
def SetArrowCursor():
|
|
import Qd
|
|
Qd.SetCursor(Qd.qd.arrow)
|
|
|
|
SetWatchCursor()
|
|
|
|
# a few constants
|
|
LOGFILENAME = "TTX errors"
|
|
PREFSFILENAME = "TTX preferences"
|
|
DEFAULTXMLOUTPUT = ":XML output"
|
|
DEFAULTTTOUTPUT = ":TrueType output"
|
|
|
|
|
|
import FrameWork
|
|
import MiniAEFrame, AppleEvents
|
|
import EasyDialogs
|
|
import Res
|
|
import macfs
|
|
import os
|
|
import sys, time
|
|
import re, string
|
|
import traceback
|
|
from fontTools import ttLib, version
|
|
from fontTools.ttLib import xmlImport
|
|
from fontTools.ttLib.macUtils import ProgressBar
|
|
|
|
abouttext = """\
|
|
TTX - The free TrueType to XML to TrueType converter
|
|
(version %s)
|
|
Copyright 1999-2001, Just van Rossum (Letterror)
|
|
just@letterror.com""" % version
|
|
|
|
|
|
class TTX(FrameWork.Application, MiniAEFrame.AEServer):
|
|
|
|
def __init__(self):
|
|
FrameWork.Application.__init__(self)
|
|
MiniAEFrame.AEServer.__init__(self)
|
|
self.installaehandler(
|
|
AppleEvents.kCoreEventClass, AppleEvents.kAEOpenApplication, self.do_nothing)
|
|
self.installaehandler(
|
|
AppleEvents.kCoreEventClass, AppleEvents.kAEPrintDocuments, self.do_nothing)
|
|
self.installaehandler(
|
|
AppleEvents.kCoreEventClass, AppleEvents.kAEOpenDocuments, self.handle_opendocumentsevent)
|
|
self.installaehandler(
|
|
AppleEvents.kCoreEventClass, AppleEvents.kAEQuitApplication, self.handle_quitevent)
|
|
|
|
def idle(self, event):
|
|
SetArrowCursor()
|
|
|
|
def makeusermenus(self):
|
|
m = FrameWork.Menu(self.menubar, "File")
|
|
FrameWork.MenuItem(m, "Open...", "O", self.domenu_open)
|
|
FrameWork.Separator(m)
|
|
FrameWork.MenuItem(m, "Quit", "Q", self._quit)
|
|
|
|
def do_about(self, *args):
|
|
EasyDialogs.Message(abouttext)
|
|
|
|
def handle_quitevent(self, *args, **kwargs):
|
|
self._quit()
|
|
|
|
def domenu_open(self, *args):
|
|
fss, ok = macfs.StandardGetFile()
|
|
if ok:
|
|
self.opendocument(fss.as_pathname())
|
|
|
|
def handle_opendocumentsevent(self, docs, **kwargs):
|
|
if type(docs) <> type([]):
|
|
docs = [docs]
|
|
for doc in docs:
|
|
fss, a = doc.Resolve()
|
|
path = fss.as_pathname()
|
|
self.opendocument(path)
|
|
|
|
def opendocument(self, path):
|
|
filename = os.path.basename(path)
|
|
filetype = guessfiletype(path)
|
|
handler = getattr(self, "handle_%s_file" % filetype)
|
|
handler(path)
|
|
|
|
def handle_xml_file(self, path):
|
|
prefs = getprefs()
|
|
makesuitcase = int(prefs.get("makesuitcases", 0))
|
|
dstfolder = prefs.get("ttoutput", DEFAULTTTOUTPUT)
|
|
if not os.path.exists(dstfolder):
|
|
os.mkdir(dstfolder)
|
|
srcfilename = dstfilename = os.path.basename(path)
|
|
if dstfilename[-4:] in (".ttx", ".xml"):
|
|
dstfilename = dstfilename[:-4]
|
|
if dstfilename[-4:] not in (".TTF", ".ttf"):
|
|
dstfilename = dstfilename + ".TTF"
|
|
dst = os.path.join(dstfolder, dstfilename)
|
|
|
|
if makesuitcase:
|
|
try:
|
|
# see if the destination file is writable,
|
|
# otherwise we'll get an error waaay at the end of
|
|
# the parse procedure
|
|
testref = Res.FSpOpenResFile(macfs.FSSpec(dst), 3) # read-write
|
|
except Res.Error, why:
|
|
if why[0] <> -43: # file not found
|
|
EasyDialogs.Message("Can't create '%s'; file already open" % dst)
|
|
return
|
|
else:
|
|
Res.CloseResFile(testref)
|
|
else:
|
|
try:
|
|
f = open(dst, "wb")
|
|
except IOError, why:
|
|
EasyDialogs.Message("Can't create '%s'; file already open" % dst)
|
|
return
|
|
else:
|
|
f.close()
|
|
pb = ProgressBar("Reading TTX file '%s'..." % srcfilename)
|
|
try:
|
|
tt = ttLib.TTFont()
|
|
tt.importXML(path, pb)
|
|
pb.setlabel("Compiling and saving...")
|
|
tt.save(dst, makesuitcase)
|
|
finally:
|
|
pb.close()
|
|
|
|
def handle_datafork_file(self, path):
|
|
prefs = getprefs()
|
|
dstfolder = prefs.get("xmloutput", DEFAULTXMLOUTPUT)
|
|
if not os.path.exists(dstfolder):
|
|
os.mkdir(dstfolder)
|
|
filename = os.path.basename(path)
|
|
pb = ProgressBar("Dumping '%s' to XML..." % filename)
|
|
if filename[-4:] in (".TTF", ".ttf"):
|
|
filename = filename[:-4]
|
|
filename = filename + ".ttx"
|
|
dst = os.path.join(dstfolder, filename)
|
|
try:
|
|
tt = ttLib.TTFont(path)
|
|
tt.saveXML(dst, pb)
|
|
finally:
|
|
pb.close()
|
|
|
|
def handle_resource_file(self, path):
|
|
prefs = getprefs()
|
|
dstfolder = prefs.get("xmloutput", DEFAULTXMLOUTPUT)
|
|
if not os.path.exists(dstfolder):
|
|
os.mkdir(dstfolder)
|
|
filename = os.path.basename(path)
|
|
fss = macfs.FSSpec(path)
|
|
try:
|
|
resref = Res.FSpOpenResFile(fss, 1) # read-only
|
|
except:
|
|
return "unknown"
|
|
Res.UseResFile(resref)
|
|
pb = None
|
|
try:
|
|
n = Res.Count1Resources("sfnt")
|
|
for i in range(1, n+1):
|
|
res = Res.Get1IndResource('sfnt', i)
|
|
resid, restype, resname = res.GetResInfo()
|
|
if not resname:
|
|
resname = filename + `i`
|
|
pb = ProgressBar("Dumping '%s' to XML..." % resname)
|
|
dst = os.path.join(dstfolder, resname + ".ttx")
|
|
try:
|
|
tt = ttLib.TTFont(path, i)
|
|
tt.saveXML(dst, pb)
|
|
finally:
|
|
pb.close()
|
|
finally:
|
|
Res.CloseResFile(resref)
|
|
|
|
def handle_python_file(self, path):
|
|
pass
|
|
#print "python", path
|
|
|
|
def handle_unknown_file(self, path):
|
|
EasyDialogs.Message("Cannot open '%s': unknown file kind" % os.path.basename(path))
|
|
|
|
def do_nothing(self, *args, **kwargs):
|
|
pass
|
|
|
|
def mainloop(self, mask=FrameWork.everyEvent, wait=0):
|
|
self.quitting = 0
|
|
while not self.quitting:
|
|
try:
|
|
self.do1event(mask, wait)
|
|
except self.__class__:
|
|
# D'OH! FrameWork tries to quit us on cmd-.!
|
|
pass
|
|
except KeyboardInterrupt:
|
|
pass
|
|
except ttLib.xmlImport.xml_parse_error, why:
|
|
EasyDialogs.Message(
|
|
"An error occurred while parsing the XML file:\n" + why)
|
|
except:
|
|
exc = traceback.format_exception(sys.exc_type, sys.exc_value, None)[0]
|
|
exc = string.strip(exc)
|
|
EasyDialogs.Message("An error occurred!\n%s\n[see the logfile '%s' for details]" %
|
|
(exc, LOGFILENAME))
|
|
traceback.print_exc()
|
|
|
|
def do_kHighLevelEvent(self, event):
|
|
import AE
|
|
AE.AEProcessAppleEvent(event)
|
|
|
|
|
|
|
|
def guessfiletype(path):
|
|
#if path[-3:] == ".py":
|
|
# return "python"
|
|
f = open(path, "rb")
|
|
data = f.read(21)
|
|
f.close()
|
|
if data[:5] == "<?xml":
|
|
return "xml"
|
|
elif data[:4] in ("\000\001\000\000", "OTTO", "true"):
|
|
return "datafork"
|
|
else:
|
|
# assume res fork font
|
|
fss = macfs.FSSpec(path)
|
|
try:
|
|
resref = Res.FSpOpenResFile(fss, 1) # read-only
|
|
except:
|
|
return "unknown"
|
|
Res.UseResFile(resref)
|
|
i = Res.Count1Resources("sfnt")
|
|
Res.CloseResFile(resref)
|
|
if i > 0:
|
|
return "resource"
|
|
return "unknown"
|
|
|
|
|
|
default_prefs = """\
|
|
xmloutput: ":XML output"
|
|
ttoutput: ":TrueType output"
|
|
makesuitcases: 1
|
|
"""
|
|
|
|
def getprefs(path=PREFSFILENAME):
|
|
if not os.path.exists(path):
|
|
f = open(path, "w")
|
|
f.write(default_prefs)
|
|
f.close()
|
|
f = open(path)
|
|
lines = f.readlines()
|
|
prefs = {}
|
|
for line in lines:
|
|
if line[-1:] == "\n":
|
|
line = line[:-1]
|
|
try:
|
|
name, value = re.split(":", line, 1)
|
|
prefs[string.strip(name)] = eval(value)
|
|
except:
|
|
pass
|
|
return prefs
|
|
|
|
|
|
class dummy_stdin:
|
|
def readline(self):
|
|
return ""
|
|
sys.stdin = dummy_stdin()
|
|
|
|
# redirect all output to a log file
|
|
sys.stdout = sys.stderr = open(LOGFILENAME, "w", 0) # unbuffered
|
|
print "Starting TTX at " + time.ctime(time.time())
|
|
|
|
# fire it up!
|
|
ttx = TTX()
|
|
ttx.mainloop()
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
# clues for BuildApplication/MacFreeze.
|
|
#
|
|
# These modules somehow get imported, but we don't want/have them:
|
|
#
|
|
# macfreeze: exclude msvcrt
|
|
# macfreeze: exclude W
|
|
# macfreeze: exclude SOCKS
|
|
# macfreeze: exclude TERMIOS
|
|
# macfreeze: exclude termios
|
|
# macfreeze: exclude icglue
|
|
# macfreeze: exclude ce
|
|
#
|
|
# these modules are imported dynamically, so MacFreeze won't see them:
|
|
#
|
|
# macfreeze: include fontTools.ttLib.tables._c_m_a_p
|
|
# macfreeze: include fontTools.ttLib.tables._c_v_t
|
|
# macfreeze: include fontTools.ttLib.tables._f_p_g_m
|
|
# macfreeze: include fontTools.ttLib.tables._g_a_s_p
|
|
# macfreeze: include fontTools.ttLib.tables._g_l_y_f
|
|
# macfreeze: include fontTools.ttLib.tables._h_d_m_x
|
|
# macfreeze: include fontTools.ttLib.tables._h_e_a_d
|
|
# macfreeze: include fontTools.ttLib.tables._h_h_e_a
|
|
# macfreeze: include fontTools.ttLib.tables._h_m_t_x
|
|
# macfreeze: include fontTools.ttLib.tables._k_e_r_n
|
|
# macfreeze: include fontTools.ttLib.tables._l_o_c_a
|
|
# macfreeze: include fontTools.ttLib.tables._m_a_x_p
|
|
# macfreeze: include fontTools.ttLib.tables._n_a_m_e
|
|
# macfreeze: include fontTools.ttLib.tables._p_o_s_t
|
|
# macfreeze: include fontTools.ttLib.tables._p_r_e_p
|
|
# macfreeze: include fontTools.ttLib.tables._v_h_e_a
|
|
# macfreeze: include fontTools.ttLib.tables._v_m_t_x
|
|
# macfreeze: include fontTools.ttLib.tables.L_T_S_H_
|
|
# macfreeze: include fontTools.ttLib.tables.O_S_2f_2
|
|
# macfreeze: include fontTools.ttLib.tables.T_S_I__0
|
|
# macfreeze: include fontTools.ttLib.tables.T_S_I__1
|
|
# macfreeze: include fontTools.ttLib.tables.T_S_I__2
|
|
# macfreeze: include fontTools.ttLib.tables.T_S_I__3
|
|
# macfreeze: include fontTools.ttLib.tables.T_S_I__5
|
|
# macfreeze: include fontTools.ttLib.tables.C_F_F_
|
|
|