Merge pull request #6806 from Lawrence37/browser-preview-applied-pparams

Enable black level and abstract profile preview in file browser
This commit is contained in:
Lawrence37 2023-09-03 15:15:25 -07:00 committed by GitHub
commit ec12c170a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 186 additions and 34 deletions

View File

@ -229,7 +229,7 @@ void mappingToCurve(const std::vector<int> &mapping, std::vector<double> &curve)
} // 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
@ -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<Thumbnail> thumb(Thumbnail::loadFromRaw(getFileName(), sensor_type, w, h, 1, false, observer, false, true));
const std::unique_ptr<Thumbnail> 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;

View File

@ -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<double> &outCurve)
virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, const procparams::RAWParams &rawParams, StandardObserver observer, std::vector<double> &outCurve)
{
outCurve = { 0.0 };
}

View File

@ -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) {

View File

@ -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;

View File

@ -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<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;
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
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <array>
#include <clocale>
#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;
}
/**
* 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)
{
@ -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<LabImage> 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<Imagefloat> 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 (

View File

@ -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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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<FileThumbnailButtonSet*>(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);
}
}

View File

@ -68,6 +68,7 @@ class FileBrowserEntry final : public ThumbBrowserEntryBase,
void updateCursor (int x, int y);
void drawStraightenGuide (Cairo::RefPtr<Cairo::Context> c);
void customBackBufferUpdate (Cairo::RefPtr<Cairo::Context> 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

View File

@ -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));

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
};