diff --git a/rtdata/languages/default b/rtdata/languages/default
index 41cd18038..de244675e 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -1184,6 +1184,7 @@ HISTORY_MSG_SH_COLORSPACE;S/H - Colorspace
HISTORY_MSG_SOFTLIGHT_ENABLED;Soft light
HISTORY_MSG_SOFTLIGHT_STRENGTH;Soft light - Strength
HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor
+HISTORY_MSG_TRANS_Method;Geometry - Method
HISTORY_NEWSNAPSHOT;Add
HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s
HISTORY_SNAPSHOT;Snapshot
@@ -2182,6 +2183,8 @@ TP_LABCURVE_RSTPRO_TOOLTIP;Works on the Chromaticity slider and the CC curve.
TP_LENSGEOM_AUTOCROP;Auto-Crop
TP_LENSGEOM_FILL;Auto-fill
TP_LENSGEOM_LABEL;Lens / Geometry
+TP_LENSGEOM_LIN;Linear
+TP_LENSGEOM_LOG;Logarithmic
TP_LENSPROFILE_CORRECTION_AUTOMATCH;Automatically selected
TP_LENSPROFILE_CORRECTION_LCPFILE;LCP file
TP_LENSPROFILE_CORRECTION_MANUAL;Manually selected
diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc
index fe982989c..221b5c2eb 100644
--- a/rtengine/dcrop.cc
+++ b/rtengine/dcrop.cc
@@ -174,8 +174,6 @@ void Crop::update(int todo)
int widIm = parent->fw;//full image
int heiIm = parent->fh;
- bool needstransform = parent->ipf.needsTransform();
-
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
MyMutex::MyLock lock(parent->minit); // Also used in improccoord
@@ -767,8 +765,9 @@ void Crop::update(int todo)
}
}
+ const bool needstransform = parent->ipf.needsTransform(skips(parent->fw, skip), skips(parent->fh, skip), parent->imgsrc->getRotateDegree(), parent->imgsrc->getMetaData());
// transform
- if (needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled)) {
+ if (needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled)) {
if (!transCrop) {
transCrop = new Imagefloat(cropw, croph);
}
@@ -785,10 +784,7 @@ void Crop::update(int todo)
baseCrop = transCrop;
}
} else {
- if (transCrop) {
- delete transCrop;
- }
-
+ delete transCrop;
transCrop = nullptr;
}
@@ -1566,41 +1562,42 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter
parent->ipf.transCoord(parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh);
- if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, *parent->params)) {
- // TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise
- int dW = int (double (parent->fw) * 0.15 / (2 * skip));
- int dH = int (double (parent->fh) * 0.15 / (2 * skip));
- int x1 = orx - dW;
- int x2 = orx + orw + dW;
- int y1 = ory - dH;
- int y2 = ory + orh + dH;
+ if (parent->ipf.needsTransform(skips(parent->fw, skip), skips(parent->fh, skip), parent->imgsrc->getRotateDegree(), parent->imgsrc->getMetaData())) {
+ if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, *parent->params)) {
+ // TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise
+ int dW = int (double (parent->fw) * 0.15 / (2 * skip));
+ int dH = int (double (parent->fh) * 0.15 / (2 * skip));
+ int x1 = orx - dW;
+ int x2 = orx + orw + dW;
+ int y1 = ory - dH;
+ int y2 = ory + orh + dH;
- if (x1 < 0) {
- x2 += -x1;
- x1 = 0;
+ if (x1 < 0) {
+ x2 += -x1;
+ x1 = 0;
+ }
+
+ if (x2 > parent->fw) {
+ x1 -= x2 - parent->fw;
+ x2 = parent->fw;
+ }
+
+ if (y1 < 0) {
+ y2 += -y1;
+ y1 = 0;
+ }
+
+ if (y2 > parent->fh) {
+ y1 -= y2 - parent->fh;
+ y2 = parent->fh;
+ }
+
+ orx = max(x1, 0);
+ ory = max(y1, 0);
+ orw = min(x2 - x1, parent->fw - orx);
+ orh = min(y2 - y1, parent->fh - ory);
}
-
- if (x2 > parent->fw) {
- x1 -= x2 - parent->fw;
- x2 = parent->fw;
- }
-
- if (y1 < 0) {
- y2 += -y1;
- y1 = 0;
- }
-
- if (y2 > parent->fh) {
- y1 -= y2 - parent->fh;
- y2 = parent->fh;
- }
-
- orx = max(x1, 0);
- ory = max(y1, 0);
- orw = min(x2 - x1, parent->fw - orx);
- orh = min(y2 - y1, parent->fh - ory);
}
-
leftBorder = skips(rqx1 - bx1, skip);
upperBorder = skips(rqy1 - by1, skip);
diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc
index 7c8aba9b0..b3fd182c5 100644
--- a/rtengine/improccoordinator.cc
+++ b/rtengine/improccoordinator.cc
@@ -654,7 +654,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
oprevi = orig_prev;
// Remove transformation if unneeded
- bool needstransform = ipf.needsTransform();
+ bool needstransform = ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData());
if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled))) {
assert(oprevi);
@@ -1955,7 +1955,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a
imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw);
ImProcFunctions ipf(&ppar, true);
- if (ipf.needsTransform()) {
+ if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) {
Imagefloat* trImg = new Imagefloat(fW, fH);
ipf.transform(im, trImg, 0, 0, 0, 0, fW, fH, fW, fH,
imgsrc->getMetaData(), imgsrc->getRotateDegree(), true);
diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h
index 9b8419ae1..a0e9bd73d 100644
--- a/rtengine/improcfun.h
+++ b/rtengine/improcfun.h
@@ -109,8 +109,8 @@ class ImProcFunctions
void calcVignettingParams(int oW, int oH, const procparams::VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul);
void transformLuminanceOnly(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH);
- void transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap);
- void transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap);
+ void transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap, bool useOriginalBuffer);
+ void transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap, bool useOriginalBuffer);
bool needsCA() const;
bool needsDistortion() const;
@@ -143,7 +143,7 @@ public:
}
void setScale(double iscale);
- bool needsTransform() const;
+ bool needsTransform(int oW, int oH, int rawRotationDeg, const FramesMetaData *metadata) const;
bool needsPCVignetting() const;
float calcGradientFactor (const struct grad_params& gp, int x, int y);
void firstAnalysis(const Imagefloat* const working, const procparams::ProcParams ¶ms, LUTu & vhist16);
@@ -184,7 +184,7 @@ public:
// void colorCurve (LabImage* lold, LabImage* lnew);
void sharpening(LabImage* lab, const procparams::SharpeningParams &sharpenParam, bool showMask = false);
void sharpeningcam(CieImage* ncie, float** buffer, bool showMask = false);
- void transform(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage);
+ void transform(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage, bool useOriginalBuffer = false);
float resizeScale(const procparams::ProcParams* params, int fw, int fh, int &imw, int &imh);
void lab2monitorRgb(LabImage* lab, Image8* image);
void resize(Imagefloat* src, Imagefloat* dst, float dScale);
diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc
index 67507f250..70eadb099 100644
--- a/rtengine/iptransform.cc
+++ b/rtengine/iptransform.cc
@@ -86,6 +86,29 @@ float normn (float a, float b, int n)
}
}
+void logEncode(rtengine::Imagefloat *src, rtengine::Imagefloat *dest, bool multiThread) {
+
+#ifdef _OPENMP
+ #pragma omp parallel for schedule(dynamic, 16) if(multiThread)
+#endif
+
+ for (int y = 0; y < src->getHeight(); ++y) {
+ int x = 0;
+#ifdef __SSE2__
+ for (; x < src->getWidth() - 3; x += 4) {
+ STVFU(dest->r(y, x), xlogf1(LVFU(src->r(y, x))));
+ STVFU(dest->g(y, x), xlogf1(LVFU(src->g(y, x))));
+ STVFU(dest->b(y, x), xlogf1(LVFU(src->b(y, x))));
+ }
+#endif
+ for (; x < src->getWidth(); ++x) {
+ dest->r(y, x) = xlogf1(src->r(y, x));
+ dest->g(y, x) = xlogf1(src->g(y, x));
+ dest->b(y, x) = xlogf1(src->b(y, x));
+ }
+ }
+}
+
#ifdef __SSE2__
inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul)
{
@@ -111,6 +134,33 @@ inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys,
g = vhadd(weight * gv);
b = vhadd(weight * bv);
}
+
+inline void interpolateTransformCubicLog(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul)
+{
+ constexpr float A = -0.85f;
+
+ // Vertical
+ const float t1Vert = A * (Dy - Dy * Dy);
+ const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy;
+ const vfloat w3Vert = F2V(t1Vert * Dy);
+ const vfloat w2Vert = F2V(t1Vert * Dy - t1Vert + t2Vert);
+ const vfloat w1Vert = F2V(1.f - (t1Vert * Dy) - t2Vert);
+ const vfloat w0Vert = F2V(t1Vert - (t1Vert * Dy));
+
+ const vfloat rv = (w0Vert * LVFU(src->r(ys, xs)) + w1Vert * LVFU(src->r(ys + 1, xs))) + (w2Vert * LVFU(src->r(ys + 2, xs)) + w3Vert * LVFU(src->r(ys + 3, xs)));
+ const vfloat gv = (w0Vert * LVFU(src->g(ys, xs)) + w1Vert * LVFU(src->g(ys + 1, xs))) + (w2Vert * LVFU(src->g(ys + 2, xs)) + w3Vert * LVFU(src->g(ys + 3, xs)));
+ const vfloat bv = (w0Vert * LVFU(src->b(ys, xs)) + w1Vert * LVFU(src->b(ys + 1, xs))) + (w2Vert * LVFU(src->b(ys + 2, xs)) + w3Vert * LVFU(src->b(ys + 3, xs)));
+
+ // Horizontal
+ const float t1Hor = A * (Dx - Dx * Dx);
+ const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx;
+ const vfloat weight = _mm_set_ps(t1Hor * Dx, t1Hor * Dx - t1Hor + t2Hor, 1.f - (t1Hor * Dx) - t2Hor, t1Hor - (t1Hor * Dx));
+ const vfloat tempv = _mm_setr_ps(vhadd(weight * rv), vhadd(weight * gv), vhadd(weight * bv), 0.f);
+ const vfloat resultv = xexpf(tempv);
+ r = mul * resultv[0];
+ g = mul * resultv[1];
+ b = mul * resultv[2];
+}
#else
inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul)
{
@@ -143,6 +193,38 @@ inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys,
g = mul * (gv[0] * w0Hor + gv[1] * w1Hor + gv[2] * w2Hor + gv[3] * w3Hor);
b = mul * (bv[0] * w0Hor + bv[1] * w1Hor + bv[2] * w2Hor + bv[3] * w3Hor);
}
+
+inline void interpolateTransformCubicLog(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul)
+{
+ constexpr float A = -0.85f;
+
+ // Vertical
+ const float t1Vert = A * (Dy - Dy * Dy);
+ const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy;
+ const float w3Vert = t1Vert * Dy;
+ const float w2Vert = t1Vert * Dy - t1Vert + t2Vert;
+ const float w1Vert = 1.f - (t1Vert * Dy) - t2Vert;
+ const float w0Vert = t1Vert - (t1Vert * Dy);
+
+ float rv[4], gv[4], bv[4];
+ for (int i = 0; i < 4; ++i) {
+ rv[i] = w0Vert * src->r(ys, xs + i) + w1Vert * src->r(ys + 1, xs + i) + w2Vert * src->r(ys + 2, xs + i) + w3Vert * src->r(ys + 3, xs + i);
+ gv[i] = w0Vert * src->g(ys, xs + i) + w1Vert * src->g(ys + 1, xs + i) + w2Vert * src->g(ys + 2, xs + i) + w3Vert * src->g(ys + 3, xs + i);
+ bv[i] = w0Vert * src->b(ys, xs + i) + w1Vert * src->b(ys + 1, xs + i) + w2Vert * src->b(ys + 2, xs + i) + w3Vert * src->b(ys + 3, xs + i);
+ }
+
+ // Horizontal
+ const float t1Hor = A * (Dx - Dx * Dx);
+ const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx;
+ const float w3Hor = t1Hor * Dx;
+ const float w2Hor = t1Hor * Dx - t1Hor + t2Hor;
+ const float w1Hor = 1.f - (t1Hor * Dx) - t2Hor;
+ const float w0Hor = t1Hor - (t1Hor * Dx);
+
+ r = mul * xexpf(rv[0] * w0Hor + rv[1] * w1Hor + rv[2] * w2Hor + rv[3] * w3Hor);
+ g = mul * xexpf(gv[0] * w0Hor + gv[1] * w1Hor + gv[2] * w2Hor + gv[3] * w3Hor);
+ b = mul * xexpf(bv[0] * w0Hor + bv[1] * w1Hor + bv[2] * w2Hor + bv[3] * w3Hor);
+}
#endif
#ifdef __SSE2__
inline void interpolateTransformChannelsCubic(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul)
@@ -165,6 +247,27 @@ inline void interpolateTransformChannelsCubic(const float* const* src, int xs, i
const vfloat weight = _mm_set_ps(t1Hor * Dx, t1Hor * Dx - t1Hor + t2Hor, 1.f - (t1Hor * Dx) - t2Hor, t1Hor - (t1Hor * Dx));
dest = mul * vhadd(weight * cv);
}
+
+inline void interpolateTransformChannelsCubicLog(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul)
+{
+ constexpr float A = -0.85f;
+
+ // Vertical
+ const float t1Vert = A * (Dy - Dy * Dy);
+ const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy;
+ const vfloat w3Vert = F2V(t1Vert * Dy);
+ const vfloat w2Vert = F2V(t1Vert * Dy - t1Vert + t2Vert);
+ const vfloat w1Vert = F2V(1.f - (t1Vert * Dy) - t2Vert);
+ const vfloat w0Vert = F2V(t1Vert - (t1Vert * Dy));
+
+ const vfloat cv = (w0Vert * LVFU(src[ys][xs]) + w1Vert * LVFU(src[ys + 1][xs])) + (w2Vert * LVFU(src[ys + 2][xs]) + w3Vert * LVFU(src[ys + 3][xs]));
+
+ // Horizontal
+ const float t1Hor = A * (Dx - Dx * Dx);
+ const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx;
+ const vfloat weight = _mm_set_ps(t1Hor * Dx, t1Hor * Dx - t1Hor + t2Hor, 1.f - (t1Hor * Dx) - t2Hor, t1Hor - (t1Hor * Dx));
+ dest = mul * xexpf(vhadd(weight * cv));
+}
#else
inline void interpolateTransformChannelsCubic(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul)
{
@@ -193,6 +296,34 @@ inline void interpolateTransformChannelsCubic(const float* const* src, int xs, i
dest = mul * (cv[0] * w0Hor + cv[1] * w1Hor + cv[2] * w2Hor + cv[3] * w3Hor);
}
+
+inline void interpolateTransformChannelsCubicLog(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul)
+{
+ constexpr float A = -0.85f;
+
+ // Vertical
+ const float t1Vert = A * (Dy - Dy * Dy);
+ const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy;
+ const float w3Vert = t1Vert * Dy;
+ const float w2Vert = t1Vert * Dy - t1Vert + t2Vert;
+ const float w1Vert = 1.f - (t1Vert * Dy) - t2Vert;
+ const float w0Vert = t1Vert - (t1Vert * Dy);
+
+ float cv[4];
+ for (int i = 0; i < 4; ++i) {
+ cv[i] = w0Vert * src[ys][xs + i] + w1Vert * src[ys + 1][xs + i] + w2Vert * src[ys + 2][xs + i] + w3Vert * src[ys + 3][xs + i];
+ }
+
+ // Horizontal
+ const float t1Hor = A * (Dx - Dx * Dx);
+ const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx;
+ const float w3Hor = t1Hor * Dx;
+ const float w2Hor = t1Hor * Dx - t1Hor + t2Hor;
+ const float w1Hor = 1.f - (t1Hor * Dx) - t2Hor;
+ const float w0Hor = t1Hor - (t1Hor * Dx);
+
+ dest = mul * xexpf(cv[0] * w0Hor + cv[1] * w1Hor + cv[2] * w2Hor + cv[3] * w3Hor);
+}
#endif
}
@@ -405,7 +536,7 @@ bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int&
void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH,
const FramesMetaData *metadata,
- int rawRotationDeg, bool fullImage)
+ int rawRotationDeg, bool fullImage, bool useOriginalBuffer)
{
double focalLen = metadata->getFocalLen();
double focalLen35mm = metadata->getFocalLen35mm();
@@ -453,10 +584,10 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed,
dest = tmpimg.get();
}
}
- transformGeneral(highQuality, original, dest, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap.get());
+ transformGeneral(highQuality, original, dest, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap.get(), useOriginalBuffer);
if (highQuality && dest != transformed) {
- transformLCPCAOnly(dest, transformed, cx, cy, pLCPMap.get());
+ transformLCPCAOnly(dest, transformed, cx, cy, pLCPMap.get(), useOriginalBuffer);
}
}
}
@@ -845,8 +976,9 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat*
}
-void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap)
+void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap, bool useOriginalBuffer)
{
+
// set up stuff, depending on the mode we are
const bool enableLCPDist = pLCPMap && params->lensProf.useDist;
const bool enableCA = highQuality && needsCA();
@@ -922,9 +1054,20 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0;
const bool darkening = (params->vignetting.amount <= 0.0);
+ const bool useLog = params->commonTrans.method == "log" && highQuality;
const double centerFactorx = cx - w2;
const double centerFactory = cy - h2;
+ std::unique_ptr tempLog;
+ if (useLog) {
+ if (!useOriginalBuffer) {
+ tempLog.reset(new Imagefloat(original->getWidth(), original->getHeight()));
+ logEncode(original, tempLog.get(), multiThread);
+ original = tempLog.get();
+ } else {
+ logEncode(original, original, multiThread);
+ }
+ }
// main cycle
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, 16) if(multiThread)
@@ -1011,14 +1154,22 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
if (yc > 0 && yc < original->getHeight() - 2 && xc > 0 && xc < original->getWidth() - 2) {
// all interpolation pixels inside image
- if (enableCA) {
- interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul);
- } else if (!highQuality) {
+ if (!highQuality) {
transformed->r(y, x) = vignmul * (original->r(yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->r(yc, xc + 1) * Dx * (1.0 - Dy) + original->r(yc + 1, xc) * (1.0 - Dx) * Dy + original->r(yc + 1, xc + 1) * Dx * Dy);
transformed->g(y, x) = vignmul * (original->g(yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->g(yc, xc + 1) * Dx * (1.0 - Dy) + original->g(yc + 1, xc) * (1.0 - Dx) * Dy + original->g(yc + 1, xc + 1) * Dx * Dy);
transformed->b(y, x) = vignmul * (original->b(yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->b(yc, xc + 1) * Dx * (1.0 - Dy) + original->b(yc + 1, xc) * (1.0 - Dx) * Dy + original->b(yc + 1, xc + 1) * Dx * Dy);
+ } else if (!useLog) {
+ if (enableCA) {
+ interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul);
+ } else {
+ interpolateTransformCubic(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul);
+ }
} else {
- interpolateTransformCubic(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul);
+ if (enableCA) {
+ interpolateTransformChannelsCubicLog(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul);
+ } else {
+ interpolateTransformCubicLog(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul);
+ }
}
} else {
// edge pixels
@@ -1027,12 +1178,22 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
const int x1 = LIM(xc, 0, original->getWidth() - 1);
const int x2 = LIM(xc + 1, 0, original->getWidth() - 1);
- if (enableCA) {
- chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
+ if (useLog) {
+ if (enableCA) {
+ chTrans[c][y][x] = vignmul * xexpf(chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
+ } else {
+ transformed->r(y, x) = vignmul * xexpf(original->r(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r(y1, x2) * Dx * (1.0 - Dy) + original->r(y2, x1) * (1.0 - Dx) * Dy + original->r(y2, x2) * Dx * Dy);
+ transformed->g(y, x) = vignmul * xexpf(original->g(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g(y1, x2) * Dx * (1.0 - Dy) + original->g(y2, x1) * (1.0 - Dx) * Dy + original->g(y2, x2) * Dx * Dy);
+ transformed->b(y, x) = vignmul * xexpf(original->b(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b(y1, x2) * Dx * (1.0 - Dy) + original->b(y2, x1) * (1.0 - Dx) * Dy + original->b(y2, x2) * Dx * Dy);
+ }
} else {
- transformed->r(y, x) = vignmul * (original->r(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r(y1, x2) * Dx * (1.0 - Dy) + original->r(y2, x1) * (1.0 - Dx) * Dy + original->r(y2, x2) * Dx * Dy);
- transformed->g(y, x) = vignmul * (original->g(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g(y1, x2) * Dx * (1.0 - Dy) + original->g(y2, x1) * (1.0 - Dx) * Dy + original->g(y2, x2) * Dx * Dy);
- transformed->b(y, x) = vignmul * (original->b(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b(y1, x2) * Dx * (1.0 - Dy) + original->b(y2, x1) * (1.0 - Dx) * Dy + original->b(y2, x2) * Dx * Dy);
+ if (enableCA) {
+ chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
+ } else {
+ transformed->r(y, x) = vignmul * (original->r(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r(y1, x2) * Dx * (1.0 - Dy) + original->r(y2, x1) * (1.0 - Dx) * Dy + original->r(y2, x2) * Dx * Dy);
+ transformed->g(y, x) = vignmul * (original->g(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g(y1, x2) * Dx * (1.0 - Dy) + original->g(y2, x1) * (1.0 - Dx) * Dy + original->g(y2, x2) * Dx * Dy);
+ transformed->b(y, x) = vignmul * (original->b(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b(y1, x2) * Dx * (1.0 - Dy) + original->b(y2, x1) * (1.0 - Dx) * Dy + original->b(y2, x2) * Dx * Dy);
+ }
}
}
} else {
@@ -1051,19 +1212,24 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
}
-void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap)
+void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap, bool useOriginalBuffer)
{
assert(pLCPMap && params->lensProf.useCA && pLCPMap->isCACorrectionAvailable());
+ const bool useLog = params->commonTrans.method == "log";
- float** chOrig[3];
- chOrig[0] = original->r.ptrs;
- chOrig[1] = original->g.ptrs;
- chOrig[2] = original->b.ptrs;
+ float** chTrans[3] = {transformed->r.ptrs, transformed->g.ptrs, transformed->b.ptrs};
- float** chTrans[3];
- chTrans[0] = transformed->r.ptrs;
- chTrans[1] = transformed->g.ptrs;
- chTrans[2] = transformed->b.ptrs;
+ std::unique_ptr tempLog;
+ if (useLog) {
+ if (!useOriginalBuffer) {
+ tempLog.reset(new Imagefloat(original->getWidth(), original->getHeight()));
+ logEncode(original, tempLog.get(), multiThread);
+ original = tempLog.get();
+ } else {
+ logEncode(original, original, multiThread);
+ }
+ }
+ float** chOrig[3] = {original->r.ptrs, original->g.ptrs, original->b.ptrs};
#ifdef _OPENMP
#pragma omp parallel for if (multiThread)
@@ -1089,15 +1255,22 @@ void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *trans
// multiplier for vignetting correction
if (yc > 0 && yc < original->getHeight() - 2 && xc > 0 && xc < original->getWidth() - 2) {
// all interpolation pixels inside image
- interpolateTransformChannelsCubic (chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0);
+ if (!useLog) {
+ interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0);
+ } else {
+ interpolateTransformChannelsCubicLog(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0);
+ }
} else {
// edge pixels
int y1 = LIM (yc, 0, original->getHeight() - 1);
int y2 = LIM (yc + 1, 0, original->getHeight() - 1);
int x1 = LIM (xc, 0, original->getWidth() - 1);
int x2 = LIM (xc + 1, 0, original->getWidth() - 1);
-
- chTrans[c][y][x] = (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
+ if (!useLog) {
+ chTrans[c][y][x] = (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
+ } else {
+ chTrans[c][y][x] = xexpf(chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
+ }
}
} else {
// not valid (source pixel x,y not inside source image, etc.)
@@ -1178,9 +1351,14 @@ bool ImProcFunctions::needsLensfun() const
return params->lensProf.useLensfun();
}
-bool ImProcFunctions::needsTransform () const
+bool ImProcFunctions::needsTransform (int oW, int oH, int rawRotationDeg, const FramesMetaData *metadata) const
{
- return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsLensfun();
+ bool needsLf = needsLensfun();
+ if (needsLf) {
+ std::unique_ptr pLCPMap = LFDatabase::getInstance()->findModifier(params->lensProf, metadata, oW, oH, params->coarse, rawRotationDeg);
+ needsLf = pLCPMap.get();
+ }
+ return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsLf;
}
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 747ef34f5..ed163c911 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -1732,13 +1732,14 @@ bool CoarseTransformParams::operator !=(const CoarseTransformParams& other) cons
}
CommonTransformParams::CommonTransformParams() :
+ method("log"),
autofill(true)
{
}
bool CommonTransformParams::operator ==(const CommonTransformParams& other) const
{
- return autofill == other.autofill;
+ return method == other.method && autofill == other.autofill;
}
bool CommonTransformParams::operator !=(const CommonTransformParams& other) const
@@ -4182,6 +4183,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->coarse.vflip, "Coarse Transformation", "VerticalFlip", coarse.vflip, keyFile);
// Common properties for transformations
+ saveToKeyfile(!pedited || pedited->commonTrans.method, "Common Properties for Transformations", "Method", commonTrans.method, keyFile);
saveToKeyfile(!pedited || pedited->commonTrans.autofill, "Common Properties for Transformations", "AutoFill", commonTrans.autofill, keyFile);
// Rotation
@@ -5640,6 +5642,11 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
}
if (keyFile.has_group("Common Properties for Transformations")) {
+ if (keyFile.has_key("Common Properties for Transformations", "Method")) {
+ assignFromKeyfile(keyFile, "Common Properties for Transformations", "Method", pedited, commonTrans.method, pedited->commonTrans.method);
+ } else {
+ commonTrans.method = "lin";
+ }
assignFromKeyfile(keyFile, "Common Properties for Transformations", "AutoFill", pedited, commonTrans.autofill, pedited->commonTrans.autofill);
}
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index c25866a42..aa070179b 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -856,6 +856,7 @@ struct CoarseTransformParams {
* Common transformation parameters
*/
struct CommonTransformParams {
+ Glib::ustring method;
bool autofill;
CommonTransformParams();
diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc
index 11e75a097..b536b8b12 100644
--- a/rtengine/rtthumbnail.cc
+++ b/rtengine/rtthumbnail.cc
@@ -1247,12 +1247,12 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0, 0);
// perform transform
- if (ipf.needsTransform()) {
+ int origFW;
+ int origFH;
+ double tscale = 0.0;
+ getDimensions (origFW, origFH, tscale);
+ if (ipf.needsTransform(origFW * tscale + 0.5, origFH * tscale + 0.5, 0, metadata)) {
Imagefloat* trImg = new Imagefloat (fw, fh);
- int origFW;
- int origFH;
- double tscale = 0.0;
- getDimensions (origFW, origFH, tscale);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, origFW * tscale + 0.5, origFH * tscale + 0.5, metadata, 0, true); // Raw rotate degree not detectable here
delete baseImg;
baseImg = trImg;
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index d819d0d84..6e16c0adf 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -875,7 +875,7 @@ private:
ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0, 0);
// perform transform (excepted resizing)
- if (ipf.needsTransform()) {
+ if (ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData())) {
Imagefloat* trImg = nullptr;
if (ipf.needsLuminanceOnly()) {
@@ -885,7 +885,7 @@ private:
}
ipf.transform(baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh,
- imgsrc->getMetaData(), imgsrc->getRotateDegree(), true);
+ imgsrc->getMetaData(), imgsrc->getRotateDegree(), true, true);
if (trImg != baseImg) {
delete baseImg;
diff --git a/rtengine/sleef.h b/rtengine/sleef.h
index 30c059010..b7655258b 100644
--- a/rtengine/sleef.h
+++ b/rtengine/sleef.h
@@ -532,7 +532,7 @@ __inline double xlog(double d) {
x = x * t + 0.693147180559945286226764 * e;
- if (xisinf(d)) x = rtengine::RT_INFINITY;
+ if (xispinf(d)) x = rtengine::RT_INFINITY;
if (d < 0) x = rtengine::RT_NAN;
if (d == 0) x = -rtengine::RT_INFINITY;
@@ -864,7 +864,7 @@ __inline double xlog10(double a) {
double2 d = mul_dd(logk(a), dd(0.43429448190325176116, 6.6494347733425473126e-17));
double x = d.x + d.y;
- if (xisinf(a)) x = rtengine::RT_INFINITY;
+ if (xispinf(a)) x = rtengine::RT_INFINITY;
if (a < 0) x = rtengine::RT_NAN;
if (a == 0) x = -rtengine::RT_INFINITY;
@@ -875,7 +875,7 @@ __inline double xlog1p(double a) {
double2 d = logk2(add2_ss(a, 1));
double x = d.x + d.y;
- if (xisinf(a)) x = rtengine::RT_INFINITY;
+ if (xispinf(a)) x = rtengine::RT_INFINITY;
if (a < -1) x = rtengine::RT_NAN;
if (a == -1) x = -rtengine::RT_INFINITY;
@@ -894,6 +894,15 @@ __inline double xlog1p(double a) {
#define R_LN2f 1.442695040888963407359924681001892137426645954152985934135449406931f
+#ifdef __SSE2__
+__inline int xrintf(float x) {
+ return _mm_cvt_ss2si(_mm_set_ss(x));
+}
+#else
+__inline int xrintf(float x) {
+ return x + (x < 0 ? -0.5f : 0.5f);
+}
+#endif
__inline int32_t floatToRawIntBits(float d) {
union {
float f;
@@ -980,7 +989,7 @@ __inline float xsinf(float d) {
int q;
float u, s;
- q = rint(d * rtengine::RT_1_PI_F);
+ q = xrintf(d * rtengine::RT_1_PI_F);
d = mlaf(q, -PI4_Af*4, d);
d = mlaf(q, -PI4_Bf*4, d);
@@ -1009,7 +1018,7 @@ __inline float xcosf(float d) {
int q;
float u, s;
- q = 1 + 2*rint(d * rtengine::RT_1_PI_F - 0.5f);
+ q = 1 + 2*xrintf(d * rtengine::RT_1_PI_F - 0.5f);
d = mlaf(q, -PI4_Af*2, d);
d = mlaf(q, -PI4_Bf*2, d);
@@ -1041,7 +1050,7 @@ __inline float2 xsincosf(float d) {
float u, s, t;
float2 r;
- q = rint(d * rtengine::RT_2_PI_F);
+ q = xrintf(d * rtengine::RT_2_PI_F);
s = d;
@@ -1083,7 +1092,7 @@ __inline float xtanf(float d) {
int q;
float u, s, x;
- q = rint(d * (float)(2 * rtengine::RT_1_PI));
+ q = xrintf(d * (float)(2 * rtengine::RT_1_PI));
x = d;
@@ -1199,17 +1208,41 @@ __inline float xlogf(float d) {
x = x * t + 0.693147180559945286226764f * e;
- if (xisinff(d)) x = rtengine::RT_INFINITY_F;
+ if (xispinff(d)) x = rtengine::RT_INFINITY_F;
if (d < 0) x = rtengine::RT_NAN_F;
if (d == 0) x = -rtengine::RT_INFINITY_F;
return x;
}
+__inline float xlogf1(float d) { // does xlogf(vmaxf(d, 1.f)) but faster
+ float x, x2, t, m;
+ int e;
+
+ e = ilogbp1f(d * 0.7071f);
+ m = ldexpkf(d, -e);
+
+ x = (m-1.0f) / (m+1.0f);
+ x2 = x * x;
+
+ t = 0.2371599674224853515625f;
+ t = mlaf(t, x2, 0.285279005765914916992188f);
+ t = mlaf(t, x2, 0.400005519390106201171875f);
+ t = mlaf(t, x2, 0.666666567325592041015625f);
+ t = mlaf(t, x2, 2.0f);
+
+ x = x * t + 0.693147180559945286226764f * e;
+
+ if (xispinff(d)) x = rtengine::RT_INFINITY_F;
+ if (d <= 1.f) x = 0;
+
+ return x;
+}
+
__inline float xexpf(float d) {
if(d<=-104.0f) return 0.0f;
- int q = rint(d * R_LN2f);
+ int q = xrintf(d * R_LN2f);
float s, u;
s = mlaf(q, -L2Uf, d);
diff --git a/rtengine/sleefsseavx.c b/rtengine/sleefsseavx.c
index 1982c7c4c..0af516f9b 100644
--- a/rtengine/sleefsseavx.c
+++ b/rtengine/sleefsseavx.c
@@ -1253,6 +1253,30 @@ static INLINE vfloat xlogf(vfloat d) {
return x;
}
+static INLINE vfloat xlogf1(vfloat d) { // does xlogf(vmaxf(d, 1.f)) but faster
+ vfloat x, x2, t, m;
+ vint2 e;
+
+ e = vilogbp1f(vmulf(d, vcast_vf_f(0.7071f)));
+ m = vldexpf(d, vsubi2(vcast_vi2_i(0), e));
+
+ x = vdivf(vaddf(vcast_vf_f(-1.0f), m), vaddf(vcast_vf_f(1.0f), m));
+ x2 = vmulf(x, x);
+
+ t = vcast_vf_f(0.2371599674224853515625f);
+ t = vmlaf(t, x2, vcast_vf_f(0.285279005765914916992188f));
+ t = vmlaf(t, x2, vcast_vf_f(0.400005519390106201171875f));
+ t = vmlaf(t, x2, vcast_vf_f(0.666666567325592041015625f));
+ t = vmlaf(t, x2, vcast_vf_f(2.0f));
+
+ x = vaddf(vmulf(x, t), vmulf(vcast_vf_f(0.693147180559945286226764f), vcast_vf_vi2(e)));
+
+ x = vself(vmaskf_ispinf(d), vcast_vf_f(INFINITYf), x);
+ x = vselfnotzero(vmaskf_le(d, vcast_vf_f(1.f)), x);
+
+ return x;
+}
+
static INLINE vfloat xlogf0(vfloat d) {
vfloat x, x2, t, m;
vint2 e;
diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc
index 76e0635eb..762726107 100644
--- a/rtgui/lensgeom.cc
+++ b/rtgui/lensgeom.cc
@@ -17,6 +17,8 @@
* along with RawTherapee. If not, see .
*/
#include "lensgeom.h"
+
+#include "eventmapper.h"
#include "guiutils.h"
#include "rtimage.h"
@@ -28,6 +30,18 @@ using namespace rtengine::procparams;
LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGEOM_LABEL")), rlistener(nullptr), lastFill(false)
{
+ auto m = ProcEventMapper::getInstance();
+ EvTransMethod = m->newEvent(TRANSFORM, "HISTORY_MSG_TRANS_METHOD");
+
+ Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ());
+ hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") + ": ")), Gtk::PACK_SHRINK, 4);
+ method = Gtk::manage (new MyComboBoxText ());
+ method->append(M("TP_LENSGEOM_LOG"));
+ method->append(M("TP_LENSGEOM_LIN"));
+ method->set_active(0);
+ hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4);
+ pack_start( *hb1, Gtk::PACK_SHRINK, 4);
+
fill = Gtk::manage (new Gtk::CheckButton (M("TP_LENSGEOM_FILL")));
pack_start (*fill);
@@ -39,8 +53,9 @@ LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGE
packBox = Gtk::manage (new ToolParamBlock ());
pack_start (*packBox);
- autoCrop->signal_pressed().connect( sigc::mem_fun(*this, &LensGeometry::autoCropPressed) );
- fillConn = fill->signal_toggled().connect( sigc::mem_fun(*this, &LensGeometry::fillPressed) );
+ method->connect(method->signal_changed().connect(sigc::mem_fun(*this, &LensGeometry::methodChanged)));
+ autoCrop->signal_pressed().connect(sigc::mem_fun(*this, &LensGeometry::autoCropPressed));
+ fillConn = fill->signal_toggled().connect(sigc::mem_fun(*this, &LensGeometry::fillPressed));
fill->set_active (true);
show_all ();
@@ -55,8 +70,14 @@ void LensGeometry::read (const ProcParams* pp, const ParamsEdited* pedited)
{
disableListener ();
+ method->block (true);
+ method->set_active(pp->commonTrans.method == "log" ? 0 : 1);
if (pedited) {
+ if(!pedited->commonTrans.method) {
+ method->set_active_text(M("GENERAL_UNCHANGED"));
+ }
+
fill->set_inconsistent (!pedited->commonTrans.autofill);
}
@@ -67,15 +88,20 @@ void LensGeometry::read (const ProcParams* pp, const ParamsEdited* pedited)
lastFill = pp->commonTrans.autofill;
+ method->block (false);
enableListener ();
}
void LensGeometry::write (ProcParams* pp, ParamsEdited* pedited)
{
-
+ int currentRow = method->get_active_row_number();
+ if( currentRow >= 0 && method->get_active_text() != M("GENERAL_UNCHANGED")) {
+ pp->commonTrans.method = currentRow == 0 ? "log" : "lin";
+ }
pp->commonTrans.autofill = fill->get_active ();
if (pedited) {
+ pedited->commonTrans.method = method->get_active_text() != M("GENERAL_UNCHANGED");
pedited->commonTrans.autofill = !fill->get_inconsistent();
}
}
@@ -115,6 +141,14 @@ void LensGeometry::fillPressed ()
}
}
+void LensGeometry::methodChanged ()
+{
+
+ if (listener && method->get_active_row_number() >= 0) {
+ listener->panelChanged(EvTransMethod, method->get_active_text());
+ }
+}
+
void LensGeometry::setBatchMode (bool batchMode)
{
diff --git a/rtgui/lensgeom.h b/rtgui/lensgeom.h
index 18b31a619..73c28b006 100644
--- a/rtgui/lensgeom.h
+++ b/rtgui/lensgeom.h
@@ -29,6 +29,7 @@ class LensGeometry final :
{
protected:
+ MyComboBoxText* method;
Gtk::Button* autoCrop;
LensGeomListener* rlistener;
Gtk::CheckButton* fill;
@@ -36,6 +37,7 @@ protected:
sigc::connection fillConn;
ToolParamBlock* packBox;
+ rtengine::ProcEvent EvTransMethod;
public:
LensGeometry ();
@@ -50,6 +52,7 @@ public:
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override;
void setBatchMode (bool batchMode) override;
+ void methodChanged();
void fillPressed ();
void autoCropPressed ();
void setLensGeomListener (LensGeomListener* l)
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index 4a575ba66..cd2f4ee5b 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -321,6 +321,7 @@ void ParamsEdited::set(bool v)
coarse.rotate = v;
coarse.hflip = v;
coarse.vflip = v;
+ commonTrans.method = v;
commonTrans.autofill = v;
rotate.degree = v;
distortion.amount = v;
@@ -918,6 +919,7 @@ void ParamsEdited::initFrom(const std::vector&
coarse.rotate = coarse.rotate && p.coarse.rotate == other.coarse.rotate;
coarse.hflip = coarse.hflip && p.coarse.hflip == other.coarse.hflip;
coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip;
+ commonTrans.method = commonTrans.method && p.commonTrans.method == other.commonTrans.method;
commonTrans.autofill = commonTrans.autofill && p.commonTrans.autofill == other.commonTrans.autofill;
rotate.degree = rotate.degree && p.rotate.degree == other.rotate.degree;
distortion.amount = distortion.amount && p.distortion.amount == other.distortion.amount;
@@ -2705,6 +2707,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.coarse.vflip = mods.coarse.vflip;
}
+ if (commonTrans.method) {
+ toEdit.commonTrans.method = mods.commonTrans.method;
+ }
+
if (commonTrans.autofill) {
toEdit.commonTrans.autofill = mods.commonTrans.autofill;
}
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 9d0197884..200cc97c4 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -369,6 +369,7 @@ struct CoarseTransformParamsEdited {
};
struct CommonTransformParamsEdited {
+ bool method;
bool autofill;
};