diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 0d98affef..9b3a03bc4 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ + #include "dcrop.h" #include "curves.h" #include "mytime.h" diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 94093d2f4..5601a7c0f 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -32,7 +32,7 @@ #include "options.h" #include "procparamchangers.h" #include "thumbnail.h" -#include "md5helper.h" +//#include "md5helper.h" namespace { @@ -308,10 +308,42 @@ void CacheManager::deleteFiles (const Glib::ustring& fname, const std::string& m error |= g_remove (getCacheFileName ("mip", fname, ".mip", md5).c_str ()); } +} - if (error != 0 && options.rtSettings.verbose) { - std::cerr << "Failed to delete all files for cache entry '" << fname << "': " << g_strerror (errno) << std::endl; +std::string CacheManager::getMD5 (const Glib::ustring& fname) +{ + +#ifdef WIN32 + + std::unique_ptr wfname(reinterpret_cast(g_utf8_to_utf16 (fname.c_str (), -1, NULL, NULL, NULL)), g_free); + + WIN32_FILE_ATTRIBUTE_DATA fileAttr; + if (GetFileAttributesExW(wfname.get(), GetFileExInfoStandard, &fileAttr)) { + // We use name, size and creation time to identify a file. + const auto identifier = Glib::ustring::compose("%1-%2-%3-%4", fileAttr.nFileSizeLow, fileAttr.ftCreationTime.dwHighDateTime, fileAttr.ftCreationTime.dwLowDateTime, fname); + return Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_MD5, identifier); } + +#else + + const auto file = Gio::File::create_for_path(fname); + if (file) { + + try + { + const auto info = file->query_info("standard::*"); + if (info) { + // We only use name and size to identify a file. + const auto identifier = Glib::ustring::compose("%1%2", fname, info->get_size()); + return Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_MD5, identifier); + } + + } catch(Gio::Error&) {} + } + +#endif + + return {}; } Glib::ustring CacheManager::getCacheFileName (const Glib::ustring& subDir, diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h index ac40be64b..5ee1ff63d 100644 --- a/rtgui/cachemanager.h +++ b/rtgui/cachemanager.h @@ -61,6 +61,7 @@ public: void clearProfiles () const; void clearmip () const; void clearFromCache (const Glib::ustring& fname, bool purge) const; + static std::string getMD5 (const Glib::ustring& fname); Glib::ustring getCacheFileName (const Glib::ustring& subDir, const Glib::ustring& fname, diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index e9975196f..648004aee 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -684,7 +684,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iops->attach_next_to (*sendtogimp, Gtk::POS_LEFT, 1, 1); } - if (!gimpPlugin) { + if (!gimpPlugin && !simpleEditor) { iops->attach_next_to (*queueimg, Gtk::POS_LEFT, 1, 1); } @@ -1589,7 +1589,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) return true; case GDK_KEY_b: - if (!simpleEditor) { + if (!gimpPlugin && !simpleEditor) { queueImgPressed(); } diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index c026b63a8..d3fc71d62 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -600,13 +600,18 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry) { MYWRITERLOCK(l, entryRW); - std::vector::iterator i = fd.begin(); - - while (i != fd.end() && *entry < * ((FileBrowserEntry*)*i)) { - ++i; - } - - fd.insert (i, entry); + fd.insert( + std::lower_bound( + fd.begin(), + fd.end(), + (ThumbBrowserEntryBase*)entry, + [](ThumbBrowserEntryBase* a, ThumbBrowserEntryBase* b) + { + return *b < *a; + } + ), + (ThumbBrowserEntryBase*)entry + ); initEntry (entry); } diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 0d10ba125..fba3f432a 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1792,38 +1792,36 @@ void FileCatalog::on_dir_changed (const Glib::RefPtr& file, const Gli void FileCatalog::checkAndAddFile (Glib::RefPtr file) { - if (!file) { - return; - } - if (!file->query_exists()) { + if (!file) { return; } try { - auto info = file->query_info (); + const auto info = file->query_info("standard::*"); - if (!info || info->get_file_type () == Gio::FILE_TYPE_DIRECTORY) { + if (!info || info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) { return; } - if (!options.fbShowHidden && info->is_hidden ()) { + if (!options.fbShowHidden && info->is_hidden()) { return; } Glib::ustring ext; - const auto lastdot = info->get_name ().find_last_of ('.'); + const auto lastdot = info->get_name().find_last_of('.'); + if (lastdot != Glib::ustring::npos) { - ext = info->get_name ().substr (lastdot + 1); + ext = info->get_name().substr(lastdot + 1); } - if (!options.is_extention_enabled (ext)) { + if (!options.is_extention_enabled(ext)) { return; } - previewLoader->add (selectedDirectoryId, file->get_parse_name (), this); + previewLoader->add(selectedDirectoryId, file->get_parse_name(), this); previewsToLoad++; } catch(Gio::Error&) {} diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 316beb791..7d0f9013b 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -157,6 +157,8 @@ FilePanel::~FilePanel () if (inspectorPanel) { delete inspectorPanel; } + + delete tpc; } void FilePanel::on_realize () diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 4d9dd3c5c..989ff2758 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -849,13 +849,15 @@ bool MyExpander::get_expanded() return expBox ? expBox->get_visible() : false; } -void MyExpander::add (Gtk::Container& widget) +void MyExpander::add (Gtk::Container& widget, bool setChild) { - child = &widget; + if(setChild) { + child = &widget; + } expBox = Gtk::manage (new ExpanderBox (child)); - expBox->add (*child); + expBox->add (widget); pack_start(*expBox, Gtk::PACK_SHRINK, 0); - child->show(); + widget.show(); expBox->hideBox(); } @@ -889,11 +891,6 @@ bool MyExpander::on_toggle(GdkEventButton* event) return false; } -Gtk::Container* MyExpander::getChild() -{ - return child; -} - // used to connect a function to the enabled_toggled signal MyExpander::type_signal_enabled_toggled MyExpander::signal_enabled_toggled() { diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 085027577..7a71fc399 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -265,9 +265,6 @@ public: return headerWidget ? headerWidget : label; } - /// Get the widget shown/hidden by the expander - Gtk::Container* getChild(); - /// Set the collapsed/expanded state of the expander void set_expanded( bool expanded ); @@ -276,7 +273,7 @@ public: /// Add a Gtk::Container for the content of the expander /// Warning: do not manually Show/Hide the widget, because this parameter is handled by the click on the Expander's title - void add (Gtk::Container& widget); + void add (Gtk::Container& widget, bool setChild = true); void updateVScrollbars(bool hide); }; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index e80b2028a..1bb1c23a3 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -199,7 +199,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch Gtk::HBox *riHBox = Gtk::manage ( new Gtk::HBox()); Gtk::Label* outputIntentLbl = Gtk::manage (new Gtk::Label(M("TP_ICM_PROFILEINTENT")+":")); riHBox->pack_start (*outputIntentLbl, Gtk::PACK_SHRINK); - ointent = Gtk::manage (new PopUpButton ()); + ointent.reset (new PopUpButton ()); ointent->addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); ointent->addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); ointent->addEntry("intent-saturation.png", M("PREFERENCES_INTENT_SATURATION")); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 0e7deefa9..35017bed4 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -83,7 +83,7 @@ private: MyComboBoxText* onames; sigc::connection onamesconn; - PopUpButton* ointent; + std::unique_ptr ointent; sigc::connection ointentconn; Gtk::RadioButton* iunchanged; MyFileChooserButton* ipDialog; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index ca9953f2a..c305cf7da 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -2436,18 +2436,8 @@ void Preferences::switchFontTo (const Glib::ustring &newFontFamily, const int ne void Preferences::workflowUpdate () { - if (moptions.tabbedUI != options.tabbedUI) { - parent->MoveFileBrowserToMain(); - parent->CloseOpenEditors(); - parent->SetMainCurrent(); - - if (moptions.tabbedUI) { - parent->epanel->hide(); - parent->set_title_decorated (""); - } else { - parent->epanel->show_all(); - parent->set_title_decorated (parent->epanel->getFileName()); - } + if(moptions.tabbedUI != options.tabbedUI) { + parent->setEditorMode(moptions.tabbedUI); } if (moptions.hideTPVScrollbar != options.hideTPVScrollbar) { diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 6f05f3f72..75f099488 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -194,7 +194,7 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL") - expsettings = new MyExpander (false, M ("TP_RETINEX_SETTINGS")); + expsettings = Gtk::manage(new MyExpander(false, M ("TP_RETINEX_SETTINGS"))); setExpandAlignProperties (expsettings, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); expsettings->signal_button_release_event().connect_notify ( sigc::bind ( sigc::mem_fun (this, &Retinex::foldAllButMe), expsettings) ); @@ -474,7 +474,7 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL") //-------------------------- - expsettings->add (*settingsGrid); + expsettings->add (*settingsGrid, false); expsettings->setLevel (2); pack_start (*expsettings); diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index e40d95f15..5edfb3b25 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -165,7 +165,6 @@ RTWindow::RTWindow () mainNB->set_scrollable (true); mainNB->signal_switch_page().connect_notify( sigc::mem_fun(*this, &RTWindow::on_mainNB_switch_page) ); - // Editor panel fpanel = new FilePanel () ; fpanel->setParent (this); @@ -203,29 +202,10 @@ RTWindow::RTWindow () mainNB->append_page (*bpanel, *lbq); - // Editor panel, single-tab mode only - epanel = Gtk::manage ( new EditorPanel (fpanel) ); - epanel->setParent (this); - - // decorate tab - Gtk::Grid* editorLabelGrid = Gtk::manage (new Gtk::Grid ()); - setExpandAlignProperties(editorLabelGrid, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - Gtk::Label* el = Gtk::manage (new Gtk::Label( Glib::ustring(" ") + M("MAIN_FRAME_EDITOR") )); - - if (options.mainNBVertical) { - el->set_angle (90); - editorLabelGrid->attach_next_to(*Gtk::manage (new RTImage ("rt-logo-small.png")), Gtk::POS_TOP, 1, 1); - editorLabelGrid->attach_next_to(*el, Gtk::POS_TOP, 1, 1); - } else { - editorLabelGrid->attach_next_to(*Gtk::manage (new RTImage ("rt-logo-small.png")), Gtk::POS_RIGHT, 1, 1); - editorLabelGrid->attach_next_to(*el, Gtk::POS_RIGHT, 1, 1); + if(isSingleTabMode()) { + createSetmEditor(); } - editorLabelGrid->set_tooltip_markup (M("MAIN_FRAME_EDITOR_TOOLTIP")); - editorLabelGrid->show_all (); - epanel->tbTopPanel_1_visible(true); //show the toggle Top Panel button - mainNB->append_page (*epanel, *editorLabelGrid); - mainNB->set_current_page (mainNB->page_num (*fpanel)); //Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ()); @@ -291,10 +271,6 @@ RTWindow::RTWindow () } } } - - if (!isSingleTabMode() && !simpleEditor) { - epanel->hide(); - } } RTWindow::~RTWindow() @@ -778,7 +754,9 @@ void RTWindow::MoveFileBrowserToEditor() void RTWindow::updateProfiles(const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC) { - epanel->updateProfiles(printerProfile, printerIntent, printerBPC); + if(epanel) { + epanel->updateProfiles(printerProfile, printerIntent, printerBPC); + } for(auto panel : epanels) { panel.second->updateProfiles(printerProfile, printerIntent, printerBPC); @@ -788,7 +766,9 @@ void RTWindow::updateProfiles(const Glib::ustring &printerProfile, rtengine::Ren void RTWindow::updateTPVScrollbar (bool hide) { fpanel->updateTPVScrollbar (hide); - epanel->updateTPVScrollbar (hide); + if(epanel) { + epanel->updateTPVScrollbar (hide); + } for(auto panel : epanels) { panel.second->updateTPVScrollbar (hide); @@ -798,7 +778,9 @@ void RTWindow::updateTPVScrollbar (bool hide) void RTWindow::updateTabsUsesIcons (bool useIcons) { fpanel->updateTabsUsesIcons (useIcons); - epanel->updateTabsUsesIcons (useIcons); + if(epanel) { + epanel->updateTabsUsesIcons (useIcons); + } for(auto panel : epanels) { panel.second->updateTabsUsesIcons (useIcons); @@ -817,8 +799,9 @@ void RTWindow::updateFBToolBarVisibility (bool showFilmStripToolBar) void RTWindow::updateHistogramPosition (int oldPosition, int newPosition) { - epanel->updateHistogramPosition (oldPosition, newPosition); - + if(epanel) { + epanel->updateHistogramPosition (oldPosition, newPosition); + } for(auto panel : epanels) { panel.second->updateHistogramPosition (oldPosition, newPosition); } @@ -862,3 +845,47 @@ bool RTWindow::isEditorPanel(guint pageNum) { return isEditorPanel(mainNB->get_nth_page(pageNum)); } + +void RTWindow::setEditorMode(bool tabbedUI) +{ + MoveFileBrowserToMain(); + CloseOpenEditors(); + SetMainCurrent(); + + if(tabbedUI) { + mainNB->remove_page(*epanel); + epanel = nullptr; + set_title_decorated(""); + } else { + createSetmEditor(); + epanel->show_all(); + set_title_decorated(""); + } +} + +void RTWindow::createSetmEditor() +{ + // Editor panel, single-tab mode only + epanel = Gtk::manage ( new EditorPanel (fpanel) ); + epanel->setParent (this); + + // decorate tab + Gtk::Grid* const editorLabelGrid = Gtk::manage (new Gtk::Grid ()); + setExpandAlignProperties(editorLabelGrid, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + Gtk::Label* const el = Gtk::manage (new Gtk::Label( Glib::ustring(" ") + M("MAIN_FRAME_EDITOR") )); + + const auto pos = options.mainNBVertical ? Gtk::POS_TOP : Gtk::POS_RIGHT; + + if (options.mainNBVertical) { + el->set_angle(90); + } + + editorLabelGrid->attach_next_to(*Gtk::manage (new RTImage ("rt-logo-small.png")), pos, 1, 1); + editorLabelGrid->attach_next_to(*el, pos, 1, 1); + + editorLabelGrid->set_tooltip_markup (M("MAIN_FRAME_EDITOR_TOOLTIP")); + editorLabelGrid->show_all (); + epanel->tbTopPanel_1_visible(true); //show the toggle Top Panel button + mainNB->append_page (*epanel, *editorLabelGrid); + +} diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index f3d6c5aa2..a57f7b4a3 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -116,6 +116,8 @@ public: } void set_title_decorated(Glib::ustring fname); void CloseOpenEditors(); + void setEditorMode(bool tabbedUI); + void createSetmEditor(); }; #endif diff --git a/rtgui/toolbar.cc b/rtgui/toolbar.cc index 6c44abe57..cf5148d8b 100644 --- a/rtgui/toolbar.cc +++ b/rtgui/toolbar.cc @@ -26,10 +26,8 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n editingMode = false; - handimg = Gtk::manage (new RTImage ("openhand.png")); - handimg->reference(); - editinghandimg = Gtk::manage (new RTImage ("editmodehand.png")); - editinghandimg->reference(); + handimg.reset(new RTImage("openhand.png")); + editinghandimg.reset(new RTImage("editmodehand.png")); handTool = Gtk::manage (new Gtk::ToggleButton ()); handTool->add (*handimg); @@ -48,10 +46,8 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n pack_start (*wbTool); - showcolpickersimg = Gtk::manage (new RTImage ("colorPickers-show.png")); - showcolpickersimg->reference(); - hidecolpickersimg = Gtk::manage (new RTImage ("colorPickers-hide.png")); - hidecolpickersimg->reference(); + showcolpickersimg.reset(new RTImage("colorPickers-show.png")); + hidecolpickersimg.reset(new RTImage("colorPickers-hide.png")); colPickerTool = Gtk::manage (new Gtk::ToggleButton ()); colPickerTool->add (*showcolpickersimg); @@ -97,14 +93,6 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n straTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_STRAIGHTEN")); } -ToolBar::~ToolBar () -{ - handimg->unreference(); - editinghandimg->unreference(); - showcolpickersimg->unreference(); - hidecolpickersimg->unreference(); - -} // // Selects the desired tool without notifying the listener // diff --git a/rtgui/toolbar.h b/rtgui/toolbar.h index 93cefb555..42e764952 100644 --- a/rtgui/toolbar.h +++ b/rtgui/toolbar.h @@ -39,10 +39,10 @@ public: class ToolBar : public Gtk::HBox { private: - RTImage* handimg; - RTImage* editinghandimg; - RTImage* showcolpickersimg; - RTImage* hidecolpickersimg; + std::unique_ptr handimg; + std::unique_ptr editinghandimg; + std::unique_ptr showcolpickersimg; + std::unique_ptr hidecolpickersimg; bool showColPickers; void hand_pressed (); @@ -72,7 +72,6 @@ protected: public: ToolBar (); - ~ToolBar (); void setTool (ToolMode tool); ToolMode getTool () diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 9a692b784..1fea0cd54 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -132,15 +132,15 @@ Wavelet::Wavelet() : wavLabels(Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER))), labmC(Gtk::manage(new Gtk::Label(M("TP_WAVELET_CTYPE") + ":"))), labmNP(Gtk::manage(new Gtk::Label(M("TP_WAVELET_NPTYPE") + ":"))), - expchroma(new MyExpander(true, M("TP_WAVELET_LEVCH"))), - expcontrast(new MyExpander(true, M("TP_WAVELET_LEVF"))), - expedge(new MyExpander(true, M("TP_WAVELET_EDGE"))), - expfinal(new MyExpander(true, M("TP_WAVELET_FINAL"))), - expgamut(new MyExpander(false, M("TP_WAVELET_CONTR"))), - expnoise(new MyExpander(true, M("TP_WAVELET_NOISE"))), - expresid(new MyExpander(true, M("TP_WAVELET_RESID"))), - expsettings(new MyExpander(false, M("TP_WAVELET_SETTINGS"))), - exptoning(new MyExpander(true, M("TP_WAVELET_TON"))), + expchroma(Gtk::manage(new MyExpander(true, M("TP_WAVELET_LEVCH")))), + expcontrast(Gtk::manage(new MyExpander(true, M("TP_WAVELET_LEVF")))), + expedge(Gtk::manage(new MyExpander(true, M("TP_WAVELET_EDGE")))), + expfinal(Gtk::manage(new MyExpander(true, M("TP_WAVELET_FINAL")))), + expgamut(Gtk::manage(new MyExpander(false, M("TP_WAVELET_CONTR")))), + expnoise(Gtk::manage(new MyExpander(true, M("TP_WAVELET_NOISE")))), + expresid(Gtk::manage(new MyExpander(true, M("TP_WAVELET_RESID")))), + expsettings(Gtk::manage(new MyExpander(false, M("TP_WAVELET_SETTINGS")))), + exptoning(Gtk::manage(new MyExpander(true, M("TP_WAVELET_TON")))), neutrHBox(Gtk::manage(new Gtk::HBox())) { CurveListener::setMulti(true); @@ -838,39 +838,39 @@ Wavelet::Wavelet() : //----------------------------- - expsettings->add(*settingsBox); + expsettings->add(*settingsBox, false); expsettings->setLevel(2); pack_start (*expsettings); - expcontrast->add(*levBox); + expcontrast->add(*levBox, false); expcontrast->setLevel(2); pack_start (*expcontrast); - expchroma->add(*chBox); + expchroma->add(*chBox, false); expchroma->setLevel(2); pack_start (*expchroma); - exptoning->add(*tonBox); + exptoning->add(*tonBox, false); exptoning->setLevel(2); pack_start (*exptoning); - expnoise->add(*noiseBox); + expnoise->add(*noiseBox, false); expnoise->setLevel(2); pack_start (*expnoise); - expedge->add(*edgBox); + expedge->add(*edgBox, false); expedge->setLevel(2); pack_start (*expedge); - expgamut->add(*conBox); + expgamut->add(*conBox, false); expgamut->setLevel(2); pack_start (*expgamut); - expresid->add(*resBox); + expresid->add(*resBox, false); expresid->setLevel(2); pack_start(*expresid); - expfinal->add(*finalBox); + expfinal->add(*finalBox, false); expfinal->setLevel(2); pack_start(*expfinal); } @@ -887,6 +887,7 @@ Wavelet::~Wavelet () delete curveEditorG; delete opacityCurveEditorW; delete opacityCurveEditorWL; + } void Wavelet::wavChanged (double nlevel) diff --git a/tools/benchmarkRT b/tools/benchmarkRT index ed5950543..fbe27ebc8 100755 --- a/tools/benchmarkRT +++ b/tools/benchmarkRT @@ -6,264 +6,268 @@ # v3 2013-03-04 # v4 2013-03-07 # v5 2013-03-23 +# v6 2017-07-03 +# v7 2017-07-04 # www.rawtherapee.com -revision="tip" inFile='http://rawtherapee.com/shared/test_images/colorspace_flowers.pef' -sidecarDefault=("Neutral.pp3" "Default.pp3") -buildType="release" -branch="default" -rtExe="rawtherapee" -repo="${HOME}/rawtherapee" +rtExe="rawtherapee-cli" OPTIND=1 # Reset in case getopts has been used previously in the shell. -outFileFormat="-t" tmpDir="/tmp/rawtherapee-benchmark" runs=5 echo +die () { + printf '%s\n' "Cleaning up." + rm -rv "${tmpDir}" + exit 1 +} + +trap die HUP INT QUIT ABRT TERM + +download () { + local retries=3 + while [[ $retries -ne 0 ]]; do + wget --progress=dot:binary --continue --trust-server-names --tries=1 --timestamping "$1" 2>&1 | sed "s/^/\t/" + return=${PIPESTATUS[0]} + ((retries--)) + if [[ $return -eq 0 ]]; then # I don't trust wget to only exit with 0 if it downloaded the file succesfully, so I check. + if [[ -f "$(basename "$1")" ]]; then + break + fi + fi + printf "%s\n\n" "Failed to download \"$1\"" "Retrying: " + sleep 1s + done + if [[ $retries -eq 0 ]]; then + printf "%s\n" "Tried to download \"$1\" 3 times but failed. Exiting." + exit 1 + fi +} + howto() { - fold -s < - Input file name with complete path. This can be a file on your - hard drive or a url. The url must start with "http". The default - behavior if you do not use -i is to download a test file from - $inFile + -h - Print this help screen. - -s -s -s - Input sidecar file name(s) with full - paths. You can specify '-s ' zero or more times. To - specify multiple processing profiles, you must precede each - file path with '-s'. The processing profile can be a file on - your hard drive or a url. Only one url is handled, so if you - want to use multiple processing profiles, download them first. - The default behaviour if you do not use -s is to use the - "Neutral" profile. + -i - Absolute path to image file. This can be a file on your + hard drive or a url. The url must start with "http". The default + behavior if you do not specify -i is to download a raw image from + ${inFile} -Examples: - Run the default benchmark (recommended) + -s -s -s - Absolute path to sidecar file. + You can specify multiple sidecar files, use -s each time. + The processing profile can be a file on your hard drive or a url. + The default behaviour if you do not specify -s is to use the + "Neutral" profile. + + Examples + -------- + Run the default benchmark (recommended) ./benchmarkRT - Run a benchmark using your own image file, a RawTherpee executable in a - custom directory, and multiple processing profiles: - ./benchmarkRT -i /tmp/kittens.raw -s /tmp/kittens.raw.pp3 -s /tmp/kittens_tonemapped.raw.pp3 -s /tmp/kittens_denoised.raw.pp3 + Run a benchmark using your own image file, a RawTherpee executable in a + custom directory, and multiple processing profiles: + ./benchmarkRT -i /tmp/kittens.raw -s /tmp/noise_reduction.pp3 -s /tmp/tonemapping.pp3 -s /tmp/retinex.pp3 -Further help: - If you need further help, discover bugs or want to request new functionality - rn this script, then tell us in the forum or on IRC: - http://rawtherapee.com/forum/ - http://webchat.freenode.net/?randomnick=1&channels=rawtherapee&prompt=1 + Further Help + ------------ + If you need further help, discover bugs or want to request new + functionality, then tell us in the forum or on IRC: + https://discuss.pixls.us/t/welcome-to-the-rawtherapee-forum-read-this-first/473 + http://webchat.freenode.net/?randomnick=1&channels=rawtherapee&prompt=1 END } -download () { - local retries=10 - while [[ $retries -ne 0 ]]; do - wget --progress=dot:binary --continue --trust-server-names --tries=5 --timestamping "$1" 2>&1 | sed "s/^/\t/" - return=${PIPESTATUS[0]} - ((retries--)) - if [[ $return -eq 0 ]]; then # I don't trust wget to only exit with 0 if it downloaded the file succesfully, so I check. - if [[ -f "`basename "$1"`" ]]; then - break - fi - fi - printf "%s\n\n" "Failed to download \"$1\"" "Retrying: " - sleep 1s - done - if [[ $retries -eq 0 ]]; then - printf "%s\n" "Tried to download \"$1\" 10 times but failed. Exiting." - exit 1 - fi -} - -while getopts "ae:h?i:s:" opt; do +OPTIND=1 +while getopts "ae:i:s:h?" opt; do case "$opt" in a) testAllTools=1 ;; e) customExeDir="${OPTARG%/}" ;; - h|\?) - howto - exit 0 - ;; i) inFile="$OPTARG" ;; s) sidecarCustom+=("$OPTARG") ;; + h|\?|*) + howto + exit 0 + ;; esac done - shift $((OPTIND-1)) - [ "$1" = "--" ] && shift -inFileName="`basename "${inFile}"`" +inFileName="$(basename "${inFile}")" if [[ ! -e "${tmpDir}" ]]; then - if [[ ! -w /tmp ]]; then - printf "Error: /tmp is not writable.\n" - exit 1 - fi - mkdir "$tmpDir" + if [[ ! -w /tmp ]]; then + printf "Error: /tmp is not writable.\n" + exit 1 + fi + mkdir "$tmpDir" fi -trap 'rm -rv "${tmpDir}"; exit 1' HUP INT QUIT ABRT TERM - cd "$tmpDir" if [[ ${inFile} = http* ]]; then # if inFile is a url and if we haven't downloaded it already, then download it - [[ ! -e "${tmpDir}/${inFileName}" ]] && { + [[ ! -e "${tmpDir}/${inFileName}" ]] && { printf "%s\n\n" "${inFileName} not found in ${tmpDir}, downloading it." [[ ! -w /tmp ]] && { printf "Error: /tmp is not writable.\n"; exit 1; } [[ ! -e "$tmpDir" ]] && mkdir "$tmpDir" cd "$tmpDir" download "$inFile" echo - } +} else # otherwise if inFile is not a url, check if it exists - [[ ! -e "${inFile}" ]] && { # if it doesnt exist, choke + [[ ! -e "${inFile}" ]] && { # if it doesnt exist, choke printf "%s\n" "You specified" "-i ${inFile}" "but that file does not exist." exit 1 - } - cp "${inFile}" "${tmpDir}/${inFileName}" +} +cp "${inFile}" "${tmpDir}/${inFileName}" fi -rtExeDirs=("${customExeDir}" "$HOME/rt_${branch}_${buildType}" "$HOME/rt_${branch}_${buildType}_patched" "$HOME/rawtherapee/") +rtExeDirs=("${customExeDir}" "${HOME}/rt" "${HOME}/programs/code-rawtherapee/build/release" "${HOME}/rt_${branch}_${buildType}" "${HOME}/rawtherapee/") +found="false" for rtExeDir in "${rtExeDirs[@]}"; do - if [[ -x "${rtExeDir}/${rtExe}" ]]; then - printf "%s\n" "Using RawTherapee executable:" "${rtExeDir}/${rtExe}" - break - fi + if [[ -x "${rtExeDir}/${rtExe}" ]]; then + found="true" + break + fi done -if [[ ! -x "${rtExeDir}/${rtExe}" ]]; then - printf "%s\n" "Could not find the RawTherapee executable:" "${rtExeDir}/${rtExe}" "Re-run this script using the -e flag." - exit 0 +if [[ $found = false ]]; then + printf "%s\n" "Could not find the RawTherapee executable." "Re-run this script using the -e flag." + exit 0 fi if [[ $testAllTools -ne 1 ]]; then - if [[ -n "${sidecarCustom}" ]]; then # if sidecarCustom was specified - if [[ ${sidecarCustom} = http* ]]; then # and if sidecarCustom starts with an http - if [[ ! -e "${tmpDir}/$/{sidecarCustom##*/}" ]]; then # and if sidecarCustom hasn't been previously downloaded, then download it - printf "${sidecarCustom} not found in ${tmpDir}, downloading it.\n" - download "$sidecarCustom" - fi - else # else if sidecarCustom does not start with an http - for sidecarFile in "${sidecarCustom[@]}"; do - [[ ! -e "${sidecarFile}" ]] && { # then check if it exists - printf "You specified \"-s ${sidecarFile}\" but it does not exist. Make sure you wrote a full, absolute path, e.g.:" " -s /tmp/kittens_denoise.raw.pp3" - exit 1 - } - done - unset sidecarFiles - sidecarDir="" - sidecarFiles=("${sidecarCustom[@]}") + if [[ -n "${sidecarCustom}" ]]; then # if sidecarCustom was specified + for sidecarFile in "${sidecarCustom[@]}"; do + if [[ ${sidecarFile} = http* ]]; then # and if sidecarCustom starts with an http + if [[ ! -e "${tmpDir}/$/{sidecarFile##*/}" ]]; then # and if sidecarCustom hasn't been previously downloaded, then download it + printf "${sidecarCustom} not found in ${tmpDir}, downloading it.\n" + download "$sidecarCustom" + fi + fi + if [[ -e "${sidecarFile}" ]]; then # then check if it exists + sidecarFinal+=("${sidecarFile}") + else + printf '%s\n' "You specified \"-s ${sidecarFile}\" but it does not exist. Make sure you wrote a full, absolute path, e.g.:" " -s /tmp/custom.pp3" + exit 1 + fi + done + unset sidecarFiles + sidecarFiles=("${sidecarCustom[@]}") + else + # if sidecarCustom was not specified, use neutral. Since neutral is not a file, + # we take advantage of the fact that when RawTherapee does not find a processing profile, it uses neutral values. + sidecarFinal=("Neutral") fi - else # if sidecarCustom was not specified, find the default ones - for sidecar in "${sidecarDefault[@]}"; do - if [[ -f "${rtExeDir}/profiles/${sidecar}" ]]; then - sidecarDir="${rtExeDir}/profiles/" - elif [[ -f "${tmpDir}/${sidecar}" ]]; then - sidecarDir="${tmpDir}/" - else - printf "%s\n" "" "Could not find \"${sidecar}\" in \"${rtExeDir}/profiles/\" where it was expected to be." "Downloading the latest \"${sidecar}\" from the repository." "" - download "https://rawtherapee.googlecode.com/hg/rtdata/profiles/${sidecar}" - sidecarDir="${tmpDir}/" - fi - done - if [[ "${sidecarDir}" = "${tmpDir}/" ]]; then - printf "%s\n" "Beware that the downloaded processing profiles might not be entirely compatible with the RawTherapee version you're testing. For authentic and consistent results, make sure that the PP3 files match this RawTherapee version. You can use the -p flag to point benchmarkRT to the correct PP3 file(s)." | fold -s - fi - sidecarFiles=("${sidecarDefault[@]}") - fi else - unset sidecarFiles avgTable - sidecarDir="${tmpDir}/" - tools=("Auto Exposure;Exposure;Auto=true" "Sharpening - Unsharp Mask;Sharpening;Enabled=true;Method=usm" "Sharpening - RL Deconvolution;Sharpening;Enabled=true;Method=rld" "Vibrance;Vibrance;Enabled=true" "Edges;SharpenEdge;Enabled=true" "Microcontrast;SharpenMicro;Enabled=true" "CIECAM02;Color appearance;Enabled=true" "Impulse Noise Reduction;Impulse Denoising;Enabled=true" "Defringe;Defringing;Enabled=true" "Noise Reduction;Directional Pyramid Denoising;Enabled=true" "Tone Mapping;EPD;Enabled=true" "Shadows/Highlights;Shadows & Highlights;Enabled=true" "Contrast by Detail Levels;Directional Pyramid Equalizer;Enabled=true" "Raw Chromatic Aberration;RAW;CA=true") - for i in "${!tools[@]}"; do - IFS=";" read toolNameHuman tool key1 key2 key3 <<< "${tools[$i]}" - i=`printf "%02d\n" "$i"` - printf "%s\n" "[${tool}]" "$key1" "$key2" "$key3" > "${sidecarDir}/${i} - ${tool}.pp3" - sidecarFiles+=("${i} - ${tool}.pp3;${toolNameHuman}") - done + unset sidecarFiles avgTable sidecarDir + sidecarDir="${tmpDir}/" + tools=("Auto Exposure;Exposure;Auto=true" "Sharpening - Unsharp Mask;Sharpening;Enabled=true;Method=usm" "Sharpening - RL Deconvolution;Sharpening;Enabled=true;Method=rld" "Vibrance;Vibrance;Enabled=true" "Edges;SharpenEdge;Enabled=true" "Microcontrast;SharpenMicro;Enabled=true" "CIECAM02;Color appearance;Enabled=true" "Impulse Noise Reduction;Impulse Denoising;Enabled=true" "Defringe;Defringing;Enabled=true" "Noise Reduction;Directional Pyramid Denoising;Enabled=true" "Tone Mapping;EPD;Enabled=true" "Shadows/Highlights;Shadows & Highlights;Enabled=true" "Contrast by Detail Levels;Directional Pyramid Equalizer;Enabled=true" "Raw Chromatic Aberration;RAW;CA=true") + for i in "${!tools[@]}"; do + IFS=";" read toolNameHuman tool key1 key2 key3 <<< "${tools[$i]}" + i=$(printf "%02d\n" "$i") + printf "%s\n" "[${tool}]" "$key1" "$key2" "$key3" > "${sidecarDir}/${i} - ${tool}.pp3" + sidecarFinal+=("${i} - ${tool}.pp3;${toolNameHuman}") + done fi -printf "%s\n" "" "--------------------------------------------------------------------------------" "" "Benchmark of RawTherapee" -printf "%s\n" "`uname -srvmpio`" "" -hash cpufreq-info 2>/dev/null && cpufreq-info -mo -printf "%s\n" "" +printf "%s\n" "$(uname -srvmpio)" "" +hash cpufreq-info 2>/dev/null && { cpufreq-info -mo; printf "%s\n" ""; } + +printf "%s\n" "RawTherapee executable: ${rtExeDir}/${rtExe}" if [[ ! -f "${rtExeDir}/AboutThisBuild.txt" ]]; then - printf "%s\n" "[Could not find ${rtExeDir}/AboutThisBuild.txt]" "" + printf "%s\n" "[Could not find ${rtExeDir}/AboutThisBuild.txt]" "" else - cat "${rtExeDir}/AboutThisBuild.txt" + cat "${rtExeDir}/AboutThisBuild.txt" fi printf "%s\n" "Photo: ${tmpDir}/${inFileName}" -for sidecar in "${sidecarFiles[@]}"; do - if [[ $testAllTools -eq 1 ]]; then - IFS=";" read sidecar toolNameHuman <<< "${sidecar}" - fi - printf "%s\n" "Sidecar: ${sidecarDir}${sidecar}" +for sidecar in "${sidecarFinal[@]}"; do + if [[ $testAllTools -eq 1 ]]; then + IFS=";" read sidecar toolNameHuman <<< "${sidecar}" + fi + printf "%s\n" "Sidecar: ${sidecarDir}${sidecar}" done echo declare -A avgTable unset benchmark total sidecar sorted -for s in "${!sidecarFiles[@]}"; do - IFS=";" read sidecar toolNameHuman <<< "${sidecarFiles[s]}" - unset benchmark - for (( i=1; i<=${runs}; i++ )); do - runTime="$( { time "${rtExeDir}/${rtExe}" -o /dev/null -p "${sidecarDir}${sidecar}" "$outFileFormat" -Y -c "${tmpDir}/${inFileName}"; } 2>&1 | grep ^real; )" -# runTime=real 0m4.751s - runTime=${runTime#*[[:blank:]]} -# runTime=0m4.751s - minOnly=${runTime%m*} - secOnly=${runTime#*m}; secOnly=${secOnly%s*} - t="$( printf "%s\n" "scale=3; $secOnly+$minOnly*60" | bc )" -# t=4.751 -## t="$(( $RANDOM %20 )).$(( $RANDOM %999 ))" -# benchmark stores time array of each run, gets reset after each PP3 - benchmark+=("$t") -# total stores time array of each run, doesnt get reset, adds up total afterwards - total+=("$t") - i=`printf "%02d\n" "$i"` + +# Unfudge numbers to make sed/PE possible without spaghetti. +export LC_ALL=C + +for s in "${!sidecarFinal[@]}"; do + IFS=";" read sidecar toolNameHuman <<< "${sidecarFinal[s]}" + unset benchmark + for (( i=1; i<=${runs}; i++ )); do + runTime="$( { time "${rtExeDir}/${rtExe}" -o /dev/null/ -p "${sidecarDir}${sidecar}" -t -Y -c "${tmpDir}/${inFileName}"; } 2>&1 | grep ^real; )" + # runTime=real 0m4.751s + runTime=${runTime#*[[:blank:]]} + # runTime=0m4.751s + minOnly=${runTime%m*} + secOnly=${runTime#*m}; secOnly=${secOnly%s*} + t="$( printf "%s\n" "scale=3; $secOnly+$minOnly*60" | bc )" + # t=4.751 + ## t="$(( $RANDOM %20 )).$(( $RANDOM %999 ))" + # benchmark stores time array of each run, gets reset after each PP3 + benchmark+=("$t") + # total stores time array of each run, doesnt get reset, adds up total afterwards + total+=("$t") + i="$(printf "%02d\n" "$i")" + if [[ $testAllTools -eq 1 ]]; then + printf "%*b" "-50" "Benchmark ${i} \"${toolNameHuman}\"" "7" "${benchmark[$i - 1]}" "" "\n" | sed 's/ /../g' + else + printf "%*b" "-50" "Benchmark ${i} \"${sidecar##*/}\"" "7" "${benchmark[$i - 1]}" "" "\n" | sed 's/ /../g' + fi + done + + avg=$( { printf "%s" "scale=3; ("; IFS="+"; printf "%s" "${benchmark[*]}"; printf "%s\n" ") / ${#benchmark[@]}"; } | bc ); if [[ $testAllTools -eq 1 ]]; then - printf "%*b" "-50" "Benchmark ${i} \"${toolNameHuman}\"" "7" "${benchmark[$i - 1]}" "" "\n" | sed 's/ /../g' + printf "%*b" "-50" "Benchmark \"${toolNameHuman}\" average" "7" "${avg}" "" "\n\n" | sed 's/ /../g' + avgTable+=(["${toolNameHuman}"]="$avg") else - printf "%*b" "-50" "Benchmark ${i} \"${sidecar##*/}\"" "7" "${benchmark[$i - 1]}" "" "\n" | sed 's/ /../g' + printf "%*b" "-50" "Benchmark \"${sidecar##*/}\" average" "7" "${avg}" "" "\n\n" | sed 's/ /../g' + avgTable+=(["${sidecar}"]="$avg") fi - done - avg=$( { printf "%s" "scale=3; ("; IFS="+"; printf "%s" "${benchmark[*]}"; printf "%s\n" ") / ${#benchmark[@]}"; } | bc ); - if [[ $testAllTools -eq 1 ]]; then - printf "%*b" "-50" "Benchmark \"${toolNameHuman}\" average" "7" "${avg}" "" "\n\n" | sed 's/ /../g' - avgTable+=(["${toolNameHuman}"]="$avg") - else - printf "%*b" "-50" "Benchmark \"${sidecar##*/}\" average" "7" "${avg}" "" "\n\n" | sed 's/ /../g' - avgTable+=(["${sidecar}"]="$avg") - fi done -printf "%*b" "-50" "Benchmark total" "7" "`IFS=+; bc -l <<< "${total[*]}"`" "" "\n\n" | sed 's/ /../g' +printf "%*b" "-50" "Benchmark total" "7" "$(IFS=+; bc -l <<< "${total[*]}")" "" "\n\n" | sed 's/ /../g' # Associative arrays don't return in alphanumerical order, must be sorted manually IFS=$'\n' sorted=($(sort <<<"${!avgTable[*]}")); -printf "%s\n" "Average times for each tool:" +printf "%s\n" "Average times for each set:" for x in "${sorted[@]}"; do - printf "%*b" "-50" "${x}" "7" "${avgTable[$x]}" "" "\n" | sed 's/ /../g' + printf "%*b" "-50" "${x}" "7" "${avgTable[$x]}" "" "\n" | sed 's/ /../g' done diff --git a/tools/gimp-plugin/file-formats.h b/tools/gimp-plugin/file-formats.h index b967c7cbe..fc6697ec7 100644 --- a/tools/gimp-plugin/file-formats.h +++ b/tools/gimp-plugin/file-formats.h @@ -35,9 +35,6 @@ struct _FileFormat const gchar *load_help; }; -#define N_(s) s -#define _(s) s - static const FileFormat file_formats[] = { { diff --git a/tools/gimp-plugin/file-rawtherapee.c b/tools/gimp-plugin/file-rawtherapee.c index 92ce40f9f..9df3f17da 100644 --- a/tools/gimp-plugin/file-rawtherapee.c +++ b/tools/gimp-plugin/file-rawtherapee.c @@ -20,18 +20,16 @@ * along with this program. If not, see . */ -//#include "config.h" +#include "config.h" #include #include -#include #include #include -#include -//#include "libgimp/stdplugins-intl.h" +#include "libgimp/stdplugins-intl.h" #include "file-formats.h" @@ -39,6 +37,7 @@ #define LOAD_THUMB_PROC "file-rawtherapee-load-thumb" +static void init (void); static void query (void); static void run (const gchar *name, gint nparams, @@ -55,7 +54,7 @@ static gint32 load_thumbnail_image (const gchar *filename, const GimpPlugInInfo PLUG_IN_INFO = { - NULL, /* init_proc */ + init, /* init_proc */ NULL, /* quit_proc */ query, /* query proc */ run, /* run_proc */ @@ -65,7 +64,7 @@ MAIN () static void -query (void) +init (void) { static const GimpParamDef load_args[] = { @@ -117,7 +116,7 @@ query (void) &rtversion) == 1) { have_rawtherapee = TRUE; - free(rtversion); + free (rtversion); } g_free (rawtherapee_stdout); @@ -168,6 +167,17 @@ query (void) } } +static void +query (void) +{ + /* query() is run only the first time for efficiency. Yet this plugin + * is dependent on the presence of rawtherapee which may be installed + * or uninstalled between GIMP startups. Therefore we should move the + * usual gimp_install_procedure() to init() so that the check is done + * at every startup instead. + */ +} + static void run (const gchar *name, gint nparams, @@ -182,7 +192,7 @@ run (const gchar *name, GError *error = NULL; gint i; -// INIT_I18N (); + INIT_I18N (); run_mode = param[0].data.d_int32; @@ -278,7 +288,7 @@ load_image (const gchar *filename, if (g_spawn_sync (NULL, argv, NULL, -// G_SPAWN_STDOUT_TO_DEV_NULL | + /*G_SPAWN_STDOUT_TO_DEV_NULL |*/ G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH, NULL, @@ -293,8 +303,8 @@ load_image (const gchar *filename, gimp_image_set_filename (image_ID, filename); } -// if (rawtherapee_stdout) printf ("%s\n", rawtherapee_stdout); - g_free(rawtherapee_stdout); + /*if (rawtherapee_stdout) printf ("%s\n", rawtherapee_stdout);*/ + g_free (rawtherapee_stdout); g_unlink (filename_out); g_free (filename_out); @@ -312,9 +322,7 @@ load_thumbnail_image (const gchar *filename, gint32 image_ID = -1; gchar *filename_out = gimp_temp_name ("jpg"); gchar *thumb_pp3 = gimp_temp_name ("pp3"); - gchar *size = g_strdup_printf ("%d", thumb_size); - FILE *thumb_pp3_f = fopen(thumb_pp3, "w"); - gboolean pp3_ok = FALSE; + FILE *thumb_pp3_f = fopen (thumb_pp3, "w"); gchar *rawtherapee_stdout = NULL; const char *pp3_content = "[Version]\n" @@ -360,7 +368,7 @@ load_thumbnail_image (const gchar *filename, "\n" "[RAW X-Trans]\n" "Method=fast\n"; - + gchar *argv[] = { @@ -376,8 +384,8 @@ load_thumbnail_image (const gchar *filename, }; if (thumb_pp3_f) { - if (fprintf(thumb_pp3_f, pp3_content, thumb_size, thumb_size) < 0) { - fclose(thumb_pp3_f); + if (fprintf (thumb_pp3_f, pp3_content, thumb_size, thumb_size) < 0) { + fclose (thumb_pp3_f); thumb_pp3_f = NULL; } } @@ -413,7 +421,7 @@ load_thumbnail_image (const gchar *filename, gimp_progress_update (1.0); if (thumb_pp3_f) { - fclose(thumb_pp3_f); + fclose (thumb_pp3_f); } g_unlink (thumb_pp3); g_free (filename_out);