diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index c86a9c92c..4624aa08f 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 @@ -311,7 +311,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, St eSensorType sensor_type; double scale; int w = fw / skip, h = fh / skip; - const std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), sensor_type, w, h, 1, false, observer, false, true)); + const std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), 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 2319ddada..95fd77d21 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 e214bbfc7..ef8dc8dbf 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1037,7 +1037,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 a0472b1fd..2e02a352c 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, sensorType, w_raw, h_raw, 1, 1.0, ColorTemp::DEFAULT_OBSERVER, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, 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 e6f9da9d5..e65cadaa3 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 59dc14f86..e3f85615a 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) { @@ -519,7 +599,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, eSensorType #define FISGREEN(filter,row,col) \ ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1 || !filter) -Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching) +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, 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; @@ -562,8 +642,15 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, eSensorType &sens 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(); @@ -1434,6 +1521,50 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.softLight(labView, params.softlight); + if (params.icm.workingTRC != ColorManagementParams::WorkingTrc::NONE) { + const int GW = labView->W; + const int GH = labView->H; + std::unique_ptr provis; + const float pres = 0.01f * params.icm.preser; + if (pres > 0.f && params.icm.wprim != ColorManagementParams::Primaries::DEFAULT) { + provis.reset(new LabImage(GW, GH)); + provis->CopyFrom(labView); + } + + const std::unique_ptr tmpImage1(new Imagefloat(GW, GH)); + + ipf.lab2rgb(*labView, *tmpImage1, params.icm.workingProfile); + + const float gamtone = params.icm.workingTRCGamma; + const float slotone = params.icm.workingTRCSlope; + + int illum = toUnderlying(params.icm.will); + const int prim = toUnderlying(params.icm.wprim); + + Glib::ustring prof = params.icm.workingProfile; + + cmsHTRANSFORM dummy = nullptr; + int ill = 0; + ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); + ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, illum, prim, dummy, false, true, true); + + ipf.rgb2lab(*tmpImage1, *labView, params.icm.workingProfile); + // labView and provis + if(provis) { + ipf.preserv(labView, provis.get(), GW, GH); + } + if(params.icm.fbw) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int x = 0; x < GH; x++) + for (int y = 0; y < GW; y++) { + labView->a[x][y] = 0.f; + labView->b[x][y] = 0.f; + } + } + + } if (params.colorappearance.enabled) { CurveFactory::curveLightBrightColor ( diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 7a2b5815b..d9a637e2d 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -99,7 +99,7 @@ public: void getDimensions (int& w, int& h, double& scaleFac); static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching=false); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, 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); void getCamWB (double& temp, double& green, StandardObserver observer); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 229aee2a8..2484eb554 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -782,7 +782,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 0f78f7ead..81efccccd 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1995,7 +1995,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 b895585ad..0c6d15e37 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -119,7 +119,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 7df29dd92..6a4bd38b4 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -89,14 +89,19 @@ void FileBrowserEntry::init () ps = RTImage::createPixbufFromFile ("filetype-ps.png"); } -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 () @@ -108,7 +113,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 () @@ -202,13 +207,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 f8fca4db1..c560efc16 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -68,6 +68,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 d196fdca5..2570e20c5 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 8a24dc340..266dbacd3 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -240,7 +240,7 @@ void Thumbnail::_generateThumbnailImage () if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, sensorType, tw, th, 1, pparams->wb.equal, pparams->wb.observer, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, sensorType, tw, th, 1, pparams->wb.equal, pparams->wb.observer, TRUE, &(pparams->raw)); } cfs.sensortype = sensorType; @@ -387,7 +387,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); } } @@ -490,7 +490,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); } } @@ -502,8 +502,18 @@ 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->raw.expos != pp.raw.expos || pparams->toneCurve != pp.toneCurve || pparams->locallab != pp.locallab || pparams->labCurve != pp.labCurve @@ -538,6 +548,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); @@ -573,7 +584,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); } } } @@ -747,12 +758,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 9ead1e5e8..82c4f4738 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -124,7 +124,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; };