started working on support for dynamic processing profiles

This commit is contained in:
Alberto Griggio 2017-02-22 18:47:00 +01:00
parent 6162cbd77d
commit d3a5a8ee96
10 changed files with 318 additions and 7 deletions

View File

@ -8079,6 +8079,8 @@ int PartialProfile::load (const Glib::ustring &fName)
if (fName == DEFPROFILE_INTERNAL) { if (fName == DEFPROFILE_INTERNAL) {
return 0; return 0;
} else if (fName == DEFPROFILE_DYNAMIC) {
return -1; // should not happen here
} else { } else {
return pparams->load(fName, pedited); return pparams->load(fName, pedited);
} }

View File

@ -30,7 +30,8 @@ set (BASESOURCEFILES
darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc wavelet.cc darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc wavelet.cc
dirpyrequalizer.cc hsvequalizer.cc defringe.cc dirpyrequalizer.cc hsvequalizer.cc defringe.cc
popupcommon.cc popupbutton.cc popuptogglebutton.cc sharpenedge.cc sharpenmicro.cc colorappearance.cc popupcommon.cc popupbutton.cc popuptogglebutton.cc sharpenedge.cc sharpenmicro.cc colorappearance.cc
filmsimulation.cc prsharpening.cc) filmsimulation.cc prsharpening.cc
dynamicprofile.cc)
include_directories (BEFORE "${CMAKE_CURRENT_BINARY_DIR}") include_directories (BEFORE "${CMAKE_CURRENT_BINARY_DIR}")

180
rtgui/dynamicprofile.cc Normal file
View File

@ -0,0 +1,180 @@
/* -*- C++ -*-
* This file is part of RawTherapee.
*
* Copyright (c) 2017 Alberto Griggio
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "dynamicprofile.h"
#include <stdlib.h>
using namespace rtengine;
using namespace rtengine::procparams;
DynamicProfileEntry::DynamicProfileEntry():
serial_number(0),
has_iso(false), iso_min(0), iso_max(1000000),
has_fnumber(false), fnumber_min(0.0), fnumber_max(1000.0),
has_focallen(false), focallen_min(0.0), focallen_max(1000000.0),
has_shutterspeed(false), shutterspeed_min(1000.0), shutterspeed_max(1.0/1000000.0),
has_expcomp(false), expcomp_min(-100.0), expcomp_max(100.0),
has_make(false), make(""),
has_model(false), model(""),
has_lens(false), lens(""),
profilepath("")
{
}
bool DynamicProfileEntry::operator<(const DynamicProfileEntry &other) const
{
return serial_number < other.serial_number;
}
bool DynamicProfileEntry::matches(const rtengine::ImageMetaData *im)
{
if (has_iso) {
int iso = im->getISOSpeed();
if (iso < iso_min || iso > iso_max) {
return false;
}
}
if (has_fnumber) {
double fnumber = im->getFNumber();
if (fnumber < fnumber_min || fnumber > fnumber_max) {
return false;
}
}
if (has_focallen) {
double focallen = im->getFocalLen();
if (focallen < focallen_min || focallen > focallen_max) {
return false;
}
}
if (has_shutterspeed) {
double shutterspeed = im->getShutterSpeed();
if (shutterspeed < shutterspeed_min || shutterspeed > shutterspeed_max){
return false;
}
}
if (has_expcomp) {
double expcomp = im->getExpComp();
if (expcomp < expcomp_min || expcomp > expcomp_max) {
return false;
}
}
if (has_make) {
if (im->getMake() != make) {
return false;
}
}
if (has_model) {
if (im->getModel() != model) {
return false;
}
}
if (has_lens) {
if (im->getLens() != lens) {
return false;
}
}
return true;
}
bool loadDynamicProfileEntries(std::vector<DynamicProfileEntry> &out)
{
out.clear();
Glib::KeyFile kf;
if (!kf.load_from_file(
Glib::build_filename(Options::rtdir, "dynamicprofile.cfg"))) {
return false;
}
printf("loading dynamic profiles...\n");
auto groups = kf.get_groups();
for (auto group : groups) {
// groups are of the form "entry N", where N is a positive integer
if (group.find("entry ") != 0) {
return false;
}
std::istringstream buf(group.c_str() + 6);
int serial = 0;
if (!(buf >> serial) || !buf.eof()) {
return false;
}
printf(" loading entry %d\n", serial);
out.emplace_back(DynamicProfileEntry());
DynamicProfileEntry &entry = out.back();
entry.serial_number = serial;
entry.has_iso = kf.get_boolean(group, "has_iso");
entry.iso_min = kf.get_integer(group, "iso_min");
entry.iso_max = kf.get_integer(group, "iso_max");
entry.has_fnumber = kf.get_boolean(group, "has_fnumber");
entry.fnumber_min = kf.get_double(group, "fnumber_min");
entry.fnumber_max = kf.get_double(group, "fnumber_max");
entry.has_focallen = kf.get_boolean(group, "has_focallen");
entry.focallen_min = kf.get_double(group, "focallen_min");
entry.focallen_max = kf.get_double(group, "focallen_max");
entry.has_shutterspeed = kf.get_boolean(group, "has_shutterspeed");
entry.shutterspeed_min = kf.get_double(group, "shutterspeed_min");
entry.shutterspeed_max = kf.get_double(group, "shutterspeed_max");
entry.has_expcomp = kf.get_boolean(group, "has_expcomp");
entry.expcomp_min = kf.get_double(group, "expcomp_min");
entry.expcomp_max = kf.get_double(group, "expcomp_max");
entry.has_make = kf.get_boolean(group, "has_make");
entry.make = kf.get_string(group, "make");
entry.has_model = kf.get_boolean(group, "has_model");
entry.model = kf.get_string(group, "model");
entry.has_lens = kf.get_boolean(group, "has_lens");
entry.lens = kf.get_string(group, "lens");
entry.profilepath = kf.get_string(group, "profilepath");
}
std::sort(out.begin(), out.end());
return true;
}
PartialProfile *loadDynamicProfile(const ImageMetaData *im)
{
PartialProfile *ret = new PartialProfile(true, true);
std::vector<DynamicProfileEntry> entries;
if (loadDynamicProfileEntries(entries)) {
for (auto &entry : entries) {
if (entry.matches(im)) {
printf("found matching profile %s\n",
entry.profilepath.c_str());
PartialProfile p(true, true);
if (!p.load(options.findProfilePath(entry.profilepath))) {
p.applyTo(ret->pparams);
} else {
printf("ERROR loading matching profile\n");
}
p.deleteInstance();
}
}
}
return ret;
}

73
rtgui/dynamicprofile.h Normal file
View File

@ -0,0 +1,73 @@
/* -*- C++ -*-
* This file is part of RawTherapee.
*
* Copyright (c) 2017 Alberto Griggio
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _DYNAMICPROFILE_H_
#define _DYNAMICPROFILE_H_
#include <glibmm.h>
#include "options.h"
class DynamicProfileEntry {
public:
DynamicProfileEntry();
bool matches(const rtengine::ImageMetaData *im);
bool operator<(const DynamicProfileEntry &other) const;
int serial_number;
bool has_iso;
int iso_min;
int iso_max;
bool has_fnumber;
double fnumber_min;
double fnumber_max;
bool has_focallen;
double focallen_min;
double focallen_max;
bool has_shutterspeed;
double shutterspeed_min;
double shutterspeed_max;
bool has_expcomp;
double expcomp_min;
double expcomp_max;
bool has_make;
std::string make;
bool has_model;
std::string model;
bool has_lens;
std::string lens;
Glib::ustring profilepath;
};
bool loadDynamicProfileEntries(std::vector<DynamicProfileEntry> &out);
rtengine::procparams::PartialProfile *loadDynamicProfile(
const rtengine::ImageMetaData *im);
#endif // _DYNAMICPROFILE_H_

View File

@ -37,6 +37,7 @@
#include "rtimage.h" #include "rtimage.h"
#include "version.h" #include "version.h"
#include "extprog.h" #include "extprog.h"
#include "dynamicprofile.h"
#ifndef WIN32 #ifndef WIN32
#include <glibmm/fileutils.h> #include <glibmm/fileutils.h>
@ -710,7 +711,7 @@ int processLineParams( int argc, char **argv )
rawParams = new rtengine::procparams::PartialProfile(true, true); rawParams = new rtengine::procparams::PartialProfile(true, true);
Glib::ustring profPath = options.findProfilePath(options.defProfRaw); Glib::ustring profPath = options.findProfilePath(options.defProfRaw);
if (options.is_defProfRawMissing() || profPath.empty() || rawParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension))) { if (options.is_defProfRawMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && rawParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension)))) {
std::cerr << "Error: default raw processing profile not found" << std::endl; std::cerr << "Error: default raw processing profile not found" << std::endl;
rawParams->deleteInstance(); rawParams->deleteInstance();
delete rawParams; delete rawParams;
@ -721,7 +722,7 @@ int processLineParams( int argc, char **argv )
imgParams = new rtengine::procparams::PartialProfile(true); imgParams = new rtengine::procparams::PartialProfile(true);
profPath = options.findProfilePath(options.defProfImg); profPath = options.findProfilePath(options.defProfImg);
if (options.is_defProfImgMissing() || profPath.empty() || imgParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension))) { if (options.is_defProfImgMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && imgParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension)))) {
std::cerr << "Error: default non-raw processing profile not found" << std::endl; std::cerr << "Error: default non-raw processing profile not found" << std::endl;
imgParams->deleteInstance(); imgParams->deleteInstance();
delete imgParams; delete imgParams;
@ -793,9 +794,19 @@ int processLineParams( int argc, char **argv )
if (useDefault) { if (useDefault) {
if (isRaw) { if (isRaw) {
if (options.defProfRaw == DEFPROFILE_DYNAMIC) {
rawParams->deleteInstance();
delete rawParams;
rawParams = loadDynamicProfile(ii->getMetaData());
}
std::cout << " Merging default raw processing profile" << std::endl; std::cout << " Merging default raw processing profile" << std::endl;
rawParams->applyTo(&currentParams); rawParams->applyTo(&currentParams);
} else { } else {
if (options.defProfImg == DEFPROFILE_DYNAMIC) {
imgParams->deleteInstance();
delete imgParams;
imgParams = loadDynamicProfile(ii->getMetaData());
}
std::cout << " Merging default non-raw processing profile" << std::endl; std::cout << " Merging default non-raw processing profile" << std::endl;
imgParams->applyTo(&currentParams); imgParams->applyTo(&currentParams);
} }

View File

@ -241,6 +241,10 @@ Glib::ustring Options::findProfilePath (Glib::ustring &profName)
return profName; return profName;
} }
if (profName == DEFPROFILE_DYNAMIC) {
return profName;
}
Glib::ustring p = profName.substr (0, 4); Glib::ustring p = profName.substr (0, 4);
if (p == "${U}") { if (p == "${U}") {

View File

@ -39,6 +39,8 @@
#define DEFPROFILE_IMG "Neutral" #define DEFPROFILE_IMG "Neutral"
// Profile name to use for internal values' profile // Profile name to use for internal values' profile
#define DEFPROFILE_INTERNAL "Neutral" #define DEFPROFILE_INTERNAL "Neutral"
// Special name for the Dynamic profile
#define DEFPROFILE_DYNAMIC "Dynamic"
class SaveFormat class SaveFormat
{ {

View File

@ -26,7 +26,7 @@ ProfileStore profileStore;
using namespace rtengine; using namespace rtengine;
using namespace rtengine::procparams; using namespace rtengine::procparams;
ProfileStore::ProfileStore () : parseMutex(nullptr), storeState(STORESTATE_NOTINITIALIZED), internalDefaultProfile(nullptr), internalDefaultEntry(nullptr) ProfileStore::ProfileStore () : parseMutex(nullptr), storeState(STORESTATE_NOTINITIALIZED), internalDefaultProfile(nullptr), internalDefaultEntry(nullptr), internalDynamicEntry(nullptr)
{ {
internalDefaultProfile = new AutoPartialProfile(); internalDefaultProfile = new AutoPartialProfile();
internalDefaultProfile->set(true); internalDefaultProfile->set(true);
@ -63,6 +63,8 @@ ProfileStore::~ProfileStore ()
partProfiles.clear (); partProfiles.clear ();
clearFileList(); clearFileList();
delete internalDefaultProfile; delete internalDefaultProfile;
delete internalDefaultEntry;
delete internalDynamicEntry;
lock.release(); lock.release();
delete parseMutex; delete parseMutex;
parseMutex = nullptr; parseMutex = nullptr;
@ -140,6 +142,10 @@ void ProfileStore::_parseProfiles ()
entries.push_back(internalDefaultEntry); entries.push_back(internalDefaultEntry);
partProfiles[internalDefaultEntry] = internalDefaultProfile; partProfiles[internalDefaultEntry] = internalDefaultProfile;
if (!internalDynamicEntry) {
internalDynamicEntry = new ProfileStoreEntry(Glib::ustring("(") + M("PROFILEPANEL_PDYNAMIC") + Glib::ustring(")"), PSET_FILE, 0, 0);
// do not add it to the entries. This is here only for the preferences dialog
}
// Check if the default profiles has been found. // Check if the default profiles has been found.
if (findEntryFromFullPathU(options.defProfRaw) == nullptr) { if (findEntryFromFullPathU(options.defProfRaw) == nullptr) {
@ -273,7 +279,7 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path
return nullptr; return nullptr;
} }
if (path == DEFPROFILE_INTERNAL) { if (path == DEFPROFILE_INTERNAL || path == DEFPROFILE_DYNAMIC) {
return internalDefaultEntry; return internalDefaultEntry;
} }
@ -603,7 +609,6 @@ void ProfileStoreComboBox::refreshProfileList_ (Gtk::TreeModel::Row *parentRow,
*/ */
void ProfileStoreComboBox::updateProfileList () void ProfileStoreComboBox::updateProfileList ()
{ {
// clear items // clear items
clear(); clear();
refTreeModel.clear(); refTreeModel.clear();
@ -622,6 +627,7 @@ void ProfileStoreComboBox::updateProfileList ()
// special case for the Internal default entry // special case for the Internal default entry
addRow(profileStore.getInternalDefaultPSE()); addRow(profileStore.getInternalDefaultPSE());
} }
addRow(profileStore.getInternalDynamicPSE());
// releasing the profilestore's entry list mutex // releasing the profilestore's entry list mutex
profileStore.releaseFileList(); profileStore.releaseFileList();
@ -710,6 +716,11 @@ Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath (Glib::ustring path)
return row; return row;
} }
if (path == DEFPROFILE_DYNAMIC) {
row = findRowFromEntry(profileStore.getInternalDynamicPSE());
return row;
}
// removing the filename // removing the filename
Glib::ustring fName = Glib::path_get_basename(path); Glib::ustring fName = Glib::path_get_basename(path);
@ -758,6 +769,10 @@ Glib::ustring ProfileStoreComboBox::getFullPathFromActiveRow()
return Glib::ustring(DEFPROFILE_INTERNAL); return Glib::ustring(DEFPROFILE_INTERNAL);
} }
if (currEntry == profileStore.getInternalDynamicPSE()) {
return Glib::ustring(DEFPROFILE_DYNAMIC);
}
path = Glib::build_filename(profileStore.getPathFromId(currEntry->parentFolderId), currEntry->label); path = Glib::build_filename(profileStore.getPathFromId(currEntry->parentFolderId), currEntry->label);
} }

View File

@ -144,6 +144,7 @@ private:
StoreState storeState; StoreState storeState;
rtengine::procparams::AutoPartialProfile *internalDefaultProfile; rtengine::procparams::AutoPartialProfile *internalDefaultProfile;
ProfileStoreEntry *internalDefaultEntry; ProfileStoreEntry *internalDefaultEntry;
ProfileStoreEntry *internalDynamicEntry;
/** Alphabetically ordered list of folder and files through Gtk::Label sub-class; /** Alphabetically ordered list of folder and files through Gtk::Label sub-class;
* ready to be used in Menu and Combobox * ready to be used in Menu and Combobox
@ -198,6 +199,11 @@ public:
return internalDefaultEntry; return internalDefaultEntry;
} }
const ProfileStoreEntry* getInternalDynamicPSE()
{
return internalDynamicEntry;
}
void addListener(ProfileStoreListener *listener); void addListener(ProfileStoreListener *listener);
void removeListener(ProfileStoreListener *listener); void removeListener(ProfileStoreListener *listener);

View File

@ -30,6 +30,7 @@
#include "profilestore.h" #include "profilestore.h"
#include "batchqueue.h" #include "batchqueue.h"
#include "extprog.h" #include "extprog.h"
#include "dynamicprofile.h"
using namespace rtengine::procparams; using namespace rtengine::procparams;
@ -217,7 +218,23 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu
const CacheImageData* cfs = getCacheImageData(); const CacheImageData* cfs = getCacheImageData();
Glib::ustring defaultPparamsPath = options.findProfilePath(defProf); Glib::ustring defaultPparamsPath = options.findProfilePath(defProf);
if (!options.CPBPath.empty() && !defaultPparamsPath.empty() && (!hasProcParams() || forceCPB) && cfs && cfs->exifValid) { if (defProf == DEFPROFILE_DYNAMIC && (!hasProcParams() || forceCPB) && cfs && cfs->exifValid) {
rtengine::ImageMetaData* imageMetaData;
if (getType() == FT_Raw) {
rtengine::RawMetaDataLocation metaData = rtengine::Thumbnail::loadMetaDataFromRaw(fname);
imageMetaData = rtengine::ImageMetaData::fromFile (fname, &metaData);
} else {
imageMetaData = rtengine::ImageMetaData::fromFile (fname, nullptr);
}
PartialProfile *pp = loadDynamicProfile(imageMetaData);
if (options.paramsLoadLocation == PLL_Input) {
pp->pparams->save(fname + paramFileExtension);
} else {
pp->pparams->save(getCacheFileName ("profiles", paramFileExtension));
}
pp->deleteInstance();
delete pp;
} else if (defProf != DEFPROFILE_DYNAMIC && !options.CPBPath.empty() && !defaultPparamsPath.empty() && (!hasProcParams() || forceCPB) && cfs && cfs->exifValid) {
// First generate the communication file, with general values and EXIF metadata // First generate the communication file, with general values and EXIF metadata
rtengine::ImageMetaData* imageMetaData; rtengine::ImageMetaData* imageMetaData;