diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 61b366778..216831c52 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -871,7 +871,8 @@ void png_flush(png_structp png_ptr) { int ImageIO::load (Glib::ustring fname) { int lastdot = fname.find_last_of ('.'); - + if( Glib::ustring::npos == lastdot ) + return IMIO_FILETYPENOTSUPPORTED; if (!fname.casefold().compare (lastdot, 4, ".png")) return loadPNG (fname); else if (!fname.casefold().compare (lastdot, 4, ".jpg")) @@ -884,7 +885,8 @@ int ImageIO::load (Glib::ustring fname) { int ImageIO::save (Glib::ustring fname) { int lastdot = fname.find_last_of ('.'); - + if( Glib::ustring::npos == lastdot ) + return IMIO_FILETYPENOTSUPPORTED; if (!fname.casefold().compare (lastdot, 4, ".png")) return savePNG (fname); else if (!fname.casefold().compare (lastdot, 4, ".jpg")) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index fcd3fdaf8..bf3f4d91b 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -161,7 +161,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) : beforePreviewHandler(NULL), be sendtogimp->set_tooltip_markup(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); iops->pack_start (*saveimgas, Gtk::PACK_SHRINK); - iops->pack_start (*queueimg, Gtk::PACK_SHRINK); + if(!simpleEditor) + iops->pack_start (*queueimg, Gtk::PACK_SHRINK); iops->pack_start (*sendtogimp, Gtk::PACK_SHRINK); // Status box diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 4497db882..f62c6f0e7 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -131,7 +131,7 @@ void FilePanel::init () { dirBrowser->fillDirTree (); placesBrowser->refreshPlacesList (); - if (argv1!="") + if (argv1!="" && safe_file_test (argv1, Glib::FILE_TEST_IS_DIR)) dirBrowser->open (argv1); else { if (options.startupDir==STARTUPDIR_HOME) diff --git a/rtgui/main.cc b/rtgui/main.cc index 93661eb68..af7acb8ad 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -43,18 +43,24 @@ extern Options options; -//#ifdef WIN32 -//#include // included for WinMain -//#endif - // stores path to data files Glib::ustring argv0; Glib::ustring argv1; +bool simpleEditor; + +/* Process line command options + * Returns + * 0 if process in batch has executed + * 1 to start GUI (with a dir or file option) + * 2 to start GUI because no files found + * -1 if there is an error in parameters + * -2 if an error occurred during processing */ +int processLineParams( int argc, char **argv ); int main(int argc, char **argv) { - std::string argv0_, argv1_; + std::string argv0_; #ifdef WIN32 char exname[512]; @@ -81,18 +87,12 @@ int main(int argc, char **argv) #endif - if (argc>1) - argv1_ = argv[1]; - else - argv1_ = ""; #ifdef GLIBMM_EXCEPTIONS_ENABLED argv0 = Glib::filename_to_utf8 (argv0_); - argv1 = Glib::filename_to_utf8 (argv1_); #else std::auto_ptr error; argv0 = Glib::filename_to_utf8 (argv0_, error); - argv1 = Glib::filename_to_utf8 (argv1_, error); #endif //GLIBMM_EXCEPTIONS_ENABLED Glib::thread_init(); @@ -101,13 +101,23 @@ int main(int argc, char **argv) Options::load (); + if (argc>1){ + int ret = processLineParams( argc, argv); + if( ret <= 0 ) + return ret; + } + #ifndef _WIN32 // Move the old path to the new one if the new does not exist if (safe_file_test(Glib::build_filename(options.rtdir,"cache"), Glib::FILE_TEST_IS_DIR) && !safe_file_test(options.cacheBaseDir, Glib::FILE_TEST_IS_DIR)) safe_g_rename(Glib::build_filename(options.rtdir,"cache"), options.cacheBaseDir); #endif -// Gtk::RC::add_default_file (argv0+"/themes/"+options.theme); + simpleEditor=false; + if( !argv1.empty() ) + if( Glib::file_test(argv1, Glib::FILE_TEST_EXISTS) && !Glib::file_test(argv1, Glib::FILE_TEST_IS_DIR)) + simpleEditor = true; + if (!options.useSystemTheme) { std::vector rcfiles; @@ -118,7 +128,7 @@ int main(int argc, char **argv) Gtk::RC::set_default_files (rcfiles); } Gtk::Main m(&argc, &argv); -// MainWindow *MainWindow = new class MainWindow(); + RTWindow *rtWindow = new class RTWindow(); gdk_threads_enter (); m.run(*rtWindow); @@ -128,5 +138,246 @@ int main(int argc, char **argv) } +int processLineParams( int argc, char **argv ) +{ + std::vector inputFiles; + Glib::ustring outputPath; + Glib::ustring processingParams; + bool isDirectory=false; + bool outputDirectory=false; + bool overwriteFiles=false; + bool sideProcParams=false; + bool copyParamsFile=false; + bool useDefaultIfAbsent=true; + int compression=100; + int bits=-1; + std::string outputType; + unsigned errors=0; + for( int iArg=1; iArg names; + Glib::RefPtr dir = Gio::File::create_for_path ( argv[iArg] ); + safe_build_file_list (dir, names, argv[iArg] ); + for(size_t iFile=0; iFile< names.size(); iFile++ ){ + if( !safe_file_test( names[iFile] , Glib::FILE_TEST_IS_DIR)){ + // skip files without extension and pp3 files + Glib::ustring s(names[iFile]); + Glib::ustring::size_type ext= s.find_last_of('.'); + if( Glib::ustring::npos == ext ) + continue; + if( ! s.substr(ext).compare( paramFileExtension )) + continue; + inputFiles.push_back( names[iFile] ); + } + } + }else{ + inputFiles.push_back( Glib::filename_to_utf8 (argv[iArg]) ); + } + } + break; + case 'h': + case '?': + default: + std::cerr << "Usage:"<< std::endl; + std::cerr << Glib::path_get_basename(argv[0]) << " [] : start RT GUI browser inside dir."<< std::endl; + std::cerr << Glib::path_get_basename(argv[0]) << " : start GUI editor with file."<< std::endl; + std::cerr << Glib::path_get_basename(argv[0]) << " -c | : convert files in batch with default parameters."<< std::endl<< std::endl; + std::cerr << "Other options used with -c (that must be last option) "<< std::endl; + std::cerr << Glib::path_get_basename(argv[0]) <<" [-o | -O ] [-s | -S | -p ] [-j[1-100]|-t|-n] -Y -c "<< std::endl; + std::cerr << " -o | : select output directory."<< std::endl; + std::cerr << " -O | : select output dir and copy pp3 file into it"<< std::endl; + std::cerr << " -s : select parameters to be pp3 file next to input file (with same name)"<< std::endl; + std::cerr << " ex: for IMG001.NEF there should be IMG001.NEF.pp3 in the same dir" << std::endl; + std::cerr << " if absent use default" << std::endl; + std::cerr << " -S : like -s but skip if pp3 file not found." << std::endl; + std::cerr << " -p : specify pp3 file to be used for all conversions."<< std::endl; + std::cerr << " -j[compression] : specify output to be jpeg.(default)"<< std::endl; + std::cerr << " -t : specify output to be tif."<< std::endl; + std::cerr << " -n : specify output to be png."<< std::endl; + std::cerr << " -Y : overwrite output if present."<< std::endl; + return -1; + } + }else{ + argv1 = Glib::filename_to_utf8 ( argv[iArg] ); + if( outputDirectory ){ + options.savePathFolder = outputPath; + options.saveUsePathTemplate = false; + } + if (outputType == "jpg") { + options.saveFormat.format = outputType; + options.saveFormat.jpegQuality = compression; + } else if (outputType == "tif") { + options.saveFormat.format = outputType; + } else if (outputType == "png") { + options.saveFormat.format = outputType; + } + break; + } + } + if( !argv1.empty() ) + return 1; + if( !inputFiles.size() ) + return 2; + rtengine::procparams::ProcParams params,paramsRaw,paramsImg, *currentParams; + if( !sideProcParams ){ + if( processingParams.length()>0 ) + params.load ( processingParams ); + else{ + paramsRaw.load(options.profilePath+"/"+options.defProfRaw+paramFileExtension); + paramsImg.load(options.profilePath+"/"+options.defProfImg+paramFileExtension); + } + } + for( size_t iFile=0; iFile< inputFiles.size(); iFile++){ + Glib::ustring inputFile = inputFiles[iFile]; + std::cout << "Processing: " << inputFile << std::endl; + + rtengine::InitialImage* ii=NULL; + rtengine::ProcessingJob* job =NULL; + int errorCode; + bool isRaw=false; + + Glib::ustring outputFile; + if( outputType.empty() ) + outputType = "jpg"; + if( outputPath.empty() ){ + Glib::ustring s = inputFile; + Glib::ustring::size_type ext= s.find_last_of('.'); + outputFile = s.substr(0,ext)+ "." + outputType; + }else if( outputDirectory ){ + Glib::ustring s = Glib::path_get_basename( inputFile ); + Glib::ustring::size_type ext= s.find_last_of('.'); + outputFile = outputPath + "/" + s.substr(0,ext) + "." + outputType; + }else{ + Glib::ustring s = outputPath; + Glib::ustring::size_type ext= s.find_last_of('.'); + outputFile = s.substr(0,ext) + "." + outputType; + } + if( inputFile == outputFile){ + std::cerr << "Cannot overwrite:" << inputFile << std::endl; + continue; + } + if( !overwriteFiles && safe_file_test( outputFile , Glib::FILE_TEST_EXISTS ) ){ + std::cerr << outputFile <<" already exists: use -Y option to overwrite:" << std::endl; + continue; + } + + // Load the image + ii = rtengine::InitialImage::load ( inputFile, true, &errorCode, NULL ); + if (ii) + isRaw=true; + else + ii = rtengine::InitialImage::load ( inputFile , false, &errorCode, NULL ); + if (!ii) { + errors++; + std::cerr << "Error loading file:"<< inputFile << std::endl; + continue; + } + if( sideProcParams ){ + Glib::ustring sideProcessingParams = inputFile + paramFileExtension; + if( !safe_file_test( sideProcessingParams, Glib::FILE_TEST_EXISTS ) || params.load ( sideProcessingParams )){ + if( useDefaultIfAbsent ){ + currentParams = isRaw? ¶msRaw: ¶msImg; + }else{ + delete ii; + errors++; + std::cerr << "Error loading processing params:"<< sideProcessingParams << std::endl; + continue; + } + }else + currentParams = ¶ms; + }else if( processingParams.length()>0 ){ + currentParams = ¶ms; + }else if(isRaw ){ + currentParams = ¶msRaw; + }else{ + currentParams = ¶msImg; + } + job = rtengine::ProcessingJob::create (ii, *currentParams); + if( !job ){ + errors++; + std::cerr << "Error creating processing for:"<< inputFile << std::endl; + ii->decreaseRef(); + continue; + } + + // Process image + rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, NULL); + if( !resultImage ){ + errors++; + std::cerr << "Error processing:"<< inputFile << std::endl; + rtengine::ProcessingJob::destroy( job ); + continue; + } + // save image to disk + if( outputType=="jpg" ) + errorCode = resultImage->saveAsJPEG( outputFile, compression ); + else if( outputType=="tif" ) + errorCode = resultImage->saveAsTIFF( outputFile, bits, compression==0 ); + else if( outputType=="png" ) + errorCode = resultImage->saveAsPNG( outputFile,compression, bits ); + else + errorCode = resultImage->saveToFile (outputFile); + + if(errorCode){ + errors++; + std::cerr << "Error saving to:"<< outputFile << std::endl; + }else{ + if( copyParamsFile ){ + Glib::ustring outputProcessingParams = outputFile + paramFileExtension; + currentParams->save( outputProcessingParams ); + } + } + + ii->decreaseRef(); + resultImage->free(); + } + return errors>0?-2:0; +} diff --git a/rtgui/options.h b/rtgui/options.h index ff0b2c1e6..d2fadbbec 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -156,6 +156,7 @@ class Options { extern Options options; extern Glib::ustring argv0; extern Glib::ustring argv1; +extern bool simpleEditor; extern Glib::ustring versionString; extern Glib::ustring paramFileExtension; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index 34e671d2e..2a3fef054 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -22,9 +22,12 @@ #include -RTWindow::RTWindow () { - - epanel=NULL; // to prevent eventing errors +RTWindow::RTWindow () +:fpanel(NULL) +,epanel(NULL) +,bpanel(NULL) +,mainNB(NULL) +{ cacheMgr->init (); @@ -49,105 +52,122 @@ RTWindow::RTWindow () { property_destroy_with_parent().set_value(false); signal_window_state_event().connect( sigc::mem_fun(*this, &RTWindow::on_window_state_event) ); - mainNB = Gtk::manage (new Gtk::Notebook ()); - mainNB->set_scrollable (true); - mainNB->signal_switch_page().connect_notify( sigc::mem_fun(*this, &RTWindow::on_mainNB_switch_page) ); + if(simpleEditor) + { + epanel = new EditorPanel (NULL); + epanel->setParent (this); + add (*epanel); + show_all (); - fpanel = new FilePanel (); - fpanel->setParent (this); + CacheManager* cm = CacheManager::getInstance(); + Thumbnail* thm= cm->getEntry( argv1 ); + if(thm){ + int error; + rtengine::InitialImage *ii= rtengine::InitialImage::load(argv1,thm->getType() == FT_Raw,&error,NULL); + epanel->open( thm, ii ); + } + }else{ + mainNB = Gtk::manage (new Gtk::Notebook ()); + mainNB->set_scrollable (true); + mainNB->signal_switch_page().connect_notify( sigc::mem_fun(*this, &RTWindow::on_mainNB_switch_page) ); - // decorate tab - if (options.mainNBVertical) { - mainNB->set_tab_pos (Gtk::POS_LEFT); + fpanel = new FilePanel (); + fpanel->setParent (this); - Gtk::VBox* vbf = Gtk::manage (new Gtk::VBox ()); - vbf->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); - Gtk::Label* l=new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_FILEBROWSER")); - l->set_angle (90); - vbf->pack_start (*l); - vbf->set_spacing (2); - vbf->show_all (); - mainNB->append_page (*fpanel, *vbf); - } else { - Gtk::HBox* hbf = Gtk::manage (new Gtk::HBox ()); - hbf->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); - hbf->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER")))); - hbf->set_spacing (2); - hbf->show_all (); - mainNB->append_page (*fpanel, *hbf); + // decorate tab + if (options.mainNBVertical) { + mainNB->set_tab_pos (Gtk::POS_LEFT); + + Gtk::VBox* vbf = Gtk::manage (new Gtk::VBox ()); + vbf->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); + Gtk::Label* l=new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_FILEBROWSER")); + l->set_angle (90); + vbf->pack_start (*l); + vbf->set_spacing (2); + vbf->show_all (); + mainNB->append_page (*fpanel, *vbf); + } else { + Gtk::HBox* hbf = Gtk::manage (new Gtk::HBox ()); + hbf->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); + hbf->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER")))); + hbf->set_spacing (2); + hbf->show_all (); + mainNB->append_page (*fpanel, *hbf); + } + + bpanel = new BatchQueuePanel (); + bpanel->setParent (this); + + // decorate tab, the label is unimportant since its updated in batchqueuepanel anyway + Gtk::Label* lbq = new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")); + mainNB->append_page (*bpanel, *lbq); + + // epanel is only for single tab mode + epanel = new EditorPanel (fpanel); + epanel->setParent (this); + + // decorate tab + if (options.mainNBVertical) { + Gtk::VBox* vbe = Gtk::manage (new Gtk::VBox ()); + vbe->pack_start (*Gtk::manage (new Gtk::Image (argv0+"/images/logoicon16.png"))); + Gtk::Label* l=new Gtk::Label( Glib::ustring(" ") + M("MAIN_FRAME_EDITOR") ); + //l->set_markup(Glib::ustring("Editor")); Bold difficult to read + l->set_angle (90); + vbe->pack_start (*l); + vbe->set_spacing (2); + vbe->show_all (); + mainNB->append_page (*epanel, *vbe); + } else { + Gtk::HBox* hbe = Gtk::manage (new Gtk::HBox ()); + hbe->pack_start (*Gtk::manage (new Gtk::Image (argv0+"/images/logoicon16.png"))); + hbe->pack_start (*Gtk::manage (new Gtk::Label(M("MAIN_FRAME_EDITOR")))); + hbe->set_spacing (2); + hbe->show_all (); + mainNB->append_page (*epanel, *hbe); + } + + mainNB->set_current_page (mainNB->page_num (*fpanel)); + + signal_key_press_event().connect( sigc::mem_fun(*this, &RTWindow::keyPressed) ); + + Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ()); + mainBox->pack_start (*mainNB); + Gtk::HBox* bottomBox = Gtk::manage (new Gtk::HBox ()); + mainBox->pack_start (*bottomBox, Gtk::PACK_SHRINK, 1); + + // filling bottom box + Gtk::LinkButton* rtWeb = Gtk::manage (new Gtk::LinkButton ("http://rawtherapee.com")); + Gtk::Button* preferences = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_PREFERENCES")+"...")); + preferences->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-preferences"), Gtk::ICON_SIZE_BUTTON))); + preferences->signal_clicked().connect( sigc::mem_fun(*this, &RTWindow::showPreferences) ); + is_fullscreen = false; + btn_fullscreen = Gtk::manage( new Gtk::Button(M("MAIN_BUTTON_FULLSCREEN"))); + btn_fullscreen->signal_clicked().connect( sigc::mem_fun(*this, &RTWindow::toggle_fullscreen) ); + bottomBox->pack_start (*preferences, Gtk::PACK_SHRINK, 0); + bottomBox->pack_end (*btn_fullscreen, Gtk::PACK_SHRINK, 4); + bottomBox->pack_start (*rtWeb, Gtk::PACK_SHRINK, 4); + bottomBox->pack_start (prLabel ); + prLabel.set_alignment(Gtk::ALIGN_RIGHT); + bottomBox->pack_start (prProgBar, Gtk::PACK_SHRINK, 4); + + pldBridge = new PLDBridge(&prLabel,&prProgBar); + + Glib::RefPtr style = Gtk::RcStyle::create (); + style->set_xthickness (0); + style->set_ythickness (0); + rtWeb->modify_style (style); + + add (*mainBox); + show_all (); } - - bpanel = new BatchQueuePanel (); - bpanel->setParent (this); - - // decorate tab, the label is unimportant since its updated in batchqueuepanel anyway - Gtk::Label* lbq = new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")); - mainNB->append_page (*bpanel, *lbq); - - // epanel is only for single tab mode - epanel = new EditorPanel (fpanel); - epanel->setParent (this); - - // decorate tab - if (options.mainNBVertical) { - Gtk::VBox* vbe = Gtk::manage (new Gtk::VBox ()); - vbe->pack_start (*Gtk::manage (new Gtk::Image (argv0+"/images/logoicon16.png"))); - Gtk::Label* l=new Gtk::Label( Glib::ustring(" ") + M("MAIN_FRAME_EDITOR") ); - //l->set_markup(Glib::ustring("Editor")); Bold difficult to read - l->set_angle (90); - vbe->pack_start (*l); - vbe->set_spacing (2); - vbe->show_all (); - mainNB->append_page (*epanel, *vbe); - } else { - Gtk::HBox* hbe = Gtk::manage (new Gtk::HBox ()); - hbe->pack_start (*Gtk::manage (new Gtk::Image (argv0+"/images/logoicon16.png"))); - hbe->pack_start (*Gtk::manage (new Gtk::Label(M("MAIN_FRAME_EDITOR")))); - hbe->set_spacing (2); - hbe->show_all (); - mainNB->append_page (*epanel, *hbe); - } - - mainNB->set_current_page (mainNB->page_num (*fpanel)); - - signal_key_press_event().connect( sigc::mem_fun(*this, &RTWindow::keyPressed) ); - - Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ()); - mainBox->pack_start (*mainNB); - Gtk::HBox* bottomBox = Gtk::manage (new Gtk::HBox ()); - mainBox->pack_start (*bottomBox, Gtk::PACK_SHRINK, 1); - - // filling bottom box - Gtk::LinkButton* rtWeb = Gtk::manage (new Gtk::LinkButton ("http://rawtherapee.com")); - Gtk::Button* preferences = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_PREFERENCES")+"...")); - preferences->set_image (*Gtk::manage(new Gtk::Image (Gtk::StockID("gtk-preferences"), Gtk::ICON_SIZE_BUTTON))); - preferences->signal_clicked().connect( sigc::mem_fun(*this, &RTWindow::showPreferences) ); - is_fullscreen = false; - btn_fullscreen = Gtk::manage( new Gtk::Button(M("MAIN_BUTTON_FULLSCREEN"))); - btn_fullscreen->signal_clicked().connect( sigc::mem_fun(*this, &RTWindow::toggle_fullscreen) ); - bottomBox->pack_start (*preferences, Gtk::PACK_SHRINK, 0); - bottomBox->pack_end (*btn_fullscreen, Gtk::PACK_SHRINK, 4); - bottomBox->pack_start (*rtWeb, Gtk::PACK_SHRINK, 4); - bottomBox->pack_start (prLabel ); - prLabel.set_alignment(Gtk::ALIGN_RIGHT); - bottomBox->pack_start (prProgBar, Gtk::PACK_SHRINK, 4); - pldBridge = new PLDBridge(&prLabel,&prProgBar); - - Glib::RefPtr style = Gtk::RcStyle::create (); - style->set_xthickness (0); - style->set_ythickness (0); - rtWeb->modify_style (style); - - add (*mainBox); - show_all (); - - if (!isSingleTabMode()) epanel->hide_all(); + if (!isSingleTabMode()&& !simpleEditor) epanel->hide_all(); } void RTWindow::on_realize () { Gtk::Window::on_realize (); - fpanel->setAspect(); + if( fpanel ) + fpanel->setAspect(); cursorManager.init (get_window()); } @@ -275,11 +295,13 @@ void RTWindow::addBatchQueueJobs (std::vector &entries) { bool RTWindow::on_delete_event(GdkEventAny* event) { - - fpanel->saveOptions (); - bpanel->saveOptions (); + if( fpanel ) + fpanel->saveOptions (); + if( bpanel ) + bpanel->saveOptions (); - if (isSingleTabMode()) epanel->saveProfile(); + if (isSingleTabMode() || simpleEditor) + epanel->saveProfile(); cacheMgr->closeCache (); // also makes cleanup if too large