From 5affa18341d732b4821ca49e7f4afcedbe4d3be6 Mon Sep 17 00:00:00 2001 From: Hombre Date: Wed, 24 Aug 2016 22:32:06 +0200 Subject: [PATCH 01/13] Introducting soft-proofing and Black Point Compensation, simplify the CMM at the end of the pipeline + sparse code refactoring A new BPC checkbutton has been created in 'Preferences/Color Management' and in the ICM tool. Better hanbling of widget sensitivity of the output profile / gamma part of the ICM tool. --- rtdata/languages/Francais | 6 + rtdata/languages/default | 6 + rtengine/dcrop.cc | 18 +- rtengine/dcrop.h | 2 +- rtengine/iccstore.cc | 336 ++++++++++++++++++++++- rtengine/iccstore.h | 12 +- rtengine/image16.cc | 33 ++- rtengine/image16.h | 2 +- rtengine/improccoordinator.cc | 36 +-- rtengine/improccoordinator.h | 9 +- rtengine/improcfun.cc | 80 ++++-- rtengine/improcfun.h | 7 +- rtengine/iplab2rgb.cc | 492 ++++++++++------------------------ rtengine/procevents.h | 1 + rtengine/procparams.cc | 13 + rtengine/procparams.h | 1 + rtengine/refreshmap.cc | 21 +- rtengine/refreshmap.h | 6 +- rtengine/rtengine.h | 2 + rtengine/rtthumbnail.cc | 2 +- rtengine/settings.h | 1 + rtengine/simpleprocess.cc | 233 ++-------------- rtgui/editorpanel.cc | 75 +++++- rtgui/editorpanel.h | 4 +- rtgui/filecatalog.cc | 1 + rtgui/icmpanel.cc | 152 +++++++++-- rtgui/icmpanel.h | 4 + rtgui/options.cc | 13 + rtgui/options.h | 1 + rtgui/paramsedited.cc | 8 +- rtgui/paramsedited.h | 1 + rtgui/preferences.cc | 21 +- rtgui/preferences.h | 1 + tools/color_management.svg | 430 +++++++++++++++++++++++++++++ 34 files changed, 1321 insertions(+), 709 deletions(-) create mode 100644 tools/color_management.svg 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 + + + + From 827acd35f9d5ea8f7209dc13e53221ff09a555fa Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 27 Aug 2016 22:20:54 +0200 Subject: [PATCH 02/13] Some bugfix. --- rtdata/images/Dark/actions/spGamutCheck.png | Bin 0 -> 707 bytes rtdata/images/Dark/actions/unchanged-18.png | Bin 0 -> 149 bytes rtdata/images/Dark/actions/unchanged-22.png | Bin 0 -> 153 bytes rtdata/images/Light/actions/spGamutCheck.png | Bin 0 -> 701 bytes rtdata/images/Light/actions/unchanged-18.png | Bin 0 -> 149 bytes rtdata/images/Light/actions/unchanged-22.png | Bin 0 -> 153 bytes rtengine/FTblockDN.cc | 1 + rtengine/color.cc | 15 +- rtengine/color.h | 29 +- rtengine/curves.cc | 1 + rtengine/iccstore.cc | 320 ++-- rtengine/iccstore.h | 27 +- rtengine/improccoordinator.cc | 1 + rtengine/improcfun.cc | 4 +- rtengine/improcfun.h | 2 +- rtengine/iplab2rgb.cc | 8 +- rtengine/ipwavelet.cc | 1 + rtengine/rawimagesource.cc | 28 +- rtengine/simpleprocess.cc | 4 +- rtgui/curveeditorgroup.cc | 2 +- rtgui/editorpanel.cc | 22 +- rtgui/histogrampanel.cc | 2 +- rtgui/icmpanel.cc | 73 +- rtgui/icmpanel.h | 6 +- rtgui/options.cc | 1 - rtgui/preferences.cc | 11 +- tools/source_icons/scalable/spGamutCheck.file | 1 + tools/source_icons/scalable/spGamutCheck.svg | 1344 ++++++++++++++++ tools/source_icons/scalable/unchanged.file | 2 + tools/source_icons/scalable/unchanged.svg | 1357 +++++++++++++++++ 30 files changed, 3006 insertions(+), 256 deletions(-) create mode 100644 rtdata/images/Dark/actions/spGamutCheck.png create mode 100644 rtdata/images/Dark/actions/unchanged-18.png create mode 100644 rtdata/images/Dark/actions/unchanged-22.png create mode 100644 rtdata/images/Light/actions/spGamutCheck.png create mode 100644 rtdata/images/Light/actions/unchanged-18.png create mode 100644 rtdata/images/Light/actions/unchanged-22.png create mode 100644 tools/source_icons/scalable/spGamutCheck.file create mode 100644 tools/source_icons/scalable/spGamutCheck.svg create mode 100644 tools/source_icons/scalable/unchanged.file create mode 100644 tools/source_icons/scalable/unchanged.svg diff --git a/rtdata/images/Dark/actions/spGamutCheck.png b/rtdata/images/Dark/actions/spGamutCheck.png new file mode 100644 index 0000000000000000000000000000000000000000..ab812272ad767ac6e2bed75df47de549cc5e4515 GIT binary patch literal 707 zcmV;!0zCbRP){_v1#j zTD{fp_sakvgm_Xc7MqbLVwGMn#;i_Q{4#+1xm?Zv~CAk6M=&!)m+KiNPZ#;pdEf$Nr zQp!gpKP3i}>=X)x-zOy&3Waa2R_n2~_RX2W)>;B+PfISB%U#!XpLe_6*Mnkoz1fF0AP#>quBGj z5IEkw5Mnjnylzr(DwT@BM2^EInPm;Srh{JJj2o^$wVA-Gg3b&N4HNdW0|`ZE9pK&4Wt pPTZ3t4^k$&a`}9IAHe=3?+wL>2?- zL=a{S)t;~y$dD{?jVKAuPb(=;EJ|f4FE7{2%*!rLPAo{(%P&fw{mw=Ts7TDy#WBR9 pH#tFqb#a17Pg9@)7n>*p1KVr{#>bzJp9iX7@O1TaS?83{1OW1!CUF1& literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/spGamutCheck.png b/rtdata/images/Light/actions/spGamutCheck.png new file mode 100644 index 0000000000000000000000000000000000000000..b1ae3e423af9fb8cfe85cc3cf88364f40d8b5adf GIT binary patch literal 701 zcmV;u0z&eDO6jjZg8eE_2TO z=DatT0sd2Qa6xOmBqG;I9*9V}TCIKn;Qk4m&1UbAyno6-9w?UO(cT$Qc2g-hr7PJ=~6|7t@Kc@3a8WY4Wmr*n4{*pGoTN-1NEc>zEG zV0Ly^`@VlqL~^4*LlcvnaL&Dnpa4*>*DJ=D=Oi}(bp956A(cv1&hUsaW}D;_k{=U; zMWhvm;g4ZPW6YNz2%Z9Xp9D;jN2APP7@kxrm6rhC0f4pEMp_UAc4lVgvetSD_gsCLljKSqe3BIGd0qtT z6bgk??@4@)EfQ7`1mC;e?lyq-pytQ=<3Vv$6^q3q02^m%{a>M!YUT6!ASpavBwHlE z0S32l}h{8+V%LexeH(_33yo5>-BGaaHG*^iO6`u#0>zO05;RwL>2?- zL=a{S)t;~y$dD{?jVKAuPb(=;EJ|f4FE7{2%*!rLPAo{(%P&fw{mw=Ts7TDy#WBR9 pH#tFqb#a17Pg9@)7n>*p1KVr{#>bzJp9iX7@O1TaS?83{1OW1!CUF1& literal 0 HcmV?d00001 diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 288c9c994..a7e4ca27b 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -37,6 +37,7 @@ #include "opthelper.h" #include "cplx_wavelet_dec.h" #include "median.h" +#include "iccstore.h" #ifdef _OPENMP #include diff --git a/rtengine/color.cc b/rtengine/color.cc index c822a6f33..5f87ce1f6 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -1433,7 +1433,7 @@ void Color::interpolateRGBColor (float realL, float iplow, float iphigh, int alg Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz);// ro go bo in gamut } -void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5) +void Color::calcGamma (double pwr, double ts, int mode, int imax, GammaValues &gamma) { //from Dcraw (D.Coffin) int i; @@ -1469,12 +1469,13 @@ void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0 } if (!mode--) { - gamma0 = g[0]; - gamma1 = g[1]; - gamma2 = g[2]; - gamma3 = g[3]; - gamma4 = g[4]; - gamma5 = g[5]; + gamma.gamma0 = g[0]; + gamma.gamma1 = g[1]; + gamma.gamma2 = g[2]; + gamma.gamma3 = g[3]; + gamma.gamma4 = g[4]; + gamma.gamma5 = g[5]; + gamma.gamma6 = 0.; return; } } diff --git a/rtengine/color.h b/rtengine/color.h index bf42140c5..6566ea1ff 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -23,7 +23,6 @@ #include "rt_math.h" #include "LUT.h" #include "labimage.h" -#include "iccstore.h" #include "iccmatrices.h" #include "sleef.c" #define SAT(a,b,c) ((float)max(a,b,c)-(float)min(a,b,c))/(float)max(a,b,c) @@ -47,6 +46,7 @@ public: #endif + class Color { @@ -95,6 +95,17 @@ private: #endif public: + class GammaValues { + public: + double gamma0; + double gamma1; + double gamma2; + double gamma3; + double gamma4; + double gamma5; + double gamma6; + }; + typedef enum Channel { CHANNEL_RED = 1 << 0, CHANNEL_GREEN = 1 << 1, @@ -852,21 +863,21 @@ public: return h; } - /** * @brief Get the gamma curves' parameters used by LCMS2 * @param pwr gamma value [>1] * @param ts slope [0 ; 20] * @param mode [always 0] * @imax imax [always 0] - * @param gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) - * @param gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) - * @param gamma2 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) - * @param gamma3 used in ip2Lab2rgb [0 ; 1], usually near 0.003(return value) - * @param gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) - * @param gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) + * @param gamma a pointer to an array of 6 double gamma values: + * gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) + * gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) + * gamma2 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) + * gamma3 used in ip2Lab2rgb [0 ; 1], usually near 0.003(return value) + * gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) + * gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) */ - static void calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5); + static void calcGamma (double pwr, double ts, int mode, int imax, GammaValues &gamma); /** diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 9b68cc9ee..2f1c274ea 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -36,6 +36,7 @@ #include "opthelper.h" #include "ciecam02.h" #include "color.h" +#include "iccstore.h" #undef CLIPD #define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 14b5dbc3c..559a5d009 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -96,20 +96,20 @@ void loadProfiles (const Glib::ustring& dirName, } catch (Glib::Exception&) {} } -inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, std::uint8_t& result) +inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, uint8_t& result) { if (cmsIsIntentSupported (profile, intent, direction)) { result |= 1 << intent; } } -inline std::uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) +inline uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) { if (!profile) { return 0; } - std::uint8_t result = 0; + uint8_t result = 0; getSupportedIntent (profile, INTENT_PERCEPTUAL, direction, result); getSupportedIntent (profile, INTENT_RELATIVE_COLORIMETRIC, direction, result); @@ -188,8 +188,8 @@ std::vector ICCStore::getProfilesFromDir (const Glib::ustring& di ProfileMap profiles; - loadProfiles (profilesDir, &profiles, NULL, NULL, false, true); - loadProfiles (dirName, &profiles, NULL, NULL, false, true); + loadProfiles (profilesDir, &profiles, nullptr, nullptr, false, true); + loadProfiles (dirName, &profiles, nullptr, nullptr, false, true); for (ProfileMap::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) { res.push_back (profile->first); @@ -202,14 +202,14 @@ cmsHPROFILE ICCStore::makeStdGammaProfile (cmsHPROFILE iprof) { // forgive me for the messy code, quick hack to change gamma of an ICC profile to the RT standard gamma if (!iprof) { - return NULL; + return nullptr; } cmsUInt32Number bytesNeeded = 0; cmsSaveProfileToMem(iprof, 0, &bytesNeeded); if (bytesNeeded == 0) { - return NULL; + return nullptr; } uint8_t *data = new uint8_t[bytesNeeded + 1]; @@ -363,180 +363,167 @@ cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const } } -void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, double *ga) +void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, Color::GammaValues &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; + ga.gamma0 = 2.22; //BT709 2.2 4.5 - my preferred as D.Coffin + ga.gamma1 = 0.909995; + ga.gamma2 = 0.090005; + ga.gamma3 = 0.222222; + ga.gamma4 = 0.081071; + ga.gamma5 = 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; + ga.gamma0 = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom + ga.gamma1 = 0.947858; + ga.gamma2 = 0.052142; + ga.gamma3 = 0.077399; + ga.gamma4 = 0.039293; + ga.gamma5 = 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; + ga.gamma0 = 1.3 ; //for high dynamic images + ga.gamma1 = 0.998279; + ga.gamma2 = 0.001721; + ga.gamma3 = 0.298507; + ga.gamma4 = 0.005746; + ga.gamma5 = 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; + ga.gamma0 = 2.6 ; //gamma 2.6 variable : for low contrast images + ga.gamma1 = 0.891161; + ga.gamma2 = 0.108839; + ga.gamma3 = 0.144928; + ga.gamma4 = 0.076332; + ga.gamma5 = 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; + ga.gamma0 = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) + ga.gamma1 = 1.; + ga.gamma2 = 0.; + ga.gamma3 = 1. / eps; + ga.gamma4 = 0.; + ga.gamma5 = 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; + ga.gamma0 = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) + ga.gamma1 = 1.; + ga.gamma2 = 0.; + ga.gamma3 = 1. / eps; + ga.gamma4 = 0.; + ga.gamma5 = 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; + ga.gamma0 = 1.8; //gamma=1.8 (as gamma of Prophoto) + ga.gamma1 = 1.; + ga.gamma2 = 0.; + ga.gamma3 = 1. / eps; + ga.gamma4 = 0.; + ga.gamma5 = 0.0; } } else { //free gamma selected - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; //gamma parameters + Color::GammaValues g_a; //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; + Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 + ga.gamma4 = g_a.gamma3 * ts; + //printf("g_a.gamma0=%f g_a.gamma1=%f g_a.gamma2=%f g_a.gamma3=%f g_a.gamma4=%f\n", g_a.gamma0,g_a.gamma1,g_a.gamma2,g_a.gamma3,g_a.gamma4); + ga.gamma0 = icm.gampos; + ga.gamma1 = 1. / (1.0 + g_a.gamma4); + ga.gamma2 = g_a.gamma4 / (1.0 + g_a.gamma4); + ga.gamma3 = 1. / slope; + ga.gamma5 = 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; +cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParams &icm, Color::GammaValues &ga) { + float p[6]; //primaries + ga.gamma6 = 0.0; - int t50; - int select_temp = 1; //5003K + enum class ColorTemp { + D50 = 5003, // for Widegamut, Prophoto Best, Beta -> D50 + D65 = 6504 // for sRGB, AdobeRGB, Bruce Rec2020 -> D65 + }; + ColorTemp temp = ColorTemp::D50; //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; + p[0] = 0.7350; //Widegamut primaries + p[1] = 0.2650; + p[2] = 0.1150; + p[3] = 0.8260; + p[4] = 0.1570; + p[5] = 0.0180; } 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; + p[0] = 0.6400; //Adobe primaries + p[1] = 0.3300; + p[2] = 0.2100; + p[3] = 0.7100; + p[4] = 0.1500; + p[5] = 0.0600; + temp = ColorTemp::D65; } 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; + p[0] = 0.6400; // sRGB primaries + p[1] = 0.3300; + p[2] = 0.3000; + p[3] = 0.6000; + p[4] = 0.1500; + p[5] = 0.0600; + temp = ColorTemp::D65; } 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; + p[0] = 0.6400; // Bruce primaries + p[1] = 0.3300; + p[2] = 0.2800; + p[3] = 0.6500; + p[4] = 0.1500; + p[5] = 0.0600; + temp = ColorTemp::D65; } 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; + p[0] = 0.6888; // Beta primaries + p[1] = 0.3112; + p[2] = 0.1986; + p[3] = 0.7551; + p[4] = 0.1265; + p[5] = 0.0352; } 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; + p[0] = 0.7347; // Best primaries + p[1] = 0.2653; + p[2] = 0.2150; + p[3] = 0.7750; + p[4] = 0.1300; + p[5] = 0.0350; } 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; + p[0] = 0.7080; // Rec2020 primaries + p[1] = 0.2920; + p[2] = 0.1700; + p[3] = 0.7970; + p[4] = 0.1310; + p[5] = 0.0460; + temp = ColorTemp::D65; } 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 + p[0] = 0.7347; //ProPhoto and default primaries + p[1] = 0.2653; + p[2] = 0.1596; + p[3] = 0.8404; + p[4] = 0.0366; + p[5] = 0.0001; } cmsCIExyY xyD; cmsCIExyYTRIPLE Primaries = { - {p1, p2, 1.0}, // red - {p3, p4, 1.0}, // green - {p5, p6, 1.0} // blue + {p[0], p[1], 1.0}, // red + {p[2], p[3], 1.0}, // green + {p[4], p[5], 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 + // 7 parameters for smoother curves + cmsFloat64Number Parameters[7] = { ga.gamma0, ga.gamma1, ga.gamma2, ga.gamma3, ga.gamma4, ga.gamma5, ga.gamma6 } ; + + cmsWhitePointFromTemp(&xyD, (double)temp); + GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters); //5 = smoother than 4 cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile cmsFreeToneCurve(GammaTRC[0]); @@ -544,10 +531,10 @@ cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParam return oprofdef; } -cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, double ga[]) { +cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, Color::GammaValues &ga) { bool pro = false; Glib::ustring outProfile; - cmsHPROFILE outputProfile = NULL; + cmsHPROFILE outputProfile = nullptr; if (icm.freegamma && icm.gampos < 1.35) { pro = true; //select profil with gammaTRC modified : @@ -583,7 +570,7 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", icm.working.c_str() ); } - return NULL; + return nullptr; } //begin adaptation rTRC gTRC bTRC @@ -594,16 +581,16 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan outputProfile = iccStore->getProfile(outProfile); //get output profile - if (outputProfile == NULL) { + if (outputProfile == nullptr) { if (settings->verbose) { printf("\"%s\" ICC output profile not found!\n", outProfile.c_str()); } - return NULL; + return nullptr; } // 7 parameters for smoother curves - cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] }; + cmsFloat64Number Parameters[7] = { ga.gamma0, ga.gamma1, ga.gamma2, ga.gamma3, ga.gamma4, ga.gamma5, ga.gamma6 }; //change desc Tag , to "free gamma", or "BT709", etc. cmsMLU *mlu; @@ -611,7 +598,7 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan mlu = cmsMLUalloc(ContextID, 1); // instruction with //ICC are used to generate ICC profile - if (mlu == NULL) { + if (mlu == nullptr) { printf("Description error\n"); } else { @@ -663,8 +650,8 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan } // Calculate output profile's rTRC gTRC bTRC - cmsToneCurve* GammaTRC = NULL; - GammaTRC = cmsBuildParametricToneCurve(NULL, 5, Parameters); + cmsToneCurve* GammaTRC = nullptr; + GammaTRC = cmsBuildParametricToneCurve(nullptr, 5, Parameters); cmsWriteTag(outputProfile, cmsSigRedTRCTag, (void*)GammaTRC ); cmsWriteTag(outputProfile, cmsSigGreenTRCTag, (void*)GammaTRC ); cmsWriteTag(outputProfile, cmsSigBlueTRCTag, (void*)GammaTRC ); @@ -680,14 +667,7 @@ 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; + return fileProfiles.find(name) != fileProfiles.end(); } cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const @@ -735,7 +715,7 @@ cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) const // profile does not exist if (f == fileStdProfilesFileNames.end ()) { - return NULL; + return nullptr; } // but there exists one => load it @@ -761,21 +741,21 @@ ProfileContent ICCStore::getContent (const Glib::ustring& name) const return r != fileProfileContents.end () ? r->second : ProfileContent(); } -std::uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const { MyMutex::MyLock lock (mutex_); return getSupportedIntents (profile, LCMS_USED_AS_INPUT); } -std::uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const { MyMutex::MyLock lock (mutex_); return getSupportedIntents (profile, LCMS_USED_AS_OUTPUT); } -std::uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const +uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const { MyMutex::MyLock lock (mutex_); @@ -792,15 +772,15 @@ void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCD profilesDir = Glib::build_filename (rtICCDir, "output"); fileProfiles.clear(); fileProfileContents.clear(); - loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, NULL, false, true); - loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, NULL, false, true); + loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false, true); + loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false, true); // Input profiles // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) stdProfilesDir = Glib::build_filename (rtICCDir, "input"); fileStdProfiles.clear(); fileStdProfilesFileNames.clear(); - loadProfiles (stdProfilesDir, NULL, NULL, &fileStdProfilesFileNames, true, false); + loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true, false); } // Determine the first monitor default profile of operating system, if selected @@ -843,7 +823,7 @@ void ICCStore::findDefaultMonitorProfile () } } -ProfileContent::ProfileContent (const Glib::ustring& fileName) : data(NULL), length(0) +ProfileContent::ProfileContent (const Glib::ustring& fileName) : data(nullptr), length(0) { FILE* f = g_fopen (fileName.c_str (), "rb"); @@ -870,14 +850,14 @@ ProfileContent::ProfileContent (const ProfileContent& other) data = new char[length + 1]; memcpy (data, other.data, length + 1); } else { - data = NULL; + data = nullptr; } } -ProfileContent::ProfileContent (cmsHPROFILE hProfile) : data(NULL), length(0) +ProfileContent::ProfileContent (cmsHPROFILE hProfile) : data(nullptr), length(0) { - if (hProfile != NULL) { + if (hProfile != nullptr) { cmsUInt32Number bytesNeeded = 0; cmsSaveProfileToMem(hProfile, 0, &bytesNeeded); @@ -901,7 +881,7 @@ ProfileContent& ProfileContent::operator= (const ProfileContent& other) data = new char[length + 1]; memcpy (data, other.data, length + 1); } else { - data = NULL; + data = nullptr; } return *this; @@ -913,7 +893,7 @@ cmsHPROFILE ProfileContent::toProfile () const if (data) { return cmsOpenProfileFromMem (data, length); } else { - return NULL; + return nullptr; } } diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 6aa30033e..dc2c5c12b 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -25,6 +25,7 @@ #include #include #include "procparams.h" +#include "color.h" #include "../rtgui/threadutils.h" namespace rtengine @@ -87,11 +88,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 void getGammaArray(const procparams::ColorManagementParams &icm, Color::GammaValues &ga); 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[]); + static cmsHPROFILE createGammaProfile (const procparams::ColorManagementParams &icm, Color::GammaValues &ga); + static cmsHPROFILE createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, Color::GammaValues &ga); // Main monitors standard profile name, from OS void findDefaultMonitorProfile (); @@ -114,19 +115,19 @@ public: std::vector getProfiles () const; std::vector getProfilesFromDir (const Glib::ustring& dirName) const; - std::uint8_t getInputIntents (cmsHPROFILE profile) const; - std::uint8_t getOutputIntents (cmsHPROFILE profile) const; - std::uint8_t getProofIntents (cmsHPROFILE profile) const; + uint8_t getInputIntents (cmsHPROFILE profile) const; + uint8_t getOutputIntents (cmsHPROFILE profile) const; + uint8_t getProofIntents (cmsHPROFILE profile) const; - std::uint8_t getInputIntents (const Glib::ustring& name) const; - std::uint8_t getOutputIntents (const Glib::ustring& name) const; - std::uint8_t getProofIntents (const Glib::ustring& name) const; + uint8_t getInputIntents (const Glib::ustring& name) const; + uint8_t getOutputIntents (const Glib::ustring& name) const; + uint8_t getProofIntents (const Glib::ustring& name) const; }; #define iccStore ICCStore::getInstance() inline ProfileContent::ProfileContent () : - data(NULL), + data(nullptr), length(0) { } @@ -146,17 +147,17 @@ inline Glib::ustring ICCStore::getDefaultMonitorProfileName () const return defaultMonitorProfile; } -inline std::uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const { return getInputIntents (getProfile (name)); } -inline std::uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const { return getOutputIntents (getProfile (name)); } -inline std::uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const +inline uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const { return getProofIntents (getProfile (name)); } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 5ba2dc5e1..e823b54a1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -23,6 +23,7 @@ #include "../rtgui/ppversion.h" #include "colortemp.h" #include "improcfun.h" +#include "iccstore.h" #ifdef _OPENMP #include #endif diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index c511bf513..283b5007e 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -92,14 +92,14 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con 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]; + Color::GammaValues ga; 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]; + Color::GammaValues ga; iccStore->getGammaArray(icm, ga); oprof = iccStore->createCustomGammaOutputProfile (icm, ga); printf("ImProcFunctions::updateColorProfiles / iccStore->createCustomGammaOutputProfile (icm, ga);\n"); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 559456c32..ad7d6f56a 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -362,7 +362,7 @@ public: 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, 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); + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, Color::GammaValues *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 ee3b35350..eec8987b7 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -280,7 +280,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, * 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) +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, Color::GammaValues *ga) { //gamutmap(lab); @@ -305,9 +305,9 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE oprof = NULL; if (ga) { - iccStore->getGammaArray(icm, ga); - oprof = iccStore->createGammaProfile(icm, ga); - printf("iccStore->createGammaProfile(icm, ga);\n"); + 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()); diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 0f09f1ddd..7a0509966 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -39,6 +39,7 @@ #include "opthelper.h" #include "median.h" #include "EdgePreservingDecomposition.h" +#include "iccstore.h" #ifdef _OPENMP #include diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index a7ca7d86c..27c129a44 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1973,7 +1973,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } else if(retinexParams.gammaretinex == "hig") { retinexgamtab = &(Color::gammatab_145_3); } else if(retinexParams.gammaretinex == "fre") { - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; + Color::GammaValues g_a; double pwr = 1.0 / retinexParams.gam; double gamm = retinexParams.gam; double ts = retinexParams.slope; @@ -1984,21 +1984,21 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } 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 + Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope // 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); double start; double add; if(gamm2 < 1.) { - start = g_a2; - add = g_a4; + start = g_a.gamma2; + add = g_a.gamma4; } else { - start = g_a3; - add = g_a4; + start = g_a.gamma3; + add = g_a.gamma4; } - double mul = 1. + g_a4; + double mul = 1. + g_a.gamma4; lutTonereti(65536); @@ -2245,7 +2245,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } else if(deh.gammaretinex == "hig") { retinexigamtab = &(Color::igammatab_145_3); } else if(deh.gammaretinex == "fre") { - double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5; + Color::GammaValues g_a; double pwr = 1.0 / deh.gam; double gamm = deh.gam; double gamm2 = gamm; @@ -2256,18 +2256,18 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC std::swap(pwr, gamm); } - 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 + Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope - double mul = 1. + g_a4; + double mul = 1. + g_a.gamma4; double add; double start; if(gamm2 < 1.) { - start = g_a3; - add = g_a3; + start = g_a.gamma3; + add = g_a.gamma3; } else { - add = g_a4; - start = g_a2; + add = g_a.gamma4; + start = g_a.gamma2; } // 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); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 270661a33..74b8d6f5a 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1162,9 +1162,9 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 - double ga[7]; + Color::GammaValues ga; // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, ga); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, &ga); customGamma = true; //or selected Free gamma diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index f703169ed..adf950ab0 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -356,7 +356,7 @@ void CurveEditorGroup::setTooltip( Glib::ustring ttip) void CurveEditorGroup::setBatchMode (bool batchMode) { for (std::vector::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) { - (*i)->curveType->addEntry("curveType-unchanged.png", M("GENERAL_UNCHANGED")); + (*i)->curveType->addEntry("unchanged-18.png", M("GENERAL_UNCHANGED")); (*i)->curveType->show(); } } diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index d74d8ee9d..472081c23 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -68,11 +68,12 @@ private: void prepareIntentBox () { - intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + // same order than the enum intentBox.addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); intentBox.addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); - intentBox.setSelected(0); + intentBox.setSelected(1); intentBox.show (); } @@ -146,7 +147,7 @@ private: profile.clear(); intentBox.set_sensitive (false); - intentBox.setSelected (0); + intentBox.setSelected (1); profileBox.set_tooltip_text (""); @@ -158,12 +159,15 @@ private: if (supportsPerceptual || supportsRelativeColorimetric || supportsAbsoluteColorimetric) { intentBox.set_sensitive (true); - intentBox.setItemSensitivity(0, supportsRelativeColorimetric); - intentBox.setItemSensitivity(1, supportsPerceptual); + intentBox.setItemSensitivity(0, supportsPerceptual); + intentBox.setItemSensitivity(1, supportsRelativeColorimetric); intentBox.setItemSensitivity(2, supportsAbsoluteColorimetric); } else { + intentBox.setItemSensitivity(0, true); + intentBox.setItemSensitivity(1, true); + intentBox.setItemSensitivity(2, true); intentBox.set_sensitive (false); - intentBox.setSelected (0); + intentBox.setSelected (1); } profileBox.set_tooltip_text (profileBox.get_active_text ()); @@ -246,10 +250,10 @@ public: switch (options.rtSettings.monitorIntent) { default: - case rtengine::RI_RELATIVE: + case rtengine::RI_PERCEPTUAL: intentBox.setSelected (0); break; - case rtengine::RI_PERCEPTUAL: + case rtengine::RI_RELATIVE: intentBox.setSelected (1); break; case rtengine::RI_ABSOLUTE: @@ -806,8 +810,6 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) } history->resetSnapShotNumber(); - - colorMgmtToolBar->reset (); } void EditorPanel::close () diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 9c8163c8e..4c6d4f4c0 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -26,9 +26,9 @@ #include "../rtengine/improccoordinator.h" #include "../rtengine/color.h" #include "../rtengine/opthelper.h" +#include "../rtengine/iccstore.h" using namespace rtengine; -extern Glib::ustring argv0; extern Options options; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index e1fc802d6..dcb8b30ce 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -193,13 +193,14 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch Gtk::HBox *riHBox = Gtk::manage ( new Gtk::HBox()); Gtk::Label* outputIntentLbl = Gtk::manage (new Gtk::Label(M("TP_ICM_PROFILEINTENT")+":")); riHBox->pack_start (*outputIntentLbl, Gtk::PACK_SHRINK); - ointent = Gtk::manage (new MyComboBoxText ()); - riHBox->pack_start (*ointent, Gtk::PACK_EXPAND_WIDGET); - ointent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); - ointent->append_text (M("PREFERENCES_INTENT_RELATIVE")); - ointent->append_text (M("PREFERENCES_INTENT_SATURATION")); - ointent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); - ointent->set_active (1); + ointent = Gtk::manage (new PopUpButton ()); + ointent->addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + ointent->addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + ointent->addEntry("intent-saturation.png", M("PREFERENCES_INTENT_SATURATION")); + ointent->addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); + ointent->setSelected (1); + ointent->show(); + riHBox->pack_start (*ointent->buttonGroup, Gtk::PACK_EXPAND_PADDING); oVBox->pack_start(*riHBox, Gtk::PACK_SHRINK); // Black Point Compensation @@ -319,6 +320,29 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch show_all (); } +void ICMPanel::updateRenderingIntent (const Glib::ustring &profile) { + const uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; + const bool supportsRelative = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; + const bool supportsSaturation = supportedIntents & 1 << INTENT_SATURATION; + const bool supportsAbsolute = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; + + if (!profile.empty() && (supportsPerceptual || supportsRelative || supportsSaturation || supportsAbsolute)) { + ointent->set_sensitive (true); + ointent->setItemSensitivity(0, supportsPerceptual); + ointent->setItemSensitivity(1, supportsRelative); + ointent->setItemSensitivity(2, supportsSaturation); + ointent->setItemSensitivity(3, supportsAbsolute); + } else { + ointent->setItemSensitivity(0, true); + ointent->setItemSensitivity(1, true); + ointent->setItemSensitivity(2, true); + ointent->setItemSensitivity(3, true); + ointent->set_sensitive (false); + ointent->setSelected (1); + } +} + void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) { @@ -535,7 +559,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) if (onames->get_active_row_number() == -1) { onames->set_active_text (M("TP_ICM_NOICM")); } - ointent->set_active(pp->icm.outputIntent); + ointent->setSelected (pp->icm.outputIntent); obpc->set_active (pp->icm.outputBPC); ckbToneCurve->set_active (pp->icm.toneCurve); @@ -558,6 +582,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) wgamma->set_sensitive(!pp->icm.freegamma); gampos->set_sensitive(pp->icm.freegamma); slpos->set_sensitive(pp->icm.freegamma); + updateRenderingIntent(pp->icm.output); } gampos->setValue (pp->icm.gampos); @@ -582,7 +607,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) } if (!pedited->icm.outputIntent) { - ointent->set_active_text(M("GENERAL_UNCHANGED")); + ointent->setSelected (4); } if (!pedited->icm.dcpIlluminant) { @@ -646,7 +671,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pp->icm.output = onames->get_active_text(); } - int ointentVal = ointent->get_active_row_number(); + int ointentVal = ointent->getSelected (); if (ointentVal >= 0 && ointentVal < RI__COUNT) { pp->icm.outputIntent = static_cast(ointentVal); } else { @@ -690,7 +715,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pedited->icm.input = !iunchanged->get_active (); pedited->icm.working = wnames->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->icm.outputIntent = ointent->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->icm.outputIntent = ointent->getSelected () < 4; pedited->icm.outputBPC = !obpc->get_inconsistent (); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent (); @@ -966,17 +991,37 @@ void ICMPanel::GamChanged() void ICMPanel::opChanged () { + updateRenderingIntent(onames->get_active_text()); if (listener) { listener->panelChanged (EvOProfile, onames->get_active_text()); } } -void ICMPanel::oiChanged () +void ICMPanel::oiChanged (int n) { if (listener) { - listener->panelChanged (EvOIntent, ointent->get_active_text()); + Glib::ustring str; + switch (n) { + case 0: + str = M("PREFERENCES_INTENT_PERCEPTUAL"); + break; + case 1: + str = M("PREFERENCES_INTENT_RELATIVE"); + break; + case 2: + str = M("PREFERENCES_INTENT_SATURATION"); + break; + case 3: + str = M("PREFERENCES_INTENT_ABSOLUTE"); + break; + case 4: + default: + str = M("GENERAL_UNCHANGED"); + break; + } + listener->panelChanged (EvOIntent, str); } } @@ -1104,7 +1149,7 @@ void ICMPanel::setBatchMode (bool batchMode) iVBox->reorder_child (*iunchanged, 5); removeIfThere (this, saveRef); onames->append_text (M("GENERAL_UNCHANGED")); - ointent->append_text (M("GENERAL_UNCHANGED")); + ointent->addEntry("unchanged-22.png", M("GENERAL_UNCHANGED")); wnames->append_text (M("GENERAL_UNCHANGED")); wgamma->append_text (M("GENERAL_UNCHANGED")); dcpIll->append_text (M("GENERAL_UNCHANGED")); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 03c894017..9ce31fbe0 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -25,6 +25,7 @@ #include "guiutils.h" #include "toolpanel.h" +#include "popupbutton.h" #include "../rtengine/imagedata.h" class ICMPanelListener @@ -81,7 +82,7 @@ private: MyComboBoxText* wgamma; MyComboBoxText* onames; - MyComboBoxText* ointent; + PopUpButton* ointent; Gtk::RadioButton* ofromdir; Gtk::RadioButton* ofromfile; Gtk::RadioButton* iunchanged; @@ -98,6 +99,7 @@ private: Glib::ustring lastRefFilename; Glib::ustring camName; void updateDCP(int dcpIlluminant, Glib::ustring dcp_name); + void updateRenderingIntent (const Glib::ustring &profile); public: ICMPanel (); @@ -110,7 +112,7 @@ public: void wpChanged (); void opChanged (); - void oiChanged (); + void oiChanged (int n); void oBPCChanged (); void ipChanged (); void gpChanged (); diff --git a/rtgui/options.cc b/rtgui/options.cc index 9ba8b175a..b1d68560a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -636,7 +636,6 @@ 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" diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 7c325033b..c47b58b7d 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -702,8 +702,9 @@ Gtk::Widget* Preferences::getColorManagementPanel () for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) monProfile->append_text (*profile); - monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + // same order than enum monIntent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); monIntent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); monIntent->set_active (1); @@ -1454,10 +1455,10 @@ void Preferences::storePreferences () switch (monIntent->get_active_row_number ()) { default: case 0: - moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE; + moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; break; case 1: - moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; + moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE; break; case 2: moptions.rtSettings.monitorIntent = rtengine::RI_ABSOLUTE; @@ -1584,10 +1585,10 @@ void Preferences::fillPreferences () setActiveTextOrIndex (*monProfile, moptions.rtSettings.monitorProfile, 0); switch (moptions.rtSettings.monitorIntent) { default: - case rtengine::RI_RELATIVE: + case rtengine::RI_PERCEPTUAL: monIntent->set_active (0); break; - case rtengine::RI_PERCEPTUAL: + case rtengine::RI_RELATIVE: monIntent->set_active (1); break; case rtengine::RI_ABSOLUTE: diff --git a/tools/source_icons/scalable/spGamutCheck.file b/tools/source_icons/scalable/spGamutCheck.file new file mode 100644 index 000000000..f8b0d6338 --- /dev/null +++ b/tools/source_icons/scalable/spGamutCheck.file @@ -0,0 +1 @@ +spGamutCheck.png,w22,actions diff --git a/tools/source_icons/scalable/spGamutCheck.svg b/tools/source_icons/scalable/spGamutCheck.svg new file mode 100644 index 000000000..9748e3916 --- /dev/null +++ b/tools/source_icons/scalable/spGamutCheck.svg @@ -0,0 +1,1344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + ! + diff --git a/tools/source_icons/scalable/unchanged.file b/tools/source_icons/scalable/unchanged.file new file mode 100644 index 000000000..bfeb052cd --- /dev/null +++ b/tools/source_icons/scalable/unchanged.file @@ -0,0 +1,2 @@ +unchanged-22.png,w22,actions +unchanged-18.png,w18,actions diff --git a/tools/source_icons/scalable/unchanged.svg b/tools/source_icons/scalable/unchanged.svg new file mode 100644 index 000000000..f0178a78a --- /dev/null +++ b/tools/source_icons/scalable/unchanged.svg @@ -0,0 +1,1357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + From f11ef69cda92b0ed5973a06177802442a8469da3 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 27 Aug 2016 23:20:37 +0200 Subject: [PATCH 03/13] Bugfix --- rtgui/icmpanel.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index dcb8b30ce..0098b4f16 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -991,7 +991,9 @@ void ICMPanel::GamChanged() void ICMPanel::opChanged () { - updateRenderingIntent(onames->get_active_text()); + if (!batchMode) { + updateRenderingIntent(onames->get_active_text()); + } if (listener) { listener->panelChanged (EvOProfile, onames->get_active_text()); @@ -1150,6 +1152,7 @@ void ICMPanel::setBatchMode (bool batchMode) removeIfThere (this, saveRef); onames->append_text (M("GENERAL_UNCHANGED")); ointent->addEntry("unchanged-22.png", M("GENERAL_UNCHANGED")); + ointent->show(); wnames->append_text (M("GENERAL_UNCHANGED")); wgamma->append_text (M("GENERAL_UNCHANGED")); dcpIll->append_text (M("GENERAL_UNCHANGED")); From 7c7cb9f9f12022de17adeee86271dc8c3bc5719c Mon Sep 17 00:00:00 2001 From: Hombre Date: Mon, 29 Aug 2016 21:04:59 +0200 Subject: [PATCH 04/13] Bug fix: the monitor profile and softproofing profile are now computed automatically even without special trigger event. The order of the Monitor Intent is now correct. --- rtengine/improccoordinator.cc | 7 +++++-- rtengine/improccoordinator.h | 7 +++++++ rtgui/editorpanel.cc | 6 +++--- rtgui/options.cc | 2 +- rtgui/preferences.cc | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index b0064bddb..3bcb2699b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -88,7 +88,7 @@ ImProcCoordinator::ImProcCoordinator () fullw(1), fullh(1), pW(-1), pH(-1), plistener(NULL), imageListener(NULL), aeListener(NULL), acListener(NULL), abwListener(NULL), actListener(NULL), adnListener(NULL), awavListener(NULL), dehaListener(NULL), hListener(NULL), - resultValid(false), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), wavcontlutili(false), + resultValid(false), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), wavcontlutili(false), butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), conversionBuffer(1, 1) {} @@ -778,7 +778,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } // Update the monitor color transform if necessary - if (todo & M_MONITOR) { + if ((todo & M_MONITOR) || (lastOutputProfile!=params.icm.output) || lastOutputIntent!=params.icm.outputIntent || lastOutputBPC!=params.icm.outputBPC) { + lastOutputProfile = params.icm.output; + lastOutputIntent = params.icm.outputIntent; + lastOutputBPC = params.icm.outputBPC; ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent, softProof, gamutCheck); } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 4e7a8d62e..f20853d6d 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -180,6 +180,13 @@ protected: MyMutex mProcessing; ProcParams params; + // for optimization purpose, the output profile, output rendering intent and + // output BPC will trigger a regeneration of the profile on parameter change only + // and automatically + Glib::ustring lastOutputProfile; + RenderingIntent lastOutputIntent; + bool lastOutputBPC; + // members of the updater: Glib::Thread* thread; MyMutex updaterThreadStart; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 472081c23..3323c795d 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -68,7 +68,7 @@ private: void prepareIntentBox () { - // same order than the enum + // same order as the enum intentBox.addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); intentBox.addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); @@ -177,10 +177,10 @@ private: switch (intentBox.getSelected ()) { default: case 0: - intent = rtengine::RI_RELATIVE; + intent = rtengine::RI_PERCEPTUAL; break; case 1: - intent = rtengine::RI_PERCEPTUAL; + intent = rtengine::RI_RELATIVE; break; case 2: intent = rtengine::RI_ABSOLUTE; diff --git a/rtgui/options.cc b/rtgui/options.cc index b1d68560a..66d84914b 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -2107,7 +2107,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_boolean ("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/preferences.cc b/rtgui/preferences.cc index c47b58b7d..980fc0702 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -702,7 +702,7 @@ Gtk::Widget* Preferences::getColorManagementPanel () for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) monProfile->append_text (*profile); - // same order than enum + // same order as the enum monIntent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); monIntent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); From d762ef45109e2dd9afc8239c0cfce9e84aa43616 Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 30 Aug 2016 02:06:10 +0200 Subject: [PATCH 05/13] Bugfix + cleanup --- rtengine/improccoordinator.cc | 5 +++++ rtengine/improcfun.cc | 3 --- rtgui/icmpanel.cc | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 3bcb2699b..4aa0b8243 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -779,6 +779,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) // Update the monitor color transform if necessary if ((todo & M_MONITOR) || (lastOutputProfile!=params.icm.output) || lastOutputIntent!=params.icm.outputIntent || lastOutputBPC!=params.icm.outputBPC) { + if (lastOutputIntent == RI__COUNT) { + // initializing... + monitorProfile = options.rtSettings.monitorProfile; + monitorIntent = options.rtSettings.monitorIntent; + } lastOutputProfile = params.icm.output; lastOutputIntent = params.icm.outputIntent; lastOutputBPC = params.icm.outputBPC; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index b53254959..081afdf43 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -95,17 +95,14 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con Color::GammaValues ga; 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 Color::GammaValues ga; 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()); } } diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 0098b4f16..ea258a319 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -321,12 +321,14 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch } void ICMPanel::updateRenderingIntent (const Glib::ustring &profile) { - const uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const uint8_t supportedIntents = rtengine::iccStore->getOutputIntents (profile); const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; const bool supportsRelative = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; const bool supportsSaturation = supportedIntents & 1 << INTENT_SATURATION; const bool supportsAbsolute = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; + //printf("Intents: %d / Perceptual: %d Relative: %d Saturation: %d Absolute: %d\n", supportedIntents, supportsPerceptual, supportsRelative, supportsSaturation, supportsAbsolute); + if (!profile.empty() && (supportsPerceptual || supportsRelative || supportsSaturation || supportsAbsolute)) { ointent->set_sensitive (true); ointent->setItemSensitivity(0, supportsPerceptual); From 72db91b574ebd1bfdda1a12ac1bbcae975dcd056 Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 30 Aug 2016 03:16:22 +0200 Subject: [PATCH 06/13] Updated color_management.svg explanation file --- tools/color_management.svg | 505 +++++++++++++++++++++++++++---------- 1 file changed, 365 insertions(+), 140 deletions(-) diff --git a/tools/color_management.svg b/tools/color_management.svg index 0307fa81c..d60fcefd3 100644 --- a/tools/color_management.svg +++ b/tools/color_management.svg @@ -18,6 +18,63 @@ sodipodi:docname="color_management.svg"> + + + + + + + + + + + + + inkscape:isstock="true" + inkscape:collect="always"> image/svg+xml - + @@ -208,115 +266,114 @@ inkscape:groupmode="layer" id="layer1" transform="translate(0,-308.26772)"> + + id="path9187" + d="m 548.40112,670.64952 0,50.45433" + style="fill:none;fill-rule:evenodd;stroke:#b049e1;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker9189)" /> + + + + style="opacity:1;fill:#ffffff;fill-opacity:0.71270716;fill-rule:nonzero;stroke:none;stroke-width:7;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect10399" + width="169.52106" + height="31.025021" + x="599.28571" + y="405.36221" /> + + + Output ICC profile & intent + + + Monitor ICC profile & intent + id="g9171" + transform="translate(65.286377,16)"> - Espace couleurde travail (WCS) - - - - Profile ICC/ICMde sortie - - - - Profile ICC/ICMdu moniteur - - - Moniteur + sodipodi:role="line">Monitor + id="g9176" + transform="translate(68.218231,40)"> Imprimante + sodipodi:role="line">Printer - Fichier de sortie + + + Output file + + Epreuvage écran + x="471.19366" + y="469.87708" + style="font-size:10px">Soft-proofing path(Output Black Point Compensation) options.rtSettings.HistogramWorking + sodipodi:role="line" + style="font-size:10px;text-align:center;text-anchor:middle">Only ifoptions.rtSettings.HistogramWorking = 1(Output Black Point Compensation) + x="359.46707" + y="361.55499" /> + transform="translate(322.64831,127.10442)"> Image L*a*b + sodipodi:role="line">L*a*b image Fin du pipeline + sodipodi:role="line">End of pipeline + Normal path(Monitor Black Point Compensation) + + Used fo image analysis only withoptions.rtSettings.HistogramWorking = 1 + Used fo image analysis withoptions.rtSettings.HistogramWorking = 0 + + Working space profile (output intent) + "Working" image + Output image * + Preview image + sodipodi:nodetypes="cc" /> + * When options.rtSettings.HistogramWorking = 1 and soft-proofing is enabled, the Output image does not really exist, i.e. no memory is allocated, the CMM only makes a double conversion of each pixel of the Lab image From d31de41f68cfcb9c3f5043987fdba0d882eed550 Mon Sep 17 00:00:00 2001 From: Hombre Date: Wed, 31 Aug 2016 23:40:27 +0200 Subject: [PATCH 07/13] Cleaner implementation of the gamma array (more C++11) --- rtengine/color.cc | 14 ++--- rtengine/color.h | 13 +---- rtengine/iccstore.cc | 108 ++++++++++++++++++------------------- rtengine/iccstore.h | 6 +-- rtengine/improcfun.cc | 4 +- rtengine/improcfun.h | 2 +- rtengine/iplab2rgb.cc | 2 +- rtengine/rawimagesource.cc | 24 ++++----- rtengine/simpleprocess.cc | 2 +- 9 files changed, 81 insertions(+), 94 deletions(-) diff --git a/rtengine/color.cc b/rtengine/color.cc index 949e3c52e..41b7e7293 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -1469,13 +1469,13 @@ void Color::calcGamma (double pwr, double ts, int mode, int imax, GammaValues &g } if (!mode--) { - gamma.gamma0 = g[0]; - gamma.gamma1 = g[1]; - gamma.gamma2 = g[2]; - gamma.gamma3 = g[3]; - gamma.gamma4 = g[4]; - gamma.gamma5 = g[5]; - gamma.gamma6 = 0.; + gamma[0] = g[0]; + gamma[1] = g[1]; + gamma[2] = g[2]; + gamma[3] = g[3]; + gamma[4] = g[4]; + gamma[5] = g[5]; + gamma[6] = 0.; return; } } diff --git a/rtengine/color.h b/rtengine/color.h index b08ad5948..03ae5afb4 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -30,6 +30,8 @@ namespace rtengine { +typedef std::array GammaValues; + #ifdef _DEBUG class MunsellDebugInfo @@ -95,17 +97,6 @@ private: #endif public: - class GammaValues { - public: - double gamma0; - double gamma1; - double gamma2; - double gamma3; - double gamma4; - double gamma5; - double gamma6; - }; - typedef enum Channel { CHANNEL_RED = 1 << 0, CHANNEL_GREEN = 1 << 1, diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 559a5d009..166ee1cc9 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -363,83 +363,79 @@ cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const } } -void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, Color::GammaValues &ga) +void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &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.gamma0 = 2.22; //BT709 2.2 4.5 - my preferred as D.Coffin - ga.gamma1 = 0.909995; - ga.gamma2 = 0.090005; - ga.gamma3 = 0.222222; - ga.gamma4 = 0.081071; - ga.gamma5 = 0.0; + 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; } else if (icm.gamma == "sRGB_g2.4_s12.92") { - ga.gamma0 = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom - ga.gamma1 = 0.947858; - ga.gamma2 = 0.052142; - ga.gamma3 = 0.077399; - ga.gamma4 = 0.039293; - ga.gamma5 = 0.0; + 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; } else if (icm.gamma == "High_g1.3_s3.35") { - ga.gamma0 = 1.3 ; //for high dynamic images - ga.gamma1 = 0.998279; - ga.gamma2 = 0.001721; - ga.gamma3 = 0.298507; - ga.gamma4 = 0.005746; - ga.gamma5 = 0.0; + ga[0] = 1.3 ; //for high dynamic images + ga[1] = 0.998279; + ga[2] = 0.001721; + ga[3] = 0.298507; + ga[4] = 0.005746; } else if (icm.gamma == "Low_g2.6_s6.9") { - ga.gamma0 = 2.6 ; //gamma 2.6 variable : for low contrast images - ga.gamma1 = 0.891161; - ga.gamma2 = 0.108839; - ga.gamma3 = 0.144928; - ga.gamma4 = 0.076332; - ga.gamma5 = 0.0; - } else if (icm.gamma == "linear_g1.0") { - ga.gamma0 = 1.0; //gamma=1 linear : for high dynamic images (cf : D.Coffin...) - ga.gamma1 = 1.; - ga.gamma2 = 0.; - ga.gamma3 = 1. / eps; - ga.gamma4 = 0.; - ga.gamma5 = 0.0; + 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; } else if (icm.gamma == "standard_g2.2") { - ga.gamma0 = 2.2; //gamma=2.2 (as gamma of Adobe, Widegamut...) - ga.gamma1 = 1.; - ga.gamma2 = 0.; - ga.gamma3 = 1. / eps; - ga.gamma4 = 0.; - ga.gamma5 = 0.0; + 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.; } else if (icm.gamma == "standard_g1.8") { - ga.gamma0 = 1.8; //gamma=1.8 (as gamma of Prophoto) - ga.gamma1 = 1.; - ga.gamma2 = 0.; - ga.gamma3 = 1. / eps; - ga.gamma4 = 0.; - ga.gamma5 = 0.0; + ga[0] = 1.8; //gamma=1.8 (as gamma of Prophoto) + ga[1] = 1.; + ga[2] = 0.; + ga[3] = 1. / eps; + ga[4] = 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; + ga[6] = 0.0; } else { //free gamma selected - Color::GammaValues g_a; //gamma parameters + GammaValues g_a; //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_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 - ga.gamma4 = g_a.gamma3 * ts; + ga[4] = g_a[3] * ts; //printf("g_a.gamma0=%f g_a.gamma1=%f g_a.gamma2=%f g_a.gamma3=%f g_a.gamma4=%f\n", g_a.gamma0,g_a.gamma1,g_a.gamma2,g_a.gamma3,g_a.gamma4); - ga.gamma0 = icm.gampos; - ga.gamma1 = 1. / (1.0 + g_a.gamma4); - ga.gamma2 = g_a.gamma4 / (1.0 + g_a.gamma4); - ga.gamma3 = 1. / slope; - ga.gamma5 = 0.0; + ga[0] = icm.gampos; + ga[1] = 1. / (1.0 + g_a[4]); + ga[2] = g_a[4] / (1.0 + g_a[4]); + ga[3] = 1. / slope; + ga[5] = 0.0; + ga[6] = 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, Color::GammaValues &ga) { +cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { float p[6]; //primaries - ga.gamma6 = 0.0; + ga[6] = 0.0; enum class ColorTemp { D50 = 5003, // for Widegamut, Prophoto Best, Beta -> D50 @@ -520,7 +516,7 @@ cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParam cmsToneCurve* GammaTRC[3]; // 7 parameters for smoother curves - cmsFloat64Number Parameters[7] = { ga.gamma0, ga.gamma1, ga.gamma2, ga.gamma3, ga.gamma4, ga.gamma5, ga.gamma6 } ; + cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] } ; cmsWhitePointFromTemp(&xyD, (double)temp); GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters); //5 = smoother than 4 @@ -531,7 +527,7 @@ cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParam return oprofdef; } -cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, Color::GammaValues &ga) { +cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { bool pro = false; Glib::ustring outProfile; cmsHPROFILE outputProfile = nullptr; @@ -590,7 +586,7 @@ cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorMan } // 7 parameters for smoother curves - cmsFloat64Number Parameters[7] = { ga.gamma0, ga.gamma1, ga.gamma2, ga.gamma3, ga.gamma4, ga.gamma5, ga.gamma6 }; + 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; diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index dc2c5c12b..ac52c998a 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -88,11 +88,11 @@ public: void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir); - static void getGammaArray(const procparams::ColorManagementParams &icm, Color::GammaValues &ga); + static void getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga); 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, Color::GammaValues &ga); - static cmsHPROFILE createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, Color::GammaValues &ga); + static cmsHPROFILE createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga); + static cmsHPROFILE createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga); // Main monitors standard profile name, from OS void findDefaultMonitorProfile (); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 081afdf43..7b98e54aa 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -92,13 +92,13 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con if (softProof) { cmsHPROFILE oprof; if(icm.gamma != "default" || icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 - Color::GammaValues ga; + GammaValues ga; iccStore->getGammaArray(icm, ga); oprof = iccStore->createGammaProfile (icm, ga); } 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 - Color::GammaValues ga; + GammaValues ga; iccStore->getGammaArray(icm, ga); oprof = iccStore->createCustomGammaOutputProfile (icm, ga); } else { diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index ad7d6f56a..04b234cbd 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -362,7 +362,7 @@ public: 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, const procparams::ColorManagementParams &icm); - Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, Color::GammaValues *ga=NULL); + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *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 eec8987b7..62af03f0a 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -280,7 +280,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, * 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, Color::GammaValues *ga) +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *ga) { //gamutmap(lab); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 27c129a44..8b19f3841 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1973,7 +1973,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } else if(retinexParams.gammaretinex == "hig") { retinexgamtab = &(Color::gammatab_145_3); } else if(retinexParams.gammaretinex == "fre") { - Color::GammaValues g_a; + GammaValues g_a; double pwr = 1.0 / retinexParams.gam; double gamm = retinexParams.gam; double ts = retinexParams.slope; @@ -1991,14 +1991,14 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar double add; if(gamm2 < 1.) { - start = g_a.gamma2; - add = g_a.gamma4; + start = g_a[2]; + add = g_a[4]; } else { - start = g_a.gamma3; - add = g_a.gamma4; + start = g_a[3]; + add = g_a[4]; } - double mul = 1. + g_a.gamma4; + double mul = 1. + g_a[4]; lutTonereti(65536); @@ -2245,7 +2245,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } else if(deh.gammaretinex == "hig") { retinexigamtab = &(Color::igammatab_145_3); } else if(deh.gammaretinex == "fre") { - Color::GammaValues g_a; + GammaValues g_a; double pwr = 1.0 / deh.gam; double gamm = deh.gam; double gamm2 = gamm; @@ -2258,16 +2258,16 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC Color::calcGamma(pwr, ts, mode, imax, g_a); // call to calcGamma with selected gamma and slope - double mul = 1. + g_a.gamma4; + double mul = 1. + g_a[4]; double add; double start; if(gamm2 < 1.) { - start = g_a.gamma3; - add = g_a.gamma3; + start = g_a[3]; + add = g_a[3]; } else { - add = g_a.gamma4; - start = g_a.gamma2; + add = g_a[4]; + start = g_a[2]; } // 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); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 62e16f2f0..a01597d96 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1162,7 +1162,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 - Color::GammaValues ga; + GammaValues ga; // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, &ga); customGamma = true; From c96c7dc8f396805fda1c74d01509607ebdece050 Mon Sep 17 00:00:00 2001 From: Hombre Date: Fri, 2 Sep 2016 16:23:21 +0200 Subject: [PATCH 08/13] Soft-proofing ang GamutCheck buttons are now disabled if Monitor profile == NONE of is no suported intent for the selected profile. The Monitor profile list (in the Editor and in Preferences) shows RGB profiles only, whereas the output profile list shows all profiles (RGB, CMYK, ... anything!) Bugfix: When switching to a new image, the image now use the selected profile and intent. --- rtengine/iccstore.cc | 17 ++++++++------- rtengine/iccstore.h | 2 +- rtengine/improccoordinator.cc | 5 ----- rtgui/editorpanel.cc | 39 ++++++++++++++++++++++++++++------- rtgui/preferences.cc | 2 +- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 166ee1cc9..b0be63151 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -40,7 +40,7 @@ void loadProfiles (const Glib::ustring& dirName, std::map* profiles, std::map* profileContents, std::map* profileNames, - bool nameUpper, bool onlyRgb) + bool nameUpper) { if (dirName.empty ()) { return; @@ -80,7 +80,7 @@ void loadProfiles (const Glib::ustring& dirName, const ProfileContent content (filePath); const cmsHPROFILE profile = content.toProfile (); - if (profile && (!onlyRgb || cmsGetColorSpace (profile) == cmsSigRgbData)) { + if (profile) { profiles->insert (std::make_pair (name, profile)); if (profileContents) { @@ -165,7 +165,7 @@ std::vector getWorkingProfiles () return res; } -std::vector ICCStore::getProfiles () const +std::vector ICCStore::getProfiles (const bool onlyRgb) const { MyMutex::MyLock lock(mutex_); @@ -173,6 +173,7 @@ std::vector ICCStore::getProfiles () const std::vector res; for (ProfileMap::const_iterator profile = fileProfiles.begin (); profile != fileProfiles.end (); ++profile) { + if (!onlyRgb || (onlyRgb && cmsGetColorSpace (profile->second) == cmsSigRgbData)) res.push_back (profile->first); } @@ -188,8 +189,8 @@ std::vector ICCStore::getProfilesFromDir (const Glib::ustring& di ProfileMap profiles; - loadProfiles (profilesDir, &profiles, nullptr, nullptr, false, true); - loadProfiles (dirName, &profiles, nullptr, nullptr, false, true); + loadProfiles (profilesDir, &profiles, nullptr, nullptr, false); + loadProfiles (dirName, &profiles, nullptr, nullptr, false); for (ProfileMap::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) { res.push_back (profile->first); @@ -768,15 +769,15 @@ void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCD profilesDir = Glib::build_filename (rtICCDir, "output"); fileProfiles.clear(); fileProfileContents.clear(); - loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false, true); - loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false, true); + loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, nullptr, false); + loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, nullptr, false); // Input profiles // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) stdProfilesDir = Glib::build_filename (rtICCDir, "input"); fileStdProfiles.clear(); fileStdProfilesFileNames.clear(); - loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true, false); + loadProfiles (stdProfilesDir, nullptr, nullptr, &fileStdProfilesFileNames, true); } // Determine the first monitor default profile of operating system, if selected diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index ac52c998a..0c49a7e4c 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -112,7 +112,7 @@ public: cmsHPROFILE getXYZProfile () const; cmsHPROFILE getsRGBProfile () const; - std::vector getProfiles () const; + std::vector getProfiles (const bool onlyRgb = false) const; std::vector getProfilesFromDir (const Glib::ustring& dirName) const; uint8_t getInputIntents (cmsHPROFILE profile) const; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 4aa0b8243..3bcb2699b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -779,11 +779,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) // Update the monitor color transform if necessary if ((todo & M_MONITOR) || (lastOutputProfile!=params.icm.output) || lastOutputIntent!=params.icm.outputIntent || lastOutputBPC!=params.icm.outputBPC) { - if (lastOutputIntent == RI__COUNT) { - // initializing... - monitorProfile = options.rtSettings.monitorProfile; - monitorIntent = options.rtSettings.monitorIntent; - } lastOutputProfile = params.icm.output; lastOutputIntent = params.icm.outputIntent; lastOutputBPC = params.icm.outputBPC; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 3323c795d..50297632a 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -59,7 +59,7 @@ private: profileBox.set_active (0); #endif - const std::vector profiles = rtengine::iccStore->getProfiles (); + const std::vector profiles = rtengine::iccStore->getProfiles (true); for (std::vector::const_iterator iterator = profiles.begin (); iterator != profiles.end (); ++iterator) { profileBox.append_text (*iterator); } @@ -119,7 +119,7 @@ private: updateSoftProofParameters (); } - void updateParameters () + void updateParameters (bool noEvent = false) { ConnectionBlocker profileBlocker (profileConn); ConnectionBlocker intentBlocker (intentConn); @@ -148,6 +148,8 @@ private: intentBox.set_sensitive (false); intentBox.setSelected (1); + softProof.set_sensitive(false); + spGamutCheck.set_sensitive(false); profileBox.set_tooltip_text (""); @@ -162,12 +164,16 @@ private: intentBox.setItemSensitivity(0, supportsPerceptual); intentBox.setItemSensitivity(1, supportsRelativeColorimetric); intentBox.setItemSensitivity(2, supportsAbsoluteColorimetric); + softProof.set_sensitive(true); + spGamutCheck.set_sensitive(true); } else { intentBox.setItemSensitivity(0, true); intentBox.setItemSensitivity(1, true); intentBox.setItemSensitivity(2, true); intentBox.set_sensitive (false); intentBox.setSelected (1); + softProof.set_sensitive(false); + spGamutCheck.set_sensitive(false); } profileBox.set_tooltip_text (profileBox.get_active_text ()); @@ -191,19 +197,28 @@ private: return; } - processor->beginUpdateParams (); + if (!noEvent) { + processor->beginUpdateParams (); + } processor->setMonitorProfile (profile, intent); - processor->endUpdateParams (rtengine::EvMonitorTransform); + processor->setSoftProofing (softProof.get_sensitive() && softProof.get_active(), spGamutCheck.get_sensitive() && spGamutCheck.get_active()); + if (!noEvent) { + processor->endUpdateParams (rtengine::EvMonitorTransform); + } } - void updateSoftProofParameters () + void updateSoftProofParameters (bool noEvent = false) { 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); + if (!noEvent) { + processor->beginUpdateParams (); + } + processor->setSoftProofing (softProof.get_sensitive() && softProof.get_active(), spGamutCheck.get_sensitive() && spGamutCheck.get_active()); + if (!noEvent) { + processor->endUpdateParams (rtengine::EvMonitorTransform); + } } } @@ -232,6 +247,13 @@ public: box->pack_end (profileBox, Gtk::PACK_SHRINK, 0); } + void updateProcessor() + { + if (processor) { + updateParameters(true); + } + } + void reset () { ConnectionBlocker profileBlocker (profileConn); @@ -762,6 +784,7 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) this->isrc = isrc; ipc = rtengine::StagedImageProcessor::create (isrc); ipc->setProgressListener (this); + colorMgmtToolBar->updateProcessor(); ipc->setPreviewImageListener (previewHandler); ipc->setPreviewScale (10); // Important tpc->initImage (ipc, tmb->getType() == FT_Raw); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 980fc0702..28f5e2096 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -698,7 +698,7 @@ Gtk::Widget* Preferences::getColorManagementPanel () monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); monProfile->set_active (0); - const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (); + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (true); for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) monProfile->append_text (*profile); From a69c631f22a76e3ed4085fd7717d4a4082e372b5 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 3 Sep 2016 00:49:35 +0200 Subject: [PATCH 09/13] Fix issue #3411 + revert some code to the old one for better readability --- rtengine/iccstore.cc | 3 +- rtengine/image16.cc | 16 +++---- rtengine/image16.h | 2 +- rtengine/iplab2rgb.cc | 97 ++++++++---------------------------------- rtengine/procparams.cc | 2 +- rtengine/settings.h | 2 +- rtgui/paramsedited.cc | 2 - 7 files changed, 31 insertions(+), 93 deletions(-) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index b0be63151..13d1fbbdd 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -519,11 +519,12 @@ cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParam // 7 parameters for smoother curves cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] } ; + lcmsMutex->lock (); cmsWhitePointFromTemp(&xyD, (double)temp); GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters); //5 = smoother than 4 cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile - cmsFreeToneCurve(GammaTRC[0]); + lcmsMutex->unlock (); return oprofdef; } diff --git a/rtengine/image16.cc b/rtengine/image16.cc index d57bcf6a9..f41ccd036 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -326,7 +326,7 @@ Image16::tofloat() } // Parallized transformation; create transform with cmsFLAGS_NOCACHE! -void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage) +void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy) { // LittleCMS cannot parallelize planar Lab float images // so build temporary buffers to allow multi processor execution @@ -341,15 +341,15 @@ void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImag #pragma omp for schedule(static) #endif - for (int y = 0; y < height; y++) + for (int y = cy; y < cy + height; 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]; + pL = labImage.L[y] + cx; + pa = labImage.a[y] + cx; + pb = labImage.b[y] + cx; for (int x = 0; x < width; x++) { *(pLab++) = *(pL++) / 327.68f; @@ -360,9 +360,9 @@ void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImag cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width); pRGB = bufferRGB.data; - pR = r(y); - pG = g(y); - pB = b(y); + pR = r(y - cy); + pG = g(y - cy); + pB = b(y - cy); for (int x = 0; x < width; x++) { *(pR++) = *(pRGB++); diff --git a/rtengine/image16.h b/rtengine/image16.h index 7fcff307f..58e142560 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -96,7 +96,7 @@ public: delete this; } - void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage); + void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); }; } diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 62af03f0a..01144b397 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -238,14 +238,14 @@ 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]; - uint8_t* dest = image->r(i - cy) + cx; + int ix = 3 * i * cw; for (int j = cx; j < cx + cw; j++) { - 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 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 * Color::f2xyz(fx) * Color::D50x; //float y_ = 65535.0f * Color::f2xyz(fy); @@ -254,9 +254,9 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb); - *(dest++) = (int)Color::gamma2curve[CLIP(R)] >> 8; - *(dest++) = (int)Color::gamma2curve[CLIP(G)] >> 8; - *(dest++) = (int)Color::gamma2curve[CLIP(B)] >> 8; + image->data[ix++] = (int)Color::gamma2curve[R] >> 8; + image->data[ix++] = (int)Color::gamma2curve[G] >> 8; + image->data[ix++] = (int)Color::gamma2curve[B] >> 8; } } } @@ -314,63 +314,6 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int } if (oprof) { - - - /* - - -#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) + cx; - short* ya = (short*)image->g(i - cy) + cx; - short* za = (short*)image->b(i - cy) + cx; - - for (int j = 0; j < cw; j++) { - - 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 * 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 = 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 = (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; @@ -378,12 +321,11 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int } else printf("lab2rgb16 / icm.outputBPC=false / outputIntent=%d\n", icm.outputIntent); lcmsMutex->lock (); - //cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, icm.outputIntent, flags); + cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_16, icm.outputIntent, flags); lcmsMutex->unlock (); - //image->ExecCMSTransform(hTransform); - image->ExecCMSTransform(hTransform, *lab); + image->ExecCMSTransform(hTransform, *lab, cx, cy); cmsDeleteTransform(hTransform); } else { // @@ -395,16 +337,13 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int 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 = 0; j < cw; j++) { + for (int j = cx; j < cx + cw; j++) { - 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 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 * Color::f2xyz(fx) * Color::D50x; //float y_ = 65535.0 * Color::f2xyz(fy); @@ -413,9 +352,9 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int Color::xyz2srgb(x_, y_, z_, R, G, B); - *(rR++) = (int)Color::gamma2curve[CLIP(R)]; - *(rG++) = (int)Color::gamma2curve[CLIP(G)]; - *(rB++) = (int)Color::gamma2curve[CLIP(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)]; } } } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index a5a2515a5..69cdd17c5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -5930,7 +5930,7 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) icm.outputBPC = keyFile.get_boolean ("Color Management", "OutputBPC"); if (pedited) { - pedited->icm.gamfree = true; + pedited->icm.outputBPC = true; } } diff --git a/rtengine/settings.h b/rtengine/settings.h index 3c728f061..4599a28a7 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -40,7 +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 monitorBPC; ///< Black Point Compensation for the Labimage->Monitor transform (directly, i.e. not soft-proofing and no WCS in between) 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/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index b448cd2ee..ff3e4c0b1 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -2216,8 +2216,6 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten 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) { toEdit.icm.gampos = dontforceSet && options.baBehav[ADDSET_FREE_OUPUT_GAMMA] ? toEdit.icm.gampos + mods.icm.gampos : mods.icm.gampos; } From a9fc506ac96e5d5f5e9561fc33c2de5f52d39e55 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 3 Sep 2016 23:29:26 +0200 Subject: [PATCH 10/13] Bugfix: the options file were reseted unexpectedly The error was that it was reading a wrong value, which thrown an exception, but the error was diplayed in verbose mode only. Bug fixed, and now it'll report any error in evry case. --- rtgui/options.cc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index 8bf8de19f..774afde2e 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -1473,7 +1473,7 @@ int Options::readFromFile (Glib::ustring fname) rtSettings.monitorIntent = static_cast(keyFile.get_integer("Color Management", "Intent")); } - if (keyFile.has_key ("Color Management", "Intent")) { + if (keyFile.has_key ("Color Management", "MonitorBPC")) { rtSettings.monitorBPC = keyFile.get_boolean("Color Management", "MonitorBPC"); } @@ -1796,13 +1796,9 @@ int Options::readFromFile (Glib::ustring fname) } } catch (Glib::Error &err) { - if (options.rtSettings.verbose) { - printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); - } + printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); } catch (...) { - if (options.rtSettings.verbose) { - printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); - } + printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); } return 1; From ee4749f27197057b97d31056960f76af26bc5357 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 11 Sep 2016 03:49:33 +0200 Subject: [PATCH 11/13] Fix a recursive Mutex lock bug when selecting an output Gamma profile. --- rtengine/iccstore.cc | 6 ++++-- rtengine/iplab2rgb.cc | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 13d1fbbdd..7b52a7a53 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -434,6 +434,7 @@ void ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, Gamma } } +// WARNING: the caller must lock lcmsMutex cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { float p[6]; //primaries ga[6] = 0.0; @@ -519,16 +520,17 @@ cmsHPROFILE ICCStore::createGammaProfile (const procparams::ColorManagementParam // 7 parameters for smoother curves cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] } ; - lcmsMutex->lock (); + //lcmsMutex->lock (); Mutex acquired by the caller cmsWhitePointFromTemp(&xyD, (double)temp); GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, 5, Parameters); //5 = smoother than 4 cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile cmsFreeToneCurve(GammaTRC[0]); - lcmsMutex->unlock (); + //lcmsMutex->unlock (); return oprofdef; } +// WARNING: the caller must lock lcmsMutex cmsHPROFILE ICCStore::createCustomGammaOutputProfile (const procparams::ColorManagementParams &icm, GammaValues &ga) { bool pro = false; Glib::ustring outProfile; diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 01144b397..b82b0ca22 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -305,8 +305,10 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE oprof = NULL; if (ga) { + lcmsMutex->lock (); iccStore->getGammaArray(icm, *ga); oprof = iccStore->createGammaProfile(icm, *ga); + lcmsMutex->unlock (); printf("iccStore->createGammaProfile(icm, *ga);\n"); } else { oprof = iccStore->getProfile (icm.output); From a989d440b1ac55645b8caefb6bfec943fd5ca3ef Mon Sep 17 00:00:00 2001 From: Hombre Date: Mon, 10 Oct 2016 23:48:39 +0200 Subject: [PATCH 12/13] Bugfix : RT was crashing if Soft-proofing activated w/ "No ICM" output See issue #3406 --- rtengine/improcfun.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 4855cd21a..5795ed32b 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -90,7 +90,7 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con bool softProofCreated = false; if (softProof) { - cmsHPROFILE oprof; + cmsHPROFILE oprof = nullptr; if(icm.gamma != "default" || icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 GammaValues ga; iccStore->getGammaArray(icm, ga); From 81c5b1ca4197f39ddfd9c98b204c63da235cbb2d Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 11 Oct 2016 23:21:41 +0200 Subject: [PATCH 13/13] Cancelling a 32 bits Tiff workaround, now the Gamma value from embedded ICC profile is correctly handled --- rtengine/imageio.cc | 88 +++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index a9be4e7e3..48d9d81b6 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -771,39 +771,39 @@ int ImageIO::loadTIFF (Glib::ustring fname) * We could use the min/max values set in TIFFTAG_SMINSAMPLEVALUE and * TIFFTAG_SMAXSAMPLEVALUE, but for now, we normalize the image to the * effective minimum and maximum values - * - printf("Informations de \"%s\":\n", fname.c_str()); - uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit; - if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) { - printf(" DefaultScale: %d\n", tiffDefaultScale); - } - else - printf(" No DefaultScale value!\n"); - if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) { - printf(" BaselineExposure: %d\n", tiffBaselineExposure); - } - else - printf(" No BaselineExposure value!\n"); - if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) { - printf(" LinearResponseLimit: %d\n", tiffLinearResponseLimit); - } - else - printf(" No LinearResponseLimit value!\n"); + */ + if (options.rtSettings.verbose) { + printf("Informations of \"%s\":\n", fname.c_str()); + uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit; + if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) { + printf(" DefaultScale: %d\n", tiffDefaultScale); + } + else + printf(" No DefaultScale value!\n"); + if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) { + printf(" BaselineExposure: %d\n", tiffBaselineExposure); + } + else + printf(" No BaselineExposure value!\n"); + if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) { + printf(" LinearResponseLimit: %d\n", tiffLinearResponseLimit); + } + else + printf(" No LinearResponseLimit value!\n"); - uint16 tiffMinValue, tiffMaxValue; - if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) { - printf(" MinValue: %d\n", tiffMinValue); + uint16 tiffMinValue, tiffMaxValue; + if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) { + printf(" MinValue: %d\n", tiffMinValue); + } + else + printf(" No minimum value!\n"); + if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) { + printf(" MaxValue: %d\n\n", tiffMaxValue); + } + else + printf(" No maximum value!\n\n"); + printf(" Those values are not taken into account, the image data are normalized to a [0;1] range\n\n"); } - else - printf(" No minimum value!\n"); - if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) { - printf(" MaxValue: %d\n\n", tiffMaxValue); - } - else - printf(" No maximum value!\n\n"); - printf("\n"); - */ - char* profdata; deleteLoadedProfileData(); @@ -811,30 +811,8 @@ int ImageIO::loadTIFF (Glib::ustring fname) if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &loadedProfileLength, &profdata)) { embProfile = cmsOpenProfileFromMem (profdata, loadedProfileLength); - - // For 32 bits floating point images, gamma is forced to linear in embedded ICC profiles - if ( sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32 | IIOSF_FLOAT) ) { - // Modifying the gammaTRG tags - cmsWriteTag(embProfile, cmsSigGreenTRCTag, (void*)Color::linearGammaTRC ); - cmsWriteTag(embProfile, cmsSigRedTRCTag, (void*)Color::linearGammaTRC ); - cmsWriteTag(embProfile, cmsSigBlueTRCTag, (void*)Color::linearGammaTRC ); - - // Saving the profile in the memory - cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem(embProfile, 0, &bytesNeeded); - - if (bytesNeeded > 0) { - loadedProfileData = new char[bytesNeeded + 1]; - cmsSaveProfileToMem(embProfile, loadedProfileData, &bytesNeeded); - } - - loadedProfileLength = (int)bytesNeeded; - } else { - // Saving the profile in the memory as is - loadedProfileData = new char [loadedProfileLength]; - memcpy (loadedProfileData, profdata, loadedProfileLength); - } - + loadedProfileData = new char [loadedProfileLength]; + memcpy (loadedProfileData, profdata, loadedProfileLength); } else { embProfile = NULL; }