"""Main TTX application, Mac-only""" __version__ = "1.0a6" #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 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, 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) srcfilename = dstfilename = os.path.basename(path) if dstfilename[-4:] == ".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 XML 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) filename = os.path.basename(path) pb = ProgressBar("Dumping '%s' to XML..." % filename) if filename[-4:] in (".TTF", ".ttf"): filename = filename[:-4] filename = filename + ".xml" 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) 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 + ".xml") 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 == "": 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_