1 // -*- c-basic-offset: 4 -*-
2 
3 /** @file PanoOutputDialog.cpp
4  *
5  *	@brief implementation of PanoOutputDialog class
6  *
7  *  @author T. Modes
8  *
9  */
10 
11 /*  This is free software; you can redistribute it and/or
12  *  modify it under the terms of the GNU General Public
13  *  License as published by the Free Software Foundation; either
14  *  version 2 of the License, or (at your option) any later version.
15  *
16  *  This software is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  *  Lesser General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public
22  *  License along with this software. If not, see
23  *  <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "hugin/PanoOutputDialog.h"
28 #include "base_wx/wxPlatform.h"
29 #include "panoinc.h"
30 
31 #include "hugin/huginApp.h"
32 #include "base_wx/platform.h"
33 #include "hugin/config_defaults.h"
34 #include "algorithms/basic/LayerStacks.h"
35 #include "algorithms/basic/CalculateOptimalScale.h"
36 
BEGIN_EVENT_TABLE(PanoOutputDialog,wxDialog)37 BEGIN_EVENT_TABLE(PanoOutputDialog,wxDialog)
38     EVT_BUTTON(wxID_OK, PanoOutputDialog::OnOk)
39     EVT_CHECKBOX(XRCID("output_normal"), PanoOutputDialog::OnOutputChanged)
40     EVT_CHECKBOX(XRCID("output_fused_blended"), PanoOutputDialog::OnOutputChanged)
41     EVT_CHECKBOX(XRCID("output_blended_fused"), PanoOutputDialog::OnOutputChanged)
42     EVT_CHECKBOX(XRCID("output_hdr"), PanoOutputDialog::OnOutputChanged)
43     EVT_CHOICE(XRCID("output_ldr_format"), PanoOutputDialog::OnLDRFormatChanged)
44     EVT_CHOICE(XRCID("output_hdr_format"), PanoOutputDialog::OnHDRFormatChanged)
45     EVT_SPINCTRL(XRCID("output_width"), PanoOutputDialog::OnWidthChanged)
46     EVT_SPINCTRL(XRCID("output_height"), PanoOutputDialog::OnHeightChanged)
47 END_EVENT_TABLE()
48 
49 PanoOutputDialog::PanoOutputDialog(wxWindow *parent, HuginBase::Panorama& pano, GuiLevel guiLevel) : m_pano(pano), m_aspect(0)
50 {
51     // load our children. some children might need special
52     // initialization. this will be done later.
53     wxXmlResource::Get()->LoadDialog(this, parent, wxT("pano_output_dialog"));
54 
55 #ifdef __WXMSW__
56     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
57 #else
58     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
59 #endif
60     SetIcon(myIcon);
61     //set parameters
62     wxConfigBase * cfg = wxConfigBase::Get();
63     //position
64     int x = cfg->Read(wxT("/PanoOutputDialog/positionX"),-1l);
65     int y = cfg->Read(wxT("/PanoOutputDialog/positionY"),-1l);
66     if ( y >= 0 && x >= 0)
67     {
68         this->Move(x, y);
69     }
70     else
71     {
72         this->Move(0, 44);
73     };
74     // get number of stacks and exposure layers
75     m_guiLevel=guiLevel;
76     HuginBase::UIntSet images=getImagesinROI(m_pano, m_pano.getActiveImages());
77     m_stacks=getHDRStacks(m_pano, images, m_pano.getOptions());
78     m_exposureLayers=getExposureLayers(m_pano, images, m_pano.getOptions());
79     // set initial width
80     m_newOpt = m_pano.getOptions();
81     wxConfigBase* config = wxConfigBase::Get();
82     if (m_newOpt.fovCalcSupported(m_newOpt.getProjection()))
83     {
84         // calc optimal size of pano, only of projection is supported
85         // otherwise use current width as start point
86         long opt_width = hugin_utils::roundi(HuginBase::CalculateOptimalScale::calcOptimalScale(m_pano) * m_newOpt.getWidth());
87         double sizeFactor = HUGIN_ASS_PANO_DOWNSIZE_FACTOR;
88         config->Read(wxT("/Assistant/panoDownsizeFactor"), &sizeFactor, HUGIN_ASS_PANO_DOWNSIZE_FACTOR);
89         m_newOpt.setWidth(hugin_utils::floori(sizeFactor*opt_width), true);
90     };
91     m_initalWidth=m_newOpt.getWidth();
92     m_initalROIWidth=m_newOpt.getROI().width();
93     m_aspect=(double)m_newOpt.getROI().height()/m_newOpt.getROI().width();
94     m_edit_width=XRCCTRL(*this, "output_width", wxSpinCtrl);
95     m_edit_height=XRCCTRL(*this, "output_height", wxSpinCtrl);
96     m_edit_width->SetValue(m_newOpt.getROI().width());
97     m_edit_height->SetValue(m_newOpt.getROI().height());
98 
99     //LDR output format, as in preferences set
100     int i = config->Read(wxT("/output/jpeg_quality"),HUGIN_JPEG_QUALITY);
101     XRCCTRL(*this, "output_jpeg_quality", wxSpinCtrl)->SetValue(i);
102     i=config->Read(wxT("/output/tiff_compression"), HUGIN_TIFF_COMPRESSION);
103     XRCCTRL(*this, "output_tiff_compression", wxChoice)->SetSelection(i);
104     i=config->Read(wxT("/output/ldr_format"), HUGIN_LDR_OUTPUT_FORMAT);
105     XRCCTRL(*this, "output_ldr_format", wxChoice)->SetSelection(i);
106     //HDR output format, as in project given
107     if (m_newOpt.outputImageTypeHDR == "exr")
108     {
109         XRCCTRL(*this, "output_hdr_format", wxChoice)->SetSelection(0);
110         XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->SetSelection(2);
111     }
112     else
113     {
114         XRCCTRL(*this, "output_hdr_format", wxChoice)->SetSelection(1);
115         if (m_newOpt.outputImageTypeHDRCompression  == "PACKBITS")
116         {
117             XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->SetSelection(1);
118         }
119         else
120         {
121             if (m_newOpt.outputImageTypeHDRCompression == "LZW")
122             {
123                 XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->SetSelection(2);
124             }
125             else
126             {
127                 if (m_newOpt.outputImageTypeHDRCompression  == "DEFLATE")
128                 {
129                     XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->SetSelection(3);
130                 }
131                 else
132                 {
133                     XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->SetSelection(0);
134                 };
135             };
136         };
137     };
138     EnableOutputOptions();
139     wxCommandEvent dummy;
140     OnOutputChanged(dummy);
141     OnLDRFormatChanged(dummy);
142     OnHDRFormatChanged(dummy);
143 };
144 
~PanoOutputDialog()145 PanoOutputDialog::~PanoOutputDialog()
146 {
147     wxConfigBase * cfg = wxConfigBase::Get();
148     wxPoint ps = this->GetPosition();
149     cfg->Write(wxT("/PanoOutputDialog/positionX"), ps.x);
150     cfg->Write(wxT("/PanoOutputDialog/positionY"), ps.y);
151     cfg->Flush();
152 };
153 
EnableOutputOptions()154 void PanoOutputDialog::EnableOutputOptions()
155 {
156     // check, if hdr images
157     wxFileName file1(wxString(m_pano.getImage(0).getFilename().c_str(), HUGIN_CONV_FILENAME));
158     wxString ext1=file1.GetExt().Lower();
159     if(ext1 == wxT(".hdr") || ext1 == wxT(".exr") || ext1==wxT("hdr") || ext1==wxT("exr"))
160     {
161         XRCCTRL(*this, "output_normal", wxCheckBox)->SetValue(true);
162         XRCCTRL(*this, "output_normal", wxCheckBox)->Enable(true);
163         XRCCTRL(*this, "output_normal_bitmap", wxStaticBitmap)->Enable(true);
164         return;
165     }
166     //hide hdr controls for simple interface
167     if(m_guiLevel==GUI_SIMPLE)
168     {
169         XRCCTRL(*this, "output_hdr", wxCheckBox)->Hide();
170         XRCCTRL(*this, "output_hdr_bitmap", wxStaticBitmap)->Hide();
171         XRCCTRL(*this, "output_hdr_format_label", wxStaticText)->Hide();
172         XRCCTRL(*this, "output_hdr_format", wxChoice)->Hide();
173         XRCCTRL(*this, "output_hdr_compression_label", wxStaticText)->Hide();
174         XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->Hide();
175         Layout();
176         GetSizer()->Fit(this);
177     };
178     //single image or normal panorama, enable only normal output
179     if(m_pano.getNrOfImages()==1 || m_stacks.size() >= 0.7 * m_pano.getNrOfImages())
180     {
181         XRCCTRL(*this, "output_normal", wxCheckBox)->SetValue(true);
182         XRCCTRL(*this, "output_normal", wxCheckBox)->Enable(true);
183         XRCCTRL(*this, "output_normal_bitmap", wxStaticBitmap)->Enable(true);
184         if(m_pano.getNrOfImages()==1 || m_stacks.size()==m_pano.getNrOfImages())
185         {
186             return;
187         };
188     };
189     XRCCTRL(*this, "output_fused_blended", wxCheckBox)->Enable(true);
190     XRCCTRL(*this, "output_fused_blended_bitmap", wxStaticBitmap)->Enable(true);
191     XRCCTRL(*this, "output_blended_fused", wxCheckBox)->Enable(true);
192     XRCCTRL(*this, "output_blended_fused_bitmap", wxStaticBitmap)->Enable(true);
193     if(m_guiLevel!=GUI_SIMPLE)
194     {
195         XRCCTRL(*this, "output_hdr", wxCheckBox)->Enable(true);
196         XRCCTRL(*this, "output_hdr_bitmap", wxStaticBitmap)->Enable(true);
197     };
198     if(m_pano.getNrOfImages() % m_stacks.size() == 0)
199     {
200         XRCCTRL(*this, "output_fused_blended", wxCheckBox)->SetValue(true);
201     }
202     else
203     {
204         if(m_exposureLayers.size()==1)
205         {
206             XRCCTRL(*this, "output_normal", wxCheckBox)->SetValue(true);
207             XRCCTRL(*this, "output_normal", wxCheckBox)->Enable(true);
208             XRCCTRL(*this, "output_normal_bitmap", wxStaticBitmap)->Enable(true);
209         }
210         else
211         {
212             XRCCTRL(*this, "output_blended_fused", wxCheckBox)->SetValue(true);
213         };
214     };
215 };
216 
OnOk(wxCommandEvent & e)217 void PanoOutputDialog::OnOk(wxCommandEvent & e)
218 {
219     bool output_normal=XRCCTRL(*this, "output_normal", wxCheckBox)->GetValue();
220     bool output_fused_blended=XRCCTRL(*this, "output_fused_blended", wxCheckBox)->GetValue();
221     bool output_blended_fused=XRCCTRL(*this, "output_blended_fused", wxCheckBox)->GetValue();
222     bool output_hdr=XRCCTRL(*this, "output_hdr", wxCheckBox)->GetValue();
223     bool keep_intermediate=XRCCTRL(*this, "output_keep_intermediate", wxCheckBox)->GetValue();
224     //normal output
225     m_newOpt.outputLDRBlended=output_normal;
226     m_newOpt.outputLDRLayers=output_normal && keep_intermediate;
227     //fused stacks, then blended
228     m_newOpt.outputLDRExposureBlended=output_fused_blended;
229     m_newOpt.outputLDRExposureRemapped=(output_fused_blended || output_blended_fused) && keep_intermediate;
230     m_newOpt.outputLDRStacks=output_fused_blended && keep_intermediate;
231     // blended exposure layers, then fused
232     m_newOpt.outputLDRExposureLayersFused=output_blended_fused;
233     m_newOpt.outputLDRExposureLayers=output_blended_fused && keep_intermediate;
234     // HDR output
235     m_newOpt.outputHDRBlended=output_hdr;
236     m_newOpt.outputHDRLayers=output_hdr && keep_intermediate;
237     m_newOpt.outputHDRStacks=output_hdr && keep_intermediate;
238     // read compression
239     if(output_normal || output_fused_blended || output_blended_fused)
240     {
241         if(m_newOpt.outputImageType=="jpg")
242         {
243             m_newOpt.quality=XRCCTRL(*this, "output_jpeg_quality", wxSpinCtrl)->GetValue();
244         }
245         else
246         {
247             if(m_newOpt.outputImageType=="tif")
248             {
249                 switch(XRCCTRL(*this, "output_tiff_compression", wxChoice)->GetSelection())
250                 {
251                     case 0:
252                     default:
253                         m_newOpt.outputImageTypeCompression = "NONE";
254                         m_newOpt.tiffCompression = "NONE";
255                         break;
256                     case 1:
257                         m_newOpt.outputImageTypeCompression = "PACKBITS";
258                         m_newOpt.tiffCompression = "PACKBITS";
259                         break;
260                     case 2:
261                         m_newOpt.outputImageTypeCompression = "LZW";
262                         m_newOpt.tiffCompression = "LZW";
263                         break;
264                     case 3:
265                         m_newOpt.outputImageTypeCompression = "DEFLATE";
266                         m_newOpt.tiffCompression = "DEFLATE";
267                         break;
268                 };
269             };
270         };
271     };
272     //HDR compression
273     if(output_hdr)
274     {
275         if(m_newOpt.outputImageTypeHDR=="tif")
276         {
277             switch(XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->GetSelection())
278             {
279                 case 0:
280                 default:
281                     m_newOpt.outputImageTypeHDRCompression = "NONE";
282                     break;
283                 case 1:
284                     m_newOpt.outputImageTypeHDRCompression = "PACKBITS";
285                     break;
286                 case 2:
287                     m_newOpt.outputImageTypeHDRCompression = "LZW";
288                     break;
289                 case 3:
290                     m_newOpt.outputImageTypeHDRCompression = "DEFLATE";
291                     break;
292             };
293         };
294     }
295     // canvas size
296     double scale=m_edit_width->GetValue()/m_initalROIWidth;
297     m_newOpt.setWidth(hugin_utils::roundi(m_initalWidth*scale), true);
298     //some checks to prevent some rounding errors, only for cropped outputs
299     if(m_initalROIWidth < m_initalWidth)
300     {
301         if(m_newOpt.getROI().width()<m_edit_width->GetValue() || m_newOpt.getROI().height()<m_edit_height->GetValue())
302         {
303             m_newOpt.setWidth(m_newOpt.getWidth()+1, true);
304         };
305         vigra::Rect2D roi=m_newOpt.getROI();
306         if(roi.width()>m_edit_width->GetValue() || roi.height()>m_edit_height->GetValue())
307         {
308             roi.setSize(m_edit_width->GetValue(), m_edit_height->GetValue());
309             m_newOpt.setROI(roi);
310         };
311     };
312     //send Ok
313     EndModal(wxID_OK);
314 };
315 
OnOutputChanged(wxCommandEvent & e)316 void PanoOutputDialog::OnOutputChanged(wxCommandEvent & e)
317 {
318     bool output_normal=XRCCTRL(*this, "output_normal", wxCheckBox)->GetValue();
319     bool output_fused_blended=XRCCTRL(*this, "output_fused_blended", wxCheckBox)->GetValue();
320     bool output_blended_fused=XRCCTRL(*this, "output_blended_fused", wxCheckBox)->GetValue();
321     bool output_hdr=XRCCTRL(*this, "output_hdr", wxCheckBox)->GetValue();
322     //enable Ok only if at least one option is enabled
323     XRCCTRL(*this, "wxID_OK", wxButton)->Enable(output_normal || output_fused_blended || output_blended_fused || output_hdr);
324     XRCCTRL(*this, "output_ldr_format_label", wxStaticText)->Enable(output_normal || output_fused_blended || output_blended_fused);
325     XRCCTRL(*this, "output_ldr_format", wxChoice)->Enable(output_normal || output_fused_blended || output_blended_fused);
326     XRCCTRL(*this, "output_ldr_compression_label", wxStaticText)->Enable(output_normal || output_fused_blended || output_blended_fused);
327     XRCCTRL(*this, "output_jpeg_quality", wxSpinCtrl)->Enable(output_normal || output_fused_blended || output_blended_fused);
328     XRCCTRL(*this, "output_tiff_compression", wxChoice)->Enable(output_normal || output_fused_blended || output_blended_fused);
329     XRCCTRL(*this, "output_hdr_format_label", wxStaticText)->Enable(output_hdr);
330     XRCCTRL(*this, "output_hdr_format", wxChoice)->Enable(output_hdr);
331     XRCCTRL(*this, "output_hdr_compression_label", wxStaticText)->Enable(output_hdr);
332     XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->Enable(output_hdr);
333     GetSizer()->Layout();
334 };
335 
OnLDRFormatChanged(wxCommandEvent & e)336 void PanoOutputDialog::OnLDRFormatChanged(wxCommandEvent & e)
337 {
338     int sel = XRCCTRL(*this, "output_ldr_format", wxChoice)->GetSelection();
339     switch (sel)
340     {
341         case 1:
342             m_newOpt.outputImageType ="jpg";
343             XRCCTRL(*this, "output_ldr_compression_label", wxStaticText)->Show();
344             XRCCTRL(*this, "output_ldr_compression_label", wxStaticText)->SetLabel(_("Quality:"));
345             XRCCTRL(*this, "output_jpeg_quality", wxSpinCtrl)->Show();
346             XRCCTRL(*this, "output_tiff_compression", wxChoice)->Hide();
347             break;
348         case 2:
349             m_newOpt.outputImageType ="png";
350             XRCCTRL(*this, "output_ldr_compression_label", wxStaticText)->Hide();
351             XRCCTRL(*this, "output_jpeg_quality", wxSpinCtrl)->Hide();
352             XRCCTRL(*this, "output_tiff_compression", wxChoice)->Hide();
353             break;
354         default:
355         case 0:
356             m_newOpt.outputImageType ="tif";
357             XRCCTRL(*this, "output_ldr_compression_label", wxStaticText)->Show();
358             XRCCTRL(*this, "output_ldr_compression_label", wxStaticText)->SetLabel(_("Compression:"));
359             XRCCTRL(*this, "output_jpeg_quality", wxSpinCtrl)->Hide();
360             XRCCTRL(*this, "output_tiff_compression", wxChoice)->Show();
361             break;
362     };
363     GetSizer()->Layout();
364 };
365 
366 
OnHDRFormatChanged(wxCommandEvent & e)367 void PanoOutputDialog::OnHDRFormatChanged(wxCommandEvent & e)
368 {
369     int sel = XRCCTRL(*this, "output_hdr_format", wxChoice)->GetSelection();
370     switch (sel)
371     {
372         case 1:
373             m_newOpt.outputImageTypeHDR="tif";
374             XRCCTRL(*this, "output_hdr_compression_label", wxStaticText)->Show();
375             XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->Show();
376             break;
377         case 0:
378         default:
379             m_newOpt.outputImageTypeHDR="exr";
380             XRCCTRL(*this, "output_hdr_compression_label", wxStaticText)->Hide();
381             XRCCTRL(*this, "output_hdr_tiff_compression", wxChoice)->Hide();
382             break;
383     };
384     GetSizer()->Layout();
385 };
386 
OnWidthChanged(wxSpinEvent & e)387 void PanoOutputDialog::OnWidthChanged(wxSpinEvent & e)
388 {
389     if(m_aspect>0)
390     {
391         m_edit_height->SetValue(m_edit_width->GetValue()*m_aspect);
392     };
393 };
394 
OnHeightChanged(wxSpinEvent & e)395 void PanoOutputDialog::OnHeightChanged(wxSpinEvent & e)
396 {
397     if(m_aspect>0)
398     {
399         m_edit_width->SetValue(m_edit_height->GetValue()/m_aspect);
400     };
401 };
402