From d17bb0cfe6b9b0ba8a5b43c2e92fc78d78b0b1d4 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 21 Mar 2018 10:47:38 +0100 Subject: [PATCH] feature: added option to use a (fast) neutral RAW rendering in 'inspector mode' --- rtdata/languages/default | 4 ++ rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 3 +- rtengine/rtthumbnail.cc | 109 ++++++++++++++++++++++++++++++++++--- rtengine/settings.h | 7 +++ rtgui/options.cc | 7 +++ rtgui/preferences.cc | 16 +++++- rtgui/preferences.h | 1 + 8 files changed, 139 insertions(+), 12 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 60b68bbd7..4f2f0b1ae 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1157,6 +1157,10 @@ PREFERENCES_TAB_IMPROC;Image Processing PREFERENCES_TAB_PERFORMANCE;Performance & Quality PREFERENCES_TAB_SOUND;Sounds PREFERENCES_THEME;Theme +PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;Embedded JPEG preview +PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Image to show +PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral RAW rendering +PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral RAW otherwise PREFERENCES_TIMAX;High PREFERENCES_TINB;Number of tiles PREFERENCES_TISTD;Standard diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 081ac3661..ebd92bf3e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1518,7 +1518,7 @@ void RawImageSource::vflip (Imagefloat* image) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::load (const Glib::ustring &fname) +int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) { MyTime t1, t2; @@ -1535,7 +1535,7 @@ int RawImageSource::load (const Glib::ustring &fname) if (errCode) { return errCode; } - numFrames = ri->getFrameCount(); + numFrames = firstFrameOnly ? 1 : ri->getFrameCount(); errCode = 0; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 884c32dbe..04b7396bc 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -118,7 +118,8 @@ public: RawImageSource (); ~RawImageSource (); - int load (const Glib::ustring &fname); + int load(const Glib::ustring &fname) { return load(fname, false); } + int load(const Glib::ustring &fname, bool firstFrameOnly); void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true); void demosaic (const RAWParams &raw); void retinex (const ColorManagementParams& cmp, const RetinexParams &deh, const ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 05d4bead8..8c6b7155c 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -36,7 +36,10 @@ #include "jpeg.h" #include "../rtgui/ppversion.h" #include "improccoordinator.h" +#include "settings.h" #include +#include "StopWatch.h" +#include "median.h" namespace { @@ -147,6 +150,8 @@ extern Options options; namespace rtengine { +extern const Settings *settings; + using namespace procparams; Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode) @@ -261,13 +266,92 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, return tpp; } + +namespace { + +Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml, eSensorType &sensorType, int &w, int &h) +{ + BENCHFUN + + RawImageSource src; + int err = src.load(fname, true); + if (err) { + return nullptr; + } + + src.getFullSize(w, h); + sensorType = src.getSensorType(); + + ProcParams neutral; + neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); + neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); + neutral.icm.input = "(camera)"; + neutral.icm.working = "RT_sRGB"; + + src.preprocess(neutral.raw, neutral.lensProf, neutral.coarse, false); + src.demosaic(neutral.raw); + + PreviewProps pp(0, 0, w, h, 1); + + Imagefloat tmp(w, h); + src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw); + src.convertColorSpace(&tmp, neutral.icm, src.getWB()); + + Image8 *img = new Image8(w, h); + const float f = 255.f/65535.f; +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + float r = tmp.r(y, x); + float g = tmp.g(y, x); + float b = tmp.b(y, x); + // avoid magenta highlights + if (r > MAXVALF && b > MAXVALF) { + float v = CLIP((r + g + b) / 3.f) * f; + img->r(y, x) = img->g(y, x) = img->b(y, x) = v; + } else { + img->r(y, x) = Color::gamma_srgbclipped(r) * f; + img->g(y, x) = Color::gamma_srgbclipped(g) * f; + img->b(y, x) = Color::gamma_srgbclipped(b) * f; + } + } + } + + return img; +} + +} // namespace + Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode) { + Thumbnail* tpp = new Thumbnail (); + tpp->isRaw = 1; + memset (tpp->colorMatrix, 0, sizeof (tpp->colorMatrix)); + tpp->colorMatrix[0][0] = 1.0; + tpp->colorMatrix[1][1] = 1.0; + tpp->colorMatrix[2][2] = 1.0; + + if (inspectorMode && !forHistogramMatching && settings->thumbnail_inspector_mode == Settings::ThumbnailInspectorMode::RAW) { + Image8 *img = load_inspector_mode(fname, rml, sensorType, w, h); + if (!img) { + delete tpp; + return nullptr; + } + + tpp->scale = 1.; + tpp->thumbImg = img; + + return tpp; + } + RawImage *ri = new RawImage (fname); unsigned int imageNum = 0; int r = ri->loadRaw (false, imageNum, false); if ( r ) { + delete tpp; delete ri; sensorType = ST_NONE; return nullptr; @@ -301,24 +385,33 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL // did we succeed? if ( err ) { printf ("Could not extract thumb from %s\n", fname.data()); + delete tpp; delete img; delete ri; return nullptr; } - Thumbnail* tpp = new Thumbnail (); - - tpp->isRaw = 1; - memset (tpp->colorMatrix, 0, sizeof (tpp->colorMatrix)); - tpp->colorMatrix[0][0] = 1.0; - tpp->colorMatrix[1][1] = 1.0; - tpp->colorMatrix[2][2] = 1.0; - if (inspectorMode) { // Special case, meaning that we want a full sized thumbnail image (e.g. for the Inspector feature) w = img->getWidth(); h = img->getHeight(); tpp->scale = 1.; + + if (!forHistogramMatching && settings->thumbnail_inspector_mode == Settings::ThumbnailInspectorMode::RAW_IF_NOT_JPEG_FULLSIZE && float(std::max(w, h))/float(std::max(ri->get_width(), ri->get_height())) < 0.9f) { + delete img; + delete ri; + + img = load_inspector_mode(fname, rml, sensorType, w, h); + if (!img) { + delete tpp; + return nullptr; + } + + tpp->scale = 1.; + tpp->thumbImg = img; + + return tpp; + } } else { if (fixwh == 1) { w = h * img->getWidth() / img->getHeight(); diff --git a/rtengine/settings.h b/rtengine/settings.h index eebc2fb4b..74a855c3f 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -83,6 +83,13 @@ public: double level0_cbdl; double level123_cbdl; Glib::ustring lensfunDbDirectory; ///< The directory containing the lensfun database. If empty, the system defaults will be used (as described in http://lensfun.sourceforge.net/manual/dbsearch.html) + + enum class ThumbnailInspectorMode { + JPEG, + RAW, + RAW_IF_NOT_JPEG_FULLSIZE + }; + ThumbnailInspectorMode thumbnail_inspector_mode; /** Creates a new instance of Settings. * @return a pointer to the new Settings instance. */ diff --git a/rtgui/options.cc b/rtgui/options.cc index 485f9cc3b..dda61419f 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -592,6 +592,8 @@ void Options::setDefaults () rtSettings.lensfunDbDirectory = ""; // set also in main.cc and main-cli.cc cropGuides = CROP_GUIDE_FULL; cropAutoFit = false; + + rtSettings.thumbnail_inspector_mode = rtengine::Settings::ThumbnailInspectorMode::JPEG; } Options* Options::copyFrom (Options* other) @@ -1065,6 +1067,10 @@ void Options::readFromFile (Glib::ustring fname) if (keyFile.has_key ("Performance", "SerializeTiffRead")) { serializeTiffRead = keyFile.get_boolean ("Performance", "SerializeTiffRead"); } + + if (keyFile.has_key("Performance", "ThumbnailInspectorMode")) { + rtSettings.thumbnail_inspector_mode = static_cast(keyFile.get_integer("Performance", "ThumbnailInspectorMode")); + } } if (keyFile.has_group ("GUI")) { @@ -1844,6 +1850,7 @@ void Options::saveToFile (Glib::ustring fname) keyFile.set_integer ("Performance", "PreviewDemosaicFromSidecar", prevdemo); keyFile.set_boolean ("Performance", "Daubechies", rtSettings.daubech); keyFile.set_boolean ("Performance", "SerializeTiffRead", serializeTiffRead); + keyFile.set_integer("Performance", "ThumbnailInspectorMode", int(rtSettings.thumbnail_inspector_mode)); keyFile.set_string ("Output", "Format", saveFormat.format); keyFile.set_integer ("Output", "JpegQuality", saveFormat.jpegQuality); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 25855d588..63106fa0e 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -657,7 +657,19 @@ Gtk::Widget* Preferences::getPerformancePanel () maxInspectorBuffersSB->set_range (1, 12); // ... we have to set a limit, 12 seem to be enough even for systems with tons of RAM maxIBuffersHB->pack_start (*maxIBufferLbl, Gtk::PACK_SHRINK, 0); maxIBuffersHB->pack_end (*maxInspectorBuffersSB, Gtk::PACK_SHRINK, 0); - finspect->add (*maxIBuffersHB); + + Gtk::VBox *inspectorvb = Gtk::manage(new Gtk::VBox()); + inspectorvb->add(*maxIBuffersHB); + + Gtk::HBox *insphb = Gtk::manage(new Gtk::HBox()); + thumbnailInspectorMode = Gtk::manage(new Gtk::ComboBoxText()); + thumbnailInspectorMode->append(M("PREFERENCES_THUMBNAIL_INSPECTOR_JPEG")); + thumbnailInspectorMode->append(M("PREFERENCES_THUMBNAIL_INSPECTOR_RAW")); + thumbnailInspectorMode->append(M("PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE")); + insphb->pack_start(*Gtk::manage(new Gtk::Label(M("PREFERENCES_THUMBNAIL_INSPECTOR_MODE") + ": ")), Gtk::PACK_SHRINK, 4); + insphb->pack_start(*thumbnailInspectorMode); + inspectorvb->pack_start(*insphb); + finspect->add (*inspectorvb); mainContainer->pack_start (*finspect, Gtk::PACK_SHRINK, 4); Gtk::Frame* fdenoise = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_NOISE")) ); @@ -1853,6 +1865,7 @@ void Preferences::storePreferences () moptions.rgbDenoiseThreadLimit = rgbDenoiseTreadLimitSB->get_value_as_int(); moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); + moptions.rtSettings.thumbnail_inspector_mode = static_cast(thumbnailInspectorMode->get_active_row_number()); // Sounds only on Windows and Linux #if defined(WIN32) || defined(__linux__) @@ -2072,6 +2085,7 @@ void Preferences::fillPreferences () rgbDenoiseTreadLimitSB->set_value (moptions.rgbDenoiseThreadLimit); clutCacheSizeSB->set_value (moptions.clutCacheSize); maxInspectorBuffersSB->set_value (moptions.maxInspectorBuffers); + thumbnailInspectorMode->set_active(int(moptions.rtSettings.thumbnail_inspector_mode)); darkFrameDir->set_current_folder ( moptions.rtSettings.darkFramesPath ); darkFrameChanged (); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index cb0e6c709..ecf3638d9 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -166,6 +166,7 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener Gtk::SpinButton* rgbDenoiseTreadLimitSB; Gtk::SpinButton* clutCacheSizeSB; Gtk::SpinButton* maxInspectorBuffersSB; + Gtk::ComboBoxText *thumbnailInspectorMode; Gtk::CheckButton* ckbmenuGroupRank; Gtk::CheckButton* ckbmenuGroupLabel;