from gui.boldstatictext import BoldStaticText
import viewers
import gui.fields
+import gui.plugin
import viewers.raw
import viewers.simple
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# gpdf2swf.py
+# graphical user interface for pdf2swf
+#
+# Part of the swftools package.
+#
+# Copyright (c) 2008,2009 Matthias Kramm <kramm@quiss.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+from __future__ import division
+import os
+import wx
+import time
+import pickle
+
+from lib.wordwrap import wordwrap
+from wx.lib.pubsub import Publisher
+
+from document import Document
+from gui.dialogs import (ProgressDialog, OptionsDialog, AboutDialog, InfoDialog)
+from gui.gmain import (PdfFrame,
+ ID_INVERT_SELECTION, ID_SELECT_ODD,
+ ID_ONE_PAGE_PER_FILE,
+ ID_SELECT_EVEN, ID_DOC_INFO,
+ )
+
+
+def GetDataDir():
+ """
+ Return the standard location on this platform for application data
+ """
+ sp = wx.StandardPaths.Get()
+ return sp.GetUserDataDir()
+
+def GetConfig():
+ if not os.path.exists(GetDataDir()):
+ os.makedirs(GetDataDir())
+
+ config = wx.FileConfig(
+ localFilename=os.path.join(GetDataDir(), "options"))
+ return config
+
+
+class Pdf2Swf:
+ def __init__(self):
+ self.__doc = Document()
+
+ self.__threads = {}
+
+ self.__busy = None
+ self.__progress = None
+
+ self.__can_save = False
+ self.__can_viewinfo = False
+
+ self.view = PdfFrame()
+ wx.GetApp().SetTopWindow(self.view)
+ # Call Show after the current and pending event
+ # handlers have been completed. Otherwise on MSW
+ # we see the frame been draw and after that we saw
+ # the menubar appear
+ wx.CallAfter(self.view.Show)
+
+ self.options = OptionsDialog(self.view)
+ self.__ReadConfigurationFile()
+
+ self.view.toolbar_preview_type.SetSelection(0)
+
+ Publisher.subscribe(self.OnPageChanged, "PAGE_CHANGED")
+ Publisher.subscribe(self.OnFileLoaded, "FILE_LOADED")
+ Publisher.subscribe(self.OnFileNotLoaded, "FILE_NOT_LOADED")
+ Publisher.subscribe(self.OnDiffSizes, "DIFF_SIZES")
+ Publisher.subscribe(self.OnThumbnailAdded, "THUMBNAIL_ADDED")
+ Publisher.subscribe(self.OnThumbnailDone, "THUMBNAIL_DONE")
+ Publisher.subscribe(self.OnProgressBegin, "SWF_BEGIN_SAVE")
+ Publisher.subscribe(self.OnProgressUpdate, "SWF_PAGE_SAVED")
+ Publisher.subscribe(self.OnProgressDone, "SWF_FILE_SAVED")
+ Publisher.subscribe(self.OnCombineError, "SWF_COMBINE_ERROR")
+ Publisher.subscribe(self.OnFileDroped, "FILE_DROPED")
+ Publisher.subscribe(self.OnFilesDroped, "FILES_DROPED")
+ Publisher.subscribe(self.OnPluginOnePagePerFileNotSupported,
+ "PLUGIN_ONE_PAGE_PER_FILE_NOT_SUPPORTED")
+ Publisher.subscribe(self.OnPluginError, "PLUGIN_ERROR")
+
+ self.view.Bind(wx.EVT_MENU, self.OnMenuOpen, id=wx.ID_OPEN)
+ self.view.Bind(wx.EVT_MENU, self.OnMenuSave, id=wx.ID_SAVE)
+ self.view.Bind(wx.EVT_MENU, self.OnMenuSaveSelected, id=wx.ID_SAVEAS)
+ self.view.Bind(wx.EVT_MENU, self.OnMenuExit, id=wx.ID_EXIT)
+ self.view.Bind(wx.EVT_MENU_RANGE, self.OnFileHistory,
+ id=wx.ID_FILE1, id2=wx.ID_FILE9)
+
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_SAVE)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_SAVEAS)
+
+ self.view.Bind(wx.EVT_MENU, self.OnMenuSelectAll, id=wx.ID_SELECTALL)
+ self.view.Bind(wx.EVT_MENU,
+ self.OnMenuInvertSelection, id=ID_INVERT_SELECTION)
+ self.view.Bind(wx.EVT_MENU, self.OnMenuSelectOdd, id=ID_SELECT_ODD)
+ self.view.Bind(wx.EVT_MENU, self.OnMenuSelectEven, id=ID_SELECT_EVEN)
+ self.view.Bind(wx.EVT_MENU, self.OnMenuOptions, id=wx.ID_PREFERENCES)
+
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_SELECTALL)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_INVERT_SELECTION)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_SELECT_ODD)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_SELECT_EVEN)
+
+ self.view.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT)
+
+ self.view.Bind(wx.EVT_MENU, self.OnZoom, id=wx.ID_ZOOM_IN)
+ self.view.Bind(wx.EVT_MENU, self.OnZoom, id=wx.ID_ZOOM_OUT)
+ self.view.Bind(wx.EVT_MENU, self.OnZoom, id=wx.ID_ZOOM_100)
+ self.view.Bind(wx.EVT_MENU, self.OnFit, id=wx.ID_ZOOM_FIT)
+ self.view.Bind(wx.EVT_MENU, self.OnShowDocInfo, id=ID_DOC_INFO)
+
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_IN)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_OUT)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_100)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_FIT)
+ self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUIInfo, id=ID_DOC_INFO)
+
+ self.view.page_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectItem)
+ self.view.Bind(wx.EVT_CLOSE, self.OnMenuExit)
+
+ self.view.toolbar_preview_type.Bind(wx.EVT_CHOICE,
+ self.OnPreviewType)
+
+ # statusbar cancel thumbanails generation button
+ self.view.statusbar.btn_cancel.Bind(wx.EVT_BUTTON,
+ self.OnThumbnailCancel)
+
+ def OnFilesDroped(self, evt):
+ dlg = wx.MessageDialog(self.view,
+ u"You must drop only one file.",
+ u"Notice",
+ style=wx.OK, pos=wx.DefaultPosition)
+ dlg.ShowModal()
+ dlg.Destroy()
+
+ def OnFileDroped(self, message):
+ self.__Load(message.data["filename"])
+
+ def OnPluginOnePagePerFileNotSupported(self, message):
+ self.Message(u"Selected viewer does not support "
+ u"one page per file. ")
+
+ def OnPluginError(self, message):
+ self.Message(u"Error applying selected viewer")
+
+ def OnFileHistory(self, evt):
+ # get the file based on the menu ID
+ fileNum = evt.GetId() - wx.ID_FILE1
+ filename = self.view.filehistory.GetHistoryFile(fileNum)
+
+ self.__Load(filename)
+
+ def OnProgressBegin(self, message):
+ pages = message.data["pages"]
+ style = (
+ wx.PD_APP_MODAL|wx.PD_ELAPSED_TIME|
+ wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT|
+ wx.PD_AUTO_HIDE
+ )
+ self.__progress = ProgressDialog(u"Saving...",
+ u"Start saving SWF pages",
+ maximum=pages,
+ parent=self.view, style=style)
+ self.__progress.Show()
+ self.view.SetStatusText(u"Saving document...")
+
+ def OnProgressUpdate(self, message):
+ pagenr = message.data["pagenr"]
+ pages = message.data["pages"]
+
+ keep_running = self.__progress.Update(
+ pagenr,
+ u"Saving SWF page %d of %d" % (pagenr, pages)
+ )
+
+ if not keep_running and self.__threads.has_key("progress"):
+ self.view.SetStatusText(u"Cancelling...")
+ self.__threads.pop("progress").Stop()
+
+
+ def OnProgressDone(self, message):
+ if self.__threads.has_key("progress"): # it goes all the way?
+ self.__threads.pop("progress")
+ self.view.SetStatusText(u"SWF document saved successfully.")
+ else:
+ self.view.SetStatusText(u"")
+
+ self.__progress.Destroy()
+ self.__progress = None
+
+ def OnCombineError(self, message):
+ from wx.lib.dialogs import ScrolledMessageDialog
+ ScrolledMessageDialog(self.view, message.data, u"Notice").ShowModal()
+
+
+ def OnThumbnailAdded(self, message):
+ self.view.statusbar.SetGaugeValue(message.data['pagenr'])
+ tot = self.view.page_list.GetItemCount()
+ self.view.SetStatusText(u"Generating thumbnails %s/%d" %
+ (message.data['pagenr'], tot), 0)
+
+ def OnThumbnailDone(self, message):
+ self.view.statusbar.SetGaugeValue(0)
+ self.view.SetStatusText(u"", 0)
+ if self.__threads.has_key("thumbnails"):
+ self.__threads.pop("thumbnails")
+ self.view.SendSizeEvent()
+
+ def OnThumbnailCancel(self, event):
+ if self.__threads.has_key("thumbnails"):
+ self.__threads["thumbnails"].Stop()
+
+ def OnSelectItem(self, event):
+ self.__doc.ChangePage(event.GetIndex() + 1)
+
+ def OnPreviewType(self, event):
+ filename = self.__doc.filename
+ if filename:
+ self.__Load(filename)
+
+ def OnPageChanged(self, message):
+ # ignore if we have more than one item selected
+ if self.view.page_list.GetSelectedItemCount() > 1:
+ return
+
+ self.view.page_preview.DisplayPage(message.data)
+
+ def SetTitle(self):
+ name = wx.GetApp().GetAppName()
+ filename = os.path.basename(self.__doc.filename)
+ if self.__doc.title != "n/a":
+ t = "%s - %s (%s)" % (name, filename, self.__doc.title)
+ else:
+ t = "%s - %s" % (name, filename)
+ self.view.SetTitle(t)
+
+ def OnFileLoaded(self, message):
+ if self.__progress:
+ self.__progress.Destroy()
+ self.__progress = None
+
+ self.__can_viewinfo = True
+ del self.__busy
+
+ self.SetTitle()
+
+ if self.__doc.oktocopy == 'no':
+ self.__can_save = False
+ self.view.page_list.DisplayEmptyThumbnails(0)
+ self.view.page_preview.Clear()
+ self.view.SetStatusText(u"")
+ self.Message(
+ u"This PDF disallows copying, cannot be converted."
+ )
+ return
+
+ #if not self.__doc.oktoprint:
+ self.view.SetStatusText(u"Document loaded successfully.")
+
+ self.view.page_list.DisplayEmptyThumbnails(message.data["pages"])
+ thumbs = self.__doc.GetThumbnails()
+ t = self.view.page_list.DisplayThumbnails(thumbs)
+ self.__threads["thumbnails"] = t
+ self.view.statusbar.SetGaugeRange(message.data["pages"])
+ #del self.__busy
+
+ def OnFileNotLoaded(self, message):
+ self.__can_save = False
+ self.__can_viewinfo = False
+ del self.__busy
+ self.view.SetStatusText(u"")
+ self.Message(
+ u"Could not open file %s" % message.data['filename']
+ )
+
+ def OnDiffSizes(self, message):
+ # just let the user know- for now, we can't handle this properly
+ self.Message(
+ u"In this PDF, width or height are not the same for "
+ u"each page. This might cause problems if you export "
+ u"pages of different dimensions into the same SWF file."
+ )
+
+ def OnMenuOpen(self, event):
+ dlg = wx.FileDialog(self.view, u"Choose PDF File:",
+ style=wx.OPEN|wx.CHANGE_DIR,
+ wildcard = u"PDF files (*.pdf)|*.pdf|all files (*.*)|*.*")
+
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ self.__Load(filename)
+
+ def OnMenuSave(self, event, pages=None):
+ defaultFile = self.__doc.lastsavefile
+ if "wxMSW" in wx.PlatformInfo:
+ allFiles = "*.*"
+ else:
+ allFiles = "*"
+ self.view.SetStatusText(u"")
+ dlg = wx.FileDialog(self.view, u"Choose Save Filename:",
+ style = wx.SAVE | wx.OVERWRITE_PROMPT,
+ defaultFile=os.path.basename(defaultFile),
+ wildcard=u"SWF files (*.swf)|*.swf"
+ "|all files (%s)|%s" % (allFiles, allFiles))
+
+
+ if dlg.ShowModal() == wx.ID_OK:
+ menubar = self.view.GetMenuBar()
+ one_file_per_page = menubar.IsChecked(ID_ONE_PAGE_PER_FILE)
+
+ self.__threads["progress"] = self.__doc.SaveSWF(dlg.GetPath(),
+ one_file_per_page,
+ pages, self.options)
+
+ def OnUpdateUI(self, event):
+ menubar = self.view.GetMenuBar()
+ menubar.Enable(event.GetId(), self.__can_save)
+
+ self.view.GetToolBar().EnableTool(event.GetId(), self.__can_save)
+
+ def OnUpdateUIInfo(self, event):
+ menubar = self.view.GetMenuBar()
+ menubar.Enable(event.GetId(), self.__can_viewinfo)
+
+ self.view.GetToolBar().EnableTool(event.GetId(), self.__can_viewinfo)
+
+ def OnMenuSaveSelected(self, event):
+ pages = []
+ page = self.view.page_list.GetFirstSelected()
+ pages.append(page+1)
+
+ while True:
+ page = self.view.page_list.GetNextSelected(page)
+ if page == -1:
+ break
+ pages.append(page+1)
+
+ self.OnMenuSave(event, pages)
+
+ def OnMenuExit(self, event):
+ self.view.SetStatusText(u"Cleaning up...")
+
+ # Stop any running thread
+ self.__StopThreads()
+
+ config = GetConfig()
+ self.view.filehistory.Save(config)
+ config.Flush()
+ # A little extra cleanup is required for the FileHistory control
+ del self.view.filehistory
+
+ # Save quality options
+ dirpath = GetDataDir()
+ data = self.options.quality_panel.pickle()
+ try:
+ f = file(os.path.join(dirpath, 'quality.pkl'), 'wb')
+ pickle.dump(data, f)
+ f.close()
+ except Exception:
+ pass
+
+ # Save viewer options
+ try:
+ f = file(os.path.join(dirpath, 'viewers.pkl'), 'wb')
+ data = self.options.viewers_panel.pickle()
+ pickle.dump(data, f)
+ f.close()
+ except Exception:
+ pass
+
+ self.view.Destroy()
+
+ def OnMenuSelectAll(self, event):
+ for i in range(0, self.view.page_list.GetItemCount()):
+ self.view.page_list.Select(i, True)
+
+ def OnMenuInvertSelection(self, event):
+ for i in range(0, self.view.page_list.GetItemCount()):
+ self.view.page_list.Select(i, not self.view.page_list.IsSelected(i))
+
+ def OnMenuSelectOdd(self, event):
+ for i in range(0, self.view.page_list.GetItemCount()):
+ self.view.page_list.Select(i, not bool(i%2))
+
+ def OnMenuSelectEven(self, event):
+ for i in range(0, self.view.page_list.GetItemCount()):
+ self.view.page_list.Select(i, bool(i%2))
+
+ def OnMenuOptions(self, event):
+ self.options.ShowModal()
+
+ def OnFit(self, event):
+ self.__doc.Fit(self.view.page_preview.GetClientSize())
+
+ def OnZoom(self, event):
+ zoom = {
+ wx.ID_ZOOM_IN: .1,
+ wx.ID_ZOOM_OUT: -.1,
+ wx.ID_ZOOM_100: 1,
+ }
+ self.__doc.Zoom(zoom[event.GetId()])
+
+ def OnShowDocInfo(self, event):
+ info = InfoDialog(self.view)
+ info.info.display(self.__doc)
+ info.Show()
+
+ def OnAbout(self, evt):
+ AboutDialog(self.view)
+
+ def __Load(self, filename):
+ self.__can_save = True
+ self.__StopThreads()
+ self.view.SetStatusText(u"Loading document...")
+ self.__busy = wx.BusyInfo(u"One moment please, "
+ u"opening pdf document...")
+
+ self.view.filehistory.AddFileToHistory(filename)
+ try:
+ # I dont care if this, for some reason,
+ # give some error. I just swallow it
+ os.chdir(os.path.dirname(filename))
+ except:
+ pass
+
+ # Need to delay the file load a little bit
+ # for the BusyInfo get a change to repaint itself
+ #wx.FutureCall(150, self.__doc.Load, filename)
+ sel = self.view.toolbar_preview_type.GetSelection()
+ #print sel
+ PREV_TYPE = {
+ 0 : [('bitmap', '1'), ('poly2bitmap', '0'), ('bitmapfonts', '1'),],
+ 1 : [('bitmap', '0'), ('poly2bitmap', '1'), ('bitmapfonts', '0'),],
+ 2 : [('bitmap', '0'), ('poly2bitmap', '0'), ('bitmapfonts', '0'),],
+ }
+ self.__doc.preview_parameters = PREV_TYPE[sel]
+ wx.CallAfter(self.__doc.Load, filename)
+
+ def __StopThreads(self):
+ for n, t in self.__threads.items():
+ t.Stop()
+
+ running = True
+ while running:
+ running = False
+ for n, t in self.__threads.items():
+ running = running + t.IsRunning()
+ time.sleep(0.1)
+
+ def __ReadConfigurationFile(self):
+ config = GetConfig()
+ self.view.filehistory.Load(config)
+
+ dirpath = GetDataDir()
+ try:
+ f = file(os.path.join(dirpath, 'quality.pkl'), 'rb')
+ #try:
+ if 1:
+ data = pickle.load(f)
+ self.options.quality_panel.unpickle(data)
+ #except:
+ # self.Message(
+ # u"Error loading quality settings. "
+ # u"They will be reset to defaults. ")
+ f.close()
+ except Exception:
+ pass
+
+ try:
+ f = file(os.path.join(dirpath, 'viewers.pkl'), 'rb')
+ #try:
+ if 1:
+ data = pickle.load(f)
+ self.options.viewers_panel.unpickle(data)
+ #except:
+ # self.Message(
+ # u"Error loading viewers settings. "
+ # u"They will be reset to defaults. ")
+ f.close()
+ except Exception:
+ pass
+ #d = pickle.load(f)
+
+ def Message(self, message):
+ dlg = wx.MessageDialog(self.view,
+ message,
+ style=wx.OK, pos=wx.DefaultPosition)
+ dlg.ShowModal()
+ dlg.Destroy()
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# gpdf2swf.py
+# graphical user interface for pdf2swf
+#
+# Part of the swftools package.
+#
+# Copyright (c) 2008,2009 Matthias Kramm <kramm@quiss.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+from __future__ import division
+import os
+import time
+import thread
+import gfx
+import wx
+from wx.lib.pubsub import Publisher
+from subprocess import Popen, PIPE
+
+class _SaveSWFThread:
+ def __init__(self, pdffilename, filename, one_page_per_file, doc, pages, options):
+ #self.__doc = doc
+ self.__filename = filename
+ self.__pdffilename = pdffilename
+ self.__pages = pages or range(1, doc.pages+1)
+ self.__options = options
+ self.__one_page_per_file = one_page_per_file
+
+ def Start(self):
+ self.__keep_running = self.__running = True
+ thread.start_new_thread(self.Run, ())
+ #self.Run()
+
+ def Stop(self):
+ self.__keep_running = False
+
+ def IsRunning(self):
+ return self.__running
+
+ def Run(self):
+ swf = gfx.SWF()
+
+ try:
+ plugin = self.__options.viewers.init(swf, self.__filename)
+ except Exception, e:
+ wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR")
+ self.__running = False
+ return
+
+ if self.__one_page_per_file and not plugin.one_page_per_file:
+ wx.CallAfter(Publisher.sendMessage,
+ "PLUGIN_ONE_PAGE_PER_FILE_NOT_SUPPORTED",
+ {'plugin': plugin,})
+ self.__running = False
+ return
+
+ pages = len(self.__pages)
+ wx.CallAfter(Publisher.sendMessage, "SWF_BEGIN_SAVE",
+ {'pages': pages,})
+
+ time.sleep(0.05)
+
+ self.setparameters(gfx)
+ self.__doc = gfx.open("pdf", self.__pdffilename)
+
+ self.setparameters(swf)
+
+ try:
+ plugin.before_render()
+ except Exception, e:
+ wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR")
+ self.__running = False
+ return
+
+ for pagenr in self.__pages:
+ page = self.__doc.getPage(pagenr)
+ swf.startpage(page.width, page.height)
+ page.render(swf)
+ swf.endpage()
+ wx.CallAfter(Publisher.sendMessage, "SWF_PAGE_SAVED",
+ {'pagenr': pagenr,
+ 'pages': pages,})
+ time.sleep(0.05)
+
+ if self.__one_page_per_file:
+ form = '.%%0%dd.swf' % len(str(len(self.__pages)))
+ filename = self.__filename.replace('.swf', form % pagenr)
+ swf.save(filename)
+ swf = gfx.SWF()
+ self.setparameters(swf)
+
+ if not self.__keep_running:
+ break
+ else:
+ # This will not run if we break the for loop
+ if not self.__one_page_per_file:
+ try:
+ plugin.before_save(page)
+ except Exception, e:
+ wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR")
+ self.__running = False
+ return
+ swf.save(self.__filename)
+ try:
+ plugin.after_save(page)
+ except Exception, e:
+ wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR")
+ self.__running = False
+ return
+
+ # No need. But to be sure that it's clean up
+ # as soon as possible
+ del swf
+
+ wx.CallAfter(Publisher.sendMessage, "SWF_FILE_SAVED")
+ time.sleep(0.05)
+
+ self.__running = False
+
+ def setparameters(self, swf):
+ #print "driver", swf
+ for opt in self.__options.quality:
+ if type(opt.name) in (tuple, list):
+ for name, value in (
+ # Example to better understand the list comprehension:
+ # opt.name = ['a', 'b', 'c']
+ # opt.value = [1, 2, 3]
+ # zip them = [('a',1), ('b', 2), ('c', 3)]
+ # pair will be in this example ('a', 1) due to
+ # the if pair[1] condition
+ pair for pair in zip(opt.name, opt.value) #if pair[1] == 1
+ ):
+ #print "1.swf.setparameter(%s, %s)" % (name, value)
+ swf.setparameter(str(name), str(value))
+ else:
+ #print "2.swf.setparameter(%s, %s)" % (opt.name, str(opt.value))
+ swf.setparameter(opt.name, str(opt.value))
+
+ #swf.setparameter('noclips', '1')
+ #swf.setparameter('reordertags', '1')
+ #swf.setparameter('animate', '1')
+
+PDF_INFO = [
+ "title", "subject", "keywords", "author",
+ "creator", "producer", "creationdate", "moddate",
+ "linearized", "tagged", "encrypted", "oktoprint",
+ "oktocopy", "oktochange", "oktoaddnotes", "version",
+]
+
+class Document(object):
+ def __init__(self):
+ self.__page = None
+ self.__zoom = 1
+ self.__lastsavefile = "output.swf"
+ self.__pdffilename = None
+ self.__preview_parameters = []
+
+ def __getattr__(self, name):
+ if name in PDF_INFO:
+ return self.__pdf.getInfo(name) or "n/a"
+ raise AttributeError, name
+
+ def filename(self):
+ return self.__pdffilename
+ filename = property(filename)
+
+ def __get_lastsavefile(self):
+ return self.__lastsavefile
+ def __set_lastsavefile(self, lastsavefile):
+ self.__lastsavefile = lastsavefile
+ lastsavefile = property(__get_lastsavefile, __set_lastsavefile)
+
+ def __SwapExtension(self, filename, newext):
+ basename, ext = os.path.splitext(filename)
+ return "%s.%s" % (basename, newext)
+
+ def __Reload(self):
+ Publisher.sendMessage("PAGE_CHANGED",
+ {'page': self.__page,
+ 'width': int(self.__page.width * self.__zoom),
+ 'height': int(self.__page.height * self.__zoom)})
+
+ def __get_preview_parameters(self):
+ return self.__preview_parameters
+ def __set_preview_parameters(self, parameters):
+ self.__preview_parameters = parameters
+ preview_parameters = property(__get_preview_parameters,
+ __set_preview_parameters)
+
+ def Load(self, filename):
+ self.__lastsavefile = self.__SwapExtension(filename, "swf")
+ self.__pdffilename = filename
+
+ #print 'Load',self.__preview_parameters
+ for parameter, value in self.__preview_parameters:
+ gfx.setparameter(parameter, value)
+
+ try:
+ self.__pdf = gfx.open("pdf", filename)
+ except:
+ Publisher.sendMessage("FILE_NOT_LOADED", {'filename': filename})
+ else:
+ Publisher.sendMessage("FILE_LOADED", {'pages': self.__pdf.pages})
+
+ def ChangePage(self, pagenr=1, size=None):
+ self.__page = page = self.__pdf.getPage(pagenr)
+ self.__Reload()
+
+ def Fit(self, size):
+ w = size[0] / self.__page.width
+ h = size[1] / self.__page.height
+ self.__zoom = min(w, h)
+ self.__Reload()
+
+ def Zoom(self, zoom):
+ if zoom == 1:
+ self.__zoom = 1
+ else:
+ self.__zoom += zoom
+ self.__Reload()
+
+ def GetThumbnails(self):
+ for pagenr in range(1, self.__pdf.pages + 1):
+ page = self.__pdf.getPage(pagenr)
+ yield page
+
+ def SaveSWF(self, filename, one_page_per_file, pages, options):
+ self.__lastsavefile = filename
+ t = _SaveSWFThread(self.__pdffilename, filename, one_page_per_file, self.__pdf, pages, options)
+ t.Start()
+ return t
+
+
--- /dev/null
+#----------------------------------------------------------------------
+# Name: wx.lib.embeddedimage
+# Purpose: Defines a class used for embedding PNG images in Python
+# code. The primary method of using this module is via
+# the code generator in wx.tools.img2py.
+#
+# Author: Anthony Tuininga
+#
+# Created: 26-Nov-2007
+# RCS-ID: $Id: embeddedimage.py 59672 2009-03-20 20:59:42Z RD $
+# Copyright: (c) 2007 by Anthony Tuininga
+# Licence: wxWindows license
+#----------------------------------------------------------------------
+
+import base64
+import cStringIO
+import wx
+
+try:
+ b64decode = base64.b64decode
+except AttributeError:
+ b64decode = base64.decodestring
+
+
+class PyEmbeddedImage(object):
+ """
+ PyEmbeddedImage is primarily intended to be used by code generated
+ by img2py as a means of embedding image data in a python module so
+ the image can be used at runtime without needing to access the
+ image from an image file. This makes distributing icons and such
+ that an application uses simpler since tools like py2exe will
+ automatically bundle modules that are imported, and the
+ application doesn't have to worry about how to locate the image
+ files on the user's filesystem.
+
+ The class can also be used for image data that may be acquired
+ from some other source at runtime, such as over the network or
+ from a database. In this case pass False for isBase64 (unless the
+ data actually is base64 encoded.) Any image type that
+ wx.ImageFromStream can handle should be okay.
+ """
+
+ def __init__(self, data, isBase64=True):
+ self.data = data
+ self.isBase64 = isBase64
+
+ def GetBitmap(self):
+ return wx.BitmapFromImage(self.GetImage())
+
+ def GetData(self):
+ if self.isBase64:
+ data = b64decode(self.data)
+ return data
+
+ def GetIcon(self):
+ icon = wx.EmptyIcon()
+ icon.CopyFromBitmap(self.GetBitmap())
+ return icon
+
+ def GetImage(self):
+ stream = cStringIO.StringIO(self.GetData())
+ return wx.ImageFromStream(stream)
+
+ # added for backwards compatibility
+ getBitmap = GetBitmap
+ getData = GetData
+ getIcon = GetIcon
+ getImage = GetImage
+
+ # define properties, for convenience
+ Bitmap = property(GetBitmap)
+ Icon = property(GetIcon)
+ Image = property(GetImage)
+
--- /dev/null
+#----------------------------------------------------------------------
+# This file was generated by /usr/bin/img2py
+#
+from embeddedimage import PyEmbeddedImage
+
+blank = PyEmbeddedImage(
+ "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAZiS0dE"
+ "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kHDAscKjCK/4UAAABo"
+ "SURBVHja7dABAcBAEAIgXf/Ofo8dRKDblqPa5stxAgQIECBAgAABAgQIECBAgAABAgQIECBA"
+ "gAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEPALTbLLAQ8OIAV9"
+ "8WNeKwAAAABJRU5ErkJggg==")
+getblankData = blank.GetData
+getblankImage = blank.GetImage
+getblankBitmap = blank.GetBitmap
+getblankIcon = blank.GetIcon
+
+#----------------------------------------------------------------------
+stop = PyEmbeddedImage(
+ "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAAZiS0dE"
+ "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kHGAEINtjJMYEAAADV"
+ "SURBVBjTPc8xTgJBAEbh988sLFkDXEAvgB338AhauI3EUqOVVhR6gq0s9Do2WpDVipaOLCZL"
+ "LGZ+G+IJ3ve0KssBUo3UWAJANtgL7JcCqXZVNcxmKXVdBBMn06S2bdT3xOvh8D3P50nPTyF2"
+ "O3xyjG9vpI/PrM3mrHAI/PZ9PHp79Xi5VAZ+7u7t7TY6BAI2g/2ehDAgBXSwABTKmWIyTr44"
+ "D93Do0FQX6Kv76T1Omo1Gl25qhqdzlLqdtE5E6fTpLaN6vuFVmU5kFQTQmMdMjn/b/4BTeBh"
+ "NrAp1ecAAAAASUVORK5CYII=")
+getstopData = stop.GetData
+getstopImage = stop.GetImage
+getstopBitmap = stop.GetBitmap
+getstopIcon = stop.GetIcon
+
+#----------------------------------------------------------------------
+gpdf2swf = PyEmbeddedImage(
+ "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"
+ "fQAAAABJRU5ErkJggg==")
+getgpdf2swfData = gpdf2swf.GetData
+getgpdf2swfImage = gpdf2swf.GetImage
+getgpdf2swfBitmap = gpdf2swf.GetBitmap
+getgpdf2swfIcon = gpdf2swf.GetIcon
+
--- /dev/null
+import wx
+
+def blank_bmp(w, h, color="white"):
+ bmp = wx.EmptyBitmap(max(w,1) , max(h,1))
+ clear_bmp(bmp, color)
+ return bmp
+
+def clear_bmp(bmp, color):
+ dc = wx.MemoryDC()
+ dc.SelectObject(bmp)
+ dc.SetBackground(wx.Brush(color))
+ dc.Clear()
+
+
+# Taken and adapt from django.utils.encoding
+class GPdf2SwfUnicodeDecodeError(UnicodeDecodeError):
+ def __init__(self, obj, *args):
+ self.obj = obj
+ UnicodeDecodeError.__init__(self, *args)
+
+ def __str__(self):
+ original = UnicodeDecodeError.__str__(self)
+ return '%s. You passed in %r (%s)' % (original, self.obj,
+ type(self.obj))
+
+def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
+ try:
+ if not isinstance(s, basestring,):
+ if hasattr(s, '__unicode__'):
+ s = unicode(s)
+ else:
+ try:
+ s = unicode(str(s), encoding, errors)
+ except UnicodeEncodeError:
+ if not isinstance(s, Exception):
+ raise
+ # If we get to here, the caller has passed in an Exception
+ # subclass populated with non-ASCII data without special
+ # handling to display as a string. We need to handle this
+ # without raising a further exception. We do an
+ # approximation to what the Exception's standard str()
+ # output should be.
+ s = ' '.join([force_unicode(arg, encoding, strings_only,
+ errors) for arg in s])
+ elif not isinstance(s, unicode):
+ # Note: We use .decode() here, instead of unicode(s, encoding,
+ # errors), so that if s is a SafeString, it ends up being a
+ # SafeUnicode at the end.
+ s = s.decode(encoding, errors)
+ except UnicodeDecodeError, e:
+ raise GPdf2SwfUnicodeDecodeError(s, *e.args)
+ #raise UnicodeDecodeError(*e.args)
+ return s
+
+
--- /dev/null
+#----------------------------------------------------------------------
+# Name: wx.lib.wordwrap
+# Purpose: Contains a function to aid in word-wrapping some text
+#
+# Author: Robin Dunn
+#
+# Created: 15-Oct-2006
+# RCS-ID: $Id: wordwrap.py 54718 2008-07-19 18:57:26Z RD $
+# Copyright: (c) 2006 by Total Control Software
+# Licence: wxWindows license
+#----------------------------------------------------------------------
+
+def wordwrap(text, width, dc, breakLongWords=True, margin=0):
+ """
+ Returns a copy of text with newline characters inserted where long
+ lines should be broken such that they will fit within the given
+ width, with the given margin left and right, on the given `wx.DC`
+ using its current font settings. By default words that are wider
+ than the margin-adjusted width will be broken at the nearest
+ character boundary, but this can be disabled by passing ``False``
+ for the ``breakLongWords`` parameter.
+ """
+
+ wrapped_lines = []
+ text = text.split('\n')
+ for line in text:
+ pte = dc.GetPartialTextExtents(line)
+ wid = ( width - (2*margin+1)*dc.GetTextExtent(' ')[0]
+ - max([0] + [pte[i]-pte[i-1] for i in range(1,len(pte))]) )
+ idx = 0
+ start = 0
+ startIdx = 0
+ spcIdx = -1
+ while idx < len(pte):
+ # remember the last seen space
+ if line[idx] == ' ':
+ spcIdx = idx
+
+ # have we reached the max width?
+ if pte[idx] - start > wid and (spcIdx != -1 or breakLongWords):
+ if spcIdx != -1:
+ idx = spcIdx + 1
+ wrapped_lines.append(' '*margin + line[startIdx : idx] + ' '*margin)
+ start = pte[idx]
+ startIdx = idx
+ spcIdx = -1
+
+ idx += 1
+
+ wrapped_lines.append(' '*margin + line[startIdx : idx] + ' '*margin)
+
+ return '\n'.join(wrapped_lines)
+
+
+
+if __name__ == '__main__':
+ import wx
+ class TestPanel(wx.Panel):
+ def __init__(self, parent):
+ wx.Panel.__init__(self, parent)
+
+ self.tc = wx.TextCtrl(self, -1, "", (20,20), (150,150), wx.TE_MULTILINE)
+ self.Bind(wx.EVT_TEXT, self.OnDoUpdate, self.tc)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+
+
+ def OnSize(self, evt):
+ wx.CallAfter(self.OnDoUpdate, None)
+
+
+ def OnDoUpdate(self, evt):
+ WIDTH = self.GetSize().width - 220
+ HEIGHT = 200
+ bmp = wx.EmptyBitmap(WIDTH, HEIGHT)
+ mdc = wx.MemoryDC(bmp)
+ mdc.SetBackground(wx.Brush("white"))
+ mdc.Clear()
+ mdc.SetPen(wx.Pen("black"))
+ mdc.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
+ mdc.DrawRectangle(0,0, WIDTH, HEIGHT)
+
+ text = wordwrap(self.tc.GetValue(), WIDTH-2, mdc, False)
+ #print repr(text)
+ mdc.DrawLabel(text, (1,1, WIDTH-2, HEIGHT-2))
+
+ del mdc
+ dc = wx.ClientDC(self)
+ dc.DrawBitmap(bmp, 200, 20)
+
+
+ app = wx.App(False)
+ frm = wx.Frame(None, title="Test wordWrap")
+ pnl = TestPanel(frm)
+ frm.Show()
+ app.MainLoop()
+
+