Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
hugin_executor.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
12 /* This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This software is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public
23  * License along with this software. If not, see
24  * <http://www.gnu.org/licenses/>.
25  *
26  */
27 
28 #include <hugin_config.h>
29 
30 #include <fstream>
31 #include <sstream>
32 
33 #include <wx/app.h>
34 #include <wx/cmdline.h>
35 #include <wx/arrstr.h>
36 #include <wx/stdpaths.h>
37 #if defined _WIN32
38 // undefine DIFFERENCE defined in windows.h (included by wx/app.h)
39 #undef DIFFERENCE
40 #endif
41 
42 #include "base_wx/huginConfig.h"
43 #include "base_wx/platform.h"
44 #include "panodata/Panorama.h"
45 #include "hugin/config_defaults.h"
46 
47 #include "base_wx/Executor.h"
50 
51 #ifdef __WXMAC__
52 // on wxMac wxAppConsole stores the settings in another folder, so we have to use wxApp to
53 // retrieve our settings which are stored by Hugin
54 // wxAppConsole is accessing preferences in $HOME/appname Preferences
55 // wxApp is accessing preferences in $HOME/Library/Preferences/appname Preferences
56 #define APP wxApp
57 #else
58 #define APP wxAppConsole
59 #endif
60 
61 class HuginExecutor : public APP
62 {
64  virtual bool OnInit()
65  {
66  wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
67  m_utilsBinDir=exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
68 #if defined __WXMSW__
69  // locale setup
70  exePath.RemoveLastDir();
71  m_locale.AddCatalogLookupPathPrefix(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + wxT("share\\locale"));
72 #elif defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
73  // nothing to do
74 #elif defined UNIX_SELF_CONTAINED_BUNDLE
75  // initialize paths
76  {
77  wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
78  exePath.RemoveLastDir();
79  const wxString huginRoot=exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
80  // add the locale directory specified during configure
81  m_locale.AddCatalogLookupPathPrefix(huginRoot + wxT("share/locale"));
82  }
83 #else
84  // add the locale directory specified during configure
85  m_locale.AddCatalogLookupPathPrefix(wxT(INSTALL_LOCALE_DIR));
86 #endif
87  // init our config settings
88 #if defined __WXGTK__
89  CheckConfigFilename();
90 #endif
91  wxConfig* config = new wxConfig(wxT("hugin"));
92  wxConfigBase::Set(config);
93 
94  // need to explicitly initialize locale for C++ library/runtime
95  setlocale(LC_ALL, "");
96  // initialize i18n
97  int localeID = config->Read(wxT("language"), (long)HUGIN_LANGUAGE);
98  m_locale.Init(localeID);
99  // set the name of locale recource to look for
100  m_locale.AddCatalog(wxT("hugin"));
101 
102  return APP::OnInit();
103  };
105  virtual int OnRun()
106  {
107  HuginBase::Panorama pano;
108  wxFileName inputFile(m_input);
109  inputFile.Normalize(wxPATH_NORM_ABSOLUTE | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_SHORTCUT);
110  std::string input(inputFile.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
111  if (!pano.ReadPTOFile(input, hugin_utils::getPathPrefix(input)))
112  {
113  return 1;
114  };
115 
116  HuginQueue::CommandQueue* commands;
117  wxArrayString tempfiles;
118  wxString oldCwd;
119  if (m_runAssistant)
120  {
121  if (m_userAssistant.IsEmpty())
122  {
124  }
125  else
126  {
128  };
129  }
130  else
131  {
132  wxFileName outputPrefix;
133  if (m_prefix.IsEmpty())
134  {
135  outputPrefix = getDefaultOutputName(m_input, pano);
136  outputPrefix.Normalize(wxPATH_NORM_ABSOLUTE | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_SHORTCUT);
137  }
138  else
139  {
140  outputPrefix = m_prefix;
141  outputPrefix.MakeAbsolute();
142  };
143  oldCwd = wxFileName::GetCwd();
144  wxFileName::SetCwd(outputPrefix.GetPath());
145  wxString statusText;
146  wxArrayString outputFiles;
147  if (m_userOutput.IsEmpty())
148  {
149  commands = HuginQueue::GetStitchingCommandQueue(pano, m_utilsBinDir, inputFile.GetFullPath(), outputPrefix.GetName(), statusText, outputFiles, tempfiles, std::cerr);
150  }
151  else
152  {
153  commands = HuginQueue::GetStitchingCommandQueueUserOutput(pano, m_utilsBinDir, inputFile.GetFullPath(), outputPrefix.GetName(), m_userOutput, statusText, outputFiles, tempfiles, std::cerr);
154  };
155  if (!m_dryRun)
156  {
157  std::cout << statusText.mb_str(wxConvLocal) << std::endl;
158  }
159  };
160 
161  if (commands->empty())
162  {
163  std::cout << "ERROR: Queue is empty." << std::endl;
164  return 1;
165  };
166 
167  if (m_threads == -1)
168  {
169  m_threads = wxConfigBase::Get()->Read(wxT("/output/NumberOfThreads"), 0l);
170  };
171 
172  const bool success = HuginQueue::RunCommandsQueue(commands, m_threads, m_dryRun);
173  if (!tempfiles.IsEmpty())
174  {
175  if (m_dryRun)
176  {
177 #ifdef __WXMSW__
178  std::cout << "del ";
179 #else
180  std::cout << "rm ";
181 #endif
182  std::cout << HuginQueue::GetQuotedFilenamesString(tempfiles).mb_str(wxConvLocal) << std::endl;
183  }
184  else
185  {
186  // short waiting time to write all files to disc
187  wxMilliSleep(100);
188  std::cout << _("Removing temporary files") << std::endl;
189  for (size_t i = 0; i < tempfiles.size(); ++i)
190  {
191  wxRemoveFile(tempfiles[i]);
192  };
193  };
194  };
195  // restore current working dir
196  if (!oldCwd.IsEmpty())
197  {
198  wxFileName::SetCwd(oldCwd);
199  }
200  return success ? 0 : 1;
201  };
202 
204  virtual void OnInitCmdLine(wxCmdLineParser &parser)
205  {
206  parser.AddSwitch(wxT("h"), wxT("help"), _("shows this help message"), wxCMD_LINE_OPTION_HELP);
207  parser.AddSwitch(wxT("a"), wxT("assistant"), _("execute assistant"));
208  parser.AddSwitch(wxT("s"), wxT("stitching"), _("execute stitching with given project"));
209  parser.AddOption(wxT("t"), wxT("threads"), _("number of used threads"), wxCMD_LINE_VAL_NUMBER);
210  parser.AddOption(wxT("p"), wxT("prefix"), _("prefix used for stitching"), wxCMD_LINE_VAL_STRING);
211  parser.AddOption(wxT("u"), wxT("user-defined-output"), _("use user defined commands in given file"), wxCMD_LINE_VAL_STRING);
212  parser.AddLongOption(wxT("user-defined-assistant"), _("use user defined assistant commands in given file"), wxCMD_LINE_VAL_STRING);
213  parser.AddSwitch(wxT("d"), wxT("dry-run"), _("only print commands"));
214  parser.AddParam(wxT("input.pto"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY);
215  m_runAssistant = false;
216  m_runStitching = false;
217  m_dryRun = false;
218  m_threads = -1;
219  }
220 
222  virtual bool OnCmdLineParsed(wxCmdLineParser &parser)
223  {
224  // we don't call the parents method of OnCmdLineParse, this will pull in other options we don't want
225  m_runAssistant = parser.Found(wxT("a"));
226  m_runStitching = parser.Found(wxT("s"));
227  m_dryRun = parser.Found(wxT("d"));
228  long threads;
229  if (parser.Found(wxT("t"), &threads))
230  {
231  m_threads = threads;
232  };
233  parser.Found(wxT("p"), &m_prefix);
234  parser.Found(wxT("u"), &m_userOutput);
235  if (!m_userOutput.IsEmpty() && m_runStitching)
236  {
237  wxFileName userOutputFile(m_userOutput);
238  if (!userOutputFile.FileExists())
239  {
240  if (userOutputFile.GetDirCount() == 0)
241  {
242  // file not found, search now in data dir
243  userOutputFile.SetPath(wxString(hugin_utils::GetDataDir().append("output").c_str(), HUGIN_CONV_FILENAME));
244  if (!userOutputFile.FileExists())
245  {
246  const wxString testedFile1 = userOutputFile.GetFullPath();
247  userOutputFile.SetPath(wxString(hugin_utils::GetUserAppDataDir().c_str(), HUGIN_CONV_FILENAME));
248  if (!userOutputFile.FileExists())
249  {
250  std::cerr << "ERROR: File \"" << m_userOutput.mb_str(wxConvLocal) << "\" does not exists." << std::endl
251  << " Also tried files \"" << testedFile1.mb_str(wxConvLocal) << "\" and \"" << userOutputFile.GetFullPath().mb_str(wxConvLocal) << "\", which don't exist." << std::endl;
252  return false;
253  };
254  }
255  m_userOutput = userOutputFile.GetFullPath();
256  }
257  else
258  {
259  std::cerr << "ERROR: File \"" << m_userOutput.mb_str(wxConvLocal) << "\" does not exists." << std::endl;
260  return false;
261  };
262  };
263  }
264  parser.Found(wxT("user-defined-assistant"), &m_userAssistant);
265  if (!m_userAssistant.IsEmpty() && m_runAssistant)
266  {
267  wxFileName userAssistantFile(m_userAssistant);
268  if (!userAssistantFile.FileExists())
269  {
270  if (userAssistantFile.GetDirCount() == 0)
271  {
272  // file not found, search now in data dir
273  userAssistantFile.SetPath(wxString(hugin_utils::GetDataDir().append("assistant").c_str(), HUGIN_CONV_FILENAME));
274  if (!userAssistantFile.FileExists())
275  {
276  const wxString testedFile1 = userAssistantFile.GetFullPath();
277  userAssistantFile.SetPath(wxString(hugin_utils::GetUserAppDataDir().c_str(), HUGIN_CONV_FILENAME));
278  if (!userAssistantFile.FileExists())
279  {
280  std::cerr << "ERROR: File \"" << m_userAssistant.mb_str(wxConvLocal) << "\" does not exists." << std::endl
281  << " Also tried files \"" << testedFile1.mb_str(wxConvLocal) << "\" and \"" << userAssistantFile.GetFullPath().mb_str(wxConvLocal) << "\", which don't exist." << std::endl;
282  return false;
283  };
284  }
285  m_userAssistant = userAssistantFile.GetFullPath();
286  }
287  else
288  {
289  std::cerr << "ERROR: File \"" << m_userAssistant.mb_str(wxConvLocal) << "\" does not exists." << std::endl;
290  return false;
291  };
292  };
293  }
294  m_input = parser.GetParam();
296  {
297  std::cerr << "ERROR: Switch --assistant or --stitching is required." << std::endl;
298  return false;
299  };
301  {
302  std::cerr << "ERROR: Switches --assistant and --stitching are mutually excluse." << std::endl;
303  return false;
304  }
305  return true;
306  };
307 
308 private:
310  bool m_runAssistant;
314  wxString m_userOutput;
316  wxString m_userAssistant;
318  bool m_dryRun;
320  wxString m_input;
322  wxString m_prefix;
324  long m_threads;
326  wxString m_utilsBinDir;
328  wxLocale m_locale;
329 };
330 
331 DECLARE_APP(HuginExecutor)
332 
333 IMPLEMENT_APP_CONSOLE(HuginExecutor)
implementation of huginApp Class
interface of CommandQueue creating for stitching engine
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
long m_threads
number of threads used for assistant or stitching
#define HUGIN_LANGUAGE
virtual bool OnInit()
init translation settings
virtual int OnRun()
the main procedure of Executor app
bool m_dryRun
flag, if commands should only be printed
wxLocale m_locale
locale for internationalisation
basic classes and function for queuing commands in wxWidgets
CommandQueue * GetAssistantCommandQueue(const HuginBase::Panorama &pano, const wxString &ExePath, const wxString &project)
generates the command queue for running the assistant
Model for a panorama.
Definition: Panorama.h:152
#define APP
std::string GetDataDir()
returns the full path to the data directory
Definition: utils.cpp:441
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
virtual bool OnCmdLineParsed(wxCmdLineParser &parser)
processes the command line parameters
bool ReadPTOFile(const std::string &filename, const std::string &prefix="")
read pto file from the given filename into Panorama object it does some checks on the file and issues...
Definition: Panorama.cpp:2023
bool RunCommandsQueue(CommandQueue *queue, size_t threads, bool dryRun)
execute the given, set environment variable OMP_NUM_THREADS to threads (ignored for 0) after running ...
Definition: Executor.cpp:83
wxString GetQuotedFilenamesString(const wxArrayString &files)
return a wxString with all files in files quoted
wxString m_input
input project file
bool m_runStitching
flag, if stitching should started
wxString m_userOutput
input file for userdefined output
bool m_runAssistant
flag, if assistant should started
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
Definition: utils.cpp:497
functions for interaction with the hugin configuration file
wxString m_userAssistant
input file for user defined assistant
CommandQueue * GetAssistantCommandQueueUserDefined(const HuginBase::Panorama &pano, const wxString &ExePath, const wxString &project, const wxString &assistantSetting, wxArrayString &tempFilesDelete, std::ostream &errStream)
generates the command queue for running the assistant
wxString getDefaultOutputName(const wxString projectname, const HuginBase::Panorama &pano, const wxString filenameTemplate)
gets the default output prefix, based on filename and images in project the setting is read from the ...
CommandQueue * GetStitchingCommandQueueUserOutput(const HuginBase::Panorama &pano, const wxString &ExePath, const wxString &project, const wxString &prefix, const wxString &outputSettings, wxString &statusText, wxArrayString &outputFiles, wxArrayString &tempFilesDelete, std::ostream &errStream)
generates the command queue for stitching a pano, the commands are parsed from the given executor out...
wxString m_prefix
stitching prefix
wxString m_utilsBinDir
path to utils
virtual void OnInitCmdLine(wxCmdLineParser &parser)
set the parameters for the command line parser
CommandQueue * GetStitchingCommandQueue(const HuginBase::Panorama &pano, const wxString &ExePath, const wxString &project, const wxString &prefix, wxString &statusText, wxArrayString &outputFiles, wxArrayString &tempFilesDelete, std::ostream &errStream)
generates the command queue for stitching a pano it will also generate the necessary exiftool argfile...
std::vector< NormalCommand * > CommandQueue
Definition: Executor.h:61
create a CommandQueue for running the assistant using CLI tools