[GRASS-SVN] r54324 - grass/trunk/gui/wxpython/animation

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Dec 17 06:14:16 PST 2012


Author: annakrat
Date: 2012-12-17 06:14:15 -0800 (Mon, 17 Dec 2012)
New Revision: 54324

Modified:
   grass/trunk/gui/wxpython/animation/controller.py
   grass/trunk/gui/wxpython/animation/dialogs.py
   grass/trunk/gui/wxpython/animation/utils.py
Log:
wxGUI/animation: export to swf, gif, avi using external python library visvis

Modified: grass/trunk/gui/wxpython/animation/controller.py
===================================================================
--- grass/trunk/gui/wxpython/animation/controller.py	2012-12-17 13:58:20 UTC (rev 54323)
+++ grass/trunk/gui/wxpython/animation/controller.py	2012-12-17 14:14:15 UTC (rev 54324)
@@ -16,12 +16,23 @@
 import os
 import wx
 
+try:
+    import visvis.vvmovie as vv
+    hasVisvis = True
+except ImportError:
+    # if visvis.vvmovie is in grass python library
+    # import grass.visvis as vv
+    # 
+    # question: if integrate visvis, if integrate visvis.vvmovie or only 
+    # images2swf.py, images2gif.py?
+    hasVisvis = False
+
 from core.gcmd import GException, GError, GMessage
 import grass.script as grass
 
 from temporal_manager import TemporalManager
 from dialogs import InputDialog, EditDialog, AnimationData, ExportDialog
-from utils import TemporalMode, Orientation, RenderText
+from utils import TemporalMode, Orientation, RenderText, WxImageToPil
 
 class AnimationController(wx.EvtHandler):
     def __init__(self, frame, sliders, animations, mapwindows, providers, bitmapPool):
@@ -455,7 +466,8 @@
         if not self.animationData:
             GMessage(parent = self.frame, message = _("No animation to export."))
             return
-        dlg = ExportDialog(self.frame, temporal = self.temporalMode)
+        dlg = ExportDialog(self.frame, temporal = self.temporalMode,
+                           timeTick = self.timeTick, visvis = hasVisvis)
         if dlg.ShowModal() == wx.ID_OK:
             decorations = dlg.GetDecorations()
             exportInfo = dlg.GetExportInformation()
@@ -534,8 +546,31 @@
 
             busy.Destroy()
 
+        elif exportInfo['method'] in ('gif', 'swf', 'avi'):
+            pilImages = [WxImageToPil(image) for image in images]
+            
 
+            busy = wx.BusyInfo(message = _("Exporting animation, please wait..."), parent = self.frame)
+            wx.Yield()
+            try:
+                if exportInfo['method'] == 'gif':
+                    vv.writeGif(filename = exportInfo['file'], images = pilImages,
+                                duration = self.timeTick / float(1000), repeat = True)
+                elif exportInfo['method'] == 'swf':
+                    vv.writeSwf(filename = exportInfo['file'], images = pilImages,
+                                duration = self.timeTick / float(1000), repeat = True)
+                elif exportInfo['method'] == 'avi':
+                    vv.writeAvi(filename = exportInfo['file'], images = pilImages,
+                                duration = self.timeTick / float(1000),
+                                encoding = exportInfo['encoding'],
+                                inputOptions = '-sameq')
+            except Exception, e:
+                del busy
+                GError(parent = self.frame, message = str(e))
+                return
+            del busy
 
+
             # image.SaveFile('/home/anna/testy/grass/export/export_%s.png' % frameIndex, wx.BITMAP_TYPE_PNG)
 
 

Modified: grass/trunk/gui/wxpython/animation/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/animation/dialogs.py	2012-12-17 13:58:20 UTC (rev 54323)
+++ grass/trunk/gui/wxpython/animation/dialogs.py	2012-12-17 14:14:15 UTC (rev 54324)
@@ -8,6 +8,7 @@
  - dialogs::InputDialog
  - dialogs::EditDialog
  - dialogs::AnimationData
+ - dialogs::ExportDialog
 
 
 (C) 2012 by the GRASS Development Team
@@ -784,15 +785,16 @@
 
 
 class ExportDialog(wx.Dialog):
-    def __init__(self, parent, temporal):
+    def __init__(self, parent, temporal, timeTick, visvis):
         wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = _("Export animation"),
                            style = wx.DEFAULT_DIALOG_STYLE)
         self.decorations = []
 
         self.temporal = temporal
+        self.timeTick = timeTick
+        self.visvis = visvis
         self._layout()
 
-        self.OnFormatRadio(event = None)
         wx.CallAfter(self._hideAll)
 
     def _layout(self):
@@ -939,70 +941,137 @@
     def _createExportFormatPanel(self, notebook):
         panel = wx.Panel(notebook, id = wx.ID_ANY)
         borderSizer = wx.BoxSizer(wx.VERTICAL)
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        self.gifRadio = wx.RadioButton(panel, id = wx.ID_ANY, 
-                                       label = _("Export to animated GIF (not supported yet):"),
-                                       style = wx.RB_GROUP)
 
-        self.dirRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("Export as image sequence:"))
-        self.dirRadio.SetValue(True)
-        self.gifRadio.Bind(wx.EVT_RADIOBUTTON, self.OnFormatRadio)
-        self.dirRadio.Bind(wx.EVT_RADIOBUTTON, self.OnFormatRadio)
+        if not self.visvis:
+            isVisvisText = wx.StaticText(panel, id = wx.ID_ANY,
+                                     label = _("To enable export to GIF and SWF, please install visvis library."))
+            isVisvisText.Wrap(400)
+            borderSizer.Add(item = isVisvisText, proportion = 0,
+                            flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, border = 5)
 
-        prefixLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("File prefix:"))
-        self.prefixCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = _("animation"))
-        
-        formatLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("File format:"))
-        self.formatChoice = wx.Choice(panel, id = wx.ID_ANY)
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        if not self.visvis:
+            choices = [_("image sequence")]
+        else:
+            choices = [_("image sequence"), _("animated GIF"), _("SWF"), _("AVI")]
+        self.formatChoice = wx.Choice(parent = panel, id = wx.ID_ANY,
+                                      choices = choices)
+        self.formatChoice.Bind(wx.EVT_CHOICE, lambda event: self.ChangeFormat(event.GetSelection()))
+        hSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Export to:")),
+                   proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 2)
+        hSizer.Add(item = self.formatChoice, proportion = 1,
+                   flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, border = 2)
+        borderSizer.Add(item = hSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
+
+        helpSizer = wx.BoxSizer(wx.HORIZONTAL)
+        helpSizer.AddStretchSpacer(1)
+        self.formatPanelSizer = wx.BoxSizer(wx.VERTICAL)
+        helpSizer.Add(self.formatPanelSizer, proportion = 5)
+        borderSizer.Add(helpSizer, proportion = 1, flag = wx.EXPAND)
+        self.formatPanels = []
+
+        # panel for image sequence
+        imSeqPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
+        prefixLabel = wx.StaticText(imSeqPanel, id = wx.ID_ANY, label = _("File prefix:"))
+        self.prefixCtrl = wx.TextCtrl(imSeqPanel, id = wx.ID_ANY, value = _("animation"))
+        formatLabel = wx.StaticText(imSeqPanel, id = wx.ID_ANY, label = _("File format:"))
+        self.imSeqFormatChoice = wx.Choice(imSeqPanel, id = wx.ID_ANY)
         wildcard, ltype = GetImageHandlers(wx.EmptyImage(10, 10))
         formats = [format for format in wildcard.split('|') if 'file' in format]
         for format, cdata in zip(formats, ltype):
-            self.formatChoice.Append(format, cdata)
-
-        self.formatChoice.SetSelection(0)
-        
-        self.dirBrowse = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
-                                                    labelText = _("Export directory:"),
+            self.imSeqFormatChoice.Append(format, cdata)
+        self.imSeqFormatChoice.SetSelection(0)
+        self.dirBrowse = filebrowse.DirBrowseButton(parent = imSeqPanel, id = wx.ID_ANY,
+                                                    labelText = _("Directory:"),
                                                      dialogTitle = _("Choose directory for export"),
                                                      buttonText = _("Browse"),
                                                      startDirectory = os.getcwd())
-        self.gifBrowse = filebrowse.FileBrowseButton(parent = panel, id = wx.ID_ANY,
+
+        dirGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        dirGridSizer.AddGrowableCol(1)
+        dirGridSizer.Add(prefixLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        dirGridSizer.Add(self.prefixCtrl, pos = (0, 1), flag = wx.EXPAND)
+        dirGridSizer.Add(formatLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        dirGridSizer.Add(self.imSeqFormatChoice, pos = (1, 1), flag = wx.EXPAND)
+        dirGridSizer.Add(self.dirBrowse, pos = (2, 0), flag = wx.EXPAND, span = (1, 2))
+        imSeqPanel.SetSizer(dirGridSizer)
+        dirGridSizer.Fit(imSeqPanel)
+
+        self.formatPanelSizer.Add(item = imSeqPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        self.formatPanels.append(imSeqPanel)
+
+        # panel for gif
+        gifPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
+
+        self.gifBrowse = filebrowse.FileBrowseButton(parent = gifPanel, id = wx.ID_ANY,
                                                      fileMask = "GIF file (*.gif)|*.gif",
                                                      labelText = _("GIF file:"),
-                                                     dialogTitle = _("Choose image file"),
+                                                     dialogTitle = _("Choose file to save animation"),
                                                      buttonText = _("Browse"),
                                                      startDirectory = os.getcwd(), fileMode = wx.SAVE)
+        gifGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gifGridSizer.AddGrowableCol(0)
+        gifGridSizer.Add(self.gifBrowse, pos = (0, 0), flag = wx.EXPAND)
+        gifPanel.SetSizer(gifGridSizer)
+        gifGridSizer.Fit(gifPanel)
 
-        sizer.Add(self.gifRadio, proportion = 0, flag = wx.EXPAND)
-        gifSizer = wx.BoxSizer(wx.HORIZONTAL)
-        gifSizer.AddStretchSpacer(prop = 1)
-        gifSizer.Add(self.gifBrowse, proportion = 6, flag = wx.EXPAND)
-        sizer.Add(gifSizer, proportion = 0, flag = wx.EXPAND)
+        self.formatPanelSizer.Add(item = gifPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        self.formatPanels.append(gifPanel)
 
-        sizer.Add(self.dirRadio, proportion = 0, flag = wx.EXPAND)
+        # panel for swf
+        swfPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
+        self.swfBrowse = filebrowse.FileBrowseButton(parent = swfPanel, id = wx.ID_ANY,
+                                                     fileMask = "SWF file (*.swf)|*.swf",
+                                                     labelText = _("SWF file:"),
+                                                     dialogTitle = _("Choose file to save animation"),
+                                                     buttonText = _("Browse"),
+                                                     startDirectory = os.getcwd(), fileMode = wx.SAVE)
+        swfGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        swfGridSizer.AddGrowableCol(0)
+        swfGridSizer.Add(self.swfBrowse, pos = (0, 0), flag = wx.EXPAND)
+        swfPanel.SetSizer(swfGridSizer)
+        swfGridSizer.Fit(swfPanel)
 
-        dirSizer = wx.BoxSizer(wx.HORIZONTAL)
-        dirSizer.AddStretchSpacer(prop = 1)
-        self.dirGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        self.dirGridSizer.AddGrowableCol(1)
-        self.dirGridSizer.Add(prefixLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self.dirGridSizer.Add(self.prefixCtrl, pos = (0, 1), flag = wx.EXPAND)
-        self.dirGridSizer.Add(formatLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self.dirGridSizer.Add(self.formatChoice, pos = (1, 1), flag = wx.EXPAND)
-        self.dirGridSizer.Add(self.dirBrowse, pos = (2, 0), flag = wx.EXPAND, span = (1, 2))
-        dirSizer.Add(self.dirGridSizer, proportion = 6, flag = wx.EXPAND)
+        self.formatPanelSizer.Add(item = swfPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        self.formatPanels.append(swfPanel)
 
-        sizer.Add(dirSizer, proportion = 0, flag = wx.EXPAND)
-        borderSizer.Add(sizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 10)
+        # panel for avi
+        aviPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
+        self.aviBrowse = filebrowse.FileBrowseButton(parent = aviPanel, id = wx.ID_ANY,
+                                                     fileMask = "AVI file (*.avi)|*.avi",
+                                                     labelText = _("AVI file:"),
+                                                     dialogTitle = _("Choose file to save animation"),
+                                                     buttonText = _("Browse"),
+                                                     startDirectory = os.getcwd(), fileMode = wx.SAVE)
+        encodingLabel = wx.StaticText(parent = aviPanel, id = wx.ID_ANY, label = _("Video codec:"))
+        self.encodingText = wx.TextCtrl(parent = aviPanel, id = wx.ID_ANY, value = 'mpeg4')
+        aviGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        aviGridSizer.AddGrowableCol(1)
+        aviGridSizer.Add(self.aviBrowse, pos = (0, 0), span = (1, 2), flag = wx.EXPAND)
+        aviGridSizer.Add(encodingLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        aviGridSizer.Add(self.encodingText, pos = (1, 1), flag = wx.EXPAND)
+        aviPanel.SetSizer(aviGridSizer)
+        aviGridSizer.Fit(aviPanel)
+
+        self.formatPanelSizer.Add(item = aviPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        self.formatPanels.append(aviPanel)
+
+        fpsSizer = wx.BoxSizer(wx.HORIZONTAL)
+        fps = 1000 / self.timeTick
+        fpsSizer.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Current frame rate: %.2f fps") % fps),
+                     proportion = 1, flag = wx.EXPAND)
+        borderSizer.Add(fpsSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
+
         panel.SetSizer(borderSizer)
         borderSizer.Fit(panel)
+        self.ChangeFormat(index = 0)
 
         return panel
 
-    def OnFormatRadio(self, event):
-        self.gifBrowse.Enable(self.gifRadio.GetValue())
-        for child in self.dirGridSizer.GetChildren():
-            child.GetWindow().Enable(self.dirRadio.GetValue())
+    def ChangeFormat(self, index):
+        for i, panel in enumerate(self.formatPanels):
+            self.formatPanelSizer.Show(item = panel, show = (i == index))
+        self.formatPanelSizer.Layout()
 
     def OnFont(self, event):
         index = self.listbox.GetSelection()
@@ -1113,7 +1182,7 @@
                         GError(parent = self, message = _("Decoration image file is missing."))
                     return
 
-        if self.dirRadio.GetValue():
+        if self.formatChoice.GetSelection() == 0:
             name = self.dirBrowse.GetValue()
             if not os.path.exists(name):
                 if name:
@@ -1121,10 +1190,14 @@
                 else:
                     GError(parent = self, message = _("Export directory is missing."))
                 return
-        elif self.gifRadio.GetValue():
+        elif self.formatChoice.GetSelection() == 1:
             if not self.gifBrowse.GetValue():
                 GError(parent = self, message = _("Export file is missing."))
                 return
+        elif self.formatChoice.GetSelection() == 2:
+            if not self.swfBrowse.GetValue():
+                GError(parent = self, message = _("Export file is missing."))
+                return
 
         self.EndModal(wx.ID_OK)
            
@@ -1133,14 +1206,25 @@
 
     def GetExportInformation(self):
         info = {}
-        if self.gifRadio.GetValue():
-            info['method'] = 'gif'
-            info['file'] = self.gifBrowse.GetValue()
-        else:
+        if self.formatChoice.GetSelection() == 0:
             info['method'] = 'sequence'
             info['directory'] = self.dirBrowse.GetValue()
             info['prefix'] = self.prefixCtrl.GetValue()
-            info['format'] = self.formatChoice.GetClientData(self.formatChoice.GetSelection())
+            info['format'] = self.imSeqFormatChoice.GetClientData(self.imSeqFormatChoice.GetSelection())
+
+        elif self.formatChoice.GetSelection() == 1:
+            info['method'] = 'gif'
+            info['file'] = self.gifBrowse.GetValue()
+
+        elif self.formatChoice.GetSelection() == 2:
+            info['method'] = 'swf'
+            info['file'] = self.swfBrowse.GetValue()
+
+        elif self.formatChoice.GetSelection() == 3:
+            info['method'] = 'avi'
+            info['file'] = self.aviBrowse.GetValue()
+            info['encoding'] = self.encodingText.GetValue()
+
         return info
 
     def _updateListBox(self):
@@ -1188,7 +1272,8 @@
     dlg.Show()
 
 def testExport():
-    dlg = ExportDialog(parent = None, temporal = TemporalMode.TEMPORAL)
+    dlg = ExportDialog(parent = None, temporal = TemporalMode.TEMPORAL,
+                       timeTick = 200, visvis = True)
     if dlg.ShowModal() == wx.ID_OK:
         print dlg.GetDecorations()
         print dlg.GetExportInformation()

Modified: grass/trunk/gui/wxpython/animation/utils.py
===================================================================
--- grass/trunk/gui/wxpython/animation/utils.py	2012-12-17 13:58:20 UTC (rev 54323)
+++ grass/trunk/gui/wxpython/animation/utils.py	2012-12-17 14:14:15 UTC (rev 54324)
@@ -18,6 +18,12 @@
 @author Anna Kratochvilova <kratochanna gmail.com>
 """
 import wx
+try:
+    from PIL import Image
+    hasPIL = True
+except ImportError:
+    hasPIL = False
+
 import grass.temporal as tgis
 import grass.script as grass
 
@@ -131,3 +137,9 @@
     dc.SelectObject(wx.NullBitmap)
 
     return bmp
+
+def WxImageToPil(image):
+    """!Converts wx.Image to PIL image"""
+    pilImage = Image.new( 'RGB', (image.GetWidth(), image.GetHeight()) )
+    pilImage.fromstring( image.GetData() )
+    return pilImage



More information about the grass-commit mailing list