diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index d35371458..139584785 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -632,6 +632,7 @@ HISTORY_MSG_403;O - NB - Sensibilité des bords HISTORY_MSG_404;O - NB - Base amplification HISTORY_MSG_405;O - Débruitage - Niveau 4 HISTORY_MSG_406;O - NB - Pixels voisins +HISTORY_MSG_443;Compensation du Point Noir de Sortie HISTORY_NEWSNAPSHOT;Ajouter HISTORY_NEWSNAPSHOT_TOOLTIP;Raccourci: Alt-s HISTORY_SNAPSHOT;Capture @@ -953,6 +954,7 @@ PREFERENCES_MENUGROUPPROFILEOPERATIONS;Opérations sur les profils PREFERENCES_MENUGROUPRANK;Classement PREFERENCES_MENUOPTIONS;Options du menu PREFERENCES_METADATA;Metadonnées +PREFERENCES_MONBPC;Compensation du Point Noir pour la transformation L*a*b*->Moniteur PREFERENCES_MIN;Mini (100x115) PREFERENCES_MULTITAB;Éditeurs multiple PREFERENCES_MULTITABDUALMON;Éditeurs multiple, si possible sur un second moniteur @@ -1082,6 +1084,8 @@ SAVEDLG_SUBSAMP_3;Meilleure qualité SAVEDLG_TIFFUNCOMPRESSED;TIFF non compressé SAVEDLG_WARNFILENAME;Le fichier sera nommé SHCSELECTOR_TOOLTIP;Cliquez le bouton droit de la souris\npour réinitialiser la position de ces 3 curseurs +SOFTPROOF_GAMUTCHECK_TOOLTIP;Si activé, indique en gris les pixels dont la couleurs est en dehors du gamut du profile de sortie +SOFTPROOF_TOOLTIP;Épreuvage écran\nSi activé, simule le rendu généré par le profiles de sortie de l'outil ICM. Particulièrement utile pour simuler le rendu en sortie d'imprimante. THRESHOLDSELECTOR_B;Bas THRESHOLDSELECTOR_BL;Bas-gauche THRESHOLDSELECTOR_BR;Bas-droite @@ -1462,6 +1466,8 @@ TP_ICM_APPLYLOOKTABLE;Table de recherche TP_ICM_APPLYLOOKTABLE_TOOLTIP;Utilise la table de recherche (LUT) contenu dans le profil DCP. Ce réglage n'est possible que si le profil DCP sélectionné en contient une. TP_ICM_BLENDCMSMATRIX;Mélange des hautes lumières\ndu profil ICC avec la matrice TP_ICM_BLENDCMSMATRIX_TOOLTIP;Activer la récupération des zones brûlées lorsque les profils ICC basés sur la LUT sont utilisés +TP_ICM_BPC;Compensation du Point Noir +TP_ICM_BPC_TOOLTIP;Activez ceci pour faire correspondre le canal Luminosité à l'espace couleur de sortie avec un Point Blanc fixe TP_ICM_DCPILLUMINANT;Illuminant TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolé TP_ICM_DCPILLUMINANT_TOOLTIP;Sélectionne quel illuminant DCP inclus utiliser. La valeur par défaut est "Interpolé", qui est un mix entre les 2 profils inclus basé sur la Balance des Blancs choisie. Ce paramètre n'est actif que si un fichier DCP Bi-Illuminant avec support de l'interpolation est choisi. diff --git a/rtdata/languages/default b/rtdata/languages/default index 5998c585d..fa324db86 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -672,6 +672,7 @@ HISTORY_MSG_439;Retinex - Process HISTORY_MSG_440;CbDL - Method HISTORY_MSG_441;Retinex - Gain transmission HISTORY_MSG_442;Retinex - Scale +HISTORY_MSG_443;Output Black Point Compensation HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -998,6 +999,7 @@ PREFERENCES_MENUGROUPRANK;Group "Rank" PREFERENCES_MENUOPTIONS;Context Menu Options PREFERENCES_METADATA;Metadata PREFERENCES_MIN;Mini (100x115) +PREFERENCES_MONBPC;Black Point Compensation for the L*a*b*->Monitor transform PREFERENCES_MONINTENT;Default monitor intent PREFERENCES_MONPROFILE;Default monitor profile PREFERENCES_MULTITAB;Multiple Editor Tabs Mode @@ -1133,6 +1135,8 @@ SAVEDLG_SUBSAMP_TOOLTIP;Best compression:\nJ:a:b 4:2:0\nh/v 2/2\nChroma halved h SAVEDLG_TIFFUNCOMPRESSED;Uncompressed TIFF SAVEDLG_WARNFILENAME;File will be named SHCSELECTOR_TOOLTIP;Click right mouse button to reset the position of those 3 sliders. +SOFTPROOF_GAMUTCHECK_TOOLTIP;If active, indicates in grey the pixels which have out of gamut colors from the output profile. +SOFTPROOF_TOOLTIP;Soft-proofing\nIf active, let you simulate de rendering generated by the output profile of the ICM tool. Most useful for simulating printing outputs. THRESHOLDSELECTOR_B;Bottom THRESHOLDSELECTOR_BL;Bottom-left THRESHOLDSELECTOR_BR;Bottom-right @@ -1519,6 +1523,8 @@ TP_ICM_APPLYLOOKTABLE;Look table TP_ICM_APPLYLOOKTABLE_TOOLTIP;Employ the embedded DCP look table. The setting is only enabled if the selected DCP has one. TP_ICM_BLENDCMSMATRIX;Blend ICC highlights with matrix TP_ICM_BLENDCMSMATRIX_TOOLTIP;Enable to recover clipped highlights when using LUT-based ICC profiles. +TP_ICM_BPC;Black Point Compensation +TP_ICM_BPC_TOOLTIP;Enable this to fit the Luminosity channel to the output color space with a fix White Point TP_ICM_DCPILLUMINANT;Illuminant TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolated TP_ICM_DCPILLUMINANT_TOOLTIP;Select which embedded DCP illuminant to employ. Default is "interpolated" which is a mix between the two based on white balance. The setting is only enabled if a Dual-Illuminant DCP with interpolation support is selected. diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 577a3f4a6..129f44de8 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -989,24 +989,14 @@ void Crop::update (int todo) // all pipette buffer processing should be finished now PipetteBuffer::setReady(); - // switch back to rgb + // Computing the preview image, i.e. converting from lab->Monitor color space (soft-proofing disabled) or lab->Output profile->Monitor color space (soft-proofing enabled) parent->ipf.lab2monitorRgb (labnCrop, cropImg); if (cropImageListener) { - // this in output space held in parallel to allow analysis like shadow/highlight - Glib::ustring outProfile = params.icm.output; - Glib::ustring workProfile = params.icm.working; - Image8 *cropImgtrue; + // Computing the internal image for analysis, i.e. conversion from lab->Output profile (rtSettings.HistogramWorking disabled) or lab->WCS (rtSettings.HistogramWorking enabled) - if(settings->HistogramWorking) { - 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, params.icm.outputIntent, false); - } + // internal image in output color space for analysis + Image8 *cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, params.icm); int finalW = rqcropw; diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index f1230bf01..450c659f0 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -44,7 +44,7 @@ protected: Imagefloat* origCrop; // "one chunk" allocation LabImage* laboCrop; // "one chunk" allocation LabImage* labnCrop; // "one chunk" allocation - Image8* cropImg; // "one chunk" allocation + Image8* cropImg; // "one chunk" allocation ; displayed image in monitor color space, showing the output profile as well (soft-proofing enabled, which then correspond to workimg) or not float * cbuf_real; // "one chunk" allocation SHMap* cshmap; // per line allocation diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 82f280e54..14b5dbc3c 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -32,12 +32,13 @@ #include "../rtgui/options.h" -namespace +namespace rtengine { +extern const Settings* settings; void loadProfiles (const Glib::ustring& dirName, std::map* profiles, - std::map* profileContents, + std::map* profileContents, std::map* profileNames, bool nameUpper, bool onlyRgb) { @@ -76,7 +77,7 @@ void loadProfiles (const Glib::ustring& dirName, } if (profiles) { - const rtengine::ProfileContent content (filePath); + const ProfileContent content (filePath); const cmsHPROFILE profile = content.toProfile (); if (profile && (!onlyRgb || cmsGetColorSpace (profile) == cmsSigRgbData)) { @@ -121,7 +122,7 @@ inline std::uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number di 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"); + return ICCStore::createFromMatrix (mat, false, "XYZ"); } const double (*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best, xyz_rec2020}; @@ -362,6 +363,333 @@ cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const } } +void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, double *ga) +{ + const double eps = 0.000000001; // not divide by zero + if (!icm.freegamma) {//if Free gamma not selected + // gamma : ga[0],ga[1],ga[2],ga[3],ga[4],ga[5] by calcul + if(icm.gamma == "BT709_g2.2_s4.5") { + ga[0] = 2.22; //BT709 2.2 4.5 - my preferred as D.Coffin + ga[1] = 0.909995; + ga[2] = 0.090005; + ga[3] = 0.222222; + ga[4] = 0.081071; + ga[5] = 0.0; + } else if (icm.gamma == "sRGB_g2.4_s12.92") { + ga[0] = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom + ga[1] = 0.947858; + ga[2] = 0.052142; + ga[3] = 0.077399; + ga[4] = 0.039293; + ga[5] = 0.0; + } else if (icm.gamma == "High_g1.3_s3.35") { + ga[0] = 1.3 ; //for high dynamic images + ga[1] = 0.998279; + ga[2] = 0.001721; + ga[3] = 0.298507; + ga[4] = 0.005746; + ga[5] = 0.0; + } else if (icm.gamma == "Low_g2.6_s6.9") { + ga[0] = 2.6 ; //gamma 2.6 variable : for low contrast images + ga[1] = 0.891161; + ga[2] = 0.108839; + ga[3] = 0.144928; + ga[4] = 0.076332; + ga[5] = 0.0; + } else if (icm.gamma == "linear_g1.0") { + ga[0] = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 0.; + ga[5] = 0.0; + } else if (icm.gamma == "standard_g2.2") { + ga[0] = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 0.; + ga[5] = 0.0; + } else if (icm.gamma == "standard_g1.8") { + ga[0] = 1.8; //gamma=1.8 (as gamma of Prophoto) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 0.; + ga[5] = 0.0; + } + } else { //free gamma selected + double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; //gamma parameters + double pwr = 1.0 / icm.gampos; + double ts = icm.slpos; + double slope = icm.slpos == 0 ? eps : icm.slpos; + + int mode = 0, imax = 0; + Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 + ga[4] = g_a3 * ts; + //printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); + ga[0] = icm.gampos; + ga[1] = 1. / (1.0 + g_a4); + ga[2] = g_a4 / (1.0 + g_a4); + ga[3] = 1. / slope; + ga[5] = 0.0; + //printf("ga[0]=%f ga[1]=%f ga[2]=%f ga[3]=%f ga[4]=%f\n", ga[0],ga[1],ga[2],ga[3],ga[4]); + } +} + +cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParams &icm, double ga[]) { + float p1, p2, p3, p4, p5, p6; //primaries + ga[6] = 0.0; + int mode = 0, imax = 0; + + int t50; + int select_temp = 1; //5003K + + //primaries for 7 working profiles ==> output profiles + // eventually to adapt primaries if RT used special profiles ! + if (icm.output == "WideGamut") { + p1 = 0.7350; //Widegamut primaries + p2 = 0.2650; + p3 = 0.1150; + p4 = 0.8260; + p5 = 0.1570; + p6 = 0.0180; + select_temp = 1; + } else if (icm.output == "Adobe RGB") { + p1 = 0.6400; //Adobe primaries + p2 = 0.3300; + p3 = 0.2100; + p4 = 0.7100; + p5 = 0.1500; + p6 = 0.0600; + select_temp = 2; + } else if (icm.output == "sRGB") { + p1 = 0.6400; // sRGB primaries + p2 = 0.3300; + p3 = 0.3000; + p4 = 0.6000; + p5 = 0.1500; + p6 = 0.0600; + select_temp = 2; + } else if (icm.output == "BruceRGB") { + p1 = 0.6400; // Bruce primaries + p2 = 0.3300; + p3 = 0.2800; + p4 = 0.6500; + p5 = 0.1500; + p6 = 0.0600; + select_temp = 2; + } else if (icm.output == "Beta RGB") { + p1 = 0.6888; // Beta primaries + p2 = 0.3112; + p3 = 0.1986; + p4 = 0.7551; + p5 = 0.1265; + p6 = 0.0352; + select_temp = 1; + } else if (icm.output == "BestRGB") { + p1 = 0.7347; // Best primaries + p2 = 0.2653; + p3 = 0.2150; + p4 = 0.7750; + p5 = 0.1300; + p6 = 0.0350; + select_temp = 1; + } else if (icm.output == "Rec2020") { + p1 = 0.7080; // Rec2020 primaries + p2 = 0.2920; + p3 = 0.1700; + p4 = 0.7970; + p5 = 0.1310; + p6 = 0.0460; + select_temp = 2; + } else { + p1 = 0.7347; //ProPhoto and default primaries + p2 = 0.2653; + p3 = 0.1596; + p4 = 0.8404; + p5 = 0.0366; + p6 = 0.0001; + select_temp = 1; + } + + if(select_temp == 1) { + t50 = 5003; // for Widegamut, Prophoto Best, Beta -> D50 + } else if (select_temp == 2) { + t50 = 6504; // for sRGB, AdobeRGB, Bruce Rec2020 -> D65 + } + + cmsCIExyY xyD; + cmsCIExyYTRIPLE Primaries = { + {p1, p2, 1.0}, // red + {p3, p4, 1.0}, // green + {p5, p6, 1.0} // blue + }; + cmsToneCurve* GammaTRC[3]; + cmsFloat64Number Parameters[7]; // 7 parameters for smoother curves + Parameters[0] = ga[0]; + Parameters[1] = ga[1]; + Parameters[2] = ga[2]; + Parameters[3] = ga[3]; + Parameters[4] = ga[4]; + Parameters[5] = ga[5]; + Parameters[6] = ga[6]; + + cmsWhitePointFromTemp(&xyD, t50); + GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters);//5 = more smoother than 4 + cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile + + cmsFreeToneCurve(GammaTRC[0]); + + return oprofdef; +} + +cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, double ga[]) { + bool pro = false; + Glib::ustring outProfile; + cmsHPROFILE outputProfile = NULL; + + if (icm.freegamma && icm.gampos < 1.35) { + pro = true; //select profil with gammaTRC modified : + } else if (icm.gamma == "linear_g1.0" || (icm.gamma == "High_g1.3_s3.35")) { + pro = true; //pro=0 RT_sRGB || Prophoto + } + + // Check that output profiles exist, otherwise use LCMS2 + // Use the icc/icm profiles associated to possible working profiles, set in "options" + if (icm.working == "ProPhoto" && iccStore->outputProfileExist(options.rtSettings.prophoto) && !pro) { + outProfile = options.rtSettings.prophoto; + } else if (icm.working == "Adobe RGB" && iccStore->outputProfileExist(options.rtSettings.adobe) ) { + outProfile = options.rtSettings.adobe; + } else if (icm.working == "WideGamut" && iccStore->outputProfileExist(options.rtSettings.widegamut) ) { + outProfile = options.rtSettings.widegamut; + } else if (icm.working == "Beta RGB" && iccStore->outputProfileExist(options.rtSettings.beta) ) { + outProfile = options.rtSettings.beta; + } else if (icm.working == "BestRGB" && iccStore->outputProfileExist(options.rtSettings.best) ) { + outProfile = options.rtSettings.best; + } else if (icm.working == "BruceRGB" && iccStore->outputProfileExist(options.rtSettings.bruce) ) { + outProfile = options.rtSettings.bruce; + } else if (icm.working == "sRGB" && iccStore->outputProfileExist(options.rtSettings.srgb) && !pro) { + outProfile = options.rtSettings.srgb; + } else if (icm.working == "sRGB" && iccStore->outputProfileExist(options.rtSettings.srgb10) && pro) { + outProfile = options.rtSettings.srgb10; + } else if (icm.working == "ProPhoto" && iccStore->outputProfileExist(options.rtSettings.prophoto10) && pro) { + outProfile = options.rtSettings.prophoto10; + } else if (icm.working == "Rec2020" && iccStore->outputProfileExist(options.rtSettings.rec2020) ) { + outProfile = options.rtSettings.rec2020; + } else { + // Should not occurs + if (settings->verbose) { + printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", icm.working.c_str() ); + } + + return NULL; + } + + //begin adaptation rTRC gTRC bTRC + //"outputProfile" profile has the same characteristics than RGB values, but TRC are adapted... for applying profile + if (settings->verbose) { + printf("Output Gamma - profile: \"%s\"\n", outProfile.c_str() ); //c_str() + } + + outputProfile = iccStore->getProfile(outProfile); //get output profile + + if (outputProfile == NULL) { + + if (settings->verbose) { + printf("\"%s\" ICC output profile not found!\n", outProfile.c_str()); + } + return NULL; + } + + // 7 parameters for smoother curves + cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] }; + + //change desc Tag , to "free gamma", or "BT709", etc. + cmsMLU *mlu; + cmsContext ContextID = cmsGetProfileContextID(outputProfile); // create context to modify some TAGs + mlu = cmsMLUalloc(ContextID, 1); + + // instruction with //ICC are used to generate ICC profile + if (mlu == NULL) { + printf("Description error\n"); + } else { + + // Description TAG : selection of gamma and Primaries + if (!icm.freegamma) { + std::wstring gammaStr; + + if(icm.gamma == "High_g1.3_s3.35") { + gammaStr = std::wstring(L"GammaTRC: High g=1.3 s=3.35"); + } else if (icm.gamma == "Low_g2.6_s6.9") { + gammaStr = std::wstring(L"GammaTRC: Low g=2.6 s=6.9"); + } else if (icm.gamma == "sRGB_g2.4_s12.92") { + gammaStr = std::wstring(L"GammaTRC: sRGB g=2.4 s=12.92"); + } else if (icm.gamma == "BT709_g2.2_s4.5") { + gammaStr = std::wstring(L"GammaTRC: BT709 g=2.2 s=4.5"); + } else if (icm.gamma == "linear_g1.0") { + gammaStr = std::wstring(L"GammaTRC: Linear g=1.0"); + } else if (icm.gamma == "standard_g2.2") { + gammaStr = std::wstring(L"GammaTRC: g=2.2"); + } else if (icm.gamma == "standard_g1.8") { + gammaStr = std::wstring(L"GammaTRC: g=1.8"); + } + + cmsMLUsetWide(mlu, "en", "US", gammaStr.c_str()); + } else { + // create description with gamma + slope + primaries + std::wostringstream gammaWs; + gammaWs.precision(2); + gammaWs << "Manual GammaTRC: g=" << (float)icm.gampos << " s=" << (float)icm.slpos; + + cmsMLUsetWide(mlu, "en", "US", gammaWs.str().c_str()); + } + + cmsWriteTag(outputProfile, cmsSigProfileDescriptionTag, mlu);//desc changed + + /* + cmsMLUsetWide(mlu, "en", "US", L"General Public License - AdobeRGB compatible");//adapt to profil + cmsWriteTag(outputProfile, cmsSigCopyrightTag, mlu); + + cmsMLUsetWide(mlu, "en", "US", L"RawTherapee"); + cmsWriteTag(outputProfile, cmsSigDeviceMfgDescTag, mlu); + + cmsMLUsetWide(mlu, "en", "US", L"RTMedium"); //adapt to profil + cmsWriteTag(outputProfile, cmsSigDeviceModelDescTag, mlu); + + */ + + cmsMLUfree (mlu); + } + + // Calculate output profile's rTRC gTRC bTRC + cmsToneCurve* GammaTRC = NULL; + GammaTRC = cmsBuildParametricToneCurve(NULL, 5, Parameters); + cmsWriteTag(outputProfile, cmsSigRedTRCTag, (void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigGreenTRCTag, (void*)GammaTRC ); + cmsWriteTag(outputProfile, cmsSigBlueTRCTag, (void*)GammaTRC ); + + if (GammaTRC) { + cmsFreeToneCurve(GammaTRC); + } + + return outputProfile; +} + +bool ICCStore::outputProfileExist (const Glib::ustring& name) const +{ + + MyMutex::MyLock lock(mutex_); + + const ProfileMap::const_iterator r = fileProfiles.find (name); + + if (r != fileProfiles.end ()) { + return true; + } + + return false; +} + cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const { diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 8b6e6465c..6aa30033e 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include "procparams.h" #include "../rtgui/threadutils.h" namespace rtengine @@ -85,8 +87,11 @@ public: void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir); + static void getGammaArray(const procparams::ColorManagementParams &icm, double ga[]); // ga must be an array of double with 6 elements static cmsHPROFILE makeStdGammaProfile (cmsHPROFILE iprof); static cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); + static cmsHPROFILE createGammaProfile (const procparams::ColorManagementParams &icm, double ga[]); + static cmsHPROFILE createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, double ga[]); // Main monitors standard profile name, from OS void findDefaultMonitorProfile (); @@ -98,9 +103,10 @@ public: TMatrix workingSpaceMatrix (const Glib::ustring& name) const; TMatrix workingSpaceInverseMatrix (const Glib::ustring& name) const; - cmsHPROFILE getProfile (const Glib::ustring& name) const; - cmsHPROFILE getStdProfile (const Glib::ustring& name) const; - ProfileContent getContent (const Glib::ustring& name) const; + bool outputProfileExist (const Glib::ustring& name) const; + 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; diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 937e2d19d..d57bcf6a9 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -326,17 +326,16 @@ Image16::tofloat() } // Parallized transformation; create transform with cmsFLAGS_NOCACHE! -void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform) +void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage) { - //cmsDoTransform(hTransform, data, data, planestride); - - // LittleCMS cannot parallelize planar setups -- Hombre: LCMS2.4 can! But it we use this new feature, memory allocation have to be modified too + // LittleCMS cannot parallelize planar Lab float images // so build temporary buffers to allow multi processor execution #ifdef _OPENMP #pragma omp parallel #endif { - AlignedBuffer buffer(width * 3); + AlignedBuffer bufferLab(width * 3); + AlignedBuffer bufferRGB(width * 3); #ifdef _OPENMP #pragma omp for schedule(static) @@ -344,25 +343,31 @@ void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform) for (int y = 0; y < height; y++) { - unsigned short *p = buffer.data, *pR = r(y), *pG = g(y), *pB = b(y); + unsigned short *pRGB, *pR, *pG, *pB; + float *pLab, *pL, *pa, *pb; + + pLab= bufferLab.data; + pL = labImage.L[y]; + pa = labImage.a[y]; + pb = labImage.b[y]; for (int x = 0; x < width; x++) { - *(p++) = *(pR++); - *(p++) = *(pG++); - *(p++) = *(pB++); + *(pLab++) = *(pL++) / 327.68f; + *(pLab++) = *(pa++) / 327.68f; + *(pLab++) = *(pb++) / 327.68f; } - cmsDoTransform (hTransform, buffer.data, buffer.data, width); + cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width); - p = buffer.data; + pRGB = bufferRGB.data; pR = r(y); pG = g(y); pB = b(y); for (int x = 0; x < width; x++) { - *(pR++) = *(p++); - *(pG++) = *(p++); - *(pB++) = *(p++); + *(pR++) = *(pRGB++); + *(pG++) = *(pRGB++); + *(pB++) = *(pRGB++); } } // End of parallelization } diff --git a/rtengine/image16.h b/rtengine/image16.h index 0e1ac6786..7fcff307f 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -96,7 +96,7 @@ public: delete this; } - void ExecCMSTransform(cmsHTRANSFORM hTransform); + void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage); }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f585acacf..5ba2dc5e1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -33,9 +33,9 @@ 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), monitorIntent(RI_RELATIVE), scale(10), - highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), - bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(0.), + ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), monitorIntent(RI_RELATIVE), + softProof(false), gamutCheck(false), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), + allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(0.), hltonecurve(65536), shtonecurve(65536), @@ -774,7 +774,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) // Update the monitor color transform if necessary if (todo & M_MONITOR) { - ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent); + ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent, softProof, gamutCheck); } // process crop, if needed @@ -794,20 +794,12 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) MyMutex::MyLock prevImgLock(previmg->getMutex()); try { + // Computing the preview image, i.e. converting from WCS->Monitor color space (soft-proofing disabled) or WCS->Output profile->Monitor color space (soft-proofing enabled) ipf.lab2monitorRgb (nprevl, previmg); + + // Computing the internal image for analysis, i.e. conversion from WCS->Output profile delete workimg; - Glib::ustring outProfile = params.icm.output; - - if(settings->HistogramWorking) { - Glib::ustring workProfile = params.icm.working; - 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.empty() || params.icm.output == ColorManagementParams::NoICMString) { - outProfile = "sRGB"; - } - - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, outProfile, params.icm.outputIntent, false); - } + workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, params.icm); } catch(char * str) { progress ("Error converting file...", 0); return; @@ -1134,6 +1126,18 @@ void ImProcCoordinator::getMonitorProfile (Glib::ustring& profile, RenderingInte intent = monitorIntent; } +void ImProcCoordinator::setSoftProofing (bool softProof, bool gamutCheck) +{ + this->softProof = softProof; + this->gamutCheck = gamutCheck; +} + +void ImProcCoordinator::getSoftProofing (bool &softProof, bool &gamutCheck) +{ + softProof = this->softProof; + gamutCheck = this->gamutCheck; +} + void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname, bool apply_wb) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 4f1a6a691..3c4164254 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -57,8 +57,8 @@ protected: Imagefloat *oprevi; LabImage *oprevl; LabImage *nprevl; - Image8 *previmg; - Image8 *workimg; + Image8 *previmg; // displayed image in monitor color space, showing the output profile as well (soft-proofing enabled, which then correspond to workimg) or not + Image8 *workimg; // internal image in output color space for analysis CieImage *ncie; ImageSource* imgsrc; @@ -73,8 +73,9 @@ protected: ImProcFunctions ipf; Glib::ustring monitorProfile; - RenderingIntent monitorIntent; + bool softProof; + bool gamutCheck; int scale; bool highDetailPreprocessComputed; @@ -254,6 +255,8 @@ public: void setMonitorProfile (const Glib::ustring& profile, RenderingIntent intent); void getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const; + void setSoftProofing (bool softProof, bool gamutCheck); + void getSoftProofing (bool &softProof, bool &gamutCheck); bool updateTryLock () { diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 5730befbb..c511bf513 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -61,14 +61,6 @@ ImProcFunctions::~ImProcFunctions () if (monitorTransform) { cmsDeleteTransform (monitorTransform); } - - if (output2monitorTransform) { - cmsDeleteTransform (output2monitorTransform); - } - - if (lab2outputTransform) { - cmsDeleteTransform (lab2outputTransform); - } } void ImProcFunctions::setScale (double iscale) @@ -76,24 +68,14 @@ void ImProcFunctions::setScale (double iscale) scale = iscale; } -void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent) +void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck) { // set up monitor transform if (monitorTransform) { cmsDeleteTransform (monitorTransform); } - if (output2monitorTransform) { - cmsDeleteTransform (output2monitorTransform); - } - - if (lab2outputTransform) { - cmsDeleteTransform (lab2outputTransform); - } - monitorTransform = nullptr; - output2monitorTransform = nullptr; - lab2outputTransform = nullptr; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB @@ -101,20 +83,60 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con if (monitor) { MyMutex::MyLock lcmsLock (*lcmsMutex); + + cmsUInt32Number flags; cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); - 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; + bool softProofCreated = false; - 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, icm.outputIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); - output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); + if (softProof) { + cmsHPROFILE oprof; + if(icm.gamma != "default" || icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 + double ga[7]; + iccStore->getGammaArray(icm, ga); + oprof = iccStore->createGammaProfile (icm, ga); + printf("ImProcFunctions::updateColorProfiles / iccStore->createGammaProfile (icm, ga);\n"); } + else if (!icm.output.empty() && icm.output != ColorManagementParams::NoICMString) { + if(icm.gamma != "default" || icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 + double ga[7]; + iccStore->getGammaArray(icm, ga); + oprof = iccStore->createCustomGammaOutputProfile (icm, ga); + printf("ImProcFunctions::updateColorProfiles / iccStore->createCustomGammaOutputProfile (icm, ga);\n"); + } else { + oprof = iccStore->getProfile(icm.output); + printf("ImProcFunctions::updateColorProfiles / iccStore->getProfile(%s);\n", icm.output.c_str()); + } + } + + if (oprof) { + // NOCACHE is for thread safety, NOOPTIMIZE for precision + flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + if (gamutCheck) { + flags |= cmsFLAGS_GAMUTCHECK; + } + monitorTransform = cmsCreateProofingTransform( + iprof, TYPE_Lab_FLT, + monitor, TYPE_RGB_8, + oprof, + monitorIntent, icm.outputIntent, + flags + ); + if (monitorTransform) { + softProofCreated = true; + } + } + } + + if (!softProofCreated) { + flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (settings->monitorBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, flags); } cmsCloseProfile(iprof); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 3523ee183..559456c32 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -223,7 +223,7 @@ public: bool needsPCVignetting (); void firstAnalysis (const Imagefloat* const working, const ProcParams ¶ms, LUTu & vhist16); - void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent); + void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, 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, const DCPProfile::ApplyState &asIn ); @@ -361,9 +361,8 @@ 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, 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 + Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, double *ga=NULL); // 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 489ca60bc..ee3b35350 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -32,6 +32,12 @@ namespace rtengine extern const Settings* settings; +// Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc) +// Crop::update (rtengine/dcrop.cc) +// Thumbnail::processImage (rtengine/rtthumbnail.cc) +// +// If monitorTransform, divide by 327.68 then apply monitorTransform (which can integrate soft-proofing) +// otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) { if (monitorTransform) { @@ -61,21 +67,13 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) float* ra = lab->a[i]; float* rb = lab->b[i]; - float fy, fx, fz, x_, y_, z_, LL; - for (int j = 0; j < W; j++) { buffer[iy++] = rL[j] / 327.68f; buffer[iy++] = ra[j] / 327.68f; buffer[iy++] = rb[j] / 327.68f; } - if (!settings->HistogramWorking && output2monitorTransform && lab2outputTransform) { - AlignedBuffer buf(3 * W); - cmsDoTransform (lab2outputTransform, buffer, buf.data, W); - cmsDoTransform (output2monitorTransform, buf.data, data + ix, W); - } else { - cmsDoTransform (monitorTransform, buffer, data + ix, W); - } + cmsDoTransform (monitorTransform, buffer, data + ix, W); } } // End of parallelization @@ -111,7 +109,7 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) x_ = 65535.0 * Color::f2xyz(fx) * Color::D50x; // y_ = 65535.0 * Color::f2xyz(fy); z_ = 65535.0 * Color::f2xyz(fz) * Color::D50z; - y_ = (LL > Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * LL / Color::kappa; + y_ = (LL > (float)Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * LL / (float)Color::kappa; Color::xyz2srgb(x_, y_, z_, R, G, B); @@ -125,7 +123,16 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) } } -Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma) + + +// Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc) +// Crop::update (rtengine/dcrop.cc) +// +// Generate an Image8 +// +// If output profile used, divide by 327.68 then apply the "profile" profile (eventually with a standard gamma) +// otherwise divide by 327.68, convert to xyz and apply the RGB transform, before converting with gamma2curve +Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm) { //gamutmap(lab); @@ -146,9 +153,22 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, } Image8* image = new Image8 (cw, ch); - + Glib::ustring profile; cmsHPROFILE oprof = iccStore->getProfile (profile); + bool standard_gamma; + + if(settings->HistogramWorking) { + profile = icm.working; + standard_gamma = true; + } else { + profile = icm.output; + if (icm.output.empty() || icm.output == ColorManagementParams::NoICMString) { + profile = "sRGB"; + } + standard_gamma = false; + } + if (oprof) { cmsHPROFILE oprofG = oprof; @@ -156,11 +176,16 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, oprofG = ICCStore::makeStdGammaProfile(oprof); } + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + printf("lab2rgb / bpc=true\n"); + } + else printf("lab2rgb / bpc=false\n"); lcmsMutex->lock (); - cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); - cmsHTRANSFORM hTransform = cmsCreateTransform (hLab, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, intent, - cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety - cmsCloseProfile(hLab); + cmsHPROFILE LabIProf = cmsCreateLab4Profile(NULL); + cmsHTRANSFORM hTransform = cmsCreateTransform (LabIProf, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, icm.outputIntent, flags); // NOCACHE is important for thread safety + cmsCloseProfile(LabIProf); lcmsMutex->unlock (); unsigned char *data = image->data; @@ -213,33 +238,49 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, float* rL = lab->L[i]; float* ra = lab->a[i]; float* rb = lab->b[i]; - int ix = 3 * i * cw; + uint8_t* dest = image->r(i - cy) + cx; for (int j = cx; j < cx + cw; j++) { - float fy = (0.00862069 * rL[j]) / 327.68 + 0.137932; // (L+16)/116 - float fx = (0.002 * ra[j]) / 327.68 + fy; - float fz = fy - (0.005 * rb[j]) / 327.68; - float LL = rL[j] / 327.68; + float fy = (0.0086206897f * (*rL)) / 327.68f + 0.1379310345f; // (L+16)/116 + float fx = (0.002f * *(ra++)) / 327.68f + fy; + float fz = fy - (0.005f * *(rb++)) / 327.68f; + float LL = *(rL++) / 327.68f; - float x_ = 65535.0 * Color::f2xyz(fx) * Color::D50x; - //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0 * Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * LL / Color::kappa; + float x_ = 65535.0f * Color::f2xyz(fx) * Color::D50x; + //float y_ = 65535.0f * Color::f2xyz(fy); + float z_ = 65535.0f * Color::f2xyz(fz) * Color::D50z; + float y_ = (LL > (float)Color::epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / (float)Color::kappa; Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb); - image->data[ix++] = (int)Color::gamma2curve[R] >> 8; - image->data[ix++] = (int)Color::gamma2curve[G] >> 8; - image->data[ix++] = (int)Color::gamma2curve[B] >> 8; + *(dest++) = (int)Color::gamma2curve[CLIP(R)] >> 8; + *(dest++) = (int)Color::gamma2curve[CLIP(G)] >> 8; + *(dest++) = (int)Color::gamma2curve[CLIP(B)] >> 8; } } } return image; } -// for default (not gamma) -Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw) + + +/** @brief Convert the final Lab image to the output RGB color space + * + * Used in processImage (rtengine/simpleprocess.cc) + * + * Provide a pointer to a 7 floats array for "ga" (uninitialized ; this array will be filled with the gamma values) if you want + * to use the custom gamma scenario. Thoses gamma values will correspond to the ones of the chosen standard output profile + * (Prophoto if non standard output profile given) + * + * If "ga" is NULL, then we're considering standard gamma with the chosen output profile. + * + * Generate an Image16 + * + * If a custom gamma profile can be created, divide by 327.68, convert to xyz and apply the custom gamma transform + * otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve + */ +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, double *ga) { //gamutmap(lab); @@ -261,357 +302,120 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int } Image16* image = new Image16 (cw, ch); - cmsHPROFILE oprof = iccStore->getProfile (profile); - + cmsHPROFILE oprof = NULL; + if (ga) { + iccStore->getGammaArray(icm, ga); + oprof = iccStore->createGammaProfile(icm, ga); + printf("iccStore->createGammaProfile(icm, ga);\n"); + } else { + oprof = iccStore->getProfile (icm.output); + printf("iccStore->getProfile (%s);\n", icm.output.c_str()); + } if (oprof) { - #pragma omp parallel for if (multiThread) + + + /* + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif for (int i = cy; i < cy + ch; i++) { float* rL = lab->L[i]; float* ra = lab->a[i]; float* rb = lab->b[i]; - short* xa = (short*)image->r(i - cy); - short* ya = (short*)image->g(i - cy); - short* za = (short*)image->b(i - cy); + short* xa = (short*)image->r(i - cy) + cx; + short* ya = (short*)image->g(i - cy) + cx; + short* za = (short*)image->b(i - cy) + cx; - for (int j = cx; j < cx + cw; j++) { + for (int j = 0; j < cw; j++) { - float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116 - float fx = (0.002 * ra[j]) / 327.68f + fy; - float fz = fy - (0.005f * rb[j]) / 327.68f; - float LL = rL[j] / 327.68f; + float fy = (0.0086206897f * *rL) / 327.68f + 0.1379310345f; // (L+16)/116 + float fx = (0.002f * *(ra++)) / 327.68f + fy; + float fz = fy - (0.005f * *(rb++)) / 327.68f; + float LL = *(rL++) / 327.68f; - float x_ = 65535.0f * (float) Color::f2xyz(fx) * Color::D50x; - //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0f * (float) Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / Color::kappa; + float x_ = 65535.0f * Color::f2xyz(fx) * Color::D50x; + //float y_ = 65535.0f * Color::f2xyz(fy); + float z_ = 65535.0f * Color::f2xyz(fz) * Color::D50z; + float y_ = (LL > (float)Color::epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / (float)Color::kappa; - xa[j - cx] = CLIP((int) round(x_)); - ya[j - cx] = CLIP((int) round(y_)); - za[j - cx] = CLIP((int) round(z_)); - - if(bw && y_ < 65535.f ) { //force Bw value and take highlight into account - xa[j - cx] = (int) round(y_ * Color::D50x ); - za[j - cx] = (int) round(y_ * Color::D50z); - } - - } - } - - cmsHPROFILE iprof = iccStore->getXYZProfile (); - lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); - lcmsMutex->unlock (); - - image->ExecCMSTransform(hTransform); - - cmsDeleteTransform(hTransform); - } else { - #pragma omp parallel for if (multiThread) - - for (int i = cy; i < cy + ch; i++) { - float R, G, B; - float* rL = lab->L[i]; - float* ra = lab->a[i]; - float* rb = lab->b[i]; - - for (int j = cx; j < cx + cw; j++) { - - float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116 - float fx = (0.002f * ra[j]) / 327.68f + fy; - float fz = fy - (0.005f * rb[j]) / 327.68f; - float LL = rL[j] / 327.68f; - - float x_ = 65535.0f * (float) Color::f2xyz(fx) * Color::D50x; - //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0f * (float) Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? (float) 65535.0f * fy * fy * fy : 65535.0f * LL / Color::kappa; - - Color::xyz2srgb(x_, y_, z_, R, G, B); - - image->r(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(R)]; - image->g(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(G)]; - image->b(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(B)]; - } - } - } - - return image; -} - - -// for gamma options (BT709...sRGB linear...) -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); - - if (cx < 0) { - cx = 0; - } - - if (cy < 0) { - cy = 0; - } - - if (cx + cw > lab->W) { - cw = lab->W - cx; - } - - if (cy + ch > lab->H) { - ch = lab->H - cy; - } - - Image16* image = new Image16 (cw, ch); - float p1, p2, p3, p4, p5, p6; //primaries - - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; //gamma parameters - double pwr; - double ts; - ga6 = 0.0; - pwr = 1.0 / gampos; - ts = slpos; - int mode = 0, imax = 0; - - int t50; - int select_temp = 1; //5003K - const double eps = 0.000000001; // not divide by zero - - //primaries for 7 working profiles ==> output profiles - // eventually to adapt primaries if RT used special profiles ! - if (profi == "WideGamut") { - p1 = 0.7350; //Widegamut primaries - p2 = 0.2650; - p3 = 0.1150; - p4 = 0.8260; - p5 = 0.1570; - p6 = 0.0180; - select_temp = 1; - } else if (profi == "Adobe RGB") { - p1 = 0.6400; //Adobe primaries - p2 = 0.3300; - p3 = 0.2100; - p4 = 0.7100; - p5 = 0.1500; - p6 = 0.0600; - select_temp = 2; - } else if (profi == "sRGB") { - p1 = 0.6400; // sRGB primaries - p2 = 0.3300; - p3 = 0.3000; - p4 = 0.6000; - p5 = 0.1500; - p6 = 0.0600; - select_temp = 2; - } else if (profi == "BruceRGB") { - p1 = 0.6400; // Bruce primaries - p2 = 0.3300; - p3 = 0.2800; - p4 = 0.6500; - p5 = 0.1500; - p6 = 0.0600; - select_temp = 2; - } else if (profi == "Beta RGB") { - p1 = 0.6888; // Beta primaries - p2 = 0.3112; - p3 = 0.1986; - p4 = 0.7551; - p5 = 0.1265; - p6 = 0.0352; - select_temp = 1; - } else if (profi == "BestRGB") { - p1 = 0.7347; // Best primaries - p2 = 0.2653; - p3 = 0.2150; - p4 = 0.7750; - p5 = 0.1300; - p6 = 0.0350; - select_temp = 1; - } else if (profi == "Rec2020") { - p1 = 0.7080; // Rec2020 primaries - p2 = 0.2920; - p3 = 0.1700; - p4 = 0.7970; - p5 = 0.1310; - p6 = 0.0460; - select_temp = 2; - } else { - p1 = 0.7347; //ProPhoto and default primaries - p2 = 0.2653; - p3 = 0.1596; - p4 = 0.8404; - p5 = 0.0366; - p6 = 0.0001; - select_temp = 1; - } - - if (!freegamma) {//if Free gamma not selected - // gamma : ga0,ga1,ga2,ga3,ga4,ga5 by calcul - if(gam == "BT709_g2.2_s4.5") { - ga0 = 2.22; //BT709 2.2 4.5 - my prefered as D.Coffin - ga1 = 0.909995; - ga2 = 0.090005; - ga3 = 0.222222; - ga4 = 0.081071; - ga5 = 0.0; - } else if (gam == "sRGB_g2.4_s12.92") { - ga0 = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom - ga1 = 0.947858; - ga2 = 0.052142; - ga3 = 0.077399; - ga4 = 0.039293; - ga5 = 0.0; - } else if (gam == "High_g1.3_s3.35") { - ga0 = 1.3 ; //for high dynamic images - ga1 = 0.998279; - ga2 = 0.001721; - ga3 = 0.298507; - ga4 = 0.005746; - ga5 = 0.0; - } else if (gam == "Low_g2.6_s6.9") { - ga0 = 2.6 ; //gamma 2.6 variable : for low contrast images - ga1 = 0.891161; - ga2 = 0.108839; - ga3 = 0.144928; - ga4 = 0.076332; - ga5 = 0.0; - } else if (gam == "linear_g1.0") { - ga0 = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) - ga1 = 1.; - ga2 = 0.; - ga3 = 1. / eps; - ga4 = 0.; - ga5 = 0.0; - } else if (gam == "standard_g2.2") { - ga0 = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) - ga1 = 1.; - ga2 = 0.; - ga3 = 1. / eps; - ga4 = 0.; - ga5 = 0.0; - } else if (gam == "standard_g1.8") { - ga0 = 1.8; //gamma=1.8 (as gamma of Prophoto) - ga1 = 1.; - ga2 = 0.; - ga3 = 1. / eps; - ga4 = 0.; - ga5 = 0.0; - } - } else { //free gamma selected - if(slpos == 0) { - slpos = eps; - } - - Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 - ga4 = g_a3 * ts; - //printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); - ga0 = gampos; - ga1 = 1. / (1.0 + g_a4); - ga2 = g_a4 / (1.0 + g_a4); - ga3 = 1. / slpos; - ga5 = 0.0; - //printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0,ga1,ga2,ga3,ga4); - - } - - if(select_temp == 1) { - t50 = 5003; // for Widegamut, Prophoto Best, Beta D50 - } else if (select_temp == 2) { - t50 = 6504; // for sRGB, AdobeRGB, Bruce Rec2020 D65 - } - - cmsCIExyY xyD; - cmsCIExyYTRIPLE Primaries = {{p1, p2, 1.0},//red primaries - {p3, p4, 1.0}, // green - {p5, p6, 1.0} //blue - }; - cmsToneCurve* GammaTRC[3]; - cmsFloat64Number Parameters[7]; - Parameters[0] = ga0; - Parameters[1] = ga1; - Parameters[2] = ga2; - Parameters[3] = ga3; - Parameters[4] = ga4; - Parameters[5] = ga5; - Parameters[6] = ga6; -// 7 parameters for smoother curves - cmsWhitePointFromTemp(&xyD, t50); - GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters);//5 = more smoother than 4 - cmsHPROFILE oprofdef = cmsCreateRGBProfileTHR(NULL, &xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile - - cmsFreeToneCurve(GammaTRC[0]); - - - if (oprofdef) { - #pragma omp parallel for if (multiThread) - - for (int i = cy; i < cy + ch; i++) { - float* rL = lab->L[i]; - float* ra = lab->a[i]; - float* rb = lab->b[i]; - short* xa = (short*)image->r(i - cy); - short* ya = (short*)image->g(i - cy); - short* za = (short*)image->b(i - cy); - - for (int j = cx; j < cx + cw; j++) { - - float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116 - float fx = (0.002f * ra[j]) / 327.68f + fy; - float fz = fy - (0.005f * rb[j]) / 327.68f; - float LL = rL[j] / 327.68f; - - float x_ = 65535.0f * (float)Color::f2xyz(fx) * Color::D50x; - // float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0f * (float)Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? (float) 65535.0 * fy * fy * fy : 65535.0f * LL / Color::kappa; - - xa[j - cx] = CLIP((int) round(x_)) ; - ya[j - cx] = CLIP((int) round(y_)); - za[j - cx] = CLIP((int) round(z_)); + *xa = CLIP((int) round(x_)) ; + *(ya++) = CLIP((int) round(y_)); + *za = CLIP((int) round(z_)); if(bw && y_ < 65535.f) { //force Bw value and take highlight into account - xa[j - cx] = (int) round(y_ * Color::D50x); - za[j - cx] = (int) round(y_ * Color::D50z); + *xa = (int) round(y_ * Color::D50x); + *za = (int) round(y_ * Color::D50z); } - + ++xa; + ++za; } } cmsHPROFILE iprof = iccStore->getXYZProfile (); + + + */ + + cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); + + + + + // ---------------------------------------------------------------------------- + + + + + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + printf("lab2rgb16 / icm.outputBPC=true / outputIntent=%d\n", icm.outputIntent); + } + else printf("lab2rgb16 / icm.outputBPC=false / outputIntent=%d\n", icm.outputIntent); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + //cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, icm.outputIntent, flags); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_16, icm.outputIntent, flags); lcmsMutex->unlock (); - image->ExecCMSTransform(hTransform); + //image->ExecCMSTransform(hTransform); + image->ExecCMSTransform(hTransform, *lab); cmsDeleteTransform(hTransform); } else { // - #pragma omp parallel for if (multiThread) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif for (int i = cy; i < cy + ch; i++) { float R, G, B; float* rL = lab->L[i]; float* ra = lab->a[i]; float* rb = lab->b[i]; + uint16_t* rR = image->r(i - cy) + cx; + uint16_t* rG = image->g(i - cy) + cx; + uint16_t* rB = image->b(i - cy) + cx; - for (int j = cx; j < cx + cw; j++) { + for (int j = 0; j < cw; j++) { - float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116 - float fx = (0.002f * ra[j]) / 327.68f + fy; - float fz = fy - (0.005f * rb[j]) / 327.68f; - float LL = rL[j] / 327.68f; + float fy = (0.0086206897f * *rL) / 327.68f + 0.1379310345f; // (L+16)/116 + float fx = (0.002f * *(ra++)) / 327.68f + fy; + float fz = fy - (0.005f * *(rb++)) / 327.68f; + float LL = *(rL++) / 327.68f; - float x_ = 65535.0f * (float) Color::f2xyz(fx) * Color::D50x; + float x_ = 65535.0f * Color::f2xyz(fx) * Color::D50x; //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0f * (float) Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? (float) 65535.0 * fy * fy * fy : 65535.0f * LL / Color::kappa; + float z_ = 65535.0f * Color::f2xyz(fz) * Color::D50z; + float y_ = (LL > (float)Color::epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / (float)Color::kappa; Color::xyz2srgb(x_, y_, z_, R, G, B); - image->r(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(R)]; - image->g(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(G)]; - image->b(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(B)]; + *(rR++) = (int)Color::gamma2curve[CLIP(R)]; + *(rG++) = (int)Color::gamma2curve[CLIP(G)]; + *(rB++) = (int)Color::gamma2curve[CLIP(B)]; } } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 62d2a4ac1..52517e527 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -469,6 +469,7 @@ enum ProcEvent { EvcbdlMethod = 439, EvRetinexgaintransmission = 440, EvLskal = 441, + EvOBPCompens = 442, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 70b764da1..a5a2515a5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -927,6 +927,7 @@ void ColorManagementParams::setDefaults() working = "ProPhoto"; output = "RT_sRGB"; outputIntent = RI_RELATIVE; + outputBPC = true; gamma = "default"; gampos = 2.22; slpos = 4.5; @@ -2662,6 +2663,10 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b keyFile.set_string ("Color Management", "OutputProfileIntent", intent); } + if (!pedited || pedited->icm.outputBPC) { + keyFile.set_boolean ("Color Management", "OutputBPC", icm.outputBPC); + } + if (!pedited || pedited->icm.gamma) { keyFile.set_string ("Color Management", "Gammafree", icm.gamma); } @@ -5921,6 +5926,14 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Color Management", "OutputBPC")) { + icm.outputBPC = keyFile.get_boolean ("Color Management", "OutputBPC"); + + if (pedited) { + pedited->icm.gamfree = 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 cf02b9f10..3f0331457 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -967,6 +967,7 @@ public: Glib::ustring working; Glib::ustring output; RenderingIntent outputIntent; + bool outputBPC; static const Glib::ustring NoICMString; Glib::ustring gamma; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 5175836e4..025265e0a 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -119,8 +119,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvDPDNLuma, ALLNORAW, // EvDPDNChroma, ALLNORAW, // EvDPDNGamma, - ALLNORAW, // EvDirPyrEqualizer, - ALLNORAW, // EvDirPyrEqlEnabled, + ALLNORAW, // EvDirPyrEqualizer, + ALLNORAW, // EvDirPyrEqlEnabled, LUMINANCECURVE, // EvLSaturation, LUMINANCECURVE, // EvLaCurve, LUMINANCECURVE, // EvLbCurve, @@ -275,12 +275,12 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvLCLCurve LUMINANCECURVE, // EvLLHCurve LUMINANCECURVE, // EvLHHCurve - ALLNORAW, // EvDirPyrEqualizerThreshold + ALLNORAW, // EvDirPyrEqualizerThreshold ALLNORAW, // EvDPDNenhance RGBCURVE, // EvBWMethodalg - ALLNORAW, // EvDirPyrEqualizerSkin - ALLNORAW, // EvDirPyrEqlgamutlab - ALLNORAW, // EvDirPyrEqualizerHueskin + ALLNORAW, // EvDirPyrEqualizerSkin + ALLNORAW, // EvDirPyrEqlgamutlab + ALLNORAW, // EvDirPyrEqualizerHueskin ALLNORAW, // EvDPDNmedian ALLNORAW, // EvDPDNmedmet RGBCURVE, // EvColorToningEnabled @@ -453,7 +453,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLhighl DEMOSAIC, // EvLbaselog DEMOSAIC, // EvRetinexlhcurve - ALLNORAW, // EvOIntent + OUTPUTPROFILE, // EvOIntent MONITORTRANSFORM, // EvMonitorTransform: no history message RETINEX, // EvLiter RETINEX, // EvLgrad @@ -465,10 +465,11 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLradius RETINEX, // EvmapMethod DEMOSAIC, // EvRetinexmapcurve - DEMOSAIC, // EvviewMethod - ALLNORAW, // EvcbdlMethod + DEMOSAIC, // EvviewMethod + ALLNORAW, // EvcbdlMethod RETINEX, // EvRetinexgaintransmission - RETINEX //EvLskal + RETINEX, // EvLskal + OUTPUTPROFILE // EvOBPCompens }; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 23e179f9f..e262c9394 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -46,7 +46,7 @@ // 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 FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR|M_MONITOR) // 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) @@ -61,7 +61,7 @@ #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 GAMMA M_MONITOR #define CROP M_CROP #define RESIZE M_VOID #define EXIF M_VOID @@ -69,7 +69,7 @@ #define MINUPDATE M_MINUPDATE #define RETINEX (M_RETINEX|ALLNORAW) #define MONITORTRANSFORM M_MONITOR -#define OUTPUTPROFILE (ALLNORAW|MONITORTRANSFORM) +#define OUTPUTPROFILE M_MONITOR extern int refreshmap[]; #endif diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 42e06406e..eeaba48a7 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -418,6 +418,8 @@ public: virtual void setMonitorProfile (const Glib::ustring& monitorProfile, RenderingIntent intent) = 0; virtual void getMonitorProfile (Glib::ustring& monitorProfile, RenderingIntent& intent) const = 0; + virtual void setSoftProofing (bool softProof, bool gamutCheck) = 0; + virtual void getSoftProofing (bool &softProof, bool &gamutCheck) = 0; virtual ~StagedImageProcessor () {} diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index e8c1cd096..5b73b09fb 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -906,7 +906,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ImProcFunctions ipf (¶ms, false); ipf.setScale (sqrt(double(fw * fw + fh * fh)) / sqrt(double(thumbImg->width * thumbImg->width + thumbImg->height * thumbImg->height))*scale); - ipf.updateColorProfiles (params.icm, options.rtSettings.monitorProfile, options.rtSettings.monitorIntent); + ipf.updateColorProfiles (params.icm, options.rtSettings.monitorProfile, options.rtSettings.monitorIntent, false, false); LUTu hist16 (65536); diff --git a/rtengine/settings.h b/rtengine/settings.h index 4053a547f..3c728f061 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -40,6 +40,7 @@ public: Glib::ustring monitorProfile; ///< ICC profile name used for the monitor RenderingIntent monitorIntent; ///< Colorimetric intent used with the above profile + bool monitorBPC; ///< Black Point Compensation for the WCS->Monitor transform (directly, i.e. not soft-proofing) 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 25bf45742..270661a33 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1158,211 +1158,27 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p cmsHPROFILE jprof = NULL; bool customGamma = false; bool useLCMS = false; + bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled && !autili && !butili ; if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 - cmsMLU *DescriptionMLU, *CopyrightMLU, *DmndMLU, *DmddMLU;// for modification TAG - cmsToneCurve* GammaTRC[3] = { NULL, NULL, NULL }; - cmsFloat64Number Parameters[7]; - double ga0, ga1, ga2, ga3, ga4, ga5, ga6; + double ga[7]; // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - 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 ); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, ga); customGamma = true; //or selected Free gamma useLCMS = false; - bool pro = false; - Glib::ustring chpro, outProfile; - bool present_space[10] = {false, false, false, false, false, false, false, false, false, false}; - std::vector opnames = iccStore->getProfiles (); - - //test if files are in system - for (int j = 0; j < 10; j++) { - // one can modify "option" [Color Management] to adapt the profile's name if they are different for windows, MacOS, Linux ?? - // some of them are actually provided by RT, thanks to Jacques Desmis - if (j == 0) { - chpro = options.rtSettings.prophoto; - } else if(j == 1) { - chpro = options.rtSettings.adobe; - } else if(j == 2) { - chpro = options.rtSettings.widegamut; - } else if(j == 3) { - chpro = options.rtSettings.beta; - } else if(j == 4) { - chpro = options.rtSettings.best; - } else if(j == 5) { - chpro = options.rtSettings.bruce; - } else if(j == 6) { - chpro = options.rtSettings.srgb; - } else if(j == 7) { - chpro = options.rtSettings.srgb10; //gamma 1.0 - } else if(j == 8) { - chpro = options.rtSettings.prophoto10; //gamma 1.0 - } else if(j == 9) { - chpro = options.rtSettings.rec2020; - } - - for (unsigned int i = 0; i < opnames.size(); i++) { - if(chpro.compare(opnames[i]) == 0) { - present_space[j] = true; - } - } - - if (!present_space[j] && settings->verbose) { - printf("Missing file: %s\n", chpro.c_str()); - } - } - - if (params.icm.freegamma && params.icm.gampos < 1.35) { - pro = true; //select profil with gammaTRC modified : - } else if (params.icm.gamma == "linear_g1.0" || (params.icm.gamma == "High_g1.3_s3.35")) { - pro = true; //pro=0 RT_sRGB || Prophoto - } - - // Check that output profiles exist, otherwise use LCMS2 - // Use the icc/icm profiles associated to possible working profiles, set in "options" - if (params.icm.working == "ProPhoto" && present_space[0] && !pro) { - outProfile = options.rtSettings.prophoto; - } else if (params.icm.working == "Adobe RGB" && present_space[1] ) { - outProfile = options.rtSettings.adobe; - } else if (params.icm.working == "WideGamut" && present_space[2] ) { - outProfile = options.rtSettings.widegamut; - } else if (params.icm.working == "Beta RGB" && present_space[3] ) { - outProfile = options.rtSettings.beta; - } else if (params.icm.working == "BestRGB" && present_space[4] ) { - outProfile = options.rtSettings.best; - } else if (params.icm.working == "BruceRGB" && present_space[5] ) { - outProfile = options.rtSettings.bruce; - } else if (params.icm.working == "sRGB" && present_space[6] && !pro) { - outProfile = options.rtSettings.srgb; - } else if (params.icm.working == "sRGB" && present_space[7] && pro) { - outProfile = options.rtSettings.srgb10; - } else if (params.icm.working == "ProPhoto" && present_space[8] && pro) { - outProfile = options.rtSettings.prophoto10; - } else if (params.icm.working == "Rec2020" && present_space[9]) { - outProfile = options.rtSettings.rec2020; - } else { - // Should not occurs - if (settings->verbose) { - printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", params.icm.working.c_str() ); - } + if ((jprof = iccStore->createCustomGammaOutputProfile (params.icm, ga)) == NULL) { useLCMS = true; } - //begin adaptation rTRC gTRC bTRC - //"jprof" profile has the same characteristics than RGB values, but TRC are adapted... for applying profile - if (!useLCMS) { - if (settings->verbose) { - printf("Output Gamma - profile: \"%s\"\n", outProfile.c_str() ); //c_str() - } - - jprof = iccStore->getProfile(outProfile); //get output profile - - if (jprof == NULL) { - useLCMS = true; - - if (settings->verbose) { - printf("\"%s\" ICC output profile not found!\n", outProfile.c_str()); - } - } else { - Parameters[0] = ga0; - Parameters[1] = ga1; - Parameters[2] = ga2; - Parameters[3] = ga3; - Parameters[4] = ga4; - Parameters[5] = ga5; - Parameters[6] = ga6; - // 7 parameters for smoother curves - //change desc Tag , to "free gamma", or "BT709", etc. - cmsContext ContextID = cmsGetProfileContextID(jprof);//modification TAG - DescriptionMLU = cmsMLUalloc(ContextID, 1); - CopyrightMLU = cmsMLUalloc(ContextID, 1);//for ICC - DmndMLU = cmsMLUalloc(ContextID, 1); //for ICC - DmddMLU = cmsMLUalloc(ContextID, 1); // for ICC - - - // instruction with //ICC are used for generate icc profile - if (DescriptionMLU == NULL) { - printf("Description error\n"); - } - - cmsMLUsetWide(CopyrightMLU, "en", "US", L"General Public License - AdobeRGB compatible") ;//adapt to profil - cmsMLUsetWide(DmndMLU, "en", "US", L"RawTherapee") ; - cmsMLUsetWide(DmddMLU, "en", "US", L"RTMedium") ; //adapt to profil - - //display Tag desc with : selection of gamma and Primaries - if (!params.icm.freegamma) { - std::wstring gammaStr; - - if(params.icm.gamma == "High_g1.3_s3.35") { - gammaStr = std::wstring(L"GammaTRC: High g=1.3 s=3.35"); - } else if (params.icm.gamma == "Low_g2.6_s6.9") { - gammaStr = std::wstring(L"GammaTRC: Low g=2.6 s=6.9"); - } else if (params.icm.gamma == "sRGB_g2.4_s12.92") { - gammaStr = std::wstring(L"GammaTRC: sRGB g=2.4 s=12.92"); - } else if (params.icm.gamma == "BT709_g2.2_s4.5") { - gammaStr = std::wstring(L"GammaTRC: BT709 g=2.2 s=4.5"); - } else if (params.icm.gamma == "linear_g1.0") { - gammaStr = std::wstring(L"GammaTRC: Linear g=1.0"); - } else if (params.icm.gamma == "standard_g2.2") { - gammaStr = std::wstring(L"GammaTRC: g=2.2"); - } else if (params.icm.gamma == "standard_g1.8") { - gammaStr = std::wstring(L"GammaTRC: g=1.8"); - } - - cmsMLUsetWide(DescriptionMLU, "en", "US", gammaStr.c_str()); - - //for elaboration ICC profiles - // else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Medium gamma sRGB(AdobeRGB compatible)"); - // else if (params.icm.gamma== "BT709_g2.2_s4.5" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma BT709(IEC61966 equivalent)"); - // else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma sRGB(IEC61966 equivalent)"); - // else if (params.icm.gamma== "linear_g1.0" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_sRGB gamma Linear1.0(IEC61966 equivalent)"); - //else if (params.icm.gamma== "BT709_g2.2_s4.5" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma BT709(Prophoto compatible)"); - // else if (params.icm.gamma== "sRGB_g2.4_s12.92" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma sRGB(Prophoto compatible)"); - // else if (params.icm.gamma== "linear_g1.0" && !params.icm.freegamma) cmsMLUsetWide(DescriptionMLU, "en", "US", L"RT_Large gamma Linear1.0(Prophoto compatible)"); - } else { - // create description with gamma + slope + primaries - std::wostringstream gammaWs; - gammaWs.precision(2); - gammaWs << "Manual GammaTRC: g=" << (float)params.icm.gampos << " s=" << (float)params.icm.slpos; - cmsMLUsetWide(DescriptionMLU, "en", "US", gammaWs.str().c_str()); - } - - cmsWriteTag(jprof, cmsSigProfileDescriptionTag, DescriptionMLU);//desc changed - // cmsWriteTag(jprof, cmsSigCopyrightTag, CopyrightMLU); - // cmsWriteTag(jprof, cmsSigDeviceMfgDescTag, DmndMLU); - // cmsWriteTag(jprof, cmsSigDeviceModelDescTag, DmddMLU); - - // Calculate output profile's rTRC bTRC gTRC - GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters); - cmsWriteTag(jprof, cmsSigGreenTRCTag, (void*)GammaTRC[1] ); - cmsWriteTag(jprof, cmsSigRedTRCTag, (void*)GammaTRC[0] ); - cmsWriteTag(jprof, cmsSigBlueTRCTag, (void*)GammaTRC[2] ); - //for generation ICC profiles : here Prophoto ==> Large - // if(params.icm.gamma== "BT709_g2.2_s4.5") cmsSaveProfileToFile(jprof, "RT_sRGB_gBT709.icm"); - // else if (params.icm.gamma== "sRGB_g2.4_s12.92") cmsSaveProfileToFile(jprof, "RT_Medium_gsRGB.icc"); - // else if (params.icm.gamma== "linear_g1.0") cmsSaveProfileToFile(jprof, "RT_Large_g10.icc"); - - - } - } - - if (GammaTRC[0]) { - cmsFreeToneCurve(GammaTRC[0]); - } } else { // if Default gamma mode: we use the profile selected in the "Output profile" combobox; // gamma come from the selected profile, otherwise it comes from "Free gamma" tool - // readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.blackwhite.enabled); - bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled ; - - if(autili || butili ) { - bwonly = false; - } - - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, bwonly); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly); if (settings->verbose) { printf("Output profile_: \"%s\"\n", params.icm.output.c_str()); @@ -1374,17 +1190,15 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p - if(!autili && !butili ) { - if(params.blackwhite.enabled && !params.colorToning.enabled ) {//force BW r=g=b - if (settings->verbose) { - printf("Force BW\n"); - } + if(bwonly) { //force BW r=g=b + if (settings->verbose) { + printf("Force BW\n"); + } - for (int ccw = 0; ccw < cw; ccw++) { - for (int cch = 0; cch < ch; cch++) { - readyImg->r(cch, ccw) = readyImg->g(cch, ccw); - readyImg->b(cch, ccw) = readyImg->g(cch, ccw); - } + for (int ccw = 0; ccw < cw; ccw++) { + for (int cch = 0; cch < ch; cch++) { + readyImg->r(cch, ccw) = readyImg->g(cch, ccw); + readyImg->b(cch, ccw) = readyImg->g(cch, ccw); } } } @@ -1410,37 +1224,28 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // Setting the output curve to readyImg if (customGamma) { if (!useLCMS) { - // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16b + // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma ProfileContent pc(jprof); readyImg->setOutputProfile (pc.data, pc.length); } } else { - // use RT_sRGB.icm profile if present, otherwise use LCMS2 profile generate by lab2rgb16b - Glib::ustring outputProfile; + // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma if (params.icm.output != "" && params.icm.output != ColorManagementParams::NoICMString) { - outputProfile = params.icm.output; - - /* if we'd wanted the RT_sRGB profile we would have selected it - else { - // use RT_sRGB.icm profile if present, otherwise use LCMS2 profile generate by lab2rgb16b - if (settings->verbose) printf("No output profiles set ; looking for the default sRGB profile (\"%s\")...\n", options.rtSettings.srgb.c_str()); - outputProfile = options.rtSettings.srgb; - }*/ // if iccStore->getProfile send back an object, then iccStore->getContent will do too - cmsHPROFILE jprof = iccStore->getProfile(outputProfile); //get outProfile + cmsHPROFILE jprof = iccStore->getProfile(params.icm.output); //get outProfile if (jprof == NULL) { if (settings->verbose) { - printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", outputProfile.c_str()); + printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", params.icm.output.c_str()); } } else { if (settings->verbose) { - printf("Using \"%s\" output profile\n", outputProfile.c_str()); + printf("Using \"%s\" output profile\n", params.icm.output.c_str()); } - ProfileContent pc = iccStore->getContent (outputProfile); + ProfileContent pc = iccStore->getContent (params.icm.output); readyImg->setOutputProfile (pc.data, pc.length); } } else { diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 80dc3dfae..d74d8ee9d 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -35,11 +35,13 @@ using namespace rtengine::procparams; -class EditorPanel::MonitorProfileSelector +class EditorPanel::ColorManagementToolbar { private: MyComboBoxText profileBox; PopUpButton intentBox; + Gtk::ToggleButton softProof; + Gtk::ToggleButton spGamutCheck; sigc::connection profileConn, intentConn; rtengine::StagedImageProcessor* const& processor; @@ -61,6 +63,7 @@ private: for (std::vector::const_iterator iterator = profiles.begin (); iterator != profiles.end (); ++iterator) { profileBox.append_text (*iterator); } + profileBox.set_tooltip_text (profileBox.get_active_text ()); } void prepareIntentBox () @@ -73,11 +76,31 @@ private: intentBox.show (); } + void prepareSoftProofingBox () + { + Gtk::Image *softProofImage = Gtk::manage (new RTImage ("softProof.png")); + softProofImage->set_padding(0, 0); + softProof.add(*softProofImage); + softProof.set_relief(Gtk::RELIEF_NONE); + softProof.set_tooltip_markup(M("SOFTPROOF_TOOLTIP")); + + softProof.set_active(false); + softProof.show (); + + Gtk::Image *spGamutCheckImage = Gtk::manage (new RTImage ("spGamutCheck.png")); + spGamutCheckImage->set_padding(0, 0); + spGamutCheck.add(*spGamutCheckImage); + spGamutCheck.set_relief(Gtk::RELIEF_NONE); + spGamutCheck.set_tooltip_markup(M("SOFTPROOF_GAMUTCHECK_TOOLTIP")); + + spGamutCheck.set_active(false); + spGamutCheck.set_sensitive(false); + spGamutCheck.show (); + } + void profileBoxChanged () { updateParameters (); - - profileBox.set_tooltip_text (profileBox.get_active_text ()); } void intentBoxChanged (int) @@ -85,6 +108,16 @@ private: updateParameters (); } + void softProofToggled () + { + updateSoftProofParameters (); + } + + void spGamutCheckToggled () + { + updateSoftProofParameters (); + } + void updateParameters () { ConnectionBlocker profileBlocker (profileConn); @@ -115,8 +148,10 @@ private: intentBox.set_sensitive (false); intentBox.setSelected (0); + profileBox.set_tooltip_text (""); + } else { - const std::uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const 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; @@ -130,6 +165,8 @@ private: intentBox.set_sensitive (false); intentBox.setSelected (0); } + + profileBox.set_tooltip_text (profileBox.get_active_text ()); } rtengine::RenderingIntent intent; @@ -155,22 +192,38 @@ private: processor->endUpdateParams (rtengine::EvMonitorTransform); } + void updateSoftProofParameters () + { + spGamutCheck.set_sensitive(softProof.get_active()); + + if (profileBox.get_active_row_number () > 0) { + processor->beginUpdateParams (); + processor->setSoftProofing (softProof.get_active(), spGamutCheck.get_active()); + processor->endUpdateParams (rtengine::EvMonitorTransform); + } + } + public: - MonitorProfileSelector (rtengine::StagedImageProcessor* const& ipc) : + ColorManagementToolbar (rtengine::StagedImageProcessor* const& ipc) : intentBox (Glib::ustring (), true), processor (ipc) { prepareProfileBox (); prepareIntentBox (); + prepareSoftProofingBox (); reset (); - profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::profileBoxChanged)); - intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::intentBoxChanged)); + softProof.signal_toggled().connect(sigc::mem_fun (this, &ColorManagementToolbar::softProofToggled)); + spGamutCheck.signal_toggled().connect(sigc::mem_fun (this, &ColorManagementToolbar::spGamutCheckToggled));; + profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &ColorManagementToolbar::profileBoxChanged)); + intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &ColorManagementToolbar::intentBoxChanged)); } void pack_end_in (Gtk::Box* box) { + box->pack_end (spGamutCheck, Gtk::PACK_SHRINK, 0); + box->pack_end (softProof, Gtk::PACK_SHRINK, 0); box->pack_end (*intentBox.buttonGroup, Gtk::PACK_SHRINK, 0); box->pack_end (profileBox, Gtk::PACK_SHRINK, 0); } @@ -443,9 +496,9 @@ EditorPanel::EditorPanel (FilePanel* filePanel) 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); + // Color management toolbar + colorMgmtToolBar.reset (new ColorManagementToolbar (ipc)); + colorMgmtToolBar->pack_end_in (iops); editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); @@ -754,7 +807,7 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) history->resetSnapShotNumber(); - monitorProfile->reset (); + colorMgmtToolBar->reset (); } void EditorPanel::close () diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index e506e1583..dbf99d58d 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -84,8 +84,8 @@ protected: Gtk::Button* navNext; Gtk::Button* navPrev; - class MonitorProfileSelector; - std::unique_ptr monitorProfile; + class ColorManagementToolbar; + std::unique_ptr colorMgmtToolBar; ImageAreaPanel* iareapanel; PreviewHandler* previewHandler; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 3ed7608f1..ad11e079d 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1179,6 +1179,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.icm.working = options.fastexport_icm_working ; params.icm.output = options.fastexport_icm_output ; params.icm.outputIntent = options.fastexport_icm_outputIntent ; + params.icm.outputBPC = options.fastexport_icm_outputBPC ; 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/icmpanel.cc b/rtgui/icmpanel.cc index cc2cbc039..e1fc802d6 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -202,6 +202,11 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch ointent->set_active (1); oVBox->pack_start(*riHBox, Gtk::PACK_SHRINK); + // Black Point Compensation + obpc = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_BPC")))); + obpc->set_active (true); + oVBox->pack_start(*obpc, Gtk::PACK_SHRINK); + // Output gamma Gtk::HBox* gaHBox = Gtk::manage (new Gtk::HBox ()); @@ -295,6 +300,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) ); dcpIll->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::dcpIlluminantChanged) ); + obpcconn = obpc->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::oBPCChanged) ); gamcsconn = freegamma->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::GamChanged)); tcurveconn = ckbToneCurve->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::toneCurveChanged)); ltableconn = ckbApplyLookTable->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::applyLookTableChanged)); @@ -455,6 +461,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) disableListener (); + obpcconn.block (true); ipc.block (true); gamcsconn.block (true); tcurveconn.block(true); @@ -469,36 +476,50 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) if (pp->icm.input == "(none)") { inone->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input == "") && icamera->get_state() == Gtk::STATE_INSENSITIVE)) { iembedded->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state() != Gtk::STATE_INSENSITIVE) { icameraICC->set_active (true); - ckbBlendCMSMatrix->set_sensitive (true); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (true); + } updateDCP(pp->icm.dcpIlluminant, "(cameraICC)"); } else if ((pp->icm.input == "(cameraICC)") && icamera->get_state() != Gtk::STATE_INSENSITIVE && icameraICC->get_state() == Gtk::STATE_INSENSITIVE) { // this is the case when (cameraICC) is instructed by packaged profiles, but ICC file is not found // therefore falling back UI to explicitly reflect the (camera) option icamera->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else if ((pp->icm.input == "(cameraICC)") && icamera->get_state() == Gtk::STATE_INSENSITIVE && icameraICC->get_state() == Gtk::STATE_INSENSITIVE) { // If neither (camera) nor (cameraICC) are available, as is the case when loading a non-raw, activate (embedded). iembedded->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, "(cameraICC)"); } else if ((pp->icm.input == "(camera)" || pp->icm.input == "") && icamera->get_state() != Gtk::STATE_INSENSITIVE) { icamera->set_active (true); - ckbBlendCMSMatrix->set_sensitive (false); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (false); + } updateDCP(pp->icm.dcpIlluminant, ""); } else { ifromfile->set_active (true); oldip = pp->icm.input.substr(5); // cut of "file:" ipDialog->set_filename (pp->icm.input.substr(5)); - ckbBlendCMSMatrix->set_sensitive (true); + if (!batchMode) { + ckbBlendCMSMatrix->set_sensitive (true); + } updateDCP(pp->icm.dcpIlluminant, pp->icm.input.substr(5)); } @@ -516,6 +537,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) } ointent->set_active(pp->icm.outputIntent); + obpc->set_active (pp->icm.outputBPC); ckbToneCurve->set_active (pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; ckbApplyLookTable->set_active (pp->icm.applyLookTable); @@ -528,22 +550,28 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) ckbBlendCMSMatrix->set_active (pp->icm.blendCMSMatrix); lastBlendCMSMatrix = pp->icm.blendCMSMatrix; - onames->set_sensitive(wgamma->get_active_row_number() == 0 || freegamma->get_active()); //"default" - wgamma->set_sensitive(!freegamma->get_active()); - freegamma->set_active (pp->icm.freegamma); lastgamfree = pp->icm.freegamma; + if (!batchMode) { + onames->set_sensitive(wgamma->get_active_row_number() == 0 && !pp->icm.freegamma); //"default" + wgamma->set_sensitive(!pp->icm.freegamma); + gampos->set_sensitive(pp->icm.freegamma); + slpos->set_sensitive(pp->icm.freegamma); + } + gampos->setValue (pp->icm.gampos); slpos->setValue (pp->icm.slpos); if (pedited) { iunchanged->set_active (!pedited->icm.input); + obpc->set_inconsistent(!pedited->icm.outputBPC); ckbToneCurve->set_inconsistent(!pedited->icm.toneCurve); ckbApplyLookTable->set_inconsistent(!pedited->icm.applyLookTable); ckbApplyBaselineExposureOffset->set_inconsistent(!pedited->icm.applyBaselineExposureOffset); ckbApplyHueSatMap->set_inconsistent(!pedited->icm.applyHueSatMap); ckbBlendCMSMatrix->set_inconsistent(!pedited->icm.blendCMSMatrix); + freegamma->set_inconsistent (!pedited->icm.freegamma); if (!pedited->icm.working) { wnames->set_active_text(M("GENERAL_UNCHANGED")); @@ -578,6 +606,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) hsmconn.block(false); gamcsconn.block (false); ipc.block (false); + obpcconn.block (false); enableListener (); } @@ -655,12 +684,14 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pp->icm.blendCMSMatrix = ckbBlendCMSMatrix->get_active (); pp->icm.gampos = (double) gampos->getValue(); pp->icm.slpos = (double) slpos->getValue(); + pp->icm.outputBPC = obpc->get_active (); if (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.outputBPC = !obpc->get_inconsistent (); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent (); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent (); @@ -697,7 +728,7 @@ void ICMPanel::setAdjusterBehavior (bool gammaadd, bool slopeadd) void ICMPanel::adjusterChanged (Adjuster* a, double newval) { - if (listener && freegamma->get_active()) { + if (listener && (freegamma->get_active() || batchMode)) { Glib::ustring costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), newval); @@ -735,7 +766,7 @@ void ICMPanel::dcpIlluminantChanged() void ICMPanel::toneCurveChanged() { - if (batchMode) { + if (multiImage) { if (ckbToneCurve->get_inconsistent()) { ckbToneCurve->set_inconsistent (false); tcurveconn.block (true); @@ -749,13 +780,19 @@ void ICMPanel::toneCurveChanged() } if (listener) { - listener->panelChanged (EvDCPToneCurve, ckbToneCurve->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbToneCurve->get_inconsistent()) { + listener->panelChanged (EvDCPToneCurve, M("GENERAL_UNCHANGED")); + } else if (ckbToneCurve->get_active()) { + listener->panelChanged (EvDCPToneCurve, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPToneCurve, M("GENERAL_DISABLED")); + } } } void ICMPanel::applyLookTableChanged() { - if (batchMode) { + if (multiImage) { if (ckbApplyLookTable->get_inconsistent()) { ckbApplyLookTable->set_inconsistent (false); ltableconn.block (true); @@ -769,13 +806,19 @@ void ICMPanel::applyLookTableChanged() } if (listener) { - listener->panelChanged (EvDCPApplyLookTable, ckbApplyLookTable->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbApplyLookTable->get_inconsistent()) { + listener->panelChanged (EvDCPApplyLookTable, M("GENERAL_UNCHANGED")); + } else if (ckbApplyLookTable->get_active()) { + listener->panelChanged (EvDCPApplyLookTable, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPApplyLookTable, M("GENERAL_DISABLED")); + } } } void ICMPanel::applyBaselineExposureOffsetChanged() { - if (batchMode) { + if (multiImage) { if (ckbApplyBaselineExposureOffset->get_inconsistent()) { ckbApplyBaselineExposureOffset->set_inconsistent (false); beoconn.block (true); @@ -789,13 +832,19 @@ void ICMPanel::applyBaselineExposureOffsetChanged() } if (listener) { - listener->panelChanged (EvDCPApplyBaselineExposureOffset, ckbApplyBaselineExposureOffset->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbApplyBaselineExposureOffset->get_inconsistent()) { + listener->panelChanged (EvDCPApplyBaselineExposureOffset, M("GENERAL_UNCHANGED")); + } else if (ckbApplyBaselineExposureOffset->get_active()) { + listener->panelChanged (EvDCPApplyBaselineExposureOffset, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPApplyBaselineExposureOffset, M("GENERAL_DISABLED")); + } } } void ICMPanel::applyHueSatMapChanged() { - if (batchMode) { + if (multiImage) { if (ckbApplyHueSatMap->get_inconsistent()) { ckbApplyHueSatMap->set_inconsistent (false); hsmconn.block (true); @@ -809,7 +858,13 @@ void ICMPanel::applyHueSatMapChanged() } if (listener) { - listener->panelChanged (EvDCPApplyHueSatMap, ckbApplyHueSatMap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbApplyHueSatMap->get_inconsistent()) { + listener->panelChanged (EvDCPApplyHueSatMap, M("GENERAL_UNCHANGED")); + } else if (ckbApplyHueSatMap->get_active()) { + listener->panelChanged (EvDCPApplyHueSatMap, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDCPApplyHueSatMap, M("GENERAL_DISABLED")); + } } } @@ -846,7 +901,7 @@ void ICMPanel::ipChanged () void ICMPanel::blendCMSMatrixChanged() { - if (batchMode) { + if (multiImage) { if (ckbBlendCMSMatrix->get_inconsistent()) { ckbBlendCMSMatrix->set_inconsistent (false); blendcmsconn.block (true); @@ -860,13 +915,19 @@ void ICMPanel::blendCMSMatrixChanged() } if (listener) { - listener->panelChanged (EvBlendCMSMatrix, ckbBlendCMSMatrix->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + if (ckbBlendCMSMatrix->get_inconsistent()) { + listener->panelChanged (EvBlendCMSMatrix, M("GENERAL_UNCHANGED")); + } else if (ckbBlendCMSMatrix->get_active()) { + listener->panelChanged (EvBlendCMSMatrix, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvBlendCMSMatrix, M("GENERAL_DISABLED")); + } } } void ICMPanel::GamChanged() { - if (batchMode) { + if (multiImage) { if (freegamma->get_inconsistent()) { freegamma->set_inconsistent (false); gamcsconn.block (true); @@ -880,14 +941,25 @@ void ICMPanel::GamChanged() } if (listener) { - if (freegamma->get_active()) { + if (freegamma->get_inconsistent()) { + listener->panelChanged (EvGAMFREE, M("GENERAL_UNCHANGED")); + } + else if (freegamma->get_active()) { listener->panelChanged (EvGAMFREE, M("GENERAL_ENABLED")); - onames->set_sensitive(!freegamma->get_active());//disabled choice - wgamma->set_sensitive(!freegamma->get_active()); + if (!batchMode) { + onames->set_sensitive(false);//disabled choice + wgamma->set_sensitive(false); + gampos->set_sensitive(true); + slpos->set_sensitive(true); + } } else { listener->panelChanged (EvGAMFREE, M("GENERAL_DISABLED")); - onames->set_sensitive(!freegamma->get_active() && wgamma->get_active_row_number() == 0); - wgamma->set_sensitive(!freegamma->get_active()); + if (!batchMode) { + onames->set_sensitive(wgamma->get_active_row_number() == 0); + wgamma->set_sensitive(true); + gampos->set_sensitive(false); + slpos->set_sensitive(false); + } } } } @@ -908,6 +980,32 @@ void ICMPanel::oiChanged () } } +void ICMPanel::oBPCChanged () +{ + if (multiImage) { + if (obpc->get_inconsistent()) { + obpc->set_inconsistent (false); + obpcconn.block (true); + obpc->set_active (false); + obpcconn.block (false); + } else if (lastobpc) { + obpc->set_inconsistent (true); + } + + lastobpc = obpc->get_active (); + } + + if (listener) { + if (obpc->get_inconsistent()) { + listener->panelChanged (EvOBPCompens, M("GENERAL_UNCHANGED")); + } else if (obpc->get_active()) { + listener->panelChanged (EvOBPCompens, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvOBPCompens, M("GENERAL_DISABLED")); + } + } +} + void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) { diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 640cca5a2..03c894017 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -53,6 +53,8 @@ protected: sigc::connection beoconn; bool lastApplyHueSatMap; sigc::connection hsmconn; + bool lastobpc; + sigc::connection obpcconn; bool lastBlendCMSMatrix; bool isBatchMode; sigc::connection blendcmsconn; @@ -60,6 +62,7 @@ protected: private: Gtk::VBox * iVBox; + Gtk::CheckButton* obpc; Gtk::CheckButton* freegamma; Gtk::RadioButton* inone; @@ -108,6 +111,7 @@ public: void wpChanged (); void opChanged (); void oiChanged (); + void oBPCChanged (); void ipChanged (); void gpChanged (); void GamChanged (); diff --git a/rtgui/options.cc b/rtgui/options.cc index e723361be..9ba8b175a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -469,6 +469,7 @@ void Options::setDefaults () fastexport_icm_working = "ProPhoto"; fastexport_icm_output = "RT_sRGB"; fastexport_icm_outputIntent = rtengine::RI_RELATIVE; + fastexport_icm_outputBPC = true; fastexport_icm_gamma = "default"; fastexport_resize_enabled = true; fastexport_resize_scale = 1; @@ -634,6 +635,8 @@ void Options::setDefaults () rtSettings.monitorProfile = Glib::ustring(); rtSettings.monitorIntent = rtengine::RI_RELATIVE; + rtSettings.monitorBPC = true; + rtSettings.monitorBPC = true; 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" @@ -1463,6 +1466,10 @@ int Options::readFromFile (Glib::ustring fname) rtSettings.monitorIntent = static_cast(keyFile.get_integer("Color Management", "Intent")); } + if (keyFile.has_key ("Color Management", "Intent")) { + rtSettings.monitorBPC = keyFile.get_boolean("Color Management", "MonitorBPC"); + } + if (keyFile.has_key ("Color Management", "CRI")) { rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); } @@ -1719,6 +1726,10 @@ int Options::readFromFile (Glib::ustring fname) fastexport_icm_outputIntent = static_cast(keyFile.get_integer ("Fast Export", "fastexport_icm_output_intent" )); } + if (keyFile.has_key ("Fast Export", "fastexport_icm_output_bpc" )) { + fastexport_icm_outputBPC = keyFile.get_boolean ("Fast Export", "fastexport_icm_output_bpc" ); + } + if (keyFile.has_key ("Fast Export", "fastexport_icm_gamma" )) { fastexport_icm_gamma = keyFile.get_string ("Fast Export", "fastexport_icm_gamma" ); } @@ -2028,6 +2039,7 @@ int Options::saveToFile (Glib::ustring fname) 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.monitorIntent); + keyFile.set_boolean ("Color Management", "MonitorBPC", rtSettings.monitorBPC); keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); @@ -2096,6 +2108,7 @@ int Options::saveToFile (Glib::ustring fname) 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_integer ("Fast Export", "fastexport_icm_output_bpc" , fastexport_icm_outputBPC ); 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 4da827f36..275ccbe69 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -260,6 +260,7 @@ public: Glib::ustring fastexport_icm_working; Glib::ustring fastexport_icm_output; rtengine::RenderingIntent fastexport_icm_outputIntent; + bool fastexport_icm_outputBPC; Glib::ustring fastexport_icm_gamma; bool fastexport_resize_enabled; double fastexport_resize_scale; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 0422f7403..b448cd2ee 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -353,8 +353,9 @@ void ParamsEdited::set (bool v) icm.working = v; icm.output = v; icm.outputIntent = v; + icm.outputBPC = v; icm.gamma = v; - icm.freegamma = v; + icm.freegamma = v; icm.gampos = v; icm.slpos = v; raw.bayersensor.method = v; @@ -847,6 +848,7 @@ void ParamsEdited::initFrom (const std::vector 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.outputBPC = icm.outputBPC && p.icm.outputBPC == other.icm.outputBPC ; 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; @@ -2210,6 +2212,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.icm.outputIntent = mods.icm.outputIntent; } + if (icm.outputBPC) { + toEdit.icm.outputBPC = mods.icm.outputBPC; + } + //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 f8d18ae57..5c35b20da 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -544,6 +544,7 @@ public: bool working; bool output; bool outputIntent; + bool outputBPC; bool gamma; bool gampos; bool slpos; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 14c9cb0eb..7c325033b 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -707,6 +707,9 @@ Gtk::Widget* Preferences::getColorManagementPanel () monIntent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); monIntent->set_active (1); + monBPC = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_MONBPC"))); + monBPC->set_active (true); + iccDir->signal_selection_changed ().connect (sigc::mem_fun (this, &Preferences::iccDirChanged)); #if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 @@ -716,22 +719,24 @@ Gtk::Widget* Preferences::getColorManagementPanel () Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 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); + colt->attach (*pdlabel, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*iccDir, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); #if !defined(__APPLE__) // monitor profile not supported on apple ++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); + colt->attach (*mplabel, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*monProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); #if defined(WIN32) ++row; - colt->attach (*cbAutoMonProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*cbAutoMonProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, 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); + colt->attach (*milabel, 0, 1, row, row + 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*monIntent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); + mvbcm->pack_start (*monBPC, Gtk::PACK_SHRINK, 4); + #if defined(WIN32) autoMonProfileToggled(); #endif @@ -1458,6 +1463,7 @@ void Preferences::storePreferences () moptions.rtSettings.monitorIntent = rtengine::RI_ABSOLUTE; break; } + moptions.rtSettings.monitorBPC = monBPC->get_active (); #if defined(WIN32) moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); #endif @@ -1588,6 +1594,7 @@ void Preferences::fillPreferences () monIntent->set_active (2); break; } + monBPC->set_active (moptions.rtSettings.monitorBPC); #if defined(WIN32) cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 1cfb435cf..87af25941 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -97,6 +97,7 @@ protected: Gtk::FileChooserButton* iccDir; Gtk::ComboBoxText* monProfile; Gtk::ComboBoxText* monIntent; + Gtk::CheckButton* monBPC; Gtk::CheckButton* cbAutoMonProfile; //Gtk::CheckButton* cbAutocielab; Gtk::CheckButton* cbciecamfloat; diff --git a/tools/color_management.svg b/tools/color_management.svg new file mode 100644 index 000000000..0307fa81c --- /dev/null +++ b/tools/color_management.svg @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Espace couleurde travail (WCS) + + + + Profile ICC/ICMde sortie + + + + Profile ICC/ICMdu moniteur + + + + Moniteur + + + + Imprimante + + Fichier de sortie + Epreuvage écran + options.rtSettings.HistogramWorking + + + Image L*a*b + Fin du pipeline + + + +