Hugin trunk 0.1
Loading...
Searching...
No Matches
StackerPanel.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
10/* This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This software is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public
21 * License along with this software. If not, see
22 * <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#include "StackerPanel.h"
27#include <wx/stdpaths.h>
28#include <wx/propgrid/advprops.h>
29#include "base_wx/platform.h"
30#include "base_wx/wxPlatform.h"
32#include "base_wx/Executor.h"
33#include <wx/fileconf.h>
34#include <wx/wfstream.h>
35#include <wx/sstream.h>
36#include <wx/filepicker.h>
37#include <wx/dir.h>
38#include "hugin_utils/utils.h"
40#include "base_wx/LensTools.h"
41#include "base_wx/wxutils.h"
43#include "CreateBrightImgDlg.h"
44#include "ToolboxApp.h"
45
47class SelectDirectoryFileDialog :public wxDialog
48{
49public:
52 {
53 wxXmlResource::Get()->LoadDialog(this, parent, "select_dir_dialog");
54 m_dirPicker = XRCCTRL(*this, "select_dir_picker", wxDirPickerCtrl);
55 wxConfigBase* config = wxConfigBase::Get();
56 wxString path = config->Read("/actualPath", "");
57 if (!path.IsEmpty())
58 {
59 m_dirPicker->SetPath(path);
60 }
61 m_recursiveCheck = XRCCTRL(*this, "select_dir_recursive", wxCheckBox);
62 if (config->HasEntry("/ToolboxFrame/Stacker/AddDirRecursive"))
63 {
64 m_recursiveCheck->SetValue(config->ReadBool("/ToolboxFrame/Stacker/AddDirRecursive", false));
65 };
66 m_filenameCtrl = XRCCTRL(*this, "select_dir_filename", wxTextCtrl);
67 if (config->HasEntry("/ToolboxFrame/Stacker/AddDirFilenames"))
68 {
69 m_filenameCtrl->SetValue(config->Read("/ToolboxFrame/Stacker/AddDirFilenames", "*"));
70 };
71 m_filetypeChoice = XRCCTRL(*this, "select_dir_filetype", wxChoice);
73 if (config->HasEntry("/ToolboxFrame/Stacker/AddDirFileType"))
74 {
75 m_filetypeChoice->SetSelection(config->ReadLong("/ToolboxFrame/Stacker/AddDirFileType", 0l));
76 };
78 hugin_utils::RestoreFramePosition(this, "ToolboxFrame/Stacker/AddDirDialog");
79 }
80 // return list which matches the given criterium
82 {
83 return m_filenames;
84 }
85protected:
86 void OnOk(wxCommandEvent& e)
87 {
88 // save positions and settings
89 wxConfigBase* config = wxConfigBase::Get();
90 config->Write("/actualPath", m_dirPicker->GetPath());
91 config->Write("/ToolboxFrame/Stacker/AddDirRecursive", m_recursiveCheck->GetValue());
92 config->Write("/ToolboxFrame/Stacker/AddDirFilenames", m_filenameCtrl->GetValue());
93 config->Write("/ToolboxFrame/Stacker/AddDirFileType", m_filetypeChoice->GetSelection());
94 hugin_utils::StoreFramePosition(this, "ToolboxFrame/Stacker/AddDirDialog");
95 // now try to find all images
96 wxString filename = m_filenameCtrl->GetValue();
97 if (filename.IsEmpty())
98 {
99 filename = "*";
100 };
101 m_filenames.Clear();
103 if (m_recursiveCheck->GetValue())
104 {
106 };
108 for (auto& currExt : ext)
109 {
111 currFilename.Replace("*", filename, true);
112 wxDir::GetAllFiles(m_dirPicker->GetPath(), &m_filenames, currFilename, flags);
113 };
114 hugin_utils::HuginMessageBox(wxString::Format("Found %zu images", m_filenames.size()), _("Hugin_toolbox"), wxOK | wxICON_INFORMATION, this);
115 if (!m_filenames.IsEmpty())
116 {
118 };
119 }
120private:
122 {
124 size_t i = 0;
125 while (i < fileTypes.size())
126 {
127 if (i + 1 >= fileTypes.size())
128 {
129 break;
130 };
131 m_filetypeChoice->AppendString(fileTypes[i]);
132 ++i;
134 ++i;
135 };
136 m_filetypeChoice->SetSelection(0);
137 }
140 wxTextCtrl* m_filenameCtrl;
144};
145
147class StackerDropTarget : public wxFileDropTarget
148{
149public:
150 StackerDropTarget(StackerPanel* parent) : wxFileDropTarget()
151 {
153 }
154
156 {
157 // try to add as images
158 wxArrayString files;
159 for (unsigned int i = 0; i < filenames.GetCount(); i++)
160 {
161 wxFileName file(filenames[i]);
162 if (file.GetExt().CmpNoCase("jpg") == 0 ||
163 file.GetExt().CmpNoCase("jpeg") == 0 ||
164 file.GetExt().CmpNoCase("tif") == 0 ||
165 file.GetExt().CmpNoCase("tiff") == 0 ||
166 file.GetExt().CmpNoCase("png") == 0 ||
167 file.GetExt().CmpNoCase("bmp") == 0 ||
168 file.GetExt().CmpNoCase("gif") == 0 ||
169 file.GetExt().CmpNoCase("pnm") == 0 ||
170 file.GetExt().CmpNoCase("sun") == 0 ||
171 file.GetExt().CmpNoCase("hdr") == 0 ||
172 file.GetExt().CmpNoCase("viff") == 0)
173 {
174 files.push_back(file.GetFullPath());
175 };
176 };
177 // we got some images to add.
178 if (!files.empty())
179 {
180 for (auto& f : files)
181 {
183 };
184 };
185 return true;
186 }
187private:
189};
190
191// destructor, save settings
193{
194 wxConfigBase* config = wxConfigBase::Get();
195 config->Write("/ToolboxFrame/Stacker/Splitter", XRCCTRL(*this, "stacker_splitter", wxSplitterWindow)->GetSashPosition());
196
197 config->Write("/ToolboxFrame/Stacker/Mode", m_modeChoice->GetSelection());
198 config->Write("/ToolboxFrame/Stacker/WinsorTrim", m_winsorTrim->GetValue());
199 config->Write("/ToolboxFrame/Stacker/Sigma", m_sigma->GetValue());
200 config->Write("/ToolboxFrame/Stacker/SigmaIter", m_sigmaMaxIter->GetValue());
201 for (int j = 0; j < m_fileListCtrl->GetColumnCount(); j++)
202 {
203 config->Write(wxString::Format("/ToolboxFrame/Stacker/FileListColumnWidth%d", j), m_fileListCtrl->GetColumnWidth(j));
204 };
205 config->Write("/ToolboxFrame/Stacker/FileListSortColumn", m_sortCol);
206 config->Write("/ToolboxFrame/Stacker/FileListSortAscending", m_sortAscending);
207
208 config->Flush();
210}
211
213{
214 if (!wxPanel::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, "panel"))
215 {
216 return false;
217 }
218 // create preview window
219 m_preview = new PreviewWindow();
220 m_preview->Create(this);
221
223 // load from xrc file and attach unknown controls
224 wxXmlResource::Get()->LoadPanel(this, "stacker_panel");
225 wxXmlResource::Get()->AttachUnknownControl("stacker_preview_window", m_preview, this);
226 // add to sizer
227 wxPanel* mainPanel = XRCCTRL(*this, "stacker_panel", wxPanel);
229 topsizer->Add(mainPanel, wxSizerFlags(1).Expand());
230 // create columns in wxListCtrl
231 m_fileListCtrl = XRCCTRL(*this, "stacker_files", wxListCtrl);
232 m_fileListCtrl->InsertColumn(0, _("Filename"), wxLIST_FORMAT_LEFT, 200);
233 m_fileListCtrl->InsertColumn(1, _("Width"), wxLIST_FORMAT_LEFT, 50);
234 m_fileListCtrl->InsertColumn(2, _("Height"), wxLIST_FORMAT_LEFT, 50);
235 m_fileListCtrl->InsertColumn(3, _("Path"), wxLIST_FORMAT_LEFT, 200);
236 m_fileListCtrl->EnableCheckBoxes(true);
237 m_smallImagePreview = XRCCTRL(*this, "stacker_selected_image", wxStaticBitmap);
239 // store some controls for easier access
240 m_modeChoice = XRCCTRL(*this, "stacker_mode_choice", wxChoice);
241 m_winsorTrim = XRCCTRL(*this, "stacker_winsor_trim_spinctrl", wxSpinCtrlDouble);
242 m_sigma = XRCCTRL(*this, "stacker_sigma_spinctrl", wxSpinCtrlDouble);
243 m_sigmaMaxIter = XRCCTRL(*this, "stacker_sigma_iterations_spinctrl", wxSpinCtrl);
244
246
247 wxConfigBase* config = wxConfigBase::Get();
248 // restore splitter position
249 if (config->HasEntry("/ToolboxFrame/Stacker/Splitter"))
250 {
251 XRCCTRL(*this, "stacker_splitter", wxSplitterWindow)->SetSashPosition(config->ReadLong("/ToolboxFrame/Stacker/Splitter", 300));
252 }
253 m_modeChoice->SetSelection(config->ReadLong("/ToolboxFrame/Stacker/Mode", 0));
254 m_winsorTrim->SetValue(config->ReadDouble("/ToolboxFrame/Stacker/WinsorTrim", 0.2));
255 m_sigma->SetValue(config->ReadDouble("/ToolboxFrame/Stacker/Sigma", 2));
256 m_sigmaMaxIter->SetValue(config->ReadLong("/ToolboxFrame/Stacker/SigmaIter", 5));
257 //get saved width of list ctrl column width
258 for (int j = 0; j < m_fileListCtrl->GetColumnCount(); j++)
259 {
260 // -1 is auto
261 int width = config->Read(wxString::Format("/ToolboxFrame/Stacker/FileListColumnWidth%d", j), -1);
262 if (width != -1)
263 {
264 m_fileListCtrl->SetColumnWidth(j, width);
265 };
266 };
267 m_sortCol = config->Read("/ToolboxFrame/Stacker/FileListSortColumn", -1);
268 m_sortAscending = config->Read("/ToolboxFrame/Stacker/FileListSortAscending", 1) == 1 ? true : false;
269 if (m_sortCol != -1)
270 {
271 m_fileListCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
272 };
273
274 // bind event handler
275 Bind(wxEVT_BUTTON, &StackerPanel::OnAddFiles, this, XRCID("stacker_add_file"));
276 Bind(wxEVT_BUTTON, &StackerPanel::OnAddDirectory, this, XRCID("stacker_add_files_dir"));
277 Bind(wxEVT_BUTTON, &StackerPanel::OnRemoveFile, this, XRCID("stacker_remove_file"));
284 Bind(wxEVT_CHOICE, &StackerPanel::OnModeChanged, this, XRCID("stacker_mode_choice"));
285 Bind(wxEVT_BUTTON, &StackerPanel::OnGeneratePreview, this, XRCID("stacker_preview"));
286 Bind(wxEVT_BUTTON, &StackerPanel::OnGenerateOutput, this, XRCID("stacker_output"));
287 Bind(wxEVT_CHOICE, &StackerPanel::OnZoom, this, XRCID("stacker_choice_zoom"));
288
290 EnableOutputButtons(false);
291 wxCommandEvent e;
292 OnModeChanged(e);
293 return true;
294}
295
296void StackerPanel::AddFile(const wxString& filename)
297{
298 wxFileName fullFilename(filename);
299 // add image dimensions
300 vigra::ImageImportInfo info(fullFilename.GetFullPath().c_str());
301 vigra::Size2D imageSize = info.getCanvasSize();
302 if (imageSize.area() == 0)
303 {
304 imageSize = info.size();
305 };
306 // add to array
307 m_files.push_back(FileInfo(fullFilename.GetFullPath(), fullFilename.GetFullName(), fullFilename.GetPath(), imageSize.width(), imageSize.height()));
308 AddFileInfo(m_files.size() - 1);
310}
311
312void StackerPanel::OnAddFiles(wxCommandEvent& e)
313{
314 wxConfigBase* config = wxConfigBase::Get();
315 wxString path = config->Read("/actualPath", "");
316 wxFileDialog dlg(this, _("Add images"), path, wxEmptyString,
318 dlg.SetDirectory(path);
319
320 // remember the image extension
322 if (config->HasEntry("lastImageType"))
323 {
324 img_ext = config->Read("lastImageType").c_str();
325 }
326 if (img_ext == "all images")
327 dlg.SetFilterIndex(0);
328 else if (img_ext == "jpg")
329 dlg.SetFilterIndex(1);
330 else if (img_ext == "tiff")
331 dlg.SetFilterIndex(2);
332 else if (img_ext == "png")
333 dlg.SetFilterIndex(3);
334 else if (img_ext == "hdr")
335 dlg.SetFilterIndex(4);
336 else if (img_ext == "exr")
337 dlg.SetFilterIndex(5);
338 else if (img_ext == "all files")
339 dlg.SetFilterIndex(6);
340
341 // call the file dialog
342 if (dlg.ShowModal() == wxID_OK)
343 {
344 // get the selections
346 dlg.GetPaths(Pathnames);
347 // save the current path to config
348 config->Write("/actualPath", dlg.GetDirectory());
349 // save the image extension
350 switch (dlg.GetFilterIndex())
351 {
352 case 0: config->Write("lastImageType", "all images"); break;
353 case 1: config->Write("lastImageType", "jpg"); break;
354 case 2: config->Write("lastImageType", "tiff"); break;
355 case 3: config->Write("lastImageType", "png"); break;
356 case 4: config->Write("lastImageType", "hdr"); break;
357 case 5: config->Write("lastImageType", "exr"); break;
358 case 6: config->Write("lastImageType", "all files"); break;
359 };
360 m_fileListCtrl->Freeze();
361 for (auto& f : Pathnames)
362 {
363 AddFile(f);
364 };
365 SortList();
366 m_fileListCtrl->Thaw();
367 }
368}
369
370void StackerPanel::OnAddDirectory(wxCommandEvent& e)
371{
373 if (dlg.ShowModal() == wxID_OK)
374 {
375 const wxArrayString filenames = dlg.GetFilenames();
377 m_fileListCtrl->Freeze();
378 for (auto& f : filenames)
379 {
380 AddFile(f);
381 };
382 SortList();
383 m_fileListCtrl->Thaw();
384 };
385}
386
387void StackerPanel::OnRemoveFile(wxCommandEvent& e)
388{
390 if (m_fileListCtrl->GetSelectedItemCount() >= 1)
391 {
392 for (int i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
393 {
395 {
396 selected.insert(m_fileListCtrl->GetItemData(i));
397 };
398 };
399 };
400 if (!selected.empty())
401 {
402 // remove selected file from internal file list
403 for (auto it = selected.rbegin(); it != selected.rend(); ++it)
404 {
405 m_files.erase(m_files.begin() + (*it));
406 };
407 // now refill list again
408 m_fileListCtrl->DeleteAllItems();
409 FillFileList();
412 }
413 else
414 {
415 wxBell();
416 };
417}
418
420{
421 // ctrl + a, select all files
422 if (e.GetKeyCode() == 1 && e.CmdDown())
423 {
424 // select all
425 for (int i = 0; i < m_fileListCtrl->GetItemCount(); i++)
426 {
428 };
429 };
430 // insert key, add file
431 if ((e.GetKeyCode() == WXK_INSERT || e.GetKeyCode() == WXK_NUMPAD_INSERT) && !e.HasAnyModifiers())
432 {
433 wxCommandEvent e(wxEVT_BUTTON, XRCID("stacker_add_file"));
434 this->GetEventHandler()->AddPendingEvent(e);
435 };
436 // delete key, delete selected file
437 if ((e.GetKeyCode() == WXK_DELETE || e.GetKeyCode() == WXK_NUMPAD_DELETE) && !e.HasAnyModifiers())
438 {
439 if (m_fileListCtrl->GetSelectedItemCount() > 0)
440 {
441 wxCommandEvent e(wxEVT_BUTTON, XRCID("stacker_remove_file"));
442 this->GetEventHandler()->AddPendingEvent(e);
443 }
444 else
445 {
446 wxBell();
447 };
448 };
449 e.Skip();
450}
451
453{
454 // enable/disable button according to selected files
456 // display preview
457 if (m_fileListCtrl->GetSelectedItemCount() == 1)
458 {
459 const long listIndex = m_fileListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
460 if (listIndex >= 0 && listIndex < m_files.size())
461 {
462 const long index = static_cast<long>(m_fileListCtrl->GetItemData(listIndex));
463 m_selectedImage = std::string(m_files[index].fullFilename.mb_str(HUGIN_CONV_FILENAME));
465 if (cacheEntry.get())
466 {
467 // image is already in cache, display it directly
469 wxGetApp().GetToolboxFrame()->HasMonitorProfile(), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
470 m_imgRequest = ImageCache::RequestPtr();
471 m_selectedImage = std::string();
472 }
473 else
474 {
475 // load the image in the background.
477 m_imgRequest->ready.push_back(
478 std::bind(&StackerPanel::OnImageLoaded, this, std::placeholders::_1, std::placeholders::_2)
479 );
480 }
481 }
482 }
483 else
484 {
485 m_selectedImage = std::string();
486 }
487}
488
490{
491 // check we are still displaying this image
492 if (m_selectedImage == filename)
493 {
495 wxGetApp().GetToolboxFrame()->HasMonitorProfile(), wxGetApp().GetToolboxFrame()->GetMonitorProfile());
496 }
497}
498
500{
501 const long index = m_fileListCtrl->GetItemData(e.GetItem());
502 m_files[index].isChecked = m_fileListCtrl->IsItemChecked(e.GetItem());
504}
505
507{
508 const int newCol = e.GetColumn();
509 if (m_sortCol == newCol)
510 {
512 }
513 else
514 {
516 m_sortAscending = true;
517 };
518 m_fileListCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
519 SortList();
520 Refresh();
521}
522
523void StackerPanel::OnModeChanged(wxCommandEvent& e)
524{
525 const int mode = m_modeChoice->GetSelection();
526 // hide controls which are not necessary for current mode
527 XRCCTRL(*this, "stacker_winsor_trim_label", wxStaticText)->Show(mode == 2);
528 m_winsorTrim->Show(mode == 2);
529 XRCCTRL(*this, "stacker_sigma_label", wxStaticText)->Show(mode == 3);
530 m_sigma->Show(mode == 3);
531 XRCCTRL(*this, "stacker_sigma_iterations_label", wxStaticText)->Show(mode == 3);
532 m_sigmaMaxIter->Show(mode == 3);
533 m_modeChoice->GetParent()->Layout();
534}
535
536void StackerPanel::OnGeneratePreview(wxCommandEvent& e)
537{
538 // create temp file name, set extension to tif
539 m_outputFilenames.resize(2);
540 wxFileName tempfile(wxFileName::CreateTempFileName(HuginQueue::GetConfigTempDir(wxConfig::Get()) + "he"));
541 m_outputFilenames[1] = tempfile.GetFullPath();
542 tempfile.SetExt("tif");
543 m_outputFilenames[0] = tempfile.GetFullPath();
544 m_cleanupOutput = true;
545 // get command line and execute
547}
548
561
563{
565 if (!cmd.IsEmpty())
566 {
567 EnableOutputButtons(false);
571 queue->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath, "hugin_stacker"), cmd, _("Stacking images") + " (" + cmd + ")"));
572 // get first image
573 long index = -1;
574 for (long i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
575 {
576 if (m_fileListCtrl->IsItemChecked(i))
577 {
578 index = m_fileListCtrl->GetItemData(i);
579 break;
580 };
581 };
582 wxString exiftoolArgs(" -overwrite_original -tagsfromfile " + HuginQueue::wxEscapeFilename(m_files[index].fullFilename));
583 exiftoolArgs.Append(" -all:all --thumbnail --thumbnailimage --xposition --yposition --imagefullwidth --imagefullheight ");
585 queue->push_back(new HuginQueue::OptionalCommand(HuginQueue::GetExternalProgram(wxConfig::Get(), exePath, "exiftool"), exiftoolArgs, _("Updating EXIF")));
586 m_logWindow->ExecQueue(queue);
587 };
588}
589
590void StackerPanel::OnGenerateOutput(wxCommandEvent& e)
591{
592 if (m_files.empty())
593 {
594 wxBell();
595 return;
596 };
597 wxConfigBase* config = wxConfigBase::Get();
598 wxString path = config->Read("/actualPath", "");
600 dlg.SetDirectory(path);
601
602 // remember the image extension
604 if (config->HasEntry("lastImageType"))
605 {
606 img_ext = config->Read("lastImageType").c_str();
607 }
608 if (img_ext == "jpg")
609 {
610 dlg.SetFilterIndex(0);
611 }
612 else
613 {
614 if (img_ext == "tiff")
615 {
616 dlg.SetFilterIndex(1);
617 }
618 else
619 {
620 if (img_ext == "png")
621 {
622 dlg.SetFilterIndex(2);
623 };
624 };
625 };
626 wxFileName outputfilename(m_files[0].fullFilename);
627 outputfilename.SetName(outputfilename.GetName() + "_stacked");
628 dlg.SetFilename(outputfilename.GetFullPath());
629 // call the file dialog
630 if (dlg.ShowModal() == wxID_OK)
631 {
632 m_outputFilenames.resize(1);
633 m_outputFilenames[0] = dlg.GetPath();
634 // save the current path to config
635 config->Write("/actualPath", dlg.GetDirectory());
636 // save the image extension
637 switch (dlg.GetFilterIndex())
638 {
639 case 0:
640 config->Write("lastImageType", "jpg");
641 break;
642 case 1:
643 config->Write("lastImageType", "tiff");
644 break;
645 case 2:
646 config->Write("lastImageType", "png");
647 break;
648 };
649 m_cleanupOutput = false;
651 };
652}
653
654void StackerPanel::OnZoom(wxCommandEvent& e)
655{
656 double factor;
657 switch (e.GetSelection())
658 {
659 case 0:
660 factor = 1;
661 break;
662 case 1:
663 // fit to window
664 factor = 0;
665 break;
666 case 2:
667 factor = 2;
668 break;
669 case 3:
670 factor = 1.5;
671 break;
672 case 4:
673 factor = 0.75;
674 break;
675 case 5:
676 factor = 0.5;
677 break;
678 case 6:
679 factor = 0.25;
680 break;
681 default:
682 DEBUG_ERROR("unknown scale factor");
683 factor = 1;
684 }
685 m_preview->setScale(factor);
686}
687
688void StackerPanel::OnProcessFinished(wxCommandEvent& e)
689{
691 if (output.FileExists() && output.GetSize()>0)
692 {
693 m_preview->setImage(output.GetFullPath());
694 };
696 if (m_cleanupOutput && output.FileExists())
697 {
698 // cleanup up preview files
699 for (const auto& f : m_outputFilenames)
700 {
701 wxRemoveFile(f);
702 };
703 };
705}
706
708{
710 switch (XRCCTRL(*this, "stacker_mode_choice", wxChoice)->GetSelection())
711 {
712 case 0:
713 // mean or average
714 commandline.Append(" --mode=mean ");
715 break;
716 case 1:
717 // Median
718 commandline.Append(" --mode=median ");
719 break;
720 case 2:
721 // Winsor trimmed mean
722 commandline.Append(" --mode=winsor ");
723 commandline.Append("--winsor-trim=" + wxString::FromCDouble(m_winsorTrim->GetValue()) + " ");
724 break;
725 case 3:
726 // Sigma clipped mean
727 commandline.Append(" --mode=sigma ");
728 commandline.Append("--max-sigma=" + wxString::FromCDouble(m_sigma->GetValue()) + wxString::Format(" --max-iterations=%d ", m_sigmaMaxIter->GetValue()));
729 break;
730 case 4:
731 //Minimum
732 commandline.Append(" --mode=minimum ");
733 break;
734 case 5:
735 //Maximum
736 commandline.Append(" --mode=maximum ");
737 break;
738 }
739 return commandline;
740}
741
743{
745 // add options from control
746 commandline.Append(" ");
748 // now build image list
750 for (int i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
751 {
752 if (m_fileListCtrl->IsItemChecked(i))
753 {
754 selectedFiles.push_back(m_fileListCtrl->GetItemData(i));
755 };
756 };
757 if (selectedFiles.IsEmpty())
758 {
759 hugin_utils::HuginMessageBox(_("Please activate at least one file."), _("Hugin_toolbox"), wxOK | wxOK_DEFAULT | wxICON_WARNING, this);
760 return wxEmptyString;
761 }
762 if (selectedFiles.size() > 5)
763 {
764 // for more than 5 files use response file
765 // first create a temp file
766 wxString tempFilename = wxFileName::CreateTempFileName(HuginQueue::GetConfigTempDir(wxConfig::Get()) + "hsfl");
768 textfile.Open();
769 if (textfile.IsOpened())
770 {
771 m_tempFiles.push_back(tempFilename);
772 // write filenames to response file
773 for (int i = 0; i < selectedFiles.size(); ++i)
774 {
775 textfile.AddLine(m_files[selectedFiles[i]].fullFilename);
776 };
777 // write file and do some checking for erros
779 {
780 textfile.Close();
781 // add response file to command line
782 commandline.Append(" @ ");
784 return commandline;
785 }
786 else
787 {
788 textfile.Close();
789 hugin_utils::HuginMessageBox(wxString::Format(_("Could not write to temporary file (%s)."), tempFilename), _("Hugin_toolbox"), wxOK | wxOK_DEFAULT | wxICON_WARNING, this);
790 return wxEmptyString;
791
792 };
793 }
794 else
795 {
796 hugin_utils::HuginMessageBox(wxString::Format(_("Could not write to temporary file (%s)."), tempFilename), _("Hugin_toolbox"), wxOK | wxOK_DEFAULT | wxICON_WARNING, this);
797 return wxEmptyString;
798 };
799 }
800 else
801 {
802 // use filename direct on command line, if there are only up to 5 files
803 for (int i = 0; i < selectedFiles.size(); ++i)
804 {
805 commandline.Append(" ");
807 }
808 return commandline;
809 };
810}
811
813{
814 // enable/disable button according to selected files
815 XRCCTRL(*this, "stacker_remove_file", wxButton)->Enable(m_fileListCtrl->GetSelectedItemCount() >= 1);
816}
817
819{
820 // count checked items
821 long count = 0;
822 for (int i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
823 {
824 if (m_fileListCtrl->IsItemChecked(i))
825 {
826 ++count;
827 };
828 };
829 return count;
830}
831
833{
834 XRCCTRL(*this, "stacker_preview", wxButton)->Enable(enable);
835 XRCCTRL(*this, "stacker_output", wxButton)->Enable(enable);
836}
837
839{
840 for (const auto& f : m_tempFiles)
841 {
842 wxRemoveFile(f);
843 };
844 m_tempFiles.clear();
845}
846
848{
849 m_fileListCtrl->Freeze();
850 for (long i = 0; i < m_files.size();++i)
851 {
852 AddFileInfo(i);
853 };
854 SortList();
855 m_fileListCtrl->Thaw();
856}
857
859{
860 const long index = m_fileListCtrl->InsertItem(m_fileListCtrl->GetItemCount(), m_files[fileIndex].name);
861 // store index as client data for sorting
862 m_fileListCtrl->SetItemData(index, fileIndex);
863 // add image dimensions
864 m_fileListCtrl->SetItem(index, 1, wxString::Format("%zu", m_files[fileIndex].width));
865 m_fileListCtrl->SetItem(index, 2, wxString::Format("%zu", m_files[fileIndex].height));
866 m_fileListCtrl->SetItem(index, 3, m_files[fileIndex].path);
867 // set checkbox
868 m_fileListCtrl->CheckItem(index, m_files[fileIndex].isChecked);
869}
870
871#define SORTASCENDING(functionName, var) \
872int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
873{\
874 StackerPanel::FileInfoVector* data = (StackerPanel::FileInfoVector*)(sortData);\
875 if (data->at(item1).var > data->at(item2).var)\
876 return 1;\
877 if (data->at(item1).var < data->at(item2).var)\
878 return -1;\
879 return 0;\
880}
881
882#define SORTDESCENDING(functionName, var) \
883int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
884{\
885 StackerPanel::FileInfoVector* data = (StackerPanel::FileInfoVector*)(sortData); \
886 if (data->at(item1).var < data->at(item2).var)\
887 return 1; \
888 if (data->at(item1).var > data->at(item2).var)\
889 return -1; \
890 return 0; \
891}
892
901
902#undef SORTASCENDING
903#undef SORTDESCENDING
904
906{
907 if (m_sortCol > -1)
908 {
909 switch (m_sortCol)
910 {
911 case 0: // filename
912 if (m_sortAscending)
913 {
915 }
916 else
917 {
919 };
920 break;
921 case 1: // image width
922 if (m_sortAscending)
923 {
925 }
926 else
927 {
929 };
930 break;
931 case 2: // image height
932 if (m_sortAscending)
933 {
935 }
936 else
937 {
939 };
940 break;
941 case 3: // path
942 if (m_sortAscending)
943 {
945 }
946 else
947 {
949 };
950 break;
951 };
952 };
953}
954
955IMPLEMENT_DYNAMIC_CLASS(StackerPanel, wxPanel)
Definition of dialog class to create brighter/darker versions of the image.
basic classes and function for queuing commands in wxWidgets
some helper classes for graphes
#define SORTDESCENDING(functionName, var)
#define SORTASCENDING(functionName, var)
declaration of panel for stacker GUI
EntryPtr getSmallImageIfAvailable(const std::string &filename)
Get a small image if already loaded.
static ImageCache & getInstance()
get the global ImageCache object
RequestPtr requestAsyncSmallImage(const std::string &filename)
Request a small image be loaded.
std::shared_ptr< Entry > EntryPtr
a shared pointer to the entry
Definition ImageCache.h:112
normal command for queue, processing is stopped if an error occurred in program
Definition Executor.h:38
optional command for queue, processing of queue is always continued, also if an error occurred
Definition Executor.h:54
int ExecQueue(HuginQueue::CommandQueue *queue)
void AddString(const wxString &s)
display the string in the panel
int ExecWithRedirect(wxString command)
void ClearOutput()
clear the output
preview window
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
create the control
void setImage(const wxString &filename)
set the current image and mask list, this loads also the image from cache
void setScale(double factor)
set the scaling factor f.
dialog for selection of directory and file name/type
wxArrayString GetFilenames()
wxDirPickerCtrl * m_dirPicker
SelectDirectoryFileDialog(wxWindow *parent)
Constructor, read from xrc ressource; restore last uses settings, size and position.
void OnOk(wxCommandEvent &e)
wxArrayString m_filetypeExtensions
file drag and drop handler method
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
StackerPanel * m_stackerPanel
StackerDropTarget(StackerPanel *parent)
panel for stacker GUI
void OnRemoveFile(wxCommandEvent &e)
void SortList()
sort filename list
std::string m_selectedImage
PreviewWindow * m_preview
long GetCheckedItemCount() const
return the number of check images
void OnZoom(wxCommandEvent &e)
void CleanUpTempFiles()
delete all temporary files, to be called mainly at end
void OnAddDirectory(wxCommandEvent &e)
wxSpinCtrlDouble * m_winsorTrim
void OnFileColumnHeaderClick(wxListEvent &e)
void OnProcessFinished(wxCommandEvent &e)
call at the end of the enfuse command, to load result back and enable buttons again
void OnFileCheckStateChanged(wxListEvent &e)
void ExecuteStackerExiftool()
build the command line and execute enfuse and exiftool afterwards
wxListCtrl * m_fileListCtrl
wxSpinCtrl * m_sigmaMaxIter
HuginBase::ImageCache::RequestPtr m_imgRequest
void EnableOutputButtons(bool enable)
enable/disable output buttons
void OnFileListChar(wxKeyEvent &e)
bool Create(wxWindow *parent, MyExecPanel *logPanel)
creates the control and populates all controls with their settings
void AddFileInfo(const long fileIndex)
void OnImageLoaded(HuginBase::ImageCache::EntryPtr entry, std::string filename)
called when is image is fully loaded to display image in wxStaticBitmap
wxChoice * m_modeChoice
FileInfoVector m_files
wxStaticBitmap * m_smallImagePreview
void OnModeChanged(wxCommandEvent &e)
void FillFileList()
fill the list from internal file list
void AddFile(const wxString &filename)
adds the given file to the list
wxArrayString m_outputFilenames
void EnableFileButtons()
enable/disable the file(s) remove and create buttons depending on selection of wxListCtrl
MyExecPanel * m_logWindow
void ExecuteStacker()
build the command line and execute enfuse command
void OnGenerateOutput(wxCommandEvent &e)
wxString GetStackerOptions()
build string with all stacker options from values in wxPropertyGrid this are the mainly the fusion op...
void OnGeneratePreview(wxCommandEvent &e)
~StackerPanel()
destructor, save state and settings
wxArrayString m_tempFiles
void OnAddFiles(wxCommandEvent &e)
event handler
wxString GetStackerCommandLine()
get the full commandline for enfuse without program, but with files and output options,...
void OnFileSelectionChanged(wxCommandEvent &e)
wxSpinCtrlDouble * m_sigma
static uint16_t flags
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
#define DEBUG_ERROR(msg)
Definition utils.h:76
std::set< unsigned int > UIntSet
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition Executor.h:79
wxString GetExternalProgram(wxConfigBase *config, const wxString &bindir, const wxString &name)
return path and name of external program, which can be overwritten by the user
Definition Executor.cpp:148
std::vector< NormalCommand * > CommandQueue
Definition Executor.h:61
wxString GetInternalProgram(const wxString &bindir, const wxString &name)
return path and name of external program, which comes bundled with Hugin
Definition Executor.cpp:129
const wxString GetConfigTempDir(const wxConfigBase *config)
return the temp dir from the preferences, ensure that it ends with path separator
Definition Executor.cpp:302
str wxQuoteFilename(const str &arg)
Quote a filename, so that it is surrounded by "".
Definition wxPlatform.h:82
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:106
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:67
wxString GetFileDialogImageFilters()
return filter for image files, needed by file open dialog it contains all image format vigra can read...
Definition platform.cpp:70
wxString GetMainImageFilters()
return a filter for the main image files (JPG/TIFF/PNG) only
Definition platform.cpp:81
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
void GeneratePreviewSelectedFile(wxStaticBitmap *control, ImageCache::EntryPtr cacheEntry, const bool hasMonitorProfile, const cmsHPROFILE &monitorProfile)
load given image from image cache and display in wxStaticBitmap control
platform/compiler specific stuff.