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.
This commit is contained in:
Lawrence Lee 2023-07-29 17:37:13 -07:00
parent b68a6e9581
commit 6787c53c9b
No known key found for this signature in database
GPG Key ID: 048FF2B76A63895F
19 changed files with 141 additions and 34 deletions

View File

@ -229,7 +229,7 @@ void mappingToCurve(const std::vector<int> &mapping, std::vector<double> &curve)
} // namespace } // namespace
void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, StandardObserver observer, std::vector<double> &outCurve) void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector<double> &outCurve)
{ {
BENCHFUN BENCHFUN
@ -313,7 +313,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, St
eSensorType sensor_type; eSensorType sensor_type;
double scale; double scale;
int w = fw / skip, h = fh / skip; int w = fw / skip, h = fh / skip;
std::unique_ptr<Thumbnail> thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, observer, false, true)); std::unique_ptr<Thumbnail> thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, observer, false, &rawParams, true));
if (!thumb) { if (!thumb) {
if (settings->verbose) { if (settings->verbose) {
std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl;

View File

@ -167,7 +167,7 @@ public:
} }
// for RAW files, compute a tone curve using histogram matching on the embedded thumbnail // 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<double> &outCurve) virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector<double> &outCurve)
{ {
outCurve = { 0.0 }; outCurve = { 0.0 };
} }

View File

@ -793,7 +793,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
if (params->toneCurve.histmatching) { if (params->toneCurve.histmatching) {
if (!params->toneCurve.fromHistMatching) { 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) { if (params->toneCurve.autoexp) {

View File

@ -5645,7 +5645,7 @@ double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size
return 0.0; 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) { if (!raw) {
delete thumb; delete thumb;

View File

@ -186,7 +186,7 @@ public:
} }
void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getAutoExpHistogram (LUTu & histogram, int& histcompr) override;
void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override;
void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector<double> &outCurve) override; void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector<double> &outCurve) override;
DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override; DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override;
void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override;

View File

@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>. * along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <array>
#include <clocale> #include <clocale>
#include <lcms2.h> #include <lcms2.h>
@ -65,6 +67,84 @@ bool checkRawImageThumb (const rtengine::RawImage& raw_image)
return raw_image.get_thumbOffset() + length <= raw_image.get_file()->size; 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<float, 4> 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<float>(rawParams->bayersensor.black1); // R
black_adjust[1] = static_cast<float>(rawParams->bayersensor.black0); // G1
black_adjust[2] = static_cast<float>(rawParams->bayersensor.black2); // B
black_adjust[3] = static_cast<float>(rawParams->bayersensor.black3); // G2
break;
case rtengine::eSensorType::ST_FUJI_XTRANS:
black_adjust[0] = static_cast<float>(rawParams->xtranssensor.blackred);
black_adjust[1] = static_cast<float>(rawParams->xtranssensor.blackgreen);
black_adjust[2] = static_cast<float>(rawParams->xtranssensor.blackblue);
black_adjust[3] = static_cast<float>(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<float, 4> c_white;
for (int i = 0; i < c_white.size(); ++i) {
c_white[i] = static_cast<float>(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<float, 4> 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) 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; 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); RawImage *ri = new RawImage (fname);
unsigned int tempImageNum = 0; unsigned int tempImageNum = 0;
@ -587,8 +667,15 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati
tpp->greenMultiplier = ri->get_pre_mul (1); tpp->greenMultiplier = ri->get_pre_mul (1);
tpp->blueMultiplier = ri->get_pre_mul (2); 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]; float pre_mul[4], scale_mul[4], cblack[4];
ri->get_colorsCoeff (pre_mul, scale_mul, cblack, false); 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 scale_colors (ri, scale_mul, cblack, forHistogramMatching); // enable multithreading when forHistogramMatching is true
ri->pre_interpolate(); ri->pre_interpolate();

View File

@ -98,7 +98,7 @@ public:
void getDimensions (int& w, int& h, double& scaleFac); 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* 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 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); static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname);

View File

@ -781,7 +781,7 @@ private:
if (params.toneCurve.histmatching) { if (params.toneCurve.histmatching) {
if (!params.toneCurve.fromHistMatching) { 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) { if (params.toneCurve.autoexp) {

View File

@ -615,7 +615,7 @@ void BatchToolPanelCoordinator::optionsChanged ()
initSession (); initSession ();
} }
void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint)
{ {
if (whoChangedIt != BATCHEDITOR && !blockedUpdate) { if (whoChangedIt != BATCHEDITOR && !blockedUpdate) {

View File

@ -73,7 +73,7 @@ public:
void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override; void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override;
// thumbnaillistener interface // thumbnaillistener interface
void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; void procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) override;
// batchpparamschangelistener interface // batchpparamschangelistener interface
void beginBatchPParamsChange(int numberOfEntries) override; void beginBatchPParamsChange(int numberOfEntries) override;

View File

@ -1987,7 +1987,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event)
return false; return false;
} }
void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint)
{ {
if (whoChangedIt != EDITOR) { if (whoChangedIt != EDITOR) {

View File

@ -118,7 +118,7 @@ public:
void clearParamChanges() override; void clearParamChanges() override;
// thumbnaillistener interface // thumbnaillistener interface
void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; void procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) override;
// HistoryBeforeLineListener // HistoryBeforeLineListener
void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) override; void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) override;

View File

@ -90,14 +90,19 @@ FileBrowserEntry::~FileBrowserEntry ()
} }
} }
void FileBrowserEntry::refreshThumbnailImage () void FileBrowserEntry::refreshThumbnailImage(bool upgradeHint)
{ {
if (!thumbnail) { if (!thumbnail) {
return; return;
} }
thumbImageUpdater->add (this, &updatepriority, false, this); thumbImageUpdater->add (this, &updatepriority, upgradeHint, upgradeHint, this);
}
void FileBrowserEntry::refreshThumbnailImage ()
{
refreshThumbnailImage(false);
} }
void FileBrowserEntry::refreshQuickThumbnailImage () void FileBrowserEntry::refreshQuickThumbnailImage ()
@ -109,7 +114,7 @@ void FileBrowserEntry::refreshQuickThumbnailImage ()
// Only make a (slow) processed preview if the picture has been edited at all // Only make a (slow) processed preview if the picture has been edited at all
bool upgrade_to_processed = (!options.internalThumbIfUntouched || thumbnail->isPParamsValid()); 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 () void FileBrowserEntry::calcThumbnailSize ()
@ -203,13 +208,13 @@ FileThumbnailButtonSet* FileBrowserEntry::getThumbButtonSet ()
return (static_cast<FileThumbnailButtonSet*>(buttonSet)); return (static_cast<FileThumbnailButtonSet*>(buttonSet));
} }
void FileBrowserEntry::procParamsChanged (Thumbnail* thm, int whoChangedIt) void FileBrowserEntry::procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint)
{ {
if ( thumbnail->isQuick() ) { if ( thumbnail->isQuick() ) {
refreshQuickThumbnailImage (); refreshQuickThumbnailImage ();
} else { } else {
refreshThumbnailImage (); refreshThumbnailImage(upgradeHint);
} }
} }

View File

@ -69,6 +69,7 @@ class FileBrowserEntry final : public ThumbBrowserEntryBase,
void updateCursor (int x, int y); void updateCursor (int x, int y);
void drawStraightenGuide (Cairo::RefPtr<Cairo::Context> c); void drawStraightenGuide (Cairo::RefPtr<Cairo::Context> c);
void customBackBufferUpdate (Cairo::RefPtr<Cairo::Context> c) override; void customBackBufferUpdate (Cairo::RefPtr<Cairo::Context> c) override;
void refreshThumbnailImage(bool upgradeHint);
public: public:
@ -98,7 +99,7 @@ public:
void getIconSize (int& w, int& h) const override; void getIconSize (int& w, int& h) const override;
// thumbnaillistener interface // thumbnaillistener interface
void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; void procParamsChanged (Thumbnail* thm, int whoChangedIt, bool upgradeHint) override;
// thumbimageupdatelistener interface // 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) override;
void _updateImage(rtengine::IImage8* img, double scale, const rtengine::procparams::CropParams& cropParams); // inside gtk thread void _updateImage(rtengine::IImage8* img, double scale, const rtengine::procparams::CropParams& cropParams); // inside gtk thread

View File

@ -45,12 +45,13 @@ public:
struct Job { struct Job {
Job(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, Job(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade,
ThumbImageUpdateListener* listener): bool forceUpgrade, ThumbImageUpdateListener* listener):
tbe_(tbe), tbe_(tbe),
/*pparams_(pparams), /*pparams_(pparams),
height_(height), */ height_(height), */
priority_(priority), priority_(priority),
upgrade_(upgrade), upgrade_(upgrade),
force_upgrade_(forceUpgrade),
listener_(listener) listener_(listener)
{} {}
@ -58,6 +59,7 @@ public:
tbe_(nullptr), tbe_(nullptr),
priority_(nullptr), priority_(nullptr),
upgrade_(false), upgrade_(false),
force_upgrade_(false),
listener_(nullptr) listener_(nullptr)
{} {}
@ -66,6 +68,7 @@ public:
int height_;*/ int height_;*/
bool* priority_; bool* priority_;
bool upgrade_; bool upgrade_;
bool force_upgrade_;
ThumbImageUpdateListener* listener_; ThumbImageUpdateListener* listener_;
}; };
@ -153,8 +156,8 @@ public:
Thumbnail* thm = j.tbe_->thumbnail; Thumbnail* thm = j.tbe_->thumbnail;
if ( j.upgrade_ ) { if ( j.upgrade_ ) {
if ( thm->isQuick() ) { if ( thm->isQuick() || j.force_upgrade_ ) {
img = thm->upgradeThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale); img = thm->upgradeThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale, j.force_upgrade_);
} }
} else { } else {
img = thm->processThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale); img = thm->processThumbImage(thm->getProcParams(), j.tbe_->getPreviewHeight(), scale);
@ -191,7 +194,7 @@ ThumbImageUpdater::~ThumbImageUpdater() {
delete impl_; 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? // nobody listening?
if ( l == nullptr ) { if ( l == nullptr ) {
@ -206,7 +209,8 @@ void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upg
for ( ; i != impl_->jobs_.end(); ++i ) { for ( ; i != impl_->jobs_.end(); ++i ) {
if ( i->tbe_ == tbe && if ( i->tbe_ == tbe &&
i->listener_ == l && i->listener_ == l &&
i->upgrade_ == upgrade ) { i->upgrade_ == upgrade &&
i->force_upgrade_ == forceUpgrade) {
DEBUG("updating job %s", tbe->shortname.c_str()); DEBUG("updating job %s", tbe->shortname.c_str());
// we have one, update queue entry, will be picked up by thread when processed // we have one, update queue entry, will be picked up by thread when processed
/*i->pparams_ = params; /*i->pparams_ = params;
@ -218,7 +222,7 @@ void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upg
// create a new job and append to queue // create a new job and append to queue
DEBUG("queueing job %s", tbe->shortname.c_str()); 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()); DEBUG("adding run request %s", tbe->shortname.c_str());
impl_->threadPool_->push(sigc::mem_fun(*impl_, &ThumbImageUpdater::Impl::processNextJob)); impl_->threadPool_->push(sigc::mem_fun(*impl_, &ThumbImageUpdater::Impl::processNextJob));

View File

@ -78,7 +78,7 @@ public:
* @param priority if \c true then run as soon as possible * @param priority if \c true then run as soon as possible
* @param l listener waiting on update * @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. * @brief Remove jobs associated with listener \c l.

View File

@ -173,7 +173,7 @@ void Thumbnail::_generateThumbnailImage ()
if ( tpp == nullptr ) { if ( tpp == nullptr ) {
quick = false; 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; cfs.sensortype = sensorType;
@ -334,7 +334,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu
void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt) void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt)
{ {
for (size_t i = 0; i < listeners.size(); i++) { 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 } // end of mutex lock
for (size_t i = 0; i < listeners.size(); i++) { 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) 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 = const bool needsReprocessing =
resetToDefault resetToDefault
|| blackLevelChanged
|| pparams->toneCurve != pp.toneCurve || pparams->toneCurve != pp.toneCurve
|| pparams->locallab != pp.locallab || pparams->locallab != pp.locallab
|| pparams->labCurve != pp.labCurve || pparams->labCurve != pp.labCurve
@ -485,6 +494,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh
|| pparams->filmNegative != pp.filmNegative || pparams->filmNegative != pp.filmNegative
|| whoChangedIt == FILEBROWSER || whoChangedIt == FILEBROWSER
|| whoChangedIt == BATCHEDITOR; || whoChangedIt == BATCHEDITOR;
const bool upgradeHint = blackLevelChanged;
{ {
MyMutex::MyLock lock(mutex); MyMutex::MyLock lock(mutex);
@ -520,7 +530,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh
if (needsReprocessing) { if (needsReprocessing) {
for (size_t i = 0; i < listeners.size(); i++) { 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; 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); MyMutex::MyLock lock(mutex);
if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL ) { if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL && !forceUpgrade ) {
return nullptr; return nullptr;
} }

View File

@ -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 // 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* 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 getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams = nullptr);
void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h);
void getOriginalSize (int& w, int& h) const; void getOriginalSize (int& w, int& h) const;

View File

@ -24,5 +24,5 @@ class ThumbnailListener
{ {
public: public:
virtual ~ThumbnailListener() = default; virtual ~ThumbnailListener() = default;
virtual void procParamsChanged(Thumbnail* thm, int whoChangedIt) = 0; virtual void procParamsChanged(Thumbnail* thm, int whoChangedIt, bool upgradeHint) = 0;
}; };