From 6787c53c9be6f17109653b25939f4ee08f0b0cd9 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 29 Jul 2023 17:37:13 -0700 Subject: [PATCH] Show black level adjustments in file browser File browser thumbnails for raw images start with a minimally-processed images. These images are cached and image adjustments are applied on top. The black level is "baked-into" the cached image. Therefore, to reflect the black level adjustments in the thumbnail, one of two options are required: 1. Cache an image before the black level is applied and process the black level on top of this image. 2. Recreate the base image with the new black level and cache it. The first option yields better performance when the user changes the black level. However, it requires other base adjustments to be applied every time, such as the camera multipliers. The second option requires the base image to be recreated every time the black level is changed. This commit implements the second option. It minimizes code changes, and therefore possible bugs. It does add a performance penalty when the black level changes, but the black level adjustment is rarely used. --- rtengine/histmatching.cc | 4 +- rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 2 +- rtengine/improcfun.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/rtthumbnail.cc | 89 ++++++++++++++++++++++++++++++++++- rtengine/rtthumbnail.h | 2 +- rtengine/simpleprocess.cc | 2 +- rtgui/batchtoolpanelcoord.cc | 2 +- rtgui/batchtoolpanelcoord.h | 2 +- rtgui/editorpanel.cc | 2 +- rtgui/editorpanel.h | 2 +- rtgui/filebrowserentry.cc | 15 ++++-- rtgui/filebrowserentry.h | 3 +- rtgui/thumbimageupdater.cc | 16 ++++--- rtgui/thumbimageupdater.h | 2 +- rtgui/thumbnail.cc | 22 ++++++--- rtgui/thumbnail.h | 2 +- rtgui/thumbnaillistener.h | 2 +- 19 files changed, 141 insertions(+), 34 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 350dbbfab..7928c04b4 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -229,7 +229,7 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) } // namespace -void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) +void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector &outCurve) { BENCHFUN @@ -313,7 +313,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, St eSensorType sensor_type; double scale; int w = fw / skip, h = fh / skip; - std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, observer, false, true)); + std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, observer, false, &rawParams, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 1f4c2179a..ebd030b33 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -167,7 +167,7 @@ public: } // for RAW files, compute a tone curve using histogram matching on the embedded thumbnail - virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) + virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector &outCurve) { outCurve = { 0.0 }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 6e3ebc48c..1104b8baa 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -793,7 +793,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (params->toneCurve.histmatching) { if (!params->toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params->icm, params->wb.observer, params->toneCurve.curve); + imgsrc->getAutoMatchedToneCurve(params->icm, params->raw, params->wb.observer, params->toneCurve.curve); } if (params->toneCurve.autoexp) { diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 8a0e699d6..54c100c10 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5645,7 +5645,7 @@ double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size return 0.0; } - Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, ColorTemp::DEFAULT_OBSERVER, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, ColorTemp::DEFAULT_OBSERVER, FALSE, nullptr); if (!raw) { delete thumb; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index b19c6f5c0..bbaed8495 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -186,7 +186,7 @@ public: } void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; - void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) override; + void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector &outCurve) override; DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override; void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 11dae8018..6379fa52c 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include +#include #include #include @@ -65,6 +67,84 @@ bool checkRawImageThumb (const rtengine::RawImage& raw_image) return raw_image.get_thumbOffset() + length <= raw_image.get_file()->size; } +/** + * Apply the black level adjustments in the processing parameters. + * + * @param cblack The original black levels that will be modified. + * @param sensorType Sensor type. + * @param rawParams Subset of processing parameters for raw data. + */ +void adjustBlackLevels(float cblack[4], rtengine::eSensorType sensorType, const rtengine::RAWParams *rawParams) +{ + if (!rawParams) { + return; + } + + std::array black_adjust{0.f, 0.f, 0.f, 0.f}; + + switch (sensorType) { + case rtengine::eSensorType::ST_BAYER: + case rtengine::eSensorType::ST_FOVEON: + black_adjust[0] = static_cast(rawParams->bayersensor.black1); // R + black_adjust[1] = static_cast(rawParams->bayersensor.black0); // G1 + black_adjust[2] = static_cast(rawParams->bayersensor.black2); // B + black_adjust[3] = static_cast(rawParams->bayersensor.black3); // G2 + break; + case rtengine::eSensorType::ST_FUJI_XTRANS: + black_adjust[0] = static_cast(rawParams->xtranssensor.blackred); + black_adjust[1] = static_cast(rawParams->xtranssensor.blackgreen); + black_adjust[2] = static_cast(rawParams->xtranssensor.blackblue); + black_adjust[3] = static_cast(rawParams->xtranssensor.blackgreen); + break; + case rtengine::eSensorType::ST_NONE: + break; + } + + for (int i = 0; i < black_adjust.size(); i++) { + cblack[i] = std::max(0.f, cblack[i] + black_adjust[i]); + } +} + +/** + * Calculate the new scale multipliers based on new black levels. + * + * @param scale_mul The original scale multipliers to be adjusted. + * @param pre_mul Pre-multipliers. + * @param c_black Updated black levels. + * @param isMono Is the image using mono demosaicing? + * @param ri Pointer to the raw image. + */ +void calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const float c_black[4], bool isMono, const rtengine::RawImage *ri) +{ + std::array c_white; + + for (int i = 0; i < c_white.size(); ++i) { + c_white[i] = static_cast(ri->get_white(i)); + } + + if (isMono || ri->get_colors() == 1) { + for (int c = 0; c < 4; c++) { + scale_mul[c] = 65535.f / (c_white[c] - c_black[c]); + } + } else { + std::array pre_mul; + + for (int c = 0; c < 4; c++) { + pre_mul[c] = pre_mul_[c]; + } + + if (pre_mul[3] == 0) { + pre_mul[3] = pre_mul[1]; // G2 == G1 + } + + float maxpremul = std::max(std::max(std::max(pre_mul[0], pre_mul[1]), pre_mul[2]), pre_mul[3]); + + for (int c = 0; c < 4; c++) { + scale_mul[c] = (pre_mul[c] / maxpremul) * 65535.f / (c_white[c] - c_black[c]); + } + } +} + void scale_colors (rtengine::RawImage *ri, float scale_mul[4], float cblack[4], bool multiThread) { @@ -544,7 +624,7 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) return rml; } -Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching) +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, const RAWParams *rawParams, bool forHistogramMatching) { RawImage *ri = new RawImage (fname); unsigned int tempImageNum = 0; @@ -587,8 +667,15 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati tpp->greenMultiplier = ri->get_pre_mul (1); tpp->blueMultiplier = ri->get_pre_mul (2); + bool isMono = + (ri->getSensorType() == ST_FUJI_XTRANS && + rawParams->xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO)) || + (ri->getSensorType() == ST_BAYER && + rawParams->bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)); float pre_mul[4], scale_mul[4], cblack[4]; ri->get_colorsCoeff (pre_mul, scale_mul, cblack, false); + adjustBlackLevels(cblack, sensorType, rawParams); + calculate_scale_mul(scale_mul, pre_mul, cblack, isMono, ri); scale_colors (ri, scale_mul, cblack, forHistogramMatching); // enable multithreading when forHistogramMatching is true ri->pre_interpolate(); diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 535613ca2..583fecb0b 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -98,7 +98,7 @@ public: void getDimensions (int& w, int& h, double& scaleFac); static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching = false); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, const RAWParams *rawParams, bool forHistogramMatching = false); static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool inspectorMode = false); static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 96cd68d43..71d9f3bad 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -781,7 +781,7 @@ private: if (params.toneCurve.histmatching) { if (!params.toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params.icm, params.wb.observer, params.toneCurve.curve); + imgsrc->getAutoMatchedToneCurve(params.icm, params.raw, params.wb.observer, params.toneCurve.curve); } if (params.toneCurve.autoexp) { diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 4383ccb74..83d541334 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -615,7 +615,7 @@ void BatchToolPanelCoordinator::optionsChanged () initSession (); } -void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) +void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) { if (whoChangedIt != BATCHEDITOR && !blockedUpdate) { diff --git a/rtgui/batchtoolpanelcoord.h b/rtgui/batchtoolpanelcoord.h index f421793ac..687aa98bd 100644 --- a/rtgui/batchtoolpanelcoord.h +++ b/rtgui/batchtoolpanelcoord.h @@ -73,7 +73,7 @@ public: void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override; // thumbnaillistener interface - void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; + void procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) override; // batchpparamschangelistener interface void beginBatchPParamsChange(int numberOfEntries) override; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 420717b7e..d58bdf2ee 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1987,7 +1987,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) return false; } -void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) +void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) { if (whoChangedIt != EDITOR) { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 309f14e8c..0448931a8 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -118,7 +118,7 @@ public: void clearParamChanges() override; // thumbnaillistener interface - void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; + void procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) override; // HistoryBeforeLineListener void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) override; diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index b89fe340d..670584474 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -90,14 +90,19 @@ FileBrowserEntry::~FileBrowserEntry () } } -void FileBrowserEntry::refreshThumbnailImage () +void FileBrowserEntry::refreshThumbnailImage(bool upgradeHint) { if (!thumbnail) { return; } - thumbImageUpdater->add (this, &updatepriority, false, this); + thumbImageUpdater->add (this, &updatepriority, upgradeHint, upgradeHint, this); +} + +void FileBrowserEntry::refreshThumbnailImage () +{ + refreshThumbnailImage(false); } void FileBrowserEntry::refreshQuickThumbnailImage () @@ -109,7 +114,7 @@ void FileBrowserEntry::refreshQuickThumbnailImage () // Only make a (slow) processed preview if the picture has been edited at all bool upgrade_to_processed = (!options.internalThumbIfUntouched || thumbnail->isPParamsValid()); - thumbImageUpdater->add(this, &updatepriority, upgrade_to_processed, this); + thumbImageUpdater->add(this, &updatepriority, upgrade_to_processed, false, this); } void FileBrowserEntry::calcThumbnailSize () @@ -203,13 +208,13 @@ FileThumbnailButtonSet* FileBrowserEntry::getThumbButtonSet () return (static_cast(buttonSet)); } -void FileBrowserEntry::procParamsChanged (Thumbnail* thm, int whoChangedIt) +void FileBrowserEntry::procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) { if ( thumbnail->isQuick() ) { refreshQuickThumbnailImage (); } else { - refreshThumbnailImage (); + refreshThumbnailImage(upgradeHint); } } diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h index 67b953514..e0418b208 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -69,6 +69,7 @@ class FileBrowserEntry final : public ThumbBrowserEntryBase, void updateCursor (int x, int y); void drawStraightenGuide (Cairo::RefPtr c); void customBackBufferUpdate (Cairo::RefPtr c) override; + void refreshThumbnailImage(bool upgradeHint); public: @@ -98,7 +99,7 @@ public: void getIconSize (int& w, int& h) const override; // thumbnaillistener interface - void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; + void procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) override; // thumbimageupdatelistener interface void updateImage(rtengine::IImage8* img, double scale, const rtengine::procparams::CropParams& cropParams) override; void _updateImage(rtengine::IImage8* img, double scale, const rtengine::procparams::CropParams& cropParams); // inside gtk thread diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index 540ad625e..f26ecfe6d 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -45,12 +45,13 @@ public: struct Job { Job(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, - ThumbImageUpdateListener* listener): + bool forceUpgrade, ThumbImageUpdateListener* listener): tbe_(tbe), /*pparams_(pparams), height_(height), */ priority_(priority), upgrade_(upgrade), + force_upgrade_(forceUpgrade), listener_(listener) {} @@ -58,6 +59,7 @@ public: tbe_(nullptr), priority_(nullptr), upgrade_(false), + force_upgrade_(false), listener_(nullptr) {} @@ -66,6 +68,7 @@ public: int height_;*/ bool* priority_; bool upgrade_; + bool force_upgrade_; ThumbImageUpdateListener* listener_; }; @@ -153,8 +156,8 @@ public: Thumbnail* thm = j.tbe_->thumbnail; if ( j.upgrade_ ) { - if ( thm->isQuick() ) { - img = thm->upgradeThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale); + if ( thm->isQuick() || j.force_upgrade_ ) { + img = thm->upgradeThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale, j.force_upgrade_); } } else { img = thm->processThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale); @@ -191,7 +194,7 @@ ThumbImageUpdater::~ThumbImageUpdater() { delete impl_; } -void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, ThumbImageUpdateListener* l) +void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, bool forceUpgrade, ThumbImageUpdateListener* l) { // nobody listening? if ( l == nullptr ) { @@ -206,7 +209,8 @@ void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upg for ( ; i != impl_->jobs_.end(); ++i ) { if ( i->tbe_ == tbe && i->listener_ == l && - i->upgrade_ == upgrade ) { + i->upgrade_ == upgrade && + i->force_upgrade_ == forceUpgrade) { DEBUG("updating job %s", tbe->shortname.c_str()); // we have one, update queue entry, will be picked up by thread when processed /*i->pparams_ = params; @@ -218,7 +222,7 @@ void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upg // create a new job and append to queue DEBUG("queueing job %s", tbe->shortname.c_str()); - impl_->jobs_.push_back(Impl::Job(tbe, priority, upgrade, l)); + impl_->jobs_.push_back(Impl::Job(tbe, priority, upgrade, forceUpgrade, l)); DEBUG("adding run request %s", tbe->shortname.c_str()); impl_->threadPool_->push(sigc::mem_fun(*impl_, &ThumbImageUpdater::Impl::processNextJob)); diff --git a/rtgui/thumbimageupdater.h b/rtgui/thumbimageupdater.h index a2e2ecb19..4c890ee9b 100644 --- a/rtgui/thumbimageupdater.h +++ b/rtgui/thumbimageupdater.h @@ -78,7 +78,7 @@ public: * @param priority if \c true then run as soon as possible * @param l listener waiting on update */ - void add(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, ThumbImageUpdateListener* l); + void add(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, bool forceUpgrade, ThumbImageUpdateListener* l); /** * @brief Remove jobs associated with listener \c l. diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 96a8bf849..c18b0e91f 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -173,7 +173,7 @@ void Thumbnail::_generateThumbnailImage () if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, pparams->wb.observer, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, pparams->wb.observer, TRUE, &(pparams->raw)); } cfs.sensortype = sensorType; @@ -334,7 +334,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt) { for (size_t i = 0; i < listeners.size(); i++) { - listeners[i]->procParamsChanged (this, whoChangedIt); + listeners[i]->procParamsChanged (this, whoChangedIt, false); } } @@ -437,7 +437,7 @@ void Thumbnail::clearProcParams (int whoClearedIt) } // end of mutex lock for (size_t i = 0; i < listeners.size(); i++) { - listeners[i]->procParamsChanged (this, whoClearedIt); + listeners[i]->procParamsChanged (this, whoClearedIt, false); } } @@ -449,8 +449,17 @@ bool Thumbnail::hasProcParams () const void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoChangedIt, bool updateCacheNow, bool resetToDefault) { + const bool blackLevelChanged = + pparams->raw.bayersensor.black0 != pp.raw.bayersensor.black0 + || pparams->raw.bayersensor.black1 != pp.raw.bayersensor.black1 + || pparams->raw.bayersensor.black2 != pp.raw.bayersensor.black2 + || pparams->raw.bayersensor.black3 != pp.raw.bayersensor.black3 + || pparams->raw.xtranssensor.blackred != pp.raw.xtranssensor.blackred + || pparams->raw.xtranssensor.blackgreen != pp.raw.xtranssensor.blackgreen + || pparams->raw.xtranssensor.blackblue != pp.raw.xtranssensor.blackblue; const bool needsReprocessing = resetToDefault + || blackLevelChanged || pparams->toneCurve != pp.toneCurve || pparams->locallab != pp.locallab || pparams->labCurve != pp.labCurve @@ -485,6 +494,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh || pparams->filmNegative != pp.filmNegative || whoChangedIt == FILEBROWSER || whoChangedIt == BATCHEDITOR; + const bool upgradeHint = blackLevelChanged; { MyMutex::MyLock lock(mutex); @@ -520,7 +530,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh if (needsReprocessing) { for (size_t i = 0; i < listeners.size(); i++) { - listeners[i]->procParamsChanged (this, whoChangedIt); + listeners[i]->procParamsChanged (this, whoChangedIt, upgradeHint); } } } @@ -694,12 +704,12 @@ rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::Pro return image; } -rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) +rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale, bool forceUpgrade) { MyMutex::MyLock lock(mutex); - if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL ) { + if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL && !forceUpgrade ) { return nullptr; } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 4d0355747..3b1458dea 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -119,7 +119,7 @@ public: // unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w rtengine::IImage8* processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); - rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); + rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale, bool forceUpgrade); void getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams = nullptr); void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); void getOriginalSize (int& w, int& h) const; diff --git a/rtgui/thumbnaillistener.h b/rtgui/thumbnaillistener.h index 18ac99dce..fb9f8c1df 100644 --- a/rtgui/thumbnaillistener.h +++ b/rtgui/thumbnaillistener.h @@ -24,5 +24,5 @@ class ThumbnailListener { public: virtual ~ThumbnailListener() = default; - virtual void procParamsChanged(Thumbnail* thm, int whoChangedIt) = 0; + virtual void procParamsChanged(Thumbnail* thm, int whoChangedIt, bool upgradeHint) = 0; };