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) {
return 0;
} else if (fName == DEFPROFILE_DYNAMIC) {
return -1; // should not happen here
} else {
return pparams->load(fName, pedited);
}

View File

@ -30,7 +30,8 @@ set (BASESOURCEFILES
darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc wavelet.cc
dirpyrequalizer.cc hsvequalizer.cc defringe.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}")

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 "version.h"
#include "extprog.h"
#include "dynamicprofile.h"
#ifndef WIN32
#include <glibmm/fileutils.h>
@ -710,7 +711,7 @@ int processLineParams( int argc, char **argv )
rawParams = new rtengine::procparams::PartialProfile(true, true);
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;
rawParams->deleteInstance();
delete rawParams;
@ -721,7 +722,7 @@ int processLineParams( int argc, char **argv )
imgParams = new rtengine::procparams::PartialProfile(true);
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;
imgParams->deleteInstance();
delete imgParams;
@ -793,9 +794,19 @@ int processLineParams( int argc, char **argv )
if (useDefault) {
if (isRaw) {
if (options.defProfRaw == DEFPROFILE_DYNAMIC) {
rawParams->deleteInstance();
delete rawParams;
rawParams = loadDynamicProfile(ii->getMetaData());
}
std::cout << " Merging default raw processing profile" << std::endl;
rawParams->applyTo(&currentParams);
} else {
if (options.defProfImg == DEFPROFILE_DYNAMIC) {
imgParams->deleteInstance();
delete imgParams;
imgParams = loadDynamicProfile(ii->getMetaData());
}
std::cout << " Merging default non-raw processing profile" << std::endl;
imgParams->applyTo(&currentParams);
}

View File

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

View File

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

View File

@ -26,7 +26,7 @@ ProfileStore profileStore;
using namespace rtengine;
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->set(true);
@ -63,6 +63,8 @@ ProfileStore::~ProfileStore ()
partProfiles.clear ();
clearFileList();
delete internalDefaultProfile;
delete internalDefaultEntry;
delete internalDynamicEntry;
lock.release();
delete parseMutex;
parseMutex = nullptr;
@ -140,6 +142,10 @@ void ProfileStore::_parseProfiles ()
entries.push_back(internalDefaultEntry);
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.
if (findEntryFromFullPathU(options.defProfRaw) == nullptr) {
@ -273,7 +279,7 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path
return nullptr;
}
if (path == DEFPROFILE_INTERNAL) {
if (path == DEFPROFILE_INTERNAL || path == DEFPROFILE_DYNAMIC) {
return internalDefaultEntry;
}
@ -603,7 +609,6 @@ void ProfileStoreComboBox::refreshProfileList_ (Gtk::TreeModel::Row *parentRow,
*/
void ProfileStoreComboBox::updateProfileList ()
{
// clear items
clear();
refTreeModel.clear();
@ -622,6 +627,7 @@ void ProfileStoreComboBox::updateProfileList ()
// special case for the Internal default entry
addRow(profileStore.getInternalDefaultPSE());
}
addRow(profileStore.getInternalDynamicPSE());
// releasing the profilestore's entry list mutex
profileStore.releaseFileList();
@ -710,6 +716,11 @@ Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath (Glib::ustring path)
return row;
}
if (path == DEFPROFILE_DYNAMIC) {
row = findRowFromEntry(profileStore.getInternalDynamicPSE());
return row;
}
// removing the filename
Glib::ustring fName = Glib::path_get_basename(path);
@ -758,6 +769,10 @@ Glib::ustring ProfileStoreComboBox::getFullPathFromActiveRow()
return Glib::ustring(DEFPROFILE_INTERNAL);
}
if (currEntry == profileStore.getInternalDynamicPSE()) {
return Glib::ustring(DEFPROFILE_DYNAMIC);
}
path = Glib::build_filename(profileStore.getPathFromId(currEntry->parentFolderId), currEntry->label);
}

View File

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

View File

@ -30,6 +30,7 @@
#include "profilestore.h"
#include "batchqueue.h"
#include "extprog.h"
#include "dynamicprofile.h"
using namespace rtengine::procparams;
@ -217,7 +218,23 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu
const CacheImageData* cfs = getCacheImageData();
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
rtengine::ImageMetaData* imageMetaData;