From 5affa18341d732b4821ca49e7f4afcedbe4d3be6 Mon Sep 17 00:00:00 2001 From: Hombre Date: Wed, 24 Aug 2016 22:32:06 +0200 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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; } From e98bd4748717248d6d03636ae321aef9a6352df4 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 12 Oct 2016 19:04:06 +0200 Subject: [PATCH 14/20] Cppcheck: Fix some warnings --- rtengine/EdgePreservingDecomposition.cc | 20 +- rtengine/LUT.h | 2 + rtengine/array2D.h | 7 +- rtengine/color.cc | 4 +- rtengine/curves.cc | 6 +- rtengine/dfmanager.cc | 20 +- rtengine/ffmanager.cc | 22 +- rtengine/ffmanager.h | 2 - rtengine/imagesource.h | 8 +- rtengine/improccoordinator.cc | 20 +- rtengine/improccoordinator.h | 3 +- rtengine/improcfun.cc | 21 +- rtengine/improcfun.h | 20 +- rtgui/rawprocess.cc | 303 ------------------------ rtgui/rawprocess.h | 64 ----- rtgui/thumbbrowserentry.cc | 69 ------ 16 files changed, 66 insertions(+), 525 deletions(-) delete mode 100644 rtgui/rawprocess.cc delete mode 100644 rtgui/rawprocess.h delete mode 100644 rtgui/thumbbrowserentry.cc diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 927bfac2d..06fe38f2b 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -127,15 +127,13 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl #endif { float c = 0.0f; - float t; - float temp; #ifdef _OPENMP #pragma omp for reduction(+:rs) // Summation with error correction #endif for(int ii = 0; ii < n; ii++) { - temp = r[ii] * s[ii]; - t = rs + temp; + float temp = r[ii] * s[ii]; + float t = rs + temp; if( fabsf(rs) >= fabsf(temp) ) { c += ((rs - t) + temp); @@ -183,7 +181,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl return x; } -MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle) +MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle) : buffer(nullptr), DiagBuffer(nullptr) { n = Dimension; m = NumberOfDiagonalsInLowerTriangle; @@ -305,9 +303,9 @@ SSEFUNCTION void MultiDiagonalSymmetricMatrix::VectorProduct(float* RESTRICT Pro const int chunkSize = (lm - srm) / (omp_get_num_procs() * 32); #else const int chunkSize = (lm - srm) / (omp_get_num_procs() * 8); -#endif #endif #pragma omp parallel +#endif { // First fill the big part in the middle // This can be done without intermediate stores to memory and it can be parallelized too @@ -443,8 +441,8 @@ bool MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization(int Max } //It's all initialized? Uhkay. Do the actual math then. - int sss, ss, s; - int k, MaxStartRow = StartRows[m - 1]; //Handy number. + int sss, ss; + int MaxStartRow = StartRows[m - 1]; //Handy number. float **l = ic->Diagonals; float *d = ic->Diagonals[0]; //Describes D in LDLt. int icm = ic->m; @@ -506,8 +504,8 @@ bool MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization(int Max //This is a loop over k from 1 to j, inclusive. We'll cover that by looping over the index of the diagonals (s), and get k from it. //The first diagonal is d (k = 0), so skip that and have s start at 1. Cover all available s but stop if k exceeds j. - s = 1; - k = icStartRows[s]; + int s = 1; + int k = icStartRows[s]; while(k <= j) { d[j] -= l[s][j - k] * l[s][j - k] * d[j - k]; @@ -713,9 +711,7 @@ SSEFUNCTION float *EdgePreservingDecomposition::CreateBlur(float *Source, float a = Blur, g = Source; } - int i; int w1 = w - 1, h1 = h - 1; -// float eps = 0.02f; const float sqreps = 0.0004f; // removed eps*eps from inner loop diff --git a/rtengine/LUT.h b/rtengine/LUT.h index 2d3d91ed5..d83a431ca 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -536,6 +536,8 @@ public: size = 0; upperBound = 0; maxs = 0; + maxsf = 0.f; + clip = 0; } // create an identity LUT (LUT(x) = x) or a scaled identity LUT (LUT(x) = x / divisor) diff --git a/rtengine/array2D.h b/rtengine/array2D.h index db44fcfc8..2d38d2e15 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -74,7 +74,8 @@ class array2D : { private: - int x, y, owner, flags; + int x, y, owner; + unsigned int flags; T ** ptr; T * data; bool lock; // useful lock to ensure data is not changed anymore. @@ -112,7 +113,7 @@ public: // use as empty declaration, resize before use! // very useful as a member object array2D() : - x(0), y(0), owner(0), ptr(NULL), data(NULL), lock(0) + x(0), y(0), owner(0), ptr(NULL), data(NULL), lock(0), flags(0) { //printf("got empty array2D init\n"); } @@ -285,6 +286,8 @@ public: if (this != &rhs) { + flags = rhs.flags; + lock = rhs.lock; if (!owner) { // we can only copy same size data if ((x != rhs.x) || (y != rhs.y)) { printf(" assignment error in array2D\n"); diff --git a/rtengine/color.cc b/rtengine/color.cc index a23a261b7..6dda2c8b8 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -2757,8 +2757,8 @@ SSEFUNCTION void Color::LabGamutMunsell(float *labL, float *laba, float *labb, printf(" Gamut : G1negat=%iiter G165535=%iiter \n", negat, moreRGB); if (MunsDebugInfo) { - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhuelum[0] , MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhuelum[0] , MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); } else { printf(" Munsell correction wasn't requested\n"); } diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 9b68cc9ee..4da4a4a36 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -44,7 +44,7 @@ using namespace std; namespace rtengine { -Curve::Curve () : N(0), x(nullptr), y(nullptr), ypp(nullptr), hashSize(1000 /* has to be initialized to the maximum value */) {} +Curve::Curve () : N(0), ppn(0), x(nullptr), y(nullptr), mc(0.0), mfc(0.0), msc(0.0), mhc(0.0), ypp(nullptr), x1(0.0), y1(0.0), x2(0.0), y2(0.0), x3(0.0), y3(0.0), firstPointIncluded(false), increment(0.0), nbr_points(0), hashSize(1000 /* has to be initialized to the maximum value */) {} void Curve::AddPolygons () { @@ -1434,11 +1434,9 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], double currY = pCurve->getVal(x) - prevY; if (dY > 0.000001 || dY < -0.000001) { - float r1, g1, b1, r2, g2, b2, ro, go, bo; + float r1, g1, b1, r2, g2, b2; Color::hsv2rgb(float(prevY), satur, lr1, r1, g1, b1); Color::hsv2rgb(float(nextY), satur, lr2, r2, g2, b2); - bool chr = false; - bool lum = true; LUTf dum; float X1, X2, Y1, Y2, Z1, Z2, L1, a_1, b_1, c1, h1; Color::rgbxyz(r2, g2, b2, X2, Y2, Z2, xyz_rgb); diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index e06ac27e2..e0dea012b 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -36,16 +36,18 @@ extern const Settings* settings; inline dfInfo& dfInfo::operator =(const dfInfo &o) { - pathname = o.pathname; - maker = o.maker; - model = o.model; - iso = o.iso; - shutter = o.shutter; - timestamp = o.timestamp; + if (this != &o) { + pathname = o.pathname; + maker = o.maker; + model = o.model; + iso = o.iso; + shutter = o.shutter; + timestamp = o.timestamp; - if( ri ) { - delete ri; - ri = NULL; + if( ri ) { + delete ri; + ri = NULL; + } } return *this; diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index 8b26c3121..29121a696 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -31,17 +31,19 @@ extern const Settings* settings; inline ffInfo& ffInfo::operator =(const ffInfo &o) { - pathname = o.pathname; - maker = o.maker; - model = o.model; - lens = o.lens; - shutter = o.shutter; - focallength = o.focallength; - timestamp = o.timestamp; + if (this != &o) { + pathname = o.pathname; + maker = o.maker; + model = o.model; + lens = o.lens; + focallength = o.focallength; + timestamp = o.timestamp; + aperture = o.aperture; - if( ri ) { - delete ri; - ri = NULL; + if( ri ) { + delete ri; + ri = NULL; + } } return *this; diff --git a/rtengine/ffmanager.h b/rtengine/ffmanager.h index 5f6b2d267..f081c5e33 100644 --- a/rtengine/ffmanager.h +++ b/rtengine/ffmanager.h @@ -34,8 +34,6 @@ public: std::string maker; ///< manufacturer std::string model; ///< model std::string lens; ///< lens - int iso; ///< ISO (gain) - double shutter; ///< shutter or exposure time in sec double aperture; ///< aperture in stops double focallength; ///< focal length in mm time_t timestamp; ///< seconds since 1 Jan 1970 diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 305c67da5..65b2b76c0 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -41,10 +41,10 @@ class ImageMatrices { public: - double rgb_cam[3][3]; - double cam_rgb[3][3]; - double xyz_cam[3][3]; - double cam_xyz[3][3]; + double rgb_cam[3][3] = {}; + double cam_rgb[3][3] = {}; + double xyz_cam[3][3] = {}; + double cam_xyz[3][3] = {}; }; class ImageSource : public InitialImage diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 8925b29e0..20eea3011 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -40,8 +40,6 @@ ImProcCoordinator::ImProcCoordinator () hltonecurve(65536), shtonecurve(65536), tonecurve(65536, 0), //,1); - chaut(0.f), redaut(0.f), blueaut(0.f), maxredaut(0.f), maxblueaut(0.f), minredaut(0.f), minblueaut(0.f), nresi(0.f), - chromina(0.f), sigma(0.f), lumema(0.f), lumacurve(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation chroma_acurve(65536, 0), chroma_bcurve(65536, 0), @@ -84,11 +82,12 @@ ImProcCoordinator::ImProcCoordinator () rcurvehist(256), rcurvehistCropped(256), rbeforehist(256), gcurvehist(256), gcurvehistCropped(256), gbeforehist(256), bcurvehist(256), bcurvehistCropped(256), bbeforehist(256), + fw(0), fh(0), tr(0), 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), - butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), conversionBuffer(1, 1) + resultValid(false), thread(NULL), 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), colourToningSatLimit(0.f), colourToningSatLimitOpacity(0.f) {} @@ -138,9 +137,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) int readyphase = 0; bwAutoR = bwAutoG = bwAutoB = -9000.f; - chaut = redaut = blueaut = maxredaut = maxblueaut = nresi = highresi = 0.f; - chromina = sigma = lumema = 0.f; - minredaut = minblueaut = 10000.f; if (todo == CROP && ipf.needsPCVignetting()) { todo |= TRANSFORM; // Change about Crop does affect TRANSFORM @@ -443,11 +439,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, - vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale == 1 ? 1 : 1); + vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, 1); - CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale == 1 ? 1 : 1); + CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 1); + CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 1); + CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 1); opautili = false; @@ -471,7 +467,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } if(params.blackwhite.enabled) { - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, scale == 1 ? 1 : 1); + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1); } colourToningSatLimit = float(params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 0fb0041f3..dd901789f 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -90,7 +90,6 @@ protected: LUTf hltonecurve; LUTf shtonecurve; LUTf tonecurve; - float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema; LUTf lumacurve; LUTf chroma_acurve; @@ -327,7 +326,7 @@ public: } struct DenoiseInfoStore { - DenoiseInfoStore () : valid(false) {} + DenoiseInfoStore () : chM(0), max_r{}, max_b{}, ch_M{}, valid(false) {} float chM; float max_r[9]; float max_b[9]; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 1f41dd6b4..b170ba52f 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -524,7 +524,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh xw2 = xwd; yw2 = ywd; zw2 = zwd; - } else if(params->colorappearance.wbmodel == "RawTCAT02") { + } else /*if(params->colorappearance.wbmodel == "RawTCAT02")*/ { xw1 = xw; // Settings RT WB are used for CAT02 => mix , CAT02 is use for output device (screen: D50 D65, projector: lamp, LED) see preferences yw1 = yw; zw1 = zw; @@ -1034,7 +1034,6 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh // if(!params->epd.enabled || !params->colorappearance.tonecie || !settings->autocielab){ // if(!params->epd.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){ - int posl, posc; double brli = 327.; double chsacol = 327.; int libr = 0; @@ -1065,9 +1064,10 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh jp = true; if(pW != 1) { //only with improccoordinator + int posl; if(libr == 1) { posl = CLIP((int)(Q * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J - } else if(libr == 0) { + } else /*if(libr == 0)*/ { posl = CLIP((int)(J * brli)); //327 for J } @@ -1077,11 +1077,12 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh chropC = true; if(pW != 1) { //only with improccoordinator + int posc; if(colch == 0) { posc = CLIP((int)(C * chsacol)); //450.0 approximative factor for s 320 for M } else if(colch == 1) { posc = CLIP((int)(s * chsacol)); - } else if(colch == 2) { + } else /*if(colch == 2)*/ { posc = CLIP((int)(M * chsacol)); } @@ -1303,7 +1304,6 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh ncie->C_p[i][j] = (ncie->M_p[i][j]) / co_e; //show histogram in CIECAM mode (Q,J, M,s,C) - int posl, posc; double brli = 327.; double chsacol = 327.; int libr = 0; @@ -1335,9 +1335,10 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh jp = true; if(pW != 1) { //only with improccoordinator + int posl; if(libr == 1) { posl = CLIP((int)(ncie->Q_p[i][j] * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J - } else if(libr == 0) { + } else /*if(libr == 0)*/ { posl = CLIP((int)(ncie->J_p[i][j] * brli)); //327 for J } @@ -1347,12 +1348,13 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh chropC = true; if(pW != 1) { //only with improccoordinator + int posc; if(colch == 0) { posc = CLIP((int)(ncie->C_p[i][j] * chsacol)); //450.0 approximative factor for s 320 for M } else if(colch == 1) { sa_t = 100.f * sqrt(ncie->C_p[i][j] / ncie->Q_p[i][j]); //Q_p always > 0 posc = CLIP((int)(sa_t * chsacol)); - } else if(colch == 2) { + } else /*if(colch == 2)*/ { posc = CLIP((int)(ncie->M_p[i][j] * chsacol)); } @@ -1822,7 +1824,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int xw2 = xwd; yw2 = ywd; zw2 = zwd; - } else if(params->colorappearance.wbmodel == "RawTCAT02") { + } else /*if(params->colorappearance.wbmodel == "RawTCAT02")*/ { xw1 = xw; // Settings RT WB are used for CAT02 => mix , CAT02 is use for output device (screen: D50 D65, projector: lamp, LED) see preferences yw1 = yw; zw1 = zw; @@ -2680,8 +2682,6 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int for (int i = 0; i < height; i++) { // update CIECAM with new values after tone-mapping for (int j = 0; j < width; j++) { - float xx, yy, zz; - float x, y, z; // if(epdEnabled) ncie->J_p[i][j]=(100.0f* ncie->Q_p[i][j]*ncie->Q_p[i][j])/(w_h*w_h); if(epdEnabled) { @@ -4663,7 +4663,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float h, s, l; float r = tmpImage->r(i, j); float g = tmpImage->g(i, j); float b = tmpImage->b(i, j); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index ce65bc2f8..7401c871c 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -194,27 +194,9 @@ public: }; double lumimul[3]; -// float chau; -// float chred; -// float chblue; -// float maxchred; -// float maxchblue; -// float minchred; -// float minchblue; -// float resid;//used by noise_residual -// float residred;//used by noise_residual -// float residblue;//used by noise_residual -// int nb; - int nbresid; - float redresid; - float blueresid; -// float maxredresid;//used by noise_residual -// float maxblueresid;//used by noise_residual -// int comptlevel; - ImProcFunctions (const ProcParams* iparams, bool imultiThread = true) - : monitorTransform(NULL), lab2outputTransform(NULL), output2monitorTransform(NULL), params(iparams), scale(1), multiThread(imultiThread) {} + : monitorTransform(NULL), lab2outputTransform(NULL), output2monitorTransform(NULL), params(iparams), scale(1), multiThread(imultiThread), lumimul{} {} ~ImProcFunctions (); void setScale (double iscale); diff --git a/rtgui/rawprocess.cc b/rtgui/rawprocess.cc deleted file mode 100644 index 0ca4350cc..000000000 --- a/rtgui/rawprocess.cc +++ /dev/null @@ -1,303 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "rawprocess.h" -#include "options.h" -#include "guiutils.h" -using namespace rtengine; -using namespace rtengine::procparams; - -RawProcess::RawProcess () : FoldableToolPanel(this) -{ - Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); - dmethod = Gtk::manage (new MyComboBoxText ()); - - for( size_t i = 0; i < procparams::RAWParams::numMethods; i++) { - dmethod->append_text(procparams::RAWParams::methodstring[i]); - } - - dmethod->set_active(0); - hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP")); - - hb1->pack_end (*dmethod, Gtk::PACK_EXPAND_WIDGET, 4); - pack_start( *hb1, Gtk::PACK_SHRINK, 4); - - dcbOptions = Gtk::manage (new Gtk::VBox ()); - dcbOptions->set_border_width(4); - - dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"), 0, 5, 1, 2)); - dcbIterations->setAdjusterListener (this); - - if (dcbIterations->delay < options.adjusterMaxDelay) { - dcbIterations->delay = options.adjusterMaxDelay; - } - - dcbIterations->show(); - dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); - dcbOptions->pack_start(*dcbIterations); - dcbOptions->pack_start(*dcbEnhance); - pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); - - lmmseOptions = Gtk::manage (new Gtk::VBox ()); - lmmseOptions->set_border_width(4); - - lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"), 0, 6, 1, 2)); - lmmseIterations->setAdjusterListener (this); - lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); - - if (lmmseIterations->delay < options.adjusterMaxDelay) { - lmmseIterations->delay = options.adjusterMaxDelay; - } - - lmmseIterations->show(); - lmmseOptions->pack_start(*lmmseIterations); - pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); - - pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); - ccSteps->setAdjusterListener (this); - - if (ccSteps->delay < options.adjusterMaxDelay) { - ccSteps->delay = options.adjusterMaxDelay; - } - - ccSteps->show(); - pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); - - //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - //allOptions = Gtk::manage (new Gtk::VBox ()); - //allOptions->set_border_width(2); - //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); - //allOptions->pack_start(*allEnhance); - //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); - - methodconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &RawProcess::methodChanged) ); - dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::dcbEnhanceChanged), true); - //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::allEnhanceChanged), true); -} - - -void RawProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - methodconn.block (true); - dcbEnhconn.block (true); - //allEnhconn.block (true); - - dmethod->set_active(procparams::RAWParams::numMethods); - - for( size_t i = 0; i < procparams::RAWParams::numMethods; i++) - if( pp->raw.dmethod == procparams::RAWParams::methodstring[i]) { - dmethod->set_active(i); - oldSelection = i; - break; - } - - if(pedited ) { - ccSteps->setEditedState (pedited->raw.ccSteps ? Edited : UnEdited); - dcbIterations->setEditedState ( pedited->raw.dcbIterations ? Edited : UnEdited); - dcbEnhance->set_inconsistent(!pedited->raw.dcbEnhance); - //allEnhance->set_inconsistent(!pedited->raw.allEnhance); - lmmseIterations->setEditedState ( pedited->raw.lmmseIterations ? Edited : UnEdited); - - if( !pedited->raw.dmethod ) { - dmethod->set_active(procparams::RAWParams::numMethods); // No name - } - } - - //allEnhance->set_active(pp->raw.all_enhance); - - dcbIterations->setValue (pp->raw.dcb_iterations); - dcbEnhance->set_active(pp->raw.dcb_enhance); - ccSteps->setValue (pp->raw.ccSteps); - - if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::dcb] || - dmethod->get_active_row_number() == procparams::RAWParams::numMethods) { - dcbOptions->show(); - } else { - dcbOptions->hide(); - } - - lmmseIterations->setValue (pp->raw.lmmse_iterations); - - if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::lmmse] || - dmethod->get_active_row_number() == procparams::RAWParams::numMethods) { - lmmseOptions->show(); - } else { - lmmseOptions->hide(); - } - - // Flase color suppression is applied to all demozaicing method, so don't hide anything - /*if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::eahd] || - pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::hphd] || - pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::vng4]) - ccSteps->show(); - else - ccSteps->hide();*/ - - lastDCBen = pp->raw.dcb_enhance; - //lastALLen = pp->raw.all_enhance; - - methodconn.block (false); - dcbEnhconn.block (false); - //allEnhconn.block (false); - - enableListener (); -} - -void RawProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.ccSteps = ccSteps->getIntValue(); - pp->raw.dcb_iterations = dcbIterations->getIntValue(); - pp->raw.dcb_enhance = dcbEnhance->get_active(); - //pp->raw.all_enhance = allEnhance->get_active(); - pp->raw.lmmse_iterations = lmmseIterations->getIntValue(); - - int currentRow = dmethod->get_active_row_number(); - - if( currentRow >= 0 && currentRow < procparams::RAWParams::numMethods) { - pp->raw.dmethod = procparams::RAWParams::methodstring[currentRow]; - } - - if (pedited) { - pedited->raw.ccSteps = ccSteps->getEditedState (); - pedited->raw.dmethod = dmethod->get_active_row_number() != procparams::RAWParams::numMethods; - pedited->raw.dcbIterations = dcbIterations->getEditedState (); - pedited->raw.dcbEnhance = !dcbEnhance->get_inconsistent(); - //pedited->raw.allEnhance = !allEnhance->get_inconsistent(); - pedited->raw.lmmseIterations = lmmseIterations->getEditedState (); - - } -} - -void RawProcess::setBatchMode(bool batchMode) -{ - dmethod->append_text (M("GENERAL_UNCHANGED")); - dmethod->set_active(procparams::RAWParams::numMethods); // No name - dcbOptions->hide(); - lmmseOptions->hide(); - ToolPanel::setBatchMode (batchMode); - ccSteps->showEditedCB (); - dcbIterations->showEditedCB (); - lmmseIterations->showEditedCB (); - -} - -void RawProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - dcbIterations->setDefault( defParams->raw.dcb_iterations); - lmmseIterations->setDefault( defParams->raw.lmmse_iterations); - ccSteps->setDefault (defParams->raw.ccSteps); - - if (pedited) { - dcbIterations->setDefaultEditedState( pedited->raw.dcbIterations ? Edited : UnEdited); - lmmseIterations->setDefaultEditedState( pedited->raw.lmmseIterations ? Edited : UnEdited); - ccSteps->setDefaultEditedState(pedited->raw.ccSteps ? Edited : UnEdited); - } else { - dcbIterations->setDefaultEditedState( Irrelevant ); - lmmseIterations->setDefaultEditedState( Irrelevant ); - ccSteps->setDefaultEditedState(Irrelevant ); - } -} - -void RawProcess::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - if (a == dcbIterations) { - listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() ); - } else if (a == ccSteps) { - listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); - } else if (a == lmmseIterations) { - listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); - } - - } -} - -void RawProcess::methodChanged () -{ - int curSelection = dmethod->get_active_row_number(); - - if ( curSelection == procparams::RAWParams::dcb) { - dcbOptions->show(); - } else { - dcbOptions->hide(); - } - - if ( curSelection == procparams::RAWParams::lmmse) { - lmmseOptions->show(); - } else { - lmmseOptions->hide(); - } - - Glib::ustring methodName = ""; - bool ppreq = false; - - if( curSelection >= 0 && curSelection < procparams::RAWParams::numMethods) { - methodName = procparams::RAWParams::methodstring[curSelection]; - - if (curSelection == procparams::RAWParams::mono || oldSelection == procparams::RAWParams::mono) { - ppreq = true; - } - } - - oldSelection = curSelection; - - if (listener) { - listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); - } -} - -void RawProcess::dcbEnhanceChanged () -{ - if (batchMode) { - if (dcbEnhance->get_inconsistent()) { - dcbEnhance->set_inconsistent (false); - dcbEnhconn.block (true); - dcbEnhance->set_active (false); - dcbEnhconn.block (false); - } else if (lastDCBen) { - dcbEnhance->set_inconsistent (true); - } - - lastDCBen = dcbEnhance->get_active (); - } - - if (listener) { - listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - -/*void RawProcess::allEnhanceChanged () -{ - if (batchMode) { - if (allEnhance->get_inconsistent()) { - allEnhance->set_inconsistent (false); - allEnhconn.block (true); - allEnhance->set_active (false); - allEnhconn.block (false); - } - else if (lastALLen) - allEnhance->set_inconsistent (true); - - lastALLen = allEnhance->get_active (); - } - if (listener) - listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -}*/ diff --git a/rtgui/rawprocess.h b/rtgui/rawprocess.h deleted file mode 100644 index 85c1c9f44..000000000 --- a/rtgui/rawprocess.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _RAWPROCESS_H_ -#define _RAWPROCESS_H_ - -#include -#include "adjuster.h" -#include "guiutils.h" -#include "toolpanel.h" - - -class RawProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel -{ - -protected: - - MyComboBoxText* dmethod; - Gtk::Label* methodl; - Adjuster* ccSteps; - Gtk::VBox *dcbOptions; - Adjuster* dcbIterations; - Gtk::CheckButton* dcbEnhance; - //Gtk::VBox *allOptions; - //Gtk::CheckButton* allEnhance; - Gtk::VBox *lmmseOptions; - Adjuster* lmmseIterations; - - bool lastDCBen; - int oldSelection; - //bool lastALLen; - sigc::connection methodconn, dcbEnhconn; //,allEnhconn; -public: - - RawProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = NULL); - - void methodChanged (); - void adjusterChanged (Adjuster* a, double newval); - void dcbEnhanceChanged(); - //void allEnhanceChanged(); - -}; - -#endif diff --git a/rtgui/thumbbrowserentry.cc b/rtgui/thumbbrowserentry.cc deleted file mode 100644 index 1c491a641..000000000 --- a/rtgui/thumbbrowserentry.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include - -FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) - : ThumbBrowserEntryBase (fname), thumbnail(thm) -{ - - previewOwner = false; - italicstyle = thumbnail->getType() != FT_Raw; - datetimeline = thumbnail->getDateTimeString (); - exifline = thumbnail->getExifString (); -} - -void ThumbBrowserEntry::obtainThumbnailSize () -{ - - if (thumbnail) { - thumbnail->getThumbnailSize (prew, preh); - } -} -Glib::RefPtr ThumbBrowserEntry::editedIcon; -Glib::RefPtr ThumbBrowserEntry::recentlySavedIcon; -Glib::RefPtr ThumbBrowserEntry::enqueuedIcon; -std::vector > ThumbBrowserEntry::getIconsOnImageArea () -{ - - std::vector > ret; - - if (!thumbnail) { - return ret; - } - - if (thumbnail->hasProcParams() && editedIcon) { - ret.push_back (editedIcon); - } - - if (thumbnail->isRecentlySaved() && recentlySavedIcon) { - ret.push_back (recentlySavedIcon); - } - - if (thumbnail->isEnqueued () && enqueuedIcon) { - ret.push_back (enqueuedIcon); - } - - return ret; -} - -ThumbnailButtonSet* ThumbBrowserEntry::getThumbButtonSet () -{ - - return (ThumbnailButtonSet*)buttonSet; -} From 172ab63b859acb13b19b8474dc94e061cb5d75cc Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 13 Oct 2016 01:34:02 +0200 Subject: [PATCH 15/20] Cppcheck: Fixed another bunch of warnings --- rtengine/camconst.cc | 16 +++++++++++++--- rtengine/color.cc | 6 ++---- rtengine/ipretinex.cc | 11 +++++------ rtengine/processingjob.h | 2 +- rtengine/rawimage.cc | 1 + rtengine/rawimagesource.cc | 34 +++++++++++++--------------------- rtengine/rawimagesource.h | 2 +- rtengine/rawimagesource_i.h | 10 +++++----- rtengine/rtthumbnail.h | 2 +- rtengine/shmap.cc | 2 +- rtengine/stdimagesource.cc | 2 +- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index c7a6412be..8b8ce099d 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -558,10 +558,20 @@ CameraConstantsStore::parse_camera_constants_file(Glib::ustring filename_) while ((ret = fread(&buf[datasize], 1, bufsize - datasize, stream)) != 0) { datasize += ret; - if (datasize == bufsize) { + if (datasize == bufsize) { // we need more memory bufsize += increment; - buf = (char *)realloc(buf, bufsize); - increment *= 2; + void *temp = realloc(buf, bufsize); // try to realloc buffer with new size + if(!temp) { // realloc failed + temp = malloc(bufsize); // alloc now buffer + if (temp) { // alloc worked + memcpy(temp, buf, bufsize - increment); // copy old buffer content to new buffer + free(buf); // free old buffer + } else { // alloc didn't work, break + break; + } + } + buf = (char *)temp; // assign new buffer + increment *= 2; // double increment } } diff --git a/rtengine/color.cc b/rtengine/color.cc index 6dda2c8b8..4982d36b5 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -542,7 +542,7 @@ void Color::rgb2hsl(float r, float g, float b, float &h, float &s, float &l) h_ = 4. + (var_R - var_G) / C; } - h = float(h_ /= 6.0); + h = float(h_ / 6.0); if ( h < 0.f ) { h += 1.f; @@ -923,7 +923,7 @@ void Color::hsv2rgb (float h, float s, float v, int &r, int &g, int &b) r1 = t; g1 = p; b1 = v; - } else if (i == 5) { + } else /*if (i == 5)*/ { r1 = v; g1 = p; b1 = q; @@ -1996,7 +1996,6 @@ void Color::skinred ( double J, double h, double sres, double Sp, float dred, fl float factorskin, factorsat, factor, factorskinext, interm; float scale = 100.0f / 100.1f; //reduction in normal zone float scaleext = 1.0f; //reduction in transition zone - float protect_redh; float deltaHH = 0.3f; //HH value transition : I have choice 0.3 radians float HH; bool doskin = false; @@ -2077,7 +2076,6 @@ void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, f if(doskin) { float factorskin, factorsat, factor, factorskinext; - float protect_redh; float deltaHH = 0.3f; //HH value transition : I have choice 0.3 radians float chromapro = sres / Sp; diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 06f779875..2dbdbafb1 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -140,8 +140,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e { if (deh.enabled) {//enabled - float mean, stddv, maxtr, mintr; - float delta; + float maxtr, mintr; constexpr float eps = 2.f; bool useHsl = deh.retinexcolorspace == "HSLLOG"; bool useHslLin = deh.retinexcolorspace == "HSLLIN"; @@ -551,8 +550,8 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e delete [] buffer; delete [] srcBuffer; - mean = 0.f; - stddv = 0.f; + float mean = 0.f; + float stddv = 0.f; // I call mean_stddv2 instead of mean_stddv ==> logBetaGain mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); @@ -658,7 +657,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e maxi = maxtr - epsil; } - delta = maxi - mini; + float delta = maxi - mini; //printf("maxi=%f mini=%f mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", maxi, mini, mean, stddv, delta, maxtr, mintr); if ( !delta ) { @@ -691,7 +690,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e // I call mean_stddv2 instead of mean_stddv ==> logBetaGain mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); - float asig, bsig, amax, bmax, amin, bmin; + float asig = 0.f, bsig = 0.f, amax = 0.f, bmax = 0.f, amin = 0.f, bmin = 0.f; if (dehagaintransmissionCurve && mean != 0.f && stddv != 0.f) { //if curve asig = 0.166666f / stddv; diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h index fbf56234f..0613ccdeb 100644 --- a/rtengine/processingjob.h +++ b/rtengine/processingjob.h @@ -37,7 +37,7 @@ public: : fname(fn), isRaw(iR), initialImage(NULL), pparams(pp) {} ProcessingJobImpl (InitialImage* iImage, const procparams::ProcParams& pp) - : fname(""), initialImage(iImage), pparams(pp) + : fname(""), isRaw(true), initialImage(iImage), pparams(pp) { iImage->increaseRef(); } diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 8f91f8f4b..cb1c2a9c9 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -25,6 +25,7 @@ RawImage::RawImage( const Glib::ustring &name ) , filename(name) , profile_data(NULL) , allocation(NULL) + , rotate_deg(0) { memset(maximum_c4, 0, sizeof(maximum_c4)); RT_matrix_from_constant = 0; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 31deac244..8c44f8fc4 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1453,10 +1453,9 @@ void RawImageSource::getFullSize (int& w, int& h, int tr) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void RawImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) +void RawImageSource::getSize (PreviewProps pp, int& w, int& h) { - tran = defTransform (tran); w = pp.w / pp.skip + (pp.w % pp.skip > 0); h = pp.h / pp.skip + (pp.h % pp.skip > 0); } @@ -2123,7 +2122,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar #endif for (; j < W - border; j++) { - float H, S, L; + float L; //rgb=>lab Color::rgb2hslfloat(red[i][j], green[i][j], blue[i][j], conversionBuffer[0][i - border][j - border], conversionBuffer[1][i - border][j - border], L); L *= 32768.f; @@ -2296,7 +2295,6 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC float **temp = conversionBuffer[2]; // one less dereference LUTf dLcurve; LUTu hist16RET; - float val; if(dehacontlutili && histLRETI) { hist16RET(32768); @@ -2369,7 +2367,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC // hist16RET.compressTo(histLRETI); // also remove declaration and init of dLcurve some lines above then and finally remove this comment :) for (int i = 0; i < 32768; i++) { - val = (double)i / 32767.0; + float val = (double)i / 32767.0; dLcurve[i] = val; } @@ -2393,14 +2391,8 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC for (; j < W - border; j++) { - float valp; - // if(chutili) { // c=f(H) - { - valp = float((chcurve->getVal(conversionBuffer[3][i - border][j - border]) - 0.5f)); - - conversionBuffer[1][i - border][j - border] *= (1.f + 2.f * valp); - } - // } + float valp = (chcurve->getVal(conversionBuffer[3][i - border][j - border]) - 0.5f); + conversionBuffer[1][i - border][j - border] *= (1.f + 2.f * valp); } } @@ -2822,7 +2814,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile if(raw.ff_AutoClipControl) { // determine maximum calculated value to avoid clipping - int clipControlGui = 0; +// int clipControlGui = 0; float maxval = 0.f; // xtrans files have only one black level actually, so we can simplify the code a bit #ifdef _OPENMP @@ -2857,7 +2849,7 @@ void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile // there's only one white level for xtrans if(maxval + black[0] > ri->get_white(0)) { limitFactor = ri->get_white(0) / (maxval + black[0]); - clipControlGui = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui +// clipControlGui = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui } } else { limitFactor = max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); @@ -4202,7 +4194,7 @@ void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int wi for (int col = 0; col < width; col++) { float rgb[ColorCount], cam[2][ColorCount], lab[2][ColorCount], sum[2], chratio, lratio = 0; - float L, C, H, Lfrac; + float L, C, H; // Copy input pixel to rgb so it's easier to access in loops rgb[0] = rin[col]; @@ -4290,7 +4282,7 @@ void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int wi bin[col] = L + H / 3.0; if ((L = (rin[col] + gin[col] + bin[col]) / 3) > desatpt) { - Lfrac = max(0.0f, (maxave - L) / (maxave - desatpt)); + float Lfrac = max(0.0f, (maxave - L) / (maxave - desatpt)); C = Lfrac * 1.732050808 * (rin[col] - gin[col]); H = Lfrac * (2 * bin[col] - rin[col] - gin[col]); rin[col] = L - H / 6.0 + C / 3.464101615; @@ -4887,11 +4879,11 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vectorgetSensorType() != ST_BAYER) { if(ri->getSensorType() == ST_FUJI_XTRANS) { int d[9][2] = {{0, 0}, { -1, -1}, { -1, 0}, { -1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; - double rloc, gloc, bloc; - int rnbrs, gnbrs, bnbrs; for (size_t i = 0; i < red.size(); i++) { transformPosition (red[i].x, red[i].y, tran, x, y); + double rloc, gloc, bloc; + int rnbrs, gnbrs, bnbrs; rloc = gloc = bloc = rnbrs = gnbrs = bnbrs = 0; for (int k = 0; k < 9; k++) { @@ -4959,11 +4951,11 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vectorget_rotateDegree(); diff --git a/rtengine/rawimagesource_i.h b/rtengine/rawimagesource_i.h index f5685b0ef..4e953becb 100644 --- a/rtengine/rawimagesource_i.h +++ b/rtengine/rawimagesource_i.h @@ -140,7 +140,7 @@ inline void RawImageSource::interpolate_row_g (float* agh, float* agv, int i) inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, float* cg, float* ng, int i) { - if (ri->ISRED(i, 0) || ri->ISRED(i, 1)) { + if ((ri->ISRED(i, 0) || ri->ISRED(i, 1)) && pg && ng) { // RGRGR or GRGRGR line for (int j = 0; j < W; j++) { if (ri->ISRED(i, j)) { @@ -172,7 +172,7 @@ inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, b = cg[j] + b / n; ab[j] = b; - } else { + } else if(ng && pg) { // linear R-G interp. horizontally int r; @@ -199,7 +199,7 @@ inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, ab[j] = b; } } - } else { + } else if(ng && pg) { // BGBGB or GBGBGB line for (int j = 0; j < W; j++) { if (ri->ISBLUE(i, j)) { @@ -265,7 +265,7 @@ inline void RawImageSource::interpolate_row_rb (float* ar, float* ab, float* pg, inline void RawImageSource::interpolate_row_rb_mul_pp (float* ar, float* ab, float* pg, float* cg, float* ng, int i, float r_mul, float g_mul, float b_mul, int x1, int width, int skip) { - if (ri->ISRED(i, 0) || ri->ISRED(i, 1)) { + if ((ri->ISRED(i, 0) || ri->ISRED(i, 1)) && pg && ng) { // RGRGR or GRGRGR line for (int j = x1, jx = 0; jx < width; j += skip, jx++) { if (ri->ISRED(i, j)) { @@ -324,7 +324,7 @@ inline void RawImageSource::interpolate_row_rb_mul_pp (float* ar, float* ab, flo ab[jx] = b; } } - } else { + } else if(pg && ng) { // BGBGB or GBGBGB line for (int j = x1, jx = 0; jx < width; j += skip, jx++) { if (ri->ISBLUE(i, j)) { diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index bc367522d..18e72fc19 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -107,7 +107,7 @@ public: static ImageIO* resizeToSameType(int nw, int nh, TypeInterpolation interp, ImageIO* srcImg) { - ImageIO* imgPtr; + ImageIO* imgPtr = nullptr; if (srcImg->getType() == sImage8) { Image8* castedSrcImg = static_cast(srcImg); diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc index bb8e96c11..65c1070a2 100644 --- a/rtengine/shmap.cc +++ b/rtengine/shmap.cc @@ -30,7 +30,7 @@ namespace rtengine extern const Settings* settings; -SHMap::SHMap (int w, int h, bool multiThread) : W(w), H(h), multiThread(multiThread) +SHMap::SHMap (int w, int h, bool multiThread) : max_f(0.f), min_f(0.f), avg(0.f), W(w), H(h), multiThread(multiThread) { map = new float*[H]; diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index e422d23b2..3db0d06ac 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -51,7 +51,7 @@ template T** allocArray (int W, int H) } #define HR_SCALE 2 -StdImageSource::StdImageSource () : ImageSource(), img(NULL), plistener(NULL) +StdImageSource::StdImageSource () : ImageSource(), img(NULL), plistener(NULL), full(false), max{}, rgbSourceModified(false) { hrmap[0] = NULL; From 362564339233bc5bf7f21b827a63563ebf2b4f84 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 13 Oct 2016 17:37:08 +0200 Subject: [PATCH 16/20] Cppcheck: Fixed bug from last commit. Also added some new fixes --- rtengine/dcrop.cc | 2 +- rtengine/diagonalcurves.cc | 2 +- rtengine/flatcurves.cc | 4 +- rtengine/hlrecovery.cc | 397 ---------------------------------- rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 3 +- rtengine/improcfun.cc | 4 +- rtengine/ipvibrance.cc | 2 +- rtengine/procparams.h | 4 +- rtengine/rawimagesource.cc | 45 ++-- rtengine/rawimagesource.h | 6 - rtengine/stdimagesource.cc | 17 +- rtengine/stdimagesource.h | 4 +- 13 files changed, 44 insertions(+), 448 deletions(-) delete mode 100644 rtengine/hlrecovery.cc diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index ac8b6fc0e..16ec67f57 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -1121,7 +1121,7 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte PreviewProps cp (orx, ory, orw, orh, skip); int orW, orH; - parent->imgsrc->getSize (tr, cp, orW, orH); + parent->imgsrc->getSize (cp, orW, orH); int cw = SKIPS(bw, skip); int ch = SKIPS(bh, skip); diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index a5505391e..2178e3dac 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -245,7 +245,7 @@ void DiagonalCurve::NURBS_set () printf("sc_length[%zu/3]=%f \n", it, sc_length[it / 3]); } - printf("NURBS diagonal curve: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f", i, nbr_points, ppn, N, sc_length[i / 3], total_length); + printf("NURBS diagonal curve: error detected!\n i=%u nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f", i, nbr_points, ppn, N, sc_length[i / 3], total_length); exit(0); } diff --git a/rtengine/flatcurves.cc b/rtengine/flatcurves.cc index 5a4dfeacf..ae1a895ff 100644 --- a/rtengine/flatcurves.cc +++ b/rtengine/flatcurves.cc @@ -311,10 +311,10 @@ void FlatCurve::CtrlPoints_set () if (nbr_points < 0) { for(size_t it = 0; it < sc_x.size(); it += 3) { - printf("sc_length[%zd/3]=%f \n", it, sc_length[it / 3]); + printf("sc_length[%zu/3]=%f \n", it, sc_length[it / 3]); } - printf("Flat curve: error detected!\n i=%d k=%d periodic=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f\n", i, k, periodic, nbr_points, ppn, N, sc_length[i / 3], total_length); + printf("Flat curve: error detected!\n i=%u k=%u periodic=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f\n", i, k, periodic, nbr_points, ppn, N, sc_length[i / 3], total_length); exit(0); } diff --git a/rtengine/hlrecovery.cc b/rtengine/hlrecovery.cc deleted file mode 100644 index 4f527b660..000000000 --- a/rtengine/hlrecovery.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -namespace rtengine -{ - -template T** allocArray (int W, int H) -{ - - T** t = new T*[H]; - - for (int i = 0; i < H; i++) { - t[i] = new T[W]; - } - - return t; -} - -void RawImageSource::updateHLRecoveryMap (bool needred, bool needgreen, bool needblue, bool full) -{ - - // detect maximal pixel values - unsigned short* red = new unsigned short[W]; - unsigned short* blue = new unsigned short[W]; - int maxr = 0, maxg = 0, maxb = 0; - - for (int i = 32; i < H - 32; i++) { - interpolate_row_rb (red, blue, green[i - 1], green[i], green[i + 1], i); - - for (int j = 32; j < W - 32; j++) { - if (red[j] > maxr) { - maxr = red[j]; - } - - if (green[i][j] > maxg) { - maxg = green[i][j]; - } - - if (blue[j] > maxb) { - maxb = blue[j]; - } - } - } - - delete [] red; - delete [] blue; - - maxr = maxr * 19 / 20; - maxg = maxg * 19 / 20; - maxb = maxb * 19 / 20; - int max[3]; - max[0] = maxr; - max[1] = maxg; - max[2] = maxb; - - if( options.rtSettings.verbose ) { - printf ("HLRecoveryMap Maximum: R: %d, G: %d, B: %d\n", maxr, maxg, maxb); - } - - // downscale image - int dw = W / SCALE; - int dh = H / SCALE; - Image16* ds = new Image16 (dw, dh); - - // overburnt areas - int** rec[3]; - - for (int i = 0; i < 3; i++) { - rec[i] = allocArray (dw, dh); - } - - unsigned short* reds[SCALE]; - unsigned short* blues[SCALE]; - - for (int i = 0; i < SCALE; i++) { - reds[i] = new unsigned short[W]; - blues[i] = new unsigned short[W]; - } - - for (int i = 0; i < dh; i++) { - for (int j = 0; j < SCALE; j++) { - interpolate_row_rb (reds[j], blues[j], green[SCALE * i + j - 1], green[SCALE * i + j], green[SCALE * i + j + 1], SCALE * i + j); - } - - for (int j = 0; j < dw; j++) { - int sumr = 0; - int cr = 0; - int sumg = 0; - int cg = 0; - int sumb = 0; - int cb = 0; - - for (int x = 0; x < SCALE; x++) - for (int y = 0; y < SCALE; y++) { - int ix = SCALE * i + x; - int jy = SCALE * j + y; - sumr += reds[x][jy]; - - if (reds[x][jy] < maxr) { - cr++; - } - - sumg += green[ix][jy]; - - if (green[ix][jy] < maxg) { - cg++; - } - - sumb += blues[x][jy]; - - if (blues[x][jy] < maxb) { - cb++; - } - } - - if (cr < SCALE * SCALE && needred) { - rec[0][i][j] = INT_MAX; - } else { - rec[0][i][j] = sumr / SCALE / SCALE; - } - - if (cg < SCALE * SCALE && needgreen) { - rec[1][i][j] = INT_MAX; - } else { - rec[1][i][j] = sumg / SCALE / SCALE; - } - - if (cb < SCALE * SCALE && needblue) { - rec[2][i][j] = INT_MAX; - } else { - rec[2][i][j] = sumb / SCALE / SCALE; - } - - ds->r(i, j) = sumr / SCALE / SCALE; - ds->g(i, j) = sumg / SCALE / SCALE; - ds->b(i, j) = sumb / SCALE / SCALE; - } - } - - for (int i = 0; i < SCALE; i++) { - delete [] reds[i]; - delete [] blues[i]; - } - - - // STEP I. recover color from the partially lost areas - bool phase2 = false; - - for (int k = 0; k < 400; k++) { - if (k > 200) { - phase2 = true; - } - - for (int i = 1; i < dh - 1; i++) - for (int j = 1; j < dw - 1; j++) { - for (int c = 0; c < 3; c++) { - // if channel c is lost - if (rec[c][i][j] == INT_MAX) { - double ratio[2] = {0.0, 0.0}; - double w[2] = {0.0, 0.0}; - int count[2] = {0, 0}; - int ix = 0; - - for (int m = 0; m < 3; m++) { - if (m == c) { - continue; - } - - // if channel m is not lost at this point (or already recovered) - if (rec[m][i][j] != INT_MAX && rec[m][i][j] >= 0) { - for (int x = -1; x <= 1; x++) - for (int y = -1; y <= 1; y++) - - // average m/c color ratios in the surrounding pixels - if (rec[m][i + x][j + y] >= 0 && rec[m][i + x][j + y] != INT_MAX && rec[c][i + x][j + y] > 0 && rec[c][i + x][j + y] != INT_MAX) { - double ww = 1.0; - - if (!phase2 && (/*(double)(rec[m][i+x][j+y] - rec[m][i][j])/max[m]*(rec[m][i+x][j+y] - rec[m][i][j])/max[m] > 1.0/2 || */rec[c][i + x][j + y] < max[c] * 3 / 4)) { - continue; - } - - w[ix] += ww; - ratio[ix] += ww * rec[m][i + x][j + y] / rec[c][i + x][j + y]; - count[ix] ++; - } - } - - ix++; - } - - // compute new pixel values from the surrounding color ratios - double newc = 0.0; - int nc = 0; - ix = 0; - - for (int m = 0; m < 3; m++) { - if (c == m) { - continue; - } - - if (count[ix]) { - newc += (double)rec[m][i][j] / ratio[ix] * w[ix]; - nc++; - } - - ix++; - } - - if (nc) { - rec[c][i][j] = - (int) (newc / nc); - } - } - } - } - - bool change = false; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - for (int c = 0; c < 3; c++) { - if (rec[c][i][j] < 0) { - rec[c][i][j] = -rec[c][i][j]; - } - - change = true; - } - - if (!change) { - break; - } - } - - printf ("Phase1 vege\n"); - - // STEP II. recover fully lost pixels - if (full) { - int maxY = (299 * max[0] + 587 * max[1] + 114 * max[2]) / 1000; - phase2 = false; - - for (int k = 0; k < 600; k++) { - if (k > 200) { - phase2 = true; - } - - for (int i = 1; i < dh - 1; i++) - for (int j = 1; j < dw - 1; j++) { - if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) { - int count = 0; - double yavg = 0, iavg = 0, qavg = 0, weight = 0.0; - - for (int x = -1; x <= 1; x++) - for (int y = -1; y <= 1; y++) - if (rec[0][i + x][j + y] > 0 && rec[0][i + x][j + y] != INT_MAX && rec[1][i + x][j + y] > 0 && rec[1][i + x][j + y] != INT_MAX && rec[2][i + x][j + y] > 0 && rec[2][i + x][j + y] != INT_MAX) { - // convert to yiq - double Y = 0.299 * rec[0][i + x][j + y] + 0.587 * rec[1][i + x][j + y] + 0.114 * rec[2][i + x][j + y]; - double I = 0.596 * rec[0][i + x][j + y] - 0.275 * rec[1][i + x][j + y] - 0.321 * rec[2][i + x][j + y]; - double Q = 0.212 * rec[0][i + x][j + y] - 0.523 * rec[1][i + x][j + y] + 0.311 * rec[2][i + x][j + y]; - - if (Y > maxY * 7 / 10) { - double w = 1.0;// / (I*I+Q*Q); - yavg += Y * w; - iavg += I * w; - qavg += Q * w; - weight += w; - count++; - } - } - - if ((!phase2 && count > 5) || (phase2 && count > 3)) { - double Y = yavg / weight; - double I = iavg / weight; - double Q = qavg / weight; - rec[0][i][j] = - (Y + 0.956 * I + 0.621 * Q); - rec[1][i][j] = - (Y - 0.272 * I - 0.647 * Q); - rec[2][i][j] = - (Y - 1.105 * I + 1.702 * Q); - } - } - - } - - bool change = false; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - for (int c = 0; c < 3; c++) { - if (rec[c][i][j] < 0) { - rec[c][i][j] = -rec[c][i][j]; - } - - change = true; - } - - if (!change) { - break; - } - } - } - - int maxval = 0; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - for (int c = 0; c < 3; c++) - if (rec[c][i][j] != INT_MAX && rec[c][i][j] > maxval) { - maxval = rec[c][i][j]; - } - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) - if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) { - rec[0][i][j] = maxval; - rec[1][i][j] = maxval; - rec[2][i][j] = maxval; - } - - if (hrmap[0] != NULL) { - freeArray (hrmap[0], dh); - freeArray (hrmap[1], dh); - freeArray (hrmap[2], dh); - } - - hrmap[0] = allocArray (dw, dh); - hrmap[1] = allocArray (dw, dh); - hrmap[2] = allocArray (dw, dh); - - this->full = full; - - for (int i = 0; i < dh; i++) - for (int j = 0; j < dw; j++) { - hrmap[0][i][j] = (double)rec[0][i][j] / ds->r(i, j); - hrmap[1][i][j] = (double)rec[1][i][j] / ds->g(i, j); - hrmap[2][i][j] = (double)rec[2][i][j] / ds->b(i, j); - } - - /* for (int i=0; ir(i,j) = CLIP (rec[0][i][j]); - ds->g(i,j) = CLIP (rec[1][i][j]); - ds->b(i,j) = CLIP (rec[2][i][j]); - } - ds->save ("test.png"); - */ - delete ds; - freeArray (rec[0], dh); - freeArray (rec[1], dh); - freeArray (rec[2], dh); - - printf ("HLMap vege\n"); -} - -void RawImageSource::hlRecovery (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int sx2, int skip) -{ - - int blr = (i + SCALE / 2) / SCALE - 1; - - if (blr < 0 || blr >= H / SCALE - 1) { - return; - } - - double mr1 = 1.0 - ((double)((i + SCALE / 2) % SCALE) / SCALE + 0.5 / SCALE); - int jx = 0; - int maxcol = W / SCALE; - - for (int j = sx1, jx = 0; j < sx2; j += skip, jx++) { - int blc = (j + SCALE / 2) / SCALE - 1; - - if (blc < 0 || blc >= maxcol - 1) { - continue; - } - - double mc1 = 1.0 - ((double)((j + SCALE / 2) % SCALE) / SCALE + 0.5 / SCALE); - double mulr = mr1 * mc1 * hrmap[0][blr][blc] + mr1 * (1.0 - mc1) * hrmap[0][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[0][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[0][blr + 1][blc + 1]; - double mulg = mr1 * mc1 * hrmap[1][blr][blc] + mr1 * (1.0 - mc1) * hrmap[1][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[1][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[1][blr + 1][blc + 1]; - double mulb = mr1 * mc1 * hrmap[2][blr][blc] + mr1 * (1.0 - mc1) * hrmap[2][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[2][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[2][blr + 1][blc + 1]; - red[jx] = CLIP(red[jx] * mulr); - green[jx] = CLIP(green[jx] * mulg); - blue[jx] = CLIP(blue[jx] * mulb); - } -} -} - diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 65b2b76c0..f69a33e33 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -100,7 +100,7 @@ public: } virtual void getFullSize (int& w, int& h, int tr = TR_NONE) {} - virtual void getSize (int tran, PreviewProps pp, int& w, int& h) {} + virtual void getSize (PreviewProps pp, int& w, int& h) = 0; virtual int getRotateDegree() const { return 0; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 20eea3011..89a28be50 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -37,6 +37,7 @@ ImProcCoordinator::ImProcCoordinator () highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(NAN), + ctColorCurve(), hltonecurve(65536), shtonecurve(65536), tonecurve(65536, 0), //,1); @@ -901,7 +902,7 @@ void ImProcCoordinator::setScale (int prevscale) do { prevscale--; PreviewProps pp (0, 0, fw, fh, prevscale); - imgsrc->getSize (tr, pp, nW, nH); + imgsrc->getSize (pp, nW, nH); } while(nH < 400 && prevscale > 1 && (nW * nH < 1000000) ); // sctually hardcoded values, perhaps a better choice is possible if (settings->verbose) { diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index b170ba52f..1ef20b3b4 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -6159,8 +6159,8 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (settings->verbose) { t2e.set(); printf("Color::AllMunsellLch (correction performed in %d usec):\n", t2e.etime(t1e)); - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%i\n", MunsDebugInfo->maxdhuelum[0], MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad dep=%u\n", MunsDebugInfo->maxdhuelum[0], MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); } delete MunsDebugInfo; diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 1d152c737..ed944e62e 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -744,7 +744,7 @@ void ImProcFunctions::vibrance (LabImage* lab) printf(" Gamut: G1negat=%iiter G165535=%iiter G2negsat=%iiter G265535=%iiter\n", negat, moreRGB, negsat, moresat); if (MunsDebugInfo) { - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); } } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d51c032c0..82fc90396 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -65,9 +65,7 @@ public: protected: bool initEq1; bool _isDouble; -#ifndef NDEBUG - unsigned int part[5]; -#endif + public: Threshold (T bottom, T top, bool startAtOne) { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 8c44f8fc4..9a6358bda 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -423,6 +423,7 @@ extern const Settings* settings; RawImageSource::RawImageSource () : ImageSource() + , W(0), H(0) , plistener(NULL) , border(4) , ri(NULL) @@ -431,17 +432,40 @@ RawImageSource::RawImageSource () , green(0, 0) , red(0, 0) , blue(0, 0) + , lc00(0.0) + , lc01(0.0) + , lc02(0.0) + , lc10(0.0) + , lc11(0.0) + , lc12(0.0) + , lc20(0.0) + , lc21(0.0) + , lc22(0.0) + , hlmax{} + , clmax{} + , chmax{} + , scale_mul{} + , c_black{} + , c_white{} + , cblacksom{} + , ref_pre_mul{} + , refwb_red(0.0) + , refwb_green(0.0) + , refwb_blue(0.0) + , rgb_cam{} + , cam_rgb{} + , xyz_cam{} + , cam_xyz{} + , fuji(false) + , d1x(false) + , initialGain(0.0) + , camInitialGain(0.0) + , defGain(0.0) + , threshold(0) { - hrmap[0] = NULL; - hrmap[1] = NULL; - hrmap[2] = NULL; - //needhr = NULL; - //hpmap = NULL; camProfile = NULL; embProfile = NULL; rgbSourceModified = false; - hlmax[0] = hlmax[1] = hlmax[2] = hlmax[3] = 0.f; - clmax[0] = clmax[1] = clmax[2] = clmax[3] = 0.f; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -462,13 +486,6 @@ RawImageSource::~RawImageSource () delete [] cache; } - if (hrmap[0] != NULL) { - int dh = H / HR_SCALE; - freeJaggedArray(hrmap[0]); - freeJaggedArray(hrmap[1]); - freeJaggedArray(hrmap[2]); - } - if (camProfile) { cmsCloseProfile (camProfile); } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 9ef17ee0d..ed2e5ee76 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -63,17 +63,11 @@ protected: bool fuji; bool d1x; int border; - //char** hpmap; - float** hrmap[3]; // for color propagation - char** needhr; // for color propagation - int max_3[3]; float chmax[4], hlmax[4], clmax[4]; double initialGain; // initial gain calculated after scale_colors double camInitialGain; double defGain; - bool full; cmsHPROFILE camProfile; - cmsHPROFILE embProfile; bool rgbSourceModified; RawImage* ri; // Copy of raw pixels, NOT corrected for initial gain, blackpoint etc. diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 3db0d06ac..826c8a49b 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -54,10 +54,6 @@ template T** allocArray (int W, int H) StdImageSource::StdImageSource () : ImageSource(), img(NULL), plistener(NULL), full(false), max{}, rgbSourceModified(false) { - hrmap[0] = NULL; - hrmap[1] = NULL; - hrmap[2] = NULL; - needhr = NULL; embProfile = NULL; idata = NULL; } @@ -67,17 +63,6 @@ StdImageSource::~StdImageSource () delete idata; - if (hrmap[0] != NULL) { - int dh = img->getH() / HR_SCALE; - freeArray(hrmap[0], dh); - freeArray(hrmap[1], dh); - freeArray(hrmap[2], dh); - } - - if (needhr) { - freeArray(needhr, img->getH()); - } - if (img) { delete img; } @@ -311,7 +296,7 @@ void StdImageSource::getFullSize (int& w, int& h, int tr) } } -void StdImageSource::getSize (int tran, PreviewProps pp, int& w, int& h) +void StdImageSource::getSize (PreviewProps pp, int& w, int& h) { w = pp.w / pp.skip + (pp.w % pp.skip > 0); diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 048f3b3c0..509e03dc5 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -32,8 +32,6 @@ protected: ColorTemp wb; ProgressListener* plistener; bool full; - float** hrmap[3]; - char** needhr; int max[3]; bool rgbSourceModified; @@ -66,7 +64,7 @@ public: } void getFullSize (int& w, int& h, int tr = TR_NONE); - void getSize (int tran, PreviewProps pp, int& w, int& h); + void getSize (PreviewProps pp, int& w, int& h); ImageData* getImageData () { From 81421db9c9df90e54a182d31e6a475537bceab4a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 13 Oct 2016 22:15:33 +0200 Subject: [PATCH 17/20] Cppcheck: some fixes --- rtengine/rawimagesource.cc | 2 +- rtengine/utils.cc | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 9a6358bda..978cea36f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3933,7 +3933,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam lcmsMutex->unlock (); } - TMatrix toxyz, torgb; + TMatrix toxyz = {}, torgb = {}; if (!working_space_is_prophoto) { toxyz = iccStore->workingSpaceMatrix ("ProPhoto"); diff --git a/rtengine/utils.cc b/rtengine/utils.cc index 2366f3a0c..b862e290f 100644 --- a/rtengine/utils.cc +++ b/rtengine/utils.cc @@ -168,9 +168,7 @@ void rotate (unsigned char* img, int& w, int& h, int deg) rotated[3 * (j * h + h - i - 1) + 2] = img[ix++]; } - int tmp = w; - w = h; - h = tmp; + std::swap(w,h); } else if (deg == 270) { for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) { @@ -179,10 +177,8 @@ void rotate (unsigned char* img, int& w, int& h, int deg) rotated[3 * (h * (w - j - 1) + i) + 2] = img[ix++]; } - int tmp = w; - w = h; - h = tmp; - } else if (deg == 180) + std::swap(w,h); + } else /*if (deg == 180) */ for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) { rotated[3 * (w * (h - i - 1) + w - j - 1) + 0] = img[ix++]; From 8df2df664f177d648c08b64dab34794b9ce3d198 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 17 Oct 2016 18:49:15 +0200 Subject: [PATCH 18/20] Cppcheck: some fixes --- rtengine/CA_correct_RT.cc | 8 ++--- rtengine/EdgePreservingDecomposition.cc | 40 ++++++++++++------------- rtengine/EdgePreservingDecomposition.h | 10 +++---- rtengine/cfa_linedn_RT.cc | 11 ++++--- rtengine/improccoordinator.cc | 4 +-- rtengine/myfile.cc | 4 ++- rtengine/rtthumbnail.cc | 1 + rtgui/options.cc | 7 +---- rtgui/options.h | 4 --- 9 files changed, 40 insertions(+), 49 deletions(-) diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 64bb19113..7c28801ae 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -156,11 +156,9 @@ void RawImageSource::CA_correct_RT(const double cared, const double cablue, cons const int vblsz = ceil((float)(height + border2) / (ts - border2) + 2 + vz1); const int hblsz = ceil((float)(width + border2) / (ts - border2) + 2 + hz1); - char *buffer1 = (char *) calloc(vblsz * hblsz * (2 * 2 + 1), sizeof(float)); - //block CA shift values and weight assigned to block - float *blockwt = (float*)buffer1; - float (*blockshifts)[2][2] = (float (*)[2][2])(buffer1 + (vblsz * hblsz * sizeof(float))); + float* const blockwt = static_cast(calloc(vblsz * hblsz * (2 * 2 + 1), sizeof(float))); + float (*blockshifts)[2][2] = (float (*)[2][2])(blockwt + vblsz * hblsz); double fitparams[2][2][16]; @@ -1013,7 +1011,7 @@ void RawImageSource::CA_correct_RT(const double cared, const double cablue, cons } free(Gtmp); - free(buffer1); + free(blockwt); free(RawDataTmp); if(plistener) { diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 06fe38f2b..c80d5e092 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -17,20 +17,20 @@ calculates A x where x is some vector. Stops when rms residual < RMSResidual or Stops at n iterates if MaximumIterates = 0 since that many iterates gives exact solution. Applicable to symmetric positive definite problems only, which is what unconstrained smooth optimization pretty much always is. Parameter pass can be passed through, containing whatever info you like it to contain (matrix info?). -Takes less memory with OkToModify_b = true, and Preconditioner = NULL. */ +Takes less memory with OkToModify_b = true, and Preconditioner = nullptr. */ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b, float *x, float RMSResidual, void *Pass, int MaximumIterates, void Preconditioner(float *Product, float *x, void *Pass)) { int iterate, i; - char* buffer = (char*)malloc(2 * n * sizeof(float) + 128); - float *r = (float*)(buffer + 64); + float* buffer = (float*)malloc(2 * n * sizeof(float) + 128); + float *r = (buffer + 16); //Start r and x. - if(x == NULL) { + if(x == nullptr) { x = new float[n]; - memset(x, 0, sizeof(float)*n); //Zero initial guess if x == NULL. + memset(x, 0, sizeof(float)*n); //Zero initial guess if x == nullptr. memcpy(r, b, sizeof(float)*n); } else { Ax(r, x, Pass); @@ -46,7 +46,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl //s is preconditionment of r. Without, direct to r. float *s = r, rs = 0.0f; - if(Preconditioner != NULL) { + if(Preconditioner != nullptr) { s = new float[n]; Preconditioner(s, r, Pass); @@ -61,7 +61,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl } //Search direction d. - float *d = (float*)(buffer + n * sizeof(float) + 128); + float *d = (buffer + n + 32); memcpy(d, s, sizeof(float)*n); @@ -114,7 +114,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl break; } - if(Preconditioner != NULL) { + if(Preconditioner != nullptr) { Preconditioner(s, r, Pass); } @@ -185,7 +185,7 @@ MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int Nu { n = Dimension; m = NumberOfDiagonalsInLowerTriangle; - IncompleteCholeskyFactorization = NULL; + IncompleteCholeskyFactorization = nullptr; Diagonals = new float *[m]; StartRows = new int [m + 1]; @@ -196,7 +196,7 @@ MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int Nu MultiDiagonalSymmetricMatrix::~MultiDiagonalSymmetricMatrix() { - if(DiagBuffer != NULL) { + if(DiagBuffer != nullptr) { free(buffer); } else for(int i = 0; i < m; i++) { @@ -216,12 +216,12 @@ bool MultiDiagonalSymmetricMatrix::CreateDiagonal(int index, int StartRow) if(index == 0) { buffer = (char*)calloc( (n + padding) * m * sizeof(float) + (m + 16) * 64 + 63, 1); - if(buffer == NULL) + if(buffer == nullptr) // no big memory block available => try to allocate smaller blocks { - DiagBuffer = NULL; + DiagBuffer = nullptr; } else { - DiagBuffer = (char*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); + DiagBuffer = (float*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); } } @@ -236,12 +236,12 @@ bool MultiDiagonalSymmetricMatrix::CreateDiagonal(int index, int StartRow) return false; } - if(DiagBuffer != NULL) { - Diagonals[index] = (float*)(DiagBuffer + (index * (n + padding) * sizeof(float)) + ((index + 16) * 64)); + if(DiagBuffer != nullptr) { + Diagonals[index] = (DiagBuffer + (index * (n + padding)) + ((index + 16) * 16)); } else { Diagonals[index] = new float[DiagonalLength(StartRow)]; - if(Diagonals[index] == NULL) { + if(Diagonals[index] == nullptr) { printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: memory allocation failed. Out of memory?\n"); return false; } @@ -673,7 +673,7 @@ EdgePreservingDecomposition::EdgePreservingDecomposition(int width, int height) A->CreateDiagonal(3, w) && A->CreateDiagonal(4, w + 1))) { delete A; - A = NULL; + A = nullptr; printf("Error in EdgePreservingDecomposition construction: out of memory.\n"); } else { a0 = A->Diagonals[0]; @@ -692,7 +692,7 @@ EdgePreservingDecomposition::~EdgePreservingDecomposition() SSEFUNCTION float *EdgePreservingDecomposition::CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur, bool UseBlurForEdgeStop) { - if(Blur == NULL) + if(Blur == nullptr) UseBlurForEdgeStop = false, //Use source if there's no supplied Blur. Blur = new float[n]; @@ -864,7 +864,7 @@ float *EdgePreservingDecomposition::CreateIteratedBlur(float *Source, float Scal } //Create a blur here, initialize. - if(Blur == NULL) { + if(Blur == nullptr) { Blur = new float[n]; } @@ -923,7 +923,7 @@ SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Sour //Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation). float *u = CreateIteratedBlur(Source, Scale, EdgeStopping, Iterates, Reweightings); - if(Compressed == NULL) { + if(Compressed == nullptr) { Compressed = u; } diff --git a/rtengine/EdgePreservingDecomposition.h b/rtengine/EdgePreservingDecomposition.h index a15cacb62..bf567f103 100644 --- a/rtengine/EdgePreservingDecomposition.h +++ b/rtengine/EdgePreservingDecomposition.h @@ -72,7 +72,7 @@ ben_s or nonbasketless. Enjoy! #include "noncopyable.h" //This is for solving big symmetric positive definite linear problems. -float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b = true, float *x = NULL, float RMSResidual = 0.0f, void *Pass = NULL, int MaximumIterates = 0, void Preconditioner(float *Product, float *x, void *Pass) = NULL); +float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b = true, float *x = nullptr, float RMSResidual = 0.0f, void *Pass = nullptr, int MaximumIterates = 0, void Preconditioner(float *Product, float *x, void *Pass) = nullptr); //Storage and use class for symmetric matrices, the nonzero contents of which are confined to diagonals. class MultiDiagonalSymmetricMatrix : @@ -93,7 +93,7 @@ public: */ float **Diagonals; char *buffer; - char *DiagBuffer; + float *DiagBuffer; int *StartRows; bool CreateDiagonal(int index, int StartRow); int n, m; //The matrix is n x n, with m diagonals on the lower triangle. Don't change these. They should be private but aren't for convenience. @@ -143,16 +143,16 @@ public: //Create an edge preserving blur of Source. Will create and return, or fill into Blur if not NULL. In place not ok. //If UseBlurForEdgeStop is true, supplied not NULL Blur is used to calculate the edge stopping function instead of Source. - float *CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur = NULL, bool UseBlurForEdgeStop = false); + float *CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur = nullptr, bool UseBlurForEdgeStop = false); //Iterates CreateBlur such that the smoothness term approaches a specific norm via iteratively reweighted least squares. In place not ok. - float *CreateIteratedBlur(float *Source, float Scale, float EdgeStopping, int Iterates, int Reweightings, float *Blur = NULL); + float *CreateIteratedBlur(float *Source, float Scale, float EdgeStopping, int Iterates, int Reweightings, float *Blur = nullptr); /*Lowers global contrast while preserving or boosting local contrast. Can fill into Compressed. The smaller Compression the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm. In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */ - float *CompressDynamicRange(float *Source, float Scale = 1.0f, float EdgeStopping = 1.4f, float CompressionExponent = 0.8f, float DetailBoost = 0.1f, int Iterates = 20, int Reweightings = 0, float *Compressed = NULL); + float *CompressDynamicRange(float *Source, float Scale = 1.0f, float EdgeStopping = 1.4f, float CompressionExponent = 0.8f, float DetailBoost = 0.1f, int Iterates = 20, int Reweightings = 0, float *Compressed = nullptr); private: MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner. diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 78da79bb5..21fcfb1e5 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -68,11 +68,10 @@ void RawImageSource::CLASS cfa_linedn(float noise) { // allocate memory and assure the arrays don't have same 64 byte boundary to avoid L1 conflict misses - char *buffer = (char*)malloc(4 * TS * TS * sizeof(float) + 3 * 64); - float *cfain = (float*)(buffer); - float *cfablur = (float*)(buffer + (TS * TS * sizeof(float)) + 1 * 64); - float *cfadiff = (float*)(buffer + (2 * TS * TS * sizeof(float)) + 2 * 64); - float *cfadn = (float*)(buffer + (3 * TS * TS * sizeof(float)) + 3 * 64); + float *cfain = (float*)malloc(4 * TS * TS * sizeof(float) + 3 * 16 * sizeof(float)); + float *cfablur = (cfain + (TS * TS) + 1 * 16); + float *cfadiff = (cfain + (2 * TS * TS) + 2 * 16); + float *cfadn = (cfain + (3 * TS * TS) + 3 * 16); float linehvar[4], linevvar[4], noisefactor[4][8][2], coeffsq; @@ -250,7 +249,7 @@ void RawImageSource::CLASS cfa_linedn(float noise) } // clean up - free(buffer); + free(cfain); // copy temporary buffer back to image matrix #pragma omp for diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ea4ca964d..2b65e17e4 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -88,8 +88,8 @@ 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), 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) + resultValid(false), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), thread(nullptr), 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), colourToningSatLimit(0.f), colourToningSatLimitOpacity(0.f) {} void ImProcCoordinator::assign (ImageSource* imgsrc) diff --git a/rtengine/myfile.cc b/rtengine/myfile.cc index 0414cc1de..dd97e70e8 100644 --- a/rtengine/myfile.cc +++ b/rtengine/myfile.cc @@ -361,7 +361,7 @@ int fscanf (IMFILE* f, const char* s ...) // of file data and vsscanf() won't tell us how many characters that // were parsed. However, only dcraw.cc code use it and only for "%f" and // "%d", so we make a dummy fscanf here just to support dcraw case. - char buf[50], *endptr; + char buf[50], *endptr = nullptr; int copy_sz = f->size - f->pos; if (copy_sz > sizeof(buf)) { @@ -377,6 +377,7 @@ int fscanf (IMFILE* f, const char* s ...) int i = strtol(buf, &endptr, 10); if (endptr == buf) { + va_end (ap); return 0; } @@ -386,6 +387,7 @@ int fscanf (IMFILE* f, const char* s ...) float f = strtof(buf, &endptr); if (endptr == buf) { + va_end (ap); return 0; } diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 8b2dd4be1..c135acc39 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -735,6 +735,7 @@ void Thumbnail::init () } Thumbnail::Thumbnail () : + iColorMatrix{}, cam2xyz{}, scale(1.0), colorMatrix{}, isRaw(true), camProfile(nullptr), thumbImg(nullptr), camwbRed(1.0), camwbGreen(1.0), camwbBlue(1.0), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), diff --git a/rtgui/options.cc b/rtgui/options.cc index c5711edfc..d057bbe6c 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -394,8 +394,8 @@ void Options::setDefaults () gimpDir = ""; psDir = ""; customEditorProg = ""; + CPBKeys = CPBKT_TID; editorToSendTo = 1; - liveThumbnails = true; favoriteDirs.clear(); tpOpen.clear (); //crvOpen.clear (); @@ -1093,10 +1093,6 @@ int Options::readFromFile (Glib::ustring fname) thumbInterp = keyFile.get_integer ("File Browser", "ThumbnailInterpolation"); } - if (keyFile.has_key ("File Browser", "LiveThumbnails")) { - liveThumbnails = keyFile.get_boolean ("File Browser", "LiveThumbnails"); - } - if (keyFile.has_key ("File Browser", "FavoriteDirs")) { favoriteDirs = keyFile.get_string_list ("File Browser", "FavoriteDirs"); } @@ -1894,7 +1890,6 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_integer_list ("File Browser", "ParseExtensionsEnabled", pextena); keyFile.set_integer ("File Browser", "ThumbnailArrangement", fbArrangement); keyFile.set_integer ("File Browser", "ThumbnailInterpolation", thumbInterp); - keyFile.set_boolean ("File Browser", "LiveThumbnails", liveThumbnails); Glib::ArrayHandle pfav = favoriteDirs; keyFile.set_string_list ("File Browser", "FavoriteDirs", pfav); Glib::ArrayHandle pren = renameTemplates; diff --git a/rtgui/options.h b/rtgui/options.h index 4f81a966a..ab0726798 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -180,9 +180,7 @@ public: int editorToSendTo; int maxThumbnailHeight; std::size_t maxCacheEntries; - ThFileType thumbnailFormat; int thumbInterp; // 0: nearest, 1: bilinear - bool liveThumbnails; std::vector parseExtensions; // List containing all extensions type std::vector parseExtensionsEnabled; // List of bool to retain extension or not std::vector parsedExtensions; // List containing all retained extensions (lowercase) @@ -203,7 +201,6 @@ public: bool showFileNames; bool filmStripShowFileNames; bool tabbedUI; - int previewSizeTab, previewSizeBrowser; bool rememberZoomAndPan; int multiDisplayMode; // 0=none, 1=Edit panels on other display std::vector cutOverlayBrush; // Red;Green;Blue;Alpha , all ranging 0..1 @@ -219,7 +216,6 @@ public: //int histogramWorking; // 0=disabled, 1=left pane, 2=right pane bool histogramBar; bool histogramFullMode; - bool showProfileSelector; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; bool UseIconNoText; From 3d73eb45a154abe25ba86a3496e4b5b19cac3c81 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 17 Oct 2016 21:47:52 +0200 Subject: [PATCH 19/20] Disabled unused functions in dcraw.cc .h --- rtengine/dcraw.cc | 1362 ++++++++++++++++++++++----------------------- rtengine/dcraw.h | 25 +- 2 files changed, 693 insertions(+), 694 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 3593f2777..54fc09622 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -4132,127 +4132,127 @@ mask_set: } } -void CLASS remove_zeroes() -{ - unsigned row, col, tot, n, r, c; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) - if (BAYER(row,col) == 0) { - tot = n = 0; - for (r = row-2; r <= row+2; r++) - for (c = col-2; c <= col+2; c++) - if (r < height && c < width && - FC(r,c) == FC(row,col) && BAYER(r,c)) - tot += (n++,BAYER(r,c)); - if (n) BAYER(row,col) = tot/n; - } -} +//void CLASS remove_zeroes() +//{ +// unsigned row, col, tot, n, r, c; +// +// for (row=0; row < height; row++) +// for (col=0; col < width; col++) +// if (BAYER(row,col) == 0) { +// tot = n = 0; +// for (r = row-2; r <= row+2; r++) +// for (c = col-2; c <= col+2; c++) +// if (r < height && c < width && +// FC(r,c) == FC(row,col) && BAYER(r,c)) +// tot += (n++,BAYER(r,c)); +// if (n) BAYER(row,col) = tot/n; +// } +//} /* Seach from the current directory up to the root looking for a ".badpixels" file, and fix those pixels now. */ -void CLASS bad_pixels (const char *cfname) -{ - FILE *fp=0; - char *fname, *cp, line[128]; - int len, time, row, col, r, c, rad, tot, n, fixed=0; +//void CLASS bad_pixels (const char *cfname) +//{ +// FILE *fp=0; +// char *fname, *cp, line[128]; +// int len, time, row, col, r, c, rad, tot, n, fixed=0; +// +// if (!filters) return; +// if (cfname) +// fp = fopen (cfname, "r"); +// else { +// for (len=32 ; ; len *= 2) { +// fname = (char *) malloc (len); +// if (!fname) return; +// if (getcwd (fname, len-16)) break; +// free (fname); +// if (errno != ERANGE) return; +// } +//#if defined(WIN32) || defined(DJGPP) +// if (fname[1] == ':') +// memmove (fname, fname+2, len-2); +// for (cp=fname; *cp; cp++) +// if (*cp == '\\') *cp = '/'; +//#endif +// cp = fname + strlen(fname); +// if (cp[-1] == '/') cp--; +// while (*fname == '/') { +// strcpy (cp, "/.badpixels"); +// if ((fp = fopen (fname, "r"))) break; +// if (cp == fname) break; +// while (*--cp != '/'); +// } +// free (fname); +// } +// if (!fp) return; +// while (fgets (line, 128, fp)) { +// cp = strchr (line, '#'); +// if (cp) *cp = 0; +// if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; +// if ((unsigned) col >= width || (unsigned) row >= height) continue; +// if (time > timestamp) continue; +// for (tot=n=0, rad=1; rad < 3 && n==0; rad++) +// for (r = row-rad; r <= row+rad; r++) +// for (c = col-rad; c <= col+rad; c++) +// if ((unsigned) r < height && (unsigned) c < width && +// (r != row || c != col) && fcol(r,c) == fcol(row,col)) { +// tot += BAYER2(r,c); +// n++; +// } +// BAYER2(row,col) = tot/n; +// if (verbose) { +// if (!fixed++) +// fprintf (stderr,_("Fixed dead pixels at:")); +// fprintf (stderr, " %d,%d", col, row); +// } +// } +// if (fixed) fputc ('\n', stderr); +// fclose (fp); +//} - if (!filters) return; - if (cfname) - fp = fopen (cfname, "r"); - else { - for (len=32 ; ; len *= 2) { - fname = (char *) malloc (len); - if (!fname) return; - if (getcwd (fname, len-16)) break; - free (fname); - if (errno != ERANGE) return; - } -#if defined(WIN32) || defined(DJGPP) - if (fname[1] == ':') - memmove (fname, fname+2, len-2); - for (cp=fname; *cp; cp++) - if (*cp == '\\') *cp = '/'; -#endif - cp = fname + strlen(fname); - if (cp[-1] == '/') cp--; - while (*fname == '/') { - strcpy (cp, "/.badpixels"); - if ((fp = fopen (fname, "r"))) break; - if (cp == fname) break; - while (*--cp != '/'); - } - free (fname); - } - if (!fp) return; - while (fgets (line, 128, fp)) { - cp = strchr (line, '#'); - if (cp) *cp = 0; - if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; - if ((unsigned) col >= width || (unsigned) row >= height) continue; - if (time > timestamp) continue; - for (tot=n=0, rad=1; rad < 3 && n==0; rad++) - for (r = row-rad; r <= row+rad; r++) - for (c = col-rad; c <= col+rad; c++) - if ((unsigned) r < height && (unsigned) c < width && - (r != row || c != col) && fcol(r,c) == fcol(row,col)) { - tot += BAYER2(r,c); - n++; - } - BAYER2(row,col) = tot/n; - if (verbose) { - if (!fixed++) - fprintf (stderr,_("Fixed dead pixels at:")); - fprintf (stderr, " %d,%d", col, row); - } - } - if (fixed) fputc ('\n', stderr); - fclose (fp); -} - -void CLASS subtract (const char *fname) -{ - FILE *fp; - int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; - ushort *pixel; - - if (!(fp = fopen (fname, "rb"))) { - perror (fname); return; - } - if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; - while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { - if (c == '#') comment = 1; - if (c == '\n') comment = 0; - if (comment) continue; - if (isdigit(c)) number = 1; - if (number) { - if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; - else if (isspace(c)) { - number = 0; nd++; - } else error = 1; - } - } - if (error || nd < 3) { - fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); - fclose (fp); return; - } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { - fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); - fclose (fp); return; - } - pixel = (ushort *) calloc (width, sizeof *pixel); - merror (pixel, "subtract()"); - for (row=0; row < height; row++) { - fread (pixel, 2, width, fp); - for (col=0; col < width; col++) - BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); - } - free (pixel); - fclose (fp); - memset (cblack, 0, sizeof cblack); - black = 0; -} +//void CLASS subtract (const char *fname) +//{ +// FILE *fp; +// int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; +// ushort *pixel; +// +// if (!(fp = fopen (fname, "rb"))) { +// perror (fname); return; +// } +// if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; +// while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { +// if (c == '#') comment = 1; +// if (c == '\n') comment = 0; +// if (comment) continue; +// if (isdigit(c)) number = 1; +// if (number) { +// if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; +// else if (isspace(c)) { +// number = 0; nd++; +// } else error = 1; +// } +// } +// if (error || nd < 3) { +// fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); +// fclose (fp); return; +// } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { +// fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); +// fclose (fp); return; +// } +// pixel = (ushort *) calloc (width, sizeof *pixel); +// merror (pixel, "subtract()"); +// for (row=0; row < height; row++) { +// fread (pixel, 2, width, fp); +// for (col=0; col < width; col++) +// BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); +// } +// free (pixel); +// fclose (fp); +// memset (cblack, 0, sizeof cblack); +// black = 0; +//} void CLASS gamma_curve (double pwr, double ts, int mode, int imax) { @@ -4417,94 +4417,94 @@ void CLASS colorcheck() } #endif -void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) -{ - int i; - for (i=0; i < sc; i++) - temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; - for (; i+sc < size; i++) - temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; - for (; i < size; i++) - temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; -} +//void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +//{ +// int i; +// for (i=0; i < sc; i++) +// temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; +// for (; i+sc < size; i++) +// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; +// for (; i < size; i++) +// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +//} -void CLASS wavelet_denoise() -{ - float *fimg=0, *temp, thold, mul[2], avg, diff; - int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; - ushort *window[4]; - static const float noise[] = - { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; - - if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); - - while (maximum << scale < 0x10000) scale++; - maximum <<= --scale; - black <<= scale; - FORC4 cblack[c] <<= scale; - if ((size = iheight*iwidth) < 0x15550000) - fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); - merror (fimg, "wavelet_denoise()"); - temp = fimg + size*3; - if ((nc = colors) == 3 && filters) nc++; - FORC(nc) { /* denoise R,G1,B,G3 individually */ - for (i=0; i < size; i++) - fimg[i] = 256 * sqrt(image[i][c] << scale); - for (hpass=lev=0; lev < 5; lev++) { - lpass = size*((lev & 1)+1); - for (row=0; row < iheight; row++) { - hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); - for (col=0; col < iwidth; col++) - fimg[lpass + row*iwidth + col] = temp[col] * 0.25; - } - for (col=0; col < iwidth; col++) { - hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); - for (row=0; row < iheight; row++) - fimg[lpass + row*iwidth + col] = temp[row] * 0.25; - } - thold = threshold * noise[lev]; - for (i=0; i < size; i++) { - fimg[hpass+i] -= fimg[lpass+i]; - if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; - else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; - else fimg[hpass+i] = 0; - if (hpass) fimg[i] += fimg[hpass+i]; - } - hpass = lpass; - } - for (i=0; i < size; i++) - image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); - } - if (filters && colors == 3) { /* pull G1 and G3 closer together */ - for (row=0; row < 2; row++) { - mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; - blk[row] = cblack[FC(row,0) | 1]; - } - for (i=0; i < 4; i++) - window[i] = (ushort *) fimg + width*i; - for (wlast=-1, row=1; row < height-1; row++) { - while (wlast < row+1) { - for (wlast++, i=0; i < 4; i++) - window[(i+3) & 3] = window[i]; - for (col = FC(wlast,1) & 1; col < width; col+=2) - window[2][col] = BAYER(wlast,col); - } - thold = threshold/512; - for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { - avg = ( window[0][col-1] + window[0][col+1] + - window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) - * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; - avg = avg < 0 ? 0 : sqrt(avg); - diff = sqrt(BAYER(row,col)) - avg; - if (diff < -thold) diff += thold; - else if (diff > thold) diff -= thold; - else diff = 0; - BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); - } - } - } - free (fimg); -} +//void CLASS wavelet_denoise() +//{ +// float *fimg=0, *temp, thold, mul[2], avg, diff; +// int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; +// ushort *window[4]; +// static const float noise[] = +// { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; +// +// if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); +// +// while (maximum << scale < 0x10000) scale++; +// maximum <<= --scale; +// black <<= scale; +// FORC4 cblack[c] <<= scale; +// if ((size = iheight*iwidth) < 0x15550000) +// fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); +// merror (fimg, "wavelet_denoise()"); +// temp = fimg + size*3; +// if ((nc = colors) == 3 && filters) nc++; +// FORC(nc) { /* denoise R,G1,B,G3 individually */ +// for (i=0; i < size; i++) +// fimg[i] = 256 * sqrt(image[i][c] << scale); +// for (hpass=lev=0; lev < 5; lev++) { +// lpass = size*((lev & 1)+1); +// for (row=0; row < iheight; row++) { +// hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); +// for (col=0; col < iwidth; col++) +// fimg[lpass + row*iwidth + col] = temp[col] * 0.25; +// } +// for (col=0; col < iwidth; col++) { +// hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); +// for (row=0; row < iheight; row++) +// fimg[lpass + row*iwidth + col] = temp[row] * 0.25; +// } +// thold = threshold * noise[lev]; +// for (i=0; i < size; i++) { +// fimg[hpass+i] -= fimg[lpass+i]; +// if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; +// else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; +// else fimg[hpass+i] = 0; +// if (hpass) fimg[i] += fimg[hpass+i]; +// } +// hpass = lpass; +// } +// for (i=0; i < size; i++) +// image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); +// } +// if (filters && colors == 3) { /* pull G1 and G3 closer together */ +// for (row=0; row < 2; row++) { +// mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; +// blk[row] = cblack[FC(row,0) | 1]; +// } +// for (i=0; i < 4; i++) +// window[i] = (ushort *) fimg + width*i; +// for (wlast=-1, row=1; row < height-1; row++) { +// while (wlast < row+1) { +// for (wlast++, i=0; i < 4; i++) +// window[(i+3) & 3] = window[i]; +// for (col = FC(wlast,1) & 1; col < width; col+=2) +// window[2][col] = BAYER(wlast,col); +// } +// thold = threshold/512; +// for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { +// avg = ( window[0][col-1] + window[0][col+1] + +// window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) +// * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; +// avg = avg < 0 ? 0 : sqrt(avg); +// diff = sqrt(BAYER(row,col)) - avg; +// if (diff < -thold) diff += thold; +// else if (diff > thold) diff -= thold; +// else diff = 0; +// BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); +// } +// } +// } +// free (fimg); +//} void CLASS scale_colors() { @@ -4562,7 +4562,7 @@ skip_block: ; if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; dark = black; sat = maximum; - if (threshold) wavelet_denoise(); +// if (threshold) wavelet_denoise(); maximum -= black; for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { if (dmin > pre_mul[c]) @@ -4668,440 +4668,440 @@ void CLASS pre_interpolate() if (half_size) filters = 0; } -void CLASS border_interpolate (int border) -{ - unsigned row, col, y, x, f, c, sum[8]; - - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - if (col==border && row >= border && row < height-border) - col = width-border; - memset (sum, 0, sizeof sum); - for (y=row-1; y != row+2; y++) - for (x=col-1; x != col+2; x++) - if (y < height && x < width) { - f = fcol(y,x); - sum[f] += image[y*width+x][f]; - sum[f+4]++; - } - f = fcol(row,col); - FORCC if (c != f && sum[c+4]) - image[row*width+col][c] = sum[c] / sum[c+4]; - } -} +//void CLASS border_interpolate (int border) +//{ +// unsigned row, col, y, x, f, c, sum[8]; +// +// for (row=0; row < height; row++) +// for (col=0; col < width; col++) { +// if (col==border && row >= border && row < height-border) +// col = width-border; +// memset (sum, 0, sizeof sum); +// for (y=row-1; y != row+2; y++) +// for (x=col-1; x != col+2; x++) +// if (y < height && x < width) { +// f = fcol(y,x); +// sum[f] += image[y*width+x][f]; +// sum[f+4]++; +// } +// f = fcol(row,col); +// FORCC if (c != f && sum[c+4]) +// image[row*width+col][c] = sum[c] / sum[c+4]; +// } +//} /* RT: delete interpolation functions */ -void CLASS cielab (ushort rgb[3], short lab[3]) -{ - int c, i, j, k; - float r, xyz[3]; - static float cbrt[0x10000], xyz_cam[3][4]; +//void CLASS cielab (ushort rgb[3], short lab[3]) +//{ +// int c, i, j, k; +// float r, xyz[3]; +// static float cbrt[0x10000], xyz_cam[3][4]; +// +// if (!rgb) { +// for (i=0; i < 0x10000; i++) { +// r = i / 65535.0; +// cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; +// } +// for (i=0; i < 3; i++) +// for (j=0; j < colors; j++) +// for (xyz_cam[i][j] = k=0; k < 3; k++) +// xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; +// return; +// } +// xyz[0] = xyz[1] = xyz[2] = 0.5; +// FORCC { +// xyz[0] += xyz_cam[0][c] * rgb[c]; +// xyz[1] += xyz_cam[1][c] * rgb[c]; +// xyz[2] += xyz_cam[2][c] * rgb[c]; +// } +// xyz[0] = cbrt[CLIP((int) xyz[0])]; +// xyz[1] = cbrt[CLIP((int) xyz[1])]; +// xyz[2] = cbrt[CLIP((int) xyz[2])]; +// lab[0] = 64 * (116 * xyz[1] - 16); +// lab[1] = 64 * 500 * (xyz[0] - xyz[1]); +// lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +//} +// +//#define TS 512 /* Tile Size */ +//#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] +// +///* +// Frank Markesteijn's algorithm for Fuji X-Trans sensors +// */ +//void CLASS xtrans_interpolate (int passes) +//{ +// int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; +// int val, ndir, pass, hm[8], avg[4], color[3][8]; +// static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, +// patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, +// { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, +// dir[4] = { 1,TS,TS+1,TS-1 }; +// short allhex[3][3][2][8], *hex; +// ushort min, max, sgrow, sgcol; +// ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; +// short (*lab) [TS][3], (*lix)[3]; +// float (*drv)[TS][TS], diff[6], tr; +// char (*homo)[TS][TS], *buffer; +// +// if (verbose) +// fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); +// +// cielab (0,0); +// ndir = 4 << (passes > 1); +// buffer = (char *) malloc (TS*TS*(ndir*11+6)); +// merror (buffer, "xtrans_interpolate()"); +// rgb = (ushort(*)[TS][TS][3]) buffer; +// lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); +// drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); +// homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); +// +///* Map a green hexagon around each non-green pixel and vice versa: */ +// for (row=0; row < 3; row++) +// for (col=0; col < 3; col++) +// for (ng=d=0; d < 10; d+=2) { +// g = fcol(row,col) == 1; +// if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; +// if (ng == 4) { sgrow = row; sgcol = col; } +// if (ng == g+1) FORC(8) { +// v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; +// h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; +// allhex[row][col][0][c^(g*2 & d)] = h + v*width; +// allhex[row][col][1][c^(g*2 & d)] = h + v*TS; +// } +// } +// +///* Set green1 and green3 to the minimum and maximum allowed values: */ +// for (row=2; row < height-2; row++) +// for (min=~(max=0), col=2; col < width-2; col++) { +// if (fcol(row,col) == 1 && (min=~(max=0))) continue; +// pix = image + row*width + col; +// hex = allhex[row % 3][col % 3][0]; +// if (!max) FORC(6) { +// val = pix[hex[c]][1]; +// if (min > val) min = val; +// if (max < val) max = val; +// } +// pix[0][1] = min; +// pix[0][3] = max; +// switch ((row-sgrow) % 3) { +// case 1: if (row < height-3) { row++; col--; } break; +// case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; +// } +// } +// +// for (top=3; top < height-19; top += TS-16) +// for (left=3; left < width-19; left += TS-16) { +// mrow = MIN (top+TS, height-3); +// mcol = MIN (left+TS, width-3); +// for (row=top; row < mrow; row++) +// for (col=left; col < mcol; col++) +// memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); +// FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); +// +///* Interpolate green horizontally, vertically, and along both diagonals: */ +// for (row=top; row < mrow; row++) +// for (col=left; col < mcol; col++) { +// if ((f = fcol(row,col)) == 1) continue; +// pix = image + row*width + col; +// hex = allhex[row % 3][col % 3][0]; +// color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - +// 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); +// color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + +// 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); +// FORC(2) color[1][2+c] = +// 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * +// (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); +// FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = +// LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); +// } +// +// for (pass=0; pass < passes; pass++) { +// if (pass == 1) +// memcpy (rgb+=4, buffer, 4*sizeof *rgb); +// +///* Recalculate green from interpolated values of closer pixels: */ +// if (pass) { +// for (row=top+2; row < mrow-2; row++) +// for (col=left+2; col < mcol-2; col++) { +// if ((f = fcol(row,col)) == 1) continue; +// pix = image + row*width + col; +// hex = allhex[row % 3][col % 3][1]; +// for (d=3; d < 6; d++) { +// rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; +// val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] +// - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; +// rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); +// } +// } +// } +// +///* Interpolate red and blue values for solitary green pixels: */ +// for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) +// for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { +// rix = &rgb[0][row-top][col-left]; +// h = fcol(row,col+1); +// memset (diff, 0, sizeof diff); +// for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { +// for (c=0; c < 2; c++, h^=2) { +// g = 2*rix[0][1] - rix[i< 1) +// diff[d] += SQR (rix[i< 1 && (d & 1)) +// if (diff[d-1] < diff[d]) +// FORC(2) color[c*2][d] = color[c*2][d-1]; +// if (d < 2 || (d & 1)) { +// FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); +// rix += TS*TS; +// } +// } +// } +// +///* Interpolate red for blue pixels and vice versa: */ +// for (row=top+3; row < mrow-3; row++) +// for (col=left+3; col < mcol-3; col++) { +// if ((f = 2-fcol(row,col)) == 1) continue; +// rix = &rgb[0][row-top][col-left]; +// c = (row-sgrow) % 3 ? TS:1; +// h = 3 * (c ^ TS ^ 1); +// for (d=0; d < 4; d++, rix += TS*TS) { +// i = d > 1 || ((d ^ c) & 1) || +// ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < +// 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; +// rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + +// 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); +// } +// } +// +///* Fill in red and blue for 2x2 blocks of green: */ +// for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) +// for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { +// rix = &rgb[0][row-top][col-left]; +// hex = allhex[row % 3][col % 3][1]; +// for (d=0; d < ndir; d+=2, rix += TS*TS) +// if (hex[d] + hex[d+1]) { +// g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; +// for (c=0; c < 4; c+=2) rix[0][c] = +// CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); +// } else { +// g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; +// for (c=0; c < 4; c+=2) rix[0][c] = +// CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); +// } +// } +// } +// rgb = (ushort(*)[TS][TS][3]) buffer; +// mrow -= top; +// mcol -= left; +// +///* Convert to CIELab and differentiate in all directions: */ +// for (d=0; d < ndir; d++) { +// for (row=2; row < mrow-2; row++) +// for (col=2; col < mcol-2; col++) +// cielab (rgb[d][row][col], lab[row][col]); +// for (f=dir[d & 3],row=3; row < mrow-3; row++) +// for (col=3; col < mcol-3; col++) { +// lix = &lab[row][col]; +// g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; +// drv[d][row][col] = SQR(g) +// + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) +// + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); +// } +// } +// +///* Build homogeneity maps from the derivatives: */ +// memset(homo, 0, ndir*TS*TS); +// for (row=4; row < mrow-4; row++) +// for (col=4; col < mcol-4; col++) { +// for (tr=FLT_MAX, d=0; d < ndir; d++) +// if (tr > drv[d][row][col]) +// tr = drv[d][row][col]; +// tr *= 8; +// for (d=0; d < ndir; d++) +// for (v=-1; v <= 1; v++) +// for (h=-1; h <= 1; h++) +// if (drv[d][row+v][col+h] <= tr) +// homo[d][row][col]++; +// } +// +///* Average the most homogenous pixels for the final result: */ +// if (height-top < TS+4) mrow = height-top+2; +// if (width-left < TS+4) mcol = width-left+2; +// for (row = MIN(top,8); row < mrow-8; row++) +// for (col = MIN(left,8); col < mcol-8; col++) { +// for (d=0; d < ndir; d++) +// for (hm[d]=0, v=-2; v <= 2; v++) +// for (h=-2; h <= 2; h++) +// hm[d] += homo[d][row+v][col+h]; +// for (d=0; d < ndir-4; d++) +// if (hm[d] < hm[d+4]) hm[d ] = 0; else +// if (hm[d] > hm[d+4]) hm[d+4] = 0; +// for (max=hm[0],d=1; d < ndir; d++) +// if (max < hm[d]) max = hm[d]; +// max -= max >> 3; +// memset (avg, 0, sizeof avg); +// for (d=0; d < ndir; d++) +// if (hm[d] >= max) { +// FORC3 avg[c] += rgb[d][row][col][c]; +// avg[3]++; +// } +// FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; +// } +// } +// free(buffer); +// border_interpolate(8); +//} +//#undef fcol +// +// +//#undef TS - if (!rgb) { - for (i=0; i < 0x10000; i++) { - r = i / 65535.0; - cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; - } - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (xyz_cam[i][j] = k=0; k < 3; k++) - xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; - return; - } - xyz[0] = xyz[1] = xyz[2] = 0.5; - FORCC { - xyz[0] += xyz_cam[0][c] * rgb[c]; - xyz[1] += xyz_cam[1][c] * rgb[c]; - xyz[2] += xyz_cam[2][c] * rgb[c]; - } - xyz[0] = cbrt[CLIP((int) xyz[0])]; - xyz[1] = cbrt[CLIP((int) xyz[1])]; - xyz[2] = cbrt[CLIP((int) xyz[2])]; - lab[0] = 64 * (116 * xyz[1] - 16); - lab[1] = 64 * 500 * (xyz[0] - xyz[1]); - lab[2] = 64 * 200 * (xyz[1] - xyz[2]); -} - -#define TS 512 /* Tile Size */ -#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] - -/* - Frank Markesteijn's algorithm for Fuji X-Trans sensors - */ -void CLASS xtrans_interpolate (int passes) -{ - int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; - int val, ndir, pass, hm[8], avg[4], color[3][8]; - static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, - patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, - { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, - dir[4] = { 1,TS,TS+1,TS-1 }; - short allhex[3][3][2][8], *hex; - ushort min, max, sgrow, sgcol; - ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; - short (*lab) [TS][3], (*lix)[3]; - float (*drv)[TS][TS], diff[6], tr; - char (*homo)[TS][TS], *buffer; - - if (verbose) - fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); - - cielab (0,0); - ndir = 4 << (passes > 1); - buffer = (char *) malloc (TS*TS*(ndir*11+6)); - merror (buffer, "xtrans_interpolate()"); - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); - drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); - homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); - -/* Map a green hexagon around each non-green pixel and vice versa: */ - for (row=0; row < 3; row++) - for (col=0; col < 3; col++) - for (ng=d=0; d < 10; d+=2) { - g = fcol(row,col) == 1; - if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; - if (ng == 4) { sgrow = row; sgcol = col; } - if (ng == g+1) FORC(8) { - v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; - h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; - allhex[row][col][0][c^(g*2 & d)] = h + v*width; - allhex[row][col][1][c^(g*2 & d)] = h + v*TS; - } - } - -/* Set green1 and green3 to the minimum and maximum allowed values: */ - for (row=2; row < height-2; row++) - for (min=~(max=0), col=2; col < width-2; col++) { - if (fcol(row,col) == 1 && (min=~(max=0))) continue; - pix = image + row*width + col; - hex = allhex[row % 3][col % 3][0]; - if (!max) FORC(6) { - val = pix[hex[c]][1]; - if (min > val) min = val; - if (max < val) max = val; - } - pix[0][1] = min; - pix[0][3] = max; - switch ((row-sgrow) % 3) { - case 1: if (row < height-3) { row++; col--; } break; - case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; - } - } - - for (top=3; top < height-19; top += TS-16) - for (left=3; left < width-19; left += TS-16) { - mrow = MIN (top+TS, height-3); - mcol = MIN (left+TS, width-3); - for (row=top; row < mrow; row++) - for (col=left; col < mcol; col++) - memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); - FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); - -/* Interpolate green horizontally, vertically, and along both diagonals: */ - for (row=top; row < mrow; row++) - for (col=left; col < mcol; col++) { - if ((f = fcol(row,col)) == 1) continue; - pix = image + row*width + col; - hex = allhex[row % 3][col % 3][0]; - color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - - 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); - color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + - 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); - FORC(2) color[1][2+c] = - 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * - (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); - FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = - LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); - } - - for (pass=0; pass < passes; pass++) { - if (pass == 1) - memcpy (rgb+=4, buffer, 4*sizeof *rgb); - -/* Recalculate green from interpolated values of closer pixels: */ - if (pass) { - for (row=top+2; row < mrow-2; row++) - for (col=left+2; col < mcol-2; col++) { - if ((f = fcol(row,col)) == 1) continue; - pix = image + row*width + col; - hex = allhex[row % 3][col % 3][1]; - for (d=3; d < 6; d++) { - rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; - val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] - - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; - rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); - } - } - } - -/* Interpolate red and blue values for solitary green pixels: */ - for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) - for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { - rix = &rgb[0][row-top][col-left]; - h = fcol(row,col+1); - memset (diff, 0, sizeof diff); - for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { - for (c=0; c < 2; c++, h^=2) { - g = 2*rix[0][1] - rix[i< 1) - diff[d] += SQR (rix[i< 1 && (d & 1)) - if (diff[d-1] < diff[d]) - FORC(2) color[c*2][d] = color[c*2][d-1]; - if (d < 2 || (d & 1)) { - FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); - rix += TS*TS; - } - } - } - -/* Interpolate red for blue pixels and vice versa: */ - for (row=top+3; row < mrow-3; row++) - for (col=left+3; col < mcol-3; col++) { - if ((f = 2-fcol(row,col)) == 1) continue; - rix = &rgb[0][row-top][col-left]; - c = (row-sgrow) % 3 ? TS:1; - h = 3 * (c ^ TS ^ 1); - for (d=0; d < 4; d++, rix += TS*TS) { - i = d > 1 || ((d ^ c) & 1) || - ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < - 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; - rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + - 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); - } - } - -/* Fill in red and blue for 2x2 blocks of green: */ - for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) - for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { - rix = &rgb[0][row-top][col-left]; - hex = allhex[row % 3][col % 3][1]; - for (d=0; d < ndir; d+=2, rix += TS*TS) - if (hex[d] + hex[d+1]) { - g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; - for (c=0; c < 4; c+=2) rix[0][c] = - CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); - } else { - g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; - for (c=0; c < 4; c+=2) rix[0][c] = - CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); - } - } - } - rgb = (ushort(*)[TS][TS][3]) buffer; - mrow -= top; - mcol -= left; - -/* Convert to CIELab and differentiate in all directions: */ - for (d=0; d < ndir; d++) { - for (row=2; row < mrow-2; row++) - for (col=2; col < mcol-2; col++) - cielab (rgb[d][row][col], lab[row][col]); - for (f=dir[d & 3],row=3; row < mrow-3; row++) - for (col=3; col < mcol-3; col++) { - lix = &lab[row][col]; - g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; - drv[d][row][col] = SQR(g) - + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) - + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); - } - } - -/* Build homogeneity maps from the derivatives: */ - memset(homo, 0, ndir*TS*TS); - for (row=4; row < mrow-4; row++) - for (col=4; col < mcol-4; col++) { - for (tr=FLT_MAX, d=0; d < ndir; d++) - if (tr > drv[d][row][col]) - tr = drv[d][row][col]; - tr *= 8; - for (d=0; d < ndir; d++) - for (v=-1; v <= 1; v++) - for (h=-1; h <= 1; h++) - if (drv[d][row+v][col+h] <= tr) - homo[d][row][col]++; - } - -/* Average the most homogenous pixels for the final result: */ - if (height-top < TS+4) mrow = height-top+2; - if (width-left < TS+4) mcol = width-left+2; - for (row = MIN(top,8); row < mrow-8; row++) - for (col = MIN(left,8); col < mcol-8; col++) { - for (d=0; d < ndir; d++) - for (hm[d]=0, v=-2; v <= 2; v++) - for (h=-2; h <= 2; h++) - hm[d] += homo[d][row+v][col+h]; - for (d=0; d < ndir-4; d++) - if (hm[d] < hm[d+4]) hm[d ] = 0; else - if (hm[d] > hm[d+4]) hm[d+4] = 0; - for (max=hm[0],d=1; d < ndir; d++) - if (max < hm[d]) max = hm[d]; - max -= max >> 3; - memset (avg, 0, sizeof avg); - for (d=0; d < ndir; d++) - if (hm[d] >= max) { - FORC3 avg[c] += rgb[d][row][col][c]; - avg[3]++; - } - FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; - } - } - free(buffer); - border_interpolate(8); -} -#undef fcol - - -#undef TS - -void CLASS median_filter() -{ - ushort (*pix)[4]; - int pass, c, i, j, k, med[9]; - static const uchar opt[] = /* Optimal 9-element median search */ - { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, - 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; - - for (pass=1; pass <= med_passes; pass++) { - if (verbose) - fprintf (stderr,_("Median filter pass %d...\n"), pass); - for (c=0; c < 3; c+=2) { - for (pix = image; pix < image+width*height; pix++) - pix[0][3] = pix[0][c]; - for (pix = image+width; pix < image+width*(height-1); pix++) { - if ((pix-image+1) % width < 2) continue; - for (k=0, i = -width; i <= width; i += width) - for (j = i-1; j <= i+1; j++) - med[k++] = pix[j][3] - pix[j][1]; - for (i=0; i < sizeof opt; i+=2) - if (med[opt[i]] > med[opt[i+1]]) - SWAP (med[opt[i]] , med[opt[i+1]]); - pix[0][c] = CLIP(med[4] + pix[0][1]); - } - } - } -} - -void CLASS blend_highlights() -{ - int clip=INT_MAX, row, col, c, i, j; - static const float trans[2][4][4] = - { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, - { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; - static const float itrans[2][4][4] = - { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, - { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; - float cam[2][4], lab[2][4], sum[2], chratio; - - if ((unsigned) (colors-3) > 1) return; - if (verbose) fprintf (stderr,_("Blending highlights...\n")); - FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; - for (row=0; row < height; row++) - for (col=0; col < width; col++) { - FORCC if (image[row*width+col][c] > clip) break; - if (c == colors) continue; - FORCC { - cam[0][c] = image[row*width+col][c]; - cam[1][c] = MIN(cam[0][c],clip); - } - for (i=0; i < 2; i++) { - FORCC for (lab[i][c]=j=0; j < colors; j++) - lab[i][c] += trans[colors-3][c][j] * cam[i][j]; - for (sum[i]=0,c=1; c < colors; c++) - sum[i] += SQR(lab[i][c]); - } - chratio = sqrt(sum[1]/sum[0]); - for (c=1; c < colors; c++) - lab[0][c] *= chratio; - FORCC for (cam[0][c]=j=0; j < colors; j++) - cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; - FORCC image[row*width+col][c] = cam[0][c] / colors; - } -} - -#define SCALE (4 >> shrink) -void CLASS recover_highlights() -{ - float *map, sum, wgt, grow; - int hsat[4], count, spread, change, val, i; - unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; - ushort *pixel; - static const signed char dir[8][2] = - { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; - - if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); - - grow = pow (2, 4-highlight); - FORCC hsat[c] = 32000 * pre_mul[c]; - for (kc=0, c=1; c < colors; c++) - if (pre_mul[kc] < pre_mul[c]) kc = c; - high = height / SCALE; - wide = width / SCALE; - map = (float *) calloc (high, wide*sizeof *map); - merror (map, "recover_highlights()"); - FORCC if (c != kc) { - memset (map, 0, high*wide*sizeof *map); - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - sum = wgt = count = 0; - for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) - for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { - pixel = image[row*width+col]; - if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { - sum += pixel[c]; - wgt += pixel[kc]; - count++; - } - } - if (count == SCALE*SCALE) - map[mrow*wide+mcol] = sum / wgt; - } - for (spread = 32/grow; spread--; ) { - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - if (map[mrow*wide+mcol]) continue; - sum = count = 0; - for (d=0; d < 8; d++) { - y = mrow + dir[d][0]; - x = mcol + dir[d][1]; - if (y < high && x < wide && map[y*wide+x] > 0) { - sum += (1 + (d & 1)) * map[y*wide+x]; - count += 1 + (d & 1); - } - } - if (count > 3) - map[mrow*wide+mcol] = - (sum+grow) / (count+grow); - } - for (change=i=0; i < high*wide; i++) - if (map[i] < 0) { - map[i] = -map[i]; - change = 1; - } - if (!change) break; - } - for (i=0; i < high*wide; i++) - if (map[i] == 0) map[i] = 1; - for (mrow=0; mrow < high; mrow++) - for (mcol=0; mcol < wide; mcol++) { - for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) - for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { - pixel = image[row*width+col]; - if (pixel[c] / hsat[c] > 1) { - val = pixel[kc] * map[mrow*wide+mcol]; - if (pixel[c] < val) pixel[c] = CLIP(val); - } - } - } - } - free (map); -} -#undef SCALE +//void CLASS median_filter() +//{ +// ushort (*pix)[4]; +// int pass, c, i, j, k, med[9]; +// static const uchar opt[] = /* Optimal 9-element median search */ +// { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, +// 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; +// +// for (pass=1; pass <= med_passes; pass++) { +// if (verbose) +// fprintf (stderr,_("Median filter pass %d...\n"), pass); +// for (c=0; c < 3; c+=2) { +// for (pix = image; pix < image+width*height; pix++) +// pix[0][3] = pix[0][c]; +// for (pix = image+width; pix < image+width*(height-1); pix++) { +// if ((pix-image+1) % width < 2) continue; +// for (k=0, i = -width; i <= width; i += width) +// for (j = i-1; j <= i+1; j++) +// med[k++] = pix[j][3] - pix[j][1]; +// for (i=0; i < sizeof opt; i+=2) +// if (med[opt[i]] > med[opt[i+1]]) +// SWAP (med[opt[i]] , med[opt[i+1]]); +// pix[0][c] = CLIP(med[4] + pix[0][1]); +// } +// } +// } +//} +// +//void CLASS blend_highlights() +//{ +// int clip=INT_MAX, row, col, c, i, j; +// static const float trans[2][4][4] = +// { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, +// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +// static const float itrans[2][4][4] = +// { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, +// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +// float cam[2][4], lab[2][4], sum[2], chratio; +// +// if ((unsigned) (colors-3) > 1) return; +// if (verbose) fprintf (stderr,_("Blending highlights...\n")); +// FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; +// for (row=0; row < height; row++) +// for (col=0; col < width; col++) { +// FORCC if (image[row*width+col][c] > clip) break; +// if (c == colors) continue; +// FORCC { +// cam[0][c] = image[row*width+col][c]; +// cam[1][c] = MIN(cam[0][c],clip); +// } +// for (i=0; i < 2; i++) { +// FORCC for (lab[i][c]=j=0; j < colors; j++) +// lab[i][c] += trans[colors-3][c][j] * cam[i][j]; +// for (sum[i]=0,c=1; c < colors; c++) +// sum[i] += SQR(lab[i][c]); +// } +// chratio = sqrt(sum[1]/sum[0]); +// for (c=1; c < colors; c++) +// lab[0][c] *= chratio; +// FORCC for (cam[0][c]=j=0; j < colors; j++) +// cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; +// FORCC image[row*width+col][c] = cam[0][c] / colors; +// } +//} +// +//#define SCALE (4 >> shrink) +//void CLASS recover_highlights() +//{ +// float *map, sum, wgt, grow; +// int hsat[4], count, spread, change, val, i; +// unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; +// ushort *pixel; +// static const signed char dir[8][2] = +// { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; +// +// if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); +// +// grow = pow (2, 4-highlight); +// FORCC hsat[c] = 32000 * pre_mul[c]; +// for (kc=0, c=1; c < colors; c++) +// if (pre_mul[kc] < pre_mul[c]) kc = c; +// high = height / SCALE; +// wide = width / SCALE; +// map = (float *) calloc (high, wide*sizeof *map); +// merror (map, "recover_highlights()"); +// FORCC if (c != kc) { +// memset (map, 0, high*wide*sizeof *map); +// for (mrow=0; mrow < high; mrow++) +// for (mcol=0; mcol < wide; mcol++) { +// sum = wgt = count = 0; +// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +// pixel = image[row*width+col]; +// if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { +// sum += pixel[c]; +// wgt += pixel[kc]; +// count++; +// } +// } +// if (count == SCALE*SCALE) +// map[mrow*wide+mcol] = sum / wgt; +// } +// for (spread = 32/grow; spread--; ) { +// for (mrow=0; mrow < high; mrow++) +// for (mcol=0; mcol < wide; mcol++) { +// if (map[mrow*wide+mcol]) continue; +// sum = count = 0; +// for (d=0; d < 8; d++) { +// y = mrow + dir[d][0]; +// x = mcol + dir[d][1]; +// if (y < high && x < wide && map[y*wide+x] > 0) { +// sum += (1 + (d & 1)) * map[y*wide+x]; +// count += 1 + (d & 1); +// } +// } +// if (count > 3) +// map[mrow*wide+mcol] = - (sum+grow) / (count+grow); +// } +// for (change=i=0; i < high*wide; i++) +// if (map[i] < 0) { +// map[i] = -map[i]; +// change = 1; +// } +// if (!change) break; +// } +// for (i=0; i < high*wide; i++) +// if (map[i] == 0) map[i] = 1; +// for (mrow=0; mrow < high; mrow++) +// for (mcol=0; mcol < wide; mcol++) { +// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +// pixel = image[row*width+col]; +// if (pixel[c] / hsat[c] > 1) { +// val = pixel[kc] * map[mrow*wide+mcol]; +// if (pixel[c] < val) pixel[c] = CLIP(val); +// } +// } +// } +// } +// free (map); +//} +//#undef SCALE void CLASS tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save) @@ -9533,55 +9533,55 @@ notraw: if (flip == UINT_MAX) flip = 0; } -#ifndef NO_LCMS -void CLASS apply_profile (const char *input, const char *output) -{ - char *prof; - cmsHPROFILE hInProfile=0, hOutProfile=0; - cmsHTRANSFORM hTransform; - FILE *fp; - unsigned size; - - if (strcmp (input, "embed")) - hInProfile = cmsOpenProfileFromFile (input, "r"); - else if (profile_length) { - prof = (char *) malloc (profile_length); - merror (prof, "apply_profile()"); - fseek (ifp, profile_offset, SEEK_SET); - fread (prof, 1, profile_length, ifp); - hInProfile = cmsOpenProfileFromMem (prof, profile_length); - free (prof); - } else - fprintf (stderr,_("%s has no embedded profile.\n"), ifname); - if (!hInProfile) return; - if (!output) - hOutProfile = cmsCreate_sRGBProfile(); - else if ((fp = fopen (output, "rb"))) { - fread (&size, 4, 1, fp); - fseek (fp, 0, SEEK_SET); - oprof = (unsigned *) malloc (size = ntohl(size)); - merror (oprof, "apply_profile()"); - fread (oprof, 1, size, fp); - fclose (fp); - if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { - free (oprof); - oprof = 0; - } - } else - fprintf (stderr,_("Cannot open file %s!\n"), output); - if (!hOutProfile) goto quit; - if (verbose) - fprintf (stderr,_("Applying color profile...\n")); - hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, - hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); - cmsDoTransform (hTransform, image, image, width*height); - raw_color = 1; /* Don't use rgb_cam with a profile */ - cmsDeleteTransform (hTransform); - cmsCloseProfile (hOutProfile); -quit: - cmsCloseProfile (hInProfile); -} -#endif +//#ifndef NO_LCMS +//void CLASS apply_profile (const char *input, const char *output) +//{ +// char *prof; +// cmsHPROFILE hInProfile=0, hOutProfile=0; +// cmsHTRANSFORM hTransform; +// FILE *fp; +// unsigned size; +// +// if (strcmp (input, "embed")) +// hInProfile = cmsOpenProfileFromFile (input, "r"); +// else if (profile_length) { +// prof = (char *) malloc (profile_length); +// merror (prof, "apply_profile()"); +// fseek (ifp, profile_offset, SEEK_SET); +// fread (prof, 1, profile_length, ifp); +// hInProfile = cmsOpenProfileFromMem (prof, profile_length); +// free (prof); +// } else +// fprintf (stderr,_("%s has no embedded profile.\n"), ifname); +// if (!hInProfile) return; +// if (!output) +// hOutProfile = cmsCreate_sRGBProfile(); +// else if ((fp = fopen (output, "rb"))) { +// fread (&size, 4, 1, fp); +// fseek (fp, 0, SEEK_SET); +// oprof = (unsigned *) malloc (size = ntohl(size)); +// merror (oprof, "apply_profile()"); +// fread (oprof, 1, size, fp); +// fclose (fp); +// if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { +// free (oprof); +// oprof = 0; +// } +// } else +// fprintf (stderr,_("Cannot open file %s!\n"), output); +// if (!hOutProfile) goto quit; +// if (verbose) +// fprintf (stderr,_("Applying color profile...\n")); +// hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, +// hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); +// cmsDoTransform (hTransform, image, image, width*height); +// raw_color = 1; /* Don't use rgb_cam with a profile */ +// cmsDeleteTransform (hTransform); +// cmsCloseProfile (hOutProfile); +//quit: +// cmsCloseProfile (hInProfile); +//} +//#endif /* RT: DNG Float */ diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 405f202bd..9d15a5826 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -50,7 +50,7 @@ public: ,shot_select(0),multi_out(0) ,float_raw_image(NULL) ,image(NULL) - ,bright(1.),threshold(0.) + ,bright(1.) ,half_size(0),four_color_rgb(0),document_mode(0),highlight(0) ,verbose(0) ,use_auto_wb(0),use_camera_wb(0),use_camera_matrix(1) @@ -344,23 +344,23 @@ void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); int foveon_apply_curve (short *curve, int i); void foveon_interpolate(); -void xtrans_interpolate (int passes); -void cielab (ushort rgb[3], short lab[3]); +//void xtrans_interpolate (int passes); +//void cielab (ushort rgb[3], short lab[3]); -void remove_zeroes(); -void bad_pixels (const char *cfname); -void subtract (const char *fname); +//void remove_zeroes(); +//void bad_pixels (const char *cfname); +//void subtract (const char *fname); void gamma_curve (double pwr, double ts, int mode, int imax); void pseudoinverse (double (*in)[3], double (*out)[3], int size); void cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3]); -void hat_transform (float *temp, float *base, int st, int size, int sc); -void wavelet_denoise(); +//void hat_transform (float *temp, float *base, int st, int size, int sc); +//void wavelet_denoise(); void scale_colors(); void pre_interpolate(); -void border_interpolate (int border); -void median_filter(); -void blend_highlights(); -void recover_highlights(); +//void border_interpolate (int border); +//void median_filter(); +//void blend_highlights(); +//void recover_highlights(); void crop_masked_pixels(); void tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save); @@ -397,7 +397,6 @@ void simple_coeff (int index); short guess_byte_order (int words); float find_green (int bps, int bite, int off0, int off1); void identify(); -void apply_profile (const char *input, const char *output); void jpeg_thumb() {} // not needed bool dcraw_coeff_overrides(const char make[], const char model[], int iso_speed, short trans[12], int *black_level, int *white_level); void shiftXtransMatrix( const int offsy, const int offsx) { From 093fa46aa61bfa8800ca8a1a5b0eb3efae9aeb0d Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 17 Oct 2016 22:20:33 +0200 Subject: [PATCH 20/20] Updated dcraw.patch file --- rtengine/dcraw.patch | 1496 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1443 insertions(+), 53 deletions(-) diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch index 82f2ec9b8..e23136d68 100644 --- a/rtengine/dcraw.patch +++ b/rtengine/dcraw.patch @@ -1,5 +1,5 @@ ---- dcraw.c 2016-09-30 21:19:28.312191811 +0200 -+++ dcraw.cc 2016-09-30 22:41:28.157442526 +0200 +--- dcraw.c 2016-10-11 13:24:24 +0000 ++++ dcraw.cc 2016-10-17 19:32:24 +0000 @@ -1,3 +1,16 @@ +/*RT*/#include +/*RT*/#include @@ -833,10 +833,468 @@ if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { -@@ -4366,239 +4690,8 @@ - } +@@ -3808,127 +4132,127 @@ + } } +-void CLASS remove_zeroes() +-{ +- unsigned row, col, tot, n, r, c; +- +- for (row=0; row < height; row++) +- for (col=0; col < width; col++) +- if (BAYER(row,col) == 0) { +- tot = n = 0; +- for (r = row-2; r <= row+2; r++) +- for (c = col-2; c <= col+2; c++) +- if (r < height && c < width && +- FC(r,c) == FC(row,col) && BAYER(r,c)) +- tot += (n++,BAYER(r,c)); +- if (n) BAYER(row,col) = tot/n; +- } +-} ++//void CLASS remove_zeroes() ++//{ ++// unsigned row, col, tot, n, r, c; ++// ++// for (row=0; row < height; row++) ++// for (col=0; col < width; col++) ++// if (BAYER(row,col) == 0) { ++// tot = n = 0; ++// for (r = row-2; r <= row+2; r++) ++// for (c = col-2; c <= col+2; c++) ++// if (r < height && c < width && ++// FC(r,c) == FC(row,col) && BAYER(r,c)) ++// tot += (n++,BAYER(r,c)); ++// if (n) BAYER(row,col) = tot/n; ++// } ++//} + + /* + Seach from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +-void CLASS bad_pixels (const char *cfname) +-{ +- FILE *fp=0; +- char *fname, *cp, line[128]; +- int len, time, row, col, r, c, rad, tot, n, fixed=0; +- +- if (!filters) return; +- if (cfname) +- fp = fopen (cfname, "r"); +- else { +- for (len=32 ; ; len *= 2) { +- fname = (char *) malloc (len); +- if (!fname) return; +- if (getcwd (fname, len-16)) break; +- free (fname); +- if (errno != ERANGE) return; +- } +-#if defined(WIN32) || defined(DJGPP) +- if (fname[1] == ':') +- memmove (fname, fname+2, len-2); +- for (cp=fname; *cp; cp++) +- if (*cp == '\\') *cp = '/'; +-#endif +- cp = fname + strlen(fname); +- if (cp[-1] == '/') cp--; +- while (*fname == '/') { +- strcpy (cp, "/.badpixels"); +- if ((fp = fopen (fname, "r"))) break; +- if (cp == fname) break; +- while (*--cp != '/'); +- } +- free (fname); +- } +- if (!fp) return; +- while (fgets (line, 128, fp)) { +- cp = strchr (line, '#'); +- if (cp) *cp = 0; +- if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; +- if ((unsigned) col >= width || (unsigned) row >= height) continue; +- if (time > timestamp) continue; +- for (tot=n=0, rad=1; rad < 3 && n==0; rad++) +- for (r = row-rad; r <= row+rad; r++) +- for (c = col-rad; c <= col+rad; c++) +- if ((unsigned) r < height && (unsigned) c < width && +- (r != row || c != col) && fcol(r,c) == fcol(row,col)) { +- tot += BAYER2(r,c); +- n++; +- } +- BAYER2(row,col) = tot/n; +- if (verbose) { +- if (!fixed++) +- fprintf (stderr,_("Fixed dead pixels at:")); +- fprintf (stderr, " %d,%d", col, row); +- } +- } +- if (fixed) fputc ('\n', stderr); +- fclose (fp); +-} +- +-void CLASS subtract (const char *fname) +-{ +- FILE *fp; +- int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; +- ushort *pixel; +- +- if (!(fp = fopen (fname, "rb"))) { +- perror (fname); return; +- } +- if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; +- while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { +- if (c == '#') comment = 1; +- if (c == '\n') comment = 0; +- if (comment) continue; +- if (isdigit(c)) number = 1; +- if (number) { +- if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; +- else if (isspace(c)) { +- number = 0; nd++; +- } else error = 1; +- } +- } +- if (error || nd < 3) { +- fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); +- fclose (fp); return; +- } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { +- fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); +- fclose (fp); return; +- } +- pixel = (ushort *) calloc (width, sizeof *pixel); +- merror (pixel, "subtract()"); +- for (row=0; row < height; row++) { +- fread (pixel, 2, width, fp); +- for (col=0; col < width; col++) +- BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); +- } +- free (pixel); +- fclose (fp); +- memset (cblack, 0, sizeof cblack); +- black = 0; +-} ++//void CLASS bad_pixels (const char *cfname) ++//{ ++// FILE *fp=0; ++// char *fname, *cp, line[128]; ++// int len, time, row, col, r, c, rad, tot, n, fixed=0; ++// ++// if (!filters) return; ++// if (cfname) ++// fp = fopen (cfname, "r"); ++// else { ++// for (len=32 ; ; len *= 2) { ++// fname = (char *) malloc (len); ++// if (!fname) return; ++// if (getcwd (fname, len-16)) break; ++// free (fname); ++// if (errno != ERANGE) return; ++// } ++//#if defined(WIN32) || defined(DJGPP) ++// if (fname[1] == ':') ++// memmove (fname, fname+2, len-2); ++// for (cp=fname; *cp; cp++) ++// if (*cp == '\\') *cp = '/'; ++//#endif ++// cp = fname + strlen(fname); ++// if (cp[-1] == '/') cp--; ++// while (*fname == '/') { ++// strcpy (cp, "/.badpixels"); ++// if ((fp = fopen (fname, "r"))) break; ++// if (cp == fname) break; ++// while (*--cp != '/'); ++// } ++// free (fname); ++// } ++// if (!fp) return; ++// while (fgets (line, 128, fp)) { ++// cp = strchr (line, '#'); ++// if (cp) *cp = 0; ++// if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; ++// if ((unsigned) col >= width || (unsigned) row >= height) continue; ++// if (time > timestamp) continue; ++// for (tot=n=0, rad=1; rad < 3 && n==0; rad++) ++// for (r = row-rad; r <= row+rad; r++) ++// for (c = col-rad; c <= col+rad; c++) ++// if ((unsigned) r < height && (unsigned) c < width && ++// (r != row || c != col) && fcol(r,c) == fcol(row,col)) { ++// tot += BAYER2(r,c); ++// n++; ++// } ++// BAYER2(row,col) = tot/n; ++// if (verbose) { ++// if (!fixed++) ++// fprintf (stderr,_("Fixed dead pixels at:")); ++// fprintf (stderr, " %d,%d", col, row); ++// } ++// } ++// if (fixed) fputc ('\n', stderr); ++// fclose (fp); ++//} ++ ++//void CLASS subtract (const char *fname) ++//{ ++// FILE *fp; ++// int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; ++// ushort *pixel; ++// ++// if (!(fp = fopen (fname, "rb"))) { ++// perror (fname); return; ++// } ++// if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; ++// while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { ++// if (c == '#') comment = 1; ++// if (c == '\n') comment = 0; ++// if (comment) continue; ++// if (isdigit(c)) number = 1; ++// if (number) { ++// if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; ++// else if (isspace(c)) { ++// number = 0; nd++; ++// } else error = 1; ++// } ++// } ++// if (error || nd < 3) { ++// fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); ++// fclose (fp); return; ++// } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { ++// fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); ++// fclose (fp); return; ++// } ++// pixel = (ushort *) calloc (width, sizeof *pixel); ++// merror (pixel, "subtract()"); ++// for (row=0; row < height; row++) { ++// fread (pixel, 2, width, fp); ++// for (col=0; col < width; col++) ++// BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); ++// } ++// free (pixel); ++// fclose (fp); ++// memset (cblack, 0, sizeof cblack); ++// black = 0; ++//} + + void CLASS gamma_curve (double pwr, double ts, int mode, int imax) + { +@@ -4093,94 +4417,94 @@ + } + #endif + +-void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) +-{ +- int i; +- for (i=0; i < sc; i++) +- temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; +- for (; i+sc < size; i++) +- temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; +- for (; i < size; i++) +- temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; +-} +- +-void CLASS wavelet_denoise() +-{ +- float *fimg=0, *temp, thold, mul[2], avg, diff; +- int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; +- ushort *window[4]; +- static const float noise[] = +- { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; +- +- if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); +- +- while (maximum << scale < 0x10000) scale++; +- maximum <<= --scale; +- black <<= scale; +- FORC4 cblack[c] <<= scale; +- if ((size = iheight*iwidth) < 0x15550000) +- fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); +- merror (fimg, "wavelet_denoise()"); +- temp = fimg + size*3; +- if ((nc = colors) == 3 && filters) nc++; +- FORC(nc) { /* denoise R,G1,B,G3 individually */ +- for (i=0; i < size; i++) +- fimg[i] = 256 * sqrt(image[i][c] << scale); +- for (hpass=lev=0; lev < 5; lev++) { +- lpass = size*((lev & 1)+1); +- for (row=0; row < iheight; row++) { +- hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); +- for (col=0; col < iwidth; col++) +- fimg[lpass + row*iwidth + col] = temp[col] * 0.25; +- } +- for (col=0; col < iwidth; col++) { +- hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); +- for (row=0; row < iheight; row++) +- fimg[lpass + row*iwidth + col] = temp[row] * 0.25; +- } +- thold = threshold * noise[lev]; +- for (i=0; i < size; i++) { +- fimg[hpass+i] -= fimg[lpass+i]; +- if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; +- else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; +- else fimg[hpass+i] = 0; +- if (hpass) fimg[i] += fimg[hpass+i]; +- } +- hpass = lpass; +- } +- for (i=0; i < size; i++) +- image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); +- } +- if (filters && colors == 3) { /* pull G1 and G3 closer together */ +- for (row=0; row < 2; row++) { +- mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; +- blk[row] = cblack[FC(row,0) | 1]; +- } +- for (i=0; i < 4; i++) +- window[i] = (ushort *) fimg + width*i; +- for (wlast=-1, row=1; row < height-1; row++) { +- while (wlast < row+1) { +- for (wlast++, i=0; i < 4; i++) +- window[(i+3) & 3] = window[i]; +- for (col = FC(wlast,1) & 1; col < width; col+=2) +- window[2][col] = BAYER(wlast,col); +- } +- thold = threshold/512; +- for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { +- avg = ( window[0][col-1] + window[0][col+1] + +- window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) +- * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; +- avg = avg < 0 ? 0 : sqrt(avg); +- diff = sqrt(BAYER(row,col)) - avg; +- if (diff < -thold) diff += thold; +- else if (diff > thold) diff -= thold; +- else diff = 0; +- BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); +- } +- } +- } +- free (fimg); +-} ++//void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) ++//{ ++// int i; ++// for (i=0; i < sc; i++) ++// temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; ++// for (; i+sc < size; i++) ++// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; ++// for (; i < size; i++) ++// temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; ++//} ++ ++//void CLASS wavelet_denoise() ++//{ ++// float *fimg=0, *temp, thold, mul[2], avg, diff; ++// int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ++// ushort *window[4]; ++// static const float noise[] = ++// { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; ++// ++// if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); ++// ++// while (maximum << scale < 0x10000) scale++; ++// maximum <<= --scale; ++// black <<= scale; ++// FORC4 cblack[c] <<= scale; ++// if ((size = iheight*iwidth) < 0x15550000) ++// fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); ++// merror (fimg, "wavelet_denoise()"); ++// temp = fimg + size*3; ++// if ((nc = colors) == 3 && filters) nc++; ++// FORC(nc) { /* denoise R,G1,B,G3 individually */ ++// for (i=0; i < size; i++) ++// fimg[i] = 256 * sqrt(image[i][c] << scale); ++// for (hpass=lev=0; lev < 5; lev++) { ++// lpass = size*((lev & 1)+1); ++// for (row=0; row < iheight; row++) { ++// hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); ++// for (col=0; col < iwidth; col++) ++// fimg[lpass + row*iwidth + col] = temp[col] * 0.25; ++// } ++// for (col=0; col < iwidth; col++) { ++// hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); ++// for (row=0; row < iheight; row++) ++// fimg[lpass + row*iwidth + col] = temp[row] * 0.25; ++// } ++// thold = threshold * noise[lev]; ++// for (i=0; i < size; i++) { ++// fimg[hpass+i] -= fimg[lpass+i]; ++// if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; ++// else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; ++// else fimg[hpass+i] = 0; ++// if (hpass) fimg[i] += fimg[hpass+i]; ++// } ++// hpass = lpass; ++// } ++// for (i=0; i < size; i++) ++// image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); ++// } ++// if (filters && colors == 3) { /* pull G1 and G3 closer together */ ++// for (row=0; row < 2; row++) { ++// mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; ++// blk[row] = cblack[FC(row,0) | 1]; ++// } ++// for (i=0; i < 4; i++) ++// window[i] = (ushort *) fimg + width*i; ++// for (wlast=-1, row=1; row < height-1; row++) { ++// while (wlast < row+1) { ++// for (wlast++, i=0; i < 4; i++) ++// window[(i+3) & 3] = window[i]; ++// for (col = FC(wlast,1) & 1; col < width; col+=2) ++// window[2][col] = BAYER(wlast,col); ++// } ++// thold = threshold/512; ++// for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { ++// avg = ( window[0][col-1] + window[0][col+1] + ++// window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) ++// * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; ++// avg = avg < 0 ? 0 : sqrt(avg); ++// diff = sqrt(BAYER(row,col)) - avg; ++// if (diff < -thold) diff += thold; ++// else if (diff > thold) diff -= thold; ++// else diff = 0; ++// BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); ++// } ++// } ++// } ++// free (fimg); ++//} + + void CLASS scale_colors() + { +@@ -4238,7 +4562,7 @@ + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + dark = black; + sat = maximum; +- if (threshold) wavelet_denoise(); ++// if (threshold) wavelet_denoise(); + maximum -= black; + for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { + if (dmin > pre_mul[c]) +@@ -4344,776 +4668,440 @@ + if (half_size) filters = 0; + } + +-void CLASS border_interpolate (int border) +-{ +- unsigned row, col, y, x, f, c, sum[8]; +- +- for (row=0; row < height; row++) +- for (col=0; col < width; col++) { +- if (col==border && row >= border && row < height-border) +- col = width-border; +- memset (sum, 0, sizeof sum); +- for (y=row-1; y != row+2; y++) +- for (x=col-1; x != col+2; x++) +- if (y < height && x < width) { +- f = fcol(y,x); +- sum[f] += image[y*width+x][f]; +- sum[f+4]++; +- } +- f = fcol(row,col); +- FORCC if (c != f && sum[c+4]) +- image[row*width+col][c] = sum[c] / sum[c+4]; +- } +-} +- -void CLASS lin_interpolate() -{ - int code[16][16][32], size=16, *ip, sum[4]; @@ -884,8 +1342,7 @@ - This algorithm is officially called: - - "Interpolation using a Threshold-based variable number of gradients" -+/* RT: delete interpolation functions */ - +- - described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html - - I've extended the basic idea to work with non-Bayer filter arrays. @@ -1071,13 +1528,271 @@ - pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); - } -} - - void CLASS cielab (ushort rgb[3], short lab[3]) - { -@@ -4864,112 +4957,7 @@ - } - #undef fcol - +- +-void CLASS cielab (ushort rgb[3], short lab[3]) +-{ +- int c, i, j, k; +- float r, xyz[3]; +- static float cbrt[0x10000], xyz_cam[3][4]; +- +- if (!rgb) { +- for (i=0; i < 0x10000; i++) { +- r = i / 65535.0; +- cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; +- } +- for (i=0; i < 3; i++) +- for (j=0; j < colors; j++) +- for (xyz_cam[i][j] = k=0; k < 3; k++) +- xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; +- return; +- } +- xyz[0] = xyz[1] = xyz[2] = 0.5; +- FORCC { +- xyz[0] += xyz_cam[0][c] * rgb[c]; +- xyz[1] += xyz_cam[1][c] * rgb[c]; +- xyz[2] += xyz_cam[2][c] * rgb[c]; +- } +- xyz[0] = cbrt[CLIP((int) xyz[0])]; +- xyz[1] = cbrt[CLIP((int) xyz[1])]; +- xyz[2] = cbrt[CLIP((int) xyz[2])]; +- lab[0] = 64 * (116 * xyz[1] - 16); +- lab[1] = 64 * 500 * (xyz[0] - xyz[1]); +- lab[2] = 64 * 200 * (xyz[1] - xyz[2]); +-} +- +-#define TS 512 /* Tile Size */ +-#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] +- +-/* +- Frank Markesteijn's algorithm for Fuji X-Trans sensors +- */ +-void CLASS xtrans_interpolate (int passes) +-{ +- int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; +- int val, ndir, pass, hm[8], avg[4], color[3][8]; +- static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, +- patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, +- { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, +- dir[4] = { 1,TS,TS+1,TS-1 }; +- short allhex[3][3][2][8], *hex; +- ushort min, max, sgrow, sgcol; +- ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; +- short (*lab) [TS][3], (*lix)[3]; +- float (*drv)[TS][TS], diff[6], tr; +- char (*homo)[TS][TS], *buffer; +- +- if (verbose) +- fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); +- +- cielab (0,0); +- ndir = 4 << (passes > 1); +- buffer = (char *) malloc (TS*TS*(ndir*11+6)); +- merror (buffer, "xtrans_interpolate()"); +- rgb = (ushort(*)[TS][TS][3]) buffer; +- lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); +- drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); +- homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); +- +-/* Map a green hexagon around each non-green pixel and vice versa: */ +- for (row=0; row < 3; row++) +- for (col=0; col < 3; col++) +- for (ng=d=0; d < 10; d+=2) { +- g = fcol(row,col) == 1; +- if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; +- if (ng == 4) { sgrow = row; sgcol = col; } +- if (ng == g+1) FORC(8) { +- v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; +- h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; +- allhex[row][col][0][c^(g*2 & d)] = h + v*width; +- allhex[row][col][1][c^(g*2 & d)] = h + v*TS; +- } +- } +- +-/* Set green1 and green3 to the minimum and maximum allowed values: */ +- for (row=2; row < height-2; row++) +- for (min=~(max=0), col=2; col < width-2; col++) { +- if (fcol(row,col) == 1 && (min=~(max=0))) continue; +- pix = image + row*width + col; +- hex = allhex[row % 3][col % 3][0]; +- if (!max) FORC(6) { +- val = pix[hex[c]][1]; +- if (min > val) min = val; +- if (max < val) max = val; +- } +- pix[0][1] = min; +- pix[0][3] = max; +- switch ((row-sgrow) % 3) { +- case 1: if (row < height-3) { row++; col--; } break; +- case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; +- } +- } +- +- for (top=3; top < height-19; top += TS-16) +- for (left=3; left < width-19; left += TS-16) { +- mrow = MIN (top+TS, height-3); +- mcol = MIN (left+TS, width-3); +- for (row=top; row < mrow; row++) +- for (col=left; col < mcol; col++) +- memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); +- FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); +- +-/* Interpolate green horizontally, vertically, and along both diagonals: */ +- for (row=top; row < mrow; row++) +- for (col=left; col < mcol; col++) { +- if ((f = fcol(row,col)) == 1) continue; +- pix = image + row*width + col; +- hex = allhex[row % 3][col % 3][0]; +- color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - +- 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); +- color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + +- 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); +- FORC(2) color[1][2+c] = +- 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * +- (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); +- FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = +- LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); +- } +- +- for (pass=0; pass < passes; pass++) { +- if (pass == 1) +- memcpy (rgb+=4, buffer, 4*sizeof *rgb); +- +-/* Recalculate green from interpolated values of closer pixels: */ +- if (pass) { +- for (row=top+2; row < mrow-2; row++) +- for (col=left+2; col < mcol-2; col++) { +- if ((f = fcol(row,col)) == 1) continue; +- pix = image + row*width + col; +- hex = allhex[row % 3][col % 3][1]; +- for (d=3; d < 6; d++) { +- rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; +- val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] +- - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; +- rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); +- } +- } +- } +- +-/* Interpolate red and blue values for solitary green pixels: */ +- for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) +- for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { +- rix = &rgb[0][row-top][col-left]; +- h = fcol(row,col+1); +- memset (diff, 0, sizeof diff); +- for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { +- for (c=0; c < 2; c++, h^=2) { +- g = 2*rix[0][1] - rix[i< 1) +- diff[d] += SQR (rix[i< 1 && (d & 1)) +- if (diff[d-1] < diff[d]) +- FORC(2) color[c*2][d] = color[c*2][d-1]; +- if (d < 2 || (d & 1)) { +- FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); +- rix += TS*TS; +- } +- } +- } +- +-/* Interpolate red for blue pixels and vice versa: */ +- for (row=top+3; row < mrow-3; row++) +- for (col=left+3; col < mcol-3; col++) { +- if ((f = 2-fcol(row,col)) == 1) continue; +- rix = &rgb[0][row-top][col-left]; +- c = (row-sgrow) % 3 ? TS:1; +- h = 3 * (c ^ TS ^ 1); +- for (d=0; d < 4; d++, rix += TS*TS) { +- i = d > 1 || ((d ^ c) & 1) || +- ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < +- 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; +- rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + +- 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); +- } +- } +- +-/* Fill in red and blue for 2x2 blocks of green: */ +- for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) +- for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { +- rix = &rgb[0][row-top][col-left]; +- hex = allhex[row % 3][col % 3][1]; +- for (d=0; d < ndir; d+=2, rix += TS*TS) +- if (hex[d] + hex[d+1]) { +- g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; +- for (c=0; c < 4; c+=2) rix[0][c] = +- CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); +- } else { +- g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; +- for (c=0; c < 4; c+=2) rix[0][c] = +- CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); +- } +- } +- } +- rgb = (ushort(*)[TS][TS][3]) buffer; +- mrow -= top; +- mcol -= left; +- +-/* Convert to CIELab and differentiate in all directions: */ +- for (d=0; d < ndir; d++) { +- for (row=2; row < mrow-2; row++) +- for (col=2; col < mcol-2; col++) +- cielab (rgb[d][row][col], lab[row][col]); +- for (f=dir[d & 3],row=3; row < mrow-3; row++) +- for (col=3; col < mcol-3; col++) { +- lix = &lab[row][col]; +- g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; +- drv[d][row][col] = SQR(g) +- + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) +- + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); +- } +- } +- +-/* Build homogeneity maps from the derivatives: */ +- memset(homo, 0, ndir*TS*TS); +- for (row=4; row < mrow-4; row++) +- for (col=4; col < mcol-4; col++) { +- for (tr=FLT_MAX, d=0; d < ndir; d++) +- if (tr > drv[d][row][col]) +- tr = drv[d][row][col]; +- tr *= 8; +- for (d=0; d < ndir; d++) +- for (v=-1; v <= 1; v++) +- for (h=-1; h <= 1; h++) +- if (drv[d][row+v][col+h] <= tr) +- homo[d][row][col]++; +- } +- +-/* Average the most homogenous pixels for the final result: */ +- if (height-top < TS+4) mrow = height-top+2; +- if (width-left < TS+4) mcol = width-left+2; +- for (row = MIN(top,8); row < mrow-8; row++) +- for (col = MIN(left,8); col < mcol-8; col++) { +- for (d=0; d < ndir; d++) +- for (hm[d]=0, v=-2; v <= 2; v++) +- for (h=-2; h <= 2; h++) +- hm[d] += homo[d][row+v][col+h]; +- for (d=0; d < ndir-4; d++) +- if (hm[d] < hm[d+4]) hm[d ] = 0; else +- if (hm[d] > hm[d+4]) hm[d+4] = 0; +- for (max=hm[0],d=1; d < ndir; d++) +- if (max < hm[d]) max = hm[d]; +- max -= max >> 3; +- memset (avg, 0, sizeof avg); +- for (d=0; d < ndir; d++) +- if (hm[d] >= max) { +- FORC3 avg[c] += rgb[d][row][col][c]; +- avg[3]++; +- } +- FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; +- } +- } +- free(buffer); +- border_interpolate(8); +-} +-#undef fcol +- -/* - Adaptive Homogeneity-Directed interpolation is based on - the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. @@ -1103,7 +1818,7 @@ - - for (top=2; top < height-5; top += TS-6) - for (left=2; left < width-5; left += TS-6) { - +- -/* Interpolate green horizontally and vertically: */ - for (row=top; row < top+TS && row < height-2; row++) { - col = left + (FC(row,left) & 1); @@ -1184,9 +1899,587 @@ - } - free (buffer); -} - #undef TS +-#undef TS +- +-void CLASS median_filter() +-{ +- ushort (*pix)[4]; +- int pass, c, i, j, k, med[9]; +- static const uchar opt[] = /* Optimal 9-element median search */ +- { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, +- 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; +- +- for (pass=1; pass <= med_passes; pass++) { +- if (verbose) +- fprintf (stderr,_("Median filter pass %d...\n"), pass); +- for (c=0; c < 3; c+=2) { +- for (pix = image; pix < image+width*height; pix++) +- pix[0][3] = pix[0][c]; +- for (pix = image+width; pix < image+width*(height-1); pix++) { +- if ((pix-image+1) % width < 2) continue; +- for (k=0, i = -width; i <= width; i += width) +- for (j = i-1; j <= i+1; j++) +- med[k++] = pix[j][3] - pix[j][1]; +- for (i=0; i < sizeof opt; i+=2) +- if (med[opt[i]] > med[opt[i+1]]) +- SWAP (med[opt[i]] , med[opt[i+1]]); +- pix[0][c] = CLIP(med[4] + pix[0][1]); +- } +- } +- } +-} +- +-void CLASS blend_highlights() +-{ +- int clip=INT_MAX, row, col, c, i, j; +- static const float trans[2][4][4] = +- { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, +- { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +- static const float itrans[2][4][4] = +- { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, +- { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; +- float cam[2][4], lab[2][4], sum[2], chratio; +- +- if ((unsigned) (colors-3) > 1) return; +- if (verbose) fprintf (stderr,_("Blending highlights...\n")); +- FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; +- for (row=0; row < height; row++) +- for (col=0; col < width; col++) { +- FORCC if (image[row*width+col][c] > clip) break; +- if (c == colors) continue; +- FORCC { +- cam[0][c] = image[row*width+col][c]; +- cam[1][c] = MIN(cam[0][c],clip); +- } +- for (i=0; i < 2; i++) { +- FORCC for (lab[i][c]=j=0; j < colors; j++) +- lab[i][c] += trans[colors-3][c][j] * cam[i][j]; +- for (sum[i]=0,c=1; c < colors; c++) +- sum[i] += SQR(lab[i][c]); +- } +- chratio = sqrt(sum[1]/sum[0]); +- for (c=1; c < colors; c++) +- lab[0][c] *= chratio; +- FORCC for (cam[0][c]=j=0; j < colors; j++) +- cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; +- FORCC image[row*width+col][c] = cam[0][c] / colors; +- } +-} +- +-#define SCALE (4 >> shrink) +-void CLASS recover_highlights() +-{ +- float *map, sum, wgt, grow; +- int hsat[4], count, spread, change, val, i; +- unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; +- ushort *pixel; +- static const signed char dir[8][2] = +- { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; +- +- if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); +- +- grow = pow (2, 4-highlight); +- FORCC hsat[c] = 32000 * pre_mul[c]; +- for (kc=0, c=1; c < colors; c++) +- if (pre_mul[kc] < pre_mul[c]) kc = c; +- high = height / SCALE; +- wide = width / SCALE; +- map = (float *) calloc (high, wide*sizeof *map); +- merror (map, "recover_highlights()"); +- FORCC if (c != kc) { +- memset (map, 0, high*wide*sizeof *map); +- for (mrow=0; mrow < high; mrow++) +- for (mcol=0; mcol < wide; mcol++) { +- sum = wgt = count = 0; +- for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +- for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +- pixel = image[row*width+col]; +- if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { +- sum += pixel[c]; +- wgt += pixel[kc]; +- count++; +- } +- } +- if (count == SCALE*SCALE) +- map[mrow*wide+mcol] = sum / wgt; +- } +- for (spread = 32/grow; spread--; ) { +- for (mrow=0; mrow < high; mrow++) +- for (mcol=0; mcol < wide; mcol++) { +- if (map[mrow*wide+mcol]) continue; +- sum = count = 0; +- for (d=0; d < 8; d++) { +- y = mrow + dir[d][0]; +- x = mcol + dir[d][1]; +- if (y < high && x < wide && map[y*wide+x] > 0) { +- sum += (1 + (d & 1)) * map[y*wide+x]; +- count += 1 + (d & 1); +- } +- } +- if (count > 3) +- map[mrow*wide+mcol] = - (sum+grow) / (count+grow); +- } +- for (change=i=0; i < high*wide; i++) +- if (map[i] < 0) { +- map[i] = -map[i]; +- change = 1; +- } +- if (!change) break; +- } +- for (i=0; i < high*wide; i++) +- if (map[i] == 0) map[i] = 1; +- for (mrow=0; mrow < high; mrow++) +- for (mcol=0; mcol < wide; mcol++) { +- for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) +- for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { +- pixel = image[row*width+col]; +- if (pixel[c] / hsat[c] > 1) { +- val = pixel[kc] * map[mrow*wide+mcol]; +- if (pixel[c] < val) pixel[c] = CLIP(val); +- } +- } +- } +- } +- free (map); +-} +-#undef SCALE ++//void CLASS border_interpolate (int border) ++//{ ++// unsigned row, col, y, x, f, c, sum[8]; ++// ++// for (row=0; row < height; row++) ++// for (col=0; col < width; col++) { ++// if (col==border && row >= border && row < height-border) ++// col = width-border; ++// memset (sum, 0, sizeof sum); ++// for (y=row-1; y != row+2; y++) ++// for (x=col-1; x != col+2; x++) ++// if (y < height && x < width) { ++// f = fcol(y,x); ++// sum[f] += image[y*width+x][f]; ++// sum[f+4]++; ++// } ++// f = fcol(row,col); ++// FORCC if (c != f && sum[c+4]) ++// image[row*width+col][c] = sum[c] / sum[c+4]; ++// } ++//} ++ ++/* RT: delete interpolation functions */ ++ ++ ++//void CLASS cielab (ushort rgb[3], short lab[3]) ++//{ ++// int c, i, j, k; ++// float r, xyz[3]; ++// static float cbrt[0x10000], xyz_cam[3][4]; ++// ++// if (!rgb) { ++// for (i=0; i < 0x10000; i++) { ++// r = i / 65535.0; ++// cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; ++// } ++// for (i=0; i < 3; i++) ++// for (j=0; j < colors; j++) ++// for (xyz_cam[i][j] = k=0; k < 3; k++) ++// xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; ++// return; ++// } ++// xyz[0] = xyz[1] = xyz[2] = 0.5; ++// FORCC { ++// xyz[0] += xyz_cam[0][c] * rgb[c]; ++// xyz[1] += xyz_cam[1][c] * rgb[c]; ++// xyz[2] += xyz_cam[2][c] * rgb[c]; ++// } ++// xyz[0] = cbrt[CLIP((int) xyz[0])]; ++// xyz[1] = cbrt[CLIP((int) xyz[1])]; ++// xyz[2] = cbrt[CLIP((int) xyz[2])]; ++// lab[0] = 64 * (116 * xyz[1] - 16); ++// lab[1] = 64 * 500 * (xyz[0] - xyz[1]); ++// lab[2] = 64 * 200 * (xyz[1] - xyz[2]); ++//} ++// ++//#define TS 512 /* Tile Size */ ++//#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6] ++// ++///* ++// Frank Markesteijn's algorithm for Fuji X-Trans sensors ++// */ ++//void CLASS xtrans_interpolate (int passes) ++//{ ++// int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; ++// int val, ndir, pass, hm[8], avg[4], color[3][8]; ++// static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, ++// patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, ++// { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, ++// dir[4] = { 1,TS,TS+1,TS-1 }; ++// short allhex[3][3][2][8], *hex; ++// ushort min, max, sgrow, sgcol; ++// ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; ++// short (*lab) [TS][3], (*lix)[3]; ++// float (*drv)[TS][TS], diff[6], tr; ++// char (*homo)[TS][TS], *buffer; ++// ++// if (verbose) ++// fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); ++// ++// cielab (0,0); ++// ndir = 4 << (passes > 1); ++// buffer = (char *) malloc (TS*TS*(ndir*11+6)); ++// merror (buffer, "xtrans_interpolate()"); ++// rgb = (ushort(*)[TS][TS][3]) buffer; ++// lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); ++// drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); ++// homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); ++// ++///* Map a green hexagon around each non-green pixel and vice versa: */ ++// for (row=0; row < 3; row++) ++// for (col=0; col < 3; col++) ++// for (ng=d=0; d < 10; d+=2) { ++// g = fcol(row,col) == 1; ++// if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; ++// if (ng == 4) { sgrow = row; sgcol = col; } ++// if (ng == g+1) FORC(8) { ++// v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; ++// h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; ++// allhex[row][col][0][c^(g*2 & d)] = h + v*width; ++// allhex[row][col][1][c^(g*2 & d)] = h + v*TS; ++// } ++// } ++// ++///* Set green1 and green3 to the minimum and maximum allowed values: */ ++// for (row=2; row < height-2; row++) ++// for (min=~(max=0), col=2; col < width-2; col++) { ++// if (fcol(row,col) == 1 && (min=~(max=0))) continue; ++// pix = image + row*width + col; ++// hex = allhex[row % 3][col % 3][0]; ++// if (!max) FORC(6) { ++// val = pix[hex[c]][1]; ++// if (min > val) min = val; ++// if (max < val) max = val; ++// } ++// pix[0][1] = min; ++// pix[0][3] = max; ++// switch ((row-sgrow) % 3) { ++// case 1: if (row < height-3) { row++; col--; } break; ++// case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; ++// } ++// } ++// ++// for (top=3; top < height-19; top += TS-16) ++// for (left=3; left < width-19; left += TS-16) { ++// mrow = MIN (top+TS, height-3); ++// mcol = MIN (left+TS, width-3); ++// for (row=top; row < mrow; row++) ++// for (col=left; col < mcol; col++) ++// memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); ++// FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); ++// ++///* Interpolate green horizontally, vertically, and along both diagonals: */ ++// for (row=top; row < mrow; row++) ++// for (col=left; col < mcol; col++) { ++// if ((f = fcol(row,col)) == 1) continue; ++// pix = image + row*width + col; ++// hex = allhex[row % 3][col % 3][0]; ++// color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - ++// 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); ++// color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + ++// 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); ++// FORC(2) color[1][2+c] = ++// 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * ++// (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); ++// FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = ++// LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); ++// } ++// ++// for (pass=0; pass < passes; pass++) { ++// if (pass == 1) ++// memcpy (rgb+=4, buffer, 4*sizeof *rgb); ++// ++///* Recalculate green from interpolated values of closer pixels: */ ++// if (pass) { ++// for (row=top+2; row < mrow-2; row++) ++// for (col=left+2; col < mcol-2; col++) { ++// if ((f = fcol(row,col)) == 1) continue; ++// pix = image + row*width + col; ++// hex = allhex[row % 3][col % 3][1]; ++// for (d=3; d < 6; d++) { ++// rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; ++// val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] ++// - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; ++// rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); ++// } ++// } ++// } ++// ++///* Interpolate red and blue values for solitary green pixels: */ ++// for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) ++// for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { ++// rix = &rgb[0][row-top][col-left]; ++// h = fcol(row,col+1); ++// memset (diff, 0, sizeof diff); ++// for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { ++// for (c=0; c < 2; c++, h^=2) { ++// g = 2*rix[0][1] - rix[i< 1) ++// diff[d] += SQR (rix[i< 1 && (d & 1)) ++// if (diff[d-1] < diff[d]) ++// FORC(2) color[c*2][d] = color[c*2][d-1]; ++// if (d < 2 || (d & 1)) { ++// FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); ++// rix += TS*TS; ++// } ++// } ++// } ++// ++///* Interpolate red for blue pixels and vice versa: */ ++// for (row=top+3; row < mrow-3; row++) ++// for (col=left+3; col < mcol-3; col++) { ++// if ((f = 2-fcol(row,col)) == 1) continue; ++// rix = &rgb[0][row-top][col-left]; ++// c = (row-sgrow) % 3 ? TS:1; ++// h = 3 * (c ^ TS ^ 1); ++// for (d=0; d < 4; d++, rix += TS*TS) { ++// i = d > 1 || ((d ^ c) & 1) || ++// ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) < ++// 2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h; ++// rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + ++// 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); ++// } ++// } ++// ++///* Fill in red and blue for 2x2 blocks of green: */ ++// for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) ++// for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { ++// rix = &rgb[0][row-top][col-left]; ++// hex = allhex[row % 3][col % 3][1]; ++// for (d=0; d < ndir; d+=2, rix += TS*TS) ++// if (hex[d] + hex[d+1]) { ++// g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; ++// for (c=0; c < 4; c+=2) rix[0][c] = ++// CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); ++// } else { ++// g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; ++// for (c=0; c < 4; c+=2) rix[0][c] = ++// CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); ++// } ++// } ++// } ++// rgb = (ushort(*)[TS][TS][3]) buffer; ++// mrow -= top; ++// mcol -= left; ++// ++///* Convert to CIELab and differentiate in all directions: */ ++// for (d=0; d < ndir; d++) { ++// for (row=2; row < mrow-2; row++) ++// for (col=2; col < mcol-2; col++) ++// cielab (rgb[d][row][col], lab[row][col]); ++// for (f=dir[d & 3],row=3; row < mrow-3; row++) ++// for (col=3; col < mcol-3; col++) { ++// lix = &lab[row][col]; ++// g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; ++// drv[d][row][col] = SQR(g) ++// + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) ++// + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); ++// } ++// } ++// ++///* Build homogeneity maps from the derivatives: */ ++// memset(homo, 0, ndir*TS*TS); ++// for (row=4; row < mrow-4; row++) ++// for (col=4; col < mcol-4; col++) { ++// for (tr=FLT_MAX, d=0; d < ndir; d++) ++// if (tr > drv[d][row][col]) ++// tr = drv[d][row][col]; ++// tr *= 8; ++// for (d=0; d < ndir; d++) ++// for (v=-1; v <= 1; v++) ++// for (h=-1; h <= 1; h++) ++// if (drv[d][row+v][col+h] <= tr) ++// homo[d][row][col]++; ++// } ++// ++///* Average the most homogenous pixels for the final result: */ ++// if (height-top < TS+4) mrow = height-top+2; ++// if (width-left < TS+4) mcol = width-left+2; ++// for (row = MIN(top,8); row < mrow-8; row++) ++// for (col = MIN(left,8); col < mcol-8; col++) { ++// for (d=0; d < ndir; d++) ++// for (hm[d]=0, v=-2; v <= 2; v++) ++// for (h=-2; h <= 2; h++) ++// hm[d] += homo[d][row+v][col+h]; ++// for (d=0; d < ndir-4; d++) ++// if (hm[d] < hm[d+4]) hm[d ] = 0; else ++// if (hm[d] > hm[d+4]) hm[d+4] = 0; ++// for (max=hm[0],d=1; d < ndir; d++) ++// if (max < hm[d]) max = hm[d]; ++// max -= max >> 3; ++// memset (avg, 0, sizeof avg); ++// for (d=0; d < ndir; d++) ++// if (hm[d] >= max) { ++// FORC3 avg[c] += rgb[d][row][col][c]; ++// avg[3]++; ++// } ++// FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; ++// } ++// } ++// free(buffer); ++// border_interpolate(8); ++//} ++//#undef fcol ++// ++// ++//#undef TS ++ ++//void CLASS median_filter() ++//{ ++// ushort (*pix)[4]; ++// int pass, c, i, j, k, med[9]; ++// static const uchar opt[] = /* Optimal 9-element median search */ ++// { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, ++// 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; ++// ++// for (pass=1; pass <= med_passes; pass++) { ++// if (verbose) ++// fprintf (stderr,_("Median filter pass %d...\n"), pass); ++// for (c=0; c < 3; c+=2) { ++// for (pix = image; pix < image+width*height; pix++) ++// pix[0][3] = pix[0][c]; ++// for (pix = image+width; pix < image+width*(height-1); pix++) { ++// if ((pix-image+1) % width < 2) continue; ++// for (k=0, i = -width; i <= width; i += width) ++// for (j = i-1; j <= i+1; j++) ++// med[k++] = pix[j][3] - pix[j][1]; ++// for (i=0; i < sizeof opt; i+=2) ++// if (med[opt[i]] > med[opt[i+1]]) ++// SWAP (med[opt[i]] , med[opt[i+1]]); ++// pix[0][c] = CLIP(med[4] + pix[0][1]); ++// } ++// } ++// } ++//} ++// ++//void CLASS blend_highlights() ++//{ ++// int clip=INT_MAX, row, col, c, i, j; ++// static const float trans[2][4][4] = ++// { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, ++// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; ++// static const float itrans[2][4][4] = ++// { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, ++// { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; ++// float cam[2][4], lab[2][4], sum[2], chratio; ++// ++// if ((unsigned) (colors-3) > 1) return; ++// if (verbose) fprintf (stderr,_("Blending highlights...\n")); ++// FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; ++// for (row=0; row < height; row++) ++// for (col=0; col < width; col++) { ++// FORCC if (image[row*width+col][c] > clip) break; ++// if (c == colors) continue; ++// FORCC { ++// cam[0][c] = image[row*width+col][c]; ++// cam[1][c] = MIN(cam[0][c],clip); ++// } ++// for (i=0; i < 2; i++) { ++// FORCC for (lab[i][c]=j=0; j < colors; j++) ++// lab[i][c] += trans[colors-3][c][j] * cam[i][j]; ++// for (sum[i]=0,c=1; c < colors; c++) ++// sum[i] += SQR(lab[i][c]); ++// } ++// chratio = sqrt(sum[1]/sum[0]); ++// for (c=1; c < colors; c++) ++// lab[0][c] *= chratio; ++// FORCC for (cam[0][c]=j=0; j < colors; j++) ++// cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; ++// FORCC image[row*width+col][c] = cam[0][c] / colors; ++// } ++//} ++// ++//#define SCALE (4 >> shrink) ++//void CLASS recover_highlights() ++//{ ++// float *map, sum, wgt, grow; ++// int hsat[4], count, spread, change, val, i; ++// unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; ++// ushort *pixel; ++// static const signed char dir[8][2] = ++// { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; ++// ++// if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); ++// ++// grow = pow (2, 4-highlight); ++// FORCC hsat[c] = 32000 * pre_mul[c]; ++// for (kc=0, c=1; c < colors; c++) ++// if (pre_mul[kc] < pre_mul[c]) kc = c; ++// high = height / SCALE; ++// wide = width / SCALE; ++// map = (float *) calloc (high, wide*sizeof *map); ++// merror (map, "recover_highlights()"); ++// FORCC if (c != kc) { ++// memset (map, 0, high*wide*sizeof *map); ++// for (mrow=0; mrow < high; mrow++) ++// for (mcol=0; mcol < wide; mcol++) { ++// sum = wgt = count = 0; ++// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) ++// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { ++// pixel = image[row*width+col]; ++// if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { ++// sum += pixel[c]; ++// wgt += pixel[kc]; ++// count++; ++// } ++// } ++// if (count == SCALE*SCALE) ++// map[mrow*wide+mcol] = sum / wgt; ++// } ++// for (spread = 32/grow; spread--; ) { ++// for (mrow=0; mrow < high; mrow++) ++// for (mcol=0; mcol < wide; mcol++) { ++// if (map[mrow*wide+mcol]) continue; ++// sum = count = 0; ++// for (d=0; d < 8; d++) { ++// y = mrow + dir[d][0]; ++// x = mcol + dir[d][1]; ++// if (y < high && x < wide && map[y*wide+x] > 0) { ++// sum += (1 + (d & 1)) * map[y*wide+x]; ++// count += 1 + (d & 1); ++// } ++// } ++// if (count > 3) ++// map[mrow*wide+mcol] = - (sum+grow) / (count+grow); ++// } ++// for (change=i=0; i < high*wide; i++) ++// if (map[i] < 0) { ++// map[i] = -map[i]; ++// change = 1; ++// } ++// if (!change) break; ++// } ++// for (i=0; i < high*wide; i++) ++// if (map[i] == 0) map[i] = 1; ++// for (mrow=0; mrow < high; mrow++) ++// for (mcol=0; mcol < wide; mcol++) { ++// for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) ++// for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { ++// pixel = image[row*width+col]; ++// if (pixel[c] / hsat[c] > 1) { ++// val = pixel[kc] * map[mrow*wide+mcol]; ++// if (pixel[c] < val) pixel[c] = CLIP(val); ++// } ++// } ++// } ++// } ++// free (map); ++//} ++//#undef SCALE - void CLASS median_filter() + void CLASS tiff_get (unsigned base, + unsigned *tag, unsigned *type, unsigned *len, unsigned *save) @@ -5139,7 +5127,7 @@ } } @@ -1783,9 +3076,141 @@ is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { -@@ -9452,199 +9583,250 @@ +@@ -9402,249 +9533,300 @@ + if (flip == UINT_MAX) flip = 0; } - #endif + +-#ifndef NO_LCMS +-void CLASS apply_profile (const char *input, const char *output) +-{ +- char *prof; +- cmsHPROFILE hInProfile=0, hOutProfile=0; +- cmsHTRANSFORM hTransform; +- FILE *fp; +- unsigned size; +- +- if (strcmp (input, "embed")) +- hInProfile = cmsOpenProfileFromFile (input, "r"); +- else if (profile_length) { +- prof = (char *) malloc (profile_length); +- merror (prof, "apply_profile()"); +- fseek (ifp, profile_offset, SEEK_SET); +- fread (prof, 1, profile_length, ifp); +- hInProfile = cmsOpenProfileFromMem (prof, profile_length); +- free (prof); +- } else +- fprintf (stderr,_("%s has no embedded profile.\n"), ifname); +- if (!hInProfile) return; +- if (!output) +- hOutProfile = cmsCreate_sRGBProfile(); +- else if ((fp = fopen (output, "rb"))) { +- fread (&size, 4, 1, fp); +- fseek (fp, 0, SEEK_SET); +- oprof = (unsigned *) malloc (size = ntohl(size)); +- merror (oprof, "apply_profile()"); +- fread (oprof, 1, size, fp); +- fclose (fp); +- if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { +- free (oprof); +- oprof = 0; ++//#ifndef NO_LCMS ++//void CLASS apply_profile (const char *input, const char *output) ++//{ ++// char *prof; ++// cmsHPROFILE hInProfile=0, hOutProfile=0; ++// cmsHTRANSFORM hTransform; ++// FILE *fp; ++// unsigned size; ++// ++// if (strcmp (input, "embed")) ++// hInProfile = cmsOpenProfileFromFile (input, "r"); ++// else if (profile_length) { ++// prof = (char *) malloc (profile_length); ++// merror (prof, "apply_profile()"); ++// fseek (ifp, profile_offset, SEEK_SET); ++// fread (prof, 1, profile_length, ifp); ++// hInProfile = cmsOpenProfileFromMem (prof, profile_length); ++// free (prof); ++// } else ++// fprintf (stderr,_("%s has no embedded profile.\n"), ifname); ++// if (!hInProfile) return; ++// if (!output) ++// hOutProfile = cmsCreate_sRGBProfile(); ++// else if ((fp = fopen (output, "rb"))) { ++// fread (&size, 4, 1, fp); ++// fseek (fp, 0, SEEK_SET); ++// oprof = (unsigned *) malloc (size = ntohl(size)); ++// merror (oprof, "apply_profile()"); ++// fread (oprof, 1, size, fp); ++// fclose (fp); ++// if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { ++// free (oprof); ++// oprof = 0; ++// } ++// } else ++// fprintf (stderr,_("Cannot open file %s!\n"), output); ++// if (!hOutProfile) goto quit; ++// if (verbose) ++// fprintf (stderr,_("Applying color profile...\n")); ++// hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, ++// hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); ++// cmsDoTransform (hTransform, image, image, width*height); ++// raw_color = 1; /* Don't use rgb_cam with a profile */ ++// cmsDeleteTransform (hTransform); ++// cmsCloseProfile (hOutProfile); ++//quit: ++// cmsCloseProfile (hInProfile); ++//} ++//#endif ++ ++/* RT: DNG Float */ ++ ++#include ++#include ++ ++static void decodeFPDeltaRow(Bytef * src, Bytef * dst, size_t tileWidth, size_t realTileWidth, int bytesps, int factor) { ++ // DecodeDeltaBytes ++ for (size_t col = factor; col < realTileWidth*bytesps; ++col) { ++ src[col] += src[col - factor]; ++ } ++ // Reorder bytes into the image ++ // 16 and 32-bit versions depend on local architecture, 24-bit does not ++ if (bytesps == 3) { ++ for (size_t col = 0; col < tileWidth; ++col) { ++ dst[col*3] = src[col]; ++ dst[col*3 + 1] = src[col + realTileWidth]; ++ dst[col*3 + 2] = src[col + realTileWidth*2]; + } +- } else +- fprintf (stderr,_("Cannot open file %s!\n"), output); +- if (!hOutProfile) goto quit; +- if (verbose) +- fprintf (stderr,_("Applying color profile...\n")); +- hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, +- hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); +- cmsDoTransform (hTransform, image, image, width*height); +- raw_color = 1; /* Don't use rgb_cam with a profile */ +- cmsDeleteTransform (hTransform); +- cmsCloseProfile (hOutProfile); +-quit: +- cmsCloseProfile (hInProfile); ++ } else { ++ union X { uint32_t x; uint8_t c; }; ++ if (((union X){1}).c) { ++ for (size_t col = 0; col < tileWidth; ++col) { ++ for (size_t byte = 0; byte < bytesps; ++byte) ++ dst[col*bytesps + byte] = src[col + realTileWidth*(bytesps-byte-1)]; // Little endian ++ } ++ } else { ++ for (size_t col = 0; col < tileWidth; ++col) { ++ for (size_t byte = 0; byte < bytesps; ++byte) ++ dst[col*bytesps + byte] = src[col + realTileWidth*byte]; ++ } ++ } ++ } ++ + } +-#endif -void CLASS convert_to_rgb() -{ @@ -1872,41 +3297,6 @@ - for (j=0; j < colors; j++) - for (out_cam[i][j] = k=0; k < 3; k++) - out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; -+/* RT: DNG Float */ -+ -+#include -+#include -+ -+static void decodeFPDeltaRow(Bytef * src, Bytef * dst, size_t tileWidth, size_t realTileWidth, int bytesps, int factor) { -+ // DecodeDeltaBytes -+ for (size_t col = factor; col < realTileWidth*bytesps; ++col) { -+ src[col] += src[col - factor]; -+ } -+ // Reorder bytes into the image -+ // 16 and 32-bit versions depend on local architecture, 24-bit does not -+ if (bytesps == 3) { -+ for (size_t col = 0; col < tileWidth; ++col) { -+ dst[col*3] = src[col]; -+ dst[col*3 + 1] = src[col + realTileWidth]; -+ dst[col*3 + 2] = src[col + realTileWidth*2]; -+ } -+ } else { -+ union X { uint32_t x; uint8_t c; }; -+ if (((union X){1}).c) { -+ for (size_t col = 0; col < tileWidth; ++col) { -+ for (size_t byte = 0; byte < bytesps; ++byte) -+ dst[col*bytesps + byte] = src[col + realTileWidth*(bytesps-byte-1)]; // Little endian -+ } -+ } else { -+ for (size_t col = 0; col < tileWidth; ++col) { -+ for (size_t byte = 0; byte < bytesps; ++byte) -+ dst[col*bytesps + byte] = src[col + realTileWidth*byte]; -+ } -+ } -+ } -+ -+} -+ +// From DNG SDK dng_utils.h +static inline uint32_t DNG_HalfToFloat(uint16_t halfValue) { + int32_t sign = (halfValue >> 15) & 0x00000001;