/* * This file is part of RawTherapee. * * Copyright (c) 2012 Oliver Duis * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include #include #include #include #include #include "lensprofile.h" #include "guiutils.h" #include "rtimage.h" #include "options.h" #include "../rtengine/lcp.h" #include "../rtengine/procparams.h" #include "../rtengine/rtlensfun.h" using namespace rtengine; using namespace rtengine::procparams; const Glib::ustring LensProfilePanel::TOOL_NAME = "lensprof"; LensProfilePanel::LensProfilePanel() : FoldableToolPanel(this, TOOL_NAME, M("TP_LENSPROFILE_LABEL")), lcModeChanged(false), lcpFileChanged(false), useDistChanged(false), useVignChanged(false), useCAChanged(false), useLensfunChanged(false), lensfunAutoChanged(false), lensfunCameraChanged(false), lensfunLensChanged(false), allowFocusDep(true), isRaw(true), metadata(nullptr), modesGrid(Gtk::manage(new Gtk::Grid())), distGrid(Gtk::manage((new Gtk::Grid()))), corrUnchangedRB(Gtk::manage((new Gtk::RadioButton(M("GENERAL_UNCHANGED"))))), corrOffRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("GENERAL_NONE"))))), corrLensfunAutoRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_AUTOMATCH"))))), corrLensfunManualRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_MANUAL"))))), corrLcpFileRB(Gtk::manage((new Gtk::RadioButton(corrGroup, M("TP_LENSPROFILE_CORRECTION_LCPFILE"))))), corrLcpFileChooser(Gtk::manage((new MyFileChooserButton(M("TP_LENSPROFILE_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)))), lensfunCamerasLbl(Gtk::manage((new Gtk::Label(M("EXIFFILTER_CAMERA"))))), lensfunCameras(Gtk::manage((new MyComboBox()))), lensfunLensesLbl(Gtk::manage((new Gtk::Label(M("EXIFFILTER_LENS"))))), lensfunLenses(Gtk::manage((new MyComboBox()))), warning(Gtk::manage(new RTImage("warning.png"))), ckbUseDist(Gtk::manage((new Gtk::CheckButton(M("TP_LENSPROFILE_USE_GEOMETRIC"))))), ckbUseVign(Gtk::manage((new Gtk::CheckButton(M("TP_LENSPROFILE_USE_VIGNETTING"))))), ckbUseCA(Gtk::manage((new Gtk::CheckButton(M("TP_LENSPROFILE_USE_CA"))))) { if (!lf) { lf = new LFDbHelper(); } // Main containers: Gtk::Frame *nodesFrame = Gtk::manage(new Gtk::Frame(M("TP_LENSPROFILE_MODE_HEADER"))); nodesFrame->set_label_align (0.025, 0.5); modesGrid->get_style_context()->add_class("grid-spacing"); setExpandAlignProperties(modesGrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); Gtk::Frame *distFrame = Gtk::manage(new Gtk::Frame(M("TP_LENSPROFILE_USE_HEADER"))); distFrame->set_label_align (0.025, 0.5); distGrid->get_style_context()->add_class("grid-spacing"); setExpandAlignProperties(distGrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); // Mode choice widgets: setExpandAlignProperties(corrLcpFileChooser, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); // Manually-selected profile widgets: setExpandAlignProperties(lensfunCamerasLbl, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); lensfunCameras->set_model(lf->lensfunCameraModel); lensfunCameras->pack_start(lf->lensfunModelCam.model); lensfunCameras->setPreferredWidth(50, 120); setExpandAlignProperties(lensfunCameras, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); Gtk::CellRendererText* const camerasCellRenderer = static_cast(lensfunCameras->get_first_cell()); camerasCellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE; camerasCellRenderer->property_ellipsize_set() = true; setExpandAlignProperties(lensfunLensesLbl, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); lensfunLenses->set_model(lf->lensfunLensModel); lensfunLenses->pack_start(lf->lensfunModelLens.prettylens); lensfunLenses->setPreferredWidth(50, 120); setExpandAlignProperties(lensfunLenses, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); Gtk::CellRendererText* const lensesCellRenderer = static_cast(lensfunLenses->get_first_cell()); lensesCellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE; lensesCellRenderer->property_ellipsize_set() = true; warning->set_tooltip_text(M("TP_LENSPROFILE_LENS_WARNING")); warning->hide(); // LCP file filter config: const Glib::RefPtr filterLCP = Gtk::FileFilter::create(); filterLCP->set_name(M("FILECHOOSER_FILTER_LCP")); filterLCP->add_pattern("*.lcp"); filterLCP->add_pattern("*.LCP"); corrLcpFileChooser->add_filter(filterLCP); const Glib::ustring defDir = LCPStore::getInstance()->getDefaultCommonDirectory(); if (!defDir.empty()) { #ifdef WIN32 corrLcpFileChooser->set_show_hidden(true); // ProgramData is hidden on Windows #endif corrLcpFileChooser->set_current_folder(defDir); } else if (!options.lastLensProfileDir.empty()) { corrLcpFileChooser->set_current_folder(options.lastLensProfileDir); } bindCurrentFolder(*corrLcpFileChooser, options.lastLensProfileDir); // Choice of properties to correct, applicable to all modes: // Populate modes grid: modesGrid->attach(*corrOffRB, 0, 0, 3, 1); modesGrid->attach(*corrLensfunAutoRB, 0, 1, 3, 1); modesGrid->attach(*corrLensfunManualRB, 0, 2, 3, 1); modesGrid->attach(*lensfunCamerasLbl, 0, 3, 1, 1); modesGrid->attach(*lensfunCameras, 1, 3, 1, 1); modesGrid->attach(*lensfunLensesLbl, 0, 4, 1, 1); modesGrid->attach(*lensfunLenses, 1, 4, 1, 1); modesGrid->attach(*warning, 2, 3, 1, 2); modesGrid->attach(*corrLcpFileRB, 0, 5, 1, 1); modesGrid->attach(*corrLcpFileChooser, 1, 5, 1, 1); // Populate distortions grid: distGrid->attach(*ckbUseDist, 0, 0, 1, 1); distGrid->attach(*ckbUseVign, 0, 1, 1, 1); distGrid->attach(*ckbUseCA, 0, 2, 1, 1); // Attach grids: nodesFrame->add(*modesGrid); distFrame->add(*distGrid); pack_start(*nodesFrame, Gtk::PACK_EXPAND_WIDGET); pack_start(*distFrame, Gtk::PACK_EXPAND_WIDGET); // Signals: conLCPFile = corrLcpFileChooser->signal_file_set().connect(sigc::mem_fun(*this, &LensProfilePanel::onLCPFileChanged)); conUseDist = ckbUseDist->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged)); ckbUseVign->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onUseVignChanged)); ckbUseCA->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onUseCAChanged)); lensfunCameras->signal_changed().connect(sigc::mem_fun(*this, &LensProfilePanel::onLensfunCameraChanged)); lensfunLenses->signal_changed().connect(sigc::mem_fun(*this, &LensProfilePanel::onLensfunLensChanged)); corrOffRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrOffRB)); corrLensfunAutoRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrLensfunAutoRB)); corrLensfunManualRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrLensfunManualRB)); corrLcpFileRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrLcpFileRB)); } void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener(); conUseDist.block(true); // corrLensfunAutoRB->set_sensitive(true); switch (pp->lensProf.lcMode) { case procparams::LensProfParams::LcMode::LCP: { corrLcpFileRB->set_active(true); setManualParamsVisibility(false); break; } case procparams::LensProfParams::LcMode::LENSFUNAUTOMATCH: { corrLensfunAutoRB->set_active(true); if (batchMode) { setManualParamsVisibility(false); } break; } case procparams::LensProfParams::LcMode::LENSFUNMANUAL: { corrLensfunManualRB->set_active(true); break; } case procparams::LensProfParams::LcMode::NONE: { corrOffRB->set_active(true); setManualParamsVisibility(false); break; } } if (pp->lensProf.lcpFile.empty()) { const Glib::ustring lastFolder = corrLcpFileChooser->get_current_folder(); corrLcpFileChooser->set_current_folder(lastFolder); corrLcpFileChooser->unselect_all(); bindCurrentFolder(*corrLcpFileChooser, options.lastLensProfileDir); updateDisabled(false); } else if (LCPStore::getInstance()->isValidLCPFileName(pp->lensProf.lcpFile)) { corrLcpFileChooser->set_filename(pp->lensProf.lcpFile); if (corrLcpFileRB->get_active()) { updateDisabled(true); } } else { corrLcpFileChooser->unselect_filename(corrLcpFileChooser->get_filename()); updateDisabled(false); } const LFDatabase* const db = LFDatabase::getInstance(); LFCamera c; if (pp->lensProf.lfAutoMatch()) { if (metadata) { c = db->findCamera(metadata->getMake(), metadata->getModel()); setLensfunCamera(c.getMake(), c.getModel()); } } else if (pp->lensProf.lfManual()) { setLensfunCamera(pp->lensProf.lfCameraMake, pp->lensProf.lfCameraModel); } if (pp->lensProf.lfAutoMatch()) { if (metadata) { const LFLens l = db->findLens(c, metadata->getLens()); setLensfunLens(l.getLens()); } } else if (pp->lensProf.lfManual()) { setLensfunLens(pp->lensProf.lfLens); } /* if (!batchMode && !checkLensfunCanCorrect(true)) { if (corrLensfunAutoRB->get_active()) { corrOffRB->set_active(true); } corrLensfunAutoRB->set_sensitive(false); } if (!batchMode && corrLensfunManualRB->get_active() && !checkLensfunCanCorrect(false)) { corrOffRB->set_active(true); } */ ckbUseDist->set_active(pp->lensProf.useDist); ckbUseVign->set_active(pp->lensProf.useVign); ckbUseCA->set_active(pp->lensProf.useCA); if (pedited) { corrUnchangedRB->set_active(!pedited->lensProf.lcMode); ckbUseDist->set_inconsistent(!pedited->lensProf.useDist); ckbUseVign->set_inconsistent(!pedited->lensProf.useVign); ckbUseCA->set_inconsistent(!pedited->lensProf.useCA); if (!pedited->lensProf.lfCameraMake || !pedited->lensProf.lfCameraModel) { setLensfunCamera("", ""); } if (!pedited->lensProf.lfLens) { setLensfunLens(""); } ckbUseDist->set_sensitive(true); ckbUseVign->set_sensitive(true); ckbUseCA->set_sensitive(true); } lcModeChanged = lcpFileChanged = useDistChanged = useVignChanged = useCAChanged = false; useLensfunChanged = lensfunAutoChanged = lensfunCameraChanged = lensfunLensChanged = false; updateLensfunWarning(); enableListener(); conUseDist.block(false); } void LensProfilePanel::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { if (corrLcpFileRB->get_active()) { pp->lensProf.lcMode = procparams::LensProfParams::LcMode::LCP; } else if (corrLensfunManualRB->get_active()) { pp->lensProf.lcMode = procparams::LensProfParams::LcMode::LENSFUNMANUAL; } else if (corrLensfunAutoRB->get_active()) { pp->lensProf.lcMode = procparams::LensProfParams::LcMode::LENSFUNAUTOMATCH; } else if (corrOffRB->get_active()) { pp->lensProf.lcMode = procparams::LensProfParams::LcMode::NONE; } if (LCPStore::getInstance()->isValidLCPFileName(corrLcpFileChooser->get_filename())) { pp->lensProf.lcpFile = corrLcpFileChooser->get_filename(); } else { pp->lensProf.lcpFile = ""; } pp->lensProf.useDist = ckbUseDist->get_active(); pp->lensProf.useVign = ckbUseVign->get_active(); pp->lensProf.useCA = ckbUseCA->get_active(); const auto itc = lensfunCameras->get_active(); if (itc && !corrLensfunAutoRB->get_active()) { pp->lensProf.lfCameraMake = (*itc)[lf->lensfunModelCam.make]; pp->lensProf.lfCameraModel = (*itc)[lf->lensfunModelCam.model]; } else { pp->lensProf.lfCameraMake = ""; pp->lensProf.lfCameraModel = ""; } const auto itl = lensfunLenses->get_active(); if (itl && !corrLensfunAutoRB->get_active()) { pp->lensProf.lfLens = (*itl)[lf->lensfunModelLens.lens]; } else { pp->lensProf.lfLens = ""; } if (pedited) { pedited->lensProf.lcMode = lcModeChanged; pedited->lensProf.lcpFile = lcpFileChanged; pedited->lensProf.useDist = useDistChanged; pedited->lensProf.useVign = useVignChanged; pedited->lensProf.useCA = useCAChanged; pedited->lensProf.useLensfun = useLensfunChanged; pedited->lensProf.lfAutoMatch = lensfunAutoChanged; pedited->lensProf.lfCameraMake = lensfunCameraChanged; pedited->lensProf.lfCameraModel = lensfunCameraChanged; pedited->lensProf.lfLens = lensfunLensChanged; } } void LensProfilePanel::setRawMeta(bool raw, const rtengine::FramesMetaData* pMeta) { if ((!raw || pMeta->getFocusDist() <= 0) && !batchMode) { disableListener(); // CA is very focus layer dependent, otherwise it might even worsen things allowFocusDep = false; ckbUseCA->set_active(false); ckbUseCA->set_sensitive(false); enableListener(); } isRaw = raw; metadata = pMeta; } void LensProfilePanel::onLCPFileChanged() { lcpFileChanged = true; const bool valid = LCPStore::getInstance()->isValidLCPFileName(corrLcpFileChooser->get_filename()); updateDisabled(valid); if (listener) { if (valid) { disableListener(); corrLcpFileRB->set_active(true); enableListener(); } listener->panelChanged(EvLCPFile, Glib::path_get_basename(corrLcpFileChooser->get_filename())); } } void LensProfilePanel::onUseDistChanged() { useDistChanged = true; if (ckbUseDist->get_inconsistent()) { ckbUseDist->set_inconsistent(false); ckbUseDist->set_active(false); } if (listener) { listener->panelChanged(EvLCPUseDist, ckbUseDist->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } void LensProfilePanel::onUseVignChanged() { useVignChanged = true; if (ckbUseVign->get_inconsistent()) { ckbUseVign->set_inconsistent(false); ckbUseVign->set_active(false); } if (listener) { listener->panelChanged(EvLCPUseVign, ckbUseVign->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } void LensProfilePanel::onUseCAChanged() { useCAChanged = true; if (ckbUseCA->get_inconsistent()) { ckbUseCA->set_inconsistent(false); ckbUseCA->set_active(false); } if (listener) { listener->panelChanged(EvLCPUseCA, ckbUseCA->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } void LensProfilePanel::setBatchMode(bool yes) { FoldableToolPanel::setBatchMode(yes); corrUnchangedRB->set_group(corrGroup); modesGrid->attach_next_to(*corrUnchangedRB, Gtk::POS_TOP, 3, 1); corrUnchangedRB->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged), corrUnchangedRB)); corrUnchangedRB->set_active(true); } void LensProfilePanel::onLensfunCameraChanged() { const auto iter = lensfunCameras->get_active(); if (iter) { lensfunCameraChanged = true; if (listener) { disableListener(); corrLensfunManualRB->set_active(true); enableListener(); const Glib::ustring name = (*iter)[lf->lensfunModelCam.model]; listener->panelChanged(EvLensCorrLensfunCamera, name); } } updateLensfunWarning(); } void LensProfilePanel::onLensfunLensChanged() { const auto iter = lensfunLenses->get_active(); if (iter) { lensfunLensChanged = true; if (listener) { disableListener(); corrLensfunManualRB->set_active(true); enableListener(); const Glib::ustring name = (*iter)[lf->lensfunModelLens.prettylens]; listener->panelChanged(EvLensCorrLensfunLens, name); } } updateLensfunWarning(); } void LensProfilePanel::onCorrModeChanged(const Gtk::RadioButton* rbChanged) { if (rbChanged->get_active()) { // because the method gets called for the enabled AND the disabled RadioButton, we do the processing only for the enabled one Glib::ustring mode; if (rbChanged == corrOffRB) { lcModeChanged = true; useLensfunChanged = true; lensfunAutoChanged = true; lcpFileChanged = false; ckbUseDist->set_sensitive(false); ckbUseVign->set_sensitive(false); ckbUseCA->set_sensitive(false); mode = M("GENERAL_NONE"); } else if (rbChanged == corrLensfunAutoRB) { lcModeChanged = true; useLensfunChanged = true; lensfunAutoChanged = true; lensfunCameraChanged = true; lensfunLensChanged = true; lcpFileChanged = false; ckbUseDist->set_sensitive(true); ckbUseVign->set_sensitive(true); ckbUseCA->set_sensitive(true); const bool disabled = disableListener(); if (batchMode) { setLensfunCamera("", ""); setLensfunLens(""); } else if (metadata) { const LFDatabase* const db = LFDatabase::getInstance(); const LFCamera c = db->findCamera(metadata->getMake(), metadata->getModel()); const LFLens l = db->findLens(c, metadata->getLens()); setLensfunCamera(c.getMake(), c.getModel()); setLensfunLens(l.getLens()); } if (disabled) { enableListener(); } mode = M("TP_LENSPROFILE_CORRECTION_AUTOMATCH"); } else if (rbChanged == corrLensfunManualRB) { lcModeChanged = true; useLensfunChanged = true; lensfunAutoChanged = true; lensfunCameraChanged = true; lensfunLensChanged = true; lcpFileChanged = false; ckbUseDist->set_sensitive(true); ckbUseVign->set_sensitive(true); ckbUseCA->set_sensitive(false); mode = M("TP_LENSPROFILE_CORRECTION_MANUAL"); } else if (rbChanged == corrLcpFileRB) { lcModeChanged = true; useLensfunChanged = true; lensfunAutoChanged = true; lcpFileChanged = true; updateDisabled(true); mode = M("TP_LENSPROFILE_CORRECTION_LCPFILE"); } else if (rbChanged == corrUnchangedRB) { lcModeChanged = false; useLensfunChanged = false; lensfunAutoChanged = false; lcpFileChanged = false; lensfunCameraChanged = false; lensfunLensChanged = false; ckbUseDist->set_sensitive(true); ckbUseVign->set_sensitive(true); ckbUseCA->set_sensitive(true); mode = M("GENERAL_UNCHANGED"); } updateLensfunWarning(); if (rbChanged == corrLensfunManualRB || (!batchMode && rbChanged == corrLensfunAutoRB)) { setManualParamsVisibility(true); } else { setManualParamsVisibility(false); } if (listener) { listener->panelChanged(EvLensCorrMode, mode); } } } //----------------------------------------------------------------------------- // LFDbHelper //----------------------------------------------------------------------------- LensProfilePanel::LFDbHelper::LFDbHelper() { lensfunCameraModel = Gtk::TreeStore::create(lensfunModelCam); lensfunLensModel = Gtk::TreeStore::create(lensfunModelLens); #ifdef _OPENMP #pragma omp parallel sections if (!settings->verbose) #endif { #ifdef _OPENMP #pragma omp section #endif { fillLensfunCameras(); } #ifdef _OPENMP #pragma omp section #endif { fillLensfunLenses(); } } } void LensProfilePanel::LFDbHelper::fillLensfunCameras() { if (settings->verbose) { std::cout << "LENSFUN, scanning cameras:" << std::endl; } std::map> camnames; const auto camlist = LFDatabase::getInstance()->getCameras(); for (const auto& c : camlist) { camnames[c.getMake()].insert(c.getModel()); if (settings->verbose) { std::cout << " found: " << c.getDisplayString().c_str() << std::endl; } } for (const auto& p : camnames) { Gtk::TreeModel::Row row = *(lensfunCameraModel->append()); row[lensfunModelCam.make] = p.first; row[lensfunModelCam.model] = p.first; for (const auto& c : p.second) { Gtk::TreeModel::Row child = *(lensfunCameraModel->append(row.children())); child[lensfunModelCam.make] = p.first; child[lensfunModelCam.model] = c; } } } void LensProfilePanel::LFDbHelper::fillLensfunLenses() { if (settings->verbose) { std::cout << "LENSFUN, scanning lenses:" << std::endl; } std::map> lenses; const auto lenslist = LFDatabase::getInstance()->getLenses(); for (const auto& l : lenslist) { const auto& name = l.getLens(); const auto& make = l.getMake(); lenses[make].insert(name); if (settings->verbose) { std::cout << " found: " << l.getDisplayString().c_str() << std::endl; } } for (const auto& p : lenses) { Gtk::TreeModel::Row row = *(lensfunLensModel->append()); row[lensfunModelLens.lens] = p.first; row[lensfunModelLens.prettylens] = p.first; for (auto &c : p.second) { Gtk::TreeModel::Row child = *(lensfunLensModel->append(row.children())); child[lensfunModelLens.lens] = c; if (c.find(p.first, p.first.size() + 1) == p.first.size() + 1) { child[lensfunModelLens.prettylens] = c.substr(p.first.size() + 1); } else { child[lensfunModelLens.prettylens] = c; } } } } void LensProfilePanel::updateDisabled(bool enable) { if (!batchMode) { ckbUseDist->set_sensitive(enable); ckbUseVign->set_sensitive(enable && isRaw); ckbUseCA->set_sensitive(enable && allowFocusDep); } } bool LensProfilePanel::setLensfunCamera(const Glib::ustring& make, const Glib::ustring& model) { if (!make.empty() && !model.empty()) { const auto camera_it = lensfunCameras->get_active(); if (camera_it && (*camera_it)[lf->lensfunModelCam.make] == make && (*camera_it)[lf->lensfunModelCam.model] == model) { return true; } // search for the active row for (const auto& row : lf->lensfunCameraModel->children()) { if (row[lf->lensfunModelCam.make] == make) { const auto& c = row.children(); for (auto model_it = c.begin(), end = c.end(); model_it != end; ++model_it) { const auto& childrow = *model_it; if (childrow[lf->lensfunModelCam.model] == model) { lensfunCameras->set_active(model_it); return true; } } break; } } } lensfunCameras->set_active(-1); return false; } bool LensProfilePanel::setLensfunLens(const Glib::ustring& lens) { if (!lens.empty()) { const auto lens_it = lensfunLenses->get_active(); if (lens_it && (*lens_it)[lf->lensfunModelLens.lens] == lens) { return true; } bool first_maker_found = false; for (const auto& row : lf->lensfunLensModel->children()) { if (lens.find(row[lf->lensfunModelLens.lens]) == 0) { const auto& c = row.children(); for (auto model_it = c.begin(), end = c.end(); model_it != end; ++model_it) { const auto& childrow = *model_it; if (childrow[lf->lensfunModelLens.lens] == lens) { lensfunLenses->set_active(model_it); return true; } } // we do not break immediately here, because there might be multiple makers // sharing the same prefix (e.g. "Leica" and "Leica Camera AG"). // therefore, we break below when the lens doesn't match any of them first_maker_found = true; } else if (first_maker_found) { break; } } } lensfunLenses->set_active(-1); return false; } bool LensProfilePanel::checkLensfunCanCorrect(bool automatch) { if (!metadata) { return false; } rtengine::procparams::ProcParams lpp; write(&lpp); const std::unique_ptr mod(LFDatabase::getInstance()->findModifier(lpp.lensProf, metadata, 100, 100, lpp.coarse, -1)); return static_cast(mod); } void LensProfilePanel::setManualParamsVisibility(bool setVisible) { if (setVisible) { lensfunCamerasLbl->show(); lensfunCameras->show(); lensfunLensesLbl->show(); lensfunLenses->show(); updateLensfunWarning(); } else { lensfunCamerasLbl->hide(); lensfunCameras->hide(); lensfunLensesLbl->hide(); lensfunLenses->hide(); warning->hide(); } } void LensProfilePanel::updateLensfunWarning() { warning->hide(); if (corrLensfunManualRB->get_active() || corrLensfunAutoRB->get_active()) { const LFDatabase* const db = LFDatabase::getInstance(); const auto itc = lensfunCameras->get_active(); if (!itc) { return; } const LFCamera c = db->findCamera((*itc)[lf->lensfunModelCam.make], (*itc)[lf->lensfunModelCam.model]); const auto itl = lensfunLenses->get_active(); if (!itl) { return; } const LFLens l = db->findLens(LFCamera(), (*itl)[lf->lensfunModelLens.lens]); const float lenscrop = l.getCropFactor(); const float camcrop = c.getCropFactor(); if (lenscrop <= 0 || camcrop <= 0 || lenscrop / camcrop >= 1.01f) { warning->show(); } ckbUseVign->set_sensitive(l.hasVignettingCorrection()); ckbUseDist->set_sensitive(l.hasDistortionCorrection()); ckbUseCA->set_sensitive(l.hasCACorrection()); if (!isRaw || !l.hasVignettingCorrection()) { ckbUseVign->set_active(false); } if (!l.hasDistortionCorrection()) { ckbUseDist->set_active(false); } if (!l.hasCACorrection()) { ckbUseCA->set_active(false); } } } LensProfilePanel::LFDbHelper* LensProfilePanel::lf(nullptr);