diff --git a/rtengine/camconst.json b/rtengine/camconst.json index aa2e3c370..03d962a8c 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -145,7 +145,9 @@ differences in scaling, there can be a bit of variation. If you don't have access to the widest lens available for the system (say only an f/1.8 lens instead of an f/1.2) it can still be valuable to have the values down to what you can provide. Brands known to have models that have aperture scaling -include Canon, Nikon and Sony. +of white levels include Canon and Nikon. Note that if white levels are not +scaled the camera may have raw scaling anyway (Sony for example), but as +such scaling will not affect raw decoding we don't need to care about that. PROVIDE CONSERVATIVE VALUES. Most cameras have a little noise at the white level, and some can have a lot. In your raw analyzer, move around and look at @@ -234,10 +236,35 @@ Some cameras have different white levels on different color channels. When this is the case the difference is often so small so you can just provide a single value instead, ie a conservative value based on the lowest clipping. +What we know at the time of writing about different brands/models (not +complete info): + + - Canon CR2: typically same clipping per channel, but significant variations + on ISO and aperture. Maxes out at 16383, black level measured on masked + black pixels, ie don't provide that. + - Nikon NEF: sometimes different clipping per color (most often negligible + though). Will do aperture and ISO scaling, but often to a lesser extent + than Canon files, ie not as much to gain. + - Sony ARW2: no scaling. Generally black level around 512, and white level + 16350. + */ {"camera_constants": [ - { +/* + +When adding camera constants please set a quality level so we know the status for future updates + +Quality A: complete information, no need to add more, to the best of our knowledge +Quality B: not complete, but very little to gain from adding more +Quality C: complementing with additional information would provide significant gain +Quality X: unknown, ie we knowing to little about the camera properties to know if + we have enough info or not. + +*/ + + + { // quality A (only aperture scaling for f/1.2 missing) "make_model": "Canon EOS 5D Mark II", "dcraw_matrix": [ 4716,603,-830,-7798,15474,2480,-1496,1937,6651 ], "ranges": { @@ -283,7 +310,7 @@ single value instead, ie a conservative value based on the lowest clipping. ] } }, - { + { // quality B, more aperture scalings desired "make_model": "Canon EOS 5D Mark III", "dcraw_matrix": [ 6722,-635,-963,-4287,12460,2028,-908,2162,5668 ], "ranges": { @@ -330,56 +357,59 @@ single value instead, ie a conservative value based on the lowest clipping. } }, - { + { // quality B, lacks aperture and ISO scaling, known to exist, but little to gain as the levels are so close to white_max "make_model": "Nikon D7000", "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], // matrix provided by Tanveer(tsk1979) - /* Haven't tested the camera for aperture scaling or ISO differences on white levels, ie there may - be further improvements to make. Differences between white levels on the channels are so small - that there's little value to provide for each (rather than just set a single value at 15760), but - we do this anyway as this is the first entry after the separate-white-level code was added, and - we wanted an entry to show the concept. G1 and G2 have the same level, thus only 3 numbers in the array. */ - "ranges": { "white": [ 16370, 15760, 16370 ] } + "ranges": { + // measured at ISO 100. ISO differences not measured, but known to exist + "white": [ 16370, // 16383 typical + 15760, // 15778 typical + 16370 // 16383 typical + ], + "white_max": 16383 + // aperture scaling not measured, but known to exist, at f/1.8 the G channels hits white_max + } }, - { + { // quality A "make_model": "Sony SLT-A77", "dcraw_matrix": [ 5126,-830,-261,-4788,12196,2934,-948,1602,7068 ], // matrix provided by Colin Walker // note: Sony ARW2 file format gets 14 bit values, not 12 bit like in dcraw 9.19 "ranges": { "black": 512, "white": 16350 } }, - { + { // quality A "make_model": [ "Sony SLT-A99", "Sony SLT-A99V" ], "dcraw_matrix": [ 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 ], "ranges": { "black": 512, "white": 16350 } }, // Phase One: color matrices borrowed from Adobe DNG Converter, black/white levels tested on actual raw files - { + { // quality A "make_model": [ "Phase One P40+", "Phase One IQ140", "Phase One P65+", "Phase One IQ160" ], "dcraw_matrix": [ 8035,435,-962,-6001,13872,2320,-1159,3065,5434 ], "ranges": { "black": 0, "white": 64400 } }, - { + { // quality A "make_model": "Phase One IQ180", "dcraw_matrix": [ 6294,686,-712,-5435,13417,2211,-1006,2435,5042 ], "ranges": { "black": 0, "white": 64400 } }, - { + { // quality A "make_model": [ "Phase One P20", "Phase One P20+", "Phase One P25", "Phase One P25+" ], "dcraw_matrix": [ 2905,732,-237,-8135,16626,1476,-3038,4253,7517 ], "ranges": { "black": 0, "white": 64400 } }, - { + { // quality A "make_model": [ "Phase One P21", "Phase One P21+" ], "dcraw_matrix": [ 6516,-2050,-507,-8217,16703,1479,-3492,4741,8489 ], "ranges": { "black": 0, "white": 64400 } }, - { + { // quality A "make_model": [ "Phase One P30", "Phase One P30+"], "dcraw_matrix": [ 4516,-244,-36,-7020,14976,2174,-3206,4670,7087 ], "ranges": { "black": 0, "white": 64400 } }, - { + { // quality A "make_model": [ "Phase One 45", "Phase One 45+" ], "dcraw_matrix": [ 5053,-24,-117,-5685,14077,1703,-2619,4491,5850 ], "ranges": { "black": 0, "white": 64400 } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 86ba6874b..11ee198b7 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -425,7 +425,46 @@ void ProcParams::setDefaults () { ppVersion = PPVERSION; } -int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* pedited) const { +static Glib::ustring expandRelativePath(Glib::ustring procparams_fname, Glib::ustring prefix, Glib::ustring embedded_fname) { + if (embedded_fname == "" || !Glib::path_is_absolute(procparams_fname)) { + return embedded_fname; + } + if (prefix != "") { + if (embedded_fname.length() < prefix.length() || embedded_fname.substr(0, prefix.length()) != prefix) { + return embedded_fname; + } + embedded_fname = embedded_fname.substr(prefix.length()); + } + if (Glib::path_is_absolute(embedded_fname)) { + return prefix + embedded_fname; + } + Glib::ustring absPath = prefix + Glib::path_get_dirname(procparams_fname) + G_DIR_SEPARATOR_S + embedded_fname; + return absPath; +} + +static Glib::ustring relativePathIfInside(Glib::ustring procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname) { + if (fnameAbsolute || embedded_fname == "" || !Glib::path_is_absolute(procparams_fname)) { + return embedded_fname; + } + Glib::ustring prefix = ""; + if (embedded_fname.length() > 5 && embedded_fname.substr(0, 5) == "file:") { + embedded_fname = embedded_fname.substr(5); + prefix = "file:"; + } + if (!Glib::path_is_absolute(embedded_fname)) { + return prefix + embedded_fname; + } + Glib::ustring dir1 = Glib::path_get_dirname(procparams_fname) + G_DIR_SEPARATOR_S; + Glib::ustring dir2 = Glib::path_get_dirname(embedded_fname) + G_DIR_SEPARATOR_S; + size_t find = dir2.find(dir1); + if (dir2.substr(0, dir1.length()) != dir1) { + // it's in a different directory, ie not inside + return prefix + embedded_fname; + } + return prefix + embedded_fname.substr(dir1.length()); +} + +int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsolute, ParamsEdited* pedited) const { if (!fname.length() && !fname2.length()) return 0; @@ -775,7 +814,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p if (!pedited || pedited->distortion.amount) keyFile.set_double ("Distortion", "Amount", distortion.amount); // lens profile - if (!pedited || pedited->lensProf.lcpFile) keyFile.set_string ("LensProfile", "LCPFile", lensProf.lcpFile); + if (!pedited || pedited->lensProf.lcpFile) keyFile.set_string ("LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile)); if (!pedited || pedited->lensProf.useDist) keyFile.set_boolean ("LensProfile", "UseDistortion", lensProf.useDist); if (!pedited || pedited->lensProf.useVign) keyFile.set_boolean ("LensProfile", "UseVignette", lensProf.useVign); if (!pedited || pedited->lensProf.useCA) keyFile.set_boolean ("LensProfile", "UseCA", lensProf.useCA); @@ -808,7 +847,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p if (!pedited || pedited->resize.height) keyFile.set_integer ("Resize", "Height", resize.height); // save color management settings - if (!pedited || pedited->icm.input) keyFile.set_string ("Color Management", "InputProfile", icm.input); + if (!pedited || pedited->icm.input) keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input)); if (!pedited || pedited->icm.toneCurve) keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve); if (!pedited || pedited->icm.blendCMSMatrix) keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); if (!pedited || pedited->icm.preferredProfile) keyFile.set_boolean ("Color Management", "PreferredProfile", icm.preferredProfile); @@ -859,9 +898,9 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p } // save raw parameters - if (!pedited || pedited->raw.darkFrame) keyFile.set_string ("RAW", "DarkFrame", raw.dark_frame ); + if (!pedited || pedited->raw.darkFrame) keyFile.set_string ("RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame) ); if (!pedited || pedited->raw.dfAuto) keyFile.set_boolean ("RAW", "DarkFrameAuto", raw.df_autoselect ); - if (!pedited || pedited->raw.ff_file) keyFile.set_string ("RAW", "FlatFieldFile", raw.ff_file ); + if (!pedited || pedited->raw.ff_file) keyFile.set_string ("RAW", "FlatFieldFile", relativePathIfInside(fname, fnameAbsolute, raw.ff_file) ); if (!pedited || pedited->raw.ff_AutoSelect) keyFile.set_boolean ("RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect ); if (!pedited || pedited->raw.ff_BlurRadius) keyFile.set_integer ("RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius ); if (!pedited || pedited->raw.ff_BlurType) keyFile.set_string ("RAW", "FlatFieldBlurType", raw.ff_BlurType ); @@ -908,6 +947,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p int error1, error2; error1 = write (fname , sPParams); if (fname2.length()) { + error2 = write (fname2, sPParams); // If at least one file has been saved, it's a success return error1 & error2; @@ -1316,7 +1356,7 @@ if (keyFile.has_group ("Distortion")) { // lens profile if (keyFile.has_group ("LensProfile")) { - if (keyFile.has_key ("LensProfile", "LCPFile")) { lensProf.lcpFile = keyFile.get_string ("LensProfile", "LCPFile"); if (pedited) pedited->lensProf.lcpFile = true; } + if (keyFile.has_key ("LensProfile", "LCPFile")) { lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string ("LensProfile", "LCPFile")); if (pedited) pedited->lensProf.lcpFile = true; } if (keyFile.has_key ("LensProfile", "UseDistortion")) { lensProf.useDist = keyFile.get_boolean ("LensProfile", "UseDistortion"); if (pedited) pedited->lensProf.useDist = true; } if (keyFile.has_key ("LensProfile", "UseVignette")) { lensProf.useVign = keyFile.get_boolean ("LensProfile", "UseVignette"); if (pedited) pedited->lensProf.useVign = true; } if (keyFile.has_key ("LensProfile", "UseCA")) { lensProf.useCA = keyFile.get_boolean ("LensProfile", "UseCA"); if (pedited) pedited->lensProf.useCA = true; } @@ -1361,7 +1401,7 @@ if (keyFile.has_group ("Resize")) { // load color management settings if (keyFile.has_group ("Color Management")) { - if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = keyFile.get_string ("Color Management", "InputProfile"); if (pedited) pedited->icm.input = true; } + if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = expandRelativePath(fname, "file:", keyFile.get_string ("Color Management", "InputProfile")); if (pedited) pedited->icm.input = true; } if (keyFile.has_key ("Color Management", "ToneCurve")) { icm.toneCurve = keyFile.get_boolean ("Color Management", "ToneCurve"); if (pedited) pedited->icm.toneCurve = true; } if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) { icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (pedited) pedited->icm.blendCMSMatrix = true; } if (keyFile.has_key ("Color Management", "PreferredProfile")) { icm.preferredProfile = keyFile.get_boolean ("Color Management", "PreferredProfile"); if (pedited) pedited->icm.preferredProfile = true; } @@ -1403,9 +1443,9 @@ if (keyFile.has_group ("RGB Curves")) { // load raw settings if (keyFile.has_group ("RAW")) { - if (keyFile.has_key ("RAW", "DarkFrame")) { raw.dark_frame = keyFile.get_string ("RAW", "DarkFrame" ); if (pedited) pedited->raw.darkFrame = true; } + if (keyFile.has_key ("RAW", "DarkFrame")) { raw.dark_frame = expandRelativePath(fname, "", keyFile.get_string ("RAW", "DarkFrame" )); if (pedited) pedited->raw.darkFrame = true; } if (keyFile.has_key ("RAW", "DarkFrameAuto")) { raw.df_autoselect = keyFile.get_boolean ("RAW", "DarkFrameAuto" ); if (pedited) pedited->raw.dfAuto = true; } - if (keyFile.has_key ("RAW", "FlatFieldFile")) { raw.ff_file = keyFile.get_string ("RAW", "FlatFieldFile" ); if (pedited) pedited->raw.ff_file = true; } + if (keyFile.has_key ("RAW", "FlatFieldFile")) { raw.ff_file = expandRelativePath(fname, "", keyFile.get_string ("RAW", "FlatFieldFile" )); if (pedited) pedited->raw.ff_file = true; } if (keyFile.has_key ("RAW", "FlatFieldAutoSelect")) { raw.ff_AutoSelect = keyFile.get_boolean ("RAW", "FlatFieldAutoSelect" ); if (pedited) pedited->raw.ff_AutoSelect = true; } if (keyFile.has_key ("RAW", "FlatFieldBlurRadius")) { raw.ff_BlurRadius = keyFile.get_integer ("RAW", "FlatFieldBlurRadius" ); if (pedited) pedited->raw.ff_BlurRadius = true; } if (keyFile.has_key ("RAW", "FlatFieldBlurType")) { raw.ff_BlurType = keyFile.get_string ("RAW", "FlatFieldBlurType" ); if (pedited) pedited->raw.ff_BlurType = true; } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 742d2cae2..ea240b58d 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -802,10 +802,12 @@ class ProcParams { * save the same file in two different location, i.e. the cache and the image's directory * @param fname the name of the first file (can be an empty string) * @param fname2 the name of the second file (can be an empty string) (optional) + * @param fnameAbsolute set to false if embedded filenames (if any, darkframe/flatfield) should be stored as relative + * filenames if they are inside the same directory or in a sub-directory to fname's directory. * @param pedited pointer to a ParamsEdited object (optional) to store which values has to be saved * @return Error code (=0 if all supplied filenames where created correctly) */ - int save (Glib::ustring fname, Glib::ustring fname2 = "", ParamsEdited* pedited=NULL) const; + int save (Glib::ustring fname, Glib::ustring fname2 = "", bool fnameAbsolute = true, ParamsEdited* pedited=NULL) const; /** * Loads the parameters from a file. * @param fname the name of the file diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 9a487de16..89d6e3e70 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -61,6 +61,7 @@ FilePanel::FilePanel () : parent(NULL) { dirBrowser->addDirSelectionListener (fileCatalog); dirBrowser->addDirSelectionListener (recentBrowser); dirBrowser->addDirSelectionListener (placesBrowser); + dirBrowser->addDirSelectionListener (tpc); fileCatalog->setFileSelectionListener (this); fileCatalog->setDirBrowserRemoteInterface (dirBrowser); diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 65b10df17..df7c150de 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -67,6 +67,7 @@ FlatField::FlatField () : Gtk::VBox(), FoldableToolPanel(this) flatFieldFileReset->signal_clicked().connect( sigc::mem_fun(*this, &FlatField::flatFieldFile_Reset), true ); flatFieldAutoSelectconn = flatFieldAutoSelect->signal_toggled().connect ( sigc::mem_fun(*this, &FlatField::flatFieldAutoSelectChanged), true); flatFieldBlurTypeconn = flatFieldBlurType->signal_changed().connect( sigc::mem_fun(*this, &FlatField::flatFieldBlurTypeChanged) ); + lastShortcutPath = ""; } void FlatField::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) @@ -228,3 +229,22 @@ void FlatField::flatFieldAutoSelectChanged() listener->panelChanged (EvFlatFieldAutoSelect, flatFieldAutoSelect->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); } + +void FlatField::setShortcutPath(Glib::ustring path) +{ + if (path == "") return; +#ifdef WIN32 + // Dirty workaround, waiting for a clean solution by using exceptions! + if (!safe_is_shortcut_dir(path)) +#endif + { + if (lastShortcutPath != "") { + flatFieldFile->remove_shortcut_folder(lastShortcutPath); + } + lastShortcutPath = path; + try { + flatFieldFile->add_shortcut_folder(path); + } + catch (Gtk::FileChooserError &err) {} + } +} diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index 724870ee0..fb83bcc80 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -49,6 +49,7 @@ protected: bool lastFFAutoSelect; FFProvider *ffp; sigc::connection flatFieldFileconn, flatFieldAutoSelectconn, flatFieldBlurTypeconn; + Glib::ustring lastShortcutPath; public: @@ -64,6 +65,7 @@ public: void flatFieldFile_Reset (); void flatFieldAutoSelectChanged (); void flatFieldBlurTypeChanged (); + void setShortcutPath(Glib::ustring path); void setFFProvider (FFProvider* p) { ffp = p; }; }; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 5d6e0bd6e..e98b3d9ea 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -751,8 +751,9 @@ void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) { if (updatePParams && pparamsValid) { pparams.save ( + options.saveParamsFile ? fname + paramFileExtension : "", options.saveParamsCache ? getCacheFileName ("profiles")+paramFileExtension : "", - options.saveParamsFile ? fname + paramFileExtension : "" + options.saveParamsCache ); } if (updateCacheImageData) diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 4673d5c31..3c163b994 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -362,6 +362,7 @@ void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool ipc->setSizeListener (crop); ipc->setSizeListener (resize); } + flatfield->setShortcutPath(Glib::path_get_dirname(ipc->getInitialImage()->getFileName())); icm->setRawMeta (raw, (const rtengine::ImageData*)pMetaData); lensProf->setRawMeta (raw, pMetaData); @@ -630,3 +631,8 @@ void ToolPanelCoordinator::toolSelected (ToolMode tool) { break; } } + +void ToolPanelCoordinator::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + flatfield->setShortcutPath(dirname); +} diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index cef0c6574..15a917316 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -54,6 +54,7 @@ #include "toolbar.h" #include "lensgeom.h" #include "lensgeomlistener.h" +#include "dirselectionlistener.h" #include "dirpyrequalizer.h" #include "hsvequalizer.h" #include "rawprocess.h" @@ -78,6 +79,7 @@ class ToolPanelCoordinator : public ToolPanelListener, public SpotWBListener, public CropPanelListener, public ICMPanelListener, + public DirSelectionListener, public ImageAreaToolListener { protected: @@ -192,6 +194,9 @@ class ToolPanelCoordinator : public ToolPanelListener, void profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited=NULL); void setDefaults (rtengine::procparams::ProcParams* defparams); + // DirSelectionListener interface + void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile=""); + // to support the GUI: CropGUIListener* getCropGUIListener (); // through the CropGUIListener the editor area can notify the "crop" ToolPanel when the crop selection changes