diff --git a/rtdata/languages/default b/rtdata/languages/default index 31b14aa2f..f47d09e5d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -80,6 +80,8 @@ EXPORT_BYPASS_SHARPENEDGE;Bypass Edge Sharpening EXPORT_BYPASS_SHARPENING;Bypass Sharpening EXPORT_BYPASS_SHARPENMICRO;Bypass Microcontrast EXPORT_BYPASS_SH_HQ;Bypass Sharp Mask Shadows/Highlights +EXPORT_USE_FAST_PIPELINE;Enable Special "Fast-Export" Processing Pipeline +EXPORT_USE_FAST_PIPELINE_TIP;Use a dedicated processing pipeline for images in Fast Export mode, that trades speed for quality. Resizing of the image is done as early as possible, instead of doing it at the end like in the normal pipeline. The speedup can be significant, but be prepared to see artifacts and a general degradation of output quality. EXPORT_FASTEXPORTOPTIONS;Fast Export Options EXPORT_INSTRUCTIONS;Fast Export options provide overrides to bypass time and resource consuming development settings and to run queue processing using the fast export settings instead. This method is recommended for quicker generation of lower resolution images when speed is a priority or when resized output is desired for one or many images without making modifications to their saved development parameters. EXPORT_MAXHEIGHT;Maximum height: diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h index fd3fe82a8..c7f49192e 100644 --- a/rtengine/processingjob.h +++ b/rtengine/processingjob.h @@ -49,6 +49,8 @@ public: initialImage->decreaseRef(); } } + + bool fastPipeline() const { return fast; } }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 4cb672e15..7449dbd0d 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -483,6 +483,8 @@ public: * gets invalid, you must not use it any more. Dont call this function while the job is being processed. * @param job is the job to destroy */ static void destroy (ProcessingJob* job); + + virtual bool fastPipeline() const = 0; }; /** This function performs all the image processinf steps corresponding to the given ProcessingJob. It returns when it is ready, so it can be slow. diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 677f912fc..3b450c492 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -67,16 +67,12 @@ public: private: Image16 *normal_pipeline() { - if (!stage_1()) { + if (!stage_init()) { return nullptr; } - stage_calc_denoise(); - stage_2(); - stage_3(); - stage_4(); - stage_5(); - stage_6(); - return stage_7(); + stage_denoise(); + stage_transform(); + return stage_finish(); } Image16 *fast_pipeline() @@ -87,26 +83,16 @@ private: pl = nullptr; - if (!stage_1()) { + if (!stage_init()) { return nullptr; } - stage_calc_denoise(); - printf("after calc denoise\n"); fflush(stdout); - stage_2(); - stage_4(); - printf("after 4\n"); fflush(stdout); + stage_transform(); stage_early_resize(); - printf("after early resize\n"); fflush(stdout); - stage_3(); - printf("after 3\n"); fflush(stdout); - stage_5(); - printf("after 5\n"); fflush(stdout); - stage_6(); - printf("after 6\n"); fflush(stdout); - return stage_7(); + stage_denoise(); + return stage_finish(); } - bool stage_1() + bool stage_init() { errorCode = 0; @@ -230,19 +216,6 @@ private: currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); } - // // AG begin - // baseImg = new Imagefloat (fw, fh); - // imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); - // // AG end - - return true; - } - - void stage_calc_denoise() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - calclum = nullptr ; params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve); autoNR = (float) settings->nrauto;// @@ -713,14 +686,6 @@ private: //end evaluate noise } - // return true; - } - - void stage_2() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - baseImg = new Imagefloat (fw, fh); imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); @@ -752,9 +717,11 @@ private: imgsrc->flushRawData(); imgsrc->flushRGB(); } + + return true; } - void stage_3() + void stage_denoise() { procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -816,17 +783,9 @@ private: delete [] ry; delete [] sk; delete [] pcsk; - - // imgsrc->convertColorSpace(baseImg, params.icm, currWB); - - // // perform first analysis - // hist16 (65536); - - // ipf.firstAnalysis (baseImg, params, hist16); } - - void stage_4() + void stage_transform() { procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -848,7 +807,7 @@ private: } } - void stage_5() + Image16 *stage_finish() { procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -990,13 +949,7 @@ private: if (pl) { pl->setProgress (0.55); } - } - void stage_6() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // start tile processing...??? @@ -1187,13 +1140,7 @@ private: if (pl) { pl->setProgress (0.60); } - } - Image16 *stage_7() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - int imw, imh; double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0; @@ -1392,12 +1339,10 @@ private: int imw, imh; double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); - // bool resize = params.resize.enabled; LabImage *tmplab = new LabImage(fw, fh); ipf.rgb2lab(*baseImg, *tmplab, params.icm.working); - // crop and convert to rgb16 int cx = 0, cy = 0, cw = fw, ch = fh; if (params.crop.enabled) { @@ -1438,9 +1383,10 @@ private: params.dirpyrDenoise.luma *= tmpScale; params.dirpyrDenoise.smethod = "shal"; + const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); for (int i = 0; i < 6; ++i) { auto &n = params.dirpyrequalizer.mult[i]; - n = 1.0 + (n - 1.0) * tmpScale; + n = 1.0 + (n - 1.0) * dirpyreq_scale; } fw = imw; diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 1f2dac51d..a02046e01 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -35,8 +35,6 @@ #include "rtimage.h" #include -#include "../rtengine/processingjob.h" - using namespace std; using namespace rtengine; @@ -245,7 +243,7 @@ bool BatchQueue::saveBatchQueue () << saveFormat.pngBits << '|' << saveFormat.pngCompression << '|' << saveFormat.tiffBits << '|' << saveFormat.tiffUncompressed << '|' << saveFormat.saveParams << '|' << entry->forceFormatOpts << '|' - << static_cast(entry->job)->fast << '|' + << entry->job->fastPipeline() << '|' << std::endl; } } diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index 3f7be7ab4..fe18cdef7 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -39,6 +39,8 @@ ExportPanel::ExportPanel () : listener (nullptr) pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4); bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL"))); + use_fast_pipeline = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_USE_FAST_PIPELINE"))); + use_fast_pipeline->set_tooltip_text(M("EXPORT_USE_FAST_PIPELINE_TIP")); bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING"))); bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE"))); bypass_sharpenMicro = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENMICRO"))); @@ -96,6 +98,7 @@ ExportPanel::ExportPanel () : listener (nullptr) // ---------------------------------------------------------------- // start global packing + pack_start(*use_fast_pipeline , Gtk::PACK_SHRINK, 4); pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4); pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4); @@ -224,40 +227,48 @@ void ExportPanel::FastExportPressed () void ExportPanel::SaveSettingsAsDefault() { + bool changed = false; +#define FE_OPT_STORE_(n, v) \ + do { \ + if (n != v) { \ + n = v; \ + changed = true; \ + } \ + } while (false) // Save fast export settings to options - options.fastexport_bypass_sharpening = bypass_sharpening->get_active (); - options.fastexport_bypass_sharpenEdge = bypass_sharpenEdge->get_active (); - options.fastexport_bypass_sharpenMicro = bypass_sharpenMicro->get_active (); + FE_OPT_STORE_(options.fastexport_bypass_sharpening, bypass_sharpening->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_sharpenEdge, bypass_sharpenEdge->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_sharpenMicro, bypass_sharpenMicro->get_active ()); //options.fastexport_bypass_lumaDenoise = bypass_lumaDenoise->get_active (); //options.fastexport_bypass_colorDenoise = bypass_colorDenoise->get_active (); - options.fastexport_bypass_defringe = bypass_defringe->get_active (); - options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active (); - options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active (); - options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active (); - options.fastexport_bypass_wavelet = bypass_wavelet->get_active (); + FE_OPT_STORE_(options.fastexport_bypass_defringe, bypass_defringe->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_dirpyrDenoise, bypass_dirpyrDenoise->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_sh_hq, bypass_sh_hq->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_dirpyrequalizer, bypass_dirpyrequalizer->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_wavelet, bypass_wavelet->get_active ()); //options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active (); - options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active (); - options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active (); - options.fastexport_bypass_raw_bayer_lmmse_iterations = bypass_raw_bayer_lmmse_iterations->get_active(); - options.fastexport_bypass_raw_bayer_linenoise = bypass_raw_bayer_linenoise->get_active (); - options.fastexport_bypass_raw_bayer_greenthresh = bypass_raw_bayer_greenthresh->get_active (); - options.fastexport_bypass_raw_ccSteps = bypass_raw_ccSteps->get_active (); - options.fastexport_bypass_raw_ca = bypass_raw_ca->get_active (); - options.fastexport_bypass_raw_df = bypass_raw_df->get_active (); - options.fastexport_bypass_raw_ff = bypass_raw_ff->get_active (); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_dcb_iterations, bypass_raw_bayer_dcb_iterations->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_dcb_enhance, bypass_raw_bayer_dcb_enhance->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_lmmse_iterations, bypass_raw_bayer_lmmse_iterations->get_active()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_linenoise, bypass_raw_bayer_linenoise->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_greenthresh, bypass_raw_bayer_greenthresh->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_ccSteps, bypass_raw_ccSteps->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_ca, bypass_raw_ca->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_df, bypass_raw_df->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_ff, bypass_raw_ff->get_active ()); //saving Bayer demosaic_method int currentRow = raw_bayer_method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { - options.fastexport_raw_bayer_method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; + FE_OPT_STORE_(options.fastexport_raw_bayer_method, procparams::RAWParams::BayerSensor::methodstring[currentRow]); } //saving X-Trans demosaic_method currentRow = raw_xtrans_method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) { - options.fastexport_raw_xtrans_method = procparams::RAWParams::XTransSensor::methodstring[currentRow]; + FE_OPT_STORE_(options.fastexport_raw_xtrans_method, procparams::RAWParams::XTransSensor::methodstring[currentRow]); } // options.fastexport_icm_input = icm_input ; @@ -269,9 +280,16 @@ void ExportPanel::SaveSettingsAsDefault() // options.fastexport_resize_appliesTo = resize_appliesTo; // options.fastexport_resize_dataspec = resize_dataspec ; - options.fastexport_resize_method = "Lanczos"; - options.fastexport_resize_width = MaxWidth->get_value_as_int (); - options.fastexport_resize_height = MaxHeight->get_value_as_int (); + FE_OPT_STORE_(options.fastexport_resize_method, "Lanczos"); + FE_OPT_STORE_(options.fastexport_resize_width, MaxWidth->get_value_as_int ()); + FE_OPT_STORE_(options.fastexport_resize_height, MaxHeight->get_value_as_int ()); + + FE_OPT_STORE_(options.fastexport_use_fast_pipeline, use_fast_pipeline->get_active()); +#undef FE_OPT_STORE_ + + if (changed) { + Options::save(); + } } void ExportPanel::LoadDefaultSettings() @@ -327,6 +345,8 @@ void ExportPanel::LoadDefaultSettings() MaxWidth->set_value(options.fastexport_resize_width); MaxHeight->set_value(options.fastexport_resize_height); + + use_fast_pipeline->set_active(options.fastexport_use_fast_pipeline); } void ExportPanel::LoadSettings() diff --git a/rtgui/exportpanel.h b/rtgui/exportpanel.h index 840a4638d..ce7639921 100644 --- a/rtgui/exportpanel.h +++ b/rtgui/exportpanel.h @@ -38,6 +38,7 @@ protected: //Gtk::CheckButton* enabled; Gtk::CheckButton* bypass_ALL; + Gtk::CheckButton* use_fast_pipeline; Gtk::CheckButton* bypass_sharpenEdge; Gtk::CheckButton* bypass_sharpenMicro; Gtk::CheckButton* bypass_sharpening; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 99c190cde..68219d745 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1094,7 +1094,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas // controlling time and resource consuming tasks // and also those which effect is not pronounced after reducing the image size // TODO!!! could expose selections below via preferences - if (fastmode && false) { + if (fastmode) { if (options.fastexport_bypass_sharpening ) { params.sharpening.enabled = false; } @@ -1183,11 +1183,11 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.resize.appliesTo = options.fastexport_resize_appliesTo ; params.resize.method = options.fastexport_resize_method ; params.resize.dataspec = options.fastexport_resize_dataspec ; - params.resize.width = options.fastexport_resize_width ; - params.resize.height = options.fastexport_resize_height ; + params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width) ; + params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height) ; } - rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode); + rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline); int pw; int ph = BatchQueue::calcMaxThumbnailHeight(); diff --git a/rtgui/options.cc b/rtgui/options.cc index 2f71a7106..9a8b5e08b 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -480,6 +480,7 @@ void Options::setDefaults () fastexport_resize_dataspec = 3; fastexport_resize_width = 900; fastexport_resize_height = 900; + fastexport_use_fast_pipeline = false; clutsDir = "./cluts"; @@ -1784,6 +1785,9 @@ int Options::readFromFile (Glib::ustring fname) if (keyFile.has_key ("Fast Export", "fastexport_resize_height" )) { fastexport_resize_height = keyFile.get_integer ("Fast Export", "fastexport_resize_height" ); } + if (keyFile.has_key ("Fast Export", "fastexport_use_fast_pipeline" )) { + fastexport_use_fast_pipeline = keyFile.get_integer ("Fast Export", "fastexport_use_fast_pipeline" ); + } } if (keyFile.has_group ("Dialogs")) { @@ -2142,6 +2146,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_integer ("Fast Export", "fastexport_resize_dataspec", fastexport_resize_dataspec ); keyFile.set_integer ("Fast Export", "fastexport_resize_width", fastexport_resize_width ); keyFile.set_integer ("Fast Export", "fastexport_resize_height", fastexport_resize_height ); + keyFile.set_integer ("Fast Export", "fastexport_use_fast_pipeline", fastexport_use_fast_pipeline ); keyFile.set_string ("Dialogs", "LastIccDir", lastIccDir); keyFile.set_string ("Dialogs", "LastDarkframeDir", lastDarkframeDir); diff --git a/rtgui/options.h b/rtgui/options.h index efc649417..b853c07f6 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -279,6 +279,7 @@ public: int fastexport_resize_dataspec; int fastexport_resize_width; int fastexport_resize_height; + bool fastexport_use_fast_pipeline; // Dialog settings Glib::ustring lastIccDir;