diff --git a/CMakeLists.txt b/CMakeLists.txt index 685b418bf..e506499b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,7 @@ pkg_check_modules (GIOMM REQUIRED giomm-2.4>=2.44) pkg_check_modules (GTHREAD REQUIRED gthread-2.0>=2.44) pkg_check_modules (GOBJECT REQUIRED gobject-2.0>=2.44) pkg_check_modules (SIGC REQUIRED sigc++-2.0>=2.3.1) +pkg_check_modules (LENSFUN REQUIRED lensfun>=0.2) if(WIN32) add_definitions(-DWIN32) diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index a813d4156..32d99cb8f 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -9,6 +9,7 @@ include_directories(${EXTRA_INCDIR} ${GTK_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS} ${LCMS_INCLUDE_DIRS} + ${LENSFUN_INCLUDE_DIRS} ) link_directories("${PROJECT_SOURCE_DIR}/rtexif" @@ -109,6 +110,7 @@ set(RTENGINESOURCEFILES slicer.cc stdimagesource.cc utils.cc + rtlensfun.cc ) if(NOT WITH_SYSTEM_KLT) @@ -153,6 +155,7 @@ target_link_libraries(rtengine rtexif ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ${ZLIB_LIBRARIES} + ${LENSFUN_LIBRARIES} ) install(FILES ${CAMCONSTSFILE} DESTINATION "${DATADIR}" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index acd73c0a3..92416917d 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -1086,8 +1086,9 @@ bool check_need_larger_crop_for_lcp_distortion (int fw, int fh, int x, int y, in return false; } - return (params.lensProf.lcpFile.length() > 0 && - params.lensProf.useDist); + return (params.lensProf.useDist && + (params.lensProf.useLensfun || + params.lensProf.lcpFile.length() > 0)); } } // namespace diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index b14db1588..9f53ab81d 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -400,8 +400,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } if (needstransform) - ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, fw, fh, imgsrc->getMetaData()->getFocalLen(), + ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, fw, fh, imgsrc->getMetaData(), + // imgsrc->getMetaData()->getFocalLen(), // imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getMetaData()->getFNumber(), imgsrc->getRotateDegree(), false); else { @@ -1120,7 +1121,7 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int & MyMutex::MyLock lock (mProcessing); - LCPMapper *pLCPMap = nullptr; + LensCorrection *pLCPMap = nullptr; if (params.lensProf.lcpFile.length() && imgsrc->getMetaData()->getFocalLen() > 0) { LCPProfile *pLCPProf = lcpStore->getProfile (params.lensProf.lcpFile); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 983295c38..1bcca4d37 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -60,7 +60,7 @@ class ImProcFunctions TRANSFORM_HIGH_QUALITY_FULLIMAGE }; void transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH); - void transformGeneral(TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap); + void transformGeneral(TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap); void sharpenHaloCtrl (float** luminance, float** blurmap, float** base, int W, int H, const SharpeningParams &sharpenParam); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H, SharpeningParams &sharpenParam); @@ -74,6 +74,7 @@ class ImProcFunctions bool needsGradient (); bool needsVignetting (); bool needsLCP (); + bool needsLensfun(); // static cmsUInt8Number* Mempro = NULL; inline void interpolateTransformCubic (Imagefloat* src, int xs, int ys, double Dx, double Dy, float *r, float *g, float *b, double mul) @@ -352,11 +353,11 @@ public: Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *ga = nullptr); // CieImage *ciec; - bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LCPMapper *pLCPMap = nullptr); - bool transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1, const LCPMapper *pLCPMap = nullptr); + bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr); + bool transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr); static void getAutoExp (const LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh); static double getAutoDistor (const Glib::ustring& fname, int thumb_size); - double getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap = nullptr); + double getTransformAutoFill (int oW, int oH, const LensCorrection *pLCPMap = nullptr); void rgb2lab (const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace); void lab2rgb (const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace); }; diff --git a/rtengine/init.cc b/rtengine/init.cc index 2d157c762..7ef40f43a 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -30,6 +30,7 @@ #include "rtthumbnail.h" #include "profilestore.h" #include "../rtgui/threadutils.h" +#include "rtlensfun.h" namespace rtengine { @@ -50,6 +51,7 @@ int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDi Color::init (); PerceptualToneCurve::init (); RawImageSource::init (); + LFDatabase::init(); delete lcmsMutex; lcmsMutex = new MyMutex; dfm.init( s->darkFramesPath ); diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index 6d34c5935..a054cc57a 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -24,6 +24,7 @@ #include "mytime.h" #include "rt_math.h" #include "sleef.c" +#include "rtlensfun.h" using namespace std; @@ -86,16 +87,18 @@ float normn (float a, float b, int n) } -void correct_distortion(const rtengine::LCPMapper *lcp, double &x, double &y, +inline void correct_distortion(const rtengine::LensCorrection *lcp, double &x, double &y, int cx, int cy, double scale) { assert (lcp); - x += cx; - y += cy; - lcp->correctDistortion(x, y, scale); - x -= (cx * scale); - y -= (cy * scale); + // x += cx; + // y += cy; + // std::cout << "DIST: x=" << x << ", y=" << y; + lcp->correctDistortion(x, y, cx, cy, scale); + // std::cout << " --> pos[0]=" << x << ", pos[1]=" << y << std::endl; + // x -= (cx * scale); + // y -= (cy * scale); } } @@ -107,7 +110,7 @@ namespace rtengine #define CLIPTOC(a,b,c,d) ((a)>=(b)?((a)<=(c)?(a):(d=true,(c))):(d=true,(b))) bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef, - const LCPMapper *pLCPMap) + const LensCorrection *pLCPMap) { bool clipped = false; @@ -209,7 +212,7 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, } // Transform all corners and critical sidelines of an image -bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef, const LCPMapper *pLCPMap) +bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef, const LensCorrection *pLCPMap) { const int DivisionsPerBorder = 32; @@ -316,9 +319,30 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, float focusDist = metadata->getFocusDist(); double fNumber = metadata->getFNumber(); - LCPMapper *pLCPMap = nullptr; + LensCorrection *pLCPMap = nullptr; - if (needsLCP()) { // don't check focal length to allow distortion correction for lenses without chip + if (needsLensfun()) { + const LFDatabase *db = LFDatabase::getInstance(); + Glib::ustring make, model, lens; + if (params->lensProf.lfAutoMatch) { + make = metadata->getMake(); + model = metadata->getModel(); + lens = metadata->getLens(); + } else { + make = params->lensProf.lfCameraMake; + model = params->lensProf.lfCameraModel; + lens = params->lensProf.lfLens; + } + LFCamera c = db->findCamera(make, model); + LFLens l = db->findLens(c, lens); + pLCPMap = db->getModifier(c, l, fW, fH, focalLen, fNumber, focusDist); + + std::cout << "LENSFUN:\n" + << " camera: " << c.getDisplayString() << "\n" + << " lens: " << l.getDisplayString() << "\n" + << " correction? " << (pLCPMap ? "yes" : "no") << std::endl; + + } else if (needsLCP()) { // don't check focal length to allow distortion correction for lenses without chip LCPProfile *pLCPProf = lcpStore->getProfile (params->lensProf.lcpFile); if (pLCPProf) { @@ -329,7 +353,7 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, } } - if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && (needsVignetting() || needsPCVignetting() || needsGradient())) { + if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP() || needsLensfun()) && (needsVignetting() || needsPCVignetting() || needsGradient())) { transformLuminanceOnly (original, transformed, cx, cy, oW, oH, fW, fH); } else { TransformMode mode; @@ -734,7 +758,7 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* } -void ImProcFunctions::transformGeneral(ImProcFunctions::TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap) +void ImProcFunctions::transformGeneral(ImProcFunctions::TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; @@ -801,7 +825,7 @@ void ImProcFunctions::transformGeneral(ImProcFunctions::TransformMode mode, Imag switch (mode) { case ImProcFunctions::TRANSFORM_HIGH_QUALITY_FULLIMAGE: - enableLCPCA = pLCPMap && params->lensProf.useCA && pLCPMap->enableCA; + enableLCPCA = pLCPMap && params->lensProf.useCA && pLCPMap->supportsCA(); // no break on purpose case ImProcFunctions::TRANSFORM_HIGH_QUALITY: enableLCPDist = pLCPMap && params->lensProf.useDist; @@ -958,12 +982,16 @@ void ImProcFunctions::transformGeneral(ImProcFunctions::TransformMode mode, Imag } -double ImProcFunctions::getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap) +double ImProcFunctions::getTransformAutoFill (int oW, int oH, const LensCorrection *pLCPMap) { if (!needsCA() && !needsDistortion() && !needsRotation() && !needsPerspective() && (!params->lensProf.useDist || pLCPMap == nullptr)) { return 1; } + if (pLCPMap && !pLCPMap->supportsAutoFill()) { + return 1; + } + double scaleU = 2, scaleL = 0.001; // upper and lower border, iterate inbetween do { @@ -1019,12 +1047,17 @@ bool ImProcFunctions::needsVignetting () bool ImProcFunctions::needsLCP () { - return params->lensProf.lcpFile.length() > 0; + return params->lensProf.lcpFile.length() > 0 && !needsLensfun(); +} + +bool ImProcFunctions::needsLensfun() +{ + return params->lensProf.useLensfun; } bool ImProcFunctions::needsTransform () { - return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP(); + return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsLensfun(); } diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index c09d2d9be..92a3a3ce8 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -210,8 +210,11 @@ LCPMapper::LCPMapper(LCPProfile* pProf, float focalLength, float focalLength35mm isFisheye = pProf->isFisheye; } -void LCPMapper::correctDistortion(double& x, double& y, double scale) const +void LCPMapper::correctDistortion(double &x, double &y, int cx, int cy, double scale) const { + x += cx; + y += cy; + if (isFisheye) { double u = x * scale; double v = y * scale; @@ -253,6 +256,9 @@ void LCPMapper::correctDistortion(double& x, double& y, double scale) const x = xnew * mc.fx + x0; y = ynew * mc.fy + y0; } + + x -= cx * scale; + y -= cy * scale; } void LCPMapper::correctCA(double& x, double& y, int channel) const diff --git a/rtengine/lcp.h b/rtengine/lcp.h index f7164117f..1a4b677d3 100644 --- a/rtengine/lcp.h +++ b/rtengine/lcp.h @@ -136,8 +136,20 @@ public: #define lcpStore LCPStore::getInstance() +class LensCorrection { +public: + virtual ~LensCorrection() {} + virtual void correctDistortion(double &x, double &y, int cx, int cy, double scale) const = 0; + virtual bool supportsAutoFill() const = 0; + virtual bool supportsCA() const = 0; + virtual void correctCA(double &x, double &y, int channel) const = 0; + virtual void processVignetteLine(int width, int y, float *line) const = 0; + virtual void processVignetteLine3Channels(int width, int y, float *line) const = 0; +}; + + // Once precalculated class to correct a point -class LCPMapper +class LCPMapper: public LensCorrection { bool useCADist; // should the distortion in the CA info be used? @@ -153,7 +165,9 @@ public: LCPMapper(LCPProfile* pProf, float focalLength, float focalLength35mm, float focusDist, float aperture, bool vignette, bool useCADistP, int fullWidth, int fullHeight, const CoarseTransformParams& coarse, int rawRotationDeg); - void correctDistortion(double& x, double& y, double scale) const; // MUST be the first stage + void correctDistortion(double &x, double &y, int cx, int cy, double scale) const; // MUST be the first stage + bool supportsCA() const { return enableCA; } + bool supportsAutoFill() const { return true; } void correctCA(double& x, double& y, int channel) const; void processVignetteLine(int width, int y, float *line) const; void processVignetteLine3Channels(int width, int y, float *line) const; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e1a3002e2..29b2cce84 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -922,6 +922,11 @@ void LensProfParams::setDefaults() lcpFile = ""; useDist = useVign = true; useCA = false; + useLensfun = false; + lfAutoMatch = true; + lfCameraMake = ""; + lfCameraModel = ""; + lfLens = ""; } void CoarseTransformParams::setDefaults() @@ -2565,6 +2570,22 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_boolean ("LensProfile", "UseCA", lensProf.useCA); } + if (!pedited || pedited->lensProf.useLensfun) { + keyFile.set_boolean("LensProfile", "UseLensfun", lensProf.useLensfun); + } + if (!pedited || pedited->lensProf.lfAutoMatch) { + keyFile.set_boolean("LensProfile", "LFAutoMatch", lensProf.lfAutoMatch); + } + if (!pedited || pedited->lensProf.lfCameraMake) { + keyFile.set_string("LensProfile", "LFCameraMake", lensProf.lfCameraMake); + } + if (!pedited || pedited->lensProf.lfCameraModel) { + keyFile.set_string("LensProfile", "LFCameraModel", lensProf.lfCameraModel); + } + if (!pedited || pedited->lensProf.lfLens) { + keyFile.set_string("LensProfile", "LFLens", lensProf.lfLens); + } + // save perspective correction if (!pedited || pedited->perspective.horizontal) { keyFile.set_double ("Perspective", "Horizontal", perspective.horizontal); @@ -5832,6 +5853,41 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) pedited->lensProf.useCA = true; } } + + if (keyFile.has_key("LensProfile", "UseLensfun")) { + lensProf.useLensfun = keyFile.get_boolean("LensProfile", "UseLensfun"); + if (pedited) { + pedited->lensProf.useLensfun = true; + } + } + + if (keyFile.has_key("LensProfile", "LFAutoMatch")) { + lensProf.lfAutoMatch = keyFile.get_boolean("LensProfile", "LFAutoMatch"); + if (pedited) { + pedited->lensProf.lfAutoMatch = true; + } + } + + if (keyFile.has_key("LensProfile", "LFCameraMake")) { + lensProf.lfCameraMake = keyFile.get_string("LensProfile", "LFCameraMake"); + if (pedited) { + pedited->lensProf.lfCameraMake = true; + } + } + + if (keyFile.has_key("LensProfile", "LFCameraModel")) { + lensProf.lfCameraModel = keyFile.get_string("LensProfile", "LFCameraModel"); + if (pedited) { + pedited->lensProf.lfCameraModel = true; + } + } + + if (keyFile.has_key("LensProfile", "LFLens")) { + lensProf.lfLens = keyFile.get_string("LensProfile", "LFLens"); + if (pedited) { + pedited->lensProf.lfLens = true; + } + } } // load perspective correction @@ -8432,6 +8488,11 @@ bool ProcParams::operator== (const ProcParams& other) && lensProf.useDist == other.lensProf.useDist && lensProf.useVign == other.lensProf.useVign && lensProf.useCA == other.lensProf.useCA + && lensProf.useLensfun == other.lensProf.useLensfun + && lensProf.lfAutoMatch == other.lensProf.lfAutoMatch + && lensProf.lfCameraMake == other.lensProf.lfCameraMake + && lensProf.lfCameraModel == other.lensProf.lfCameraModel + && lensProf.lfLens == other.lensProf.lfLens && perspective.horizontal == other.perspective.horizontal && perspective.vertical == other.perspective.vertical && gradient.enabled == other.gradient.enabled diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 53561ce16..c7bedf611 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -831,6 +831,11 @@ class LensProfParams public: Glib::ustring lcpFile; bool useDist, useVign, useCA; + bool useLensfun; + bool lfAutoMatch; + Glib::ustring lfCameraMake; + Glib::ustring lfCameraModel; + Glib::ustring lfLens; LensProfParams() { @@ -839,6 +844,7 @@ public: void setDefaults(); }; + /** * Parameters of the perspective correction */ diff --git a/rtengine/rtlensfun.cc b/rtengine/rtlensfun.cc index 1b8009ee1..7d376269d 100644 --- a/rtengine/rtlensfun.cc +++ b/rtengine/rtlensfun.cc @@ -26,32 +26,46 @@ namespace rtengine { // LFModifier //----------------------------------------------------------------------------- -bool LFModifier::ok() const +LFModifier::LFModifier(lfModifier *m): + data_(m) { - return data_.get(); } -void LFModifier::correctDistortion(double &x, double &y) +LFModifier::~LFModifier() +{ + if (data_) { + data_->Destroy(); + } +} + +bool LFModifier::ok() const +{ + return data_; +} + + +void LFModifier::correctDistortion(double &x, double &y, int cx, int cy, double scale) const { if (!ok()) { return; } float pos[2]; - data_->ApplyGeometryDistortion(x, y, 1, 1, pos); - x = pos[0]; - y = pos[1]; + if (data_->ApplyGeometryDistortion(x+cx, y+cy, 1, 1, pos)) { + x = pos[0] - cx; + y = pos[1] - cy; + } } -void LFModifier::processVignetteLine(int width, int y, float *line) +void LFModifier::processVignetteLine(int width, int y, float *line) const { // TODO } -void LFModifier::processVignetteLine3Channels(int width, int y, float *line) +void LFModifier::processVignetteLine3Channels(int width, int y, float *line) const { // TODO } @@ -61,15 +75,21 @@ void LFModifier::processVignetteLine3Channels(int width, int y, float *line) // LFCamera //----------------------------------------------------------------------------- +LFCamera::LFCamera(): + data_(nullptr) +{ +} + + bool LFCamera::ok() const { - return data_.get(); + return data_; } Glib::ustring LFCamera::getMake() const { - if (ok()) { + if (data_) { return data_->Maker; } else { return ""; @@ -79,7 +99,7 @@ Glib::ustring LFCamera::getMake() const Glib::ustring LFCamera::getModel() const { - if (ok()) { + if (data_) { return data_->Model; } else { return ""; @@ -89,7 +109,7 @@ Glib::ustring LFCamera::getModel() const float LFCamera::getCropFactor() const { - if (ok()) { + if (data_) { return data_->CropFactor; } else { return 0; @@ -99,7 +119,7 @@ float LFCamera::getCropFactor() const Glib::ustring LFCamera::getDisplayString() const { - if (ok()) { + if (data_) { return Glib::ustring::compose("%1 %2", getMake(), getModel()); } else { return "---"; @@ -111,15 +131,21 @@ Glib::ustring LFCamera::getDisplayString() const // LFLens //----------------------------------------------------------------------------- +LFLens::LFLens(): + data_(nullptr) +{ +} + + bool LFLens::ok() const { - return data_->get(); + return data_; } Glib::ustring LFLens::getDisplayString() const { - if (ok()) { + if (data_) { return Glib::ustring::compose("%1 %2", data_->Maker, data_->Model); } else { return "---"; @@ -136,87 +162,111 @@ LFDatabase LFDatabase::instance_; bool LFDatabase::init() { - instance_.data_.reset(new lfDatabase()); + instance_.data_ = lfDatabase::Create(); return instance_.data_->Load() != LF_NO_ERROR; } -LFDatabase *LFDatabase::getInstance() +LFDatabase::LFDatabase(): + data_(nullptr) +{ +} + + +LFDatabase::~LFDatabase() +{ + if (data_) { + data_->Destroy(); + } +} + + +const LFDatabase *LFDatabase::getInstance() { return &instance_; } -std::vector LFDatabase::getCameras() +std::vector LFDatabase::getCameras() const { - auto cams = data_->GetCameras(); std::vector ret; - while (*cams) { - ret.emplace_back(LFCamera()); - ret.back().data_.reset(new lfCamera(**cams)); - ++cams; - } + if (data_) { + auto cams = data_->GetCameras(); + while (*cams) { + ret.emplace_back(LFCamera()); + ret.back().data_ = *cams; + ++cams; + } + } return ret; } -std::vector getLenses(const LFCamera &camera) +std::vector LFDatabase::getLenses(const LFCamera &camera) const { - auto lenses = data_->FindLenses(*camera.data_->get(), NULL, "", LF_SEARCH_LOOSE | LF_SEARCH_SORT_AND_UNIQUIFY); std::vector ret; - while (*lenses) { - ret.emplace_back(LFLens()); - ret.back().data_.reset(new lfLens(**lenses)); - ++lenses; + if (data_) { + auto lenses = data_->FindLenses(camera.data_, NULL, "", LF_SEARCH_LOOSE /*| LF_SEARCH_SORT_AND_UNIQUIFY*/); + while (*lenses) { + ret.emplace_back(LFLens()); + ret.back().data_ = *lenses; + ++lenses; + } + lf_free(lenses); } - lf_free(lenses); return ret; } -LFCamera LFDatabase::findCamera(const Glib::ustring &make, const Glib::ustring &model) +LFCamera LFDatabase::findCamera(const Glib::ustring &make, const Glib::ustring &model) const { LFCamera ret; - auto found = data_->FindCamerasExt(make.c_str(), model.c_str(), LF_SEARCH_LOOSE); - if (found) { - ret.data_.reset(new lfCamera(*found[0])); - lf_free(found); - } - return ret; -} - - -LFLens LFDatabase::findLens(const LFCamera &camera, const Glib::ustring &name) -{ - LFLens ret; - auto found = data_->FindLenses(camera.data_.get(), NULL, name.c_str(), LF_SEARCH_LOOSE); - if (!found) { - // try to split the maker from the model of the lens - Glib::ustring make, model; - auto i = name.find_first_of(' '); - if (i != Glib::ustring::npos) { - make = name.substr(0, i); - model = name.substr(i+1); - found = data_->FindLenses(camera.data_.get(), make.c_str(), model.c_str(), LF_SEARCH_LOOSE); + if (data_) { + auto found = data_->FindCamerasExt(make.c_str(), model.c_str(), LF_SEARCH_LOOSE); + if (found) { + ret.data_ = found[0]; + lf_free(found); } } - if (found) { - ret.data_.reset(new lfLens(*found[0])); - lf_free(found); + return ret; +} + + +LFLens LFDatabase::findLens(const LFCamera &camera, const Glib::ustring &name) const +{ + LFLens ret; + if (data_) { + auto found = data_->FindLenses(camera.data_, NULL, name.c_str(), LF_SEARCH_LOOSE); + if (!found) { + // try to split the maker from the model of the lens + Glib::ustring make, model; + auto i = name.find_first_of(' '); + if (i != Glib::ustring::npos) { + make = name.substr(0, i); + model = name.substr(i+1); + found = data_->FindLenses(camera.data_, make.c_str(), model.c_str(), LF_SEARCH_LOOSE); + } + } + if (found) { + ret.data_ = found[0]; + lf_free(found); + } } return ret; } -LFModifier LFDatabase::getModifier(const LFCamera &camera, const LFLens &lens, - int width, int height, float focalLen, - float aperture) +LFModifier *LFDatabase::getModifier(const LFCamera &camera, const LFLens &lens, + int width, int height, float focalLen, + float aperture, float focusDist) const { - LFModifier ret; - if (camera.ok() && lens.ok()) { - lfModifier *mod = lfModifier::Create(lens.data_.get(), camera.getCropFactor(), width, height); - mod->Initialize(lens.data_.get(), LF_PF_F32, focalLen, aperture, 1000, 1, LF_RECTILINEAR, LF_MODIFY_VIGNETTING | LF_MODIFY_DISTORTION, false); - ret.data_.reset(mod); + LFModifier *ret = nullptr; + if (data_) { + if (camera.ok() && lens.ok()) { + lfModifier *mod = lfModifier::Create(lens.data_, camera.getCropFactor(), width, height); + mod->Initialize(lens.data_, LF_PF_F32, focalLen, aperture, focusDist > 0 ? focusDist : 1000, 0.0, LF_RECTILINEAR, LF_MODIFY_VIGNETTING | LF_MODIFY_DISTORTION, false); + ret = new LFModifier(mod); + } } return ret; } diff --git a/rtengine/rtlensfun.h b/rtengine/rtlensfun.h index aaa49c8e0..434f821fd 100644 --- a/rtengine/rtlensfun.h +++ b/rtengine/rtlensfun.h @@ -23,24 +23,34 @@ #include #include #include +#include "lcp.h" namespace rtengine { -class LFModifier { +class LFModifier: public LensCorrection { public: + ~LFModifier(); bool ok() const; - void correctDistortion(double &x, double &y); - void processVignetteLine(int width, int y, float *line); - void processVignetteLine3Channels(int width, int y, float *line); + void correctDistortion(double &x, double &y, int cx, int cy, double scale) const; + bool supportsAutoFill() const { return false; } + bool supportsCA() const { return false; } + void correctCA(double &x, double &y, int channel) const {} + void processVignetteLine(int width, int y, float *line) const; + void processVignetteLine3Channels(int width, int y, float *line) const; private: + explicit LFModifier(lfModifier *m); + LFModifier(const LFModifier &); + LFModifier &operator=(const LFModifier &); + friend class LFDatabase; - std::shared_ptr data_; + lfModifier *data_; }; class LFCamera { public: + LFCamera(); bool ok() const; Glib::ustring getMake() const; @@ -51,35 +61,41 @@ public: private: friend class LFDatabase; - std::shared_ptr data_; + const lfCamera *data_; }; class LFLens { public: + LFLens(); bool ok() const; Glib::ustring getDisplayString() const; private: friend class LFDatabase; - std::shared_ptr data_; + const lfLens *data_; }; class LFDatabase { public: static bool init(); - static LFDatabase *getInstance(); + static const LFDatabase *getInstance(); - std::vector getCameras(); - std::vector getLenses(const LFCamera &camera); - LFCamera findCamera(const Glib::ustring &make, const Glib::ustring &model); - LFLens findLens(const LFCamera &camera, const Glib::ustring &name); - LFModifier getModifier(const LFCamera &camera, const LFLens &lens, - int width, int height, - float focalLen, float aperture); + ~LFDatabase(); + + std::vector getCameras() const; + std::vector getLenses(const LFCamera &camera) const; + LFCamera findCamera(const Glib::ustring &make, const Glib::ustring &model) const; + LFLens findLens(const LFCamera &camera, const Glib::ustring &name) const; + LFModifier *getModifier(const LFCamera &camera, const LFLens &lens, + int width, int height, + float focalLen, float aperture, float focusDist) const; private: + LFDatabase(); + LFDatabase(const LFDatabase &); + LFDatabase &operator=(const LFDatabase &); static LFDatabase instance_; - std::shared_ptr data_; + lfDatabase *data_; }; } // namespace rtengine diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 52314ceaf..a5d951de2 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -959,9 +959,6 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, const ImageMetaData *metadata, double& myscale) { std::string camName = metadata->getCamera(); - double focalLen = metadata->getFocalLen(); - double focalLen35mm = metadata->getFocalLen35mm(); - float focusDist = metadata->getFocusDist(); float shutter = metadata->getShutterSpeed(); float fnumber = metadata->getFNumber(); float iso = metadata->getISOSpeed(); diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 05afd9af5..377b1bcbe 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -169,6 +169,7 @@ if(WIN32) ${GLIBMM_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} + ${LENSFUN_INCLUDE_DIRS} ) link_directories(. "${PROJECT_SOURCE_DIR}/rtexif" ${EXTRA_LIBDIR} @@ -194,6 +195,7 @@ else() ${GTK_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS} ${LCMS_INCLUDE_DIRS} + ${LENSFUN_INCLUDE_DIRS} ) link_directories(${EXTRA_LIBDIR} ${CANBERRA-GTK_LIBRARY_DIRS} @@ -251,6 +253,7 @@ target_link_libraries(rth rtengine ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ${ZLIB_LIBRARIES} + ${LENSFUN_LIBRARIES} ) target_link_libraries(rth-cli rtengine @@ -270,6 +273,7 @@ target_link_libraries(rth-cli rtengine ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ${ZLIB_LIBRARIES} + ${LENSFUN_LIBRARIES} ) # Install executables diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index 378325630..0af6d4fcf 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -21,7 +21,7 @@ #include #include "options.h" -#include "rtengine.h" +#include "../rtengine/rtengine.h" class CacheImageData: public rtengine::ImageMetaData { @@ -89,9 +89,9 @@ public: bool hasExif() const { return false; } const rtexif::TagDirectory *getExifData() const { return NULL; } bool hasIPTC() const { return false; } - const procparams::IPTCPairs getIPTCData () const { return procparams::IPTCPairs(); } + const rtengine::procparams::IPTCPairs getIPTCData () const { return rtengine::procparams::IPTCPairs(); } struct tm getDateTime () const { struct tm ret; return ret; } - time_t getDateTimeAsTS() const { time_t ret; return ret; } + time_t getDateTimeAsTS() const { return time_t(-1); } int getISOSpeed() const { return iso; } double getFNumber() const { return fnumber; } double getFocalLen() const { return focalLen; } diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ea9248ddc..588006eca 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -291,6 +291,11 @@ void ParamsEdited::set (bool v) lensProf.useDist = v; lensProf.useVign = v; lensProf.useCA = v; + lensProf.useLensfun = v; + lensProf.lfAutoMatch = v; + lensProf.lfCameraMake = v; + lensProf.lfCameraModel = v; + lensProf.lfLens = v; perspective.horizontal = v; perspective.vertical = v; gradient.enabled = v; @@ -825,6 +830,11 @@ void ParamsEdited::initFrom (const std::vector lensProf.useDist = lensProf.useDist && p.lensProf.useDist == other.lensProf.useDist; lensProf.useVign = lensProf.useVign && p.lensProf.useVign == other.lensProf.useVign; lensProf.useCA = lensProf.useCA && p.lensProf.useCA == other.lensProf.useCA; + lensProf.useLensfun = lensProf.useLensfun && p.lensProf.useLensfun == other.lensProf.useLensfun; + lensProf.lfAutoMatch = lensProf.lfAutoMatch && p.lensProf.lfAutoMatch == other.lensProf.lfAutoMatch; + lensProf.lfCameraMake = lensProf.lfCameraMake && p.lensProf.lfCameraMake == other.lensProf.lfCameraMake; + lensProf.lfCameraModel = lensProf.lfCameraModel && p.lensProf.lfCameraModel == other.lensProf.lfCameraModel; + lensProf.lfLens = lensProf.lfLens && p.lensProf.lfLens == other.lensProf.lfLens; perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal; perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical; gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 35e3c80b8..c30134f86 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -428,6 +428,7 @@ class LensProfParamsEdited { public: bool lcpFile, useDist, useVign, useCA; + bool useLensfun, lfAutoMatch, lfCameraMake, lfCameraModel, lfLens; bool isUnchanged() const; };