From b6f8bc675b3d6a6c8fe0c8922f41a1c4baca8156 Mon Sep 17 00:00:00 2001 From: torger Date: Mon, 6 Jul 2015 10:26:29 +0200 Subject: [PATCH] Issue 2739: DCP looktable and curve now applied after exposure, plus fixed some premature clipping issues --- rtdata/languages/default | 9 ++ rtengine/dcp.cc | 154 ++++++++++++++++++++++++++-------- rtengine/dcp.h | 19 ++++- rtengine/dcrop.cc | 3 +- rtengine/imagesource.h | 2 + rtengine/improccoordinator.cc | 6 +- rtengine/improcfun.cc | 81 ++++++++++++++++-- rtengine/improcfun.h | 5 +- rtengine/procevents.h | 3 + rtengine/procparams.cc | 14 +++- rtengine/procparams.h | 3 + rtengine/rawimagesource.cc | 32 ++++--- rtengine/rawimagesource.h | 7 +- rtengine/refreshmap.cc | 7 +- rtengine/rtthumbnail.cc | 12 ++- rtengine/simpleprocess.cc | 5 +- rtgui/icmpanel.cc | 139 ++++++++++++++++++++++++++++-- rtgui/icmpanel.h | 12 +++ rtgui/paramsedited.h | 3 + rtgui/ppversion.h | 2 +- 20 files changed, 443 insertions(+), 75 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 3c1aabd28..94e33f04b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -622,6 +622,9 @@ HISTORY_MSG_389;W - Residual - CB blue mid HISTORY_MSG_390;W - Residual - CB green low HISTORY_MSG_391;W - Residual - CB blue low HISTORY_MSG_392;W - Residual - CB Reset +HISTORY_MSG_393;Use DCP's look table +HISTORY_MSG_394;Use DCP's baseline exposure offset +HISTORY_MSG_395;Use DCP's base table HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -1449,6 +1452,12 @@ TP_HSVEQUALIZER_HUE;H TP_HSVEQUALIZER_LABEL;HSV Equalizer TP_HSVEQUALIZER_SAT;S TP_HSVEQUALIZER_VAL;V +TP_ICM_APPLYBASELINEEXPOSUREOFFSET;Use DCP's baseline exposure offset +TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP;Employ the embedded DCP baseline exposure offset. The setting is only enabled if the selected DCP has any. +TP_ICM_APPLYHUESATMAP;Use DCP's base table +TP_ICM_APPLYHUESATMAP_TOOLTIP;Employ the embedded DCP base table (HueSatMap). The setting is only enabled if the selected DCP has one. +TP_ICM_APPLYLOOKTABLE;Use DCP's look table +TP_ICM_APPLYLOOKTABLE_TOOLTIP;Employ the embedded DCP look table. The setting is only enabled if the selected DCP has one. TP_ICM_BLENDCMSMATRIX;Blend ICC highlights with matrix TP_ICM_BLENDCMSMATRIX_TOOLTIP;Enable to recover clipped highlights when using LUT-based ICC profiles. TP_ICM_DCPILLUMINANT;Illuminant diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 20d0a389c..a4eadea1d 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -490,7 +490,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779; const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant const int TagProfileHueSatMapEncoding=51107, TagProfileLookTableEncoding=51108; - const int TagProfileToneCurve=50940; + const int TagProfileToneCurve=50940, TagBaselineExposureOffset=51109; aDeltas1=aDeltas2=aLookTable=NULL; @@ -511,6 +511,8 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { hasColorMatrix1 = false; hasColorMatrix2 = false; hasToneCurve = false; + hasBaselineExposureOffset = false; + baselineExposureOffset = 0; tag = tagDir->getTag(TagForwardMatrix1); if (tag) { hasForwardMatrix1 = true; @@ -628,6 +630,12 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { } } + tag = tagDir->getTag(TagBaselineExposureOffset); + if (tag) { + hasBaselineExposureOffset = true; + baselineExposureOffset = tag->toDouble(); + } + // Read tone curve points, if any, but disable to RTs own profiles // the DCP tone curve is subjective and of low quality in comparison to RTs tone curves tag = tagDir->getTag(TagProfileToneCurve); @@ -683,7 +691,9 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { } DCPProfile::~DCPProfile() { - delete[] aDeltas1; delete[] aDeltas2; + delete[] aDeltas1; + delete[] aDeltas2; + delete[] aLookTable; } void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, const float hs, const float ss, const float vs, float &h, float &s, float &v) const { @@ -1025,7 +1035,7 @@ void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, XY[1] = lastXY[1]; } -void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], float rawWhiteFac, bool useToneCurve) const { +void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], float rawWhiteFac, bool useToneCurve, bool applyHueSatMap, bool applyLookTable) const { TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); @@ -1033,10 +1043,12 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); HSBModify *deleteTableHandle; const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle); + if (!deltaBase) applyHueSatMap = false; + if (!aLookTable) applyLookTable = false; useToneCurve&=toneCurve; - if (deltaBase == NULL && aLookTable == NULL && !useToneCurve) { + if (!applyHueSatMap && !applyLookTable && !useToneCurve) { //===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; for (int i=0; i<3; i++) @@ -1083,7 +1095,7 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring newb = m2ProPhoto[2][0]*pImg->r(y,x) + m2ProPhoto[2][1]*pImg->g(y,x) + m2ProPhoto[2][2]*pImg->b(y,x); // if point is in negative area, just the matrix, but not the LUT - if ((deltaBase || aLookTable) && newr>=0 && newg>=0 && newb>=0) { + if ((applyHueSatMap || applyLookTable) && newr>=0 && newg>=0 && newb>=0) { Color::rgb2hsv(newr, newg, newb, h , s, v); h*=6.f; // RT calculates in [0,1] @@ -1095,11 +1107,11 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring hs=h; ss=s; vs=v; } - if (deltaBase) { + if (applyHueSatMap) { HSDApply(DeltaInfo, deltaBase, hs, ss, vs, h, s, v); hs=h; ss=s; vs=v; } - if (aLookTable) { + if (applyLookTable) { HSDApply(LookInfo, aLookTable, hs, ss, vs, h, s, v); } @@ -1122,39 +1134,115 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring if (deleteTableHandle) delete[] deleteTableHandle; } -// Integer variant is legacy, only used for thumbs. Simply take the matrix here -void DCPProfile::Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve) const { - TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); +void DCPProfile::setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure) { - double mXYZCAM[3][3]; - MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); + applyState.useToneCurve = useToneCurve; + applyState.applyLookTable = applyLookTable; + applyState.blScale = 1.0; + if (!aLookTable) applyState.applyLookTable = false; + if (!hasToneCurve) applyState.useToneCurve = false; + if (hasBaselineExposureOffset && applyBaselineExposure) { + applyState.blScale = powf(2, baselineExposureOffset); + } - useToneCurve&=toneCurve; + if (workingSpace == "ProPhoto") { + applyState.alreadyProPhoto = true; + } else { + applyState.alreadyProPhoto = false; + TMatrix mWork; - // Calculate matrix for direct conversion raw>working space - double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - for (int k=0; k<3; k++) - mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; + mWork = iccStore->workingSpaceMatrix (workingSpace); + memset(applyState.m2ProPhoto, 0, sizeof(applyState.m2ProPhoto)); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + applyState.m2ProPhoto[i][j] += prophoto_xyz[i][k] * mWork[k][j]; - // Apply the matrix part -#pragma omp parallel for - for (int y=0; yheight; y++) { - float newr, newg, newb; - for (int x=0; xwidth; x++) { - newr = mat[0][0]*pImg->r(y,x) + mat[0][1]*pImg->g(y,x) + mat[0][2]*pImg->b(y,x); - newg = mat[1][0]*pImg->r(y,x) + mat[1][1]*pImg->g(y,x) + mat[1][2]*pImg->b(y,x); - newb = mat[2][0]*pImg->r(y,x) + mat[2][1]*pImg->g(y,x) + mat[2][2]*pImg->b(y,x); - - // tone curve - if (useToneCurve) toneCurve.Apply(newr, newg, newb); - - pImg->r(y,x) = CLIP((int)newr); pImg->g(y,x) = CLIP((int)newg); pImg->b(y,x) = CLIP((int)newb); - } + mWork = iccStore->workingSpaceInverseMatrix (workingSpace); + memset(applyState.m2Work, 0, sizeof(applyState.m2Work)); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + applyState.m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; } } +void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int height, int tileWidth, float exp_scale) const { + +#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) +#define CLIP01(a) ((a)>0?((a)<1?(a):1):0) + + exp_scale *= applyState.blScale; + if (!applyState.useToneCurve && !applyState.applyLookTable) { + if (exp_scale == 1.0) { + return; + } + for (int y=0; y= 6.0f) h -= 6.0f; + h/=6.f; + Color::hsv2rgb( h, s, v, newr, newg, newb); + } + if (applyState.useToneCurve) { + toneCurve.Apply(newr, newg, newb); + } + + if (applyState.alreadyProPhoto) { + rc[y*tileWidth+x] = newr; + gc[y*tileWidth+x] = newg; + bc[y*tileWidth+x] = newb; + } else { + rc[y*tileWidth+x] = applyState.m2Work[0][0]*newr + applyState.m2Work[0][1]*newg + applyState.m2Work[0][2]*newb; + gc[y*tileWidth+x] = applyState.m2Work[1][0]*newr + applyState.m2Work[1][1]*newg + applyState.m2Work[1][2]*newb; + bc[y*tileWidth+x] = applyState.m2Work[2][0]*newr + applyState.m2Work[2][1]*newg + applyState.m2Work[2][2]*newb; + } + } + } + } +} // Generates as singleton DCPStore* DCPStore::getInstance() diff --git a/rtengine/dcp.h b/rtengine/dcp.h index ad9a936d7..1e160eb15 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -51,14 +51,23 @@ namespace rtengine { }; double mColorMatrix1[3][3],mColorMatrix2[3][3]; - bool hasColorMatrix1, hasColorMatrix2, hasForwardMatrix1, hasForwardMatrix2, hasToneCurve, willInterpolate; + bool hasColorMatrix1, hasColorMatrix2, hasForwardMatrix1, hasForwardMatrix2, hasToneCurve, hasBaselineExposureOffset, willInterpolate; double mForwardMatrix1[3][3],mForwardMatrix2[3][3]; double temperature1, temperature2; + double baselineExposureOffset; HSBModify *aDeltas1,*aDeltas2,*aLookTable; HSDTableInfo DeltaInfo,LookInfo; short iLightSource1,iLightSource2; AdobeToneCurve toneCurve; + struct { + double m2ProPhoto[3][3]; + double m2Work[3][3]; + bool alreadyProPhoto; + bool useToneCurve; + bool applyLookTable; + float blScale; + } applyState; void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const; @@ -72,9 +81,13 @@ namespace rtengine { ~DCPProfile(); bool getHasToneCurve() { return hasToneCurve; } + bool getHasLookTable() { return !!aLookTable; } + bool getHasHueSatMap() { return !!aDeltas1; } + bool getHasBaselineExposureOffset() { return hasBaselineExposureOffset; } void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) { i1 = iLightSource1; i2 = iLightSource2; temp1 = temperature1, temp2 = temperature2; willInterpolate_ = willInterpolate; }; - void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], float rawWhiteFac=1, bool useToneCurve=false) const; - void Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve) const; + void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], float rawWhiteFac=1, bool useToneCurve=false, bool applyHueSatMap=true, bool applyLookTable=false) const; + void setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure); + void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth, float exp_scale) const; }; class DCPStore { diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 7220cfcd5..e096bcb36 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -597,10 +597,11 @@ void Crop::update (int todo) { if (todo & M_RGBCURVE) { double rrm, ggm, bbm; + DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB); parent->ipf.rgbProc (baseCrop, laboCrop, this, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap, params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, satLimit ,satLimitOpacity, parent->ctColorCurve, parent->ctOpacityCurve, parent->opautili, parent->clToningcurve,parent->cl2Toningcurve, parent->customToneCurve1, parent->customToneCurve2, parent->beforeToneCurveBW, parent->afterToneCurveBW,rrm, ggm, bbm, - parent->bwAutoR, parent->bwAutoG, parent->bwAutoB); + parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf); } /*xref=000;yref=000; if (colortest && cropw>115 && croph>115) diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index b2d3b74b9..4909e5169 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -25,6 +25,7 @@ #include "colortemp.h" #include "procparams.h" #include "coord2d.h" +#include "dcp.h" #include "LUT.h" #include "imagedata.h" #include "image8.h" @@ -94,6 +95,7 @@ class ImageSource : public InitialImage { virtual ImageData* getImageData () =0; virtual ImageMatrices* getImageMatrices () =0; virtual bool isRAW() const =0; + virtual DCPProfile* getDCP(ColorManagementParams cmp, ColorTemp &wb) { return NULL; }; virtual void setProgressListener (ProgressListener* pl) {} diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index a0d643205..73078f7c1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -356,7 +356,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { //complexCurve also calculated pre-curves histogram depending on crop ipf.g = imgsrc->getGamma(); ipf.iGamma = true; - CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, + CurveFactory::complexCurve (/*params.toneCurve.expcomp*/ 0.0, params.toneCurve.black/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, @@ -433,8 +433,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { double rrm=33.; double ggm=33.; double bbm=33.; + + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB); ipf.rgbProc (oprevi, oprevl, NULL, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, - rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2,beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); + rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, 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); 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); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 27eca0f82..6d26589ba 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2186,19 +2186,55 @@ float mo=0.f; } +static inline void +filmlike_clip_rgb_tone(float *r, float *g, float *b, const float L) +{ + float r_ = *r > L ? L : *r; + float b_ = *b > L ? L : *b; + float g_ = b_ + ((r_ - b_) * (*g - *b) / (*r - *b)); + *r = r_; + *g = g_; + *b = b_; +} - +static void +filmlike_clip(float *r, float *g, float *b) +{ + // This is Adobe's hue-stable film-like curve with a diagonal, ie only used for clipping. Can probably be further optimized. + const float L = 65535.0; + if (*r >= *g) { + if (*g > *b) { // Case 1: r >= g > b + filmlike_clip_rgb_tone(r, g, b, L); + } else if (*b > *r) { // Case 2: b > r >= g + filmlike_clip_rgb_tone(b, r, g, L); + } else if (*b > *g) { // Case 3: r >= b > g + filmlike_clip_rgb_tone(r, b, g, L); + } else { // Case 4: r >= g == b + *r = *r > L ? L : *r; + *g = *g > L ? L : *g; + *b = *g; + } + } else { + if (*r >= *b) { // Case 5: g > r >= b + filmlike_clip_rgb_tone(g, r, b, L); + } else if (*b > *g) { // Case 6: b > g > r + filmlike_clip_rgb_tone(b, g, r, L); + } else { // Case 7: g >= b > r + filmlike_clip_rgb_tone(g, b, r, L); + } + } +} void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit ,float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve,LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1,const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob ) { - rgbProc (working, lab, editBuffer, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve,customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh); + const ToneCurve & customToneCurve1,const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf ) { + rgbProc (working, lab, editBuffer, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve,customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf); } // Process RGB image and convert to LAB space void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit ,float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve,LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2,double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh) { + const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2,double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf) { LUTf iGammaLUTf; Imagefloat *tmpImage=NULL; @@ -2592,9 +2628,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e //TODO: proper treatment of out-of-gamut colors //float tonefactor = hltonecurve[(0.299f*r+0.587f*g+0.114f*b)]; - float tonefactor=((rstep2ApplyTile(rtemp, gtemp, btemp, tW-jstart, tH-istart, TS, exp_scale); + } + for (int i=istart,ti=0; i 65535 || g > 65535 || b > 65535) { + filmlike_clip(&r, &g, &b); + } + + rtemp[ti*TS+tj] = r; + gtemp[ti*TS+tj] = g; + btemp[ti*TS+tj] = b; + } + } + for (int i=istart,ti=0; iicm.input) keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input)); if (!pedited || pedited->icm.toneCurve) keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve); + if (!pedited || pedited->icm.applyLookTable) keyFile.set_boolean ("Color Management", "ApplyLookTable", icm.applyLookTable); + if (!pedited || pedited->icm.applyBaselineExposureOffset) keyFile.set_boolean ("Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset); + if (!pedited || pedited->icm.applyHueSatMap) keyFile.set_boolean ("Color Management", "ApplyHueSatMap", icm.applyHueSatMap); if (!pedited || pedited->icm.blendCMSMatrix) keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); if (!pedited || pedited->icm.dcpIlluminant) keyFile.set_integer ("Color Management", "DCPIlluminant", icm.dcpIlluminant); if (!pedited || pedited->icm.working) keyFile.set_string ("Color Management", "WorkingProfile", icm.working); @@ -2501,6 +2507,9 @@ if (keyFile.has_group ("PostResizeSharpening")) { if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = expandRelativePath(fname, "file:", keyFile.get_string ("Color Management", "InputProfile")); if (pedited) pedited->icm.input = true; } if (keyFile.has_key ("Color Management", "ToneCurve")) { icm.toneCurve = keyFile.get_boolean ("Color Management", "ToneCurve"); if (pedited) pedited->icm.toneCurve = true; } + if (keyFile.has_key ("Color Management", "ApplyLookTable")) { icm.applyLookTable = keyFile.get_boolean ("Color Management", "ApplyLookTable"); if (pedited) pedited->icm.applyLookTable = true; } + if (keyFile.has_key ("Color Management", "ApplyBaselineExposureOffset")) { icm.applyBaselineExposureOffset = keyFile.get_boolean ("Color Management", "ApplyBaselineExposureOffset"); if (pedited) pedited->icm.applyBaselineExposureOffset = true; } + if (keyFile.has_key ("Color Management", "ApplyHueSatMap")) { icm.applyHueSatMap = keyFile.get_boolean ("Color Management", "ApplyHueSatMap"); if (pedited) pedited->icm.applyHueSatMap = true; } if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) { icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (pedited) pedited->icm.blendCMSMatrix = true; } if (keyFile.has_key ("Color Management", "DCPIlluminant")) { icm.dcpIlluminant = keyFile.get_integer ("Color Management", "DCPIlluminant"); if (pedited) pedited->icm.dcpIlluminant = true; } if (keyFile.has_key ("Color Management", "WorkingProfile")) { icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (pedited) pedited->icm.working = true; } @@ -3175,6 +3184,9 @@ bool ProcParams::operator== (const ProcParams& other) { && raw.hotdeadpix_thresh == other.raw.hotdeadpix_thresh && icm.input == other.icm.input && icm.toneCurve == other.icm.toneCurve + && icm.applyLookTable == other.icm.applyLookTable + && icm.applyBaselineExposureOffset == other.icm.applyBaselineExposureOffset + && icm.applyHueSatMap == other.icm.applyHueSatMap && icm.blendCMSMatrix == other.icm.blendCMSMatrix && icm.dcpIlluminant == other.icm.dcpIlluminant && icm.working == other.icm.working diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 746e33001..8d05a7f3a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -828,6 +828,9 @@ class ColorManagementParams { public: Glib::ustring input; bool toneCurve; + bool applyLookTable; + bool applyBaselineExposureOffset; + bool applyHueSatMap; bool blendCMSMatrix; // setting no longer used int dcpIlluminant; Glib::ustring working; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 73a822b49..1d091b6cd 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -310,9 +310,10 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre gm/=area; bm/=area; - hlmax[0]=chmax[0]*rm*area; - hlmax[1]=chmax[1]*gm*area; - hlmax[2]=chmax[2]*bm*area; + // raw clip levels after white balance + hlmax[0]=65535 * rm / min(rm, gm, bm); + hlmax[1]=65535 * gm / min(rm, gm, bm); + hlmax[2]=65535 * bm / min(rm, gm, bm); #ifdef _OPENMP @@ -344,7 +345,7 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre rtot*=rm; gtot*=gm; btot*=bm; - if (!hrp.hrenabled) + if (!hrp.hrenabled && (rtot > hlmax[0] || gtot > hlmax[1] || btot > hlmax[2])) { rtot=CLIP(rtot); gtot=CLIP(gtot); @@ -368,7 +369,7 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre rtot*=rm; gtot*=gm; btot*=bm; - if (!hrp.hrenabled) + if (!hrp.hrenabled && (rtot > hlmax[0] || gtot > hlmax[1] || btot > hlmax[2])) { rtot=CLIP(rtot); gtot=CLIP(gtot); @@ -456,6 +457,17 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre //colorSpaceConversion (image, cmp, raw, embProfile, camProfile, xyz_cam, (static_cast(getMetaData()))->getCamera()); } +DCPProfile *RawImageSource::getDCP(ColorManagementParams cmp, ColorTemp &wb) { + DCPProfile *dcpProf = NULL; + cmsHPROFILE dummy; + findInputProfile(cmp.input, NULL, (static_cast(getMetaData()))->getCamera(), &dcpProf, dummy); + if (dcpProf == NULL) { + return NULL; + } + dcpProf->setStep2ApplyState(cmp.working, cmp.toneCurve, cmp.applyLookTable, cmp.applyBaselineExposureOffset); + return dcpProf; +} + void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb, RAWParams raw) { double pre_mul[3] = { ri->get_pre_mul(0), ri->get_pre_mul(1), ri->get_pre_mul(2) }; colorSpaceConversion (image, cmp, wb, pre_mul, raw, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); @@ -2420,7 +2432,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam if (dcpProf!=NULL) { // DCP processing - dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, raw.expos, cmp.toneCurve); + dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, raw.expos, false, cmp.applyHueSatMap, false); return; } @@ -2845,7 +2857,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // derived from Dcraw "blend_highlights()" // very effective to reduce (or remove) the magenta, but with levels of grey ! -void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int width, float maxval, float* pre_mul, const RAWParams &raw, float* hlmax) +void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int width, float maxval, float* hlmax) { const int ColorCount=3; @@ -3054,10 +3066,8 @@ void RawImageSource::hlRecovery (std::string method, float* red, float* green, f HLRecovery_CIELab (red, green, blue, red, green, blue, width, 65535.0, imatrices.xyz_cam, imatrices.cam_xyz); /*else if (method=="Color") HLRecovery_ColorPropagation (red, green, blue, i, sx1, width, skip);*/ - else if (method=="Blend") // derived from Dcraw - { float pre_mul[4]; - for(int c=0;c<4;c++) pre_mul[c]=ri->get_pre_mul(c); - HLRecovery_blend(red, green, blue, width, 65535.0, pre_mul, raw, hlmax );} + else if (method=="Blend") // derived from Dcraw + HLRecovery_blend(red, green, blue, width, 65535.0, hlmax); } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index f711509bb..f8fba0958 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -63,7 +63,6 @@ class RawImageSource : public ImageSource { static DiagonalCurve *phaseOneIccCurveInv; static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); - static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); static void colorSpaceConversion_ (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, double pre_mul[3], const RAWParams &raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); protected: @@ -176,8 +175,10 @@ class RawImageSource : public ImageSource { void setProgressListener (ProgressListener* pl) { plistener = pl; } void getAutoExpHistogram (LUTu & histogram, int& histcompr); void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); - + DCPProfile *getDCP(ColorManagementParams cmp, ColorTemp &wb); + void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb, RAWParams raw); + static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, ColorTemp &wb, double pre_mul[3], RAWParams raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) { colorSpaceConversion_ (im, cmp, wb, pre_mul, raw, embedded, camprofile, cam, camName); } @@ -193,7 +194,7 @@ class RawImageSource : public ImageSource { static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]); - static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* pre_mul, const RAWParams &raw, float* hlmax); + static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax); static void init (); static void cleanup (); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 8598b87f7..ecbec5ff2 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -67,7 +67,7 @@ RGBCURVE, // EvToneCurveMode2, 0, // EvLDNEdgeTolerance: obsolete, 0, // EvCDNEnabled:obsolete, ALL, // EvBlendCMSMatrix, -ALL, // EvDCPToneCurve, +RGBCURVE, // EvDCPToneCurve, ALL, // EvDCPIlluminant, RETINEX, // EvSHEnabled, RGBCURVE, // EvSHHighlights, @@ -413,7 +413,10 @@ DIRPYREQUALIZER, // EvWavgreenmed DIRPYREQUALIZER, // EvWavbluemed DIRPYREQUALIZER, // EvWavgreenlow DIRPYREQUALIZER, // EvWavbluelow -DIRPYREQUALIZER // EvWavNeutral +DIRPYREQUALIZER, // EvWavNeutral +RGBCURVE, // EvDCPApplyLookTable, +RGBCURVE, // EvDCPApplyBaselineExposureOffset, +ALL // EvDCPApplyHueSatMap }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index d5f3f86bf..8c2c232e3 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -912,7 +912,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ipf.g = gamma; ipf.iGamma = true; - CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, + CurveFactory::complexCurve (0.0, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, @@ -966,7 +966,15 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei autor = autog = autob = -9000.f; // This will ask to compute the "auto" values for the B&W tool LabImage* labView = new LabImage (fw,fh); - ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh); + DCPProfile *dcpProf = NULL; + if (isRaw) { + cmsHPROFILE dummy; + RawImageSource::findInputProfile(params.icm.input, NULL, camName, &dcpProf, dummy); + if (dcpProf != NULL) { + dcpProf->setStep2ApplyState(params.icm.working, params.icm.toneCurve, params.icm.applyLookTable, params.icm.applyBaselineExposureOffset); + } + } + ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf); // freeing up some memory customToneCurve1.Reset(); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index e4a54d0fb..657b746b1 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -608,7 +608,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p ipf.g = imgsrc->getGamma(); ipf.iGamma = true; - CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, + CurveFactory::complexCurve (0.0, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); @@ -660,7 +660,8 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) - ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve,customToneCurve1, customToneCurve2,customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh); + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB); + ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit ,satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve,customToneCurve1, customToneCurve2,customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf); if (settings->verbose) printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index b48e5d96c..f6f4068ca 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -32,7 +32,7 @@ extern Options options; ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunchanged(NULL), icmplistener(NULL), lastRefFilename("") { - isBatchMode = lastToneCurve = lastBlendCMSMatrix = lastgamfree = false; + isBatchMode = lastToneCurve = lastApplyLookTable = lastApplyBaselineExposureOffset = lastApplyHueSatMap = lastBlendCMSMatrix = lastgamfree = false; ipDialog = Gtk::manage (new MyFileChooserButton (M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); ipDialog->set_tooltip_text (M("TP_ICM_INPUTCUSTOM_TOOLTIP")); @@ -98,10 +98,34 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch hb->pack_start(*dcpIll); iVBox->pack_start (*hb, Gtk::PACK_SHRINK, 2); + Gtk::VBox* c1VBox = Gtk::manage ( new Gtk::VBox()); + Gtk::VBox* c2VBox = Gtk::manage ( new Gtk::VBox()); + ckbToneCurve = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_TONECURVE"))); ckbToneCurve->set_sensitive (false); ckbToneCurve->set_tooltip_text (M("TP_ICM_TONECURVE_TOOLTIP")); - iVBox->pack_start (*ckbToneCurve, Gtk::PACK_SHRINK, 2); + c1VBox->pack_start (*ckbToneCurve, Gtk::PACK_SHRINK, 2); + + ckbApplyLookTable = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYLOOKTABLE"))); + ckbApplyLookTable->set_sensitive (false); + ckbApplyLookTable->set_tooltip_text (M("TP_ICM_APPLYLOOKTABLE_TOOLTIP")); + c1VBox->pack_start (*ckbApplyLookTable, Gtk::PACK_SHRINK, 2); + + ckbApplyHueSatMap = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYHUESATMAP"))); + ckbApplyHueSatMap->set_sensitive (false); + ckbApplyHueSatMap->set_tooltip_text (M("TP_ICM_APPLYHUESATMAP_TOOLTIP")); + c2VBox->pack_start (*ckbApplyHueSatMap, Gtk::PACK_SHRINK, 2); + + ckbApplyBaselineExposureOffset = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYBASELINEEXPOSUREOFFSET"))); + ckbApplyBaselineExposureOffset->set_sensitive (false); + ckbApplyBaselineExposureOffset->set_tooltip_text (M("TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP")); + c2VBox->pack_start (*ckbApplyBaselineExposureOffset, Gtk::PACK_SHRINK, 2); + + Gtk::HBox* dcpHBox = Gtk::manage (new Gtk::HBox ()); + dcpHBox->show (); + dcpHBox->pack_start (*c1VBox, Gtk::PACK_EXPAND_WIDGET, 2); + dcpHBox->pack_start (*c2VBox, Gtk::PACK_EXPAND_WIDGET, 2); + iVBox->pack_start (*dcpHBox, Gtk::PACK_SHRINK, 2); ckbBlendCMSMatrix = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_BLENDCMSMATRIX"))); ckbBlendCMSMatrix->set_sensitive (false); @@ -247,6 +271,9 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch gamcsconn = freegamma->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::GamChanged)); tcurveconn = ckbToneCurve->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::toneCurveChanged)); + ltableconn = ckbApplyLookTable->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::applyLookTableChanged)); + beoconn = ckbApplyBaselineExposureOffset->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::applyBaselineExposureOffsetChanged)); + hsmconn = ckbApplyHueSatMap->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::applyHueSatMapChanged)); blendcmsconn = ckbBlendCMSMatrix->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::blendCMSMatrixChanged)); icamera->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); @@ -264,6 +291,9 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) { if (isBatchMode) { ckbToneCurve->set_sensitive (true); + ckbApplyLookTable->set_sensitive (true); + ckbApplyBaselineExposureOffset->set_sensitive (true); + ckbApplyHueSatMap->set_sensitive (true); dcpIllLabel->set_sensitive (true); dcpIll->set_sensitive (true); if (dcpTemperatures[0] != 0 || dcpTemperatures[1] != 0) { @@ -289,6 +319,9 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) { return; } ckbToneCurve->set_sensitive (false); + ckbApplyLookTable->set_sensitive (false); + ckbApplyBaselineExposureOffset->set_sensitive (false); + ckbApplyHueSatMap->set_sensitive (false); dcpIllLabel->set_sensitive (false); dcpIll->set_sensitive (false); if (ifromfile->get_active() && dcpStore->isValidDCPFileName(dcp_name)) { @@ -296,8 +329,15 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) { if (dcp) { if (dcp->getHasToneCurve()) { ckbToneCurve->set_sensitive (true); - } else { - ckbToneCurve->set_active (false); + } + if (dcp->getHasLookTable()) { + ckbApplyLookTable->set_sensitive (true); + } + if (dcp->getHasBaselineExposureOffset()) { + ckbApplyBaselineExposureOffset->set_sensitive (true); + } + if (dcp->getHasHueSatMap()) { + ckbApplyHueSatMap->set_sensitive (true); } int i1, i2; double temp1, temp2; @@ -367,6 +407,9 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { ipc.block (true); gamcsconn.block (true); tcurveconn.block(true); + ltableconn.block(true); + beoconn.block(true); + hsmconn.block(true); blendcmsconn.block(true); if(pp->icm.input.substr(0,5) != "file:" && !ipDialog->get_filename().empty()) @@ -426,6 +469,12 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { ckbToneCurve->set_active (pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; + ckbApplyLookTable->set_active (pp->icm.applyLookTable); + lastApplyLookTable = pp->icm.applyLookTable; + ckbApplyBaselineExposureOffset->set_active (pp->icm.applyBaselineExposureOffset); + lastApplyBaselineExposureOffset = pp->icm.applyBaselineExposureOffset; + ckbApplyHueSatMap->set_active (pp->icm.applyHueSatMap); + lastApplyHueSatMap = pp->icm.applyHueSatMap; ckbBlendCMSMatrix->set_active (pp->icm.blendCMSMatrix); lastBlendCMSMatrix = pp->icm.blendCMSMatrix; @@ -442,6 +491,9 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { if (pedited) { iunchanged->set_active (!pedited->icm.input); ckbToneCurve->set_inconsistent(!pedited->icm.toneCurve); + ckbApplyLookTable->set_inconsistent(!pedited->icm.applyLookTable); + ckbApplyBaselineExposureOffset->set_inconsistent(!pedited->icm.applyBaselineExposureOffset); + ckbApplyHueSatMap->set_inconsistent(!pedited->icm.applyHueSatMap); ckbBlendCMSMatrix->set_inconsistent(!pedited->icm.blendCMSMatrix); if (!pedited->icm.working) wnames->set_active_text(M("GENERAL_UNCHANGED")); @@ -460,6 +512,9 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { blendcmsconn.block(false); tcurveconn.block(false); + ltableconn.block(false); + beoconn.block(false); + hsmconn.block(false); gamcsconn.block (false); ipc.block (false); @@ -496,7 +551,24 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) { else pp->icm.output = onames->get_active_text(); pp->icm.freegamma = freegamma->get_active(); - pp->icm.toneCurve = ckbToneCurve->get_active (); + + if (ifromfile->get_active() && pp->icm.input.substr(0,5) == "file:" && dcpStore->isValidDCPFileName(pp->icm.input.substr(5))) { + DCPProfile* dcp = dcpStore->getProfile(pp->icm.input.substr(5), false); + if (dcp) { + if (dcp->getHasToneCurve()) { + pp->icm.toneCurve = ckbToneCurve->get_active (); + } + if (dcp->getHasLookTable()) { + pp->icm.applyLookTable = ckbApplyLookTable->get_active (); + } + if (dcp->getHasBaselineExposureOffset()) { + pp->icm.applyBaselineExposureOffset = ckbApplyBaselineExposureOffset->get_active (); + } + if (dcp->getHasHueSatMap()) { + pp->icm.applyHueSatMap = ckbApplyHueSatMap->get_active (); + } + } + } pp->icm.blendCMSMatrix = ckbBlendCMSMatrix->get_active (); pp->icm.gampos =(double) gampos->getValue(); pp->icm.slpos =(double) slpos->getValue(); @@ -507,6 +579,9 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) { pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.dcpIlluminant = dcpIll->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent (); + pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent (); + pedited->icm.applyBaselineExposureOffset = !ckbApplyBaselineExposureOffset->get_inconsistent (); + pedited->icm.applyHueSatMap = !ckbApplyHueSatMap->get_inconsistent (); pedited->icm.blendCMSMatrix = !ckbBlendCMSMatrix->get_inconsistent (); pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.freegamma =!freegamma->get_inconsistent(); @@ -585,6 +660,60 @@ void ICMPanel::toneCurveChanged() { listener->panelChanged (EvDCPToneCurve, ckbToneCurve->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } +void ICMPanel::applyLookTableChanged() { + if (batchMode) { + if (ckbApplyLookTable->get_inconsistent()) { + ckbApplyLookTable->set_inconsistent (false); + ltableconn.block (true); + ckbApplyLookTable->set_active (false); + ltableconn.block (false); + } + else if (lastApplyLookTable) + ckbApplyLookTable->set_inconsistent (true); + + lastApplyLookTable = ckbApplyLookTable->get_active (); + } + + if (listener) + listener->panelChanged (EvDCPApplyLookTable, ckbApplyLookTable->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); +} + +void ICMPanel::applyBaselineExposureOffsetChanged() { + if (batchMode) { + if (ckbApplyBaselineExposureOffset->get_inconsistent()) { + ckbApplyBaselineExposureOffset->set_inconsistent (false); + beoconn.block (true); + ckbApplyBaselineExposureOffset->set_active (false); + beoconn.block (false); + } + else if (lastApplyBaselineExposureOffset) + ckbApplyBaselineExposureOffset->set_inconsistent (true); + + lastApplyBaselineExposureOffset = ckbApplyBaselineExposureOffset->get_active (); + } + + if (listener) + listener->panelChanged (EvDCPApplyBaselineExposureOffset, ckbApplyBaselineExposureOffset->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); +} + +void ICMPanel::applyHueSatMapChanged() { + if (batchMode) { + if (ckbApplyHueSatMap->get_inconsistent()) { + ckbApplyHueSatMap->set_inconsistent (false); + hsmconn.block (true); + ckbApplyHueSatMap->set_active (false); + hsmconn.block (false); + } + else if (lastApplyHueSatMap) + ckbApplyHueSatMap->set_inconsistent (true); + + lastApplyHueSatMap = ckbApplyHueSatMap->get_active (); + } + + if (listener) + listener->panelChanged (EvDCPApplyHueSatMap, ckbApplyHueSatMap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); +} + void ICMPanel::ipChanged () { Glib::ustring profname; diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 99dc96533..b9e2f5786 100755 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -44,6 +44,12 @@ class ICMPanel : public ToolParamBlock, public AdjusterListener, public Foldable //bool freegamma; bool lastToneCurve; sigc::connection tcurveconn; + bool lastApplyLookTable; + sigc::connection ltableconn; + bool lastApplyBaselineExposureOffset; + sigc::connection beoconn; + bool lastApplyHueSatMap; + sigc::connection hsmconn; bool lastBlendCMSMatrix; bool isBatchMode; sigc::connection blendcmsconn; @@ -61,6 +67,9 @@ class ICMPanel : public ToolParamBlock, public AdjusterListener, public Foldable Gtk::Label* dcpIllLabel; MyComboBoxText* dcpIll; Gtk::CheckButton* ckbToneCurve; + Gtk::CheckButton* ckbApplyLookTable; + Gtk::CheckButton* ckbApplyBaselineExposureOffset; + Gtk::CheckButton* ckbApplyHueSatMap; Gtk::CheckButton* ckbBlendCMSMatrix; MyComboBoxText* wnames; MyComboBoxText* wgamma; @@ -101,6 +110,9 @@ class ICMPanel : public ToolParamBlock, public AdjusterListener, public Foldable void blendCMSMatrixChanged(); void dcpIlluminantChanged(); void toneCurveChanged(); + void applyLookTableChanged(); + void applyBaselineExposureOffsetChanged(); + void applyHueSatMapChanged(); void setRawMeta (bool raw, const rtengine::ImageData* pMeta); void saveReferencePressed (); diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 548db1f8c..5697de6cd 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -463,6 +463,9 @@ class ColorManagementParamsEdited { public: bool input; bool toneCurve; + bool applyLookTable; + bool applyBaselineExposureOffset; + bool applyHueSatMap; bool blendCMSMatrix; bool dcpIlluminant; bool working; diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 4f4862067..587b4204f 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -2,7 +2,7 @@ #define _PPVERSION_ // This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 323 +#define PPVERSION 324 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /*