diff --git a/rtdata/images/Dark/actions/intent-absolute.png b/rtdata/images/Dark/actions/intent-absolute.png new file mode 100644 index 000000000..6d274a2c0 Binary files /dev/null and b/rtdata/images/Dark/actions/intent-absolute.png differ diff --git a/rtdata/images/Dark/actions/intent-perceptual.png b/rtdata/images/Dark/actions/intent-perceptual.png new file mode 100644 index 000000000..821a714ae Binary files /dev/null and b/rtdata/images/Dark/actions/intent-perceptual.png differ diff --git a/rtdata/images/Dark/actions/intent-relative.png b/rtdata/images/Dark/actions/intent-relative.png new file mode 100644 index 000000000..d586b47b2 Binary files /dev/null and b/rtdata/images/Dark/actions/intent-relative.png differ diff --git a/rtdata/images/Dark/actions/intent-saturation.png b/rtdata/images/Dark/actions/intent-saturation.png new file mode 100644 index 000000000..0654f78b6 Binary files /dev/null and b/rtdata/images/Dark/actions/intent-saturation.png differ diff --git a/rtdata/images/Dark/actions/softProof.png b/rtdata/images/Dark/actions/softProof.png new file mode 100644 index 000000000..5f17df3ea Binary files /dev/null and b/rtdata/images/Dark/actions/softProof.png differ diff --git a/rtdata/images/Light/actions/intent-absolute.png b/rtdata/images/Light/actions/intent-absolute.png new file mode 100644 index 000000000..fb5919181 Binary files /dev/null and b/rtdata/images/Light/actions/intent-absolute.png differ diff --git a/rtdata/images/Light/actions/intent-perceptual.png b/rtdata/images/Light/actions/intent-perceptual.png new file mode 100644 index 000000000..88de7b5e9 Binary files /dev/null and b/rtdata/images/Light/actions/intent-perceptual.png differ diff --git a/rtdata/images/Light/actions/intent-relative.png b/rtdata/images/Light/actions/intent-relative.png new file mode 100644 index 000000000..f952f4ab7 Binary files /dev/null and b/rtdata/images/Light/actions/intent-relative.png differ diff --git a/rtdata/images/Light/actions/intent-saturation.png b/rtdata/images/Light/actions/intent-saturation.png new file mode 100644 index 000000000..92908b030 Binary files /dev/null and b/rtdata/images/Light/actions/intent-saturation.png differ diff --git a/rtdata/images/Light/actions/softProof.png b/rtdata/images/Light/actions/softProof.png new file mode 100644 index 000000000..3e5eb2f18 Binary files /dev/null and b/rtdata/images/Light/actions/softProof.png differ diff --git a/rtdata/languages/default b/rtdata/languages/default index 2df0b7fb9..9762a38a6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -657,6 +657,7 @@ HISTORY_MSG_423;Retinex - Gamma slope HISTORY_MSG_424;Retinex - HL threshold HISTORY_MSG_425;Retinex - Log base HISTORY_MSG_426;Retinex - Hue equalizer +HISTORY_MSG_427;Output rendering intent HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -774,6 +775,8 @@ MAIN_TOOLTIP_SHOWHIDERP1;Show/Hide the right panel.\nShortcut: Alt-l MAIN_TOOLTIP_SHOWHIDETP1;Show/Hide the top panel.\nShortcut: Shift-l MAIN_TOOLTIP_THRESHOLD;Threshold MAIN_TOOLTIP_TOGGLE;Toggle the Before/After view.\nShortcut: Shift-b +MONITOR_SOFTPROOF;Soft-proof +MONITOR_PROFILE_SYSTEM;System default NAVIGATOR_B;B: NAVIGATOR_G;G: NAVIGATOR_H;H: @@ -887,7 +890,7 @@ PREFERENCES_CLIPPINGIND;Clipping Indication PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs PREFERENCES_CLUTSDIR;HaldCLUT directory -PREFERENCES_CMETRICINTENT;Colorimetric intent +PREFERENCES_MONINTENT;Default monitor intent PREFERENCES_CURVEBBOXPOS;Position of curve copypasta buttons PREFERENCES_CURVEBBOXPOS_ABOVE;Above PREFERENCES_CURVEBBOXPOS_BELOW;Below @@ -982,7 +985,7 @@ PREFERENCES_MENUGROUPRANK;Group "Rank" PREFERENCES_MENUOPTIONS;Context Menu Options PREFERENCES_METADATA;Metadata PREFERENCES_MIN;Mini (100x115) -PREFERENCES_MONITORICC;Monitor color profile +PREFERENCES_MONPROFILE;Default monitor profile PREFERENCES_MULTITAB;Multiple Editor Tabs Mode PREFERENCES_MULTITABDUALMON;Multiple Editor Tabs In Own Window Mode PREFERENCES_NAVGUIDEBRUSH;Navigator guide color @@ -1013,6 +1016,7 @@ PREFERENCES_PROFILEPRCACHE;Profile in cache PREFERENCES_PROFILEPRFILE;Profile next to the input file PREFERENCES_PROFILESAVECACHE;Save processing profile to the cache PREFERENCES_PROFILESAVEINPUT;Save processing profile next to the input file +PREFERENCES_PROFILE_NONE;None PREFERENCES_PROPERTY;Property PREFERENCES_PSPATH;Adobe Photoshop installation directory PREFERENCES_REMEMBERZOOMPAN;Remember zoom % and pan offset @@ -1514,6 +1518,7 @@ TP_ICM_INPUTPROFILE;Input Profile TP_ICM_LABEL;Color Management TP_ICM_NOICM;No ICM: sRGB Output TP_ICM_OUTPUTPROFILE;Output Profile +TP_ICM_PROFILEINTENT;Rendering Intent TP_ICM_SAVEREFERENCE;Save Reference Image for Profiling TP_ICM_SAVEREFERENCE_APPLYWB;Apply white balance TP_ICM_SAVEREFERENCE_APPLYWB_TOOLTIP;Generally, apply the white balance when saving images to create ICC profiles, and do not apply the white balance to create DCP profiles. diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index a97ae7f39..2220f68c5 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -989,40 +989,6 @@ void Crop::update (int todo) // switch back to rgb parent->ipf.lab2monitorRgb (labnCrop, cropImg); - //parent->ipf.lab2monitorRgb (laboCrop, cropImg); - - //cropImg = baseCrop->to8(); - /* - // int xref,yref; - xref=000;yref=000; - if (colortest && cropw>115 && croph>115) - for(int j=1;j<5;j++){ - xref+=j*30;yref+=j*30; - int rlin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))]/255.0) * 255.0); - int glin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1]/255.0) * 255.0); - int blin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2]/255.0) * 255.0); - - printf("after lab2rgb RGB lab2 Xr%i Yr%i Skip=%d R=%d G=%d B=%d \n",xref,yref,skip, - rlin,glin,blin); - //cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))], - //cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1)], - //cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2)]); - //printf("after lab2rgb Lab lab2 Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327); - printf("after lab2rgb Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, - labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327, - labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327, - labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327)q; - } - */ - /* - if (colortest && cropImg->height>115 && cropImg->width>115) {//for testing - xref=000;yref=000; - printf("dcrop final R= %d G= %d B= %d \n", - cropImg->data[3*xref/(skip)*(cropImg->width+1)], - cropImg->data[3*xref/(skip)*(cropImg->width+1)+1], - cropImg->data[3*xref/(skip)*(cropImg->width+1)+2]); - } - */ if (cropImageListener) { // this in output space held in parallel to allow analysis like shadow/highlight Glib::ustring outProfile = params.icm.output; @@ -1030,13 +996,13 @@ void Crop::update (int todo) Image8 *cropImgtrue; if(settings->HistogramWorking) { - cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, workProfile, false); + cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, workProfile, RI_RELATIVE, false); // HOMBRE: was RELATIVE by default in lab2rgb, is it safe to assume we have to use it again ? } else { if (params.icm.output == "" || params.icm.output == ColorManagementParams::NoICMString) { outProfile = "sRGB"; } - cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, outProfile, false); + cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, outProfile, params.icm.outputIntent, false); } int finalW = rqcropw; diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index bad4e8dfa..b77da03dd 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -29,9 +29,90 @@ #include -namespace rtengine +namespace { +void loadProfiles (const Glib::ustring& dirName, + std::map* profiles, + std::map* profileContents, + std::map* profileNames, + bool nameUpper, bool onlyRgb) +{ + if (dirName.empty ()) + return; + + try { + + Glib::Dir dir (dirName); + + for (Glib::DirIterator entry = dir.begin (); entry != dir.end (); ++entry) { + + const Glib::ustring fileName = *entry; + + if (fileName.size () < 4) + continue; + + const Glib::ustring extension = fileName.substr (fileName.size () - 4).casefold (); + + if (extension.compare(".icc") == 0 && extension.compare(".icm") == 0) + continue; + + const Glib::ustring filePath = Glib::build_filename (dirName, fileName); + + if (!safe_file_test (filePath, Glib::FILE_TEST_IS_REGULAR)) + continue; + + Glib::ustring name = fileName.substr (0, fileName.size() - 4); + + if (nameUpper) + name = name.uppercase (); + + if (profiles) { + const rtengine::ProfileContent content (filePath); + const cmsHPROFILE profile = content.toProfile (); + + if (profile && (!onlyRgb || cmsGetColorSpace (profile) == cmsSigRgbData)) { + profiles->insert (std::make_pair (name, profile)); + + if (profileContents) + profileContents->insert (std::make_pair (name, content)); + } + } + + if (profileNames) + profileNames->insert (std::make_pair (name, filePath)); + } + } + catch (Glib::Exception&) {} +} + +inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, std::uint8_t& result) +{ + if (cmsIsIntentSupported (profile, intent, direction)) + result |= 1 << intent; +} + +inline std::uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) +{ + if (!profile) + return 0; + + std::uint8_t result = 0; + + getSupportedIntent (profile, INTENT_PERCEPTUAL, direction, result); + getSupportedIntent (profile, INTENT_RELATIVE_COLORIMETRIC, direction, result); + getSupportedIntent (profile, INTENT_SATURATION, direction, result); + getSupportedIntent (profile, INTENT_ABSOLUTE_COLORIMETRIC, direction, result); + + return result; +} + +inline cmsHPROFILE createXYZProfile () +{ + double mat[3][3] = { {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0} }; + return rtengine::ICCStore::createFromMatrix (mat, false, "XYZ"); +} + const double (*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best}; const double (*iwprofiles[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz}; const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB"}; @@ -43,8 +124,12 @@ const char* wpgamma[] = {"default", "BT709_g2.2_s4.5", "sRGB_g2.4_s12.92", "line // high g=1.3 s=3.35 for high dynamic images //low g=2.6 s=6.9 for low contrast images +} -std::vector getGamma () //return gamma +namespace rtengine +{ + +std::vector getGamma () { std::vector res; @@ -56,7 +141,6 @@ std::vector getGamma () //return gamma return res; } - std::vector getWorkingProfiles () { @@ -69,32 +153,38 @@ std::vector getWorkingProfiles () return res; } -std::vector ICCStore::getOutputProfiles () +std::vector ICCStore::getProfiles () const { MyMutex::MyLock lock(mutex_); std::vector res; - for (std::map::iterator i = fileProfiles.begin(); i != fileProfiles.end(); i++) { - Glib::ustring name(i->first); - std::string::size_type i2 = name.find_last_of('/'); - - if( i2 == std::string::npos ) { - i2 = name.find_last_of('\\'); - } - - if( i2 == std::string::npos ) { - res.push_back ( name ); // list only profiles inside selected profiles directory - } - } + for (ProfileMap::const_iterator profile = fileProfiles.begin (); profile != fileProfiles.end (); ++profile) + res.push_back (profile->first); return res; } +std::vector ICCStore::getProfilesFromDir (const Glib::ustring& dirName) const +{ -cmsHPROFILE -ICCStore::makeStdGammaProfile(cmsHPROFILE iprof) + MyMutex::MyLock lock(mutex_); + + std::vector res; + + ProfileMap profiles; + + loadProfiles (profilesDir, &profiles, NULL, NULL, false, true); + loadProfiles (dirName, &profiles, NULL, NULL, false, true); + + for (ProfileMap::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + res.push_back (profile->first); + + return res; +} + +cmsHPROFILE ICCStore::makeStdGammaProfile (cmsHPROFILE iprof) { // forgive me for the messy code, quick hack to change gamma of an ICC profile to the RT standard gamma if (!iprof) { @@ -189,14 +279,15 @@ ICCStore::makeStdGammaProfile(cmsHPROFILE iprof) return oprof; } -ICCStore* -ICCStore::getInstance(void) +ICCStore* ICCStore::getInstance () { static ICCStore instance_; return &instance_; } -ICCStore::ICCStore () +ICCStore::ICCStore () : + xyz (createXYZProfile ()), + srgb (cmsCreate_sRGBProfile ()) { //cmsErrorAction (LCMS_ERROR_SHOW); @@ -208,234 +299,172 @@ ICCStore::ICCStore () wMatrices[wpnames[i]] = wprofiles[i]; iwMatrices[wpnames[i]] = iwprofiles[i]; } - - double mat[3][3] = { {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}}; - xyz = createFromMatrix (mat, false, "XYZ"); - srgb = cmsCreate_sRGBProfile (); } -int ICCStore::numOfWProfiles () +TMatrix ICCStore::workingSpaceMatrix (const Glib::ustring& name) const { - return sizeof(wpnames) / sizeof(wpnames[0]); -} - -TMatrix ICCStore::workingSpaceMatrix (Glib::ustring name) -{ - - std::map::iterator r = wMatrices.find (name); + const MatrixMap::const_iterator r = wMatrices.find (name); if (r != wMatrices.end()) { return r->second; } else { - return wMatrices["sRGB"]; + return wMatrices.find ("sRGB")->second; } } -TMatrix ICCStore::workingSpaceInverseMatrix (Glib::ustring name) +TMatrix ICCStore::workingSpaceInverseMatrix (const Glib::ustring& name) const { - std::map::iterator r = iwMatrices.find (name); + const MatrixMap::const_iterator r = iwMatrices.find (name); if (r != iwMatrices.end()) { return r->second; } else { - return iwMatrices["sRGB"]; + return iwMatrices.find ("sRGB")->second; } } -cmsHPROFILE ICCStore::workingSpace (Glib::ustring name) +cmsHPROFILE ICCStore::workingSpace (const Glib::ustring& name) const { - std::map::iterator r = wProfiles.find (name); + const ProfileMap::const_iterator r = wProfiles.find (name); if (r != wProfiles.end()) { return r->second; } else { - return wProfiles["sRGB"]; + return wProfiles.find ("sRGB")->second; } } -cmsHPROFILE ICCStore::workingSpaceGamma (Glib::ustring name) +cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const { - std::map::iterator r = wProfilesGamma.find (name); + const ProfileMap::const_iterator r = wProfilesGamma.find (name); if (r != wProfilesGamma.end()) { return r->second; } else { - return wProfilesGamma["sRGB"]; + return wProfilesGamma.find ("sRGB")->second; } } -cmsHPROFILE ICCStore::getProfile (Glib::ustring name) +cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const { MyMutex::MyLock lock(mutex_); - std::map::iterator r = fileProfiles.find (name); + const ProfileMap::const_iterator r = fileProfiles.find (name); - if (r != fileProfiles.end()) { + if (r != fileProfiles.end ()) return r->second; - } else { - if (!name.compare (0, 5, "file:") && safe_file_test (name.substr(5), Glib::FILE_TEST_EXISTS) && !safe_file_test (name.substr(5), Glib::FILE_TEST_IS_DIR)) { - ProfileContent pc (name.substr(5)); - if (pc.data) { - cmsHPROFILE profile = pc.toProfile (); + if (name.compare (0, 5, "file:") == 0) { + const ProfileContent content (name.substr (5)); + const cmsHPROFILE profile = content.toProfile (); - if (profile) { - fileProfiles[name] = profile; - fileProfileContents[name] = pc; - return profile; - } - } + if (profile) { + const_cast(fileProfiles).insert(std::make_pair(name, profile)); + const_cast(fileProfileContents).insert(std::make_pair(name, content)); + + return profile; } } return NULL; } -cmsHPROFILE ICCStore::getStdProfile (Glib::ustring name) +cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) const { + const Glib::ustring nameUpper = name.uppercase (); + MyMutex::MyLock lock(mutex_); - std::map::iterator r = fileStdProfiles.find (name.uppercase()); + const ProfileMap::const_iterator r = fileStdProfiles.find (nameUpper); - if (r == fileStdProfiles.end()) { - // profile is not yet in store - std::map::iterator f = fileStdProfilesFileNames.find (name.uppercase()); - - if(f != fileStdProfilesFileNames.end()) { - // but there exists one => load it - ProfileContent pc (f->second); - - if (pc.data) { - cmsHPROFILE profile = pc.toProfile (); - - if (profile) { - fileStdProfiles[name.uppercase()] = profile; - } - - // profile is not valid or it is now stored => remove entry from fileStdProfilesFileNames - fileStdProfilesFileNames.erase(f); - return profile; - } else { - // profile not valid => remove entry from fileStdProfilesFileNames - fileStdProfilesFileNames.erase(f); - return NULL; - } - } else { - // profile does not exist - return NULL; - } - } else { - // return profile from store + // return profile from store + if (r != fileStdProfiles.end ()) return r->second; - } + + // profile is not yet in store + const NameMap::const_iterator f = fileStdProfilesFileNames.find (nameUpper); + + // profile does not exist + if (f == fileStdProfilesFileNames.end ()) + return NULL; + + // but there exists one => load it + const ProfileContent content (f->second); + const cmsHPROFILE profile = content.toProfile (); + + if (profile) + const_cast(fileStdProfiles).insert (std::make_pair (f->first, profile)); + + // profile is not valid or it is now stored => remove entry from fileStdProfilesFileNames + const_cast(fileStdProfilesFileNames).erase (f); + return profile; } -ProfileContent ICCStore::getContent (Glib::ustring name) +ProfileContent ICCStore::getContent (const Glib::ustring& name) const { MyMutex::MyLock lock(mutex_); - return fileProfileContents[name]; + const ContentMap::const_iterator r = fileProfileContents.find (name); + + return r != fileProfileContents.end () ? r->second : ProfileContent(); +} + +std::uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const +{ + + MyMutex::MyLock lock (mutex_); + + return getSupportedIntents (profile, LCMS_USED_AS_INPUT); +} + +std::uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const +{ + + MyMutex::MyLock lock (mutex_); + + return getSupportedIntents (profile, LCMS_USED_AS_OUTPUT); +} + +std::uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const +{ + + MyMutex::MyLock lock (mutex_); + + return getSupportedIntents (profile, LCMS_USED_AS_PROOF); } // Reads all profiles from the given profiles dir -void ICCStore::init (Glib::ustring usrICCDir, Glib::ustring rtICCDir) +void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir) { MyMutex::MyLock lock(mutex_); - // + // RawTherapee's profiles take precedence if a user's profile of the same name exists + profilesDir = Glib::build_filename (rtICCDir, "output"); fileProfiles.clear(); fileProfileContents.clear(); - // RawTherapee's profiles take precedence if a user's profile of the same name exists - loadICCs(Glib::build_filename(rtICCDir, "output"), false, fileProfiles, &fileProfileContents, true, true); - loadICCs(usrICCDir, false, fileProfiles, &fileProfileContents, true, true); + loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, NULL, false, true); + loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, NULL, false, true); // Input profiles // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) + stdProfilesDir = Glib::build_filename (rtICCDir, "input"); fileStdProfiles.clear(); fileStdProfilesFileNames.clear(); - loadICCs(Glib::build_filename(rtICCDir, "input"), true, fileStdProfiles, NULL); -} - -void ICCStore::loadICCs(Glib::ustring rootDirName, bool nameUpper, std::map& resultProfiles, std::map *resultProfileContents, bool prefetch, bool onlyRgb) -{ - if (rootDirName != "") { - std::deque qDirs; - - qDirs.push_front(rootDirName); - - while (!qDirs.empty()) { - // process directory - Glib::ustring dirname = qDirs.back(); - qDirs.pop_back(); - - Glib::Dir* dir = NULL; - - try { - if (!safe_file_test (dirname, Glib::FILE_TEST_IS_DIR)) { - return; - } - - dir = new Glib::Dir (dirname); - } catch (Glib::Exception& fe) { - return; - } - - dirname = dirname + "/"; - - for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) { - Glib::ustring fname = dirname + *i; - Glib::ustring sname = *i; - - // ignore directories - if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR)) { - size_t lastdot = sname.find_last_of ('.'); - - if (lastdot != Glib::ustring::npos && lastdot <= sname.size() - 4 && (!sname.casefold().compare (lastdot, 4, ".icm") || !sname.casefold().compare (lastdot, 4, ".icc"))) { - Glib::ustring name = nameUpper ? sname.substr(0, lastdot).uppercase() : sname.substr(0, lastdot); - - if(!prefetch) { - fileStdProfilesFileNames[name] = fname; - } else { - ProfileContent pc (fname); - - if (pc.data) { - cmsHPROFILE profile = pc.toProfile (); - - if (profile && (!onlyRgb || cmsGetColorSpace(profile) == cmsSigRgbData)) { - resultProfiles[name] = profile; - - if(resultProfileContents) { - (*resultProfileContents)[name] = pc; - } - } - } - } - } - } - - // Removed recursive scanning, see issue #1730. - // To revert to the recursive method, just uncomment the next line. - - //else qDirs.push_front(fname); // for later scanning - } - - delete dir; - } - } + loadProfiles (stdProfilesDir, NULL, NULL, &fileStdProfilesFileNames, true, false); } // Determine the first monitor default profile of operating system, if selected -void ICCStore::findDefaultMonitorProfile() +void ICCStore::findDefaultMonitorProfile () { - defaultMonitorProfile = ""; + defaultMonitorProfile.clear (); #ifdef WIN32 // Get current main monitor. Could be fine tuned to get the current windows monitor (multi monitor setup), @@ -449,6 +478,11 @@ void ICCStore::findDefaultMonitorProfile() if (GetICMProfileA(hDC, &profileLength, profileName)) { defaultMonitorProfile = Glib::ustring(profileName); + defaultMonitorProfile = Glib::path_get_basename(defaultMonitorProfile); + size_t pos = defaultMonitorProfile.rfind("."); + if (pos != Glib::ustring::npos) { + defaultMonitorProfile = defaultMonitorProfile.substr(0, pos); + } } // might fail if e.g. the monitor has no profile @@ -466,7 +500,7 @@ void ICCStore::findDefaultMonitorProfile() } } -ProfileContent::ProfileContent (Glib::ustring fileName) : data(NULL), length(0) +ProfileContent::ProfileContent (const Glib::ustring& fileName) : data(NULL), length(0) { FILE* f = safe_g_fopen (fileName, "rb"); @@ -518,9 +552,7 @@ ProfileContent& ProfileContent::operator= (const ProfileContent& other) length = other.length; - if (data) { - delete [] data; - } + delete [] data; if (other.data) { data = new char[length + 1]; @@ -532,15 +564,7 @@ ProfileContent& ProfileContent::operator= (const ProfileContent& other) return *this; } -ProfileContent::~ProfileContent () -{ - - if (data) { - delete [] data; - } -} - -cmsHPROFILE ProfileContent::toProfile () +cmsHPROFILE ProfileContent::toProfile () const { if (data) { @@ -550,7 +574,7 @@ cmsHPROFILE ProfileContent::toProfile () } } -cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, Glib::ustring name) +cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, const Glib::ustring& name) { static const unsigned phead[] = { @@ -644,4 +668,5 @@ cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, G delete [] oprof; return p; } + } diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index acb31e4cf..8b6e6465c 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -37,74 +37,135 @@ public: char* data; int length; - ProfileContent (): data(NULL), length(0) {} - ProfileContent (Glib::ustring fileName); - ProfileContent (const ProfileContent& other); - ProfileContent (cmsHPROFILE hProfile); + ProfileContent (); ~ProfileContent (); + + ProfileContent (const ProfileContent& other); ProfileContent& operator= (const rtengine::ProfileContent& other); - cmsHPROFILE toProfile (); + + ProfileContent (const Glib::ustring& fileName); + ProfileContent (cmsHPROFILE hProfile); + cmsHPROFILE toProfile () const; }; class ICCStore { + typedef std::map ProfileMap; + typedef std::map MatrixMap; + typedef std::map ContentMap; + typedef std::map NameMap; - std::map wProfiles; - std::map wProfilesGamma; - std::map wMatrices; - std::map iwMatrices; + ProfileMap wProfiles; + ProfileMap wProfilesGamma; + MatrixMap wMatrices; + MatrixMap iwMatrices; // these contain profiles from user/system directory (supplied on init) - std::map fileProfiles; - std::map fileProfileContents; + Glib::ustring profilesDir; + ProfileMap fileProfiles; + ContentMap fileProfileContents; // these contain standard profiles from RT. keys are all in uppercase - std::map fileStdProfilesFileNames; - std::map fileStdProfiles; + Glib::ustring stdProfilesDir; + NameMap fileStdProfilesFileNames; + ProfileMap fileStdProfiles; - cmsHPROFILE xyz; - cmsHPROFILE srgb; + Glib::ustring defaultMonitorProfile; - MyMutex mutex_; + const cmsHPROFILE xyz; + const cmsHPROFILE srgb; + + mutable MyMutex mutex_; ICCStore (); - void loadICCs(Glib::ustring rootDirName, bool nameUpper, std::map& resultProfiles, std::map *resultProfileContents, bool prefetch = false, bool onlyRgb = false); public: - static ICCStore* getInstance(void); - static cmsHPROFILE makeStdGammaProfile(cmsHPROFILE iprof); + static ICCStore* getInstance (); - Glib::ustring defaultMonitorProfile; // Main monitors standard profile name, from OS - void findDefaultMonitorProfile(); + void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir); - int numOfWProfiles (); - cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, Glib::ustring name = ""); - cmsHPROFILE workingSpace (Glib::ustring name); - cmsHPROFILE workingSpaceGamma (Glib::ustring name); - TMatrix workingSpaceMatrix (Glib::ustring name); - TMatrix workingSpaceInverseMatrix (Glib::ustring name); + static cmsHPROFILE makeStdGammaProfile (cmsHPROFILE iprof); + static cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); - cmsHPROFILE getProfile (Glib::ustring name); - cmsHPROFILE getStdProfile(Glib::ustring name); + // Main monitors standard profile name, from OS + void findDefaultMonitorProfile (); + cmsHPROFILE getDefaultMonitorProfile () const; + Glib::ustring getDefaultMonitorProfileName () const; - void init (Glib::ustring usrICCDir, Glib::ustring stdICCDir); - ProfileContent getContent (Glib::ustring name); + cmsHPROFILE workingSpace (const Glib::ustring& name) const; + cmsHPROFILE workingSpaceGamma (const Glib::ustring& name) const; + TMatrix workingSpaceMatrix (const Glib::ustring& name) const; + TMatrix workingSpaceInverseMatrix (const Glib::ustring& name) const; - cmsHPROFILE getXYZProfile () - { - return xyz; - } - cmsHPROFILE getsRGBProfile () - { - return srgb; - } - std::vector getOutputProfiles (); + cmsHPROFILE getProfile (const Glib::ustring& name) const; + cmsHPROFILE getStdProfile (const Glib::ustring& name) const; + ProfileContent getContent (const Glib::ustring& name) const; + + cmsHPROFILE getXYZProfile () const; + cmsHPROFILE getsRGBProfile () const; + + std::vector getProfiles () const; + std::vector getProfilesFromDir (const Glib::ustring& dirName) const; + + std::uint8_t getInputIntents (cmsHPROFILE profile) const; + std::uint8_t getOutputIntents (cmsHPROFILE profile) const; + std::uint8_t getProofIntents (cmsHPROFILE profile) const; + + std::uint8_t getInputIntents (const Glib::ustring& name) const; + std::uint8_t getOutputIntents (const Glib::ustring& name) const; + std::uint8_t getProofIntents (const Glib::ustring& name) const; }; #define iccStore ICCStore::getInstance() -//extern const char* wpnames[]; +inline ProfileContent::ProfileContent () : + data(NULL), + length(0) +{ } + +inline ProfileContent::~ProfileContent () +{ + delete [] data; +} + +inline cmsHPROFILE ICCStore::getDefaultMonitorProfile () const +{ + return getProfile (defaultMonitorProfile); +} + +inline Glib::ustring ICCStore::getDefaultMonitorProfileName () const +{ + return defaultMonitorProfile; +} + +inline std::uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const +{ + return getInputIntents (getProfile (name)); +} + +inline std::uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const +{ + return getOutputIntents (getProfile (name)); +} + +inline std::uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const +{ + return getProofIntents (getProfile (name)); +} + +inline cmsHPROFILE ICCStore::getXYZProfile () const +{ + return xyz; +} + +inline cmsHPROFILE ICCStore::getsRGBProfile () const +{ + return srgb; +} + +} + #endif diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 8389ec34e..96a55989e 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -31,7 +31,7 @@ extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () : orig_prev(NULL), oprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL), - ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), scale(10), + ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), monitorIntent(RI_RELATIVE), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(0.), @@ -781,6 +781,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } } + // Update the monitor color transform if necessary + if (todo & M_MONITOR) { + ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent); + } + // process crop, if needed for (size_t i = 0; i < crops.size(); i++) if (crops[i]->hasListener () && cropCall != crops[i] ) { @@ -794,7 +799,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) progress ("Conversion to RGB...", 100 * readyphase / numofphases); - if (todo != CROP && todo != MINUPDATE) { + if ((todo != CROP && todo != MINUPDATE) || (todo & M_MONITOR)) { MyMutex::MyLock prevImgLock(previmg->getMutex()); try { @@ -804,13 +809,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if(settings->HistogramWorking) { Glib::ustring workProfile = params.icm.working; - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, workProfile, true); + workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, workProfile, RI_RELATIVE, true); // HOMBRE: was RELATIVE by default in lab2rgb, is it safe to assume we have to use it again ? } else { - if (params.icm.output == "" || params.icm.output == ColorManagementParams::NoICMString) { + if (params.icm.output.empty() || params.icm.output == ColorManagementParams::NoICMString) { outProfile = "sRGB"; } - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, outProfile, false); + workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, outProfile, params.icm.outputIntent, false); } } catch(char * str) { progress ("Error converting file...", 0); @@ -1126,6 +1131,17 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int & y = (fullh - h) / 2; } +void ImProcCoordinator::setMonitorProfile (const Glib::ustring& profile, RenderingIntent intent) +{ + monitorProfile = profile; + monitorIntent = intent; +} + +void ImProcCoordinator::getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const +{ + profile = monitorProfile; + intent = monitorIntent; +} void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname, bool apply_wb) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index ef981fe6a..4d442482e 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -72,6 +72,10 @@ protected: ImProcFunctions ipf; + Glib::ustring monitorProfile; + + RenderingIntent monitorIntent; + int scale; bool highDetailPreprocessComputed; bool highDetailRawComputed; @@ -249,6 +253,9 @@ public: void getSpotWB (int x, int y, int rectSize, double& temp, double& green); void getAutoCrop (double ratio, int &x, int &y, int &w, int &h); + void setMonitorProfile (const Glib::ustring& profile, RenderingIntent intent); + void getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const; + bool updateTryLock () { return updaterThreadStart.trylock(); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index f21748a3b..b1f47c3a9 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -140,58 +140,10 @@ void ImProcFunctions::firstAnalysisThread (Imagefloat* original, Glib::ustring w } } } -/* -void ImProcFunctions::CAT02 (Imagefloat* baseImg, const ProcParams* params) + +void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent) { - const double toxyz[3][3] = {{0.7976749, 0.1351917, 0.0313534}, - {0.2880402, 0.7118741, 0.0000857}, - {0.0000000, 0.0000000, 0.8252100}}; - - const double xyzto[3][3] = {{1.3459433, -0.2556075, -0.0511118}, - {-0.5445989, 1.5081673, 0.0205351}, - {0.0000000, 0.0000000, 1.2118128}}; - int fw = baseImg->width; - int fh = baseImg->height; - - double CAM02BB00,CAM02BB01,CAM02BB02,CAM02BB10,CAM02BB11,CAM02BB12,CAM02BB20,CAM02BB21,CAM02BB22; - double Xxx,Yyy,Zzz; - // Xxx=1.09844; - // Yyy=1.0; - // Zzz=0.355961; - //params.wb.temperature, params.wb.green, params.wb.method - double Xxyz, Zxyz; -// ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xxyz, Zxyz); - ColorTemp::temp2mulxyz (5000.0, 1.0, "Camera", Xxyz, Zxyz); - - ColorTemp::cieCAT02(Xxx, Yyy, Zzz, CAM02BB00,CAM02BB01,CAM02BB02,CAM02BB10,CAM02BB11,CAM02BB12,CAM02BB20,CAM02BB21,CAM02BB22); - printf("00=%f 01=%f 11=%f 20=%f 22=%f\n", CAM02BB00,CAM02BB01,CAM02BB11,CAM02BB20,CAM02BB22); - - - for (int i=0; ir(i,j); - float g = baseImg->g(i,j); - float b = baseImg->b(i,j); - - float x = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; - float y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; - float z = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; - float Xcam=CAM02BB00* x +CAM02BB01* y + CAM02BB02* z ; - float Ycam=CAM02BB10* x +CAM02BB11* y + CAM02BB12* z ; - float Zcam=CAM02BB20* x +CAM02BB21* y + CAM02BB22* z ; - baseImg->r(i,j) = xyzto[0][0] * Xcam + xyzto[0][1] * Ycam + xyzto[0][2] * Zcam; - baseImg->g(i,j) = xyzto[1][0] * Xcam + xyzto[1][1] * Ycam + xyzto[1][2] * Zcam; - baseImg->b(i,j) = xyzto[2][0] * Xcam + xyzto[2][1] * Ycam + xyzto[2][2] * Zcam; - } - } -} -*/ -void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* params, LUTu & histogram) -{ - // set up monitor transform - Glib::ustring wprofile = params->icm.working; - if (monitorTransform != NULL) { cmsDeleteTransform (monitorTransform); } @@ -209,43 +161,38 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par lab2outputTransform = NULL; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB - Glib::ustring monitorProfile = settings->monitorProfile; -#if defined(WIN32) - if (settings->autoMonitorProfile) { - monitorProfile = iccStore->defaultMonitorProfile; - } - -#endif - - cmsHPROFILE monitor = iccStore->getProfile ("file:" + monitorProfile); + cmsHPROFILE monitor = iccStore->getProfile (monitorProfile); if (monitor) { - lcmsMutex->lock (); + MyMutex::MyLock lcmsLock (*lcmsMutex); cmsHPROFILE iprof = cmsCreateLab4Profile(NULL); - monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, + monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is for thread safety, NOOPTIMIZE for precision Glib::ustring outputProfile; - if (params->icm.output != "" && params->icm.output != ColorManagementParams::NoICMString) { - outputProfile = params->icm.output; + if (!icm.output.empty() && icm.output != ColorManagementParams::NoICMString) { + outputProfile = icm.output; cmsHPROFILE jprof = iccStore->getProfile(outputProfile); if (jprof) { - lab2outputTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, jprof, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); - - if (monitor) { - output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); - } + lab2outputTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, jprof, TYPE_RGB_FLT, icm.outputIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); + output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); } } cmsCloseProfile(iprof); - lcmsMutex->unlock (); } #endif +} + +void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* params, LUTu & histogram) +{ + + Glib::ustring wprofile = params->icm.working; + // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments int T = 1; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index cfabbba64..ec81f26eb 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -233,6 +233,7 @@ public: bool needsPCVignetting (); void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16); + void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent); void rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf); @@ -379,9 +380,9 @@ public: void Badpixelscam(CieImage * src, CieImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad); void BadpixelsLab(LabImage * src, LabImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom); - Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool standard_gamma); - Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw);// for gamma output - Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool bw);//without gamma ==>default + Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma); + Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw);// for gamma output + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw);//without gamma ==>default // 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 = NULL); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index cc01b783f..c36e185d0 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -134,7 +134,7 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) } } -Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool standard_gamma) +Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma) { //gamutmap(lab); @@ -167,7 +167,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, lcmsMutex->lock (); cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); - cmsHTRANSFORM hTransform = cmsCreateTransform (hLab, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, + cmsHTRANSFORM hTransform = cmsCreateTransform (hLab, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety cmsCloseProfile(hLab); lcmsMutex->unlock (); @@ -259,7 +259,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, return image; } // for default (not gamma) -Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool bw) +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw) { //gamutmap(lab); @@ -322,7 +322,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE iprof = iccStore->getXYZProfile (); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); lcmsMutex->unlock (); image->ExecCMSTransform(hTransform); @@ -363,7 +363,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int // for gamma options (BT709...sRGB linear...) -Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw) +Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw) { //gamutmap(lab); @@ -593,7 +593,7 @@ Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE iprof = iccStore->getXYZProfile (); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); lcmsMutex->unlock (); image->ExecCMSTransform(hTransform); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 4dbbad07c..21ecf5a83 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -454,6 +454,8 @@ enum ProcEvent { EvLbaselog = 424, // EvLgrbl = 425, EvRetinexlhcurve = 425, + EvOIntent = 426, + EvMonitorTransform = 427, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index becd8932e..613334469 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -894,6 +894,7 @@ void ColorManagementParams::setDefaults() dcpIlluminant = 0; working = "ProPhoto"; output = "RT_sRGB"; + outputIntent = RI_RELATIVE; gamma = "default"; gampos = 2.22; slpos = 4.5; @@ -2548,6 +2549,27 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_string ("Color Management", "OutputProfile", icm.output); } + if (!pedited || pedited->icm.outputIntent) { + Glib::ustring intent; + switch (icm.outputIntent) { + default: + case RI_PERCEPTUAL: + intent = "Perceptual"; + break; + case RI_RELATIVE: + intent = "Relative"; + break; + case RI_SATURATION: + intent = "Saturation"; + break; + case RI_ABSOLUTE: + intent = "Absolute"; + break; + } + + keyFile.set_string ("Color Management", "OutputProfileIntent", intent); + } + if (!pedited || pedited->icm.gamma) { keyFile.set_string ("Color Management", "Gammafree", icm.gamma); } @@ -5672,6 +5694,23 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Color Management", "OutputProfileIntent")) { + Glib::ustring intent = keyFile.get_string ("Color Management", "OutputProfileIntent"); + if (intent == "Perceptual") { + icm.outputIntent = RI_PERCEPTUAL; + } else if (intent == "Relative") { + icm.outputIntent = RI_RELATIVE; + } else if (intent == "Saturation") { + icm.outputIntent = RI_SATURATION; + } else if (intent == "Absolute") { + icm.outputIntent = RI_ABSOLUTE; + } + + if (pedited) { + pedited->icm.outputIntent = true; + } + } + if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d46fd4181..1103d274d 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "LUT.h" #include "coord.h" @@ -41,6 +42,14 @@ class WavOpacityCurveW; class WavOpacityCurveWL; class RetinextransmissionCurve; +enum RenderingIntent { + RI_PERCEPTUAL = INTENT_PERCEPTUAL, + RI_RELATIVE = INTENT_RELATIVE_COLORIMETRIC, + RI_SATURATION = INTENT_SATURATION, + RI_ABSOLUTE = INTENT_ABSOLUTE_COLORIMETRIC, + RI__COUNT +}; + namespace procparams { @@ -941,6 +950,7 @@ public: int dcpIlluminant; Glib::ustring working; Glib::ustring output; + RenderingIntent outputIntent; static const Glib::ustring NoICMString; Glib::ustring gamma; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 3505da24f..f31300a64 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -64,9 +64,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DARKFRAME, // EvLCPUseVign, TRANSFORM, // EvLCPUseCA, M_VOID, // EvFixedExp - WHITEBALANCE, // EvWBMethod, - WHITEBALANCE, // EvWBTemp, - WHITEBALANCE, // EvWBGreen, + ALLNORAW, // EvWBMethod, + ALLNORAW, // EvWBTemp, + ALLNORAW, // EvWBGreen, RGBCURVE, // EvToneCurveMode1, RGBCURVE, // EvToneCurve2, RGBCURVE, // EvToneCurveMode2, @@ -75,7 +75,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { 0, // EvCDNEnabled:obsolete, ALL, // EvBlendCMSMatrix, RGBCURVE, // EvDCPToneCurve, - INPUTPROFILE, // EvDCPIlluminant, + ALLNORAW, // EvDCPIlluminant, RETINEX, // EvSHEnabled, RGBCURVE, // EvSHHighlights, RGBCURVE, // EvSHShadows, @@ -97,7 +97,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvHRMethod, ALLNORAW, // EvWProfile, OUTPUTPROFILE, // EvOProfile, - INPUTPROFILE, // EvIProfile, + ALLNORAW, // EvIProfile, TRANSFORM, // EvVignettingAmount, RGBCURVE, // EvChMixer, RESIZE, // EvResizeScale, @@ -234,8 +234,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvCATbadpix LUMINANCECURVE, // EvCATAutoadap DEFRINGE, // EvPFCurve - WHITEBALANCE, // EvWBequal - WHITEBALANCE, // EvWBequalbo + ALLNORAW, // EvWBequal + ALLNORAW, // EvWBequalbo TRANSFORM, // EvGradientDegree TRANSFORM, // EvGradientEnabled TRANSFORM, // EvPCVignetteStrength @@ -421,7 +421,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DIRPYREQUALIZER, // EvWavNeutral RGBCURVE, // EvDCPApplyLookTable, RGBCURVE, // EvDCPApplyBaselineExposureOffset, - INPUTPROFILE, // EvDCPApplyHueSatMap + ALLNORAW, // EvDCPApplyHueSatMap DIRPYREQUALIZER, // EvWavenacont DIRPYREQUALIZER, // EvWavenachrom DIRPYREQUALIZER, // EvWavenaedge @@ -452,7 +452,10 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvLslope RETINEX, // EvLhighl DEMOSAIC, // EvLbaselog -// DEMOSAIC, // EvLgrbl - DEMOSAIC // EvRetinexlhcurve +// DEMOSAIC, // EvLgrbl + DEMOSAIC, // EvRetinexlhcurve + ALLNORAW, // EvOIntent + MONITORTRANSFORM // EvMonitorTransform + }; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index e24d0c422..23e179f9f 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -20,15 +20,16 @@ #define __REFRESHMAP__ // Use M_VOID if you wish to update the proc params without updating the preview at all ! -#define M_VOID (1<<15) +#define M_VOID (1<<16) // Use M_MINUPDATE if you wish to update the preview without modifying the image (think about it like a "refreshPreview") // Must NOT be used with other event (i.e. will be used for MINUPDATE only) -#define M_MINUPDATE (1<<14) +#define M_MINUPDATE (1<<15) // Force high quality -#define M_HIGHQUAL (1<<13) +#define M_HIGHQUAL (1<<14) // Elementary functions that can be done to // the preview image when an event occurs +#define M_MONITOR (1<<13) #define M_RETINEX (1<<12) #define M_CROP (1<<11) #define M_PREPROC (1<<10) @@ -45,31 +46,30 @@ // Bitfield of functions to do to the preview image when an event occurs // Use those or create new ones for your new events -#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define AUTOEXP (M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE) -#define SHARPENING M_LUMINANCE -#define IMPULSEDENOISE M_LUMINANCE -#define DEFRINGE M_LUMINANCE -#define WHITEBALANCE (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DIRPYRDENOISE (M_COLOR|M_LUMINANCE) -#define CROP M_CROP -#define RESIZE M_VOID -#define EXIF M_VOID -#define IPTC M_VOID -#define DIRPYREQUALIZER (M_COLOR|M_LUMINANCE) -#define OUTPUTPROFILE (M_INIT|M_COLOR|M_LUMINANCE) -#define INPUTPROFILE WHITEBALANCE -#define GAMMA (M_COLOR|M_LUMINANCE) -#define MINUPDATE M_MINUPDATE -#define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define RETINEX (M_RETINEX|ALLNORAW) +#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define AUTOEXP (M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define SHARPENING (M_LUMINANCE|M_COLOR) +#define IMPULSEDENOISE (M_LUMINANCE|M_COLOR) +#define DEFRINGE (M_LUMINANCE|M_COLOR) +#define DIRPYRDENOISE (M_LUMINANCE|M_COLOR) +#define DIRPYREQUALIZER (M_LUMINANCE|M_COLOR) +#define GAMMA (M_LUMINANCE|M_COLOR) +#define CROP M_CROP +#define RESIZE M_VOID +#define EXIF M_VOID +#define IPTC M_VOID +#define MINUPDATE M_MINUPDATE +#define RETINEX (M_RETINEX|ALLNORAW) +#define MONITORTRANSFORM M_MONITOR +#define OUTPUTPROFILE (ALLNORAW|MONITORTRANSFORM) extern int refreshmap[]; #endif diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 195911a3a..42e06406e 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -35,7 +35,7 @@ #include "LUT.h" /** * @file - * This file contains the main functionality of the raw therapee engine. + * This file contains the main functionality of the RawTherapee engine. * */ @@ -413,9 +413,12 @@ public: virtual void setAutoBWListener (AutoBWListener* l) = 0; virtual void setAutoColorTonListener (AutoColorTonListener* l) = 0; virtual void setAutoChromaListener (AutoChromaListener* l) = 0; - virtual void setRetinexListener (RetinexListener* l) = 0; + virtual void setRetinexListener (RetinexListener* l) = 0; virtual void setWaveletListener (WaveletListener* l) = 0; + virtual void setMonitorProfile (const Glib::ustring& monitorProfile, RenderingIntent intent) = 0; + virtual void getMonitorProfile (Glib::ustring& monitorProfile, RenderingIntent& intent) const = 0; + virtual ~StagedImageProcessor () {} /** Returns a staged, cached image processing manager supporting partial updates diff --git a/rtengine/settings.h b/rtengine/settings.h index 373103d07..3e9c9d38a 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -19,6 +19,8 @@ #ifndef _RTSETTINGS_ #define _RTSETTINGS_ +#include "procparams.h" + namespace rtengine { @@ -27,7 +29,6 @@ class Settings { public: Glib::ustring iccDirectory; ///< The directory containing the possible output icc profiles - int colorimetricIntent; ///< Colorimetric intent used at color space conversions int viewingdevice; // white of output device (D50...D65..) int viewingdevicegrey; // level of grey output device int viewinggreySc; // level of grey Scene @@ -37,7 +38,8 @@ public: int leveldnliss; // level of auto multi zone int leveldnautsimpl; // STD or EXPERT - Glib::ustring monitorProfile; ///< ICC profile of the monitor (full path recommended) + Glib::ustring monitorProfile; ///< ICC profile name used for the monitor + RenderingIntent monitorIntent; ///< Colorimetric intent used with the above profile bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index da44b25e3..6e1c876cf 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1155,7 +1155,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p cmsFloat64Number Parameters[7]; double ga0, ga1, ga2, ga3, ga4, ga5, ga6; // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.working, params.icm.gamma, params.icm.freegamma, params.icm.gampos, params.icm.slpos, ga0, ga1, ga2, ga3, ga4, ga5, ga6, params.blackwhite.enabled ); + readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, params.icm.working, params.icm.gamma, params.icm.freegamma, params.icm.gampos, params.icm.slpos, ga0, ga1, ga2, ga3, ga4, ga5, ga6, params.blackwhite.enabled ); customGamma = true; //or selected Free gamma @@ -1163,7 +1163,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p bool pro = false; Glib::ustring chpro, outProfile; bool present_space[9] = {false, false, false, false, false, false, false, false, false}; - std::vector opnames = iccStore->getOutputProfiles (); + std::vector opnames = iccStore->getProfiles (); //test if files are in system for (int j = 0; j < 9; j++) { @@ -1347,7 +1347,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p bwonly = false; } - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, bwonly); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, bwonly); if (settings->verbose) { printf("Output profile_: \"%s\"\n", params.icm.output.c_str()); diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 38cf88230..99ad03e9f 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -3,6 +3,7 @@ */ #include "colortoning.h" #include "mycurve.h" +#include "rtimage.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index ad896789f..4ca2bb159 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -30,6 +30,7 @@ #include "mydiagonalcurve.h" #include "curveeditor.h" #include "diagonalcurveeditorsubgroup.h" +#include "rtimage.h" DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 82e8d9fcf..b9f123ac5 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -25,12 +25,188 @@ #include "procparamchangers.h" #include "../rtengine/safegtk.h" #include "../rtengine/imagesource.h" +#include "../rtengine/iccstore.h" #include "soundman.h" #include "rtimage.h" #include +#include "popupbutton.h" using namespace rtengine::procparams; +class EditorPanel::MonitorProfileSelector +{ +private: + MyComboBoxText profileBox; + PopUpButton intentBox; + sigc::connection profileConn, intentConn; + + rtengine::StagedImageProcessor* const& processor; + +private: + void prepareProfileBox () + { + profileBox.set_size_request (100, -1); + + profileBox.append_text (M("PREFERENCES_PROFILE_NONE")); +#ifdef WIN32 + profileBox.append_text (M("MONITOR_PROFILE_SYSTEM") + " (" + rtengine::iccStore->getDefaultMonitorProfileName() + ")"); + profileBox.set_active (options.rtSettings.autoMonitorProfile ? 1 : 0); +#else + profileBox.set_active (0); +#endif + + const std::vector profiles = rtengine::iccStore->getProfiles (); + for (std::vector::const_iterator iterator = profiles.begin (); iterator != profiles.end (); ++iterator) { + profileBox.append_text (*iterator); + } + } + + void prepareIntentBox () + { + intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + intentBox.addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + intentBox.addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); + + intentBox.setSelected(0); + intentBox.show (); + } + + void profileBoxChanged () + { + updateParameters (); + + profileBox.set_tooltip_text (profileBox.get_active_text ()); + } + + void intentBoxChanged (int) + { + updateParameters (); + } + + void updateParameters () + { + ConnectionBlocker profileBlocker (profileConn); + ConnectionBlocker intentBlocker (intentConn); + + Glib::ustring profile; + +#ifdef WIN32 + if (profileBox.get_active_row_number () == 1) { + profile = rtengine::iccStore->getDefaultMonitorProfileName (); + if (profile.empty ()) { + profile = options.rtSettings.monitorProfile; + } + if (profile.empty ()) { + profile = "sRGB IEC61966-2.1"; + } + } else if (profileBox.get_active_row_number () > 1) { + profile = profileBox.get_active_text (); + } +#else + profile = profileBox.get_active_row_number () > 0 ? profileBox.get_active_text () : Glib::ustring (); +#endif + + if (profileBox.get_active_row_number () == 0) { + + profile.clear(); + + intentBox.set_sensitive (false); + intentBox.setSelected (0); + + } else { + const std::uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const bool supportsRelativeColorimetric = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; + const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; + const bool supportsAbsoluteColorimetric = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; + + if (supportsPerceptual || supportsRelativeColorimetric || supportsAbsoluteColorimetric) { + intentBox.set_sensitive (true); + intentBox.setItemSensitivity(0, supportsRelativeColorimetric); + intentBox.setItemSensitivity(1, supportsPerceptual); + intentBox.setItemSensitivity(2, supportsAbsoluteColorimetric); + } else { + intentBox.set_sensitive (false); + intentBox.setSelected (0); + } + } + + rtengine::RenderingIntent intent; + switch (intentBox.getSelected ()) { + default: + case 0: + intent = rtengine::RI_RELATIVE; + break; + case 1: + intent = rtengine::RI_PERCEPTUAL; + break; + case 2: + intent = rtengine::RI_ABSOLUTE; + break; + } + + if (!processor) { + return; + } + + processor->beginUpdateParams (); + processor->setMonitorProfile (profile, intent); + processor->endUpdateParams (rtengine::EvMonitorTransform); + } + +public: + MonitorProfileSelector (rtengine::StagedImageProcessor* const& ipc) : + intentBox (Glib::ustring (), true), + processor (ipc) + { + prepareProfileBox (); + prepareIntentBox (); + + reset (); + + profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::profileBoxChanged)); + intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::intentBoxChanged)); + } + + void pack_end_in (Gtk::Box* box) + { + box->pack_end (*intentBox.buttonGroup, Gtk::PACK_SHRINK, 0); + box->pack_end (profileBox, Gtk::PACK_SHRINK, 0); + } + + void reset () + { + ConnectionBlocker profileBlocker (profileConn); + ConnectionBlocker intentBlocker (intentConn); + +#ifdef WIN32 + if (options.rtSettings.autoMonitorProfile) { + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 1); + } else { + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 0); + } +#else + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 0); +#endif + + switch (options.rtSettings.monitorIntent) + { + default: + case rtengine::RI_RELATIVE: + intentBox.setSelected (0); + break; + case rtengine::RI_PERCEPTUAL: + intentBox.setSelected (1); + break; + case rtengine::RI_ABSOLUTE: + intentBox.setSelected (2); + break; + } + + updateParameters (); + } + +}; + EditorPanel::EditorPanel (FilePanel* filePanel) : realized(false), iHistoryShow(NULL), iHistoryHide(NULL), iTopPanel_1_Show(NULL), iTopPanel_1_Hide(NULL), iRightPanel_1_Show(NULL), iRightPanel_1_Hide(NULL), iBeforeLockON(NULL), iBeforeLockOFF(NULL), beforePreviewHandler(NULL), beforeIarea(NULL), beforeBox(NULL), afterBox(NULL), afterHeaderBox(NULL), parent(NULL), openThm(NULL), ipc(NULL), beforeIpc(NULL), isProcessing(false), catalogPane(NULL) { @@ -179,6 +355,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) // Save buttons Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ()); + iops->set_spacing(2); //Gtk::Image *saveButtonImage = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)); Gtk::Image *saveButtonImage = Gtk::manage (new RTImage ("gtk-save-large.png")); @@ -262,6 +439,12 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iops->pack_end (*navPrev, Gtk::PACK_SHRINK, 0); } + iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); + + // Monitor profile buttons + monitorProfile.reset (new MonitorProfileSelector (ipc)); + monitorProfile->pack_end_in (iops); + editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); editbox->show_all (); @@ -568,6 +751,8 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) } history->resetSnapShotNumber(); + + monitorProfile->reset (); } void EditorPanel::close () diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index cf446da97..6de9928bd 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -84,6 +84,9 @@ protected: Gtk::Button* navNext; Gtk::Button* navPrev; + class MonitorProfileSelector; + std::auto_ptr monitorProfile; + ImageAreaPanel* iareapanel; PreviewHandler* previewHandler; PreviewHandler* beforePreviewHandler; // for the before-after view diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index e464b050e..915f0d84e 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1152,6 +1152,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.icm.input = options.fastexport_icm_input ; params.icm.working = options.fastexport_icm_working ; params.icm.output = options.fastexport_icm_output ; + params.icm.outputIntent = options.fastexport_icm_outputIntent ; params.icm.gamma = options.fastexport_icm_gamma ; params.resize.enabled = options.fastexport_resize_enabled ; params.resize.scale = options.fastexport_resize_scale ; diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index 516bed44a..691fbe3dd 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -31,6 +31,7 @@ #include "myflatcurve.h" #include "curveeditor.h" #include "flatcurveeditorsubgroup.h" +#include "rtimage.h" FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 1e65f2753..79f050c2f 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -76,6 +76,22 @@ public: } }; +class ConnectionBlocker +{ +public: + ConnectionBlocker (sigc::connection& connection) : connection (connection) + { + wasBlocked = connection.block(); + } + ~ConnectionBlocker () + { + connection.block(wasBlocked); + } +private: + sigc::connection& connection; + bool wasBlocked; +}; + /** * @brief Glue box to control visibility of the MyExpender's content ; also handle the frame around it */ @@ -496,5 +512,12 @@ public: } }; +inline void setActiveTextOrIndex (Gtk::ComboBoxText& comboBox, const Glib::ustring& text, int index) +{ + comboBox.set_active_text (text); + + if (comboBox.get_active_row_number () < 0) + comboBox.set_active (index); +} #endif diff --git a/rtgui/history.cc b/rtgui/history.cc index 57f7549db..689ea6394 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -24,7 +24,6 @@ using namespace rtengine; using namespace rtengine::procparams; Glib::ustring eventDescrArray[NUMOFEVENTS]; -extern Glib::ustring argv0; History::History (bool bookmarkSupport) : blistener(NULL), tpc (NULL), bmnum (1) { @@ -204,8 +203,8 @@ void History::bookmarkSelectionChanged () void History::procParamsChanged (ProcParams* params, ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { - // to prevent recursion, we filter out the events triggered by the history - if (ev == EvHistoryBrowsed) { + // to prevent recursion, we filter out the events triggered by the history and events that should not be registered + if (ev == EvHistoryBrowsed || ev == EvMonitorTransform) { return; } diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index e9e4e05ff..8b8057d45 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -83,7 +83,8 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch dcpFrame = Gtk::manage (new Gtk::Frame ("DCP")); Gtk::VBox* dcpFrameVBox = Gtk::manage (new Gtk::VBox ()); - dcpFrameVBox->set_border_width(4); + dcpFrameVBox->set_border_width(0); + dcpFrameVBox->set_spacing(2); Gtk::HBox* dcpIllHBox = Gtk::manage (new Gtk::HBox ()); dcpIllLabel = Gtk::manage (new Gtk::Label (M("TP_ICM_DCPILLUMINANT") + ":")); @@ -101,29 +102,25 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch dcpIllHBox->pack_start(*dcpIllLabel, Gtk::PACK_SHRINK, 4); dcpIllHBox->pack_start(*dcpIll); - Gtk::HBox* c1HBox = Gtk::manage ( new Gtk::HBox(true, 4)); ckbToneCurve = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_TONECURVE"))); ckbToneCurve->set_sensitive (false); ckbToneCurve->set_tooltip_text (M("TP_ICM_TONECURVE_TOOLTIP")); ckbApplyHueSatMap = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYHUESATMAP"))); ckbApplyHueSatMap->set_sensitive (false); ckbApplyHueSatMap->set_tooltip_text (M("TP_ICM_APPLYHUESATMAP_TOOLTIP")); - c1HBox->pack_start (*ckbToneCurve); - c1HBox->pack_start (*ckbApplyHueSatMap); - Gtk::HBox* c2HBox = Gtk::manage ( new Gtk::HBox(true, 4)); ckbApplyLookTable = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYLOOKTABLE"))); ckbApplyLookTable->set_sensitive (false); ckbApplyLookTable->set_tooltip_text (M("TP_ICM_APPLYLOOKTABLE_TOOLTIP")); ckbApplyBaselineExposureOffset = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYBASELINEEXPOSUREOFFSET"))); ckbApplyBaselineExposureOffset->set_sensitive (false); ckbApplyBaselineExposureOffset->set_tooltip_text (M("TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP")); - c2HBox->pack_start (*ckbApplyLookTable); - c2HBox->pack_start (*ckbApplyBaselineExposureOffset); - dcpFrameVBox->pack_start(*dcpIllHBox); - dcpFrameVBox->pack_start(*c1HBox); - dcpFrameVBox->pack_start(*c2HBox); + dcpFrameVBox->pack_start(*dcpIllHBox, Gtk::PACK_SHRINK, 0); + dcpFrameVBox->pack_start(*ckbToneCurve, Gtk::PACK_SHRINK,0); + dcpFrameVBox->pack_start(*ckbApplyHueSatMap, Gtk::PACK_SHRINK,0); + dcpFrameVBox->pack_start(*ckbApplyLookTable, Gtk::PACK_SHRINK,0); + dcpFrameVBox->pack_start(*ckbApplyBaselineExposureOffset, Gtk::PACK_SHRINK,0); dcpFrame->add(*dcpFrameVBox); dcpFrame->set_sensitive(false); iVBox->pack_start (*dcpFrame); @@ -185,7 +182,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch onames->append_text (M("TP_ICM_NOICM")); onames->set_active (0); - std::vector opnames = iccStore->getOutputProfiles (); + std::vector opnames = iccStore->getProfiles (); for (size_t i = 0; i < opnames.size(); i++) { onames->append_text (opnames[i]); @@ -193,6 +190,19 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch onames->set_active (0); + // Rendering intent + Gtk::HBox *riHBox = Gtk::manage ( new Gtk::HBox()); + Gtk::Label* outputIntentLbl = Gtk::manage (new Gtk::Label(M("TP_ICM_PROFILEINTENT")+":")); + riHBox->pack_start (*outputIntentLbl, Gtk::PACK_SHRINK); + ointent = Gtk::manage (new MyComboBoxText ()); + riHBox->pack_start (*ointent, Gtk::PACK_EXPAND_WIDGET); + ointent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + ointent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + ointent->append_text (M("PREFERENCES_INTENT_SATURATION")); + ointent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); + ointent->set_active (1); + oVBox->pack_start(*riHBox, Gtk::PACK_SHRINK); + // Output gamma Gtk::HBox* gaHBox = Gtk::manage (new Gtk::HBox ()); @@ -282,6 +292,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) ); onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) ); + ointent->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::oiChanged) ); wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) ); dcpIll->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::dcpIlluminantChanged) ); @@ -507,6 +518,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) if (onames->get_active_row_number() == -1) { onames->set_active_text (M("TP_ICM_NOICM")); } + ointent->set_active(pp->icm.outputIntent); ckbToneCurve->set_active (pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; @@ -545,6 +557,10 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) onames->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->icm.outputIntent) { + ointent->set_active_text(M("GENERAL_UNCHANGED")); + } + if (!pedited->icm.dcpIlluminant) { dcpIll->set_active_text(M("GENERAL_UNCHANGED")); } @@ -605,6 +621,13 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pp->icm.output = onames->get_active_text(); } + int ointentVal = ointent->get_active_row_number(); + if (ointentVal >= 0 && ointentVal < RI__COUNT) { + pp->icm.outputIntent = static_cast(ointentVal); + } else { + pp->icm.outputIntent = rtengine::RI_RELATIVE; + } + pp->icm.freegamma = freegamma->get_active(); DCPProfile* dcp = NULL; @@ -641,6 +664,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pedited->icm.input = !iunchanged->get_active (); pedited->icm.working = wnames->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->icm.outputIntent = ointent->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent (); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent (); @@ -880,6 +904,14 @@ void ICMPanel::opChanged () } } +void ICMPanel::oiChanged () +{ + + if (listener) { + listener->panelChanged (EvOIntent, ointent->get_active_text()); + } +} + void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) { @@ -979,6 +1011,7 @@ void ICMPanel::setBatchMode (bool batchMode) iVBox->reorder_child (*iunchanged, 5); removeIfThere (this, saveRef); onames->append_text (M("GENERAL_UNCHANGED")); + ointent->append_text (M("GENERAL_UNCHANGED")); wnames->append_text (M("GENERAL_UNCHANGED")); wgamma->append_text (M("GENERAL_UNCHANGED")); dcpIll->append_text (M("GENERAL_UNCHANGED")); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 93828f5fd..863e88a46 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -78,6 +78,7 @@ private: MyComboBoxText* wgamma; MyComboBoxText* onames; + MyComboBoxText* ointent; Gtk::RadioButton* ofromdir; Gtk::RadioButton* ofromfile; Gtk::RadioButton* iunchanged; @@ -107,6 +108,7 @@ public: void wpChanged (); void opChanged (); + void oiChanged (); void ipChanged (); void gpChanged (); void GamChanged (); diff --git a/rtgui/options.cc b/rtgui/options.cc index 6d0b6a0d0..e97a27ecb 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -470,6 +470,7 @@ void Options::setDefaults () fastexport_icm_input = "(camera)"; fastexport_icm_working = "ProPhoto"; fastexport_icm_output = "RT_sRGB"; + fastexport_icm_outputIntent = rtengine::RI_RELATIVE; fastexport_icm_gamma = "default"; fastexport_resize_enabled = true; fastexport_resize_scale = 1; @@ -626,7 +627,6 @@ void Options::setDefaults () #else rtSettings.iccDirectory = "/usr/share/color/icc"; #endif - rtSettings.colorimetricIntent = 1; rtSettings.viewingdevice = 0; rtSettings.viewingdevicegrey = 3; rtSettings.viewinggreySc = 1; @@ -636,7 +636,8 @@ void Options::setDefaults () rtSettings.leveldnliss = 0; rtSettings.leveldnautsimpl = 0; - rtSettings.monitorProfile = ""; + rtSettings.monitorProfile = Glib::ustring(); + rtSettings.monitorIntent = rtengine::RI_RELATIVE; rtSettings.autoMonitorProfile = false; rtSettings.adobe = "RT_Medium_gsRGB"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RT_Large_gBT709"; // these names appear in the menu "output profile" @@ -1461,7 +1462,7 @@ int Options::readFromFile (Glib::ustring fname) } if (keyFile.has_key ("Color Management", "Intent")) { - rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); + rtSettings.monitorIntent = static_cast(keyFile.get_integer("Color Management", "Intent")); } if (keyFile.has_key ("Color Management", "CRI")) { @@ -1712,6 +1713,10 @@ int Options::readFromFile (Glib::ustring fname) fastexport_icm_output = keyFile.get_string ("Fast Export", "fastexport_icm_output" ); } + if (keyFile.has_key ("Fast Export", "fastexport_icm_output_intent" )) { + fastexport_icm_outputIntent = static_cast(keyFile.get_integer ("Fast Export", "fastexport_icm_output_intent" )); + } + if (keyFile.has_key ("Fast Export", "fastexport_icm_gamma" )) { fastexport_icm_gamma = keyFile.get_string ("Fast Export", "fastexport_icm_gamma" ); } @@ -2008,7 +2013,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); keyFile.set_boolean ("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); - keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); + keyFile.set_integer ("Color Management", "Intent", rtSettings.monitorIntent); keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); @@ -2075,6 +2080,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_string ("Fast Export", "fastexport_icm_input" , fastexport_icm_input ); keyFile.set_string ("Fast Export", "fastexport_icm_working" , fastexport_icm_working ); keyFile.set_string ("Fast Export", "fastexport_icm_output" , fastexport_icm_output ); + keyFile.set_integer ("Fast Export", "fastexport_icm_output_intent" , fastexport_icm_outputIntent ); keyFile.set_string ("Fast Export", "fastexport_icm_gamma" , fastexport_icm_gamma ); keyFile.set_boolean ("Fast Export", "fastexport_resize_enabled" , fastexport_resize_enabled ); keyFile.set_double ("Fast Export", "fastexport_resize_scale" , fastexport_resize_scale ); diff --git a/rtgui/options.h b/rtgui/options.h index 614042fa2..b896f4129 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -264,6 +264,7 @@ public: Glib::ustring fastexport_icm_input; Glib::ustring fastexport_icm_working; Glib::ustring fastexport_icm_output; + rtengine::RenderingIntent fastexport_icm_outputIntent; Glib::ustring fastexport_icm_gamma; bool fastexport_resize_enabled; double fastexport_resize_scale; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ac2fe6523..866142a10 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -339,6 +339,7 @@ void ParamsEdited::set (bool v) icm.dcpIlluminant = v; icm.working = v; icm.output = v; + icm.outputIntent = v; icm.gamma = v; icm.freegamma = v; icm.gampos = v; @@ -816,6 +817,7 @@ void ParamsEdited::initFrom (const std::vector icm.dcpIlluminant = icm.dcpIlluminant && p.icm.dcpIlluminant == other.icm.dcpIlluminant; icm.working = icm.working && p.icm.working == other.icm.working; icm.output = icm.output && p.icm.output == other.icm.output; + icm.outputIntent = icm.outputIntent && p.icm.outputIntent == other.icm.outputIntent; icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma; icm.freegamma = icm.freegamma && p.icm.freegamma == other.icm.freegamma; icm.gampos = icm.gampos && p.icm.gampos == other.icm.gampos; @@ -2119,6 +2121,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.icm.output = mods.icm.output; } + if (icm.outputIntent) { + toEdit.icm.outputIntent = mods.icm.outputIntent; + } + //if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos; //if (icm.slpos) toEdit.icm.slpos = mods.icm.slpos; if (icm.gampos) { diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 3fa753013..1993c7aaa 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -530,6 +530,7 @@ public: bool dcpIlluminant; bool working; bool output; + bool outputIntent; bool gamma; bool gampos; bool slpos; diff --git a/rtgui/popupbutton.cc b/rtgui/popupbutton.cc index 440d7b420..554f41cc6 100644 --- a/rtgui/popupbutton.cc +++ b/rtgui/popupbutton.cc @@ -21,6 +21,8 @@ #include "popupbutton.h" +#include + /* * PopUpButton::PopUpButton (const Glib::ustring& label, bool imgRight) * @@ -28,8 +30,14 @@ * * Parameters: * label = label displayed in the button + * nextOnClicked = selects the next entry if the button is clicked */ -PopUpButton::PopUpButton (const Glib::ustring& label) : Gtk::Button(), PopUpCommon(this, label) { } +PopUpButton::PopUpButton (const Glib::ustring& label, bool nextOnClicked) + : Gtk::Button () + , PopUpCommon (this, label) + , nextOnClicked(nextOnClicked) +{ +} void PopUpButton::show() { @@ -39,3 +47,27 @@ void PopUpButton::set_tooltip_text (const Glib::ustring &text) { PopUpCommon::set_tooltip_text (text); } + +void PopUpButton::set_sensitive (bool isSensitive) +{ + buttonGroup->set_sensitive(isSensitive); +} + +bool PopUpButton::on_button_release_event (GdkEventButton* event) +{ + if (nextOnClicked && getEntryCount () > 1) + { + const int last = getEntryCount () - 1; + int next = getSelected (); + + if (event->state & GDK_SHIFT_MASK) { + next = next > 0 ? next - 1 : last; + } else { + next = next < last ? next + 1 : 0; + } + + entrySelected (next); + } + + return Gtk::Button::on_button_release_event(event); +} diff --git a/rtgui/popupbutton.h b/rtgui/popupbutton.h index 23a9211a8..245d29aee 100644 --- a/rtgui/popupbutton.h +++ b/rtgui/popupbutton.h @@ -21,16 +21,24 @@ #ifndef _POPUPBUTTON_ #define _POPUPBUTTON_ -#include +#include #include "popupcommon.h" class PopUpButton : public Gtk::Button, public PopUpCommon { public: - PopUpButton (const Glib::ustring& label = ""); + PopUpButton (const Glib::ustring& label = Glib::ustring (), bool nextOnClicked = false); void show (); void set_tooltip_text (const Glib::ustring &text); + void set_sensitive (bool isSensitive=true); + +protected: + bool on_button_release_event (GdkEventButton* event); + +private: + bool nextOnClicked; + }; #endif diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 881994589..f7e667219 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -19,12 +19,16 @@ * Class created by Jean-Christophe FRISCH, aka 'Hombre' */ +#include #include "multilangmgr.h" #include "popupcommon.h" #include "../rtengine/safegtk.h" #include "rtimage.h" PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) + : selected (-1) // -1 means that the button is invalid + , menu (0) + , buttonImage (0) { button = thisButton; hasMenu = false; @@ -41,15 +45,6 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) // Create the global container and put the button in it buttonGroup = Gtk::manage( new Gtk::HBox(false, 0)); buttonGroup->pack_start(*button, Gtk::PACK_EXPAND_WIDGET, 0); - // Create the list entry - imageFilenames.clear(); - images.clear(); - sItems.clear(); - items.clear(); - selected = -1; // -1 : means that the button is invalid - menu = 0; - buttonImage = 0; - buttonHint = ""; } PopUpCommon::~PopUpCommon () @@ -58,83 +53,68 @@ PopUpCommon::~PopUpCommon () delete *i; } - for (std::vector::iterator i = items.begin(); i != items.end(); ++i) { - delete *i; - } - - if (menu) { - delete menu; - } - - if (buttonImage) { - delete buttonImage; - } - - delete buttonGroup; + delete menu; + delete buttonImage; } -PopUpCommon::type_signal_changed PopUpCommon::signal_changed() +bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label) { - return message; -} + if (label.empty ()) + return false; -bool PopUpCommon::addEntry (Glib::ustring fileName, Glib::ustring label) -{ - bool added = false; + // Create the image + RTImage* newImage = new RTImage(fileName); + images.push_back(newImage); + imageFilenames.push_back(fileName); + int currPos = (int)images.size(); + // Create the menu item + Gtk::ImageMenuItem* newItem = Gtk::manage(new Gtk::ImageMenuItem (*newImage, label)); - if ( label.size() ) { - imageFilenames.push_back(fileName); - sItems.push_back(label); - // Create the image - RTImage* newImage = new RTImage(fileName); - images.push_back(newImage); - int currPos = (int)images.size(); - // Create the menu item - Gtk::ImageMenuItem* newItem = new Gtk::ImageMenuItem (*newImage, label); - items.push_back(newItem); - - if (selected == -1) { - // Create the menu on the first item - menu = new Gtk::Menu (); - // Create the image for the button - buttonImage = new RTImage(fileName); - // Use the first image by default - imageContainer->pack_start(*buttonImage, Gtk::PACK_EXPAND_WIDGET); - selected = 0; - } - - // When there is at least 1 choice, we add the arrow button - if (images.size() == 1) { - Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); - RTImage* arrowImage = Gtk::manage( new RTImage("popuparrow.png") ); - arrowButton->add(*arrowImage); //menuSymbol); - arrowButton->set_relief (Gtk::RELIEF_NONE); - arrowButton->set_border_width (0); - buttonGroup->pack_start(*arrowButton, Gtk::PACK_SHRINK, 0); - arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); - hasMenu = true; - } - - newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos - 1)); - menu->attach (*newItem, 0, 1, currPos - 1, currPos); - // The item has been created - added = true; + if (selected == -1) { + // Create the menu on the first item + menu = new Gtk::Menu (); + // Create the image for the button + buttonImage = new RTImage(fileName); + // Use the first image by default + imageContainer->pack_start(*buttonImage, Gtk::PACK_EXPAND_WIDGET); + selected = 0; } - return added; + // When there is at least 1 choice, we add the arrow button + if (images.size() == 1) { + Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); + RTImage* arrowImage = Gtk::manage( new RTImage("popuparrow.png") ); + arrowButton->add(*arrowImage); //menuSymbol); + arrowButton->set_relief (Gtk::RELIEF_NONE); + arrowButton->set_border_width (0); + buttonGroup->pack_start(*arrowButton, Gtk::PACK_SHRINK, 0); + arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); + hasMenu = true; + } + + newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos - 1)); + menu->attach (*newItem, 0, 1, currPos - 1, currPos); + + return true; } // TODO: 'PopUpCommon::removeEntry' method to be created... void PopUpCommon::entrySelected (int i) { - if (setSelected((unsigned int)i)) - // Emit a a signal if the selected item has changed - { - message.emit(selected); + // Emit a a signal if the selected item has changed + if (setSelected (i)) + message (selected); +} + +void PopUpCommon::setItemSensitivity (int i, bool isSensitive) { + Gtk::Menu_Helpers::MenuList items = menu->items(); + if (i < items.size()) { + items[i].set_sensitive(isSensitive); } } + /* * Set the button image with the selected item */ @@ -172,7 +152,12 @@ void PopUpCommon::setButtonHint() } if (selected > -1) { - hint += sItems.at(selected); + // HACK: Gtk::MenuItem::get_label does not seem to work reliably. + Gtk::MenuItem& item = menu->items ()[selected]; + Gtk::Label* label = dynamic_cast(item.get_child ()); + + if (label) + hint += label->get_text (); } button->set_tooltip_markup(hint); diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index 872beb434..b5cb757f4 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -21,11 +21,21 @@ #ifndef _POPUPCOMMON_ #define _POPUPCOMMON_ +#include +#include +#include -#include -#include -#include "rtimage.h" +namespace Gtk +{ +class HBox; +class Menu; +class Button; +class ImageMenuItem; +} +typedef struct _GdkEventButton GdkEventButton; + +class RTImage; class PopUpCommon { @@ -37,27 +47,20 @@ public: PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); virtual ~PopUpCommon (); - bool addEntry (Glib::ustring fileName, Glib::ustring label); + bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label); + int getEntryCount () const; bool setSelected (int entryNum); - int getSelected () - { - return selected; - } + int getSelected () const; void setButtonHint(); void show (); void set_tooltip_text (const Glib::ustring &text); + void setItemSensitivity (int i, bool isSensitive); private: type_signal_changed message; - /* - TODO: MenuItem::get_label() doesn't return any string, or an empty string !? - That's why we store entries strings in sItems, but it would be nice to get ride of it... - */ - std::vector sItems; std::vector imageFilenames; std::vector images; - std::vector items; Glib::ustring buttonHint; RTImage* buttonImage; Gtk::HBox* imageContainer; @@ -67,8 +70,25 @@ private: bool hasMenu; void showMenu(GdkEventButton* event); + +protected: void entrySelected (int i); }; +inline PopUpCommon::type_signal_changed PopUpCommon::signal_changed () +{ + return message; +} + +inline int PopUpCommon::getEntryCount () const +{ + return images.size(); +} + +inline int PopUpCommon::getSelected () const +{ + return selected; +} + #endif diff --git a/rtgui/popuptogglebutton.h b/rtgui/popuptogglebutton.h index 58342e66c..930fae4f2 100644 --- a/rtgui/popuptogglebutton.h +++ b/rtgui/popuptogglebutton.h @@ -21,7 +21,7 @@ #ifndef _POPUPTOGGLEBUTTON_ #define _POPUPTOGGLEBUTTON_ -#include "popupbutton.h" +#include #include "popupcommon.h" class PopUpToggleButton : public Gtk::ToggleButton, public PopUpCommon diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index dca0eff17..0033978c3 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -687,32 +687,28 @@ Gtk::Widget* Preferences::getColorManagementPanel () Gtk::VBox* mvbcm = Gtk::manage (new Gtk::VBox ()); mvbcm->set_border_width (4); - /* - Gtk::Label* intlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CMETRICINTENT")+":", Gtk::ALIGN_LEFT)); - intent = Gtk::manage (new Gtk::ComboBoxText ()); - intent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); - intent->append_text (M("PREFERENCES_INTENT_RELATIVE")); - intent->append_text (M("PREFERENCES_INTENT_SATURATION")); - intent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); - */ - iccDir = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_ICCDIR") + ":", Gtk::ALIGN_LEFT)); - Gtk::FileFilter monProfileFilter_colprof; - monProfileFilter_colprof.set_name(M("FILECHOOSER_FILTER_COLPROF")); - monProfileFilter_colprof.add_pattern("*.icc"); - monProfileFilter_colprof.add_pattern("*.ICC"); - monProfileFilter_colprof.add_pattern("*.icm"); - monProfileFilter_colprof.add_pattern("*.ICM"); - Gtk::FileFilter monProfileFilter_any; - monProfileFilter_any.set_name(M("FILECHOOSER_FILTER_ANY")); - monProfileFilter_any.add_pattern("*"); + monProfile = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONPROFILE") + ":", Gtk::ALIGN_LEFT)); - monProfile = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_MONITORICC"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - monProfile->add_filter (monProfileFilter_colprof); - monProfile->add_filter (monProfileFilter_any); - Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONITORICC") + ":", Gtk::ALIGN_LEFT)); + monIntent = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* milabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONINTENT")+":", Gtk::ALIGN_LEFT)); + + monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active (0); + + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (); + for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + monProfile->append_text (*profile); + + monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + monIntent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + monIntent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); + monIntent->set_active (1); + + iccDir->signal_selection_changed ().connect (sigc::mem_fun (this, &Preferences::iccDirChanged)); #if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 cbAutoMonProfile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_AUTOMONPROFILE"))); @@ -720,17 +716,21 @@ Gtk::Widget* Preferences::getColorManagementPanel () #endif Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 2)); - //colt->attach (*intlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - //colt->attach (*intent, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colt->attach (*pdlabel, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*iccDir, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + int row = 0; + colt->attach (*pdlabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*iccDir, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); #if !defined(__APPLE__) // monitor profile not supported on apple - colt->attach (*mplabel, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*monProfile, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + ++row; + colt->attach (*mplabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*monProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); #if defined(WIN32) - colt->attach (*cbAutoMonProfile, 1, 2, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + ++row; + colt->attach (*cbAutoMonProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); #endif #endif + ++row; + colt->attach (*milabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*monIntent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); #if defined(WIN32) @@ -1445,12 +1445,26 @@ void Preferences::storePreferences () moptions.CPBPath = txtCustProfBuilderPath->get_text(); moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); - moptions.rtSettings.monitorProfile = monProfile->get_filename (); +#if !defined(__APPLE__) // monitor profile not supported on apple + moptions.rtSettings.monitorProfile = monProfile->get_active_text (); + switch (monIntent->get_active_row_number ()) { + default: + case 0: + moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE; + break; + case 1: + moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; + break; + case 2: + moptions.rtSettings.monitorIntent = rtengine::RI_ABSOLUTE; + break; + } #if defined(WIN32) moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); #endif +#endif + moptions.rtSettings.iccDirectory = iccDir->get_filename (); - //moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); moptions.rtSettings.viewingdevice = view->get_active_row_number (); moptions.rtSettings.viewingdevicegrey = grey->get_active_row_number (); moptions.rtSettings.viewinggreySc = greySc->get_active_row_number (); @@ -1560,16 +1574,21 @@ void Preferences::fillPreferences () panFactor->set_value (moptions.panAccelFactor); rememberZoomPanCheckbutton->set_active (moptions.rememberZoomAndPan); ctiffserialize->set_active(moptions.serializeTiffRead); + #if !defined(__APPLE__) // monitor profile not supported on apple - - if (safe_file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) { - monProfile->set_filename (moptions.rtSettings.monitorProfile); + setActiveTextOrIndex (*monProfile, moptions.rtSettings.monitorProfile, 0); + switch (moptions.rtSettings.monitorIntent) { + default: + case rtengine::RI_RELATIVE: + monIntent->set_active (0); + break; + case rtengine::RI_PERCEPTUAL: + monIntent->set_active (1); + break; + case rtengine::RI_ABSOLUTE: + monIntent->set_active (2); + break; } - - if (moptions.rtSettings.monitorProfile.empty()) { - monProfile->set_current_folder (moptions.rtSettings.iccDirectory); - } - #if defined(WIN32) cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif @@ -1579,7 +1598,6 @@ void Preferences::fillPreferences () iccDir->set_current_folder (moptions.rtSettings.iccDirectory); } - //intent->set_active (moptions.rtSettings.colorimetricIntent); view->set_active (moptions.rtSettings.viewingdevice); grey->set_active (moptions.rtSettings.viewingdevicegrey); greySc->set_active (moptions.rtSettings.viewinggreySc); @@ -1931,6 +1949,22 @@ void Preferences::bundledProfilesChanged () rpconn.block (false); } +void Preferences::iccDirChanged () +{ + const Glib::ustring currentSelection = monProfile->get_active_text (); + + monProfile->clear(); + + monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active (0); + + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfilesFromDir (iccDir->get_filename ()); + for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + monProfile->append_text (*profile); + + monProfile->set_active_text (currentSelection); +} + void Preferences::storeCurrentValue() { // TODO: Find a way to get and restore the current selection; the following line can't work anymore diff --git a/rtgui/preferences.h b/rtgui/preferences.h index ee885c568..1cfb435cf 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -95,7 +95,8 @@ protected: Gtk::CheckButton* showExpComp; Gtk::FileChooserButton* iccDir; - Gtk::FileChooserButton* monProfile; + Gtk::ComboBoxText* monProfile; + Gtk::ComboBoxText* monIntent; Gtk::CheckButton* cbAutoMonProfile; //Gtk::CheckButton* cbAutocielab; Gtk::CheckButton* cbciecamfloat; @@ -106,7 +107,6 @@ protected: Gtk::SpinButton* panFactor; Gtk::CheckButton* rememberZoomPanCheckbutton; - Gtk::ComboBoxText* intent; Gtk::ComboBoxText* view; Gtk::ComboBoxText* grey; Gtk::ComboBoxText* greySc; @@ -212,7 +212,8 @@ protected: void forRAWComboChanged (); void forImageComboChanged (); void layoutComboChanged (); - void bundledProfilesChanged(); + void bundledProfilesChanged (); + void iccDirChanged (); void switchThemeTo (Glib::ustring newTheme, bool slimInterface); void switchFontTo (Glib::ustring newFont); bool splashClosed(GdkEventAny* event); diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index b964ecbb5..43cbe4f28 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -3,6 +3,7 @@ */ #include "retinex.h" #include "mycurve.h" +#include "rtimage.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 4bebb10ad..abab1d2d1 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -21,6 +21,7 @@ #include #include "edit.h" #include "guiutils.h" +#include "rtimage.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/tools/source_icons/scalable/intent-absolute.file b/tools/source_icons/scalable/intent-absolute.file new file mode 100644 index 000000000..57278bff2 --- /dev/null +++ b/tools/source_icons/scalable/intent-absolute.file @@ -0,0 +1 @@ +intent-absolute.png,w25,actions diff --git a/tools/source_icons/scalable/intent-absolute.svg b/tools/source_icons/scalable/intent-absolute.svg new file mode 100644 index 000000000..b5092b0c5 --- /dev/null +++ b/tools/source_icons/scalable/intent-absolute.svg @@ -0,0 +1,1376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/intent-perceptual.file b/tools/source_icons/scalable/intent-perceptual.file new file mode 100644 index 000000000..3e7520042 --- /dev/null +++ b/tools/source_icons/scalable/intent-perceptual.file @@ -0,0 +1 @@ +intent-perceptual.png,w25,actions diff --git a/tools/source_icons/scalable/intent-perceptual.svg b/tools/source_icons/scalable/intent-perceptual.svg new file mode 100644 index 000000000..3c949c91e --- /dev/null +++ b/tools/source_icons/scalable/intent-perceptual.svg @@ -0,0 +1,1362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/intent-relative.file b/tools/source_icons/scalable/intent-relative.file new file mode 100644 index 000000000..5191a25c3 --- /dev/null +++ b/tools/source_icons/scalable/intent-relative.file @@ -0,0 +1 @@ +intent-relative.png,w25,actions diff --git a/tools/source_icons/scalable/intent-relative.svg b/tools/source_icons/scalable/intent-relative.svg new file mode 100644 index 000000000..706de23d1 --- /dev/null +++ b/tools/source_icons/scalable/intent-relative.svg @@ -0,0 +1,1361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/tools/source_icons/scalable/intent-saturation.file b/tools/source_icons/scalable/intent-saturation.file new file mode 100644 index 000000000..9f33b978e --- /dev/null +++ b/tools/source_icons/scalable/intent-saturation.file @@ -0,0 +1 @@ +intent-saturation.png,w25,actions diff --git a/tools/source_icons/scalable/intent-saturation.svg b/tools/source_icons/scalable/intent-saturation.svg new file mode 100644 index 000000000..1af08f4f2 --- /dev/null +++ b/tools/source_icons/scalable/intent-saturation.svg @@ -0,0 +1,1362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/softProof.file b/tools/source_icons/scalable/softProof.file new file mode 100644 index 000000000..e275113ec --- /dev/null +++ b/tools/source_icons/scalable/softProof.file @@ -0,0 +1 @@ +softProof.png,w22,actions diff --git a/tools/source_icons/scalable/softProof.svg b/tools/source_icons/scalable/softProof.svg new file mode 100644 index 000000000..d09f316a2 --- /dev/null +++ b/tools/source_icons/scalable/softProof.svg @@ -0,0 +1,1389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + +