From 095cb010e52dabdfd751e2ea1e400fe54b7e8cfe Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 27 Sep 2018 18:16:29 +0200 Subject: [PATCH] reduce updates to preview, panning background, navigator and thumbs, fixes #4834 --- rtengine/improccoordinator.cc | 1431 ++++++++++++++++----------------- rtengine/improccoordinator.h | 2 +- rtengine/procparams.cc | 71 +- rtengine/procparams.h | 3 + rtgui/thumbnail.cc | 50 +- rtgui/thumbnail.h | 31 +- 6 files changed, 824 insertions(+), 764 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 298c3fc58..52a1d10bc 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -140,809 +140,805 @@ DetailedCrop* ImProcCoordinator::createCrop(::EditDataProvider *editDataProvider // todo: bitmask containing desired actions, taken from changesSinceLast -// cropCall: calling crop, used to prevent self-updates ...doesn't seem to be used -void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall) +void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) { MyMutex::MyLock processingLock(mProcessing); - int numofphases = 14; + + constexpr int numofphases = 14; int readyphase = 0; - bwAutoR = bwAutoG = bwAutoB = -9000.f; - - if (todo == CROP && ipf.needsPCVignetting()) { - todo |= TRANSFORM; // Change about Crop does affect TRANSFORM - } - - bool highDetailNeeded = false; - - if (options.prevdemo == PD_Sidecar) { - highDetailNeeded = true; //i#2664 - } else { - highDetailNeeded = (todo & M_HIGHQUAL); - } + bool highDetailNeeded = options.prevdemo == PD_Sidecar ? true : (todo & M_HIGHQUAL); // Check if any detail crops need high detail. If not, take a fast path short cut if (!highDetailNeeded) { - for (size_t i = 0; i < crops.size(); i++) + for (size_t i = 0; i < crops.size(); i++) { if (crops[i]->get_skip() == 1) { // skip=1 -> full resolution highDetailNeeded = true; break; } - } - - RAWParams rp = params.raw; - ColorManagementParams cmp = params.icm; - LCurveParams lcur = params.labCurve; - - if (!highDetailNeeded) { - // if below 100% magnification, take a fast path - if (rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE) && rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE)) { - rp.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); - } - - //bayerrp.all_enhance = false; - - if (rp.xtranssensor.method != RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::NONE) && rp.xtranssensor.method != RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::NONE)) { - rp.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); - } - - rp.bayersensor.ccSteps = 0; - rp.xtranssensor.ccSteps = 0; - //rp.deadPixelFilter = rp.hotPixelFilter = false; - } - - progress("Applying white balance, color correction & sRGB conversion...", 100 * readyphase / numofphases); - - if (frameCountListener) { - frameCountListener->FrameCountChanged(imgsrc->getFrameCount(), params.raw.bayersensor.imageNum); - } - - // raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed - if ((todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) { - imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); - - imgsrc->preprocess(rp, params.lensProf, params.coarse); - imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); - - highDetailPreprocessComputed = highDetailNeeded; - } - - /* - Demosaic is kicked off only when - Detail considerations: - accurate detail is not displayed yet needed based on preview specifics (driven via highDetailNeeded flag) - OR - HLR considerations: - Color HLR alters rgb output of demosaic, so re-demosaic is needed when Color HLR is being turned off; - if HLR is enabled and changing method *from* Color to any other method - OR HLR gets disabled when Color method was selected - */ - // If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST - - if (imageTypeListener) { - imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono()); - } - - if ((todo & M_RAW) - || (!highDetailRawComputed && highDetailNeeded) - || (params.toneCurve.hrenabled && params.toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) - || (!params.toneCurve.hrenabled && params.toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { - - if (settings->verbose) { - if (imgsrc->getSensorType() == ST_BAYER) { - printf("Demosaic Bayer image n.%d using method: %s\n", rp.bayersensor.imageNum + 1, rp.bayersensor.method.c_str()); - } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { - printf("Demosaic X-Trans image with using method: %s\n", rp.xtranssensor.method.c_str()); - } - } - if(imgsrc->getSensorType() == ST_BAYER) { - if(params.raw.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) { - imgsrc->setBorder(params.raw.bayersensor.border); - } else { - imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); - } - } - bool autoContrast = false; - double contrastThreshold = 0.f; - imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic - - // if a demosaic happened we should also call getimage later, so we need to set the M_INIT flag - todo |= M_INIT; - - if (highDetailNeeded) { - highDetailRawComputed = true; - } else { - highDetailRawComputed = false; - } - - if (params.retinex.enabled) { - lhist16RETI(32768); - lhist16RETI.clear(); - - imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, lhist16RETI); } } - if ((todo & (M_RETINEX | M_INIT)) && params.retinex.enabled) { - bool dehacontlutili = false; - bool mapcontlutili = false; - bool useHsl = false; - LUTf cdcurve(65536, 0); - LUTf mapcurve(65536, 0); + if (((todo & ALL) == ALL) || panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar)) { + bwAutoR = bwAutoG = bwAutoB = -9000.f; - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); - float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex(params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI); //enabled Retinex - - if (dehaListener) { - dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); - } - } - - if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { - MyMutex::MyLock initLock(minit); // Also used in crop window - - imgsrc->HLRecovery_Global(params.toneCurve); // this handles Color HLRecovery - - - if (settings->verbose) { - printf("Applying white balance, color correction & sRBG conversion...\n"); + if (todo == CROP && ipf.needsPCVignetting()) { + todo |= TRANSFORM; // Change about Crop does affect TRANSFORM } - currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + RAWParams rp = params.raw; + ColorManagementParams cmp = params.icm; + LCurveParams lcur = params.labCurve; - if (!params.wb.enabled) { - currWB = ColorTemp(); - } else if (params.wb.method == "Camera") { - currWB = imgsrc->getWB(); - } else if (params.wb.method == "Auto") { - if (lastAwbEqual != params.wb.equal || lastAwbTempBias != params.wb.tempBias) { - double rm, gm, bm; - imgsrc->getAutoWBMultipliers(rm, gm, bm); - - if (rm != -1.) { - autoWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); - lastAwbEqual = params.wb.equal; - lastAwbTempBias = params.wb.tempBias; - } else { - lastAwbEqual = -1.; - lastAwbTempBias = 0.0; - autoWB.useDefaults(params.wb.equal); - } - - //double rr,gg,bb; - //autoWB.getMultipliers(rr,gg,bb); + if (!highDetailNeeded) { + // if below 100% magnification, take a fast path + if (rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE) && rp.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE)) { + rp.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); } - currWB = autoWB; + //bayerrp.all_enhance = false; + + if (rp.xtranssensor.method != RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::NONE) && rp.xtranssensor.method != RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::NONE)) { + rp.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); + } + + rp.bayersensor.ccSteps = 0; + rp.xtranssensor.ccSteps = 0; + //rp.deadPixelFilter = rp.hotPixelFilter = false; } - if (params.wb.enabled) { - params.wb.temperature = currWB.getTemp(); - params.wb.green = currWB.getGreen(); + progress("Applying white balance, color correction & sRGB conversion...", 100 * readyphase / numofphases); + + if (frameCountListener) { + frameCountListener->FrameCountChanged(imgsrc->getFrameCount(), params.raw.bayersensor.imageNum); } - if (params.wb.method == "Auto" && awbListener && params.wb.enabled) { - awbListener->WBChanged(params.wb.temperature, params.wb.green); + // raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed + if ((todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) { + imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); + + imgsrc->preprocess(rp, params.lensProf, params.coarse); + imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); + + highDetailPreprocessComputed = highDetailNeeded; } /* - GammaValues g_a; - double pwr = 1.0 / params.icm.gampos; - double ts = params.icm.slpos; - - - int mode = 0; - Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope - printf("ga[0]=%f ga[1]=%f ga[2]=%f ga[3]=%f ga[4]=%f\n", g_a[0],g_a[1],g_a[2],g_a[3],g_a[4]); - - Glib::ustring datal; - datal = "lutsrgb.txt"; - ofstream fou(datal, ios::out | ios::trunc); - - for(int i=0; i < 212; i++) { - //printf("igamma2=%i\n", (int) 65535.f*Color::igamma2(i/212.0)); - float gam = Color::igamma2(i/211.0); - int lutga = nearbyint(65535.f* gam); - // fou << 65535*(int)Color::igamma2(i/212.0) << endl; - fou << i << " " << lutga << endl; - - } - fou.close(); + Demosaic is kicked off only when + Detail considerations: + accurate detail is not displayed yet needed based on preview specifics (driven via highDetailNeeded flag) + OR + HLR considerations: + Color HLR alters rgb output of demosaic, so re-demosaic is needed when Color HLR is being turned off; + if HLR is enabled and changing method *from* Color to any other method + OR HLR gets disabled when Color method was selected */ - int tr = getCoarseBitMask(params.coarse); + // If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST - imgsrc->getFullSize(fw, fh, tr); + if (imageTypeListener) { + imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono()); + } - // Will (re)allocate the preview's buffers - setScale(scale); - PreviewProps pp(0, 0, fw, fh, scale); - // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications - ipf.setScale(scale); + if ((todo & M_RAW) + || (!highDetailRawComputed && highDetailNeeded) + || (params.toneCurve.hrenabled && params.toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) + || (!params.toneCurve.hrenabled && params.toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { - imgsrc->getImage(currWB, tr, orig_prev, pp, params.toneCurve, params.raw); - denoiseInfoStore.valid = false; - //ColorTemp::CAT02 (orig_prev, ¶ms) ; - // printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale); - /* Issue 2785, disabled some 1:1 tools - if (todo & M_LINDENOISE) { - DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; - if (denoiseParams.enabled && (scale==1)) { - Imagefloat *calclum = NULL ; - - denoiseParams.getCurves(noiseLCurve,noiseCCurve); - int nbw=6;//nb tile W - int nbh=4;// - - float ch_M[nbw*nbh]; - float max_r[nbw*nbh]; - float max_b[nbw*nbh]; - - if(denoiseParams.Lmethod == "CUR") { - if(noiseLCurve) - denoiseParams.luma = 0.5f; - else - denoiseParams.luma = 0.0f; - } else if(denoiseParams.Lmethod == "SLI") - noiseLCurve.Reset(); - - - if(noiseLCurve || noiseCCurve){//only allocate memory if enabled and scale=1 - // we only need image reduced to 1/4 here - calclum = new Imagefloat ((pW+1)/2, (pH+1)/2);//for luminance denoise curve - for(int ii=0;iir(ii>>1,jj>>1) = orig_prev->r(ii,jj); - calclum->g(ii>>1,jj>>1) = orig_prev->g(ii,jj); - calclum->b(ii>>1,jj>>1) = orig_prev->b(ii,jj); - } - } - imgsrc->convertColorSpace(calclum, params.icm, currWB);//calculate values after colorspace conversion - } - - int kall=1; - ipf.RGB_denoise(kall, orig_prev, orig_prev, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi); - } + if (settings->verbose) { + if (imgsrc->getSensorType() == ST_BAYER) { + printf("Demosaic Bayer image n.%d using method: %s\n", rp.bayersensor.imageNum + 1, rp.bayersensor.method.c_str()); + } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { + printf("Demosaic X-Trans image with using method: %s\n", rp.xtranssensor.method.c_str()); } - */ - imgsrc->convertColorSpace(orig_prev, params.icm, currWB); - - ipf.firstAnalysis(orig_prev, params, vhist16); - } - - readyphase++; - - if ((todo & M_HDR) && params.fattal.enabled) { - if (fattal_11_dcrop_cache) { - delete fattal_11_dcrop_cache; - fattal_11_dcrop_cache = nullptr; - } - - ipf.ToneMapFattal02(orig_prev); - - if (oprevi != orig_prev) { - delete oprevi; - } - } - - oprevi = orig_prev; - - progress("Rotate / Distortion...", 100 * readyphase / numofphases); - // Remove transformation if unneeded - bool needstransform = ipf.needsTransform(); - - if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled))) { - assert(oprevi); - Imagefloat *op = oprevi; - oprevi = new Imagefloat(pW, pH); - - if (needstransform) - ipf.transform(op, oprevi, 0, 0, 0, 0, pW, pH, fw, fh, - imgsrc->getMetaData(), imgsrc->getRotateDegree(), false); - else { - op->copyData(oprevi); - } - } - - if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { - const int W = oprevi->getWidth(); - const int H = oprevi->getHeight(); - LabImage labcbdl(W, H); - ipf.rgb2lab(*oprevi, labcbdl, params.icm.workingProfile); - ipf.dirpyrequalizer(&labcbdl, scale); - ipf.lab2rgb(labcbdl, *oprevi, params.icm.workingProfile); - } - - readyphase++; - progress("Preparing shadow/highlight map...", 100 * readyphase / numofphases); - - readyphase++; - - if (todo & M_AUTOEXP) { - if (params.toneCurve.autoexp) { - LUTu aehist; - int aehistcompr; - imgsrc->getAutoExpHistogram(aehist, aehistcompr); - ipf.getAutoExp(aehist, aehistcompr, params.toneCurve.clip, params.toneCurve.expcomp, - params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); - - if (aeListener) - aeListener->autoExpChanged(params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, - params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.hrenabled); - } - - if (params.toneCurve.histmatching) { - if (!params.toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params.icm, params.toneCurve.curve); } - - if (params.toneCurve.autoexp) { - params.toneCurve.expcomp = 0.0; - } - - params.toneCurve.autoexp = false; - params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; - params.toneCurve.curve2 = { 0 }; - params.toneCurve.brightness = 0; - params.toneCurve.contrast = 0; - params.toneCurve.black = 0; - params.toneCurve.fromHistMatching = true; - - if (aeListener) { - aeListener->autoMatchedToneCurveChanged(params.toneCurve.curveMode, params.toneCurve.curve); - } - } - } - - progress("Exposure curve & CIELAB conversion...", 100 * readyphase / numofphases); - - if (todo & (M_AUTOEXP | M_RGBCURVE)) { - if (params.icm.workingTRC == "Custom") { //exec TRC IN free - Glib::ustring profile; - profile = params.icm.workingProfile; - - if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") { - int cw = oprevi->getWidth(); - int ch = oprevi->getHeight(); - // put gamma TRC to 1 - Imagefloat* readyImg0 = NULL; - readyImg0 = ipf.workingtrc(oprevi, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310); - #pragma omp parallel for - - for (int row = 0; row < ch; row++) { - for (int col = 0; col < cw; col++) { - oprevi->r(row, col) = (float)readyImg0->r(row, col); - oprevi->g(row, col) = (float)readyImg0->g(row, col); - oprevi->b(row, col) = (float)readyImg0->b(row, col); - } + if(imgsrc->getSensorType() == ST_BAYER) { + if(params.raw.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) { + imgsrc->setBorder(params.raw.bayersensor.border); + } else { + imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); } - - delete readyImg0; - //adjust TRC - Imagefloat* readyImg = NULL; - readyImg = ipf.workingtrc(oprevi, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope); - #pragma omp parallel for - - for (int row = 0; row < ch; row++) { - for (int col = 0; col < cw; col++) { - oprevi->r(row, col) = (float)readyImg->r(row, col); - oprevi->g(row, col) = (float)readyImg->g(row, col); - oprevi->b(row, col) = (float)readyImg->b(row, col); - } - } - - delete readyImg; - } - } - } + bool autoContrast = false; + double contrastThreshold = 0.f; + imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic + // if a demosaic happened we should also call getimage later, so we need to set the M_INIT flag + todo |= M_INIT; - if ((todo & M_RGBCURVE) || (todo & M_CROP)) { -// if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); - - //complexCurve also calculated pre-curves histogram depending on crop - CurveFactory::complexCurve(params.toneCurve.expcomp, params.toneCurve.black / 65535.0, - params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, - params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, - params.toneCurve.curve, params.toneCurve.curve2, - vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, 1); - - CurveFactory::RGBCurve(params.rgbCurves.rcurve, rCurve, 1); - CurveFactory::RGBCurve(params.rgbCurves.gcurve, gCurve, 1); - CurveFactory::RGBCurve(params.rgbCurves.bcurve, bCurve, 1); - - - opautili = false; - - if (params.colorToning.enabled) { - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile); - double wp[3][3] = { - {wprof[0][0], wprof[0][1], wprof[0][2]}, - {wprof[1][0], wprof[1][1], wprof[1][2]}, - {wprof[2][0], wprof[2][1], wprof[2][2]} - }; - params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili); - CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); - CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); - } - - if (params.blackwhite.enabled) { - CurveFactory::curveBW(params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1); - } - - colourToningSatLimit = float (params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; - colourToningSatLimitOpacity = 1.f - (float (params.colorToning.saturatedOpacity) / 100.f); - - int satTH = 80; - int satPR = 30; - int indi = 0; - - if (params.colorToning.enabled && params.colorToning.autosat && params.colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings - float moyS = 0.f; - float eqty = 0.f; - ipf.moyeqt(oprevi, moyS, eqty); //return image : mean saturation and standard dev of saturation - //printf("moy=%f ET=%f\n", moyS,eqty); - float satp = ((moyS + 1.5f * eqty) - 0.3f) / 0.7f; //1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale - - if (satp >= 0.92f) { - satp = 0.92f; //avoid values too high (out of gamut) - } - - if (satp <= 0.15f) { - satp = 0.15f; //avoid too low values - } - - //satTH=(int) 100.f*satp; - //satPR=(int) 100.f*(moyS-0.85f*eqty);//-0.85 sigma==>20% pixels with low saturation - colourToningSatLimit = 100.f * satp; - satTH = (int) 100.f * satp; - - colourToningSatLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation - satPR = (int) 100.f * (moyS - 0.85f * eqty); - } - - if (actListener) { - //if(params.blackwhite.enabled) {actListener->autoColorTonChanged(0, satTH, satPR);} - if (params.blackwhite.enabled && params.colorToning.autosat) { - actListener->autoColorTonChanged(0, satTH, satPR); //hide sliders only if autosat - indi = 0; + if (highDetailNeeded) { + highDetailRawComputed = true; } else { - if (params.colorToning.autosat) { - if (params.colorToning.method == "Lab") { - indi = 1; - } else if (params.colorToning.method == "RGBCurves") { - indi = 1; - } else if (params.colorToning.method == "RGBSliders") { - indi = 1; - } else if (params.colorToning.method == "Splico") { - indi = 2; - } else if (params.colorToning.method == "Splitlr") { - indi = 2; + highDetailRawComputed = false; + } + + if (params.retinex.enabled) { + lhist16RETI(32768); + lhist16RETI.clear(); + + imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, lhist16RETI); + } + } + + if ((todo & (M_RETINEX | M_INIT)) && params.retinex.enabled) { + bool dehacontlutili = false; + bool mapcontlutili = false; + bool useHsl = false; + LUTf cdcurve(65536, 0); + LUTf mapcurve(65536, 0); + + imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); + float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; + imgsrc->retinex(params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI); //enabled Retinex + + if (dehaListener) { + dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } + } + + if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { + MyMutex::MyLock initLock(minit); // Also used in crop window + + imgsrc->HLRecovery_Global(params.toneCurve); // this handles Color HLRecovery + + + if (settings->verbose) { + printf("Applying white balance, color correction & sRBG conversion...\n"); + } + + currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + + if (!params.wb.enabled) { + currWB = ColorTemp(); + } else if (params.wb.method == "Camera") { + currWB = imgsrc->getWB(); + } else if (params.wb.method == "Auto") { + if (lastAwbEqual != params.wb.equal || lastAwbTempBias != params.wb.tempBias) { + double rm, gm, bm; + imgsrc->getAutoWBMultipliers(rm, gm, bm); + + if (rm != -1.) { + autoWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); + lastAwbEqual = params.wb.equal; + lastAwbTempBias = params.wb.tempBias; + } else { + lastAwbEqual = -1.; + lastAwbTempBias = 0.0; + autoWB.useDefaults(params.wb.equal); } - //actListener->autoColorTonChanged(indi, satTH, satPR); - } - } - } - - // if it's just crop we just need the histogram, no image updates - if (todo & M_RGBCURVE) { - //initialize rrm bbm ggm different from zero to avoid black screen in some cases - double rrm = 33.; - double ggm = 33.; - double bbm = 33.; - - DCPProfile::ApplyState as; - DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as); - - ipf.rgbProc (oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params.toneCurve.saturation, - rCurve, gCurve, bCurve, colourToningSatLimit, colourToningSatLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf, as, histToneCurve); - - if (params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { - if (settings->verbose) { - printf("ImProcCoordinator / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", bwAutoR, bwAutoG, bwAutoB); + //double rr,gg,bb; + //autoWB.getMultipliers(rr,gg,bb); } - abwListener->BWChanged((float) rrm, (float) ggm, (float) bbm); + currWB = autoWB; } - if (params.colorToning.enabled && params.colorToning.autosat && actListener) { - if (settings->verbose) { - printf("ImProcCoordinator / Auto CT: indi=%d satH=%d satPR=%d\n", indi, (int)colourToningSatLimit, (int) colourToningSatLimitOpacity); - } - - actListener->autoColorTonChanged(indi, (int) colourToningSatLimit, (int)colourToningSatLimitOpacity); //change sliders autosat + if (params.wb.enabled) { + params.wb.temperature = currWB.getTemp(); + params.wb.green = currWB.getGreen(); } - // correct GUI black and white with value + if (params.wb.method == "Auto" && awbListener && params.wb.enabled) { + awbListener->WBChanged(params.wb.temperature, params.wb.green); + } + + /* + GammaValues g_a; + double pwr = 1.0 / params.icm.gampos; + double ts = params.icm.slpos; + + + int mode = 0; + Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope + printf("ga[0]=%f ga[1]=%f ga[2]=%f ga[3]=%f ga[4]=%f\n", g_a[0],g_a[1],g_a[2],g_a[3],g_a[4]); + + Glib::ustring datal; + datal = "lutsrgb.txt"; + ofstream fou(datal, ios::out | ios::trunc); + + for(int i=0; i < 212; i++) { + //printf("igamma2=%i\n", (int) 65535.f*Color::igamma2(i/212.0)); + float gam = Color::igamma2(i/211.0); + int lutga = nearbyint(65535.f* gam); + // fou << 65535*(int)Color::igamma2(i/212.0) << endl; + fou << i << " " << lutga << endl; + + } + fou.close(); + */ + int tr = getCoarseBitMask(params.coarse); + + imgsrc->getFullSize(fw, fh, tr); + + // Will (re)allocate the preview's buffers + setScale(scale); + PreviewProps pp(0, 0, fw, fh, scale); + // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications + ipf.setScale(scale); + + imgsrc->getImage(currWB, tr, orig_prev, pp, params.toneCurve, params.raw); + denoiseInfoStore.valid = false; + //ColorTemp::CAT02 (orig_prev, ¶ms) ; + // printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale); + /* Issue 2785, disabled some 1:1 tools + if (todo & M_LINDENOISE) { + DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; + if (denoiseParams.enabled && (scale==1)) { + Imagefloat *calclum = NULL ; + + denoiseParams.getCurves(noiseLCurve,noiseCCurve); + int nbw=6;//nb tile W + int nbh=4;// + + float ch_M[nbw*nbh]; + float max_r[nbw*nbh]; + float max_b[nbw*nbh]; + + if(denoiseParams.Lmethod == "CUR") { + if(noiseLCurve) + denoiseParams.luma = 0.5f; + else + denoiseParams.luma = 0.0f; + } else if(denoiseParams.Lmethod == "SLI") + noiseLCurve.Reset(); + + + if(noiseLCurve || noiseCCurve){//only allocate memory if enabled and scale=1 + // we only need image reduced to 1/4 here + calclum = new Imagefloat ((pW+1)/2, (pH+1)/2);//for luminance denoise curve + for(int ii=0;iir(ii>>1,jj>>1) = orig_prev->r(ii,jj); + calclum->g(ii>>1,jj>>1) = orig_prev->g(ii,jj); + calclum->b(ii>>1,jj>>1) = orig_prev->b(ii,jj); + } + } + imgsrc->convertColorSpace(calclum, params.icm, currWB);//calculate values after colorspace conversion + } + + int kall=1; + ipf.RGB_denoise(kall, orig_prev, orig_prev, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi); + } + } + */ + imgsrc->convertColorSpace(orig_prev, params.icm, currWB); + + ipf.firstAnalysis(orig_prev, params, vhist16); } - // compute L channel histogram - int x1, y1, x2, y2; - params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); - } - - readyphase++; - - if (todo & (M_LUMACURVE | M_CROP)) { - LUTu lhist16(32768); - lhist16.clear(); -#ifdef _OPENMP - const int numThreads = min(max(pW * pH / (int)lhist16.getSize(), 1), omp_get_max_threads()); - #pragma omp parallel num_threads(numThreads) if(numThreads>1) -#endif - { - LUTu lhist16thr(lhist16.getSize()); - lhist16thr.clear(); -#ifdef _OPENMP - #pragma omp for nowait -#endif - - for (int x = 0; x < pH; x++) - for (int y = 0; y < pW; y++) { - int pos = (int)(oprevl->L[x][y]); - lhist16thr[pos]++; - } - -#ifdef _OPENMP - #pragma omp critical -#endif - lhist16 += lhist16thr; - } -#ifdef _OPENMP - static_cast(numThreads); // to silence cppcheck warning -#endif - CurveFactory::complexLCurve(params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lumacurve, histLCurve, scale == 1 ? 1 : 16, utili); - } - - if (todo & M_LUMACURVE) { - - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); - - CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, - params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16); - } - - if (todo & (M_LUMINANCE + M_COLOR)) { - nprevl->CopyFrom(oprevl); - - progress("Applying Color Boost...", 100 * readyphase / numofphases); - // ipf.MSR(nprevl, nprevl->W, nprevl->H, 1); - histCCurve.clear(); - histLCurve.clear(); - ipf.chromiLuminanceCurve(nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); - ipf.vibrance(nprevl); - - if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { - ipf.EPDToneMap(nprevl, 5, scale); - } - - // for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled readyphase++; - /* Issue 2785, disabled some 1:1 tools - if (scale==1) { - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ - progress ("Denoising luminance impulse...",100*readyphase/numofphases); - ipf.impulsedenoise (nprevl); - readyphase++; + if ((todo & M_HDR) && params.fattal.enabled) { + if (fattal_11_dcrop_cache) { + delete fattal_11_dcrop_cache; + fattal_11_dcrop_cache = nullptr; + } + + ipf.ToneMapFattal02(orig_prev); + + if (oprevi != orig_prev) { + delete oprevi; + } + } + + oprevi = orig_prev; + + progress("Rotate / Distortion...", 100 * readyphase / numofphases); + // Remove transformation if unneeded + bool needstransform = ipf.needsTransform(); + + if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled))) { + assert(oprevi); + Imagefloat *op = oprevi; + oprevi = new Imagefloat(pW, pH); + + if (needstransform) + ipf.transform(op, oprevi, 0, 0, 0, 0, pW, pH, fw, fh, + imgsrc->getMetaData(), imgsrc->getRotateDegree(), false); + else { + op->copyData(oprevi); + } + } + + if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { + const int W = oprevi->getWidth(); + const int H = oprevi->getHeight(); + LabImage labcbdl(W, H); + ipf.rgb2lab(*oprevi, labcbdl, params.icm.workingProfile); + ipf.dirpyrequalizer(&labcbdl, scale); + ipf.lab2rgb(labcbdl, *oprevi, params.icm.workingProfile); + } + + readyphase++; + progress("Preparing shadow/highlight map...", 100 * readyphase / numofphases); + + readyphase++; + + if (todo & M_AUTOEXP) { + if (params.toneCurve.autoexp) { + LUTu aehist; + int aehistcompr; + imgsrc->getAutoExpHistogram(aehist, aehistcompr); + ipf.getAutoExp(aehist, aehistcompr, params.toneCurve.clip, params.toneCurve.expcomp, + params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); + + if (aeListener) + aeListener->autoExpChanged(params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, + params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.hrenabled); + } + + if (params.toneCurve.histmatching) { + if (!params.toneCurve.fromHistMatching) { + imgsrc->getAutoMatchedToneCurve(params.icm, params.toneCurve.curve); + } + + if (params.toneCurve.autoexp) { + params.toneCurve.expcomp = 0.0; + } + + params.toneCurve.autoexp = false; + params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; + params.toneCurve.curve2 = { 0 }; + params.toneCurve.brightness = 0; + params.toneCurve.contrast = 0; + params.toneCurve.black = 0; + params.toneCurve.fromHistMatching = true; + + if (aeListener) { + aeListener->autoMatchedToneCurveChanged(params.toneCurve.curveMode, params.toneCurve.curve); + } + } + } + + progress("Exposure curve & CIELAB conversion...", 100 * readyphase / numofphases); + + if (todo & (M_AUTOEXP | M_RGBCURVE)) { + if (params.icm.workingTRC == "Custom") { //exec TRC IN free + Glib::ustring profile; + profile = params.icm.workingProfile; + + if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") { + int cw = oprevi->getWidth(); + int ch = oprevi->getHeight(); + // put gamma TRC to 1 + Imagefloat* readyImg0 = NULL; + readyImg0 = ipf.workingtrc(oprevi, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310); + #pragma omp parallel for + + for (int row = 0; row < ch; row++) { + for (int col = 0; col < cw; col++) { + oprevi->r(row, col) = (float)readyImg0->r(row, col); + oprevi->g(row, col) = (float)readyImg0->g(row, col); + oprevi->b(row, col) = (float)readyImg0->b(row, col); + } } - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ - progress ("Defringing...",100*readyphase/numofphases); - ipf.defringe (nprevl); - readyphase++; + + delete readyImg0; + //adjust TRC + Imagefloat* readyImg = NULL; + readyImg = ipf.workingtrc(oprevi, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope); + #pragma omp parallel for + + for (int row = 0; row < ch; row++) { + for (int col = 0; col < cw; col++) { + oprevi->r(row, col) = (float)readyImg->r(row, col); + oprevi->g(row, col) = (float)readyImg->g(row, col); + oprevi->b(row, col) = (float)readyImg->b(row, col); + } } - if (params.sharpenEdge.enabled) { - progress ("Edge sharpening...",100*readyphase/numofphases); - ipf.MLsharpen (nprevl); - readyphase++; + + delete readyImg; + + } + } + } + + + if ((todo & M_RGBCURVE) || (todo & M_CROP)) { + // if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); + + //complexCurve also calculated pre-curves histogram depending on crop + CurveFactory::complexCurve(params.toneCurve.expcomp, params.toneCurve.black / 65535.0, + params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, + params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, + params.toneCurve.curve, params.toneCurve.curve2, + vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, 1); + + CurveFactory::RGBCurve(params.rgbCurves.rcurve, rCurve, 1); + CurveFactory::RGBCurve(params.rgbCurves.gcurve, gCurve, 1); + CurveFactory::RGBCurve(params.rgbCurves.bcurve, bCurve, 1); + + + opautili = false; + + if (params.colorToning.enabled) { + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile); + double wp[3][3] = { + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili); + CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); + CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + } + + if (params.blackwhite.enabled) { + CurveFactory::curveBW(params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1); + } + + colourToningSatLimit = float (params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; + colourToningSatLimitOpacity = 1.f - (float (params.colorToning.saturatedOpacity) / 100.f); + + int satTH = 80; + int satPR = 30; + int indi = 0; + + if (params.colorToning.enabled && params.colorToning.autosat && params.colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings + float moyS = 0.f; + float eqty = 0.f; + ipf.moyeqt(oprevi, moyS, eqty); //return image : mean saturation and standard dev of saturation + //printf("moy=%f ET=%f\n", moyS,eqty); + float satp = ((moyS + 1.5f * eqty) - 0.3f) / 0.7f; //1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale + + if (satp >= 0.92f) { + satp = 0.92f; //avoid values too high (out of gamut) + } + + if (satp <= 0.15f) { + satp = 0.15f; //avoid too low values + } + + //satTH=(int) 100.f*satp; + //satPR=(int) 100.f*(moyS-0.85f*eqty);//-0.85 sigma==>20% pixels with low saturation + colourToningSatLimit = 100.f * satp; + satTH = (int) 100.f * satp; + + colourToningSatLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation + satPR = (int) 100.f * (moyS - 0.85f * eqty); + } + + if (actListener && params.colorToning.enabled) { + if (params.blackwhite.enabled && params.colorToning.autosat) { + actListener->autoColorTonChanged(0, satTH, satPR); //hide sliders only if autosat + indi = 0; + } else { + if (params.colorToning.autosat) { + if (params.colorToning.method == "Lab") { + indi = 1; + } else if (params.colorToning.method == "RGBCurves") { + indi = 1; + } else if (params.colorToning.method == "RGBSliders") { + indi = 1; + } else if (params.colorToning.method == "Splico") { + indi = 2; + } else if (params.colorToning.method == "Splitlr") { + indi = 2; + } } - if (params.sharpenMicro.enabled) { - if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ - progress ("Microcontrast...",100*readyphase/numofphases); - ipf.MLmicrocontrast (nprevl); + } + } + + // if it's just crop we just need the histogram, no image updates + if (todo & M_RGBCURVE) { + //initialize rrm bbm ggm different from zero to avoid black screen in some cases + double rrm = 33.; + double ggm = 33.; + double bbm = 33.; + + DCPProfile::ApplyState as; + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as); + + ipf.rgbProc (oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params.toneCurve.saturation, + rCurve, gCurve, bCurve, colourToningSatLimit, colourToningSatLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf, as, histToneCurve); + + if (params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { + if (settings->verbose) { + printf("ImProcCoordinator / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", bwAutoR, bwAutoG, bwAutoB); + } + + abwListener->BWChanged((float) rrm, (float) ggm, (float) bbm); + } + + if (params.colorToning.enabled && params.colorToning.autosat && actListener) { + if (settings->verbose) { + printf("ImProcCoordinator / Auto CT: indi=%d satH=%d satPR=%d\n", indi, (int)colourToningSatLimit, (int) colourToningSatLimitOpacity); + } + + actListener->autoColorTonChanged(indi, (int) colourToningSatLimit, (int)colourToningSatLimitOpacity); //change sliders autosat + } + + // correct GUI black and white with value + } + + // compute L channel histogram + int x1, y1, x2, y2; + params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + } + + readyphase++; + + if (todo & (M_LUMACURVE | M_CROP)) { + LUTu lhist16(32768); + lhist16.clear(); +#ifdef _OPENMP + const int numThreads = min(max(pW * pH / (int)lhist16.getSize(), 1), omp_get_max_threads()); + #pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif + { + LUTu lhist16thr(lhist16.getSize()); + lhist16thr.clear(); +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int x = 0; x < pH; x++) + for (int y = 0; y < pW; y++) { + int pos = (int)(oprevl->L[x][y]); + lhist16thr[pos]++; + } + +#ifdef _OPENMP + #pragma omp critical +#endif + lhist16 += lhist16thr; + } +#ifdef _OPENMP + static_cast(numThreads); // to silence cppcheck warning +#endif + CurveFactory::complexLCurve(params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lumacurve, histLCurve, scale == 1 ? 1 : 16, utili); + } + + if (todo & M_LUMACURVE) { + + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); + + CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, + params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16); + } + + if (todo & (M_LUMINANCE + M_COLOR)) { + nprevl->CopyFrom(oprevl); + + progress("Applying Color Boost...", 100 * readyphase / numofphases); + // ipf.MSR(nprevl, nprevl->W, nprevl->H, 1); + histCCurve.clear(); + histLCurve.clear(); + ipf.chromiLuminanceCurve(nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); + ipf.vibrance(nprevl); + + if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { + ipf.EPDToneMap(nprevl, 5, scale); + } + + // for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled + readyphase++; + + /* Issue 2785, disabled some 1:1 tools + if (scale==1) { + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ + progress ("Denoising luminance impulse...",100*readyphase/numofphases); + ipf.impulsedenoise (nprevl); + readyphase++; + } + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ + progress ("Defringing...",100*readyphase/numofphases); + ipf.defringe (nprevl); + readyphase++; + } + if (params.sharpenEdge.enabled) { + progress ("Edge sharpening...",100*readyphase/numofphases); + ipf.MLsharpen (nprevl); + readyphase++; + } + if (params.sharpenMicro.enabled) { + if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ + progress ("Microcontrast...",100*readyphase/numofphases); + ipf.MLmicrocontrast (nprevl); + readyphase++; + } + } + if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { + progress ("Sharpening...",100*readyphase/numofphases); + + float **buffer = new float*[pH]; + for (int i=0; iautocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { - progress ("Sharpening...",100*readyphase/numofphases); + */ + if (params.dirpyrequalizer.cbdlMethod == "aft") { + if (((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled))) { + progress("Pyramid wavelet...", 100 * readyphase / numofphases); + ipf.dirpyrequalizer(nprevl, scale); + //ipf.Lanczoslab (ip_wavelet(LabImage * lab, LabImage * dst, const procparams::EqualizerParams & eqparams), nprevl, 1.f/scale); + readyphase++; + } + } - float **buffer = new float*[pH]; - for (int i=0; iL[x][y])); + int posc = CLIP((int)sqrt(nprevl->a[x][y] * nprevl->a[x][y] + nprevl->b[x][y] * nprevl->b[x][y])); + lhist16CAM[pos]++; + lhist16CCAM[posc]++; + } + } + + CurveFactory::curveLightBrightColor(params.colorappearance.curve, params.colorappearance.curve2, params.colorappearance.curve3, + lhist16CAM, histLCAM, lhist16CCAM, histCCAM, + customColCurve1, customColCurve2, customColCurve3, 1); + + const FramesMetaData* metaData = imgsrc->getMetaData(); + int imgNum = 0; + + if (imgsrc->isRAW()) { + if (imgsrc->getSensorType() == ST_BAYER) { + imgNum = rtengine::LIM(params.raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); + } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { + //imgNum = rtengine::LIM(params.raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); } } - */ - if (params.dirpyrequalizer.cbdlMethod == "aft") { - if (((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled))) { - progress("Pyramid wavelet...", 100 * readyphase / numofphases); - ipf.dirpyrequalizer(nprevl, scale); - //ipf.Lanczoslab (ip_wavelet(LabImage * lab, LabImage * dst, const procparams::EqualizerParams & eqparams), nprevl, 1.f/scale); + + float fnum = metaData->getFNumber(imgNum); // F number + float fiso = metaData->getISOSpeed(imgNum) ; // ISO + float fspeed = metaData->getShutterSpeed(imgNum) ; // Speed + double fcomp = metaData->getExpComp(imgNum); // Compensation +/- + double adap; + + if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong + adap = 2000.; + } else { + double E_V = fcomp + log2(double ((fnum * fnum) / fspeed / (fiso / 100.f))); + E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV + E_V += log2(params.raw.expos); // exposure raw white point ; log2 ==> linear to EV + adap = powf(2.f, E_V - 3.f); // cd / m2 + // end calculation adaptation scene luminosity + } + + float d, dj, yb; + bool execsharp = false; + + if (!ncie) { + ncie = new CieImage(pW, pH); + } + + if (!CAMBrightCurveJ && (params.colorappearance.algo == "JC" || params.colorappearance.algo == "JS" || params.colorappearance.algo == "ALL")) { + CAMBrightCurveJ(32768, 0); + } + + if (!CAMBrightCurveQ && (params.colorappearance.algo == "QM" || params.colorappearance.algo == "ALL")) { + CAMBrightCurveQ(32768, 0); + } + + // Issue 2785, only float version of ciecam02 for navigator and pan background + CAMMean = NAN; + CAMBrightCurveJ.dirty = true; + CAMBrightCurveQ.dirty = true; + + ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, ¶ms, customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, scale, execsharp, d, dj, yb, 1); + + if ((params.colorappearance.autodegree || params.colorappearance.autodegreeout) && acListener && params.colorappearance.enabled) { + acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); + } + + if (params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) { + acListener->adapCamChanged(adap); //real value of adapt scene + } + + if (params.colorappearance.autoybscen && acListener && params.colorappearance.enabled) { + acListener->ybCamChanged((int) yb); //real value Yb scene + } + readyphase++; - } - } + } else { + // CIECAM is disabled, we free up its image buffer to save some space + if (ncie) { + delete ncie; + } + ncie = nullptr; - wavcontlutili = false; - //CurveFactory::curveWavContL ( wavcontlutili,params.wavelet.lcurve, wavclCurve, LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,int skip); - CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); + if (CAMBrightCurveJ) { + CAMBrightCurveJ.reset(); + } - - if ((params.wavelet.enabled)) { - WaveletParams WaveParams = params.wavelet; - // WaveParams.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY); - WaveParams.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); - - int kall = 0; - progress("Wavelet...", 100 * readyphase / numofphases); - // ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, scale); - ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); - - } - - - if (params.colorappearance.enabled) { - //L histo and Chroma histo for ciecam - // histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C - int x1, y1, x2, y2; - params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); - lhist16CAM.clear(); - lhist16CCAM.clear(); - - if (!params.colorappearance.datacie) { - for (int x = 0; x < pH; x++) - for (int y = 0; y < pW; y++) { - int pos = CLIP((int)(nprevl->L[x][y])); - int posc = CLIP((int)sqrt(nprevl->a[x][y] * nprevl->a[x][y] + nprevl->b[x][y] * nprevl->b[x][y])); - lhist16CAM[pos]++; - lhist16CCAM[posc]++; - } - } - - CurveFactory::curveLightBrightColor(params.colorappearance.curve, params.colorappearance.curve2, params.colorappearance.curve3, - lhist16CAM, histLCAM, lhist16CCAM, histCCAM, - customColCurve1, customColCurve2, customColCurve3, 1); - - const FramesMetaData* metaData = imgsrc->getMetaData(); - int imgNum = 0; - - if (imgsrc->isRAW()) { - if (imgsrc->getSensorType() == ST_BAYER) { - imgNum = rtengine::LIM(params.raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); - } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { - //imgNum = rtengine::LIM(params.raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); + if (CAMBrightCurveQ) { + CAMBrightCurveQ.reset(); } } - - float fnum = metaData->getFNumber(imgNum); // F number - float fiso = metaData->getISOSpeed(imgNum) ; // ISO - float fspeed = metaData->getShutterSpeed(imgNum) ; // Speed - double fcomp = metaData->getExpComp(imgNum); // Compensation +/- - double adap; - - if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong - adap = 2000.; - } else { - double E_V = fcomp + log2(double ((fnum * fnum) / fspeed / (fiso / 100.f))); - E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV - E_V += log2(params.raw.expos); // exposure raw white point ; log2 ==> linear to EV - adap = powf(2.f, E_V - 3.f); // cd / m2 - // end calculation adaptation scene luminosity - } - - float d, dj, yb; - bool execsharp = false; - - if (!ncie) { - ncie = new CieImage(pW, pH); - } - - if (!CAMBrightCurveJ && (params.colorappearance.algo == "JC" || params.colorappearance.algo == "JS" || params.colorappearance.algo == "ALL")) { - CAMBrightCurveJ(32768, 0); - } - - if (!CAMBrightCurveQ && (params.colorappearance.algo == "QM" || params.colorappearance.algo == "ALL")) { - CAMBrightCurveQ(32768, 0); - } - - // Issue 2785, only float version of ciecam02 for navigator and pan background - CAMMean = NAN; - CAMBrightCurveJ.dirty = true; - CAMBrightCurveQ.dirty = true; - - ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, ¶ms, customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, scale, execsharp, d, dj, yb, 1); - - if ((params.colorappearance.autodegree || params.colorappearance.autodegreeout) && acListener && params.colorappearance.enabled) { - acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); - } - - if (params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) { - acListener->adapCamChanged(adap); //real value of adapt scene - } - - if (params.colorappearance.autoybscen && acListener && params.colorappearance.enabled) { - acListener->ybCamChanged((int) yb); //real value Yb scene - } - - readyphase++; - } else { - // CIECAM is disabled, we free up its image buffer to save some space - if (ncie) { - delete ncie; - } - - ncie = nullptr; - - if (CAMBrightCurveJ) { - CAMBrightCurveJ.reset(); - } - - if (CAMBrightCurveQ) { - CAMBrightCurveQ.reset(); - } } - } - // Update the monitor color transform if necessary - if ((todo & M_MONITOR) || (lastOutputProfile != params.icm.outputProfile) || lastOutputIntent != params.icm.outputIntent || lastOutputBPC != params.icm.outputBPC) { - lastOutputProfile = params.icm.outputProfile; - lastOutputIntent = params.icm.outputIntent; - lastOutputBPC = params.icm.outputBPC; - ipf.updateColorProfiles(monitorProfile, monitorIntent, softProof, gamutCheck); + // Update the monitor color transform if necessary + if ((todo & M_MONITOR) || (lastOutputProfile != params.icm.outputProfile) || lastOutputIntent != params.icm.outputIntent || lastOutputBPC != params.icm.outputBPC) { + lastOutputProfile = params.icm.outputProfile; + lastOutputIntent = params.icm.outputIntent; + lastOutputBPC = params.icm.outputBPC; + ipf.updateColorProfiles(monitorProfile, monitorIntent, softProof, gamutCheck); + } } // process crop, if needed for (size_t i = 0; i < crops.size(); i++) - if (crops[i]->hasListener() && cropCall != crops[i]) { + if (crops[i]->hasListener() && (panningRelatedChange || crops[i]->get_skip() == 1)) { crops[i]->update(todo); // may call ourselves } - progress("Conversion to RGB...", 100 * readyphase / numofphases); + if (panningRelatedChange) { + progress("Conversion to RGB...", 100 * readyphase / numofphases); - if ((todo != CROP && todo != MINUPDATE) || (todo & M_MONITOR)) { - MyMutex::MyLock prevImgLock(previmg->getMutex()); + if ((todo != CROP && todo != MINUPDATE) || (todo & M_MONITOR)) { + MyMutex::MyLock prevImgLock(previmg->getMutex()); - try { - // Computing the preview image, i.e. converting from WCS->Monitor color space (soft-proofing disabled) or WCS->Printer profile->Monitor color space (soft-proofing enabled) - ipf.lab2monitorRgb(nprevl, previmg); + try { + // Computing the preview image, i.e. converting from WCS->Monitor color space (soft-proofing disabled) or WCS->Printer profile->Monitor color space (soft-proofing enabled) + ipf.lab2monitorRgb(nprevl, previmg); - // Computing the internal image for analysis, i.e. conversion from WCS->Output profile - delete workimg; - workimg = ipf.lab2rgb(nprevl, 0, 0, pW, pH, params.icm); - } catch (char * str) { - progress("Error converting file...", 0); - return; + // Computing the internal image for analysis, i.e. conversion from WCS->Output profile + delete workimg; + workimg = ipf.lab2rgb(nprevl, 0, 0, pW, pH, params.icm); + } catch (char * str) { + progress("Error converting file...", 0); + return; + } } - } - if (!resultValid) { - resultValid = true; + if (!resultValid) { + resultValid = true; - if (imageListener) { - imageListener->setImage(previmg, scale, params.crop); + if (imageListener) { + imageListener->setImage(previmg, scale, params.crop); + } } - } - if (imageListener) - // TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values - { - imageListener->imageReady(params.crop); - } + if (imageListener) + // TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values + { + imageListener->imageReady(params.crop); + } - readyphase++; + readyphase++; - if (hListener) { - updateLRGBHistograms(); - hListener->histogramChanged(histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histCCurve, /*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma, histLRETI); + if (hListener) { + updateLRGBHistograms(); + hListener->histogramChanged(histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histCCurve, /*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma, histLRETI); + } } } @@ -1414,6 +1410,7 @@ void ImProcCoordinator::process() paramsUpdateMutex.lock(); while (changeSinceLast) { + const bool panningRelatedChange = params.isPanningRelatedChange(nextParams); params = nextParams; int change = changeSinceLast; changeSinceLast = 0; @@ -1421,7 +1418,7 @@ void ImProcCoordinator::process() // M_VOID means no update, and is a bit higher that the rest if (change & (M_VOID - 1)) { - updatePreviewImage(change); + updatePreviewImage(change, panningRelatedChange); } paramsUpdateMutex.lock(); diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index aabc9000b..dba12cdd7 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -179,7 +179,7 @@ protected: void reallocAll (); void updateLRGBHistograms (); void setScale (int prevscale); - void updatePreviewImage (int todo, Crop* cropCall = nullptr); + void updatePreviewImage (int todo, bool panningRelatedChange); MyMutex mProcessing; ProcParams params; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index aebc8c047..bee556b27 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1646,7 +1646,9 @@ bool LensProfParams::operator ==(const LensProfParams& other) const && useCA == other.useCA && lfCameraMake == other.lfCameraMake && lfCameraModel == other.lfCameraModel - && lfLens == other.lfLens; + && lfLens == other.lfLens + && useDist == other.useDist + && useVign == other.useVign; } bool LensProfParams::operator !=(const LensProfParams& other) const @@ -5046,6 +5048,73 @@ int ProcParams::write(const Glib::ustring& fname, const Glib::ustring& content) return error; } +bool ProcParams::isThumbRelatedChange(const ProcParams &newParams) const +{ + return toneCurve != newParams.toneCurve + || labCurve != newParams.labCurve + || localContrast != newParams.localContrast + || rgbCurves != newParams.rgbCurves + || colorToning != newParams.colorToning + || vibrance != newParams.vibrance + || wb != newParams.wb + || colorappearance != newParams.colorappearance + || epd != newParams.epd + || fattal != newParams.fattal + || sh != newParams.sh + || crop != newParams.crop + || coarse != newParams.coarse + || commonTrans != newParams.commonTrans + || rotate != newParams.rotate + || distortion != newParams.distortion + || lensProf != newParams.lensProf + || perspective != newParams.perspective + || gradient != newParams.gradient + || pcvignette != newParams.pcvignette + || cacorrection != newParams.cacorrection + || vignetting != newParams.vignetting + || chmixer != newParams.chmixer + || blackwhite != newParams.blackwhite + || icm != newParams.icm + || hsvequalizer != newParams.hsvequalizer + || filmSimulation != newParams.filmSimulation + || softlight != newParams.softlight; +} + +bool ProcParams::isPanningRelatedChange(const ProcParams &newParams) const +{ + return toneCurve != newParams.toneCurve + || labCurve != newParams.labCurve + || localContrast != newParams.localContrast + || rgbCurves != newParams.rgbCurves + || colorToning != newParams.colorToning + || vibrance != newParams.vibrance + || wb != newParams.wb + || colorappearance != newParams.colorappearance + || epd != newParams.epd + || fattal != newParams.fattal + || sh != newParams.sh + || crop != newParams.crop + || coarse != newParams.coarse + || commonTrans != newParams.commonTrans + || rotate != newParams.rotate + || distortion != newParams.distortion + || lensProf != newParams.lensProf + || perspective != newParams.perspective + || gradient != newParams.gradient + || pcvignette != newParams.pcvignette + || cacorrection != newParams.cacorrection + || vignetting != newParams.vignetting + || chmixer != newParams.chmixer + || blackwhite != newParams.blackwhite + || icm != newParams.icm + || hsvequalizer != newParams.hsvequalizer + || filmSimulation != newParams.filmSimulation + || softlight != newParams.softlight + || raw != newParams.raw + || retinex != newParams.retinex + || dirpyrequalizer != newParams.dirpyrequalizer; +} + PartialProfile::PartialProfile(bool createInstance, bool paramsEditedValue) { if (createInstance) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0b8b5ba56..db89754a7 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1488,6 +1488,9 @@ public: bool operator ==(const ProcParams& other) const; bool operator !=(const ProcParams& other) const; + bool isThumbRelatedChange(const ProcParams &newParams) const; + bool isPanningRelatedChange(const ProcParams &newParams) const; + private: /** Write the ProcParams's text in the file of the given name. * @param fname the name of the file diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index bfb1b8797..88cabe19d 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -37,7 +37,7 @@ using namespace rtengine::procparams; Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(nullptr), - pparamsValid(false), needsReProcessing(true), imageLoading(false), lastImg(nullptr), + pparamsValid(false), imageLoading(false), lastImg(nullptr), lastW(0), lastH(0), lastScale(0), initial_(false) { @@ -65,7 +65,7 @@ Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageDa Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) : fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(nullptr), pparamsValid(false), - needsReProcessing(true), imageLoading(false), lastImg(nullptr), + imageLoading(false), lastImg(nullptr), lastW(0), lastH(0), lastScale(0.0), initial_(true) { @@ -155,7 +155,6 @@ void Thumbnail::_generateThumbnailImage () tpp->getAutoWBMultipliers(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul); _saveThumbnail (); cfs.supported = true; - needsReProcessing = true; cfs.save (getCacheFileName ("data", ".txt")); @@ -368,7 +367,6 @@ void Thumbnail::clearProcParams (int whoClearedIt) cfs.recentlySaved = false; pparamsValid = false; - needsReProcessing = true; //TODO: run though customprofilebuilder? // probably not as this is the only option to set param values to default @@ -413,7 +411,7 @@ void Thumbnail::clearProcParams (int whoClearedIt) } } -bool Thumbnail::hasProcParams () +bool Thumbnail::hasProcParams () const { return pparamsValid; @@ -421,26 +419,21 @@ bool Thumbnail::hasProcParams () void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoChangedIt, bool updateCacheNow) { - + const bool needsReprocessing = pparams.isThumbRelatedChange(pp); { MyMutex::MyLock lock(mutex); - if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble()) { - printf("WARNING: Sharpening different!\n"); - } - - if (pparams.vibrance.psthreshold.isDouble() != pp.vibrance.psthreshold.isDouble()) { - printf("WARNING: Vibrance different!\n"); - } - if (pparams != pp) { cfs.recentlySaved = false; + } else if (pparamsValid && !updateCacheNow) { + // nothing to do + return; } // do not update rank, colorlabel and inTrash - int rank = getRank(); - int colorlabel = getColorLabel(); - int inTrash = getStage(); + const int rank = getRank(); + const int colorlabel = getColorLabel(); + const int inTrash = getStage(); if (pe) { pe->combine(pparams, pp, true); @@ -449,24 +442,24 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh } pparamsValid = true; - needsReProcessing = true; setRank(rank); setColorLabel(colorlabel); setStage(inTrash); if (updateCacheNow) { - updateCache (); + updateCache(); } - } // end of mutex lock - for (size_t i = 0; i < listeners.size(); i++) { - listeners[i]->procParamsChanged (this, whoChangedIt); + if (needsReprocessing) { + for (size_t i = 0; i < listeners.size(); i++) { + listeners[i]->procParamsChanged (this, whoChangedIt); + } } } -bool Thumbnail::isRecentlySaved () +bool Thumbnail::isRecentlySaved () const { return cfs.recentlySaved; @@ -495,17 +488,17 @@ void Thumbnail::imageRemovedFromQueue () enqueueNumber--; } -bool Thumbnail::isEnqueued () +bool Thumbnail::isEnqueued () const { return enqueueNumber > 0; } -bool Thumbnail::isPixelShift () +bool Thumbnail::isPixelShift () const { return cfs.isPixelShift; } -bool Thumbnail::isHDR () +bool Thumbnail::isHDR () const { return cfs.isHDR; } @@ -694,13 +687,13 @@ void Thumbnail::generateExifDateTimeStrings () dateTimeString = ostr.str (); } -const Glib::ustring& Thumbnail::getExifString () +const Glib::ustring& Thumbnail::getExifString () const { return exifString; } -const Glib::ustring& Thumbnail::getDateTimeString () +const Glib::ustring& Thumbnail::getDateTimeString () const { return dateTimeString; @@ -798,7 +791,6 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetCamWB (temp, green); @@ -143,7 +142,7 @@ public: } ThFileType getType (); - Glib::ustring getFileName () + Glib::ustring getFileName () const { return fname; } @@ -155,12 +154,12 @@ public: { return &cfs; } - std::string getMD5 () + std::string getMD5 () const { return cfs.md5; } - int getRank () + int getRank () const { return pparams.rank; } @@ -172,7 +171,7 @@ public: } } - int getColorLabel () + int getColorLabel () const { return pparams.colorlabel; } @@ -184,7 +183,7 @@ public: } } - int getStage () + int getStage () const { return pparams.inTrash; }