diff --git a/AUTHORS.txt b/AUTHORS.txt index 227390faa..aae24ff63 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -7,6 +7,7 @@ Development contributors, in last name alphabetical order: Roel Baars Martin Burri + Pierre Cabrera Javier Celaya Jacques Desmis Pavlov Dmitry @@ -20,6 +21,7 @@ Development contributors, in last name alphabetical order: Steve Herrell Philippe Hupé Wolfgang Kuehnel + Lawrence Lee Guokai Ma Emil Martinec Wyatt Olson @@ -36,8 +38,9 @@ Development contributors, in last name alphabetical order: Ingo Weyrich Makoto Yoshida -Other contributors (profiles, ideas, mockups, testing, forum activity, translations, etc.), in last name alphabetical order: +Other contributors (profiles, ideas, mockups, testing, forum activity, translations, tutorials etc.), in last name alphabetical order: + Andy Astbury Marcin Bajor Javier Bartol Thorsten Bartolomäus diff --git a/CMakeLists.txt b/CMakeLists.txt index e3ae3b7ff..b7cf35099 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,13 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION "Building RawTherapee requires using GCC version 4.9 or higher!") endif() +# Warning for GCC 10, which causes problems #5749: +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "10.0") + message(STATUS "WARNING: gcc ${CMAKE_CXX_COMPILER_VERSION} is known to miscompile RawTherapee when using -ftree-loop-vectorize, forcing the option to be off") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-tree-loop-vectorize") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-tree-loop-vectorize") +endif() + # We might want to build using the old C++ ABI, even when using a new GCC # version: if(USE_OLD_CXX_ABI) @@ -68,6 +75,11 @@ set(CACHE_NAME_SUFFIX "" CACHE STRING "RawTherapee's cache folder suffix") +# For macOS only, OSX_DEV_BUILD option allows using relative paths instead of absolute +# paths. Consequently, for development builds, application can be launching without +# being bundled. However, file access can be restricted for some folder. +option(OSX_DEV_BUILD "Generate macOS development builds" OFF) + # By default we don't use a specific processor target, so PROC_TARGET_NUMBER is # set to 0. Specify other values to optimize for specific processor architecture # as listed in ProcessorTargets.cmake: @@ -128,6 +140,10 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PROC_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=unused-label") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=delete-incomplete") +# Do net set math errno, as we never check its value. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-math-errno") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-math-errno") + # Special treatment for x87 and x86-32 SSE (see GitHub issue #4324) include(FindX87Math) if(HAVE_X87_MATH) @@ -665,7 +681,14 @@ if(WIN32) elseif(APPLE) set( ABOUT_COMMAND_WITH_ARGS - cmake -DPROJECT_SOURCE_DIR:STRING=${PROJECT_SOURCE_DIR} -P ${PROJECT_SOURCE_DIR}/UpdateInfo.cmake -DSYSTEM:STRING=Apple -DCXX_FLAGS:STRING=${CXX_FLAGS} -DLFLAGS:STRING=${LFLAGS} -DCOMPILER_INFO:STRING=${COMPILER_INFO} -DCACHE_NAME_SUFFIX:STRING=${CACHE_NAME_SUFFIX}) + cmake + -DPROJECT_SOURCE_DIR:STRING=${PROJECT_SOURCE_DIR} + -DCACHE_NAME_SUFFIX:STRING=${CACHE_NAME_SUFFIX} + -P ${PROJECT_SOURCE_DIR}/UpdateInfo.cmake + -DSYSTEM:STRING=Apple + -DCXX_FLAGS:STRING=${CXX_FLAGS} + -DLFLAGS:STRING=${LFLAGS} + -DCOMPILER_INFO:STRING=${COMPILER_INFO}) else() list(APPEND ABOUT_COMMAND_WITH_ARGS -DSYSTEM:STRING=Linux -DCXX_FLAGS:STRING=${CXX_FLAGS} -DLFLAGS:STRING=${LFLAGS} diff --git a/rtdata/languages/Czech b/rtdata/languages/Czech index 19182a1e5..b6006cd36 100644 --- a/rtdata/languages/Czech +++ b/rtdata/languages/Czech @@ -40,10 +40,12 @@ #39 2017-07-21 updated by mkyral #40 2017-12-13 updated by mkyral #41 2018-03-03 updated by mkyral -#42 2018-04-28 updated by mkyral -#43 2018-12-13 updated by mkyral -#44 2019-04-17 updated by mkyral - +#42 2018-10-24 updated by mkyral +#43 2018-12-04 updated by mkyral +#44 2018-12-13 updated by mkyral +#45 2020-04-20 updated by mkyral +#46 2020-04-21 updated by mkyral +#47 2020-06-02 updated by mkyral ABOUT_TAB_BUILD;Verze ABOUT_TAB_CREDITS;Zásluhy ABOUT_TAB_LICENSE;Licence @@ -153,7 +155,7 @@ FILEBROWSER_APPLYPROFILE;Použít FILEBROWSER_APPLYPROFILE_PARTIAL;Aplikovat - částečně FILEBROWSER_AUTODARKFRAME;Automatický tmavý snímek FILEBROWSER_AUTOFLATFIELD;Auto Flat Field -FILEBROWSER_BROWSEPATHBUTTONHINT;Klikněte pro otevření zadané cesty, obnovte složku a aplikujte klíčové slovo "find". +FILEBROWSER_BROWSEPATHBUTTONHINT;Klikněte pro otevření zadané cesty, obnovte složku a aplikujte klíčová slova z pole "Najít:". FILEBROWSER_BROWSEPATHHINT;Vložte cestu pro procházení.\n\nKlávesové zkratky:\nCtrl-o pro přepnutí do adresního řádku.\nEnter/ Ctrl-Enter pro procházení ;\nEsc pro zrušení změn.\nShift-Esc pro zrušení přepnutí.\n\nZkratky pro cesty:\n~\t- domácí složka uživatele.\n!\t- složka s obrázky uživatele. FILEBROWSER_CACHE;Mezipaměť FILEBROWSER_CACHECLEARFROMFULL;Smazat vše včetně profilů zpracování v mezipaměti @@ -163,8 +165,12 @@ FILEBROWSER_COLORLABEL_TOOLTIP;Barevný štítek.\n\nPoužijte výběr ze seznam FILEBROWSER_COPYPROFILE;Kopírovat FILEBROWSER_CURRENT_NAME;Současné jméno: FILEBROWSER_DARKFRAME;Tmavý snímek -FILEBROWSER_DELETEDIALOG_HEADER;Potvrzení smazání souboru +FILEBROWSER_DELETEDIALOG_ALL;Jste si jisti, že chcete trvale vymazat %1 vybraných souborů? +FILEBROWSER_DELETEDIALOG_HEADER;Potvrzení smazání souboru: +FILEBROWSER_DELETEDIALOG_SELECTED;Jste si jisti, že chcete trvale vymazat %1 vybraných souborů? +FILEBROWSER_DELETEDIALOG_SELECTEDINCLPROC;Jste si jisti, že chcete trvale vymazat %1 vybraných souborů včetně výstupů dávkového zpracování? FILEBROWSER_EMPTYTRASH;Vysypat koš +FILEBROWSER_EMPTYTRASHHINT;Trvale smaže všechny soubory z koše. FILEBROWSER_EXTPROGMENU;Otevřít pomocí FILEBROWSER_FLATFIELD;Flat Field FILEBROWSER_MOVETODARKFDIR;Přesunout do složky tmavých snímků @@ -198,6 +204,8 @@ FILEBROWSER_POPUPRANK2;Hodnocení 2 ** FILEBROWSER_POPUPRANK3;Hodnocení 3 *** FILEBROWSER_POPUPRANK4;Hodnocení 4 **** FILEBROWSER_POPUPRANK5;Hodnocení 5 ***** +FILEBROWSER_POPUPREMOVE;Trvale smazat +FILEBROWSER_POPUPREMOVEINCLPROC;Trvale smazat, včetně dávkově zpracovaných verzí FILEBROWSER_POPUPRENAME;Přejmenovat FILEBROWSER_POPUPSELECTALL;Vybrat vše FILEBROWSER_POPUPTRASH;Přesunout do koše @@ -224,6 +232,7 @@ FILEBROWSER_SHOWDIRHINT;Smazat všechny filtry.\nZkratka: d FILEBROWSER_SHOWEDITEDHINT;Ukázat upravené obrázky.\nZkratka: 7 FILEBROWSER_SHOWEDITEDNOTHINT;Ukázat neupravené obrázky.\nZkratka: 6 FILEBROWSER_SHOWEXIFINFO;Zobrazit Exif informace.\n\nZkratky:\ni - režim více karet editoru,\nAlt-i - režim jedné karty editoru. +FILEBROWSER_SHOWNOTTRASHHINT;Zobrazit pouze snímky které nejsou v koši. FILEBROWSER_SHOWORIGINALHINT;Zobrazí pouze originální obrázky.\n\nPokud existuje několik obrázků se stejným názvem, ale rozdílnými příponami, bude jako originál vybrán ten, jehož přípona je nejvýše v seznamu přípon veVolby > Prohlížeč souborů > Analyzované přípony. FILEBROWSER_SHOWRANK1HINT;Ukázat obrázky hodnocené jednou hvězdičkou.\nZkratka: 1 FILEBROWSER_SHOWRANK2HINT;Ukázat obrázky hodnocené dvěma hvězdičkami.\nZkratka: 2 @@ -260,6 +269,7 @@ GENERAL_DISABLED;Vypnuto GENERAL_ENABLE;Zapnout GENERAL_ENABLED;Zapnuto GENERAL_FILE;Soubor +GENERAL_HELP;Nápověda GENERAL_LANDSCAPE;Na šířku GENERAL_NA;n/a GENERAL_NO;Ne @@ -402,11 +412,11 @@ HISTORY_MSG_113;L*a*b* - Ochrana červ. a pleť. tónů HISTORY_MSG_114;Průchody DCB HISTORY_MSG_115;Potlačení chybných barev HISTORY_MSG_116;Vylepšení DCB -HISTORY_MSG_117;Raw korekce CA - červená -HISTORY_MSG_118;Raw korekce CA - modrá +HISTORY_MSG_117;Raw korekce ChA - červená +HISTORY_MSG_118;Raw korekce ChA - modrá HISTORY_MSG_119;Filtrovat linkové rušení HISTORY_MSG_120;Vyrovnání zelené -HISTORY_MSG_121;Raw korekce CA - automatická +HISTORY_MSG_121;Raw korekce ChA - automatická HISTORY_MSG_122;Tmavé snímky - Automatický výběr HISTORY_MSG_123;Tmavé snímky - Soubor HISTORY_MSG_124;Korekce bílého bodu @@ -601,10 +611,10 @@ HISTORY_MSG_314;Vlnka - Gamut - Omezení artefaktů HISTORY_MSG_315;Vlnka - Zůstatek - Kontrast HISTORY_MSG_316;Vlnka - Gamut - Ochrana a zaměření pleťových tónů HISTORY_MSG_317;Vlnka - Gamut - Odstín pleti -HISTORY_MSG_318;Vlnka - Kontrast - Úrovně světel -HISTORY_MSG_319;Vlnka - Kontrast - - rozsah světel -HISTORY_MSG_320;Vlnka - Kontrast - Rozsah stínů -HISTORY_MSG_321;Vlnka - Kontrast - Úrovně stínů +HISTORY_MSG_318;Vlnka - Kontrast - Jemnější úrovně +HISTORY_MSG_319;Vlnka - Kontrast - Jemnější rozsah +HISTORY_MSG_320;Vlnka - Kontrast - Hrubší rozsah +HISTORY_MSG_321;Vlnka - Kontrast - Hrubší úrovně HISTORY_MSG_322;Vlnka - Gamut - Zabránit posunu barev HISTORY_MSG_323;Vlnka - DH - Místní kontrast HISTORY_MSG_324;Vlnka - Barevnost - Pastelové @@ -761,6 +771,12 @@ HISTORY_MSG_490;DRC - Míra HISTORY_MSG_491;Vyvážení bílé HISTORY_MSG_492;RGB křivky HISTORY_MSG_493;L*a*b* úpravy +HISTORY_MSG_494;Doostření vstupu +HISTORY_MSG_BLSHAPE;Rozmazat dle úrovně +HISTORY_MSG_BLURCWAV;Rozmazat barevnost +HISTORY_MSG_BLURWAV;Rozmazat jas +HISTORY_MSG_BLUWAV;Útlum +HISTORY_MSG_CAT02PRESET;Automatické přednastavení Cat02 HISTORY_MSG_CLAMPOOG;Oříznout barvy mimo gamut HISTORY_MSG_COLORTONING_LABGRID_VALUE;Barevné tónování - Korekce barev HISTORY_MSG_COLORTONING_LABREGION_AB;Barevné tónování - Korekce barev @@ -769,7 +785,7 @@ HISTORY_MSG_COLORTONING_LABREGION_CHROMATICITYMASK;BT -oblast C masky HISTORY_MSG_COLORTONING_LABREGION_HUEMASK;Barevné tónování - H maska HISTORY_MSG_COLORTONING_LABREGION_LIGHTNESS;BT - Světlost HISTORY_MSG_COLORTONING_LABREGION_LIGHTNESSMASK;BT - L maska -HISTORY_MSG_COLORTONING_LABREGION_LIST;BT - +HISTORY_MSG_COLORTONING_LABREGION_LIST;BT - HISTORY_MSG_COLORTONING_LABREGION_MASKBLUR;BT - oblast masky rozostření HISTORY_MSG_COLORTONING_LABREGION_OFFSET;BT - oblast posunu HISTORY_MSG_COLORTONING_LABREGION_POWER;BT - oblast síly @@ -778,10 +794,15 @@ HISTORY_MSG_COLORTONING_LABREGION_SHOWMASK;BT - oblast zobrazené masky HISTORY_MSG_COLORTONING_LABREGION_SLOPE;BT - oblast sklonu HISTORY_MSG_DEHAZE_DEPTH;Závoj - Hloubka HISTORY_MSG_DEHAZE_ENABLED;Odstranění závoje +HISTORY_MSG_DEHAZE_LUMINANCE;Závoj - Pouze jas HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;Závoj - Ukázat hloubkovou mapu HISTORY_MSG_DEHAZE_STRENGTH;Závoj - Síla HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dvojité demozajkování - automatický práh HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dvojité demozajkování - Práh kontrastu +HISTORY_MSG_EDGEFFECT;Útlum hrany +HISTORY_MSG_FILMNEGATIVE_ENABLED;Negativní film +HISTORY_MSG_FILMNEGATIVE_FILMBASE;Barva podkladu filmu +HISTORY_MSG_FILMNEGATIVE_VALUES;Film negativní hodnoty HISTORY_MSG_HISTMATCHING;Automaticky nalezená tónová křivka HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Výstup - Základní barvy HISTORY_MSG_ICM_OUTPUT_TEMP;Výstup - ICC-v4 světelný zdroj D @@ -789,6 +810,7 @@ HISTORY_MSG_ICM_OUTPUT_TYPE;Výstup - Typ HISTORY_MSG_ICM_WORKING_GAMMA;Pracovní - Gama HISTORY_MSG_ICM_WORKING_SLOPE;Pracovní - sklon HISTORY_MSG_ICM_WORKING_TRC_METHOD;Pracovní - Metoda TRC +HISTORY_MSG_ILLUM;Osvětlení HISTORY_MSG_LOCALCONTRAST_AMOUNT;Místní kontrast - Míra HISTORY_MSG_LOCALCONTRAST_DARKNESS;Místní kontrast - Tmavé HISTORY_MSG_LOCALCONTRAST_ENABLED;Místní kontrast @@ -796,20 +818,56 @@ HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Místní kontrast - Světlé HISTORY_MSG_LOCALCONTRAST_RADIUS;Místní kontrast - Poloměr HISTORY_MSG_METADATA_MODE;Režim kopírování metadat HISTORY_MSG_MICROCONTRAST_CONTRAST;Mikrokontrast - Práh kontrastu +HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;DV - Automatický práh +HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;DV - Automatický poloměr +HISTORY_MSG_PDSHARPEN_CHECKITER;DV- Automatický počet průchodů +HISTORY_MSG_PDSHARPEN_CONTRAST;DV - Práh kontrastu +HISTORY_MSG_PDSHARPEN_ITERATIONS;DV - Průchody +HISTORY_MSG_PDSHARPEN_RADIUS;DV - Poloměr +HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;DV - Zvýšení poloměru rohu HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - Metoda demozajkování pohybu HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;Směr filtru linkového rušení HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;Filtr PDAF linek +HISTORY_MSG_PREPROCWB_MODE;Režim předzpracování VB +HISTORY_MSG_PROTAB;Ochrana HISTORY_MSG_PRSHARPEN_CONTRAST;Doostření - Práh kontrastu -HISTORY_MSG_RAWCACORR_AUTOIT;Raw korekce CA - Iterace -HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw korekce CA - Zabránit posunu barev +HISTORY_MSG_RANGEAB;Rozsah ab +HISTORY_MSG_RAWCACORR_AUTOIT;Raw korekce ChA - Iterace +HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw korekce ChA - Zabránit posunu barev HISTORY_MSG_RAW_BORDER;Okraj Raw HISTORY_MSG_RESIZE_ALLOWUPSCALING;Změna rozměrů - Povolit zvětšení HISTORY_MSG_SHARPENING_BLUR;Doostření - Poloměr rozmazání HISTORY_MSG_SHARPENING_CONTRAST;Doostření - Práh kontrastu HISTORY_MSG_SH_COLORSPACE;S/S - Barevný prostor +HISTORY_MSG_SIGMACOL;Útlum barevnosti +HISTORY_MSG_SIGMADIR;Útlum směru +HISTORY_MSG_SIGMAFIN;Finální útlum kontrastu +HISTORY_MSG_SIGMATON;Útlum tónování HISTORY_MSG_SOFTLIGHT_ENABLED;Měkké světlo HISTORY_MSG_SOFTLIGHT_STRENGTH;Měkká světla - Síla +HISTORY_MSG_TEMPOUT;CAM02 - Automatická teplota +HISTORY_MSG_THRESWAV;Práh vyvážení HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Kotva +HISTORY_MSG_TRANS_Method;Geometrie - Metoda +HISTORY_MSG_WAVBALCHROM;Vyvážení barevnosti +HISTORY_MSG_WAVBALLUM;Vyvážení jasu +HISTORY_MSG_WAVBL;Úrovně rozmazání +HISTORY_MSG_WAVCHROMCO;Hrubá barevnost +HISTORY_MSG_WAVCHROMFI;Jemné barevnost +HISTORY_MSG_WAVCLARI;Čirost +HISTORY_MSG_WAVEDGS;Zachování hran +HISTORY_MSG_WAVLOWTHR;Práh nízkého kontrastu +HISTORY_MSG_WAVMERGEC;Sloučení barevnosti +HISTORY_MSG_WAVMERGEL;Sloučení jasu +HISTORY_MSG_WAVOFFSET;Posun +HISTORY_MSG_WAVOLDSH;Starý algoritmus +HISTORY_MSG_WAVRADIUS;Poloměr Stíny-Světla +HISTORY_MSG_WAVSCALE;Měřítko +HISTORY_MSG_WAVSHOWMASK;Ukázat masku vlnky +HISTORY_MSG_WAVSIGMA;Útlum +HISTORY_MSG_WAVSOFTRAD;Čirost jemný poloměr +HISTORY_MSG_WAVSOFTRADEND;Konečný jemný poloměr +HISTORY_MSG_WAVUSHAMET;Metoda čirosti HISTORY_NEWSNAPSHOT;Přidat HISTORY_NEWSNAPSHOT_TOOLTIP;Zkratka: Alt-s HISTORY_SNAPSHOT;Snímek @@ -939,15 +997,15 @@ MAIN_TAB_COLOR;Barvy MAIN_TAB_COLOR_TOOLTIP;Zkratka: Alt-c MAIN_TAB_DETAIL;Detaily MAIN_TAB_DETAIL_TOOLTIP;Zkratka: Alt-d -MAIN_TAB_DEVELOP; Dávková editace +MAIN_TAB_DEVELOP; Dávková editace MAIN_TAB_EXIF;Exif -MAIN_TAB_EXPORT; Rychlý export +MAIN_TAB_EXPORT; Rychlý export MAIN_TAB_EXPOSURE;Expozice MAIN_TAB_EXPOSURE_TOOLTIP;Zkratka: Alt-e MAIN_TAB_FAVORITES;Oblíbené MAIN_TAB_FAVORITES_TOOLTIP;Zkratka: Alt-u -MAIN_TAB_FILTER; Filtr -MAIN_TAB_INSPECT; Prohlížení +MAIN_TAB_FILTER; Filtr +MAIN_TAB_INSPECT; Prohlížení MAIN_TAB_IPTC;IPTC MAIN_TAB_METADATA;Metadata MAIN_TAB_METADATA_TOOLTIP;Zkratka: Alt-m @@ -961,8 +1019,8 @@ MAIN_TOOLTIP_BACKCOLOR2;Barva pozadí náhledu: bílá\nZkratka: 9 MAIN_TOOLTIP_BACKCOLOR3;Barva pozadí náhledu: středně šedá\nZkratka: 9 MAIN_TOOLTIP_BEFOREAFTERLOCK;Zamknout / Odemknout pohled Před\n\nZamknout: ponechá pohled Před nezměněn.\nUžitečné pro posouzení výsledného efektu po použití více nástrojů.\nNavíc může být porovnání provedeno proti kterémukoli stavu v historii.\n\nOdemknout: pohled Před bude následovat pohled Poté, vždy jen o jeden krok zpět, představí vliv právě použitého nástroje. MAIN_TOOLTIP_HIDEHP;Zobrazit či schovat levý panel (obsahující historii).\nZkratka: l -MAIN_TOOLTIP_INDCLIPPEDH;Zvýraznit oříznutá světla.\nZkratka: > -MAIN_TOOLTIP_INDCLIPPEDS;Zvýraznit oříznuté stíny.\nZkratka: < +MAIN_TOOLTIP_INDCLIPPEDH;Zvýraznění oříznutých světel.\nZkratka: > +MAIN_TOOLTIP_INDCLIPPEDS;Zvýraznění oříznutých stínů.\nZkratka: < MAIN_TOOLTIP_PREVIEWB;Náhled modrého kanálu.\nZkratka: b MAIN_TOOLTIP_PREVIEWFOCUSMASK;Náhled masky zaostření.\nZkratka: Shift-f\n\nVíce přesné u snímků s nízkou hloubkou ostrosti, nízkým šumem a na vyšších úrovních zvětšení.\n\nPoužijte přiblížení v rozsahu 10 až 30% pro zlepšení přesnosti detekce u zašuměných snímků. MAIN_TOOLTIP_PREVIEWG;Náhled zeleného kanálu.\nZkratka: g @@ -1017,6 +1075,7 @@ PARTIALPASTE_EQUALIZER;Úrovně vlnky PARTIALPASTE_EVERYTHING;Vše PARTIALPASTE_EXIFCHANGES;Exif PARTIALPASTE_EXPOSURE;Expozice +PARTIALPASTE_FILMNEGATIVE;Negativní film PARTIALPASTE_FILMSIMULATION;Simulace filmu PARTIALPASTE_FLATFIELDAUTOSELECT;Automatický výběr Flat Field PARTIALPASTE_FLATFIELDBLURRADIUS;Poloměr rozostření Flat Field @@ -1041,6 +1100,7 @@ PARTIALPASTE_PREPROCESS_GREENEQUIL;Vyrovnání zelené PARTIALPASTE_PREPROCESS_HOTPIXFILT;Filtr vypálených pixelů PARTIALPASTE_PREPROCESS_LINEDENOISE;Filtrovat linkové rušení PARTIALPASTE_PREPROCESS_PDAFLINESFILTER;Filtr PDAF linek +PARTIALPASTE_PREPROCWB;Předzpracování Vyvážení bílé PARTIALPASTE_PRSHARPENING;Doostření po změně velikosti PARTIALPASTE_RAWCACORR_AUTO;Automatická korekce CA PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT;CA zabránit posunu barev @@ -1075,6 +1135,7 @@ PREFERENCES_APPEARANCE_COLORPICKERFONT;Písmo Průzkumníka barev PREFERENCES_APPEARANCE_CROPMASKCOLOR;Barva masky ořezu PREFERENCES_APPEARANCE_MAINFONT;Hlavní písmo PREFERENCES_APPEARANCE_NAVGUIDECOLOR;Barva vodítek navigátoru +PREFERENCES_APPEARANCE_PSEUDOHIDPI;Pseudo-HiDPI režim PREFERENCES_APPEARANCE_THEME;Motiv PREFERENCES_APPLNEXTSTARTUP;vyžaduje restart aplikace PREFERENCES_AUTOMONPROFILE;Použít barevný profil hlavního monitoru z operačního systému @@ -1094,11 +1155,11 @@ PREFERENCES_CACHEMAXENTRIES;Maximální počet záznamů v mezipaměti PREFERENCES_CACHEOPTS;Vlastnosti mezipaměti PREFERENCES_CACHETHUMBHEIGHT;Maximální výška náhledu PREFERENCES_CHUNKSIZES;Dlaždic na vlákno -PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE demozajkování -PREFERENCES_CHUNKSIZE_RAW_CA;Raw korekce CA +PREFERENCES_CHUNKSIZE_RAW_AMAZE;Demozajkování AMaZE +PREFERENCES_CHUNKSIZE_RAW_CA;Raw korekce ChA PREFERENCES_CHUNKSIZE_RAW_RCD;RCD demozajkování -PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans demozajkování -PREFERENCES_CHUNKSIZE_RGB;RGB zpracování +PREFERENCES_CHUNKSIZE_RAW_XT;Demozajkování Xtrans +PREFERENCES_CHUNKSIZE_RGB;Zpracování barev PREFERENCES_CLIPPINGIND;Indikace oříznutí PREFERENCES_CLUTSCACHE;Mezipaměť HaldCLUT PREFERENCES_CLUTSCACHE_LABEL;Maximální počet přednačtených CLUTů @@ -1186,8 +1247,8 @@ PREFERENCES_PARSEDEXTADDHINT;Vymazat označenou příponu ze seznamu. PREFERENCES_PARSEDEXTDELHINT;Vymazat označenou příponu ze seznamu. PREFERENCES_PARSEDEXTDOWNHINT;Vybranou příponu posunout na seznamu níže. PREFERENCES_PARSEDEXTUPHINT;Vybranou příponu posunout na seznamu výše. -PREFERENCES_PERFORMANCE_MEASURE;Měřit -PREFERENCES_PERFORMANCE_MEASURE_HINT;Vypisovat časy zpracování v konzoli +PREFERENCES_PERFORMANCE_MEASURE;Měření +PREFERENCES_PERFORMANCE_MEASURE_HINT;Vypisuje doby zpracování do konzole PREFERENCES_PERFORMANCE_THREADS;Vlákna PREFERENCES_PERFORMANCE_THREADS_LABEL;Maximální počet vláken pro Redukci šumu a Úrovně vlnky (0 = Automaticky) PREFERENCES_PREVDEMO;Metoda demozajkování náhledu @@ -1262,11 +1323,11 @@ PROFILEPANEL_TOOLTIPCOPY;Kopírovat současný profil do schránky.\nCtrl-kli PROFILEPANEL_TOOLTIPLOAD;Nahrát profil ze souboru.\nCtrl-klik umožní vybrat parametry pro nahrání. PROFILEPANEL_TOOLTIPPASTE;Vložit profil ze schránky.\nCtrl-klik umožní vybrat parametry pro vložení. PROFILEPANEL_TOOLTIPSAVE;Uložit současný profil.\nCtrl-klik umožní vybrat parametry pro uložení. -PROGRESSBAR_DECODING;Dekodování... +PROGRESSBAR_DECODING;Dekódování… PROGRESSBAR_GREENEQUIL;Vyrovnání zelené... -PROGRESSBAR_HLREC;Rekonstrukce světel... -PROGRESSBAR_HOTDEADPIXELFILTER;Filtr vypálených/mrtvých pixelů... -PROGRESSBAR_LINEDENOISE;Filtr linkového rušení... +PROGRESSBAR_HLREC;Rekonstrukce světel… +PROGRESSBAR_HOTDEADPIXELFILTER;Filtrování vypálených/mrtvých pixelů… +PROGRESSBAR_LINEDENOISE;Filtr linkového rušení… PROGRESSBAR_LOADING;Načítání obrázku... PROGRESSBAR_LOADINGTHUMBS;Načítání náhledů... PROGRESSBAR_LOADJPEG;Načítání JPEG... @@ -1275,7 +1336,7 @@ PROGRESSBAR_LOADTIFF;Načítání TIFF... PROGRESSBAR_NOIMAGES;Složka neobsahuje obrázky PROGRESSBAR_PROCESSING;Zpracovávaní obrázku... PROGRESSBAR_PROCESSING_PROFILESAVED;Profil zpracování uložen -PROGRESSBAR_RAWCACORR;RAW korekce chromatické aberace... +PROGRESSBAR_RAWCACORR;Korekce ChA… PROGRESSBAR_READY;Připraven PROGRESSBAR_SAVEJPEG;Ukládání JPEG souboru... PROGRESSBAR_SAVEPNG;Ukládání PNG souboru... @@ -1293,8 +1354,8 @@ QUEUE_DESTFILENAME;Cesta a název souboru QUEUE_FORMAT_TITLE;Formát souboru QUEUE_LOCATION_FOLDER;Ulož do souboru QUEUE_LOCATION_TEMPLATE;Použít šablonu -QUEUE_LOCATION_TEMPLATE_TOOLTIP;Specifikujte kam se mají uložit výstupy. Lze použít umístění zdrojových souborů, pořadí, stav koše nebo pozice ve frontě.\n\nNapříklad pokud má zpracovávaná fotografie následující cestu:\n/home/tomas/fotky/2010-10-31/dsc0042.nef,\nmají jednotlivé formátovací řetězce tento význam:\n%d4 = home\n%d3 = tomas\n%d2 = fotky\n%d1 = 2010-10-31\n%f = dsc0042\n%p1 = /home/tomas/fotky/2010-10-31/\n%p2 = /home/tomas/fotky/\n%p3 = /home/tomas/\n%p4 = /home/\n\n%r bude nahrazeno hodnocením fotografie.Pokud není fotografie ohodnocena, bude %r nahrazeno '0'.Pokud je fotografie v koši, bude %r nahrazeno 'x'.\n\nPokud si přejete uložit výstupní obrázek vedle originálu, napište:\n%p1/%f\n\nPokud si jej ale přejete uložit do adresáře "converted" ve stejném adresáři jako otevřený obrázek, napište:\n%p1/converted/%f\n\nPro uložení výstupního obrázku do adresáře"/home/tom/photos/converted/2010-10-31", napište:\n%p2/converted/%d1/%f -QUEUE_LOCATION_TITLE;Výstupní umístění +QUEUE_LOCATION_TEMPLATE_TOOLTIP;Lze použít následující formátovací řetězce:\n%f, %d1, %d2, ..., %p1, %p2, ..., %r\n\nTyto formátovací řetězce reprezentují různé části cesty k uložené fotografii.\n\nNapříklad pokud má zpracovávaná fotografie následující cestu:\n/home/tomas/fotky/2010-10-31/fotka1.raw,\nmají jednotlivé formátovací řetězce tento význam:\n%d4 = home\n%d3 = tomas\n%d2 = fotky\n%d1 = 2010-10-31\n%f = fotka1\n%p1 = /home/tomas/fotky/2010-10-31/\n%p2 = /home/tomas/fotky/\n%p3 = /home/tomas/\n%p4 = /home/\n\n%r bude nahrazeno hodnocením fotografie.Pokud není fotografie ohodnocena, bude %r nahrazeno '0'.Pokud je fotografie v koši, bude %r nahrazeno 'x'.\n\nPokud si přejete uložit výstupní obrázek vedle originálu, napište:\n%p1/%f\n\nPokud si jej ale přejete uložit do adresáře "converted" ve stejném adresáři jako otevřený obrázek, napište:\n%p1/converted/%f\n\nPro uložení výstupního obrázku do adresáře"/home/tom/photos/converted/2010-10-31", napište:\n%p2/converted/%d1/%f +QUEUE_LOCATION_TITLE;Umístění výstupu QUEUE_STARTSTOP_TOOLTIP;Spustit nebo zastavit zpracování obrázků ve frontě.\n\nZkratka: Ctrl+s SAMPLEFORMAT_0;Neznámý datový formát SAMPLEFORMAT_1;8-bitový neznaménkový @@ -1331,7 +1392,7 @@ THRESHOLDSELECTOR_HINT;Držte klávesu Shift pro přesun individuálních THRESHOLDSELECTOR_T;Nahoře THRESHOLDSELECTOR_TL;Nahoře vlevo THRESHOLDSELECTOR_TR;Nahoře vpravo -TOOLBAR_TOOLTIP_COLORPICKER;Uzamykatelný Průzkumník barev\n\nPokud je nástroj aktivní:\n- Přidání sondy: levý-klik.\n- Posunutí sondy: levý-klik a posunutí.\n- Smazání sondy: pravý-klik.\n- Smazání všech sond: Ctrl+Shift+pravý-klik.\n- Návrat k nástroji posunu: pravý-klik mimo průzkumníky. +TOOLBAR_TOOLTIP_COLORPICKER;Uzamykatelný Průzkumník barev\n\nPokud je nástroj aktivní:\n- Přidání sondy: levý-klik.\n- Posunutí sondy: levý-klik a posunutí.\n- Smazání sondy: pravý-klik.\n- Smazání všech sond: Ctrl+Shift+pravý-klik.\n- Návrat k nástroji posunu: pravý-klik mimo jakoukoli sondu. TOOLBAR_TOOLTIP_CROP;Oříznutí výběru.\nZkratka: c\nVýřez posunete pomocí Shift + tažení myši TOOLBAR_TOOLTIP_HAND;Posun.\nZkratka: h TOOLBAR_TOOLTIP_STRAIGHTEN;Vyznačení roviny / rotace.\nZkratka: s\n\nZobrazení míry rotace pomocí vodící linky na náhledu snímky. Úhel rotace je zobrazen vedle vodící linky. Střed rotace je geometrický střed snímku. @@ -1417,7 +1478,7 @@ TP_COLORAPP_ALGO_JS;Světlost + Nasycení (JS) TP_COLORAPP_ALGO_QM;Jas a pestrobarevnost (QM) TP_COLORAPP_ALGO_TOOLTIP;Umožňuje vybrat mezi podmnožinou nebo všemi parametry. TP_COLORAPP_BADPIXSL;Filtr vypálených/mrtvých pixelů -TP_COLORAPP_BADPIXSL_TOOLTIP;Potlačení vypálených/mrtvých (jasně zabarvených) pixelů.\n0 = Bez efektu\n1 = Medián\n2 = Gaussův.\nPopřípadě obrázek upravte tak, aby jste se vyhnuli velmi tmavým stínům.\n\nTyto artefakty vznikají díky omezením CIECAM02. +TP_COLORAPP_BADPIXSL_TOOLTIP;Potlačení vypálených/mrtvých (jasně zabarvených) pixelů.\n0 = Bez efektu\n1 = Medián\n2 = Gaussův.\nPopřípadě obrázek upravte tak, aby jste se vyhnuli velmi tmavým stínům.\n\nTyto artefakty vznikají díky omezením CIECAM02. TP_COLORAPP_BRIGHT;Jas (O) TP_COLORAPP_BRIGHT_TOOLTIP;Jas v CIECAM02 bere v potaz svítivost bílé a rozdíly jasů mezi L*a*b* a RGB. TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;U ručního nastavení jsou doporučeny hodnoty nad 65. @@ -1428,7 +1489,7 @@ TP_COLORAPP_CHROMA_S;Nasycení (S) TP_COLORAPP_CHROMA_S_TOOLTIP;Nasycení se v CIECAM02 liší od nasycení L*a*b* a RGB. TP_COLORAPP_CHROMA_TOOLTIP;Barevnost se v CIECAM02 liší od barevnosti L*a*b* a RGB. TP_COLORAPP_CIECAT_DEGREE;CAT02 přizpůsobení -TP_COLORAPP_CONTRAST;Kontrast (I) +TP_COLORAPP_CONTRAST;Kontrast (J) TP_COLORAPP_CONTRAST_Q;Kontrast (O) TP_COLORAPP_CONTRAST_Q_TOOLTIP;Liší se od kontrastu L*a*b* a RGB. TP_COLORAPP_CONTRAST_TOOLTIP;Liší se od kontrastu L*a*b* a RGB. @@ -1445,17 +1506,29 @@ TP_COLORAPP_GAMUT;Kontrola gamutu (L*a*b*) TP_COLORAPP_GAMUT_TOOLTIP;Povolí kontrolu gamutu v L*a*b* režimu. TP_COLORAPP_HUE;Odstín (h) TP_COLORAPP_HUE_TOOLTIP;Odstín (h) - úhel mezi 0° a 360°. +TP_COLORAPP_IL41;D41 +TP_COLORAPP_IL50;D50 +TP_COLORAPP_IL55;D55 +TP_COLORAPP_IL60;D60 +TP_COLORAPP_IL65;D65 +TP_COLORAPP_IL75;D75 +TP_COLORAPP_ILA;Žárovka StdA 2856K +TP_COLORAPP_ILFREE;Volná +TP_COLORAPP_ILLUM;Osvětlení +TP_COLORAPP_ILLUM_TOOLTIP;Vyberte osvětlení nejvíce se blížící podmínkám v době pořízení snímku.\nObecně D50, to se ale může lišit v závislosti na denní době a zeměpisné šířce. TP_COLORAPP_LABEL;CIE model přizpůsobení barev 2002 TP_COLORAPP_LABEL_CAM02;Úpravy obrázku TP_COLORAPP_LABEL_SCENE;Podmínky scény TP_COLORAPP_LABEL_VIEWING;Podmínky zobrazení -TP_COLORAPP_LIGHT;Světlost (I) +TP_COLORAPP_LIGHT;Světlost (J) TP_COLORAPP_LIGHT_TOOLTIP;Světlost v CIECAM02 se liší od světlosti v L*a*b* a RGB. TP_COLORAPP_MEANLUMINANCE;Střední jas (Yb%) TP_COLORAPP_MODEL;VB - Model TP_COLORAPP_MODEL_TOOLTIP;Model bílého bodu.\n\nWB [RT] + [výstup]: Pro scénu je použito vyvážení bílé RawTherapee , CIECAM02 je nastaven na D50 a vyvážení bílé výstupního zařízení je nastaveno v Podmínkách prohlížení.\n\nWB [RT+CAT02] + [výstup]: CAT02 používá RawTherapee nastavení vyvážení bílé a vyvážení bílé výstupního zařízení je nastaveno v Podmínkách prohlížení.\n\nVolná teplota+zelená + CAT02 + [výstup]: teplota a zelená je vybrána uživatelem, vyvážení bílé výstupního zařízení je nastaveno v Podmínkách prohlížení. TP_COLORAPP_NEUTRAL;Obnovit TP_COLORAPP_NEUTRAL_TIP;Obnoví původní hodnoty u všech posuvníků a křivek. +TP_COLORAPP_PRESETCAT02;Automatické přednastavení Cat02 +TP_COLORAPP_PRESETCAT02_TIP;Nastaví volby, posuvníky, teplotu a zelenou podle Cat02 automatického přednastavení.\nMusíte nastavit světelné podmínky při fotografování.\nPokud je potřeba, musíte změnit Cat02 podmínky přizpůsobení pro prohlížení.\nPokud je potřeba, můžete změnit teplotu a odstín podmínek při prohlížení a také další nastavení. TP_COLORAPP_RSTPRO;Ochrana červených a pleťových tónů TP_COLORAPP_RSTPRO_TOOLTIP;Ochrana červených a pleťových tónů ovlivňuje posuvníky i křivky. TP_COLORAPP_SURROUND;Okolí @@ -1472,7 +1545,9 @@ TP_COLORAPP_TCMODE_LABEL2;Mód křivky 2 TP_COLORAPP_TCMODE_LABEL3;Mód barevné křivky TP_COLORAPP_TCMODE_LIGHTNESS;Světlost TP_COLORAPP_TCMODE_SATUR;Nasycení -TP_COLORAPP_TEMP_TOOLTIP;Pro výběr osvětlení vždy nastavte Tint=1.\n\nA barva=2856\nD50 barva=5003\nD55 barva=5503\nD65 barva=6504\nD75 barva=7504 +TP_COLORAPP_TEMP2_TOOLTIP;Buď symetrický režim teploty = Nastavení bílé,\nNebo vyberte osvětlení, vždy nastavte Odstín=1.\n\nA barva=2856\nD50 barva=5003\nD55 barva=5503\nD65 barva=6504\nD75 barva=7504 +TP_COLORAPP_TEMPOUT_TOOLTIP;Zakažte pro změnu teploty a nádechu +TP_COLORAPP_TEMP_TOOLTIP;Pro výběr osvětlení vždy nastavte Odstín=1.\n\nA barva=2856\nD41 temp=4100\nD50 barva=5003\nD55 barva=5503\nD60 temp=6000\nD65 barva=6504\nD75 barva=7504 TP_COLORAPP_TONECIE;Mapování tónů pomocí CIECAM02 TP_COLORAPP_TONECIE_TOOLTIP;Pokud je volba zakázána, probíhá mapování tónů v prostoru L*a*b*.\nPokud je volba povolena. probíhá mapování tónů pomocí CIECAM02.\nAby měla tato volba efekt, musí být povolen nástroj Mapování tónů. TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP;Absolutní jas prostředí prohlížení\n(obvykle 16 cd/m²). @@ -1499,7 +1574,7 @@ TP_COLORTONING_LABREGION_CHANNEL_B;Modrá TP_COLORTONING_LABREGION_CHANNEL_G;Zelená TP_COLORTONING_LABREGION_CHANNEL_R;Červená TP_COLORTONING_LABREGION_CHROMATICITYMASK;C -TP_COLORTONING_LABREGION_HUEMASK;H +TP_COLORTONING_LABREGION_HUEMASK;H TP_COLORTONING_LABREGION_LIGHTNESS;Světlost TP_COLORTONING_LABREGION_LIGHTNESSMASK;L TP_COLORTONING_LABREGION_LIST_TITLE;Oprava @@ -1561,6 +1636,7 @@ TP_DEFRINGE_RADIUS;Poloměr TP_DEFRINGE_THRESHOLD;Práh TP_DEHAZE_DEPTH;Hloubka TP_DEHAZE_LABEL;Odstranění závoje +TP_DEHAZE_LUMINANCE;Pouze jas TP_DEHAZE_SHOW_DEPTH_MAP;Ukázat hloubkovou mapu TP_DEHAZE_STRENGTH;Síla TP_DIRPYRDENOISE_CHROMINANCE_AMZ;Více zónová automatika @@ -1669,6 +1745,15 @@ TP_EXPOSURE_TCMODE_STANDARD;Běžný TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Běžný vážený TP_EXPOS_BLACKPOINT_LABEL;Raw černé body TP_EXPOS_WHITEPOINT_LABEL;Raw bílé body +TP_FILMNEGATIVE_BLUE;Poměr modré +TP_FILMNEGATIVE_FILMBASE_PICK;Výběr barvy podkladu filmu +TP_FILMNEGATIVE_FILMBASE_TOOLTIP;Vyberte místo neexponovaného filmu (například okraj mezi snímky) pro získání aktuální barvy podkladu a uložte jej do profilu zpracování.\nTo umožňuje jednoduchou kontrolu konzistence vyvážení barev během dávkového zpracování více obrázků ze stejného filmu.\nTaké použijte pokud jsou převáděné snímky moc tmavé, přesvícené nebo barevně nevyvážené. +TP_FILMNEGATIVE_FILMBASE_VALUES;Barva podkladu filmu: +TP_FILMNEGATIVE_GREEN;Referenční exponent (kontrast) +TP_FILMNEGATIVE_GUESS_TOOLTIP;Automaticky nastaví poměr červené a modré výběrem dvou vzorků s neutrálním odstínem (bez barvy) v původní scéně. Vzorky by se měly lišit jasem. Následně je nastaveno vyvážení bílé. +TP_FILMNEGATIVE_LABEL;Negativní film +TP_FILMNEGATIVE_PICK;Výběr neutrálních míst +TP_FILMNEGATIVE_RED;Poměr červené TP_FILMSIMULATION_LABEL;Simulace filmu TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee je nakonfigurován aby hledal Hald CLUT obrázky pro nástroj Simulace filmu ve složce, jejíž načítání trvá velmi dlouho.\nZkontrolujte prosím nastavení v menu Volby > Zpracování obrázku > Simulace filmu.\nNastavená složka by měla buď obsahovat jen a pouze Hald CLUT obrázky nebo být prázdná, pokud nechcete nástroj Simulace filmu používat.\n\nVíce informací získáte v článku o nástroji Simulace filmu na RawPedii.\n\nChcete zrušit právě probíhající prohledávání složky? TP_FILMSIMULATION_STRENGTH;Síla @@ -1681,7 +1766,7 @@ TP_FLATFIELD_BT_HORIZONTAL;Vodorovně TP_FLATFIELD_BT_VERTHORIZ;Vodorovně a svisle TP_FLATFIELD_BT_VERTICAL;Svisle TP_FLATFIELD_CLIPCONTROL;Kontrola oříznutí -TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Kontrola oříznutí zabrání oříznutí světel po aplikaci Flat Field. Pokud byly světla oříznuta ještě před aplikací Flat field, může se objevit barevný nádech. +TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Kontrola oříznutí zabrání oříznutí světel po aplikaci Flat Field. Pokud byly světla oříznuta ještě před aplikací Flat field, použije se hodnota 0. TP_FLATFIELD_LABEL;Flat Field TP_GENERAL_11SCALE_TOOLTIP;Efekt tohoto nástroje je viditelný pouze při přiblížení 1:1. TP_GRADIENT_CENTER;Střed @@ -1789,6 +1874,8 @@ TP_LABCURVE_RSTPRO_TOOLTIP;Pracuje s posuvníkem barevnosti a CC křivkou. TP_LENSGEOM_AUTOCROP;Automatický ořez TP_LENSGEOM_FILL;Automatické vyplnění TP_LENSGEOM_LABEL;Objektiv / Geometrie +TP_LENSGEOM_LIN;Lineární +TP_LENSGEOM_LOG;Logaritmická TP_LENSPROFILE_CORRECTION_AUTOMATCH;Automaticky vybráno TP_LENSPROFILE_CORRECTION_LCPFILE;LCP soubor TP_LENSPROFILE_CORRECTION_MANUAL;Ručně vybráno @@ -1817,6 +1904,7 @@ TP_PCVIGNETTE_ROUNDNESS;Zaoblení TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Zaoblení:\n0 = čtverec,\n50 = elipsa,\n100 = kruh. TP_PCVIGNETTE_STRENGTH;Síla TP_PCVIGNETTE_STRENGTH_TOOLTIP;Síla filtru v expozičních stupních (v rozích). +TP_PDSHARPENING_LABEL;Doostření vstupu TP_PERSPECTIVE_HORIZONTAL;Vodorovně TP_PERSPECTIVE_LABEL;Perspektiva TP_PERSPECTIVE_VERTICAL;Svisle @@ -1836,6 +1924,10 @@ TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;Vodorovně pouze u PDAF řádků TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Svisle TP_PREPROCESS_NO_FOUND;Nic nenalezeno TP_PREPROCESS_PDAFLINESFILTER;Filtr PDAF linek +TP_PREPROCWB_LABEL;Předzpracování Vyvážení bílé +TP_PREPROCWB_MODE;Mód +TP_PREPROCWB_MODE_AUTO;Automaticky +TP_PREPROCWB_MODE_CAMERA;Fotoaparát TP_PRSHARPENING_LABEL;Doostření po změně velikosti TP_PRSHARPENING_TOOLTIP;Obrázek po zmenšení doostří. Funguje pouze pokud je použita "Lanczos" metoda zmenšení. Náhled výsledku není v tomto nástroji možný. Podívejte se do RawPedie pro návod k použití. TP_RAWCACORR_AUTO;Automatická korekce @@ -1868,7 +1960,7 @@ TP_RAW_DCBENHANCE;Vylepšení DCB TP_RAW_DCBITERATIONS;Počet průchodů DCB TP_RAW_DCBVNG4;DCB+VNG4 TP_RAW_DMETHOD;Metoda -TP_RAW_DMETHOD_PROGRESSBAR;%1 demozajkování... +TP_RAW_DMETHOD_PROGRESSBAR;%1 demozajkování… TP_RAW_DMETHOD_PROGRESSBAR_REFINE;Vylepšení demozajkování... TP_RAW_DMETHOD_TOOLTIP;Poznámka: IGV a LMMSE jsou určeny pro obrázky s vysokým ISO, kterým pomáhají vyhnout se u redukce šumu vzniku vzorů, posterizaci a vyžehlenému vzhledu.\n\nPixel Shift je určen pro soubory Pentax/Sony Pixel Shift.\nPro soubory neobsahující Pixel Shift data je použita metoda AMaZE. TP_RAW_DUALDEMOSAICAUTOCONTRAST;Automatický práh @@ -1882,7 +1974,7 @@ TP_RAW_HD_TOOLTIP;Nižší hodnoty učiní detekci vypálených/mrtvých bodů a TP_RAW_HPHD;HPHD TP_RAW_IGV;IGV TP_RAW_IMAGENUM;Dílčí snímek -TP_RAW_IMAGENUM_SN;Režim SN +TP_RAW_IMAGENUM_SN;Režim Signál/Šum TP_RAW_IMAGENUM_TOOLTIP;Některé raw snímky obsahují několik podsnímků (Pentax/Sony Pixel Shift, Pentax 3-in-1 HDR, Canon Dual Pixel, Fuji EXR).\n\nV případě, že je pro demozajkování použita jiná metoda než Pixel Shift, tato volba určí, který podsnímek se použije.\n\nPokud je použita Pixel Shift metoda demozajkování na Pixel Shift raw soubory, budou použity všechny podsnímky a tato volba určí, který snímek bude použit pro pohyblivé části. TP_RAW_LABEL;Demozajkování TP_RAW_LMMSE;LMMSE @@ -1924,7 +2016,7 @@ TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;Tří průchodová dává lepší výsledky TP_RAW_SENSOR_XTRANS_LABEL;Senzory s X-Trans maticí TP_RAW_VNG4;VNG4 TP_RAW_XTRANS;X-Trans -TP_RAW_XTRANSFAST;Fast X-Trans +TP_RAW_XTRANSFAST;Rychlý X-Trans TP_RESIZE_ALLOW_UPSCALING;Povolit zvětšení TP_RESIZE_APPLIESTO;Aplikovat na: TP_RESIZE_CROPPEDAREA;Oblast ořezu @@ -2047,10 +2139,12 @@ TP_SHARPENING_EDRADIUS;Poloměr TP_SHARPENING_EDTOLERANCE;Tolerance k hranám TP_SHARPENING_HALOCONTROL;Omezení halo efektu TP_SHARPENING_HCAMOUNT;Míra +TP_SHARPENING_ITERCHECK;Automatické omezení průchodů TP_SHARPENING_LABEL;Doostření TP_SHARPENING_METHOD;Metoda TP_SHARPENING_ONLYEDGES;Doostřit pouze hrany TP_SHARPENING_RADIUS;Poloměr +TP_SHARPENING_RADIUS_BOOST;Zvýšení poloměru rohu TP_SHARPENING_RLD;RL Dekonvoluce TP_SHARPENING_RLD_AMOUNT;Míra TP_SHARPENING_RLD_DAMPING;Útlum @@ -2110,11 +2204,17 @@ TP_WAVELET_BACKGROUND;Pozadí TP_WAVELET_BACUR;Křivka TP_WAVELET_BALANCE;Vyvážení kontrastu d/v-h TP_WAVELET_BALANCE_TOOLTIP;Změní vyvážení mezi směry vlnky: svisle-vodorovně a úhlopříčně.\nPokud je aktivován kontrast, barevnost nebo zbytkové tónové mapování je efekt díky vyvážení zesílen. -TP_WAVELET_BALCHRO;Vyvážení barev +TP_WAVELET_BALCHRO;Vyvážení barevnosti +TP_WAVELET_BALCHROM;Korekce odšumění Modrá-Červená TP_WAVELET_BALCHRO_TOOLTIP;Pokud je povoleno, křivka nebo posuvníky "Vyvážení kontrastu" ovlivňují i vyvážení barev. +TP_WAVELET_BALLUM;Korekce odšumění Bílá-Černá TP_WAVELET_BANONE;Nic TP_WAVELET_BASLI;Posuvník TP_WAVELET_BATYPE;Metoda vyvážení kontrastu +TP_WAVELET_BL;Úrovně rozmazání +TP_WAVELET_BLCURVE;Rozmazání dle úrovní +TP_WAVELET_BLURFRAME;Rozmazání +TP_WAVELET_BLUWAV;Útlum TP_WAVELET_CBENAB;Tónování a vyvážení barev TP_WAVELET_CB_TOOLTIP;Pro silnější hodnoty barevného tónování s kombinováním nebo bez rozkladu na vrstvy tónování\nPro menší hodnoty můžete změnit vyvážení bílé na barvu pozadí (obloha, ...) bez změny předního plánu, obecně více kontrastní. TP_WAVELET_CCURVE;Místní kontrast @@ -2124,22 +2224,32 @@ TP_WAVELET_CH3;Propojit kontrast úrovní TP_WAVELET_CHCU;Křivka TP_WAVELET_CHR;Barevnost - kontrast síla propojení TP_WAVELET_CHRO;Práh nasycené/pastelové +TP_WAVELET_CHROFRAME;Odšumění Barevnosti +TP_WAVELET_CHROMAFRAME;Barevnost +TP_WAVELET_CHROMCO;Hrubá barevnost +TP_WAVELET_CHROMFI;Jemná barevnost TP_WAVELET_CHRO_TOOLTIP;Nastaví úroveň vlnky, která bude prahová pro syté a pastelové barvy.\n1-x: syté\nx-9: pastelové\n\nHodnota bude ignorována pokud přesáhne množství úrovní vlnky. +TP_WAVELET_CHRWAV;Rozmazat barevnost TP_WAVELET_CHR_TOOLTIP;Upraví barevnost jako funkci "Kontrast úrovní" a "Barevnost - kontrast síla propojení" TP_WAVELET_CHSL;Posuvníky TP_WAVELET_CHTYPE;Metoda barevnost +TP_WAVELET_CLA;Čirost +TP_WAVELET_CLARI;Ostrá maska a čirost TP_WAVELET_COLORT;Neprůhlednost červená-zelená TP_WAVELET_COMPCONT;Kontrast TP_WAVELET_COMPGAMMA;Komprese gamy TP_WAVELET_COMPGAMMA_TOOLTIP;Úprava gamy zůstatku obrázku vám umožní vyvážit data a histogram. TP_WAVELET_COMPTM;Mapování tónů TP_WAVELET_CONTEDIT;Křivka kontrastu 'Po' +TP_WAVELET_CONTFRAME;Kontrast - komprese TP_WAVELET_CONTR;Gamut TP_WAVELET_CONTRA;Kontrast +TP_WAVELET_CONTRASTEDIT;Jemnější - Hrubší úrovně TP_WAVELET_CONTRAST_MINUS;Kontrast - TP_WAVELET_CONTRAST_PLUS;Kontrast + TP_WAVELET_CONTRA_TOOLTIP;Změní kontrast zůstatku obrazu. TP_WAVELET_CTYPE;Ovládání barevnosti +TP_WAVELET_CURVEEDITOR_BL_TOOLTIP;Zakázáno pokud je přiblížení přes 300% TP_WAVELET_CURVEEDITOR_CC_TOOLTIP;Mění lokální kontrast jako funkci originálního lokálního kontrastu(úsečka).\nNízké hodnoty na úsečce představují malý lokální kontrast (skutečné hodnoty okolo 10..20).\n50% z úsečky představuje průměrný lokální kontrast (skutečné hodnoty okolo 100..300).\n66% z úsečky představuje představuje standardní odchylku lokálního kontrastu (skutečné hodnoty okolo 300..800).\n100% z úsečky představuje maximální lokální kontrast (skutečné hodnoty okolo 3000..8000). TP_WAVELET_CURVEEDITOR_CH;Kontrast úrovní=f(Barevnost) TP_WAVELET_CURVEEDITOR_CH_TOOLTIP;Mění kontrast každé úrovně jako funkci odstínu.\nDejte pozor, abyste nepřepsali změny udělané v podnástroji Gamut nástroje Odstín.\nZměny křivky se projeví pouze v případě, že posuvníky kontrastu úrovní vlnky nejsou nastaveny na nulu. @@ -2155,10 +2265,13 @@ TP_WAVELET_DAUB6;D6 - standard plus TP_WAVELET_DAUB10;D10 - střední TP_WAVELET_DAUB14;D14 - Vysoká TP_WAVELET_DAUB_TOOLTIP;Změní Daubechiesové koeficienty:\nD4 = Standard,\nD14 = Nejčastěji nejlepší výkon, ale o 10% delší zpracování .\n\nOvlivňuje detekci hran a obecnou kvalitu obrázku na prvních úrovních.Ovšem kvalita není striktně vázána na koeficienty a může se lišit v závislosti na obrázku a použití. +TP_WAVELET_DIRFRAME;Směrový kontrast TP_WAVELET_DONE;Svisle TP_WAVELET_DTHR;Napříč TP_WAVELET_DTWO;Vodorovně TP_WAVELET_EDCU;Křivka +TP_WAVELET_EDEFFECT;Útlum +TP_WAVELET_EDEFFECT_TOOLTIP;Posuvník ovlivňuje rozsah hodnot kontrastu, které získají maximální efekt nástroje.\nMaximální hodnota (2.5) nástroj zakáže. TP_WAVELET_EDGCONT;Místní kontrast TP_WAVELET_EDGCONT_TOOLTIP;Posunutí bodů doleva snižuje kontrast a posunutí bodů doprava jej zvyšuje.\nRohy levý spodní, levý horní, pravý horní, pravý spodní postupně představují místní kontrast pro nízké hodnoty, průměr, průměr + stdev a maximum. TP_WAVELET_EDGE;Doostření hran @@ -2178,10 +2291,12 @@ TP_WAVELET_EDSL;Práh posuvníků TP_WAVELET_EDTYPE;Metoda místního kontrastu TP_WAVELET_EDVAL;Síla TP_WAVELET_FINAL;Finální doladění +TP_WAVELET_FINCFRAME;Finální místní kontrast +TP_WAVELET_FINCOAR_TOOLTIP;Levá (pozitivní) část křivky působí na jemnější úrovně (navýšení).\nDva body na úsečce představují příslušné akční limity jemnějšía hrubší úrovně 5 a 6 (výchozí). Pravá (negativní) část křivky působí na hrubší úrovně (navýšení).\nVyvarujte se posouvání levé části křivky se zápornými hodnotami. Vyvarujte se posouvání pravé části křivky s kladnými hodnotami. TP_WAVELET_FINEST;Nejjemnější -TP_WAVELET_HIGHLIGHT;Zvýrazněný rozsah jasů +TP_WAVELET_HIGHLIGHT;Jemnější úrovně rozsahu jasu TP_WAVELET_HS1;Celý rozsah jasů -TP_WAVELET_HS2;Stíny/Světla +TP_WAVELET_HS2;Výběrový rozsah jasu TP_WAVELET_HUESKIN;Odstín pleti TP_WAVELET_HUESKIN_TOOLTIP;Spodní body nastaví začátek zóny přenosu a horní body její konec. Tam bude efekt největší.\n\nPokud potřebujete oblast výrazně změnit nebo se objevily artefakty, je nastavení vyvážení bílé nesprávné. TP_WAVELET_HUESKY;Odstín oblohy @@ -2192,9 +2307,9 @@ TP_WAVELET_LABEL;Úrovně vlnky TP_WAVELET_LARGEST;Nejhrubší TP_WAVELET_LEVCH;Barevnost TP_WAVELET_LEVDIR_ALL;Všechny úrovně ve všech směrech -TP_WAVELET_LEVDIR_INF;Méně nebo shodně s úrovní +TP_WAVELET_LEVDIR_INF;Jemnější úrovně detailů s vybranou úrovní TP_WAVELET_LEVDIR_ONE;Jedna úroveň -TP_WAVELET_LEVDIR_SUP;Nad úrovní +TP_WAVELET_LEVDIR_SUP;Hrubší úrovně detailů s vybranou úrovní TP_WAVELET_LEVELS;Úrovně vlnky TP_WAVELET_LEVELS_TOOLTIP;Vyberte počet úrovní detailu mezi které bude obrázek rozložen. Více úrovní potřebuje více paměti a zpracování trvá déle. TP_WAVELET_LEVF;Kontrast @@ -2205,57 +2320,89 @@ TP_WAVELET_LEVTWO;Úroveň 3 TP_WAVELET_LEVZERO;Úroveň 1 TP_WAVELET_LINKEDG;Spojit se sílou doostření hran TP_WAVELET_LIPST;Vylepšený algoritmus -TP_WAVELET_LOWLIGHT;Rozsah jasu a stínů +TP_WAVELET_LOWLIGHT;Hrubší úrovně rozsahu jasu +TP_WAVELET_LOWTHR_TOOLTIP;Zabraňuje zesílení šumu v jemných texturách TP_WAVELET_MEDGREINF;První úroveň TP_WAVELET_MEDI;Omezení artefaktů na modré obloze TP_WAVELET_MEDILEV;Detekce hran TP_WAVELET_MEDILEV_TOOLTIP;Pro povolení Detekce hran Vám doporučujeme:\n- zakázat úrovně s nízkým kontrastem pro vyhnutí se vzniku artefaktů,\n- použít vysoké hodnoty gradientu citlivosti.\n\nSílu můžete ovlivnit pomocí 'vylepšení' z Odšumění a vylepšení. +TP_WAVELET_MERGEC;Sloučení barevnosti +TP_WAVELET_MERGEL;Sloučení jasu TP_WAVELET_NEUTRAL;Neutrální TP_WAVELET_NOIS;Odšumění TP_WAVELET_NOISE;Odšumění a vylepšení +TP_WAVELET_NOISE_TOOLTIP;Pokud je čtvrtá úroveň jasu odšumění lepší než 20, použije se Agresivní režim.\nPokud je hrubší barevnost lepší než 20, použije se Agresívní režim. TP_WAVELET_NPHIGH;Vysoká TP_WAVELET_NPLOW;Nízká TP_WAVELET_NPNONE;Nic TP_WAVELET_NPTYPE;Sousední pixely TP_WAVELET_NPTYPE_TOOLTIP;Tento algoritmus zkoumá blízkost pixelu a jeho osmi sousedů. V případě menšího rozdílu je hrana zesílena. +TP_WAVELET_OFFSET_TOOLTIP;Posun změní vyvážení mezi světly a stíny.\nVyšší hodnoty zdůrazní změnu kontrastu světel, kdežto nižší hodnoty zdůrazní změnu kontrastu stínů.\nZároveň s nízkou hodnotou útlumu máte možnost si vybrat, které kontrasty budou zvýrazněny. +TP_WAVELET_OLDSH;Algoritmus používá záporné hodnoty TP_WAVELET_OPACITY;Neprůhlednost modrá-žlutá TP_WAVELET_OPACITYW;Vyrovnání kontrastu d/v-h křivka -TP_WAVELET_OPACITYWL;Finální místní kontrast +TP_WAVELET_OPACITYWL;Místní kontrast TP_WAVELET_OPACITYWL_TOOLTIP;Změní finální lokální kontrast na konci zpracování vlnky.\n\nLevá strana představuje nejmenší lokální kontrast a pravá strana zase největší lokální kontrast. TP_WAVELET_PASTEL;Barevnost pastelů TP_WAVELET_PROC;Zpracování +TP_WAVELET_PROTAB;Ochrana +TP_WAVELET_RADIUS;Poloměr Stíny - Světla +TP_WAVELET_RANGEAB;Rozsah a a b % TP_WAVELET_RE1;Zesílená TP_WAVELET_RE2;Nezměněno TP_WAVELET_RE3;Omezená -TP_WAVELET_RESCHRO;Barevnost +TP_WAVELET_RESBLUR;Jas rozmazání +TP_WAVELET_RESBLURC;Barevnost rozmazání +TP_WAVELET_RESBLUR_TOOLTIP;Zakázáno pokud je přiblížení přes 500% +TP_WAVELET_RESCHRO;Intenzita TP_WAVELET_RESCON;Stíny TP_WAVELET_RESCONH;Světla TP_WAVELET_RESID;Zůstatek obrazu TP_WAVELET_SAT;Nasycená barevnost TP_WAVELET_SETTINGS;Nastavení vlnky +TP_WAVELET_SHA;Ostrá maska +TP_WAVELET_SHFRAME;Stíny/Světla +TP_WAVELET_SHOWMASK;Ukázat vlnkovou 'masku' +TP_WAVELET_SIGMA;Útlum +TP_WAVELET_SIGMAFIN;Útlum +TP_WAVELET_SIGMA_TOOLTIP;Efekt posuvníků kontrastu je silnější u detailů se středními hodnotami kontrastu, a slabší u detailů s vysokými nebo nízkými hodnotami kontrastu.\n Tímto posuvníkem můžete kontrolovat jak rychle je potlačen efekt u extrémních hodnot kontrastu.\n Čím výše je posuvník nastaven, tím širší je rozsah hodnot kontrastů u kterých nastane silnější změna s větší šancí na vytvoření artefaktů.\n Čím je níže, tím přesněji bude účinek aplikován na úzkýrozsah hodnot kontrastu. TP_WAVELET_SKIN;Ochrana: zaměření na pleťové tóny TP_WAVELET_SKIN_TOOLTIP;Hodnota -100: zaměřeno na pleťové tóny.\nHodnota 0: se všemi tóny je zacházeno stejně.\nHodnota +100: pleťové tóny jsou chráněny zatímco všechny ostatní tóny jsou ovlivněny. TP_WAVELET_SKY;Ochrana a zaměření na tóny oblohy TP_WAVELET_SKY_TOOLTIP;Hodnota -100: zaměřeno na pleťové tóny.\nHodnota 0: se všemi tóny je zacházeno stejně.\nHodnota +100: pleťové tóny jsou chráněny zatímco všechny ostatní tóny jsou ovlivněny. +TP_WAVELET_SOFTRAD;Jemný poloměr TP_WAVELET_STREN;Síla TP_WAVELET_STRENGTH;Síla TP_WAVELET_SUPE;Extra TP_WAVELET_THR;Práh stínů -TP_WAVELET_THRESHOLD;Úrovně světel -TP_WAVELET_THRESHOLD2;Úrovně stínů -TP_WAVELET_THRESHOLD2_TOOLTIP;Pouze úrovně 9 a 9 mínus hodnota budou ovlivněny rozsahem stínů a jasů.Ostatní úrovně budou plně zpracovány. Maximální možná úroveň je omezena na nejvyšší hodnotu úrovně (9 - nejvyšší úroveň). -TP_WAVELET_THRESHOLD_TOOLTIP;Pouze úrovně pod vybranou hodnotou budou ovlivněny rozsahem zvýraznění jasů.Ostatní úrovně budou plně zpracovány. Zde vybraná hodnota omezí nejvyšší možnou hodnotu úrovně stínů. +TP_WAVELET_THRESHOLD;Jemnější úrovně +TP_WAVELET_THRESHOLD2;Hrubší úrovně +TP_WAVELET_THRESHOLD2_TOOLTIP;Pouze úrovně mezi 9 a 9 mínus hodnota budou ovlivněny rozsahem jasu stínů. Ostatní úrovně budou upraveny celé. Nejvyšší možná úroveň je omezena hodnotou zvýrazněné úrovně (9 mínus hodnota zvýrazněné úrovně). Pouze úrovně mezi vybranou hodnotou a úrovní 9/Extra budou ovlivněny Hrubým rozsahem úrovní.\nVšechny ostatní úrovně budou ovlivněny v celém rozsahu jasu, pokud nebudou omezeny nastavením Jemnými úrovněmi.\nNejnižší možná úroveň, kterou bude algoritmus zvažovat, je omezená hodnotou Jemných úrovní. +TP_WAVELET_THRESHOLD_TOOLTIP;Pouze úrovně mimo vybranou hodnotu budou ovlivněny rozsahem jasu stínů. Ostatní úrovně budou upraveny celé. Zde vybraná hodnota omezuje nejvyšší možnou hodnotu úrovní stínů. Všechny úrovně od úrovně jedna až po vybranou úroveň ovlivněny Jemným rozsahem úrovní.\nVšechny ostatní úrovně budou ovlivněny v celém rozsahu jasu, pokud nebudou omezeny nastavením Hrubými úrovněmi.\nZde vybraná hodnota, se stane nejnižší možnou úrovní Hrubých úrovní. +TP_WAVELET_THRESWAV;Práh vyvážení TP_WAVELET_THRH;Práh světel -TP_WAVELET_TILESBIG;Velké dlaždice +TP_WAVELET_TILESBIG;Dlaždice TP_WAVELET_TILESFULL;Celý obrázek TP_WAVELET_TILESIZE;Metoda dlaždicování TP_WAVELET_TILESLIT;Malé dlaždice TP_WAVELET_TILES_TOOLTIP;Zpracování celého obrázku vede k lepší kvalitě a je doporučováno. Naproti tomu dlaždice jsou náhradní řešení pro uživatele s nedostatkem paměti. Paměťové nároky najdete na RawPedii. +TP_WAVELET_TMEDGS;Zachování hran +TP_WAVELET_TMSCALE;Měřítko TP_WAVELET_TMSTRENGTH;Síla komprese -TP_WAVELET_TMSTRENGTH_TOOLTIP;Ovládá sílu mapování tónů nebo kontrast komprese zůstatku obrázku. Pokud je hodnota rozdílná od nuly, budou posuvníky Síla a Gama v nástroji Mapování tónů v kartě Expozice neaktivní. +TP_WAVELET_TMSTRENGTH_TOOLTIP;Kontroluje sílu tónového mapování nebo komprese kontrastu zůstatku obrazu. TP_WAVELET_TMTYPE;Metoda komprese TP_WAVELET_TON;Tónování +TP_WAVELET_TONFRAME;Vyloučené barvy +TP_WAVELET_USH;Nic +TP_WAVELET_USHARP;Metoda čirosti +TP_WAVELET_USHARP_TOOLTIP;Původní : zdrojovým souborem je soubor před Vlnkou.\nVlnka : zdrojovým souborem je soubor s aplikovanou Vlnkou. +TP_WAVELET_USH_TOOLTIP;Pokud vyberete Ostrou masku, bude nastavení vlnky automaticky změněno na:\nPozadí=černá, zpracování=pod, úroveň=3 — ta může být změněna v rozmezí 1 až 4.\n\nPokud vyberete Čirost, bude nastavení vlnky automaticky změněno na:\nPozadí=zůstatek, zpracování=nad, úroveň=7 — ta může být změněna v rozmezí 5 až 10 úrovní vlnky. +TP_WAVELET_WAVLOWTHR;Práh nízkého kontrastu +TP_WAVELET_WAVOFFSET;Posun TP_WBALANCE_AUTO;Automaticky +TP_WBALANCE_AUTOITCGREEN;Teplotní korelace +TP_WBALANCE_AUTOOLD;RGB šedé +TP_WBALANCE_AUTO_HEADER;Automaticky TP_WBALANCE_CAMERA;Fotoaparát TP_WBALANCE_CLOUDY;Zataženo TP_WBALANCE_CUSTOM;Vlastní @@ -2297,6 +2444,8 @@ TP_WBALANCE_SOLUX41;Solux 4100K TP_WBALANCE_SOLUX47;Solux 4700K (vendor) TP_WBALANCE_SOLUX47_NG;Solux 4700K (Nat. Gallery) TP_WBALANCE_SPOTWB;Použijte pipetu pro nabrání vyvážení bílé z neutrální oblasti v náhledu. +TP_WBALANCE_STUDLABEL;Faktor korelace: %1 +TP_WBALANCE_STUDLABEL_TOOLTIP;Zobrazí vypočítanou korelaci metody Student\nNižší hodnoty jsou lepší, přičemž pro <0.005 jsou výborné\n<0.01 jsou dobré a >0.5 jsou špatné.\nNízké hodnoty neznamenají, že je vyvážení bílé dobré: pro nestandardní světelné podmínky jsou výsledky nepředvídatelné.\nHodnota 1000 znamená, že byl použit předchozí výpočet a výsledky jsou pravděpodobně dobré. TP_WBALANCE_TEMPBIAS;AVB - Zdůraznění teploty TP_WBALANCE_TEMPBIAS_TOOLTIP;Dovolí ovlivnit výpočet "automatického vyvážení bílé"\nzdůrazněním teplejší nebo chladnější teploty. Toto zdůraznění\nje vyjádřeno v procentech vypočtené teploty a výsledek\nlze vyjádřit vzorcem "vypočtenáTeplota + vypočtenáTeplota * zdůraznění". TP_WBALANCE_TEMPERATURE;Teplota @@ -2311,42 +2460,3 @@ ZOOMPANEL_ZOOMFITCROPSCREEN;Přizpůsobit ořez obrazovce\nZkratka: f ZOOMPANEL_ZOOMFITSCREEN;Přizpůsobit celý obrázek obrazovce\nZkratka: Alt-f ZOOMPANEL_ZOOMIN;Přiblížit\nZkratka: + ZOOMPANEL_ZOOMOUT;Oddálit\nZkratka: - - -!!!!!!!!!!!!!!!!!!!!!!!!! -! Untranslated keys follow; remove the ! prefix after an entry is translated. -!!!!!!!!!!!!!!!!!!!!!!!!! - -!FILEBROWSER_DELETEDIALOG_ALL;Are you sure you want to permanently delete all %1 files in trash? -!FILEBROWSER_DELETEDIALOG_SELECTED;Are you sure you want to permanently delete the selected %1 files? -!FILEBROWSER_DELETEDIALOG_SELECTEDINCLPROC;Are you sure you want to permanently delete the selected %1 files, including a queue-processed version? -!FILEBROWSER_EMPTYTRASHHINT;Permanently delete all files in trash. -!FILEBROWSER_POPUPREMOVE;Delete permanently -!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version -!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. -!GENERAL_HELP;Help -!HISTORY_MSG_494;Capture Sharpening -!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only -!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative -!HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values -!HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold -!HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - Auto radius -!HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations -!HISTORY_MSG_PDSHARPEN_CONTRAST;CS - Contrast threshold -!HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - Iterations -!HISTORY_MSG_PDSHARPEN_RADIUS;CS - Radius -!HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - Corner radius boost -!HISTORY_MSG_TRANS_Method;Geometry - Method -!PARTIALPASTE_FILMNEGATIVE;Film Negative -!PREFERENCES_APPEARANCE_PSEUDOHIDPI;Pseudo-HiDPI mode -!TP_DEHAZE_LUMINANCE;Luminance only -!TP_FILMNEGATIVE_BLUE;Blue ratio -!TP_FILMNEGATIVE_GREEN;Reference exponent (contrast) -!TP_FILMNEGATIVE_GUESS_TOOLTIP;Automatically set the red and blue ratios by picking two patches which had a neutral hue (no color) in the original scene. The patches should differ in brightness. Set the white balance afterwards. -!TP_FILMNEGATIVE_LABEL;Film Negative -!TP_FILMNEGATIVE_PICK;Pick neutral spots -!TP_FILMNEGATIVE_RED;Red ratio -!TP_LENSGEOM_LIN;Linear -!TP_LENSGEOM_LOG;Logarithmic -!TP_PDSHARPENING_LABEL;Capture Sharpening -!TP_SHARPENING_ITERCHECK;Auto limit iterations -!TP_SHARPENING_RADIUS_BOOST;Corner radius boost diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US) index d8c497f16..1bd319e6f 100644 --- a/rtdata/languages/English (US) +++ b/rtdata/languages/English (US) @@ -937,7 +937,7 @@ !MAIN_TOOLTIP_BACKCOLOR0;Background color of the preview: theme-based\nShortcut: 9 !MAIN_TOOLTIP_BACKCOLOR1;Background color of the preview: black\nShortcut: 9 !MAIN_TOOLTIP_BACKCOLOR2;Background color of the preview: white\nShortcut: 9 -!MAIN_TOOLTIP_BACKCOLOR3;Background color of the preview: middle grey\nShortcut: 9 +!MAIN_TOOLTIP_BACKCOLOR3;Background color of the preview: middle gray\nShortcut: 9 !MAIN_TOOLTIP_BEFOREAFTERLOCK;Lock / Unlock the Before view\n\nLock: keep the Before view unchanged.\nUseful to evaluate the cumulative effect of multiple tools.\nAdditionally, comparisons can be made to any state in the History.\n\nUnlock: the Before view will follow the After view one step behind, showing the image before the effect of the currently used tool. !MAIN_TOOLTIP_HIDEHP;Show/Hide the left panel (including the history).\nShortcut: l !MAIN_TOOLTIP_INDCLIPPEDH;Clipped highlight indication.\nShortcut: > @@ -2097,7 +2097,7 @@ !TP_WAVELET_APPLYTO;Apply To !TP_WAVELET_AVOID;Avoid color shift !TP_WAVELET_B0;Black -!TP_WAVELET_B1;Grey +!TP_WAVELET_B1;Gray !TP_WAVELET_B2;Residual !TP_WAVELET_BACKGROUND;Background !TP_WAVELET_BACUR;Curve diff --git a/rtdata/languages/Nederlands b/rtdata/languages/Nederlands index c43f6314e..ba5880bfb 100644 --- a/rtdata/languages/Nederlands +++ b/rtdata/languages/Nederlands @@ -14,6 +14,7 @@ #14 2015-11-23 update by wim ter meer #15 2016-07-21 update by wim ter meer #16 2017-04-21 update by wim ter meer +#17 2020-06-05 update by dheijl ABOUT_TAB_BUILD;Versie ABOUT_TAB_CREDITS;Credits @@ -1962,367 +1963,367 @@ ZOOMPANEL_ZOOMOUT;Zoom uit\nSneltoets: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! -!ADJUSTER_RESET_TO_DEFAULT;Click - reset to default value.\nCtrl+click - reset to initial value. -!CURVEEDITOR_CATMULLROM;Flexible -!DONT_SHOW_AGAIN;Don't show this message again. -!DYNPROFILEEDITOR_IMGTYPE_ANY;Any -!DYNPROFILEEDITOR_IMGTYPE_HDR;HDR -!DYNPROFILEEDITOR_IMGTYPE_PS;Pixel Shift -!DYNPROFILEEDITOR_IMGTYPE_STD;Standard -!EXIFFILTER_IMAGETYPE;Image type -!EXIFPANEL_SHOWALL;Show all -!FILEBROWSER_BROWSEPATHBUTTONHINT;Click to open specified path, reload folder and apply "find" keywords. -!FILEBROWSER_CACHECLEARFROMFULL;Clear all including cached profiles -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear all except cached profiles -!FILEBROWSER_DELETEDIALOG_ALL;Are you sure you want to permanently delete all %1 files in trash? -!FILEBROWSER_DELETEDIALOG_SELECTED;Are you sure you want to permanently delete the selected %1 files? -!FILEBROWSER_DELETEDIALOG_SELECTEDINCLPROC;Are you sure you want to permanently delete the selected %1 files, including a queue-processed version? -!FILEBROWSER_EMPTYTRASHHINT;Permanently delete all files in trash. -!FILEBROWSER_POPUPREMOVE;Delete permanently -!FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version -!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. -!GENERAL_CURRENT;Current -!GENERAL_HELP;Help -!GENERAL_RESET;Reset -!GENERAL_SAVE_AS;Save as... -!GENERAL_SLIDER;Slider -!GIMP_PLUGIN_INFO;Welcome to the RawTherapee GIMP plugin!\nOnce you are done editing, simply close the main RawTherapee window and the image will be automatically imported in GIMP. -!HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram. -!HISTORY_MSG_173;NR - Detail recovery -!HISTORY_MSG_203;NR - Color space -!HISTORY_MSG_235;B&W - CM - Auto -!HISTORY_MSG_237;B&W - CM -!HISTORY_MSG_256;NR - Median - Type -!HISTORY_MSG_273;CT - Color Balance SMH -!HISTORY_MSG_297;NR - Mode -!HISTORY_MSG_392;W - Residual - Color Balance -!HISTORY_MSG_441;Retinex - Gain transmission -!HISTORY_MSG_475;PS - Equalize channel -!HISTORY_MSG_476;CAM02 - Temp out -!HISTORY_MSG_477;CAM02 - Green out -!HISTORY_MSG_478;CAM02 - Yb out -!HISTORY_MSG_479;CAM02 - CAT02 adaptation out -!HISTORY_MSG_480;CAM02 - Automatic CAT02 out -!HISTORY_MSG_481;CAM02 - Temp scene -!HISTORY_MSG_482;CAM02 - Green scene -!HISTORY_MSG_483;CAM02 - Yb scene -!HISTORY_MSG_484;CAM02 - Auto Yb scene -!HISTORY_MSG_485;Lens Correction -!HISTORY_MSG_486;Lens Correction - Camera -!HISTORY_MSG_487;Lens Correction - Lens -!HISTORY_MSG_488;Dynamic Range Compression -!HISTORY_MSG_489;DRC - Detail -!HISTORY_MSG_490;DRC - Amount -!HISTORY_MSG_491;White Balance -!HISTORY_MSG_492;RGB Curves -!HISTORY_MSG_493;L*a*b* Adjustments -!HISTORY_MSG_494;Capture Sharpening -!HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors -!HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction -!HISTORY_MSG_COLORTONING_LABREGION_AB;CT - Color correction -!HISTORY_MSG_COLORTONING_LABREGION_CHANNEL;CT - Channel -!HISTORY_MSG_COLORTONING_LABREGION_CHROMATICITYMASK;CT - region C mask -!HISTORY_MSG_COLORTONING_LABREGION_HUEMASK;CT - H mask -!HISTORY_MSG_COLORTONING_LABREGION_LIGHTNESS;CT - Lightness -!HISTORY_MSG_COLORTONING_LABREGION_LIGHTNESSMASK;CT - L mask -!HISTORY_MSG_COLORTONING_LABREGION_LIST;CT - List -!HISTORY_MSG_COLORTONING_LABREGION_MASKBLUR;CT - region mask blur -!HISTORY_MSG_COLORTONING_LABREGION_OFFSET;CT - region offset -!HISTORY_MSG_COLORTONING_LABREGION_POWER;CT - region power -!HISTORY_MSG_COLORTONING_LABREGION_SATURATION;CT - Saturation -!HISTORY_MSG_COLORTONING_LABREGION_SHOWMASK;CT - region show mask -!HISTORY_MSG_COLORTONING_LABREGION_SLOPE;CT - region slope -!HISTORY_MSG_DEHAZE_DEPTH;Dehaze - Depth -!HISTORY_MSG_DEHAZE_ENABLED;Haze Removal -!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only -!HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;Dehaze - Show depth map -!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength -!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold -!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold -!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative -!HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values -!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve -!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries -!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D -!HISTORY_MSG_ICM_OUTPUT_TYPE;Output - Type -!HISTORY_MSG_ICM_WORKING_GAMMA;Working - Gamma -!HISTORY_MSG_ICM_WORKING_SLOPE;Working - Slope -!HISTORY_MSG_ICM_WORKING_TRC_METHOD;Working - TRC method -!HISTORY_MSG_LOCALCONTRAST_AMOUNT;Local Contrast - Amount -!HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness -!HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast -!HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Local Contrast - Lightness -!HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius -!HISTORY_MSG_METADATA_MODE;Metadata copy mode -!HISTORY_MSG_MICROCONTRAST_CONTRAST;Microcontrast - Contrast threshold -!HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold -!HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - Auto radius -!HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations -!HISTORY_MSG_PDSHARPEN_CONTRAST;CS - Contrast threshold -!HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - Iterations -!HISTORY_MSG_PDSHARPEN_RADIUS;CS - Radius -!HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - Corner radius boost -!HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - Demosaic method for motion -!HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;Line noise filter direction -!HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAF lines filter -!HISTORY_MSG_PRSHARPEN_CONTRAST;PRS - Contrast threshold -!HISTORY_MSG_RAWCACORR_AUTOIT;Raw CA Correction - Iterations -!HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw CA Correction - Avoid color shift -!HISTORY_MSG_RAW_BORDER;Raw border -!HISTORY_MSG_RESIZE_ALLOWUPSCALING;Resize - Allow upscaling -!HISTORY_MSG_SHARPENING_BLUR;Sharpening - Blur radius -!HISTORY_MSG_SHARPENING_CONTRAST;Sharpening - Contrast threshold -!HISTORY_MSG_SH_COLORSPACE;S/H - Colorspace -!HISTORY_MSG_SOFTLIGHT_ENABLED;Soft light -!HISTORY_MSG_SOFTLIGHT_STRENGTH;Soft light - Strength -!HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor -!HISTORY_MSG_TRANS_Method;Geometry - Method -!ICCPROFCREATOR_COPYRIGHT;Copyright: -!ICCPROFCREATOR_COPYRIGHT_RESET_TOOLTIP;Reset to the default copyright, granted to "RawTherapee, CC0" -!ICCPROFCREATOR_CUSTOM;Custom -!ICCPROFCREATOR_DESCRIPTION;Description: -!ICCPROFCREATOR_DESCRIPTION_ADDPARAM;Append gamma and slope values to the description -!ICCPROFCREATOR_DESCRIPTION_TOOLTIP;Leave empty to set the default description. -!ICCPROFCREATOR_GAMMA;Gamma -!ICCPROFCREATOR_ICCVERSION;ICC version: -!ICCPROFCREATOR_ILL;Illuminant: -!ICCPROFCREATOR_ILL_41;D41 -!ICCPROFCREATOR_ILL_50;D50 -!ICCPROFCREATOR_ILL_55;D55 -!ICCPROFCREATOR_ILL_60;D60 -!ICCPROFCREATOR_ILL_65;D65 -!ICCPROFCREATOR_ILL_80;D80 -!ICCPROFCREATOR_ILL_DEF;Default -!ICCPROFCREATOR_ILL_INC;StdA 2856K -!ICCPROFCREATOR_ILL_TOOLTIP;You can only set the illuminant for ICC v4 profiles. -!ICCPROFCREATOR_PRIMARIES;Primaries: -!ICCPROFCREATOR_PRIM_ACESP0;ACES AP0 -!ICCPROFCREATOR_PRIM_ACESP1;ACES AP1 -!ICCPROFCREATOR_PRIM_ADOBE;Adobe RGB (1998) -!ICCPROFCREATOR_PRIM_BEST;BestRGB -!ICCPROFCREATOR_PRIM_BETA;BetaRGB -!ICCPROFCREATOR_PRIM_BLUX;Blue X -!ICCPROFCREATOR_PRIM_BLUY;Blue Y -!ICCPROFCREATOR_PRIM_BRUCE;BruceRGB -!ICCPROFCREATOR_PRIM_GREX;Green X -!ICCPROFCREATOR_PRIM_GREY;Green Y -!ICCPROFCREATOR_PRIM_PROPH;Prophoto -!ICCPROFCREATOR_PRIM_REC2020;Rec2020 -!ICCPROFCREATOR_PRIM_REDX;Red X -!ICCPROFCREATOR_PRIM_REDY;Red Y -!ICCPROFCREATOR_PRIM_SRGB;sRGB -!ICCPROFCREATOR_PRIM_TOOLTIP;You can only set custom primaries for ICC v4 profiles. -!ICCPROFCREATOR_PRIM_WIDEG;Widegamut -!ICCPROFCREATOR_PROF_V2;ICC v2 -!ICCPROFCREATOR_PROF_V4;ICC v4 -!ICCPROFCREATOR_SAVEDIALOG_TITLE;Save ICC profile as... -!ICCPROFCREATOR_SLOPE;Slope -!ICCPROFCREATOR_TRC_PRESET;Tone response curve: -!MAIN_BUTTON_ICCPROFCREATOR;ICC Profile Creator -!MAIN_FRAME_PLACES_DEL;Remove -!MAIN_MSG_TOOMANYOPENEDITORS;Too many open editors.\nPlease close an editor to continue. -!MAIN_TAB_ADVANCED;Advanced -!MAIN_TAB_ADVANCED_TOOLTIP;Shortcut: Alt-a -!MAIN_TAB_FAVORITES;Favorites -!MAIN_TAB_FAVORITES_TOOLTIP;Shortcut: Alt-u -!MAIN_TOOLTIP_BACKCOLOR3;Background color of the preview: middle grey\nShortcut: 9 -!MAIN_TOOLTIP_PREVIEWSHARPMASK;Preview the sharpening contrast mask.\nShortcut: p\n\nOnly works when sharpening is enabled and zoom >= 100%. -!OPTIONS_BUNDLED_MISSING;The bundled profile "%1" could not be found!\n\nYour installation could be damaged.\n\nDefault internal values will be used instead. -!OPTIONS_DEFIMG_MISSING;The default profile for non-raw photos could not be found or is not set.\n\nPlease check your profiles' directory, it may be missing or damaged.\n\n"%1" will be used instead. -!OPTIONS_DEFRAW_MISSING;The default profile for raw photos could not be found or is not set.\n\nPlease check your profiles' directory, it may be missing or damaged.\n\n"%1" will be used instead. -!PARTIALPASTE_ADVANCEDGROUP;Advanced Settings -!PARTIALPASTE_DEHAZE;Haze removal -!PARTIALPASTE_FILMNEGATIVE;Film Negative -!PARTIALPASTE_LOCALCONTRAST;Local contrast -!PARTIALPASTE_METADATA;Metadata mode -!PARTIALPASTE_PREPROCESS_PDAFLINESFILTER;PDAF lines filter -!PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT;CA avoid color shift -!PARTIALPASTE_RAW_BORDER;Raw border -!PARTIALPASTE_SOFTLIGHT;Soft light -!PARTIALPASTE_TM_FATTAL;Dynamic range compression -!PREFERENCES_APPEARANCE;Appearance -!PREFERENCES_APPEARANCE_COLORPICKERFONT;Color picker font -!PREFERENCES_APPEARANCE_CROPMASKCOLOR;Crop mask color -!PREFERENCES_APPEARANCE_MAINFONT;Main font -!PREFERENCES_APPEARANCE_PSEUDOHIDPI;Pseudo-HiDPI mode -!PREFERENCES_APPEARANCE_THEME;Theme -!PREFERENCES_AUTOSAVE_TP_OPEN;Save tool collapsed/expanded state on exit -!PREFERENCES_CACHECLEAR;Clear -!PREFERENCES_CACHECLEAR_ALL;Clear all cached files: -!PREFERENCES_CACHECLEAR_ALLBUTPROFILES;Clear all cached files except for cached processing profiles: -!PREFERENCES_CACHECLEAR_ONLYPROFILES;Clear only cached processing profiles: -!PREFERENCES_CACHECLEAR_SAFETY;Only files in the cache are cleared. Processing profiles stored alongside the source images are not touched. -!PREFERENCES_CHUNKSIZES;Tiles per thread -!PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE demosaic -!PREFERENCES_CHUNKSIZE_RAW_CA;Raw CA correction -!PREFERENCES_CHUNKSIZE_RAW_RCD;RCD demosaic -!PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans demosaic -!PREFERENCES_CHUNKSIZE_RGB;RGB processing -!PREFERENCES_CROP;Crop Editing -!PREFERENCES_CROP_AUTO_FIT;Automatically zoom to fit the crop -!PREFERENCES_CROP_GUIDES;Guides shown when not editing the crop -!PREFERENCES_CROP_GUIDES_FRAME;Frame -!PREFERENCES_CROP_GUIDES_FULL;Original -!PREFERENCES_CROP_GUIDES_NONE;None -!PREFERENCES_DIRECTORIES;Directories -!PREFERENCES_EDITORCMDLINE;Custom command line -!PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser -!PREFERENCES_LANG;Language -!PREFERENCES_PERFORMANCE_MEASURE;Measure -!PREFERENCES_PERFORMANCE_MEASURE_HINT;Logs processing times in console -!PREFERENCES_PERFORMANCE_THREADS;Threads -!PREFERENCES_PERFORMANCE_THREADS_LABEL;Maximum number of threads for Noise Reduction and Wavelet Levels (0 = Automatic) -!PREFERENCES_PROFILESAVEBOTH;Save processing profile both to the cache and next to the input file -!PREFERENCES_PROFILESAVELOCATION;Processing profile saving location -!PREFERENCES_SAVE_TP_OPEN_NOW;Save tool collapsed/expanded state now -!PREFERENCES_TAB_PERFORMANCE;Performance -!PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;Embedded JPEG preview -!PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Image to show -!PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral raw rendering -!PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral raw otherwise -!PROGRESSBAR_DECODING;Decoding... -!PROGRESSBAR_GREENEQUIL;Green equilibration... -!PROGRESSBAR_HLREC;Highlight reconstruction... -!PROGRESSBAR_HOTDEADPIXELFILTER;Hot/dead pixel filter... -!PROGRESSBAR_LINEDENOISE;Line noise filter... -!PROGRESSBAR_RAWCACORR;Raw CA correction... -!QINFO_FRAMECOUNT;%2 frames -!QINFO_HDR;HDR / %2 frame(s) -!QINFO_PIXELSHIFT;Pixel Shift / %2 frame(s) -!QUEUE_LOCATION_TITLE;Output Location -!QUEUE_STARTSTOP_TOOLTIP;Start or stop processing the images in the queue.\n\nShortcut: Ctrl+s -!SAMPLEFORMAT_0;Unknown data format -!SAMPLEFORMAT_1;8-bit unsigned -!SAMPLEFORMAT_2;16-bit unsigned -!SAMPLEFORMAT_4;24-bit LogLuv -!SAMPLEFORMAT_8;32-bit LogLuv -!SAMPLEFORMAT_16;16-bit floating-point -!SAMPLEFORMAT_32;24-bit floating-point -!SAMPLEFORMAT_64;32-bit floating-point -!SAVEDLG_FILEFORMAT_FLOAT; floating-point -!SOFTPROOF_GAMUTCHECK_TOOLTIP;Highlight pixels with out-of-gamut colors with respect to:\n- the printer profile, if one is set and soft-proofing is enabled,\n- the output profile, if a printer profile is not set and soft-proofing is enabled,\n- the monitor profile, if soft-proofing is disabled. -!SOFTPROOF_TOOLTIP;Soft-proofing simulates the appearance of the image:\n- when printed, if a printer profile is set in Preferences > Color Management,\n- when viewed on a display that uses the current output profile, if a printer profile is not set. -!TP_BWMIX_MIXC;Channel Mixer -!TP_BWMIX_NEUTRAL;Reset -!TP_COLORAPP_ABSOLUTELUMINANCE;Absolute luminance -!TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;When setting manually, values above 65 are recommended. -!TP_COLORAPP_FREE;Free temp+green + CAT02 + [output] -!TP_COLORAPP_MEANLUMINANCE;Mean luminance (Yb%) -!TP_COLORAPP_NEUTRAL;Reset -!TP_COLORAPP_NEUTRAL_TIP;Reset all sliders checkbox and curves to their default values -!TP_COLORAPP_TEMP_TOOLTIP;To select an illuminant, always set Tint=1.\n\nA temp=2856\nD50 temp=5003\nD55 temp=5503\nD65 temp=6504\nD75 temp=7504 -!TP_COLORTONING_LABGRID;L*a*b* color correction grid -!TP_COLORTONING_LABGRID_VALUES;HL: a=%1 b=%2\nS: a=%3 b=%4 -!TP_COLORTONING_LABREGIONS;Color correction regions -!TP_COLORTONING_LABREGION_ABVALUES;a=%1 b=%2 -!TP_COLORTONING_LABREGION_CHANNEL;Channel -!TP_COLORTONING_LABREGION_CHANNEL_ALL;All -!TP_COLORTONING_LABREGION_CHANNEL_B;Blue -!TP_COLORTONING_LABREGION_CHANNEL_G;Green -!TP_COLORTONING_LABREGION_CHANNEL_R;Red -!TP_COLORTONING_LABREGION_CHROMATICITYMASK;C -!TP_COLORTONING_LABREGION_HUEMASK;H -!TP_COLORTONING_LABREGION_LIGHTNESS;Lightness -!TP_COLORTONING_LABREGION_LIGHTNESSMASK;L -!TP_COLORTONING_LABREGION_LIST_TITLE;Correction -!TP_COLORTONING_LABREGION_MASK;Mask -!TP_COLORTONING_LABREGION_MASKBLUR;Mask Blur -!TP_COLORTONING_LABREGION_OFFSET;Offset -!TP_COLORTONING_LABREGION_POWER;Power -!TP_COLORTONING_LABREGION_SATURATION;Saturation -!TP_COLORTONING_LABREGION_SHOWMASK;Show mask -!TP_COLORTONING_LABREGION_SLOPE;Slope -!TP_CROP_PPI;PPI -!TP_CROP_RESETCROP;Reset -!TP_CROP_SELECTCROP;Select -!TP_DEHAZE_DEPTH;Depth -!TP_DEHAZE_LABEL;Haze Removal -!TP_DEHAZE_LUMINANCE;Luminance only -!TP_DEHAZE_SHOW_DEPTH_MAP;Show depth map -!TP_DEHAZE_STRENGTH;Strength -!TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Increase (multiply) the value of all chrominance sliders.\nThis curve lets you adjust the strength of chromatic noise reduction as a function of chromaticity, for instance to increase the action in areas of low saturation and to decrease it in those of high saturation. -!TP_DIRPYRDENOISE_LABEL;Noise Reduction -!TP_EXPOSURE_CLAMPOOG;Clip out-of-gamut colors -!TP_EXPOSURE_HISTMATCHING;Auto-Matched Tone Curve -!TP_EXPOSURE_HISTMATCHING_TOOLTIP;Automatically adjust sliders and curves (except exposure compensation) to match the look of the embedded JPEG thumbnail. -!TP_FILMNEGATIVE_BLUE;Blue ratio -!TP_FILMNEGATIVE_GREEN;Reference exponent (contrast) -!TP_FILMNEGATIVE_GUESS_TOOLTIP;Automatically set the red and blue ratios by picking two patches which had a neutral hue (no color) in the original scene. The patches should differ in brightness. Set the white balance afterwards. -!TP_FILMNEGATIVE_LABEL;Film Negative -!TP_FILMNEGATIVE_PICK;Pick neutral spots -!TP_FILMNEGATIVE_RED;Red ratio -!TP_ICM_WORKING_TRC;Tone response curve: -!TP_ICM_WORKING_TRC_CUSTOM;Custom -!TP_ICM_WORKING_TRC_GAMMA;Gamma -!TP_ICM_WORKING_TRC_NONE;None -!TP_ICM_WORKING_TRC_SLOPE;Slope -!TP_ICM_WORKING_TRC_TOOLTIP;Only for built-in profiles. -!TP_LENSGEOM_LIN;Linear -!TP_LENSGEOM_LOG;Logarithmic -!TP_LENSPROFILE_CORRECTION_AUTOMATCH;Automatically selected -!TP_LENSPROFILE_CORRECTION_LCPFILE;LCP file -!TP_LENSPROFILE_CORRECTION_MANUAL;Manually selected -!TP_LENSPROFILE_LENS_WARNING;Warning: the crop factor used for lens profiling is larger than the crop factor of the camera, the results might be wrong. -!TP_LENSPROFILE_MODE_HEADER;Lens Profile -!TP_LENSPROFILE_USE_CA;Chromatic aberration -!TP_LENSPROFILE_USE_GEOMETRIC;Geometric distortion -!TP_LENSPROFILE_USE_HEADER;Correct -!TP_LENSPROFILE_USE_VIGNETTING;Vignetting -!TP_LOCALCONTRAST_AMOUNT;Amount -!TP_LOCALCONTRAST_DARKNESS;Darkness level -!TP_LOCALCONTRAST_LABEL;Local Contrast -!TP_LOCALCONTRAST_LIGHTNESS;Lightness level -!TP_LOCALCONTRAST_RADIUS;Radius -!TP_METADATA_EDIT;Apply modifications -!TP_METADATA_MODE;Metadata copy mode -!TP_METADATA_STRIP;Strip all metadata -!TP_METADATA_TUNNEL;Copy unchanged -!TP_PDSHARPENING_LABEL;Capture Sharpening -!TP_PREPROCESS_LINEDENOISE_DIRECTION;Direction -!TP_PREPROCESS_LINEDENOISE_DIRECTION_BOTH;Both -!TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL;Horizontal -!TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;Horizontal only on PDAF rows -!TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Vertical -!TP_PREPROCESS_PDAFLINESFILTER;PDAF lines filter -!TP_RAWCACORR_AUTOIT;Iterations -!TP_RAWCACORR_AUTOIT_TOOLTIP;This setting is available if "Auto-correction" is checked.\nAuto-correction is conservative, meaning that it often does not correct all chromatic aberration.\nTo correct the remaining chromatic aberration, you can use up to five iterations of automatic chromatic aberration correction.\nEach iteration will reduce the remaining chromatic aberration from the last iteration at the cost of additional processing time. -!TP_RAWCACORR_AVOIDCOLORSHIFT;Avoid color shift -!TP_RAW_2PASS;1-pass+fast -!TP_RAW_4PASS;3-pass+fast -!TP_RAW_AMAZEVNG4;AMaZE+VNG4 -!TP_RAW_BORDER;Border -!TP_RAW_DCBVNG4;DCB+VNG4 -!TP_RAW_DUALDEMOSAICAUTOCONTRAST;Auto threshold -!TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;If the checkbox is checked (recommended), RawTherapee calculates an optimum value based on flat regions in the image.\nIf there is no flat region in the image or the image is too noisy, the value will be set to 0.\nTo set the value manually, uncheck the checkbox first (reasonable values depend on the image). -!TP_RAW_DUALDEMOSAICCONTRAST;Contrast threshold -!TP_RAW_IMAGENUM_SN;SN mode -!TP_RAW_IMAGENUM_TOOLTIP;Some raw files consist of several sub-images (Pentax/Sony Pixel Shift, Pentax 3-in-1 HDR, Canon Dual Pixel, Fuji EXR).\n\nWhen using any demosaicing method other than Pixel Shift, this selects which sub-image is used.\n\nWhen using the Pixel Shift demosaicing method on a Pixel Shift raw, all sub-images are used, and this selects which sub-image should be used for moving parts. -!TP_RAW_PIXELSHIFTDMETHOD;Demosaic method for motion -!TP_RAW_PIXELSHIFTEPERISO;Sensitivity -!TP_RAW_PIXELSHIFTEPERISO_TOOLTIP;The default value of 0 should work fine for base ISO.\nHigher values increase sensitivity of motion detection.\nChange in small steps and watch the motion mask while changing.\nIncrease sensitivity for underexposed or high ISO images. -!TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL;Equalize per channel -!TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL_TOOLTIP;Enabled: Equalize the RGB channels individually.\nDisabled: Use same equalization factor for all channels. -!TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a green mask showing the regions with motion. -!TP_RAW_RCD;RCD -!TP_RAW_RCDVNG4;RCD+VNG4 -!TP_RAW_XTRANS;X-Trans -!TP_RAW_XTRANSFAST;Fast X-Trans -!TP_RESIZE_ALLOW_UPSCALING;Allow Upscaling -!TP_RETINEX_CONTEDIT_MAP;Equalizer -!TP_RETINEX_GAINOFFS;Gain and Offset (brightness) -!TP_RETINEX_GAINTRANSMISSION;Gain transmission -!TP_RETINEX_GAINTRANSMISSION_TOOLTIP;Amplify or reduce the transmission map to achieve the desired luminance.\nThe x-axis is the transmission.\nThe y-axis is the gain. -!TP_RETINEX_MAP;Method -!TP_SHARPENING_BLUR;Blur radius -!TP_SHARPENING_CONTRAST;Contrast threshold -!TP_SHARPENING_ITERCHECK;Auto limit iterations -!TP_SHARPENING_RADIUS_BOOST;Corner radius boost -!TP_SHARPENMICRO_CONTRAST;Contrast threshold -!TP_SOFTLIGHT_LABEL;Soft Light -!TP_SOFTLIGHT_STRENGTH;Strength -!TP_TM_FATTAL_AMOUNT;Amount -!TP_TM_FATTAL_ANCHOR;Anchor -!TP_TM_FATTAL_LABEL;Dynamic Range Compression -!TP_TM_FATTAL_THRESHOLD;Detail -!TP_WAVELET_CB_TOOLTIP;For strong values product color-toning by combining it or not with levels decomposition 'toning'\nFor low values you can change the white balance of the background (sky, ...) without changing that of the front plane, generally more contrasted -!TP_WBALANCE_PICKER;Pick +ADJUSTER_RESET_TO_DEFAULT;Klik - terug naar standaardwaarde.\nCtrl+klik - terug naar laatst opgeslagen waarde. +CURVEEDITOR_CATMULLROM;Flexibel +DONT_SHOW_AGAIN;Dit bericht niet meer tonen +DYNPROFILEEDITOR_IMGTYPE_ANY;Alles +DYNPROFILEEDITOR_IMGTYPE_HDR;HDR +DYNPROFILEEDITOR_IMGTYPE_PS;Pixel Shift +DYNPROFILEEDITOR_IMGTYPE_STD;Standaard +EXIFFILTER_IMAGETYPE;Type afbeelding +EXIFPANEL_SHOWALL;Toon alles +FILEBROWSER_BROWSEPATHBUTTONHINT;Klik om de opgegeven map te laden, en het zoekfilter opnieuw toe te passen. +FILEBROWSER_CACHECLEARFROMFULL;Wis alles inclusief opgeslagen profielen +FILEBROWSER_CACHECLEARFROMPARTIAL;Wis alles behalve opgeslagen profielen +FILEBROWSER_DELETEDIALOG_ALL;Alle %1 bestanden in de prullenbak definitief verwijderen? +FILEBROWSER_DELETEDIALOG_SELECTED;Geselecteerde %1 bestanden definitief verwijderen? +FILEBROWSER_DELETEDIALOG_SELECTEDINCLPROC;Geselecteerde %1 bestanden inclusief een versie die door de verwerkingsrij is gemaakt verwijderen? +FILEBROWSER_EMPTYTRASHHINT;Alle bestanden in de prullenbak permanent verwijderen +FILEBROWSER_POPUPREMOVE;Permanent verwijderen +FILEBROWSER_POPUPREMOVEINCLPROC;Verwijder definitief, inclusief met uitvoer in de verwerkingsrij +FILEBROWSER_SHOWNOTTRASHHINT;Toon alleen niet-verwijderde afbeeldingen. +GENERAL_CURRENT;Huidig +GENERAL_HELP;Help +GENERAL_RESET;Terugzetten +GENERAL_SAVE_AS;Bewaren als... +GENERAL_SLIDER;Schuifregelaar +GIMP_PLUGIN_INFO;Welkom bij de RawTherapee GIMP plug-in!\nAls uw bewerking gereed is, sluit dan het hoofdvenster van RawTherapee en uw afbeelding wordt automatisch in GIMP geladen. +HISTOGRAM_TOOLTIP_MODE;Wissel tussen lineair, log-lineair and log-log schalen van het histogram. +HISTORY_MSG_173;NR - Detailbehoud +HISTORY_MSG_203;NR - Kleurruimte +HISTORY_MSG_235;B&W - CM - Auto +HISTORY_MSG_237;B&W - CM +HISTORY_MSG_256;NR - Mediaan - Type +HISTORY_MSG_273;CT - Kleurbalans SMH +HISTORY_MSG_297;NR - Modus +HISTORY_MSG_392;W - Overblijvend - Kleurbalans +HISTORY_MSG_441;Retinex - Toename transmissie +HISTORY_MSG_475;PS - Kanaalbalans +HISTORY_MSG_476;CAM02 - Temp uit +HISTORY_MSG_477;CAM02 - Groen uit +HISTORY_MSG_478;CAM02 - Yb uit +HISTORY_MSG_479;CAM02 - CAT02 aanpassing uit +HISTORY_MSG_480;CAM02 - Automatische CAT02 uit +HISTORY_MSG_481;CAM02 - Temp scène +HISTORY_MSG_482;CAM02 - Groen scène +HISTORY_MSG_483;CAM02 - Yb scène +HISTORY_MSG_484;CAM02 - Auto Yb scène +HISTORY_MSG_485;Lenscorrectie +HISTORY_MSG_486;Lenscorrectie - Camera +HISTORY_MSG_487;Lenscorrectie - Lens +HISTORY_MSG_488;Compressie Dynamisch Bereik +HISTORY_MSG_489;DRC - Detail +HISTORY_MSG_490;DRC - Hoeveelheid +HISTORY_MSG_491;Witbalans +HISTORY_MSG_492;RGB Curven +HISTORY_MSG_493;L*a*b* Adjustments +HISTORY_MSG_494;verscherpen +HISTORY_MSG_CLAMPOOG;Kleuren afkappen die buiten het gamma vallen +HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Kleurcorrectie +HISTORY_MSG_COLORTONING_LABREGION_AB;CT - Kleurcorrectie +HISTORY_MSG_COLORTONING_LABREGION_CHANNEL;CT - Kanaal +HISTORY_MSG_COLORTONING_LABREGION_CHROMATICITYMASK;CT - gebied C masker +HISTORY_MSG_COLORTONING_LABREGION_HUEMASK;CT - H masker +HISTORY_MSG_COLORTONING_LABREGION_LIGHTNESS;CT - Licht +HISTORY_MSG_COLORTONING_LABREGION_LIGHTNESSMASK;CT - L masker +HISTORY_MSG_COLORTONING_LABREGION_LIST;CT - Lijst +HISTORY_MSG_COLORTONING_LABREGION_MASKBLUR;CT - verzachtingsmasker gebied +HISTORY_MSG_COLORTONING_LABREGION_OFFSET;CT - offset gebied +HISTORY_MSG_COLORTONING_LABREGION_POWER;CT - sterkte gebied +HISTORY_MSG_COLORTONING_LABREGION_SATURATION;CT - Verzadiging +HISTORY_MSG_COLORTONING_LABREGION_SHOWMASK;CT - toon gebiedsmasker +HISTORY_MSG_COLORTONING_LABREGION_SLOPE;CT - hellingsgebied +HISTORY_MSG_DEHAZE_DEPTH;Nevelvermindering - Diepte +HISTORY_MSG_DEHAZE_ENABLED;Nevelvermindering +HISTORY_MSG_DEHAZE_LUMINANCE;Nevelvermindering - Alleen Luminantie +HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;Nevelvermindering - Toon dieptemap +HISTORY_MSG_DEHAZE_STRENGTH;Nevelvermindering - Sterkte +HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual-demozaïek - auto-drempel +HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual-demozaïek - Contrastdrempel +HISTORY_MSG_FILMNEGATIVE_ENABLED;Filmnegatief +HISTORY_MSG_FILMNEGATIVE_VALUES;Filmnegatief waarden +HISTORY_MSG_HISTMATCHING;Auto-matched tooncurve +HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Uitvoer - Primaries +HISTORY_MSG_ICM_OUTPUT_TEMP;Uitvoer - ICC-v4 illuminant D +HISTORY_MSG_ICM_OUTPUT_TYPE;Uitvoer - Type +HISTORY_MSG_ICM_WORKING_GAMMA;Working - Gamma +HISTORY_MSG_ICM_WORKING_SLOPE;Working - Helling +HISTORY_MSG_ICM_WORKING_TRC_METHOD;Working - TRC methode +HISTORY_MSG_LOCALCONTRAST_AMOUNT;Local Contrast - Hoeveelheid +HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Donker +HISTORY_MSG_LOCALCONTRAST_ENABLED;Lokaal Contrast +HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Lokaal Contrast - Licht +HISTORY_MSG_LOCALCONTRAST_RADIUS;Lokaal Contrast - Radius +HISTORY_MSG_METADATA_MODE;Metadata kopieermodus +HISTORY_MSG_MICROCONTRAST_CONTRAST;Microcontrast - Contrastdrempel +HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto drempel +HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - Auto radius +HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limiet herhalingen +HISTORY_MSG_PDSHARPEN_CONTRAST;CS - Contrastdrempel +HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - Herhalingen +HISTORY_MSG_PDSHARPEN_RADIUS;CS - Radius +HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - Toename hoekradius +HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - Demozaïekmethode voor beweging +HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;lijnruisfilter richting +HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAF lijnfilter +HISTORY_MSG_PRSHARPEN_CONTRAST;PRS - Contrastdrempel +HISTORY_MSG_RAWCACORR_AUTOIT;Raw CA Correctie - Herhalingen +HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw CA Correctie - Vermijd kleurverschuiving +HISTORY_MSG_RAW_BORDER;Raw rand +HISTORY_MSG_RESIZE_ALLOWUPSCALING;Schalen - sta vergroting toe +HISTORY_MSG_SHARPENING_BLUR;Verscherpen - Vervagingsradius +HISTORY_MSG_SHARPENING_CONTRAST;Verscherpen - Contrastdrempel +HISTORY_MSG_SH_COLORSPACE;S/H - Kleurruimte +HISTORY_MSG_SOFTLIGHT_ENABLED;Zacht licht +HISTORY_MSG_SOFTLIGHT_STRENGTH;Zacht licht - Sterkte +HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anker +HISTORY_MSG_TRANS_Method;Geometrie - Methode +ICCPROFCREATOR_COPYRIGHT;Copyright: +ICCPROFCREATOR_COPYRIGHT_RESET_TOOLTIP;Zet terug naar standaard copyright, verleend aan "RawTherapee, CC0" +ICCPROFCREATOR_CUSTOM;Handmatig +ICCPROFCREATOR_DESCRIPTION;Beschriiving: +ICCPROFCREATOR_DESCRIPTION_ADDPARAM;Voeg gamma- en hellingwaarden toe aan de beschrijving +ICCPROFCREATOR_DESCRIPTION_TOOLTIP;Laat leeg voor de standaard beschrijving. +ICCPROFCREATOR_GAMMA;Gamma +ICCPROFCREATOR_ICCVERSION;ICC versie: +ICCPROFCREATOR_ILL;Illuminant: +ICCPROFCREATOR_ILL_41;D41 +ICCPROFCREATOR_ILL_50;D50 +ICCPROFCREATOR_ILL_55;D55 +ICCPROFCREATOR_ILL_60;D60 +ICCPROFCREATOR_ILL_65;D65 +ICCPROFCREATOR_ILL_80;D80 +ICCPROFCREATOR_ILL_DEF;Standaard +ICCPROFCREATOR_ILL_INC;StdA 2856K +ICCPROFCREATOR_ILL_TOOLTIP;U kunt alleen de illuminant instellen voor ICC v4-profielen. +ICCPROFCREATOR_PRIMARIES;Primaire kleuren: +ICCPROFCREATOR_PRIM_ACESP0;ACES AP0 +ICCPROFCREATOR_PRIM_ACESP1;ACES AP1 +ICCPROFCREATOR_PRIM_ADOBE;Adobe RGB (1998) +ICCPROFCREATOR_PRIM_BEST;BestRGB +ICCPROFCREATOR_PRIM_BETA;BetaRGB +ICCPROFCREATOR_PRIM_BLUX;Blauw X +ICCPROFCREATOR_PRIM_BLUY;Blauw Y +ICCPROFCREATOR_PRIM_BRUCE;BruceRGB +ICCPROFCREATOR_PRIM_GREX;Groen X +ICCPROFCREATOR_PRIM_GREY;Groen Y +ICCPROFCREATOR_PRIM_PROPH;Prophoto +ICCPROFCREATOR_PRIM_REC2020;Rec2020 +ICCPROFCREATOR_PRIM_REDX;Rood X +ICCPROFCREATOR_PRIM_REDY;Rood Y +ICCPROFCREATOR_PRIM_SRGB;sRGB +ICCPROFCREATOR_PRIM_TOOLTIP;U kunt alleen aangepaste primaries voor ICC v4-profielen instellen. +ICCPROFCREATOR_PRIM_WIDEG;Widegamut +ICCPROFCREATOR_PROF_V2;ICC v2 +ICCPROFCREATOR_PROF_V4;ICC v4 +ICCPROFCREATOR_SAVEDIALOG_TITLE;Bewaar ICC profiel als... +ICCPROFCREATOR_SLOPE;Helling +ICCPROFCREATOR_TRC_PRESET;Toonresponscurve: +MAIN_BUTTON_ICCPROFCREATOR;ICC Profielmaker +MAIN_FRAME_PLACES_DEL;Verwijderen +MAIN_MSG_TOOMANYOPENEDITORS;Teveel open fotobewerkers.\nSluit er een om verder te kunnen. +MAIN_TAB_ADVANCED;Geavanceerd +MAIN_TAB_ADVANCED_TOOLTIP;Sneltoets: Alt-a +MAIN_TAB_FAVORITES;Favorieten +MAIN_TAB_FAVORITES_TOOLTIP;Sneltoets: Alt-u +MAIN_TOOLTIP_BACKCOLOR3;Achtergrondkleur van het voorbeeld: middelgrijs\nSneltoets: 9 +MAIN_TOOLTIP_PREVIEWSHARPMASK;Bekijk het scherptecontrastmasker.\nSneltoets: p\nWerkt alleen als verscherping is geactiveerd en het zoomniveau >= 100%. +OPTIONS_BUNDLED_MISSING;Het gebundelde profiel "%1" werd niet gevonden!\n\nUw installatie kan beschadigd zijn.\n\nDaarom worden interne standaardwaarden gebruikt. +OPTIONS_DEFIMG_MISSING;Het standaardprofiel voor niet-raw- foto's werd niet gevonden of is niet ingesteld.\n\nControleer de profielenmap, het kan ontbreken of beschadigd zijn.\n\n"%1" wordt daarom gebruikt. +OPTIONS_DEFRAW_MISSING;Het standaardprofiel voor raw-foto's werd niet gevonden of is niet ingesteld.\n\nControleer de profielenmap, het kan ontbreken of beschadigd zijn.\n\n"%1" wordt daarom gebruikt. +PARTIALPASTE_ADVANCEDGROUP;Geavanceerd +PARTIALPASTE_DEHAZE;Nevel verminderen +PARTIALPASTE_FILMNEGATIVE;Film Negatief +PARTIALPASTE_LOCALCONTRAST;Lokaal contrast +PARTIALPASTE_METADATA;Metadata modus +PARTIALPASTE_PREPROCESS_PDAFLINESFILTER;PDAF lijnfilter +PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT;CA vermijd kleurverschuiving +PARTIALPASTE_RAW_BORDER;Raw rand +PARTIALPASTE_SOFTLIGHT;Zacht licht +PARTIALPASTE_TM_FATTAL;Compressie dynamisch bereik +PREFERENCES_APPEARANCE;Uiterlijk +PREFERENCES_APPEARANCE_COLORPICKERFONT;Lettertype kleurenkiezer +PREFERENCES_APPEARANCE_CROPMASKCOLOR;Kleur bijsnijdmasker +PREFERENCES_APPEARANCE_MAINFONT;Standaard lettertype +PREFERENCES_APPEARANCE_PSEUDOHIDPI;Pseudo-HiDPI modus +PREFERENCES_APPEARANCE_THEME;Thema +PREFERENCES_AUTOSAVE_TP_OPEN;Bewaar positie gereedschappen (open/dicht) bij afsluiten +PREFERENCES_CACHECLEAR;Wissen +PREFERENCES_CACHECLEAR_ALL;Wis alle bestanden in de cache: +PREFERENCES_CACHECLEAR_ALLBUTPROFILES;Wis alle bestanden in de cache behalve verwerkingsprofielen: +PREFERENCES_CACHECLEAR_ONLYPROFILES;Wis alleen verwerkingsprofielen in de cache: +PREFERENCES_CACHECLEAR_SAFETY;Alleen bestanden in de cache worden gewist. Verwerkingsprofielen van de oorspronkelijke afbeeldingen blijven ongemoeid. +PREFERENCES_CHUNKSIZES;Tegels per thread +PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE demosaïek +PREFERENCES_CHUNKSIZE_RAW_CA;Raw CA correctie +PREFERENCES_CHUNKSIZE_RAW_RCD;RCD demosaïek +PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans demosaïek +PREFERENCES_CHUNKSIZE_RGB;RGB verwerking +PREFERENCES_CROP;Uitsnijden +PREFERENCES_CROP_AUTO_FIT;Automatisch zoomen tot de uitsnede +PREFERENCES_CROP_GUIDES;Getoonde hulplijnen als uitsnede niet bewerkt wordt +PREFERENCES_CROP_GUIDES_FRAME;Frame +PREFERENCES_CROP_GUIDES_FULL;Origineel +PREFERENCES_CROP_GUIDES_NONE;Geen +PREFERENCES_DIRECTORIES;Mappen +PREFERENCES_EDITORCMDLINE;Aangepaste opdrachtregel +PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compacte gereedschapsbalken in bestandsnavigator +PREFERENCES_LANG;Taal +PREFERENCES_PERFORMANCE_MEASURE;Meting +PREFERENCES_PERFORMANCE_MEASURE_HINT;Log verwerkingstijden in de console +PREFERENCES_PERFORMANCE_THREADS;Threads +PREFERENCES_PERFORMANCE_THREADS_LABEL;Maximaal aantal threads voor ruisvermindering and Wavelet Niveaus (0 = Automatisch) +PREFERENCES_PROFILESAVEBOTH;Bewaar verwerkingsprofielen zowel in de cache als naast het invoerbestand +PREFERENCES_PROFILESAVELOCATION;Opslaglocatie profielen +PREFERENCES_SAVE_TP_OPEN_NOW;Bewaar open/dicht-status van de gereedschappen nu +PREFERENCES_TAB_PERFORMANCE;Performantie +PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;Ingesloten JPEG voorbeeld +PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Te tonen foto +PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutrale raw rendering +PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Ingesloten JPEG indien vol formaat, anders neutrale raw +PROGRESSBAR_DECODING;Decoderen... +PROGRESSBAR_GREENEQUIL;Groen blancering... +PROGRESSBAR_HLREC;Reconstructie hoge lichten... +PROGRESSBAR_HOTDEADPIXELFILTER;Hot/dead pixel filter... +PROGRESSBAR_LINEDENOISE;Lijnruis filter... +PROGRESSBAR_RAWCACORR;Raw CA correctie... +QINFO_FRAMECOUNT;%2 frames +QINFO_HDR;HDR / %2 frame(s) +QINFO_PIXELSHIFT;Pixel Shift / %2 frame(s) +QUEUE_LOCATION_TITLE;Uitvoerlocatie +QUEUE_STARTSTOP_TOOLTIP;;Start of stop de verwerking van foto's in de rij.\n\nSneltoets: Ctrl+s +SAMPLEFORMAT_0;onbekend data formaat +SAMPLEFORMAT_1;8-bit unsigned +SAMPLEFORMAT_2;16-bit unsigned +SAMPLEFORMAT_4;24-bit LogLuv +SAMPLEFORMAT_8;32-bit LogLuv +SAMPLEFORMAT_16;16-bit drijvendekomma +SAMPLEFORMAT_32;24-bit drijvendekomma +SAMPLEFORMAT_64;32-bit drijvendekomma +SAVEDLG_FILEFORMAT_FLOAT; drijvendekomma +SOFTPROOF_GAMUTCHECK_TOOLTIP;Markeer pixels waarvan de kleuren buiten het kleurgamma vallen, relatief aan:\n- het printerprofiel, indien opgegeven en soft-proofing is ingeschakeld,\n- het uitvoerprofiel, indien geen printerprofiel is gekozen en soft-proofing is ingeschakeld,\n- het beeldschermprofiel, indien soft-proofing is uitgeschakeld. +SOFTPROOF_TOOLTIP;Soft-proofing simuleert hoe een foto wordt getoond:\n- als deze wordt afgedrukt, indien een printerprofiel is opgegeven in Voorkeuren > Kleurbeheer,\n- als de foto getoond wordt op een beeldscherm dat het huidige uitvoerprofiel gebruikt en een printerprofiel niet is opgegeven. +TP_BWMIX_MIXC;Kanaal Mixer +TP_BWMIX_NEUTRAL;Terugzetten +TP_COLORAPP_ABSOLUTELUMINANCE;Absolute luminantie +TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;Bij manuele aanpassing worden waardon boven 65 aanbevolen. +TP_COLORAPP_FREE;Vrije temp+groen + CAT02 + [uitvoer] +TP_COLORAPP_MEANLUMINANCE;Gemiddelde luminantie (Yb%) +TP_COLORAPP_NEUTRAL;Terugzetten +TP_COLORAPP_NEUTRAL_TIP;Zet alle regelaars, vinkjes en curves terug naar hun standaardwaarde +TP_COLORAPP_TEMP_TOOLTIP;Zet altijd Tint=1 om een lichtbron te selecteren.\n\nA temp=2856\nD50 temp=5003\nD55 temp=5503\nD65 temp=6504\nD75 temp=7504 +TP_COLORTONING_LABGRID;L*a*b* kleurcorrectie raster +TP_COLORTONING_LABGRID_VALUES;HL: a=%1 b=%2\nS: a=%3 b=%4 +TP_COLORTONING_LABREGIONS;Kleurcorrectie gebieden +TP_COLORTONING_LABREGION_ABVALUES;a=%1 b=%2 +TP_COLORTONING_LABREGION_CHANNEL;Kanaal +TP_COLORTONING_LABREGION_CHANNEL_ALL;Alle +TP_COLORTONING_LABREGION_CHANNEL_B;Blauw +TP_COLORTONING_LABREGION_CHANNEL_G;Groen +TP_COLORTONING_LABREGION_CHANNEL_R;Rood +TP_COLORTONING_LABREGION_CHROMATICITYMASK;C +TP_COLORTONING_LABREGION_HUEMASK;H +TP_COLORTONING_LABREGION_LIGHTNESS;Helderheid(L) +TP_COLORTONING_LABREGION_LIGHTNESSMASK;L +TP_COLORTONING_LABREGION_LIST_TITLE;Correctie +TP_COLORTONING_LABREGION_MASK;Masker +TP_COLORTONING_LABREGION_MASKBLUR;Verzachtingsmasker +TP_COLORTONING_LABREGION_OFFSET;Offset +TP_COLORTONING_LABREGION_POWER;Kracht +TP_COLORTONING_LABREGION_SATURATION;Verzadiging +TP_COLORTONING_LABREGION_SHOWMASK;Toon masker +TP_COLORTONING_LABREGION_SLOPE;Helling +TP_CROP_PPI;PPI +TP_CROP_RESETCROP;Terugzetten +TP_CROP_SELECTCROP;Selecteer +TP_DEHAZE_DEPTH;Diepte +TP_DEHAZE_LABEL;Nevel vermindering +TP_DEHAZE_LUMINANCE;Luminantie alleen +TP_DEHAZE_SHOW_DEPTH_MAP;Toon de dieptemap +TP_DEHAZE_STRENGTH;Sterkte +TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Verhoog (vermenigvuldig) de waarde van alle chrominantie regelaars.\nDeze curve regelt de sterkte van de chromatische ruisvermindering als een functie van de chromaticiteit, om bijvoorbeeld het effect te vergroten in gebieden met lage verzadiging en te verminderen in deze met lage verzadiging. +TP_DIRPYRDENOISE_LABEL;Ruisvermindering +TP_EXPOSURE_CLAMPOOG;Knip kleuren die buiten het gamma vallen +TP_EXPOSURE_HISTMATCHING;Automatische Tooncurve +TP_EXPOSURE_HISTMATCHING_TOOLTIP;Pas automatisch de curves en schuifregelaars aan (behalve belichtingscompensatie) om overeen te komen met de ingesloten JPEG miniatuur. +TP_FILMNEGATIVE_BLUE;Blauw verhouding +TP_FILMNEGATIVE_GREEN;Referentie exponent (contrast) +TP_FILMNEGATIVE_GUESS_TOOLTIP;Zet automatisch de rood/groen verhouding door 2 gebieden te kiezen met een neutrale tint (geen kleur) in het origineel. De gebieden moeten verschillen in helderheid. Zet de witbalans nadien. +TP_FILMNEGATIVE_LABEL;Film Negatief +TP_FILMNEGATIVE_PICK;Kies neutrale punten +TP_FILMNEGATIVE_RED;Rood verhouding +TP_ICM_WORKING_TRC;Tooncurve: +TP_ICM_WORKING_TRC_CUSTOM;Gebruiker gedefinieerd +TP_ICM_WORKING_TRC_GAMMA;Gamma +TP_ICM_WORKING_TRC_NONE;Geen +TP_ICM_WORKING_TRC_SLOPE;Helling +TP_ICM_WORKING_TRC_TOOLTIP;Enkel voor ingebouwde profielen. +TP_LENSGEOM_LIN;Lineair +TP_LENSGEOM_LOG;Logarithmisch +TP_LENSPROFILE_CORRECTION_AUTOMATCH;Automatische selectie +TP_LENSPROFILE_CORRECTION_LCPFILE;LCP bestand +TP_LENSPROFILE_CORRECTION_MANUAL;Manuele selectie +TP_LENSPROFILE_LENS_WARNING;Waarschuwing: de gebruikte lens profiel crop factor komt niet overeen met de camera crop factor, de resultaten kunnen verkeerd zijn. +TP_LENSPROFILE_MODE_HEADER;Lens Profiel +TP_LENSPROFILE_USE_CA;Chromatische afwijking +TP_LENSPROFILE_USE_GEOMETRIC;Geometrische vervorming +TP_LENSPROFILE_USE_HEADER;Lenscorrecties +TP_LENSPROFILE_USE_VIGNETTING;Vignettering +TP_LOCALCONTRAST_AMOUNT;Hoeveelheid +TP_LOCALCONTRAST_DARKNESS;Donker niveau +TP_LOCALCONTRAST_LABEL;Lokaal Contrast +TP_LOCALCONTRAST_LIGHTNESS;helderheidsniveau +TP_LOCALCONTRAST_RADIUS;Straal +TP_METADATA_EDIT;Pas wijzigingen toe +TP_METADATA_MODE;Metadata kopieermodus +TP_METADATA_STRIP;Strip alle metadata +TP_METADATA_TUNNEL;Kopieer ongewijzigd +TP_PDSHARPENING_LABEL;Verscherpen +TP_PREPROCESS_LINEDENOISE_DIRECTION;Richting +TP_PREPROCESS_LINEDENOISE_DIRECTION_BOTH;Beide +TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL;Horizontaal +TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;Horizontaal enkel op PDAF-rijen +TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Verticaal +TP_PREPROCESS_PDAFLINESFILTER;PDAF lijnfilter +TP_RAWCACORR_AUTOIT;Herhalingen +TP_RAWCACORR_AUTOIT_TOOLTIP;Deze schuif is alleen actief als Automatische CA-correctie is aangevinkt.\nAuto-correctie werkt conservatief en corrigeert meestal niet alle chromatische aberratie.\nOm de resterende CA te corrigeren, kunt u dit proces tot vijf keer herhalen.\nElke herhaling vermindert de CA van de vorige herhaling, maar gaat wel ten koste van extra rekentijd. +TP_RAWCACORR_AVOIDCOLORSHIFT;Vermijd kleurverschuiving +TP_RAW_2PASS;1-pass+snel +TP_RAW_4PASS;3-pass+snel +TP_RAW_AMAZEVNG4;AMaZE+VNG4 +TP_RAW_BORDER;Rand +TP_RAW_DCBVNG4;DCB+VNG4 +TP_RAW_DUALDEMOSAICAUTOCONTRAST;Auto drempel +TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;Als checkbox is aangevinkt (aanbevolen), berekent RT een optimale waarde gebaseerd op vlakke gebieden in de foto.\nIndien die niet gevonden worden of de foto bevat veel ruis, wordt de waarde op 0 gezet.\nOm de waarde handmatig in te voeren moet u eerst de checkbox uitvinken (redelijke waarden zijn afhankelijk van het soort foto). +TP_RAW_DUALDEMOSAICCONTRAST;Contrast drempel +TP_RAW_IMAGENUM_SN;SN modus +TP_RAW_IMAGENUM_TOOLTIP;Sommige raw bestanden bestaan uit verschillende sub-afbeeldingen (Pentax/Sony Pixel Shift, Pentax 3-in-1 HDR, Canon Dual Pixel, Fuji EXR).\n\Als een andere demozaïek methode dan Pixel Shift gebruikt wordt, selecteert dit de gebruikte sub-afbeelding.\n\nBij gebruik van de Pixel Shift demozaïek methode op een Pixel Shift raw, worden alle sub-afbeeldingen gebruikt, and dit selecteert de subafbeeldijg die gebruikt wordt voor bewegende moving gebieden. +TP_RAW_PIXELSHIFTDMETHOD;Demozaïek voor beweging +TP_RAW_PIXELSHIFTEPERISO;Gevoeligheid +TP_RAW_PIXELSHIFTEPERISO_TOOLTIP;De standaardwaarde 0 werkt goed voor lage ISO-waarden.\nHogere waarden vergroten de gevoeligheid van bewegingsdetectie.\nWijzig in kleine stappen en controleer het bewegingsmasker.\nVerhoog gevoeligheid voor onderbelichte foto's of foto's met hoge ISO-waarden. +TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL;Balanceer per kanaal +TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL_TOOLTIP;Ingeschakeld: Balanceer elk RGB kanaal afzonderlijk.\nUitgeschakeld: Balanceer alle kanalen evenveel. +TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Toont de foto met een groen masker dat de bewegingsgebieden toont. +TP_RAW_RCD;RCD +TP_RAW_RCDVNG4;RCD+VNG4 +TP_RAW_XTRANS;X-Trans +TP_RAW_XTRANSFAST;Snelle X-Trans +TP_RESIZE_ALLOW_UPSCALING;Sta opschalen toe +TP_RETINEX_CONTEDIT_MAP;Equalizer +TP_RETINEX_GAINOFFS;Versterking en Offset (helderheid) +TP_RETINEX_GAINTRANSMISSION;Transmissie versterking +TP_RETINEX_GAINTRANSMISSION_TOOLTIP;Versterk of verzwak de transmssiemap om de gewenste luminantie te bekomen.\nThe x-as is the transmissie.\nThe y-as is the versterking. +TP_RETINEX_MAP;Methode +TP_SHARPENING_BLUR;Vervagen straal +TP_SHARPENING_CONTRAST;Contrast drempel +TP_SHARPENING_ITERCHECK;Automatische limiet herhalingen +TP_SHARPENING_RADIUS_BOOST;Straalvergroting +TP_SHARPENMICRO_CONTRAST;Contrast drempel +TP_SOFTLIGHT_LABEL;Zacht licht +TP_SOFTLIGHT_STRENGTH;Sterkte +TP_TM_FATTAL_AMOUNT;Hoeveelheid +TP_TM_FATTAL_ANCHOR;Anker +TP_TM_FATTAL_LABEL;Dynamisch bereik compressie +TP_TM_FATTAL_THRESHOLD;Detail +TP_WAVELET_CB_TOOLTIP;Voor hoge waarden: kleurcorrectie door al of niet te combineren met niveau decompositie 'toning'\nVoor lage waarden de witbalans van de achtergrond (hemel, ...) wijzigen zonder die van de voorgrond, meestal meer contrastrijk +TP_WBALANCE_PICKER;Kies diff --git a/rtdata/languages/default b/rtdata/languages/default index 6589c3a43..f89c13cb5 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -22,7 +22,7 @@ CURVEEDITOR_EDITPOINT_HINT;Enable edition of node in/out values.\n\nRight-click CURVEEDITOR_HIGHLIGHTS;Highlights CURVEEDITOR_LIGHTS;Lights CURVEEDITOR_LINEAR;Linear -CURVEEDITOR_LOADDLGLABEL;Load curve... +CURVEEDITOR_LOADDLGLABEL;Load curve CURVEEDITOR_MINMAXCPOINTS;Equalizer CURVEEDITOR_NURBS;Control cage CURVEEDITOR_PARAMETRIC;Parametric @@ -567,10 +567,10 @@ HISTORY_MSG_314;W - Gamut - Reduce artifacts HISTORY_MSG_315;W - Residual - Contrast HISTORY_MSG_316;W - Gamut - Skin tar/prot HISTORY_MSG_317;W - Gamut - Skin hue -HISTORY_MSG_318;W - Contrast - Highlight levels -HISTORY_MSG_319;W - Contrast - Highlight range -HISTORY_MSG_320;W - Contrast - Shadow range -HISTORY_MSG_321;W - Contrast - Shadow levels +HISTORY_MSG_318;W - Contrast - Fine levels +HISTORY_MSG_319;W - Contrast - Fine range +HISTORY_MSG_320;W - Contrast - Coarse range +HISTORY_MSG_321;W - Contrast - Coarse levels HISTORY_MSG_322;W - Gamut - Avoid color shift HISTORY_MSG_323;W - ES - Local contrast HISTORY_MSG_324;W - Chroma - Pastel @@ -694,21 +694,37 @@ HISTORY_MSG_441;Retinex - Gain transmission HISTORY_MSG_442;Retinex - Scale HISTORY_MSG_443;Output black point compensation HISTORY_MSG_444;WB - Temp bias -HISTORY_MSG_445;Raw sub-image -HISTORY_MSG_449;PS - ISO adaption -HISTORY_MSG_452;PS - Show motion -HISTORY_MSG_453;PS - Show mask only -HISTORY_MSG_457;PS - Check red/blue -HISTORY_MSG_462;PS - Check green -HISTORY_MSG_464;PS - Blur motion mask -HISTORY_MSG_465;PS - Blur radius -HISTORY_MSG_468;PS - Fill holes -HISTORY_MSG_469;PS - Median -HISTORY_MSG_471;PS - Motion correction -HISTORY_MSG_472;PS - Smooth transitions -HISTORY_MSG_473;PS - Use LMMSE -HISTORY_MSG_474;PS - Equalize -HISTORY_MSG_475;PS - Equalize channel +HISTORY_MSG_445;Raw Sub-Image +HISTORY_MSG_446;EvPixelShiftMotion +HISTORY_MSG_447;EvPixelShiftMotionCorrection +HISTORY_MSG_448;EvPixelShiftStddevFactorGreen +HISTORY_MSG_449;PS ISO adaption +HISTORY_MSG_450;EvPixelShiftNreadIso +HISTORY_MSG_451;EvPixelShiftPrnu +HISTORY_MSG_452;PS Show motion +HISTORY_MSG_453;PS Show mask only +HISTORY_MSG_454;EvPixelShiftAutomatic +HISTORY_MSG_455;EvPixelShiftNonGreenHorizontal +HISTORY_MSG_456;EvPixelShiftNonGreenVertical +HISTORY_MSG_457;PS Check red/blue +HISTORY_MSG_458;EvPixelShiftStddevFactorRed +HISTORY_MSG_459;EvPixelShiftStddevFactorBlue +HISTORY_MSG_460;EvPixelShiftGreenAmaze +HISTORY_MSG_461;EvPixelShiftNonGreenAmaze +HISTORY_MSG_462;PS Check green +HISTORY_MSG_463;EvPixelShiftRedBlueWeight +HISTORY_MSG_464;PS Blur motion mask +HISTORY_MSG_465;PS Blur radius +HISTORY_MSG_466;EvPixelShiftSum +HISTORY_MSG_467;EvPixelShiftExp0 +HISTORY_MSG_468;PS Fill holes +HISTORY_MSG_469;PS Median +HISTORY_MSG_470;EvPixelShiftMedian3 +HISTORY_MSG_471;PS Motion correction +HISTORY_MSG_472;PS Smooth transitions +HISTORY_MSG_473;PS Use lmmse +HISTORY_MSG_474;PS Equalize +HISTORY_MSG_475;PS Equalize channel HISTORY_MSG_476;CAM02 - Temp out HISTORY_MSG_477;CAM02 - Green out HISTORY_MSG_478;CAM02 - Yb out @@ -726,8 +742,429 @@ HISTORY_MSG_489;DRC - Detail HISTORY_MSG_490;DRC - Amount HISTORY_MSG_491;White Balance HISTORY_MSG_492;RGB Curves -HISTORY_MSG_493;L*a*b* Adjustments +HISTORY_MSG_493;Local Adjustments HISTORY_MSG_494;Capture Sharpening +HISTORY_MSG_496;Local Spot deleted +HISTORY_MSG_497;Local Spot selected +HISTORY_MSG_498;Local Spot name +HISTORY_MSG_499;Local Spot visibility +HISTORY_MSG_500;Local Spot shape +HISTORY_MSG_501;Local Spot method +HISTORY_MSG_502;Local Spot shape method +HISTORY_MSG_503;Local Spot locX +HISTORY_MSG_504;Local Spot locXL +HISTORY_MSG_505;Local Spot locY +HISTORY_MSG_506;Local Spot locYT +HISTORY_MSG_507;Local Spot center +HISTORY_MSG_508;Local Spot circrad +HISTORY_MSG_509;Local Spot quality method +HISTORY_MSG_510;Local Spot transition +HISTORY_MSG_511;Local Spot thresh +HISTORY_MSG_512;Local Spot ΔE -weakening +HISTORY_MSG_513;Local Spot scope +HISTORY_MSG_514;Local Spot structure +HISTORY_MSG_515;Local Adjustments +HISTORY_MSG_516;Local - Color and light +HISTORY_MSG_517;Local - Enable super +HISTORY_MSG_518;Local - Lightness +HISTORY_MSG_519;Local - Contrast +HISTORY_MSG_520;Local - Chrominance +HISTORY_MSG_521;Local - Scope +HISTORY_MSG_522;Local - curve method +HISTORY_MSG_523;Local - LL Curve +HISTORY_MSG_524;Local - CC curve +HISTORY_MSG_525;Local - LH Curve +HISTORY_MSG_526;Local - H curve +HISTORY_MSG_527;Local - Color Inverse +HISTORY_MSG_528;Local - Exposure +HISTORY_MSG_529;Local - Exp Compensation +HISTORY_MSG_530;Local - Exp Hlcompr +HISTORY_MSG_531;Local - Exp hlcomprthresh +HISTORY_MSG_532;Local - Exp black +HISTORY_MSG_533;Local - Exp Shcompr +HISTORY_MSG_534;Local - Warm Cool +HISTORY_MSG_535;Local - Exp Scope +HISTORY_MSG_536;Local - Exp Contrast curve +HISTORY_MSG_537;Local - Vibrance +HISTORY_MSG_538;Local - Vib Saturated +HISTORY_MSG_539;Local - Vib Pastel +HISTORY_MSG_540;Local - Vib Threshold +HISTORY_MSG_541;Local - Vib Protect skin tones +HISTORY_MSG_542;Local - Vib avoid colorshift +HISTORY_MSG_543;Local - Vib link +HISTORY_MSG_544;Local - Vib Scope +HISTORY_MSG_545;Local - Vib H curve +HISTORY_MSG_546;Local - Blur and noise +HISTORY_MSG_547;Local - Radius +HISTORY_MSG_548;Local - Noise +HISTORY_MSG_549;Local - Blur scope +HISTORY_MSG_550;Local - Blur method +HISTORY_MSG_551;Local - Blur Luminance only +HISTORY_MSG_552;Local - Tone mapping +HISTORY_MSG_553;Local - TM compression strength +HISTORY_MSG_554;Local - TM gamma +HISTORY_MSG_555;Local - TM edge stopping +HISTORY_MSG_556;Local - TM scale +HISTORY_MSG_557;Local - TM Reweighting +HISTORY_MSG_558;Local - TM scope +HISTORY_MSG_559;Local - Retinex +HISTORY_MSG_560;Local - Retinex method +HISTORY_MSG_561;Local - Retinex strength +HISTORY_MSG_562;Local - Retinex chroma +HISTORY_MSG_563;Local - Retinex radius +HISTORY_MSG_564;Local - Retinex contrast +HISTORY_MSG_565;Local - scope +HISTORY_MSG_566;Local - Retinex Gain curve +HISTORY_MSG_567;Local - Retinex Inverse +HISTORY_MSG_568;Local - Sharpening +HISTORY_MSG_569;Local - Sh Radius +HISTORY_MSG_570;Local - Sh Amount +HISTORY_MSG_571;Local - Sh Damping +HISTORY_MSG_572;Local - Sh Iterations +HISTORY_MSG_573;Local - Sh Scope +HISTORY_MSG_574;Local - Sh Inverse +HISTORY_MSG_575;Local - CBDL +HISTORY_MSG_576;Local - cbdl mult +HISTORY_MSG_577;Local - cbdl chroma +HISTORY_MSG_578;Local - cbdl threshold +HISTORY_MSG_579;Local - cbdl scope +HISTORY_MSG_580;Local - Denoise +HISTORY_MSG_581;Local - deNoise lum f 1 +HISTORY_MSG_582;Local - deNoise lum c +HISTORY_MSG_583;Local - deNoise lum detail +HISTORY_MSG_584;Local - deNoise Equalizer white-black +HISTORY_MSG_585;Local - deNoise chro f +HISTORY_MSG_586;Local - deNoise chro c +HISTORY_MSG_587;Local - deNoise chro detail +HISTORY_MSG_588;Local - deNoise Equalizer blue-red +HISTORY_MSG_589;Local - deNoise bilateral +HISTORY_MSG_590;Local - deNoise Scope +HISTORY_MSG_591;Local - Avoid color shift +HISTORY_MSG_592;Local - Sh Contrast +HISTORY_MSG_593;Local - Local contrast +HISTORY_MSG_594;Local - Local contrast radius +HISTORY_MSG_595;Local - Local contrast amount +HISTORY_MSG_596;Local - Local contrast darkness +HISTORY_MSG_597;Local - Local contrast lightness +HISTORY_MSG_598;Local - Local contrast scope +HISTORY_MSG_599;Local - Retinex dehaze +HISTORY_MSG_600;Local - Soft Light enable +HISTORY_MSG_601;Local - Soft Light strength +HISTORY_MSG_602;Local - Soft Light scope +HISTORY_MSG_603;Local - Sh Blur radius +HISTORY_MSG_605;Local - Mask preview choice +HISTORY_MSG_606;Local Spot selected +HISTORY_MSG_607;Local - Color Mask C +HISTORY_MSG_608;Local - Color Mask L +HISTORY_MSG_609;Local - Exp Mask C +HISTORY_MSG_610;Local - Exp Mask L +HISTORY_MSG_611;Local - Color Mask H +HISTORY_MSG_612;Local - Color Structure +HISTORY_MSG_613;Local - Exp Structure +HISTORY_MSG_614;Local - Exp Mask H +HISTORY_MSG_615;Local - Blend color +HISTORY_MSG_616;Local - Blend Exp +HISTORY_MSG_617;Local - Blur Exp +HISTORY_MSG_618;Local - Use Color Mask +HISTORY_MSG_619;Local - Use Exp Mask +HISTORY_MSG_620;Local - Blur col +HISTORY_MSG_621;Local - Exp inverse +HISTORY_MSG_622;Local - Exclude structure +HISTORY_MSG_623;Local - Exp Chroma compensation +HISTORY_MSG_624;Local - Color correction grid +HISTORY_MSG_625;Local - Color correction strength +HISTORY_MSG_626;Local - Color correction Method +HISTORY_MSG_627;Local - Shadow Highlight +HISTORY_MSG_628;Local - SH Highlight +HISTORY_MSG_629;Local - SH H tonalwidth +HISTORY_MSG_630;Local - SH Shadows +HISTORY_MSG_631;Local - SH S tonalwidth +HISTORY_MSG_632;Local - SH radius +HISTORY_MSG_633;Local - SH Scope +HISTORY_MSG_634;Local - radius color +HISTORY_MSG_635;Local - radius Exp +HISTORY_MSG_636;Local - Tool added +HISTORY_MSG_637;Local - SH Mask C +HISTORY_MSG_638;Local - SH Mask L +HISTORY_MSG_639;Local - SH Mask H +HISTORY_MSG_640;Local - SH blend +HISTORY_MSG_641;Local - Use SH mask +HISTORY_MSG_642;Local - radius SH +HISTORY_MSG_643;Local - Blur SH +HISTORY_MSG_644;Local - inverse SH +HISTORY_MSG_645;Local - balance ΔE ab-L +HISTORY_MSG_646;Local - Exp mask chroma +HISTORY_MSG_647;Local - Exp mask gamma +HISTORY_MSG_648;Local - Exp mask slope +HISTORY_MSG_649;Local - Exp soft radius +HISTORY_MSG_650;Local - Color mask chroma +HISTORY_MSG_651;Local - Color mask gamma +HISTORY_MSG_652;Local - Color mask slope +HISTORY_MSG_653;Local - SH mask chroma +HISTORY_MSG_654;Local - SH mask gamma +HISTORY_MSG_655;Local - SH mask slope +HISTORY_MSG_656;Local - Color soft radius +HISTORY_MSG_657;Local - Retinex Reduce artifacts +HISTORY_MSG_658;Local - CBDL soft radius +HISTORY_MSG_659;Local Spot transition-weakening +HISTORY_MSG_660;Local - cbdl clarity +HISTORY_MSG_661;Local - cbdl contrast residual +HISTORY_MSG_662;Local - deNoise lum f 0 +HISTORY_MSG_663;Local - deNoise lum f 2 +HISTORY_MSG_664;Local - cbdl Blur +HISTORY_MSG_665;Local - cbdl mask Blend +HISTORY_MSG_666;Local - cbdl mask radius +HISTORY_MSG_667;Local - cbdl mask chroma +HISTORY_MSG_668;Local - cbdl mask gamma +HISTORY_MSG_669;Local - cbdl mask slope +HISTORY_MSG_670;Local - cbdl mask C +HISTORY_MSG_671;Local - cbdl mask L +HISTORY_MSG_672;Local - cbdl mask CL +HISTORY_MSG_673;Local - Use cbdl mask +HISTORY_MSG_674;Local - Tool removed +HISTORY_MSG_675;Local - TM soft radius +HISTORY_MSG_676;Local Spot transition-differentiation +HISTORY_MSG_677;Local - TM amount +HISTORY_MSG_678;Local - TM saturation +HISTORY_MSG_679;Local - Retinex mask C +HISTORY_MSG_680;Local - Retinex mask L +HISTORY_MSG_681;Local - Retinex mask CL +HISTORY_MSG_682;Local - Retinex mask +HISTORY_MSG_683;Local - Retinex mask Blend +HISTORY_MSG_684;Local - Retinex mask radius +HISTORY_MSG_685;Local - Retinex mask chroma +HISTORY_MSG_686;Local - Retinex mask gamma +HISTORY_MSG_687;Local - Retinex mask slope +HISTORY_MSG_688;Local - Tool removed +HISTORY_MSG_689;Local - Retinex mask transmission map +HISTORY_MSG_690;Local - Retinex scale +HISTORY_MSG_691;Local - Retinex darkness +HISTORY_MSG_692;Local - Retinex lightness +HISTORY_MSG_693;Local - Retinex threshold +HISTORY_MSG_694;Local - Retinex Laplacian threshold +HISTORY_MSG_695;Local - Soft method +HISTORY_MSG_696;Local - Retinex Normalize +HISTORY_MSG_697;Local - TM Normalize +HISTORY_MSG_698;Local - Local contrast Fast Fourier +HISTORY_MSG_699;Local - Retinex Fast Fourier +HISTORY_MSG_701;Local - Exp Shadows +HISTORY_MSG_702;Local - Exp Method +HISTORY_MSG_703;Local - Exp Laplacian threshold +HISTORY_MSG_704;Local - Exp PDE balance +HISTORY_MSG_705;Local - Exp linearity +HISTORY_MSG_706;Local - TM mask C +HISTORY_MSG_707;Local - TM mask L +HISTORY_MSG_708;Local - TM mask CL +HISTORY_MSG_709;Local - use TM mask +HISTORY_MSG_710;Local - TM mask Blend +HISTORY_MSG_711;Local - TM mask radius +HISTORY_MSG_712;Local - TM mask chroma +HISTORY_MSG_713;Local - TM mask gamma +HISTORY_MSG_714;Local - TM mask slope +HISTORY_MSG_716;Local - Local method +HISTORY_MSG_717;Local - Local contrast +HISTORY_MSG_718;Local - Local contrast levels +HISTORY_MSG_719;Local - Local contrast residual L +HISTORY_MSG_720;Local - Blur mask C +HISTORY_MSG_721;Local - Blur mask L +HISTORY_MSG_722;Local - Blur mask CL +HISTORY_MSG_723;Local - use Blur mask +HISTORY_MSG_725;Local - Blur mask Blend +HISTORY_MSG_726;Local - Blur mask radius +HISTORY_MSG_727;Local - Blur mask chroma +HISTORY_MSG_728;Local - Blur mask gamma +HISTORY_MSG_729;Local - Blur mask slope +HISTORY_MSG_730;Local - Blur method +HISTORY_MSG_731;Local - median method +HISTORY_MSG_732;Local - median iterations +HISTORY_MSG_733;Local - soft radius +HISTORY_MSG_734;Local - detail +HISTORY_MSG_738;Local - Local contrast Merge L +HISTORY_MSG_739;Local - Local contrast Soft radius +HISTORY_MSG_740;Local - Local contrast Merge C +HISTORY_MSG_741;Local - Local contrast Residual C +HISTORY_MSG_742;Local - Exp Laplacian gamma +HISTORY_MSG_743;Local - Exp Fattal Amount +HISTORY_MSG_744;Local - Exp Fattal Detail +HISTORY_MSG_745;Local - Exp Fattal Offset +HISTORY_MSG_746;Local - Exp Fattal Sigma +HISTORY_MSG_747;Local Spot created +HISTORY_MSG_748;Local - Exp Denoise +HISTORY_MSG_749;Local - Reti Depth +HISTORY_MSG_750;Local - Reti Mode log - lin +HISTORY_MSG_751;Local - Reti Dehaze luminance +HISTORY_MSG_752;Local - Reti Offset +HISTORY_MSG_753;Local - Reti Transmission map +HISTORY_MSG_754;Local - Reti Clip +HISTORY_MSG_755;Local - TM use tm mask +HISTORY_MSG_756;Local - Exp use algo exposure mask +HISTORY_MSG_757;Local - Exp Laplacian mask +HISTORY_MSG_758;Local - Reti Laplacian mask +HISTORY_MSG_759;Local - Exp Laplacian mask +HISTORY_MSG_760;Local - Color Laplacian mask +HISTORY_MSG_761;Local - SH Laplacian mask +HISTORY_MSG_762;Local - cbdl Laplacian mask +HISTORY_MSG_763;Local - Blur Laplacian mask +HISTORY_MSG_764;Local - Solve PDE Laplacian mask +HISTORY_MSG_765;Local - deNoise Detail threshold +HISTORY_MSG_766;Local - Blur Fast Fourier +HISTORY_MSG_767;Local - Grain Iso +HISTORY_MSG_768;Local - Grain Strength +HISTORY_MSG_769;Local - Grain Scale +HISTORY_MSG_770;Local - Color Mask contrast curve +HISTORY_MSG_771;Local - Exp Mask contrast curve +HISTORY_MSG_772;Local - SH Mask contrast curve +HISTORY_MSG_773;Local - TM Mask contrast curve +HISTORY_MSG_774;Local - Reti Mask contrast curve +HISTORY_MSG_775;Local - CBDL Mask contrast curve +HISTORY_MSG_776;Local - Blur Denoise Mask contrast curve +HISTORY_MSG_777;Local - Blur Mask local contrast curve +HISTORY_MSG_778;Local - Mask highlights +HISTORY_MSG_779;Local - Color Mask local contrast curve +HISTORY_MSG_780;Local - Color Mask shadows +HISTORY_MSG_781;Local - Contrast Mask Wavelet level +HISTORY_MSG_782;Local - Blur Denoise Mask Wavelet levels +HISTORY_MSG_783;Local - Color Wavelet levels +HISTORY_MSG_784;Local - Mask ΔE +HISTORY_MSG_785;Local - Mask Scope ΔE +HISTORY_MSG_786;Local - SH method +HISTORY_MSG_787;Local - Equalizer multiplier +HISTORY_MSG_788;Local - Equalizer detail +HISTORY_MSG_789;Local - SH mask amount +HISTORY_MSG_790;Local - SH mask anchor +HISTORY_MSG_791;Local - Mask Short L curves +HISTORY_MSG_792;Local - Mask Luminance Background +HISTORY_MSG_793;Local - SH TRC gamma +HISTORY_MSG_794;Local - SH TRC slope +HISTORY_MSG_795;Local - Mask save restore image +HISTORY_MSG_796;Local - Recursive references +HISTORY_MSG_797;Local - Merge Original method +HISTORY_MSG_798;Local - Opacity +HISTORY_MSG_799;Local - Color RGB ToneCurve +HISTORY_MSG_800;Local - Color ToneCurve Method +HISTORY_MSG_801;Local - Color ToneCurve Special +HISTORY_MSG_802;Local - Contrast threshold +HISTORY_MSG_803;Local - Color Merge +HISTORY_MSG_804;Local - Color mask Structure +HISTORY_MSG_805;Local - Blur Noise mask Structure +HISTORY_MSG_806;Local - Color mask Structure as tool +HISTORY_MSG_807;Local - Blur Noise mask Structure as tool +HISTORY_MSG_808;Local - Color mask curve H(H) +HISTORY_MSG_809;Local - Vib mask curve C(C) +HISTORY_MSG_810;Local - Vib mask curve L(L) +HISTORY_MSG_811;Local - Vib mask curve LC(H) +HISTORY_MSG_813;Local - Use Vib mask +HISTORY_MSG_814;Local - Vib mask Blend +HISTORY_MSG_815;Local - Vib mask radius +HISTORY_MSG_816;Local - Vib mask chroma +HISTORY_MSG_817;Local - Vib mask gamma +HISTORY_MSG_818;Local - Vib mask slope +HISTORY_MSG_819;Local - Vib mask laplacian +HISTORY_MSG_820;Local - Vib mask contrast curve +HISTORY_MSG_821;Local - color grid background +HISTORY_MSG_822;Local - color background merge +HISTORY_MSG_823;Local - color background luminance +HISTORY_MSG_824;Local - Exp gradient mask strength +HISTORY_MSG_825;Local - Exp gradient mask angle +HISTORY_MSG_826;Local - Exp gradient strength +HISTORY_MSG_827;Local - Exp gradient angle +HISTORY_MSG_828;Local - SH gradient strength +HISTORY_MSG_829;Local - SH gradient angle +HISTORY_MSG_830;Local - Color gradient strength L +HISTORY_MSG_831;Local - Color gradient angle +HISTORY_MSG_832;Local - Color gradient strength C +HISTORY_MSG_833;Local - Gradient feather +HISTORY_MSG_834;Local - Color gradient strength H +HISTORY_MSG_835;Local - Vib gradient strength L +HISTORY_MSG_836;Local - Vib gradient angle +HISTORY_MSG_837;Local - Vib gradient strength C +HISTORY_MSG_838;Local - Vib gradient strength H +HISTORY_MSG_839;Local - Software complexity +HISTORY_MSG_840;Local - CL Curve +HISTORY_MSG_841;Local - LC curve +HISTORY_MSG_842;Local - Contrast Threshold Mask blur +HISTORY_MSG_843;Local - Radius Mask blur +HISTORY_MSG_844;Local - Color Mask fftw +HISTORY_MSG_845;Local - Encoding log +HISTORY_MSG_846;Local - Encoding auto +HISTORY_MSG_847;Local - Source Gray +HISTORY_MSG_848;Local - Source Gray auto +HISTORY_MSG_849;Local - Auto Grayon +HISTORY_MSG_850;Local - Black Ev +HISTORY_MSG_851;Local - White Ev +HISTORY_MSG_852;Local - Target Gray +HISTORY_MSG_853;Local - Local contrast +HISTORY_MSG_854;Local - Scope encoding log +HISTORY_MSG_855;Local - Entire image +HISTORY_MSG_856;Local - Base log +HISTORY_MSG_857;Local - Contrast Blur Residual +HISTORY_MSG_858;Local - Contrast Luminance only +HISTORY_MSG_859;Local - Contrast Maximum Blur levels +HISTORY_MSG_860;Local - Contrast Curve Blur levels +HISTORY_MSG_861;Local - Contrast Curve Contrast levels +HISTORY_MSG_862;Local - Contrast Sigma luminance +HISTORY_MSG_863;Local - Contrast Merge Original +HISTORY_MSG_864;Local - Directional sigma +HISTORY_MSG_865;Local - Directional delta +HISTORY_MSG_866;Local - Contrast Curve Compression +HISTORY_MSG_867;Local - Contrast Amount residual +HISTORY_MSG_868;Local - balance ΔE C-H +HISTORY_MSG_869;Local - denoise curve luminance +HISTORY_MSG_870;Local - LC mask curve LC(H) +HISTORY_MSG_871;Local - LC mask curve C(C) +HISTORY_MSG_872;Local - LC mask curve L(L) +HISTORY_MSG_873;Local - LC mask enable +HISTORY_MSG_875;Local - LC mask blend +HISTORY_MSG_876;Local - LC mask radius +HISTORY_MSG_877;Local - LC mask chroma +HISTORY_MSG_878;Local - LC mask curve contrast +HISTORY_MSG_879;Local - LC Chroma levels +HISTORY_MSG_880;Local - LC Chroma blur levels +HISTORY_MSG_881;Local - Contrast Offset Luminance +HISTORY_MSG_882;Local - Contrast Blur +HISTORY_MSG_883;Local - Contrast By Levels +HISTORY_MSG_884;Local - Contrast Dynamic Range Laplacian +HISTORY_MSG_885;Local - Contrast Dynamic Range Wavelet +HISTORY_MSG_886;Local - Contrast Wavelet Curve Compression +HISTORY_MSG_887;Local - Contrast Wavelet Compression Residual +HISTORY_MSG_888;Local - Contrast Wavelet Balance Threshold +HISTORY_MSG_889;Local - Contrast Wavelet Graduated Strength +HISTORY_MSG_890;Local - Contrast Wavelet Graduated angle +HISTORY_MSG_891;Local - Contrast Wavelet Graduated +HISTORY_MSG_892;Local - Encoding log Graduated Strength +HISTORY_MSG_893;Local - Encoding log Graduated angle +HISTORY_MSG_894;Local - Color Preview dE +HISTORY_MSG_897;Local - Contrast Wavelet ES strength +HISTORY_MSG_898;Local - Contrast Wavelet ES radius +HISTORY_MSG_899;Local - Contrast Wavelet ES detail +HISTORY_MSG_900;Local - Contrast Wavelet ES gradient +HISTORY_MSG_901;Local - Contrast Wavelet ES threshold low +HISTORY_MSG_902;Local - Contrast Wavelet ES threshold high +HISTORY_MSG_903;Local - Contrast Wavelet ES local contrast +HISTORY_MSG_904;Local - Contrast Wavelet ES first level +HISTORY_MSG_905;Local - Contrast Wavelet Edge Sharpness +HISTORY_MSG_906;Local - Contrast Wavelet ES sensitivity +HISTORY_MSG_907;Local - Contrast Wavelet ES amplification +HISTORY_MSG_908;Local - Contrast Wavelet ES neighboring +HISTORY_MSG_909;Local - Contrast Wavelet ES show +HISTORY_MSG_910;Local - Wavelet Edge performance +HISTORY_MSG_911;Local - Blur Chroma Luma +HISTORY_MSG_912;Local - Blur Guide filter strength +HISTORY_MSG_913;Local - Contrast Wavelet Sigma DR +HISTORY_MSG_914;Local - Blur Wavelet Sigma BL +HISTORY_MSG_915;Local - Edge Wavelet Sigma ED +HISTORY_MSG_916;Local - Residual wavelet shadows +HISTORY_MSG_917;Local - Residual wavelet shadows threshold +HISTORY_MSG_918;Local - Residual wavelet highlights +HISTORY_MSG_919;Local - Residual wavelet highlights threshold +HISTORY_MSG_920;Local - Wavelet sigma LC +HISTORY_MSG_921;Local - Wavelet Graduated sigma LC2 +HISTORY_MSG_922;Local - changes In Black and White +HISTORY_MSG_923;Local - Tool complexity mode +HISTORY_MSG_924;Local - Tool complexity mode +HISTORY_MSG_925;Local - Scope color tools +HISTORY_MSG_926;Local - Show mask type +HISTORY_MSG_927;Local - Shadow mask HISTORY_MSG_CAT02PRESET;Cat02 automatic preset HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction @@ -786,6 +1223,7 @@ HISTORY_MSG_PERSP_PROJ_SHIFT;Perspective - PCA HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - Demosaic method for motion HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;Line noise filter direction HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAF lines filter +HISTORY_MSG_PREPROCWB_MODE;Preprocess WB Mode HISTORY_MSG_PRSHARPEN_CONTRAST;PRS - Contrast threshold HISTORY_MSG_RAWCACORR_AUTOIT;Raw CA Correction - Iterations HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw CA Correction - Avoid color shift @@ -810,12 +1248,12 @@ HISTORY_MSG_WAVMERGEL;Merge L HISTORY_MSG_WAVRADIUS;Radius Shadows-Highlight HISTORY_MSG_WAVSCALE;Scale HISTORY_MSG_WAVSHOWMASK;Show wavelet mask -HISTORY_MSG_WAVSIGMA;Damper +HISTORY_MSG_WAVSIGMA;Attenuation Response HISTORY_MSG_WAVSOFTRAD;Soft radius clarity HISTORY_MSG_WAVSOFTRADEND;Soft radius final HISTORY_MSG_WAVUSHAMET;Clarity method HISTORY_MSG_THRESWAV;Balance threshold -HISTORY_MSG_BLUWAV;Damper +HISTORY_MSG_BLUWAV;Attenuation Response HISTORY_MSG_WAVOLDSH;Old algorithm HISTORY_MSG_WAVOFFSET;Offset HISTORY_MSG_WAVLOWTHR;Threshold low contrast @@ -823,7 +1261,13 @@ HISTORY_MSG_BLSHAPE;Blur by level HISTORY_MSG_WAVBL;Blur levels HISTORY_MSG_BLURWAV;Blur luminance HISTORY_MSG_BLURCWAV;Blur chroma -HISTORY_MSG_EDGEFFECT;Edge Damper +HISTORY_MSG_EDGEFFECT;Edge Attenuation Response +HISTORY_MSG_SIGMAFIN;Final contrast Attenuation Response +HISTORY_MSG_SIGMATON;Toning Attenuation Response +HISTORY_MSG_SIGMACOL;Chroma Attenuation Response +HISTORY_MSG_SIGMADIR;Dir Attenuation Response +HISTORY_MSG_RANGEAB;Range ab +HISTORY_MSG_PROTAB;Protection HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -963,6 +1407,8 @@ MAIN_TAB_FAVORITES_TOOLTIP;Shortcut: Alt-u MAIN_TAB_FILTER; Filter MAIN_TAB_INSPECT; Inspect MAIN_TAB_IPTC;IPTC +MAIN_TAB_LOCALLAB;Local +MAIN_TAB_LOCALLAB_TOOLTIP;Shortcut: Alt-o MAIN_TAB_METADATA;Metadata MAIN_TAB_METADATA_TOOLTIP;Shortcut: Alt-m MAIN_TAB_RAW;Raw @@ -1005,6 +1451,7 @@ NAVIGATOR_XY_NA;x: --, y: -- OPTIONS_BUNDLED_MISSING;The bundled profile "%1" could not be found!\n\nYour installation could be damaged.\n\nDefault internal values will be used instead. OPTIONS_DEFIMG_MISSING;The default profile for non-raw photos could not be found or is not set.\n\nPlease check your profiles' directory, it may be missing or damaged.\n\n"%1" will be used instead. OPTIONS_DEFRAW_MISSING;The default profile for raw photos could not be found or is not set.\n\nPlease check your profiles' directory, it may be missing or damaged.\n\n"%1" will be used instead. +PARTIALPASTE_LOCALLABGROUP;Local Adjustments Settings PARTIALPASTE_ADVANCEDGROUP;Advanced Settings PARTIALPASTE_BASICGROUP;Basic Settings PARTIALPASTE_CACORRECTION;Chromatic aberration correction @@ -1045,6 +1492,8 @@ PARTIALPASTE_IMPULSEDENOISE;Impulse noise reduction PARTIALPASTE_IPTCINFO;IPTC PARTIALPASTE_LABCURVE;L*a*b* adjustments PARTIALPASTE_LENSGROUP;Lens Related Settings +PARTIALPASTE_LOCALLAB;Local Adjustments +PARTIALPASTE_LOCGROUP;Local PARTIALPASTE_LENSPROFILE;Profiled lens correction PARTIALPASTE_LOCALCONTRAST;Local contrast PARTIALPASTE_METADATA;Metadata mode @@ -1056,6 +1505,7 @@ PARTIALPASTE_PREPROCESS_GREENEQUIL;Green equilibration PARTIALPASTE_PREPROCESS_HOTPIXFILT;Hot pixel filter PARTIALPASTE_PREPROCESS_LINEDENOISE;Line noise filter PARTIALPASTE_PREPROCESS_PDAFLINESFILTER;PDAF lines filter +PARTIALPASTE_PREPROCWB;Preprocess White Balance PARTIALPASTE_PRSHARPENING;Post-resize sharpening PARTIALPASTE_RAWCACORR_AUTO;CA auto-correction PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT;CA avoid color shift @@ -1120,6 +1570,9 @@ PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs PREFERENCES_CLUTSDIR;HaldCLUT directory PREFERENCES_CMMBPC;Black point compensation +PREFERENCES_COMPLEXITYLOC;Default complexity for Local Adjustments +PREFERENCES_COMPLEXITY_EXP;Expert +PREFERENCES_COMPLEXITY_NORM;Normal PREFERENCES_CROP;Crop Editing PREFERENCES_CROP_AUTO_FIT;Automatically zoom to fit the crop PREFERENCES_CROP_GUIDES;Guides shown when not editing the crop @@ -1234,8 +1687,9 @@ PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP;Enabling this option when working with f PREFERENCES_SET;Set PREFERENCES_SHOWBASICEXIF;Show basic Exif info PREFERENCES_SHOWDATETIME;Show date and time -PREFERENCES_SHOWEXPOSURECOMPENSATION;Append exposure compensation PREFERENCES_SHOWFILMSTRIPTOOLBAR;Show Filmstrip toolbar +PREFERENCES_SHOWEXPOSURECOMPENSATION;Append exposure compensation +PREFERENCES_SHOWTOOLTIP;Show Local Adjustments advice tooltips PREFERENCES_SHTHRESHOLD;Threshold for clipped shadows PREFERENCES_SINGLETAB;Single Editor Tab Mode PREFERENCES_SINGLETABVERTAB;Single Editor Tab Mode, Vertical Tabs @@ -1502,7 +1956,7 @@ TP_COLORAPP_TCMODE_LIGHTNESS;Lightness TP_COLORAPP_TCMODE_SATUR;Saturation TP_COLORAPP_TEMP_TOOLTIP;To select an illuminant, always set Tint=1.\n\nA temp=2856\nD41 temp=4100\nD50 temp=5003\nD55 temp=5503\nD60 temp=6000\nD65 temp=6504\nD75 temp=7504 TP_COLORAPP_TEMP2_TOOLTIP;Either symmetrical mode temp = White balance.\nEither select illuminant always set Tint=1.\n\nA temp=2856\nD41 temp=4100\nD50 temp=5003\nD55 temp=5503\nD60 temp=6000\nD65 temp=6504\nD75 temp=7504 -TP_COLORAPP_TEMPOUT_TOOLTIP;Disable to chnage temperature and tint +TP_COLORAPP_TEMPOUT_TOOLTIP;Disable to change temperature and tint TP_COLORAPP_TONECIE;Tone mapping using CIECAM02 TP_COLORAPP_TONECIE_TOOLTIP;If this option is disabled, tone mapping is done in L*a*b* space.\nIf this option is enabled, tone mapping is done using CIECAM02.\nThe Tone Mapping tool must be enabled for this setting to take effect. TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP;Absolute luminance of the viewing environment\n(usually 16 cd/m²). @@ -1841,6 +2295,562 @@ TP_LENSPROFILE_USE_CA;Chromatic aberration TP_LENSPROFILE_USE_GEOMETRIC;Geometric distortion TP_LENSPROFILE_USE_HEADER;Correct TP_LENSPROFILE_USE_VIGNETTING;Vignetting +TP_LOCALLAB_ACTIV;Luminance only +TP_LOCALLAB_ADJ;Equalizer Blue-yellow Red-green +TP_LOCALLAB_ALL;All rubrics +TP_LOCALLAB_AMOUNT;Amount +TP_LOCALLAB_ARTIF;Shape detection +TP_LOCALLAB_ARTIF_TOOLTIP;Threshold deltaE-scope increase the range of scope-deltaE - high values are for very wide gamut images.\nIncrease deltaE Weakening improve shape detection, but can reduce the scope of detection. +TP_LOCALLAB_AUTOGRAY;Automatic +TP_LOCALLAB_AVOID;Avoid color shift +TP_LOCALLAB_BALAN;Balance ΔE ab-L +TP_LOCALLAB_BALANH;Balance ΔE C-H +TP_LOCALLAB_BALAN_TOOLTIP;Change algorithm ΔE parameter.\nMore or less ab-L, more or less C - H.\nNot for Denoise +TP_LOCALLAB_BALANEXP;ΔØ PDE balance +TP_LOCALLAB_BASELOG;Logarithm base +TP_LOCALLAB_BILATERAL;Bilateral filter +TP_LOCALLAB_BLACK_EV;Black Ev +TP_LOCALLAB_BLENDMASKCOL;Blend +TP_LOCALLAB_BLENDMASK_TOOLTIP;If blend = 0 only shape detection is improved.\nIf blend > 0 the mask is added to the image. If blend < 0 the mask is subtracted from the image +TP_LOCALLAB_BLGUID;Guided Filter +TP_LOCALLAB_BLINV;Inverse +TP_LOCALLAB_BLCO;Chrominance only +TP_LOCALLAB_BLLO;Luminance only +TP_LOCALLAB_BLLC;Luminance & Chrominance +TP_LOCALLAB_BLMED;Median +TP_LOCALLAB_BLMETHOD_TOOLTIP;Normal - direct blur and noise with all settings.\nInverse blur and noise with all settings. Be careful some results may be curious +TP_LOCALLAB_BLNORM;Normal +TP_LOCALLAB_BLSYM;Symmetric +TP_LOCALLAB_BLWH;All changes forced in Black and White +TP_LOCALLAB_BLWH_TOOLTIP;Force color change composante "a" and "b" to zero.\nUsefull when the user chooses black and white processes, or film. +TP_LOCALLAB_SPOTNAME;New Spot +TP_LOCALLAB_BLUFR;Smooth - Blur - Grain - Denoise +TP_LOCALLAB_BLUMETHOD_TOOLTIP;To blur the background and isolate the foreground:\n*Blur the background by a RT-spot fully covering the image (high values for scope and transition) - normal or inverse.\n*Isolate the foreground by one or more excluding RT-spot with the tools you want (increse scope).\n\nThis module can be used in additional noise reduction,including "median" and "Guided filter" +TP_LOCALLAB_BLURMASK_TOOLTIP;Generate a blur mask, take into account the structure with the contrast threshold Mask Blur slider. +TP_LOCALLAB_BLUR;Gaussian Blur - Noise - Grain +TP_LOCALLAB_BLURCBDL;Blur levels 0-1-2-3-4 +TP_LOCALLAB_BLURCOL;Radius Mask Blur +TP_LOCALLAB_BLURDE;Blur Shape detection +TP_LOCALLAB_BLURLC;Luminance Only +TP_LOCALLAB_BLURLEVELFRA;Blur Levels +TP_LOCALLAB_BLURRESIDFRA;Blur Residual +TP_LOCALLAB_BUTTON_ADD;Add +TP_LOCALLAB_BUTTON_DEL;Delete +TP_LOCALLAB_BUTTON_DUPL;Duplicate +TP_LOCALLAB_BUTTON_REN;Rename +TP_LOCALLAB_BUTTON_VIS;Show/Hide +TP_LOCALLAB_CBDL;Contrast by detail levels - Defects +TP_LOCALLAB_CBDL_ADJ_TOOLTIP;Acts as a wavelet tools.\nThe first level (0) acts on 2x2 details.\nThe last level (5) acts on 64x64 details. +TP_LOCALLAB_CBDLCLARI_TOOLTIP;Takes the midtones and enhance them. +TP_LOCALLAB_CBDL_THRES_TOOLTIP;Prevent the sharpening of noise +TP_LOCALLAB_CENTER_X;Center X +TP_LOCALLAB_CENTER_Y;Center Y +TP_LOCALLAB_CH;Curves CL - LC +TP_LOCALLAB_CHROMA;Chrominance +TP_LOCALLAB_CHROMACBDL;Chroma +TP_LOCALLAB_CHROMACB_TOOLTIP;Acts as an amplifier-reducer action compare to sliders of luminance.\nUnder 100 reduce, above 100 amplifie +TP_LOCALLAB_CHROMALEV;Chroma levels +TP_LOCALLAB_CHROMABLU;Chroma levels +TP_LOCALLAB_CHROMABLU_TOOLTIP;Acts as an amplifier-reducer action compare to settings of luma.\nUnder 1 reduce, above 1 amplifie +TP_LOCALLAB_CHROMASKCOL;Chroma mask +TP_LOCALLAB_CHROMASK_TOOLTIP;You can use this slider to desaturated background (inverse mask - curve near 0).\nAlso to attenuate or enhance the action of a mask on the chroma +TP_LOCALLAB_CHRRT;Chroma +TP_LOCALLAB_CIRCRADIUS;Spot size +TP_LOCALLAB_CIRCRAD_TOOLTIP;Contains the references of RT-spot, useful for shape detection (hue, luma, chroma, Sobel).\nLow values may be useful for treating foliage.\nHigh values may be useful for treating skin +TP_LOCALLAB_CLARICRES;Merge Chroma +TP_LOCALLAB_CLARIFRA;Clarity & Sharp mask - Blend & Soft images +TP_LOCALLAB_CLARILRES;Merge Luma +TP_LOCALLAB_CLARISOFT;Soft radius +TP_LOCALLAB_CLARISOFT_TOOLTIP;Enabled for Clarity and Sharp mask if Merge Luma different from zero.\n\nEnabled for all wavelets pyramid modules.\nDisabled if Soft radius = 0 +TP_LOCALLAB_CLARITYML;Clarity +TP_LOCALLAB_CLARI_TOOLTIP;Under or equal level wavelet 4, 'Sharp mask' is enabled.\nAbove level wavelet 5 'Clarity' is enabled.\nUsefull if you use 'Level dynamic Range Compression' +TP_LOCALLAB_CLIPTM;Clip Restored datas (gain) +TP_LOCALLAB_COFR;Color & Light - Small defects +TP_LOCALLAB_COL_NAME;Name +TP_LOCALLAB_COL_VIS;Status +TP_LOCALLAB_COLORDE;Color preview selection ΔE - Intensity +TP_LOCALLAB_COLORDE_TOOLTIP;Show preview selection ΔE in blue if negative and in green if positive.\n\nMask and modifications (show modifications without mask): show real modifications if positive, show enhanced modifications (only luminance) with blue and yellow if negative. +TP_LOCALLAB_COLORDEPREV_TOOLTIP;Button Preview ΔE needs that only one tool is enabled (expander).\nTo be able to have an Preview ΔE with several enable tools use Mask and modifications - Preview ΔE +TP_LOCALLAB_COLORSCOPE;Scope Color Tools +TP_LOCALLAB_COLORSCOPE_TOOLTIP;Use a common Scope for Color and light, Exposure (Standard), Shadows highlight, Vibrance.\nOthers tools have their specific scope. +TP_LOCALLAB_COMPFRA;Levels Directional Contrast +TP_LOCALLAB_COMPREFRA;Levels Dynamic Wavelet Range (un)Compression +TP_LOCALLAB_COMPRESS_TOOLTIP;Use if necessary the module 'Clarity & Sharp mask and Blend & Soft Images' by adjusting 'Soft radius' to reduce artifacts. +TP_LOCALLAB_COMPFRAME_TOOLTIP;Allows special effects. You can reduce artifacts with 'Clarity & Sharp mask - Blend & Soft Images".\nUses a lot of resources +TP_LOCALLAB_COMPLEX_METHOD;Software Complexity +TP_LOCALLAB_COMPLEX_TOOLTIP; Allow user to select Local adjustments rubrics. +TP_LOCALLAB_CONTCOL;Contrast threshold Mask Blur +TP_LOCALLAB_CONTFRA;Contrast by Level +TP_LOCALLAB_CONTRAST;Contrast +TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP;Main mask contrast control. +TP_LOCALLAB_CONTRESID;Contrast +TP_LOCALLAB_CONTTHR;Contrast Threshold +TP_LOCALLAB_CSTHRESHOLD;Ψ Wavelets Levels +TP_LOCALLAB_CSTHRESHOLDBLUR;Ψ Mask Wavelet level +TP_LOCALLAB_CURV;Lightness - Contrast - Chrominance "Super" +TP_LOCALLAB_CURVCURR;Normal +TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP;If curves at the top, mask is completely black no transformation is made by the mask on the image.\nAs you go down the curve, the mask gradually more colorful and brilliant, the image is changing more and more.\n\nIt is recommended (not required) to position the top of the curves on the gray transition line which represents the references (chroma, luma, hue). +TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP;To be active, you must enable combobox 'Curves type' +TP_LOCALLAB_CURVEEDITOR_TONES_LABEL;Tone curve +TP_LOCALLAB_CURVEEDITOR_TONES_TOOLTIP;L=f(L), can be used with L(H) in Color and Light +TP_LOCALLAB_CURVEMETHOD_TOOLTIP;'Normal', the curve L=f(L) has the same algorithm than slider lightness.\n'Super' the curve L=f(L) has an new improved algorithm, which can leeds in some cases to artifacts. +TP_LOCALLAB_CURVENCONTRAST;Super+Contrast threshold (experimental) +TP_LOCALLAB_CURVENH;Super +TP_LOCALLAB_CURVENHSU;Combined HueChroma (experimental) +TP_LOCALLAB_CURVENSOB2;Combined HueChroma + Contrast threshold (experimental) +TP_LOCALLAB_CURVNONE;Disable curves +TP_LOCALLAB_DARKRETI;Darkness +TP_LOCALLAB_DEHAFRA;Dehaze +TP_LOCALLAB_DEHAZ;Strength +TP_LOCALLAB_DEHAZ_TOOLTIP;Negative values adds haze +TP_LOCALLAB_DELTAD;Delta balance +TP_LOCALLAB_DELTAEC;Mask ΔE Image +TP_LOCALLAB_DENOIS;Ψ Denoise +TP_LOCALLAB_DENOI_TOOLTIP;This module can be used alone (at the end of process), or in complement of main denoise (at the beginning).\nScope allows to differentiate the action according to the color (deltaE).\nYou can complete the action with "median" or "Guided Filter" (Smooth Blur...).\nYou can complete the action with "Blur levels" "Wavelet pyramid" +TP_LOCALLAB_DEPTH;Depth +TP_LOCALLAB_DETAIL;Local contrast +TP_LOCALLAB_DETAILSH;Details +TP_LOCALLAB_DETAILTHR;Detail threshold Luminance Chroma (DCT ƒ) +TP_LOCALLAB_DUPLSPOTNAME;Copy +TP_LOCALLAB_EDGFRA;Edge Sharpness +TP_LOCALLAB_EDGSHOW;Show all tools +TP_LOCALLAB_ELI;Elipse +TP_LOCALLAB_ENABLE_AFTER_MASK;Use Tone Mapping +TP_LOCALLAB_ENABLE_MASK;Enable mask +TP_LOCALLAB_ENABLE_MASKAFT;Use all algorithms Exposure +TP_LOCALLAB_ENARETIMASKTMAP_TOOLTIP;If enabled Mask uses Restored Datas after Transmission Map instead of Original datas +TP_LOCALLAB_ENH;Enhanced +TP_LOCALLAB_ENHDEN;Enhanced + chroma denoise +TP_LOCALLAB_EPSBL;Detail +TP_LOCALLAB_EQUIL;Normalize Luminance +TP_LOCALLAB_EQUILTM_TOOLTIP;Reconstruct luminance in such a way that the mean and the variance of the output image is identical to that of the original. +TP_LOCALLAB_ESTOP;Edge stopping +TP_LOCALLAB_EV_DUPL;Copy of +TP_LOCALLAB_EV_NVIS;Hide +TP_LOCALLAB_EV_NVIS_ALL;Hide all +TP_LOCALLAB_EV_VIS;Show +TP_LOCALLAB_EV_VIS_ALL;Show all +TP_LOCALLAB_EXCLUF;Excluding +TP_LOCALLAB_EXCLUF_TOOLTIP;Can be used to exclude this part of datas - move Scope to extend color.\n You can apply all settings to this RT-spot. +TP_LOCALLAB_EXCLUTYPE;Spot method +TP_LOCALLAB_EXCLUTYPE_TOOLTIP;Normal spot use recursive data.\n\nExcluding spot reinitialize data to origin.\nCan be used to totally or partially cancel a previous action or to perform a inverse mode +TP_LOCALLAB_EXECLU;Excluding spot +TP_LOCALLAB_EXNORM;Normal spot +TP_LOCALLAB_EXPCBDL_TOOLTIP;In the case of contaminated sensor (type "grease"), and when the area is important or for a series of small defects.\n\na) Put the selection spot on a pronounced default (adapting its size if necessary), use a large spot enough to allow wavelet; b) choose a wide selection area to cover most of the area affected by the defects; c) Select a transition value (low) and transition weakening (high value); d) act on levels 2, 3, 4 or 5 or lower by reducing the contrast (values below 100) and by acting on the chroma slider if necessary. e)possibly act on "scope" to reduce the extent of the action.\n\nYou can also complete with Blur levels and Gaussian blur (Smooth Blur and noise) +TP_LOCALLAB_EXPCHROMA;Chroma compensation +TP_LOCALLAB_EXPCHROMA_TOOLTIP;Only in association with exposure compensation and PDE Ipol.\nAvoids desaturation of colors +TP_LOCALLAB_EXPCOLOR_TOOLTIP;In the case of small defects.\n\nRed-eyes : red-centered circular selector, spot delimiters close to the eye, weak scope, "lightness" -100, "chrominance" -100.\n\nSpotIR :Circular selector centered on the defect, spot delimiters close to the default - reduce "chrominance", possibly act on "scope" to reduce the extent of the action.\n\nDust - grease (small) :Circular selector centered on the defect (adapt the size of the spot), spot delimiters not too close to the defect to allow an inconspicuous transition. a) "Transition" (low values) and "Transition weak" (high values); b) act on "lightness" and possibly on "chrominance" or "Color correction grid - direct" to approach the rendering of the polluted zone to that of the healthy zone; c) act moderately on "scope" to modulate the desired action.\n\nYou can also complete with Gaussian blur (Smooth Blur and noise) +TP_LOCALLAB_EXPCONTRAST_TOOLTIP;Avoid spots that are too small(< 32x32 pixels).\nUse low transition values and high weakening transition values and scope to simulate small RT-spot and deal wth defects.\nUse if necessary the module 'Clarity & Sharp mask and Blend images' by adjusting 'Soft radius' to reduce artifacts. +TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;See the documentation of wavelet levels.\nHowever there are some differences: more tools and closer to the details.\nEx: Tone mapping for wavelet levels. +TP_LOCALLAB_EXPCURV;Curves +TP_LOCALLAB_EXPGRAD;Graduated Filter +TP_LOCALLAB_EXPLAP_TOOLTIP;The more you act on this threshold slider, the greater the action of reducing contrast. +TP_LOCALLAB_EXPLAPBAL_TOOLTIP;Balances the action between the original image and the Laplace transform. +TP_LOCALLAB_EXPLAPLIN_TOOLTIP;Add linear exposure component before application Laplace transform +TP_LOCALLAB_EXPLAPGAMM_TOOLTIP;Apply a gamma before and after Laplace transform +TP_LOCALLAB_EXPMERGEFILE_TOOLTIP;Allows various possibilities to blend image (as layers in Photosshop) : difference, multiply, soft light, overlay...with opacity...\nOriginal Image : merge current RT-spot with Original.\nPrevious spot : merge current Rt-spot with previous - if there is only one spot previous = original.\nBackground : merge current RT-spot with a color and luminance background (less possibilties) +TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP;Apply a median before Laplace transform to prevent artifacts (noise).\nYou can also use "Denoise" tool. +TP_LOCALLAB_EXPMETHOD_TOOLTIP;Standard : use an algorithm similar as main Exposure but in L*a*b* and taking account of deltaE.\n\nLaplacian & PDE : use another algorithm also with deltaE and with Poisson equation to solve Laplacian in Fourier space.\nPDE IPOL, PDE Fattal and Standard can be combined.\nFFTW Fourier Transform is optimized in size to reduce processing time.\nPDE reduce artifacts and noise. +TP_LOCALLAB_EXPOSE;Exposure - PDE algorithms +TP_LOCALLAB_EXPOSURE_TOOLTIP;In some cases (strong shadows ..) you can use others modules "Shadows Highlights", "Tone equalizer", "TRC", "Encoding Log"... +TP_LOCALLAB_EXPRETITOOLS;Advanced Retinex Tools +TP_LOCALLAB_EXPSHARP_TOOLTIP;RT-Spot minimum 39*39.\nUse low transition values and high weakening transition values and scope to simulate small RT-spot. +TP_LOCALLAB_EXPTOOL;Tools exposure +TP_LOCALLAB_EXPTRC;Tone Response Curve - TRC +TP_LOCALLAB_FATAMOUNT;Amount +TP_LOCALLAB_FATANCHOR;Anchor +TP_LOCALLAB_FATANCHORA;Offset +TP_LOCALLAB_FATDETAIL;Detail +TP_LOCALLAB_FATFRA;Dynamic Range Compression ƒ +TP_LOCALLAB_FATFRAME_TOOLTIP;PDE Fattal - use Fattal Tone mapping algorithm. +TP_LOCALLAB_FATLEVEL;Sigma +TP_LOCALLAB_FATRES;Amount Residual Image +TP_LOCALLAB_FATSHFRA;Dynamic Range Compression Mask ƒ +TP_LOCALLAB_FEATH_TOOLTIP;Gradient width in percent of the Spot diagonal\nUsed by all Graduated filter in all tools.\nNo action if Graduated Filter are not used. +TP_LOCALLAB_FEATVALUE;Feather gradient (Graduated Filters) +TP_LOCALLAB_FFTCOL_MASK;FFTW ƒ +TP_LOCALLAB_FFTW;ƒ - Use Fast Fourier Transform +TP_LOCALLAB_FFTW2;ƒ - Use Fast Fourier Transform (TIF, JPG,..) +TP_LOCALLAB_FFTWBLUR;ƒ - Always Use Fast Fourier Transform +TP_LOCALLAB_FULLIMAGE;Calculate DarkEv - WhiteEv - Value on the entire image +TP_LOCALLAB_GAM;Gamma +TP_LOCALLAB_GAMFRA;Tone response curve (TRC) +TP_LOCALLAB_GAMM;Gamma +TP_LOCALLAB_GAMMASKCOL;Gamma mask +TP_LOCALLAB_GAMSH;Gamma +TP_LOCALLAB_GRADANG;Gradient angle +TP_LOCALLAB_GRADANG_TOOLTIP;Rotation angle in degrees : -180 0 +180 +TP_LOCALLAB_GRADFRA;Graduated Filter Mask +TP_LOCALLAB_GRADGEN_TOOLTIP;Graduated filter is supplied with Color and Light & merge file, Exposure & mask, Shadows Highlight, Vibrance, Encoding log.\n\nVibrance, Color and Light & merge file, are provided with GF luminance, chrominance, Hue.\nFeather is located in settings. +TP_LOCALLAB_GRADLOGFRA;Graduated Filter Luminance +TP_LOCALLAB_GRADSTR;Gradient strength +TP_LOCALLAB_GRADSTRAB_TOOLTIP;Filter chroma strength +TP_LOCALLAB_GRADSTRCHRO;Gradient strength Chrominance +TP_LOCALLAB_GRADSTRHUE2;Gradient strength Hue +TP_LOCALLAB_GRADSTRHUE;Gradient strength Hue +TP_LOCALLAB_GRADSTRHUE_TOOLTIP;Filter Hue strength +TP_LOCALLAB_GRADSTRLUM;Gradient strength Luminance +TP_LOCALLAB_GRADSTR_TOOLTIP;Filter strength in stops +TP_LOCALLAB_GRAINFRA;Film Grain 1:1 +TP_LOCALLAB_GRALWFRA;Graduated Filter Local contrast +TP_LOCALLAB_GRIDFRAME_TOOLTIP;You can use this tool as a brush. Use small spot and adapt transition and transition weakening\nOnly mode NORMAL and eventually Hue, Saturation, Color, Luminosity are concerned by Merge background (ΔE) +TP_LOCALLAB_GRIDONE;Color Toning +TP_LOCALLAB_GRIDTWO;Direct +TP_LOCALLAB_GUIDBL;Soft radius +TP_LOCALLAB_GUIDFILTER;Guided filter radius +TP_LOCALLAB_GUIDFILTER_TOOLTIP;Adapt this values according to images - can reduce or increase artifacts. +TP_LOCALLAB_HIGHMASKCOL;Highlights mask +TP_LOCALLAB_HHMASK_TOOLTIP;Fine hue adjustments for example for the skin. +TP_LOCALLAB_HLH;Curves H +TP_LOCALLAB_IND;Independent (mouse) +TP_LOCALLAB_INDSL;Independent (mouse + sliders) +TP_LOCALLAB_INVERS;Inverse +TP_LOCALLAB_INVERS_TOOLTIP;If selected (inverse) less possibilities.\n\nAlternative\nFirst Spot:\n full image - delimiter outside preview\n Shape RT-spot area : rectangle. Transition 100\n\nSecond spot : Excluding spot +TP_LOCALLAB_ISOGR;Coarseness (ISO) +TP_LOCALLAB_LABEL;Local Adjustments +TP_LOCALLAB_LABBLURM;Mask Blur +TP_LOCALLAB_LABGRID;Color correction grid +TP_LOCALLAB_LABGRIDMERG;Background +TP_LOCALLAB_LABGRID_VALUES;High(a)=%1 High(b)=%2\nLow(a)=%3 Low(b)=%4 +TP_LOCALLAB_LABSTRUM;Mask Structure +TP_LOCALLAB_LAPLACC;ΔØ Mask Laplacian solve PDE +TP_LOCALLAB_LAP_MASK_TOOLTIP;Solve PDE for all Laplacian masks.\nIf enabled Laplacian threshold mask reduce artifacts and smooth result.\nIf disabled linear response. +TP_LOCALLAB_LAPLACE;Δ - Laplacian threshold ΔE +TP_LOCALLAB_LAPLACEXP;∆ - Laplacian threshold +TP_LOCALLAB_LAPMASKCOL;∆ - Laplacian threshold mask +TP_LOCALLAB_LAPRAD_TOOLTIP;Avoid using Radius and Laplace Threshold simultaneously.\nLaplacian threshold reduce contrast, artifacts, smooth result (if PDE settings enabled). +TP_LOCALLAB_LC_FFTW_TOOLTIP;FFT improve quality and allow big radius, but increases the treatment time.\nThe treatment time depends on the surface to be treated.\nTo be used preferably for large radius.\n\nDimensions can be reduced by a few pixels to optimize FFTW.\nThis optimization can reduce the treatment time by a factor of 1.5 to 10.\n +TP_LOCALLAB_LEVELBLUR;Maximum Blur levels +TP_LOCALLAB_LEVELLOCCONTRAST_TOOLTIP;On the abscissa local contrast (near concept luminance). On the ordinate, amplification or reduction local contrast. +TP_LOCALLAB_LEVELWAV;Ψ Wavelets Levels +TP_LOCALLAB_LEVELWAV_TOOLTIP;The Level is automatically adapted to the size of the spot and the preview.\nFrom level 9 size max 512 to level 1 size max = 4 +TP_LOCALLAB_LIGHTNESS;Lightness +TP_LOCALLAB_LIGHTN_TOOLTIP;In inverse mode: selection = -100 force luminance to zero +TP_LOCALLAB_LIGHTRETI;Lightness +TP_LOCALLAB_LINEAR;Linearity +TP_LOCALLAB_LMASK_LEVEL_TOOLTIP;Give priority to action on midtones and high lights and by choosing the concerned wavelet levels +TP_LOCALLAB_LMASK_LL_TOOLTIP;Give priority to action on midtones and high lights +TP_LOCALLAB_LOCCONT;Unsharp Mask +TP_LOCALLAB_LOC_CONTRAST;Local contrast -Wavelet - defects +TP_LOCALLAB_LOC_CONTRASTPYR;Ψ Pyramid 1: +TP_LOCALLAB_LOC_CONTRASTPYRLAB; Graduated Filter - Edge Sharpness - Blur +TP_LOCALLAB_LOC_CONTRASTPYR2;Ψ Pyramid 2: +TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contrast by Levels- Tone Mapping - Dir. Contrast +TP_LOCALLAB_LOC_RESIDPYR;Residual Image Main +TP_LOCALLAB_LOG;Encoding log +TP_LOCALLAB_LOGAUTO;Automatic +TP_LOCALLAB_LOGFRA;Source Gray Point +TP_LOCALLAB_LOGLIN;Logarithm mode +TP_LOCALLAB_LOGPFRA;Relative Exposure Levels +TP_LOCALLAB_LOGENCOD_TOOLTIP;Allows Tone Mapping with Logarithm encoding (ACES).\nUsefull for underexposed pictures, or with high dynamic range.\n\nTwo steps in the process : 1) Calculate Dynamic Range 2) User adaptation +TP_LOCALLAB_LOGFRAME_TOOLTIP;Calculate or use Exposure levels of the image early in the process:\n Black Ev, White Ev and Source Gray point.\n Take into account main exposure compensation. +TP_LOCALLAB_LOGAUTO_TOOLTIP;Pressing this button will bring an evaluation of dynamic range and Source Gray point (if "Automatic" Source gray enabled).\nTo be able to touch up the automatic values, press the button again +TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP;Estimated values of Dynamic Range - Black Ev and White Ev +TP_LOCALLAB_LOGSRCGREY_TOOLTIP;Estimated gray point value of the image, early in the process +TP_LOCALLAB_LOGTARGGREY_TOOLTIP;You can change this value to adapt it to your taste. +TP_LOCALLAB_LOGBASE_TOOLTIP;Default = 2.\nValues less than 2 reduce the action of the algorithm, the shadows are darker, the highlights are brighter.\nValues greater than 2 change the action of the algorithm, the shadows are grayer the highlights are more washed out +TP_LOCALLAB_LUM;Curves LL - CC +TP_LOCALLAB_LUMADARKEST;Darkest +TP_LOCALLAB_LUMASK;Luminance Background Mask +TP_LOCALLAB_LUMASK_TOOLTIP;Adjust the gray of the mask background in Show Mask (Mask and modifications) +TP_LOCALLAB_LUMAWHITESEST;Whiteest +TP_LOCALLAB_LUMONLY;Luminance only +TP_LOCALLAB_MASFRAME;Mask and Merge +TP_LOCALLAB_MASFRAME_TOOLTIP;For all masks.\nTake into account deltaE image to avoid retouching the selection area when sliders gamma mask, slope mask, chroma mask and curves contrast , levels contrasts, and mask blur, structure(if enabled tool) are used.\nDisabled in Inverse +TP_LOCALLAB_MASK2;Contrast curve mask +TP_LOCALLAB_MASK;Mask +TP_LOCALLAB_MASKCOL;Mask Curves +TP_LOCALLAB_MASKH;Hue curve mask +TP_LOCALLAB_MASK_TOOLTIP;You can enable multiple masks for a single tool, this requires activating another tool (but without using the tool : sliders to 0,...) where is the mask you want to activate.\n\nYou can also duplicate the RT-spot and place it right next to each other,variations of references allow fine work on images. +TP_LOCALLAB_MED;Medium +TP_LOCALLAB_MEDIAN;Median Low +TP_LOCALLAB_MEDNONE;None +TP_LOCALLAB_MERCOL;Color +TP_LOCALLAB_MERDCOL;Merge background (ΔE) +TP_LOCALLAB_MERELE;Lighten only +TP_LOCALLAB_MERFIV;Addition +TP_LOCALLAB_MERFOR;Color Dodge +TP_LOCALLAB_MERFOU;Multiply +TP_LOCALLAB_MERGE1COLFRA;Merge with Original or Previous or Background +TP_LOCALLAB_MERGECOLFRA;Mask: LCH & Structure +TP_LOCALLAB_MERGEFIV;Previous Spot(Mask 7) + Mask LCH +TP_LOCALLAB_MERGEFOU;Previous Spot(Mask 7) +TP_LOCALLAB_MERGENONE;None +TP_LOCALLAB_MERGEONE;Short Curves 'L' Mask +TP_LOCALLAB_MERGEOPA_TOOLTIP;Opacity merge % current Spot with original or previous Spot.\nContrast threshold : adjust result in function of Original contrast +TP_LOCALLAB_MERGETHR;Original(Mask 7) + Mask LCH +TP_LOCALLAB_MERGETWO;Original(Mask 7) +TP_LOCALLAB_MERGETYPE;Merge image and mask +TP_LOCALLAB_MERGETYPE_TOOLTIP;None, use all mask in LCH mode.\nShort curves 'L' mask, use a short circuit for mask 2, 3, 4, 6, 7.\nOriginal mask 8, blend current image with original +TP_LOCALLAB_MERGEMER_TOOLTIP;Take into account ΔE to merge files (equivalent of scope for this use) +TP_LOCALLAB_MERHEI;Overlay +TP_LOCALLAB_MERHUE;Hue +TP_LOCALLAB_MERLUCOL;Luminance +TP_LOCALLAB_MERLUM;Luminosity +TP_LOCALLAB_MERNIN;Screen +TP_LOCALLAB_MERONE;Normal +TP_LOCALLAB_MERSAT;Saturation +TP_LOCALLAB_MERSEV0;Soft Light Illusion +TP_LOCALLAB_MERSEV1;Soft Light W3C +TP_LOCALLAB_MERSEV2;Hard Light +TP_LOCALLAB_MERSEV;Soft Light Photshop +TP_LOCALLAB_MERSIX;Divide +TP_LOCALLAB_MERTEN;Darken only +TP_LOCALLAB_MERTHI;Color Burn +TP_LOCALLAB_MERTHR;Difference +TP_LOCALLAB_MERTWE;Exclusion +TP_LOCALLAB_MERTWO;Substract +TP_LOCALLAB_METHOD_TOOLTIP;'Enhanced + chroma denoise' significantly increases processing times.\nBut reduce artifacts. +TP_LOCALLAB_MLABEL;Restored datas Min=%1 Max=%2 (Clip - Offset) +TP_LOCALLAB_MLABEL_TOOLTIP;'Should be' near min=0 max=32768 (log mode) but others values are possible.\nYou can act on Clip Restored datas and Offset to normalize.\n\nRestored image with no mixture. +TP_LOCALLAB_MODE_EXPERT;Expert +TP_LOCALLAB_MODE_NORMAL;Normal +TP_LOCALLAB_MRFIV;Background +TP_LOCALLAB_MRFOU;Previous Spot +TP_LOCALLAB_MRONE;None +TP_LOCALLAB_MRTHR;Original Image +TP_LOCALLAB_MRTWO;Short Curves 'L' Mask +TP_LOCALLAB_MULTIPL_TOOLTIP;Allows the retouching of tones over a very wide range : -18EV +4EV. The first slider acts on very dark tones between -18EV and -6EV. The last slider acts light tones up to 4EV +TP_LOCALLAB_NEIGH;Radius +TP_LOCALLAB_NOISECHROCOARSE;Chroma coarse (Wav) +TP_LOCALLAB_NOISECHROC_TOOLTIP;If superior to zero, high quality algorithm is enabled.\nCoarse is for slider >=0.02 +TP_LOCALLAB_NOISECHRODETAIL;Chroma detail recovery (DCT ƒ) +TP_LOCALLAB_NOISECHROFINE;Chroma fine (Wav) +TP_LOCALLAB_NOISEDETAIL_TOOLTIP;Disabled if slider = 100 +TP_LOCALLAB_NOISELEQUAL;Equalizer white-black +TP_LOCALLAB_NOISELUMCOARSE;Luminance coarse (Wav) +TP_LOCALLAB_NOISELUMDETAIL;Luminance detail recovery (DCT ƒ) +TP_LOCALLAB_NOISELUMFINE;Luminance fine 1 (Wav) +TP_LOCALLAB_NOISELUMFINETWO;Luminance fine 2 (Wav) +TP_LOCALLAB_NOISELUMFINEZERO;Luminance fine 0 (Wav) +TP_LOCALLAB_NOISEMETH;Denoise +TP_LOCALLAB_NONENOISE;None +TP_LOCALLAB_OFFS;Offset +TP_LOCALLAB_OFFSETWAV;Offset +TP_LOCALLAB_OPACOL;Opacity +TP_LOCALLAB_ORIGLC;Merge only with original image +TP_LOCALLAB_ORRETISTREN_TOOLTIP;Acts on the Laplacian threshold, the greater the action, the more the differences in contrast will be reduced +TP_LOCALLAB_ORRETILAP_TOOLTIP;Acts on a second Laplacian threshold, to take into account ΔE to differentiate the action especially with the background (different from Scope) +TP_LOCALLAB_PASTELS2;Vibrance +TP_LOCALLAB_PDE;ΔØ Laplacian PDE - Dynamic Range compression + Standard +TP_LOCALLAB_PDEFRA;PDE IPOL - Contrast attenuator ƒ +TP_LOCALLAB_PDEFRAME_TOOLTIP;PDE IPOL - personal algorithm adapted from IPOL to Rawtherapee: lead to very different results and needs differents settings that Standard (negative black, gamma < 1,...)\nMay be usefull for low exposure or high dynamic range.\n +TP_LOCALLAB_PREVIEW;Preview ΔE +TP_LOCALLAB_PROXI;ΔE weakening +TP_LOCALLAB_QUALCURV_METHOD;Curves type +TP_LOCALLAB_QUAL_METHOD;Global quality +TP_LOCALLAB_RADIUS;Radius +TP_LOCALLAB_RADIUS_TOOLTIP;Above Radius 30 Use Fast Fourier Transform +TP_LOCALLAB_RADMASKCOL;Smooth Radius Mask +TP_LOCALLAB_RECT;Rectangle +TP_LOCALLAB_RECURS;Recursive references +TP_LOCALLAB_RECURS_TOOLTIP;Recalculate references for hue, luma, chroma after each module and after each RT-spot.\nAlso useful for working with masks. +TP_LOCALLAB_REFLABEL;Ref. (0..1) Chroma=%1 Luma=%2 Hue=%3 +TP_LOCALLAB_REN_DIALOG_LAB;Enter the new Control Spot name +TP_LOCALLAB_REN_DIALOG_NAME;Renaming Control Spot +TP_LOCALLAB_RESETSHOW;Reset All Show Modifications +TP_LOCALLAB_RESID;Residual Image +TP_LOCALLAB_RESIDBLUR;Blur Residual Image +TP_LOCALLAB_RESIDCHRO;Residual image Chroma +TP_LOCALLAB_RESIDCOMP;Compress Residual image +TP_LOCALLAB_RESIDCONT;Residual image Contrast +TP_LOCALLAB_RESIDHI;Highlights +TP_LOCALLAB_RESIDHITHR;Highlights threshold +TP_LOCALLAB_RESIDSHA;Shadows +TP_LOCALLAB_RESIDSHATHR;Shadows threshold +TP_LOCALLAB_RETI;Dehaze - Retinex Strong contrast +TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP;Play on internal parameters to optimize response.\nLook at the "restored datas" indicators "near" min=0 and max=32768 (log mode), but others values are possible. +TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP;Have no effect when the value "Lightness = 1" or "Darkness =2" is chosen.\nIn other cases, the last step of "Multiple scale Retinex" is applied an algorithm close to "local contrast", these 2 cursors, associated with "Strength" will allow to play upstream on the local contrast. +TP_LOCALLAB_RETI_LOGLIN_TOOLTIP;Logarithm allows differenciation for haze or normal.\nLogarithm brings more contrast but will generate more halo. +TP_LOCALLAB_RETI_SCALE_TOOLTIP;If scale=1, retinex behaves like local contrast with many more possibilities.\nThe greater the scale, the more intense the recursive action, the longer the calculation times +TP_LOCALLAB_RETIFRA;Retinex +TP_LOCALLAB_RETIM;Original Retinex +TP_LOCALLAB_RETITOOLFRA;Retinex Tools +TP_LOCALLAB_RETI_FFTW_TOOLTIP;FFT improve quality and allow big radius, but increases the treatment time.\nThe treatment time depends on the surface to be treated\nThe treatment time depends on the value of scale (be carefull to high values).\nTo be used preferably for large radius.\n\nDimensions can be reduced by a few pixels to optimize FFTW.\nThis optimization can reduce the treatment time by a factor of 1.5 to 10.\nOptimization not used in Preview +TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP;Adapt these values according to images - if misty images and depending on whether you want to act on the front or the background +TP_LOCALLAB_REWEI;Reweighting iterates +TP_LOCALLAB_RGB;RGB Tone Curve +TP_LOCALLAB_ROW_NVIS;Not visible +TP_LOCALLAB_ROW_VIS;Visible +TP_LOCALLAB_SATUR;Saturation +TP_LOCALLAB_SAVREST;Save - Restore Current Image +TP_LOCALLAB_SCALEGR;Scale +TP_LOCALLAB_SCALERETI;Scale +TP_LOCALLAB_SCALTM;Scale +TP_LOCALLAB_SCOPEMASK;Scope Mask ΔE Image +TP_LOCALLAB_SCOPEMASK_TOOLTIP;Enabled if Mask DeltaE Image is enabled.\nLow values avoid retouching selected area +TP_LOCALLAB_SENSI;Scope +TP_LOCALLAB_SENSIBN;Scope +TP_LOCALLAB_SENSICB;Scope +TP_LOCALLAB_SENSIDEN;Scope +TP_LOCALLAB_SENSIEXCLU;Scope +TP_LOCALLAB_SENSIEXCLU_TOOLTIP;Adjust color to include in exclusion! +TP_LOCALLAB_SENSIH;Scope +TP_LOCALLAB_SENSIH_TOOLTIP;Adjust scope of action:\nSmall values limit action to colors very similar to those under the center spot.\nHigh values let the tool act upon a wider range of colors. +TP_LOCALLAB_SENSILOG;Scope +TP_LOCALLAB_SENSIS;Scope +TP_LOCALLAB_SENSIS_TOOLTIP;Adjust scope of action:\nSmall values limit action to colors very similar to those under the center spot.\nHigh values let the tool act upon a wider range of colors.\nValues smaller than 20 lead to a better algorithm. +TP_LOCALLAB_SENSI_TOOLTIP;Adjust scope of action:\nSmall values limit action to colors very similar to those under the center spot.\nHigh values let the tool act upon a wider range of colors.\nValues smaller than 20 lead to a better algorithm. +TP_LOCALLAB_SETTINGS;Settings +TP_LOCALLAB_SH1;Shadows Highlights +TP_LOCALLAB_SH2;Equalizer +TP_LOCALLAB_SHADEX;Shadows +TP_LOCALLAB_SHADEXCOMP;Shadows compression & tonal width +TP_LOCALLAB_SHADHIGH;ShadowsHighlight - Tone equalizer +TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP;Can be used instead - or in complement - of exposure module in difficult cases.\nThe use of Denoise may be necessary : lightening the shadows.\n\nCan be used as graduated filter (increase Scope) +TP_LOCALLAB_SHAMASKCOL;Shadows mask +TP_LOCALLAB_SHAPETYPE;Shape RT-spot area +TP_LOCALLAB_SHAPE_TOOLTIP;Elipse is normal mode.\nRectangle can be used in some cases, for example to work in full image in conjonction with delimiters outside preview, transition = 100.\n\nPolygone - Beziers are waiting for GUI... +TP_LOCALLAB_SHARAMOUNT;Amount +TP_LOCALLAB_SHARBLUR;Blur radius +TP_LOCALLAB_SHARDAMPING;Damping +TP_LOCALLAB_SHARITER;Iterations +TP_LOCALLAB_SHARFRAME;Modifications +TP_LOCALLAB_SHARP;Sharpening +TP_LOCALLAB_SHARRADIUS;Radius +TP_LOCALLAB_SHORTC;Short Curves 'L' Mask +TP_LOCALLAB_SHORTCMASK_TOOLTIP;Short circuit the 2 curves L(L) and L(H).\nAllows you to mix the current image with the original image modified by the mask job.\nUsable with masks 2, 3, 4, 6, 7 +TP_LOCALLAB_SHOWC1;Merge file +TP_LOCALLAB_SHOWC;Mask and modifications +TP_LOCALLAB_SHOWCB;Mask and modifications +TP_LOCALLAB_SHOWDCT;Show process Fourier ƒ +TP_LOCALLAB_SHOWE;Mask and modifications +TP_LOCALLAB_SHOWFOURIER;Fourier ƒ(dct) +TP_LOCALLAB_SHOWLAPLACE;∆ Laplacian (first) +TP_LOCALLAB_SHOWLC;Mask and modifications +TP_LOCALLAB_SHOWMASK;Show mask +TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;Display mask modifications.\nBeware, you can only view one tool mask at the same time.\n\nNote: Use Mask is before algorihtm shape detection. +TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;Show process Fourier:\nShows the different stages of the process.\nLaplace - builds the second derivative according to the threshold (first step).\nFourier -shows the transformed Laplacian with DCT.\nPoisson - show solution of Poisson DCE.\nNormalize - show result without normalization luminance. +TP_LOCALLAB_SHOWMASKTYP1;Blur & Noise +TP_LOCALLAB_SHOWMASKTYP2;Denoise +TP_LOCALLAB_SHOWMASKTYP3;Blur & Noise + Denoise +TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;Mask and modifications can be chosen.\nBlur and noise : in this case it is not used for 'denoise'.\nDenoise : in this case it is not used for 'blur and noise'.\n\nBlur and noise + denoise : mask is shared, be carefull to 'show modifications' and 'scope' +TP_LOCALLAB_SHOWMNONE;None +TP_LOCALLAB_SHOWMODIF;Show modifications without mask +TP_LOCALLAB_SHOWMODIFMASK;Show modifications with mask +TP_LOCALLAB_SHOWNORMAL;Normalize luminance (no) +TP_LOCALLAB_SHOWPLUS;Mask and modifications - Smooth-Blur & Denoise +TP_LOCALLAB_SHOWPOISSON;Poisson (pde ƒ) +TP_LOCALLAB_SHOWR;Mask and modifications +TP_LOCALLAB_SHOWS;Mask and modifications +TP_LOCALLAB_SHOWREF;Preview ΔE +TP_LOCALLAB_SHOWSTRUC;Show structure Spot +TP_LOCALLAB_SHOWSTRUCEX;Show structure Spot +TP_LOCALLAB_SHOWT;Mask and modifications +TP_LOCALLAB_SHOWVI;Mask and modifications +TP_LOCALLAB_SHRESFRA;Shadows/Highlights +TP_LOCALLAB_SHTRC_TOOLTIP;Modifies the tones of the image by acting on a TRC (Tone Response Curve).\nGamma acts mainly on light tones.\nSlope acts mainly on dark tones +TP_LOCALLAB_SIGMAWAV;Attenuation Response +TP_LOCALLAB_SIM;Simple +TP_LOCALLAB_SLOMASKCOL;Slope mask +TP_LOCALLAB_SLOSH;Slope +TP_LOCALLAB_SOFT;Soft Light - Original Retinex +TP_LOCALLAB_SOFTM;Soft Light +TP_LOCALLAB_SOFTMETHOD_TOOLTIP;Original Retinex is very different from others Retinex method.\nIts acts on grey and balance luminance.\nIt is an emulation of "Dodge" and "Burn" +TP_LOCALLAB_SOFTRADIUSCOL;Soft radius +TP_LOCALLAB_SOFTRETI;Reduce artifact ΔE +TP_LOCALLAB_SOFTRETI_TOOLTIP;Take into account deltaE to improve Transmission map +TP_LOCALLAB_SOURCE_GRAY;Value +TP_LOCALLAB_SPECIAL;Special use of RGB curves +TP_LOCALLAB_SPECIAL_TOOLTIP;Only for this RGB curve, disabled (or reduce effects) of Scope, mask...for example, if you want to have a negative effect. +TP_LOCALLAB_SPECCASE; Specific cases +TP_LOCALLAB_SPOTNAME;Control Spot # +TP_LOCALLAB_STD;Standard +TP_LOCALLAB_STR;Strength +TP_LOCALLAB_STRBL;Strength +TP_LOCALLAB_STREN;Compression Strength +TP_LOCALLAB_STRENG;Strength +TP_LOCALLAB_STRENGR;Strength +TP_LOCALLAB_STRENGTH;Noise +TP_LOCALLAB_STRGRID;Strength +TP_LOCALLAB_STRRETI_TOOLTIP;if Strength Retinex < 0.2 only Dehaze is enabled.\nif Strength Retinex >= 0.1 Dehaze is in luminance mode. +TP_LOCALLAB_STRUC;Structure +TP_LOCALLAB_STRUCCOL1;Structure Spot +TP_LOCALLAB_STRUCT_TOOLTIP;Use Sobel algorithm to take into account structure in shape detection.\nyou can have a preview by activating "mask and modifications - Show structure spot".\n\nCan be used in conjunction with masks (expert) structure, blur, wavelet to improve edge detection.\n\nNeeds maskless adjustments to be activated (lightness, exposure...) +TP_LOCALLAB_STRUCCOL;Structure +TP_LOCALLAB_STRUMASKCOL;Structure mask strength +TP_LOCALLAB_STRUMASK_TOOLTIP;Generate a structure mask with difference between surface areas and reliefs.\nIf structure mask as tool is enabled, this mask is used in addition to the other tools (gamma, slope, contrast curve ...) +TP_LOCALLAB_STYPE;Shape method +TP_LOCALLAB_STYPE_TOOLTIP;You can choose between:\nSymmetrical - left handle linked to right, top handle linked to bottom.\nIndependent - all handles are independent. +TP_LOCALLAB_SYM;Symmetrical (mouse) +TP_LOCALLAB_SYMSL;Symmetrical (mouse + sliders) +TP_LOCALLAB_TARGET_GRAY;Target Gray Point +TP_LOCALLAB_THRES;Threshold structure +TP_LOCALLAB_THRESDELTAE;Threshold ΔE-scope +TP_LOCALLAB_THRESRETI;Threshold +TP_LOCALLAB_THRESWAV;Balance Threshold +TP_LOCALLAB_TLABEL2;TM Effective Tm=%1 TM=%2 +TP_LOCALLAB_TLABEL;TM Datas Min=%1 Max=%2 Mean=%3 Sigma=%4 (Threshold) +TP_LOCALLAB_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map.\nYou can act on Threshold to normalize +TP_LOCALLAB_TM;Tone Mapping - Texture +TP_LOCALLAB_TM_MASK;Use transmission map +TP_LOCALLAB_TONEMAPESTOP_TOOLTIP;This parameter affects sensitivity to edges.\n The greater it is the more likely an illumination change is to be considered an "edge".\n If set to zero tone mapping will have an effect similar to unsharp masking. +TP_LOCALLAB_TONEMAPREWEI_TOOLTIP;In some cases tone mapping may result in a cartoonish appearance, and in some rare cases soft but wide halos may appear.\n Increasing the number of reweighting iterates will help fight some of these problems. +TP_LOCALLAB_TONEMASCALE_TOOLTIP;This control gives meaning to the difference between "local" and "global" contrast.\nThe greater it is the larger a detail needs to be in order to be boosted +TP_LOCALLAB_TONEMAPGAM_TOOLTIP;Gamma moves the action of tone-mapping to shadows or highlights. +TP_LOCALLAB_TOOLCOL;Structure mask as tool +TP_LOCALLAB_TONEMAP_TOOLTIP;Tone Mapping - main menu must be disabled +TP_LOCALLAB_TOOLMASK;Tools +TP_LOCALLAB_TRANSIT;Transition Gradient +TP_LOCALLAB_TRANSITGRAD;Transition differentiation XY +TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Changes the transition of the abscissa to that of the ordinate +TP_LOCALLAB_TRANSITVALUE;Transition value +TP_LOCALLAB_TRANSITWEAK;Transition weakening +TP_LOCALLAB_TRANSITWEAK_TOOLTIP;Adjust transition weakening : change smoothness process - 1 linear - 2 parabolic - 3 cubic - ^25.\nCan be used in conjunction with very low transition values to reduce defects (CBDL, Wavelet, Color & Light) +TP_LOCALLAB_TRANSIT_TOOLTIP;Adjust smoothness of transition between affected and unaffected areas, as a percentage of the "radius" +TP_LOCALLAB_TRANSMISSIONGAIN;Transmission gain +TP_LOCALLAB_TRANSMISSIONMAP;Transmission map +TP_LOCALLAB_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positives values (max).\nOrdinate: amplification or reduction.\nYou can act on this curve to change Transmission and reduce the artifacts +TP_LOCALLAB_USEMASK;Use mask +TP_LOCALLAB_VART;Variance (contrast) +TP_LOCALLAB_VIBRANCE;Vibrance - Warm & Cool +TP_LOCALLAB_VIS_TOOLTIP;Click to show/hide selected Control Spot.\nCtrl+click to show/hide all Control Spot. +TP_LOCALLAB_LIST_NAME;Add tool to current spot... +TP_LOCALLAB_LIST_TOOLTIP;Choose a tool and then its level of complexity "Normal" or "Expert".\nThe number reflects the place of the tool in the process of each RT-Spot +TP_LOCALLAB_COLOR_TOOLNAME;Color&Light (Defects) - 11 +TP_LOCALLAB_EXP_TOOLNAME;Exposure - Dynamic Range Compression - 10 +TP_LOCALLAB_SH_TOOLNAME;Shadows Highlight & Tone Equalizer - 5 +TP_LOCALLAB_VIB_TOOLNAME;Vibrance - Warm & Cool - 3 +TP_LOCALLAB_SOFT_TOOLNAME;Soft Light & Original Retinex - 6 +TP_LOCALLAB_BLUR_TOOLNAME;Smooth Blur Gain & Denoise - 1 +TP_LOCALLAB_TONE_TOOLNAME;Tone Mapping - 4 +TP_LOCALLAB_RET_TOOLNAME;Dehaze & Retinex - 9 +TP_LOCALLAB_SHARP_TOOLNAME;Sharpening - 8 +TP_LOCALLAB_LC_TOOLNAME;Local Constrast & Wavelet (Defects) - 7 +TP_LOCALLAB_CBDL_TOOLNAME;CBDL (Defects) - 2 +TP_LOCALLAB_LOG_TOOLNAME;Encoding log - 0 +TP_LOCALLAB_WAMASKCOL;Ψ Mask Wavelet level +TP_LOCALLAB_WARM;Warm - Cool & Color artifacts +TP_LOCALLAB_WARM_TOOLTIP;This slider use Ciecam algorithm and acts as White Balance, it can warm or cool the area selected.\nIt can also in some cases reduce color artifacts. +TP_LOCALLAB_WAV;Levels local contrast +TP_LOCALLAB_WAVMASK_TOOLTIP;Allows fine work on mask levels contrasts (structure) +TP_LOCALLAB_WAVBLUR_TOOLTIP;Performs a blur for each level of decomposition, as well as the residual image. +TP_LOCALLAB_WAVEDG;Local contrast +TP_LOCALLAB_WAVCOMP;Compression by Level +TP_LOCALLAB_WAVCOMP_TOOLTIP;Achive local contrast in function of the direction wavelet decomposition : horizontal, vertical, diagonal +TP_LOCALLAB_WAVCOMPRE;(un)Compression by Level +TP_LOCALLAB_WAVCOMPRE_TOOLTIP;Achieve a Tone-mapping or reduction local contrast by levels.\nOn abscissa levels +TP_LOCALLAB_WAVCON;Contrast by Level +TP_LOCALLAB_WAVCONTF_TOOLTIP;Similar to Contrast By Detail Levels : on abscissa levels. +TP_LOCALLAB_WAVDEN;Luminance denoise by level (0 1 2 + 3 and more) +TP_LOCALLAB_WASDEN_TOOLTIP;Denoise luminance for the 3 first levels (fine).\nThe right limit of the curve correspond to coarse : level 3 and beyond +TP_LOCALLAB_WAVE;Ψ Wavelet +TP_LOCALLAB_WAVEEDG_TOOLTIP;Achieves a sharpness taking into account the notion of edges wavelet.\nRequires that at least the first 4 levels are usable +TP_LOCALLAB_WAVGRAD_TOOLTIP;Graduated filter for Local contrast "luminance" +TP_LOCALLAB_WAVHIGH;Ψ Wavelet high +TP_LOCALLAB_WAVLEV;Blur by Level +TP_LOCALLAB_WAVLOW;Ψ Wavelet low +TP_LOCALLAB_WAVMASK;Ψ Mask Levels local contrast +TP_LOCALLAB_WAVMED;Ψ Wavelet normal +TP_LOCALLAB_WEDIANHI;Median Hi +TP_LOCALLAB_WHITE_EV;White Ev +TP_LOCALLAB_BLNOI_EXP;Blur & Noise +TP_LOCALLAB_DENOI_EXP;Denoise +TP_LOCAL_HEIGHT;Bottom +TP_LOCAL_HEIGHT_T;Top +TP_LOCAL_WIDTH;Right +TP_LOCAL_WIDTH_L;Left +TP_LOCRETI_METHOD_TOOLTIP;Low = Reinforce low light.\nUniform = Equalize action.\nHigh = Reinforce high light.\n TP_LOCALCONTRAST_AMOUNT;Amount TP_LOCALCONTRAST_DARKNESS;Darkness level TP_LOCALCONTRAST_LABEL;Local Contrast @@ -1899,6 +2909,10 @@ TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;Horizontal only on PDAF rows TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;Vertical TP_PREPROCESS_NO_FOUND;None found TP_PREPROCESS_PDAFLINESFILTER;PDAF lines filter +TP_PREPROCWB_LABEL;Preprocess White Balance +TP_PREPROCWB_MODE;Mode +TP_PREPROCWB_MODE_AUTO;Auto +TP_PREPROCWB_MODE_CAMERA;Camera TP_PRSHARPENING_LABEL;Post-Resize Sharpening TP_PRSHARPENING_TOOLTIP;Sharpens the image after resizing. Only works when the "Lanczos" resizing method is used. It is impossible to preview the effects of this tool. See RawPedia for usage instructions. TP_RAWCACORR_AUTO;Auto-correction @@ -2052,8 +3066,8 @@ TP_RETINEX_MAP_NONE;None TP_RETINEX_MEDIAN;Transmission median filter TP_RETINEX_METHOD;Method TP_RETINEX_METHOD_TOOLTIP;Low = Reinforce low light.\nUniform = Equalize action.\nHigh = Reinforce high light.\nHighlights = Remove magenta in highlights. -TP_RETINEX_MLABEL;Restored haze-free Min=%1 Max=%2 -TP_RETINEX_MLABEL_TOOLTIP;Should be near min=0 max=32768\nRestored image with no mixture. +TP_RETINEX_MLABEL;Restored data Min=%1 Max=%2 +TP_RETINEX_MLABEL_TOOLTIP;'Should be' near min=0 max=32768 (log mode) but others values are possible\nRestored image with no mixture. TP_RETINEX_NEIGHBOR;Radius TP_RETINEX_NEUTRAL;Reset TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. @@ -2066,11 +3080,11 @@ TP_RETINEX_SLOPE;Free gamma slope TP_RETINEX_STRENGTH;Strength TP_RETINEX_THRESHOLD;Threshold TP_RETINEX_THRESHOLD_TOOLTIP;Limits in/out.\nIn = image source,\nOut = image gauss. -TP_RETINEX_TLABEL;TM Min=%1 Max=%2 Mean=%3 Sigma=%4 -TP_RETINEX_TLABEL2;TM Tm=%1 TM=%2 -TP_RETINEX_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nMean and Sigma.\nTm=Min TM=Max of transmission map. +TP_RETINEX_TLABEL;TM Datas Min=%1 Max=%2 Mean=%3 Sigma=%4 +TP_RETINEX_TLABEL2;TM Effective Tm=%1 TM=%2 +TP_RETINEX_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map. TP_RETINEX_TRANF;Transmission -TP_RETINEX_TRANSMISSION;Transmission map +TP_RETINEX_TRANSMISSION;Transmission map TP_RETINEX_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positives values (max).\nOrdinate: amplification or reduction. TP_RETINEX_UNIFORM;Uniform TP_RETINEX_VARIANCE;Contrast @@ -2131,7 +3145,7 @@ TP_SOFTLIGHT_LABEL;Soft Light TP_SOFTLIGHT_STRENGTH;Strength TP_TM_FATTAL_AMOUNT;Amount TP_TM_FATTAL_ANCHOR;Anchor -TP_TM_FATTAL_LABEL;Dynamic Range Compression +TP_TM_FATTAL_LABEL;Dynamic Range Compression ƒ TP_TM_FATTAL_THRESHOLD;Detail TP_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift TP_VIBRANCE_CURVEEDITOR_SKINTONES;HH @@ -2177,14 +3191,14 @@ TP_WAVELET_BALANCE;Contrast balance d/v-h TP_WAVELET_BALANCE_TOOLTIP;Alters the balance between the wavelet directions: vertical-horizontal and diagonal.\nIf contrast, chroma or residual tone mapping are activated, the effect due to balance is amplified. TP_WAVELET_BALCHRO;Chrominance balance TP_WAVELET_BALCHRO_TOOLTIP;If enabled, the 'Contrast balance' curve or slider also modifies chroma balance. -TP_WAVELET_BALCHROM;Denoise Equalizer Blue-Red +TP_WAVELET_BALCHROM;Denoise Equalizer Blue-yellow Red-green TP_WAVELET_BALLUM;Denoise Equalizer White-Black TP_WAVELET_BANONE;None TP_WAVELET_BASLI;Slider TP_WAVELET_BATYPE;Contrast balance method TP_WAVELET_BLCURVE;Blur by levels TP_WAVELET_BLURFRAME;Blur -TP_WAVELET_BLUWAV;Damper +TP_WAVELET_BLUWAV;Attenuation Response TP_WAVELET_CBENAB;Toning and Color Balance TP_WAVELET_CB_TOOLTIP;For strong values product color-toning by combining it or not with levels decomposition 'toning'\nFor low values you can change the white balance of the background (sky, ...) without changing that of the front plane, generally more contrasted TP_WAVELET_CCURVE;Local contrast @@ -2214,10 +3228,12 @@ TP_WAVELET_CONTEDIT;'After' contrast curve TP_WAVELET_CONTFRAME;Contrast - Compression TP_WAVELET_CONTR;Gamut TP_WAVELET_CONTRA;Contrast +TP_WAVELET_CONTRASTEDIT;Finer - Coarser levels TP_WAVELET_CONTRAST_MINUS;Contrast - TP_WAVELET_CONTRAST_PLUS;Contrast + TP_WAVELET_CONTRA_TOOLTIP;Changes contrast of the residual image. TP_WAVELET_CTYPE;Chrominance control +TP_WAVELET_CURVEEDITOR_BL_TOOLTIP;Disabled if zoom > about 300% TP_WAVELET_CURVEEDITOR_CC_TOOLTIP;Modifies local contrast as a function of the original local contrast (abscissa).\nLow abscissa values represent small local contrast (real values about 10..20).\n50% abscissa represents average local contrast (real value about 100..300).\n66% abscissa represents standard deviation of local contrast (real value about 300..800).\n100% abscissa represents maximum local contrast (real value about 3000..8000). TP_WAVELET_CURVEEDITOR_CH;Contrast levels=f(Hue) TP_WAVELET_CURVEEDITOR_CH_TOOLTIP;Modifies each level's contrast as a function of hue.\nTake care not to overwrite changes made with the Gamut sub-tool's hue controls.\nThe curve will only have an effect when wavelet contrast level sliders are non-zero. @@ -2227,12 +3243,14 @@ TP_WAVELET_CURVEEDITOR_HH;HH TP_WAVELET_CURVEEDITOR_HH_TOOLTIP;Modifies the residual image's hue as a function of hue. TP_WAVELET_DALL;All directions TP_WAVELET_DAUB;Edge performance +TP_WAVELET_DAUBLOCAL;Wavelet Edge performance TP_WAVELET_DAUB2;D2 - low TP_WAVELET_DAUB4;D4 - standard TP_WAVELET_DAUB6;D6 - standard plus TP_WAVELET_DAUB10;D10 - medium TP_WAVELET_DAUB14;D14 - high TP_WAVELET_DAUB_TOOLTIP;Changes Daubechies coefficients:\nD4 = Standard,\nD14 = Often best performance, 10% more time-intensive.\n\nAffects edge detection as well as the general quality of the firsts levels. However the quality is not strictly related to this coefficient and can vary with images and uses. +TP_WAVELET_DIRFRAME;Directional contrast TP_WAVELET_DONE;Vertical TP_WAVELET_DTHR;Diagonal TP_WAVELET_DTWO;Horizontal @@ -2246,7 +3264,7 @@ TP_WAVELET_EDGEDETECTTHR;Threshold low (noise) TP_WAVELET_EDGEDETECTTHR2;Threshold high (detection) TP_WAVELET_EDGEDETECTTHR_TOOLTIP;This adjuster lets you target edge detection for example to avoid applying edge sharpness to fine details, such as noise in the sky. TP_WAVELET_EDGEDETECT_TOOLTIP;Moving the slider to the right increases edge sensitivity. This affects local contrast, edge settings and noise. -TP_WAVELET_EDEFFECT;Damper +TP_WAVELET_EDEFFECT;Attenuation Response TP_WAVELET_EDEFFECT_TOOLTIP;This slider controls how wide the range of contrast values are that receive the maximum effect from the tool.\nMaximum value (2.5) disabled the tool TP_WAVELET_EDGESENSI;Edge sensitivity TP_WAVELET_EDGREINF_TOOLTIP;Reinforce or reduce the action of the first level, do the opposite to the second level, and leave the rest unchanged. @@ -2258,10 +3276,12 @@ TP_WAVELET_EDSL;Threshold Sliders TP_WAVELET_EDTYPE;Local contrast method TP_WAVELET_EDVAL;Strength TP_WAVELET_FINAL;Final Touchup +TP_WAVELET_FINCFRAME;Final Local Contrast TP_WAVELET_FINEST;Finest -TP_WAVELET_HIGHLIGHT;Highlight luminance range +TP_WAVELET_HIGHLIGHT;Finer levels luminance range +TP_WAVELET_FINCOAR_TOOLTIP;The left (positive) part of the curve acts on the finer levels (increase).\nThe 2 points on the abscissa represent the respective action limits of finer and coarser levels 5 and 6 (default).\nThe right (negative) part of the curve acts on the coarser levels (increase).\nAvoid moving the left part of the curve with negative values. Avoid moving the right part of the curve with positives values TP_WAVELET_HS1;Whole luminance range -TP_WAVELET_HS2;Shadows/Highlights +TP_WAVELET_HS2;Selective luminance range TP_WAVELET_HUESKIN;Skin hue TP_WAVELET_HUESKIN_TOOLTIP;The bottom points set the beginning of the transition zone, and the upper points the end of it, where the effect is at its maximum.\n\nIf you need to move the area significantly, or if there are artifacts, then the white balance is incorrect. TP_WAVELET_HUESKY;Sky hue @@ -2271,10 +3291,10 @@ TP_WAVELET_ITER_TOOLTIP;Left: increase low levels and reduce high levels,\nRight TP_WAVELET_LABEL;Wavelet Levels TP_WAVELET_LARGEST;Coarsest TP_WAVELET_LEVCH;Chroma -TP_WAVELET_LEVDIR_ALL;All levels in all directions -TP_WAVELET_LEVDIR_INF;Below or equal the level +TP_WAVELET_LEVDIR_ALL;All levels, in all directions +TP_WAVELET_LEVDIR_INF;Finer details levels, with selected level TP_WAVELET_LEVDIR_ONE;One level -TP_WAVELET_LEVDIR_SUP;Above the level +TP_WAVELET_LEVDIR_SUP;Coarser details levels, without selected level TP_WAVELET_LEVELS;Wavelet levels TP_WAVELET_LEVELS_TOOLTIP;Choose the number of detail levels the image is to be decomposed into. More levels require more RAM and require a longer processing time. TP_WAVELET_LEVF;Contrast @@ -2285,7 +3305,7 @@ TP_WAVELET_LEVTWO;Level 3 TP_WAVELET_LEVZERO;Level 1 TP_WAVELET_LINKEDG;Link with Edge Sharpness' Strength TP_WAVELET_LIPST;Enhanced algoritm -TP_WAVELET_LOWLIGHT;Shadow luminance range +TP_WAVELET_LOWLIGHT;Coarser levels luminance range TP_WAVELET_LOWTHR_TOOLTIP;Prevents amplification of fine textures and noise TP_WAVELET_MEDGREINF;First level TP_WAVELET_MEDI;Reduce artifacts in blue sky @@ -2296,6 +3316,7 @@ TP_WAVELET_MERGEL;Merge Luma TP_WAVELET_NEUTRAL;Neutral TP_WAVELET_NOIS;Denoise TP_WAVELET_NOISE;Denoise and Refine +TP_WAVELET_NOISE_TOOLTIP;If level 4 luminance denoise superior to 20, mode Agressive is used.\nIf chrominance coarse superior to 20, mode Agressive is used. TP_WAVELET_NPHIGH;High TP_WAVELET_NPLOW;Low TP_WAVELET_NPNONE;None @@ -2304,16 +3325,19 @@ TP_WAVELET_NPTYPE_TOOLTIP;This algorithm uses the proximity of a pixel and eight TP_WAVELET_OLDSH;Algorithm using negatives values TP_WAVELET_OPACITY;Opacity Blue-Yellow TP_WAVELET_OPACITYW;Contrast balance d/v-h curve -TP_WAVELET_OPACITYWL;Final local contrast +TP_WAVELET_OPACITYWL;Local contrast TP_WAVELET_OPACITYWL_TOOLTIP;Modify the final local contrast at the end of the wavelet treatment.\n\nThe left side represents the smallest local contrast, progressing to the largest local contrast on the right. TP_WAVELET_PASTEL;Pastel chroma TP_WAVELET_PROC;Process +TP_WAVELET_PROTAB;Protection TP_WAVELET_RADIUS;Radius Shadows - Highlight +TP_WAVELET_RANGEAB;Range a and b % TP_WAVELET_RE1;Reinforced TP_WAVELET_RE2;Unchanged TP_WAVELET_RE3;Reduced TP_WAVELET_RESBLUR;Blur Luminance TP_WAVELET_RESBLURC;Blur Chroma +TP_WAVELET_RESBLUR_TOOLTIP;Disabled if zoom > about 500% TP_WAVELET_RESCHRO;Intensity TP_WAVELET_RESCON;Shadows TP_WAVELET_RESCONH;Highlights @@ -2323,8 +3347,9 @@ TP_WAVELET_SETTINGS;Wavelet Settings TP_WAVELET_SHA;Sharp mask TP_WAVELET_SHFRAME;Shadows/Highlights TP_WAVELET_SHOWMASK;Show wavelet 'mask' -TP_WAVELET_SIGMA;Damper -TP_WAVELET_SIGMA_TOOLTIP;The effect of the contrast sliders is stronger in medium contrast details, and weaker in high and low contrast details.\n With this slider you can control how quickly the effect dampens towards the extreme contrasts.\n The higher the slider is set, the wider the range of contrasts which will get a strong change, and the higher the risk to generate artifacts.\n The lower it is, the more pinpoint will the effect be applied to a narrow range of contrast values. +TP_WAVELET_SIGMA;Attenuation Response +TP_WAVELET_SIGMAFIN;Attenuation Response +TP_WAVELET_SIGMA_TOOLTIP;The effect of the contrast sliders is stronger in medium contrast details, and weaker in high and low contrast details.\n With this slider you can control how quickly the effect dampens towards the extreme contrasts.\n The higher the slider is set, the wider the range of contrasts which will get a strong change, and the higher the risk to generate artifacts.\n .The lower it is, the more the effect will be pinpointed towards a narrow range of contrast values TP_WAVELET_SKIN;Skin targetting/protection TP_WAVELET_SKIN_TOOLTIP;At -100 skin-tones are targetted.\nAt 0 all tones are treated equally.\nAt +100 skin-tones are protected while all other tones are affected. TP_WAVELET_SKY;Sky targetting/protection @@ -2334,10 +3359,10 @@ TP_WAVELET_STREN;Strength TP_WAVELET_STRENGTH;Strength TP_WAVELET_SUPE;Extra TP_WAVELET_THR;Shadows threshold -TP_WAVELET_THRESHOLD;Highlight levels -TP_WAVELET_THRESHOLD2;Shadow levels -TP_WAVELET_THRESHOLD2_TOOLTIP;Only levels between 9 and 9 minus the value will be affected by the shadow luminance range. Other levels will be fully treated. The highest level possible is limited by the highlight level value (9 minus highlight level value). -TP_WAVELET_THRESHOLD_TOOLTIP;Only levels beyond the chosen value will be affected by the highlight luminance range. Other levels will be fully treated. The chosen value here limits the highest possible value of the shadow levels. +TP_WAVELET_THRESHOLD;Finer levels +TP_WAVELET_THRESHOLD2;Coarser levels +TP_WAVELET_THRESHOLD_TOOLTIP;Only levels below and including the chosen value will be affected by the Highlight luminance range. +TP_WAVELET_THRESHOLD2_TOOLTIP;Only levels from the chosen value to the selected number of ‘wavelet levels’ will be affected by the Shadow luminance range. TP_WAVELET_THRESWAV;Balance Threshold TP_WAVELET_THRH;Highlights threshold TP_WAVELET_TILESBIG;Tiles @@ -2352,6 +3377,7 @@ TP_WAVELET_TMSTRENGTH;Compression strength TP_WAVELET_TMSTRENGTH_TOOLTIP;Control the strength of tone mapping or contrast compression of the residual image. TP_WAVELET_TMEDGS;Edge stopping TP_WAVELET_TON;Toning +TP_WAVELET_TONFRAME;Excluded Colors TP_WAVELET_TMTYPE;Compression method TP_WAVELET_USH;None TP_WAVELET_USHARP;Clarity method @@ -2359,11 +3385,11 @@ TP_WAVELET_USHARP_TOOLTIP;Origin : the source file is the file before Wavelet.\n TP_WAVELET_USH_TOOLTIP;If you select Sharp-mask, wavelet settings will be automatically positioned :\nBackground=black, Process=below, level=3...you can change level between 1 and 4.\n\nIf you select Clarity, wavelet settings will be automatically positioned :\nBackground=residual, Process=above, level=7..you can change level between 5 and 10 and wavelet levels. TP_WAVELET_WAVLOWTHR;Low contrast threshold TP_WAVELET_WAVOFFSET;Offset -TP_WAVELET_OFFSET_TOOLTIP;Offset modifies the balance between shadows and highlights.\nHigh values here will amplify the contrast change of the highlights, whereas low values will amplify the contrast change of the shadows.\nAlong with a low Damper value you will able to select the contrasts that will be enhanced. +TP_WAVELET_OFFSET_TOOLTIP;Offset modifies the balance between shadows and highlights.\nHigh values here will amplify the contrast change of the highlights, whereas low values will amplify the contrast change of the shadows.\nAlong with a low Attenuation Response value you will able to select the contrasts that will be enhanced. TP_WBALANCE_AUTO;Auto -TP_WBALANCE_AUTOITCGREEN;Auto iterate temperature correlation -TP_WBALANCE_AUTOOLD;Auto RGB grey -TP_WBALANCE_AUTO_HEADER;Autos +TP_WBALANCE_AUTOITCGREEN;Temperature correlation +TP_WBALANCE_AUTOOLD;RGB grey +TP_WBALANCE_AUTO_HEADER;Automatic TP_WBALANCE_CAMERA;Camera TP_WBALANCE_CLOUDY;Cloudy TP_WBALANCE_CUSTOM;Custom @@ -2405,8 +3431,8 @@ TP_WBALANCE_SOLUX41;Solux 4100K TP_WBALANCE_SOLUX47;Solux 4700K (vendor) TP_WBALANCE_SOLUX47_NG;Solux 4700K (Nat. Gallery) TP_WBALANCE_SPOTWB;Use the pipette to pick the white balance from a neutral patch in the preview. -TP_WBALANCE_STUDLABEL;Student Itcwb: %1 -TP_WBALANCE_STUDLABEL_TOOLTIP;Display calculated Student correlation\nThe lower the student value, the better the correlation\nValues below 0.002 are excellent\nValues below 0.005 are very good\nValues below 0.01 are good\nValues below 0.05 are good enough\nValues above 0.5 are poor\nVery good Student test results does not mean that the WB is good, if the illuminant is non-standard the results are erratic.\nStudent=1000 means the calculations were not restarted but results are probably goods, use previous results +TP_WBALANCE_STUDLABEL;Correlation factor: %1 +TP_WBALANCE_STUDLABEL_TOOLTIP;Display calculated Student correlation.\nLower values are better, where <0.005 is excellent,\n<0.01 is good, and >0.5 is poor.\nLow values do not mean that the white balance is good:\nif the illuminant is non-standard the results can be erratic.\nA value of 1000 means previous calculations are used and\nthe resultsare probably good. TP_WBALANCE_TEMPBIAS;AWB temperature bias TP_WBALANCE_TEMPBIAS_TOOLTIP;Allows to alter the computation of the "auto white balance"\nby biasing it towards warmer or cooler temperatures. The bias\nis expressed as a percentage of the computed temperature,\nso that the result is given by "computedTemp + computedTemp * bias". TP_WBALANCE_TEMPERATURE;Temperature diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index bdadc00db..76f0004ee 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -745,6 +745,7 @@ flowboxchild:selected { background-color: #363636; } +#LocallabToolPanel frame, #ExpanderBox frame, #ExpanderBox2 frame, #ExpanderBox3 frame { @@ -761,18 +762,22 @@ flowboxchild:selected { padding: 0.25em; } +#LocallabToolPanel frame > label, #LocallabToolPanel frame frame > label, #ExpanderBox frame > label, #ExpanderBox frame frame > label, #ExpanderBox2 frame > label, #ExpanderBox2 frame frame > label, #ExpanderBox3 frame > label, #ExpanderBox3 frame frame > label { margin-left: 7pt; margin-top: 0; } + +#LocallabToolPanel frame > box, #LocallabToolPanel frame frame > box, #LocallabToolPanel frame > grid, #LocallabToolPanel frame frame > grid, #ExpanderBox frame > box, #ExpanderBox frame frame > box, #ExpanderBox frame > grid, #ExpanderBox frame frame > grid, #ExpanderBox2 frame > box, #ExpanderBox2 frame frame > box, #ExpanderBox2 frame > grid, #ExpanderBox2 frame frame > grid, #ExpanderBox3 frame > box, #ExpanderBox3 frame frame > box, #ExpanderBox3 frame > grid, #ExpanderBox3 frame frame > grid { margin: 0.1666666666666666em; } +#LocallabToolPanel > box > checkbutton, #LocallabToolPanel > box > box, #LocallabToolPanel > grid > checkbutton, #LocallabToolPanel > box > grid, #LocallabToolPanel > grid > grid, #LocallabToolPanel frame > box > grid, #LocallabToolPanel frame > grid > grid, #LocallabToolPanel frame > grid > box, #ExpanderBox > box > checkbutton, #ExpanderBox > box > box, #ExpanderBox > grid > checkbutton, #ExpanderBox > box > grid, #ExpanderBox > grid > grid, #ExpanderBox frame > box > grid, #ExpanderBox frame > grid > grid, #ExpanderBox frame > grid > box, #ExpanderBox2 > box > checkbutton, #ExpanderBox2 > box > box, #ExpanderBox2 > grid > checkbutton, #ExpanderBox2 > box > grid, #ExpanderBox2 > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box, #ExpanderBox3 > box > checkbutton, #ExpanderBox3 > box > box, #ExpanderBox3 > grid > checkbutton, #ExpanderBox3 > box > grid, #ExpanderBox3 > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box { @@ -796,6 +801,7 @@ flowboxchild:selected { } /* Sub-tool (MyExpander) background */ +#LocallabToolPanel > box, #LocallabToolPanel > grid, #ExpanderBox2 > box, #ExpanderBox2 > grid { background-color: #3B3B3B; border: 0.0833333333333333em solid #2A2A2A; @@ -804,10 +810,12 @@ flowboxchild:selected { padding: 0.25em; } +#LocallabToolPanel drawingarea, #ExpanderBox2 drawingarea { background-color: #3B3B3B; } +#LocallabToolPanel frame > border, #ExpanderBox2 frame > border { background-color: #414141; border: 0.0833333333333333em solid #373737; @@ -816,10 +824,12 @@ flowboxchild:selected { padding: 0.25em; } +#LocallabToolPanel frame drawingarea, #ExpanderBox2 frame drawingarea { background-color: #414141; } +#LocallabToolPanel frame frame > border, #ExpanderBox2 frame frame > border { background-color: #474747; border: 0.0833333333333333em solid #3D3D3D; @@ -828,6 +838,7 @@ flowboxchild:selected { padding: 0.25em; } +#LocallabToolPanel frame frame drawingarea, #ExpanderBox2 frame frame drawingarea { background-color: #474747; } @@ -854,7 +865,7 @@ flowboxchild:selected { color: #D8D8D8; } -#ExpanderBox2 separator, #ExpanderBox3 separator { +#LocallabToolPanel separator, #ExpanderBox2 separator, #ExpanderBox3 separator { color: #292929; } diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 749c31210..d3634f3d0 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -117,7 +117,9 @@ set(RTENGINESOURCEFILES impulse_denoise.cc init.cc ipdehaze.cc + ipgrain.cc iplab2rgb.cc + iplocallab.cc iplabregions.cc iplocalcontrast.cc ipresize.cc diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 04459e88a..34ac2440b 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -916,7 +916,7 @@ void EdgePreservingDecomposition::CompressDynamicRange(float *Source, float Scal float temp; if(DetailBoost > 0.f) { - float betemp = expf(-(2.f - DetailBoost + 0.694f)) - 1.f; //0.694 = log(2) + float betemp = expf(-(2.f - DetailBoost + 0.693147f)) - 1.f; //0.694 = log(2) temp = 1.2f * xlogf( -betemp); } else { temp = CompressionExponent - 1.0f; @@ -939,7 +939,7 @@ void EdgePreservingDecomposition::CompressDynamicRange(float *Source, float Scal cev = xexpf(LVFU(Source[i]) + LVFU(u[i]) * (tempv)) - epsv; uev = xexpf(LVFU(u[i])) - epsv; sourcev = xexpf(LVFU(Source[i])) - epsv; - _mm_storeu_ps( &Source[i], cev + DetailBoostv * (sourcev - uev) ); + _mm_storeu_ps( &Source[i], cev + DetailBoostv * (sourcev - uev)); } } diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 894c72ce2..fca26987f 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -43,7 +43,6 @@ #include "procparams.h" #include "rt_math.h" #include "sleef.h" - #include "../rtgui/threadutils.h" #include "../rtgui/options.h" @@ -483,11 +482,9 @@ enum nrquality {QUALITY_STANDARD, QUALITY_HIGH}; void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagefloat * dst, Imagefloat * calclum, float * ch_M, float *max_r, float *max_b, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, const NoiseCurve & noiseLCurve, const NoiseCurve & noiseCCurve, float &nresi, float &highresi) { BENCHFUN -//#ifdef _DEBUG MyTime t1e, t2e; t1e.set(); -//#endif if (dnparams.luma == 0 && dnparams.chroma == 0 && !dnparams.median && !noiseLCurve && !noiseCCurve) { //nothing to do; copy src to dst or do nothing in case src == dst if (src != dst) { @@ -549,7 +546,7 @@ BENCHFUN const float noisevarL = (useNoiseLCurve && (denoiseMethodRgb || !isRAW)) ? SQR(((noiseluma + 1.f) / 125.f) * (10.f + (noiseluma + 1.f) / 25.f)) : SQR((noiseluma / 125.f) * (1.f + noiseluma / 25.f)); const bool denoiseLuminance = (noisevarL > 0.00001f); - //printf("NL=%f \n",noisevarL); +// printf("NL=%f \n",noisevarL); if (useNoiseLCurve || useNoiseCCurve) { int hei = calclum->getHeight(); int wid = calclum->getWidth(); @@ -955,13 +952,8 @@ BENCHFUN labdn->b[i1][j1] = B_ < 65535.f ? gamcurve[B_] : Color::gammanf(B_ / 65535.f, gam) * 32768.f; if (((i1 | j1) & 1) == 0) { - if (numTries == 1) { - noisevarlum[(i1 >> 1) * width2 + (j1 >> 1)] = useNoiseLCurve ? lumcalc[i >> 1][j >> 1] : noisevarL; - noisevarchrom[(i1 >> 1) * width2 + (j1 >> 1)] = useNoiseCCurve ? maxNoiseVarab * ccalc[i >> 1][j >> 1] : 1.f; - } else { - noisevarlum[(i1 >> 1) * width2 + (j1 >> 1)] = lumcalc[i >> 1][j >> 1]; - noisevarchrom[(i1 >> 1) * width2 + (j1 >> 1)] = ccalc[i >> 1][j >> 1]; - } + noisevarlum[(i1 >> 1) * width2 + (j1 >> 1)] = useNoiseLCurve ? lumcalc[i >> 1][j >> 1] : noisevarL; + noisevarchrom[(i1 >> 1) * width2 + (j1 >> 1)] = useNoiseCCurve ? maxNoiseVarab * ccalc[i >> 1][j >> 1] : 1.f; } //end chroma @@ -993,13 +985,8 @@ BENCHFUN labdn->b[i1][j1] = (Y - Z); if (((i1 | j1) & 1) == 0) { - if (numTries == 1) { - noisevarlum[(i1 >> 1)*width2 + (j1 >> 1)] = useNoiseLCurve ? lumcalc[i >> 1][j >> 1] : noisevarL; - noisevarchrom[(i1 >> 1)*width2 + (j1 >> 1)] = useNoiseCCurve ? maxNoiseVarab * ccalc[i >> 1][j >> 1] : 1.f; - } else { - noisevarlum[(i1 >> 1)*width2 + (j1 >> 1)] = lumcalc[i >> 1][j >> 1]; - noisevarchrom[(i1 >> 1)*width2 + (j1 >> 1)] = ccalc[i >> 1][j >> 1]; - } + noisevarlum[(i1 >> 1)*width2 + (j1 >> 1)] = useNoiseLCurve ? lumcalc[i >> 1][j >> 1] : noisevarL; + noisevarchrom[(i1 >> 1)*width2 + (j1 >> 1)] = useNoiseCCurve ? maxNoiseVarab * ccalc[i >> 1][j >> 1] : 1.f; } } } @@ -1111,9 +1098,6 @@ BENCHFUN } if (execwavelet) {//gain time if user choose only median sliders L <=1 slider chrom master < 1 - wavelet_decomposition* Ldecomp; - wavelet_decomposition* adecomp; - int levwav = 5; float maxreal = max(realred, realblue); @@ -1154,9 +1138,9 @@ BENCHFUN levwav = min(maxlev2, levwav); // if (settings->verbose) printf("levwavelet=%i noisevarA=%f noisevarB=%f \n",levwav, noisevarab_r, noisevarab_b); - Ldecomp = new wavelet_decomposition(labdn->L[0], labdn->W, labdn->H, levwav, 1, 1, max(1, denoiseNestedLevels)); + const std::unique_ptr Ldecomp(new wavelet_decomposition(labdn->L[0], labdn->W, labdn->H, levwav, 1, 1, max(1, denoiseNestedLevels))); - if (Ldecomp->memoryAllocationFailed) { + if (Ldecomp->memory_allocation_failed()) { memoryAllocationFailed = true; } @@ -1175,7 +1159,7 @@ BENCHFUN int Wlvl_L = Ldecomp->level_W(lvl); int Hlvl_L = Ldecomp->level_H(lvl); - float ** WavCoeffs_L = Ldecomp->level_coeffs(lvl); + const float* const* WavCoeffs_L = Ldecomp->level_coeffs(lvl); if (!denoiseMethodRgb) { madL[lvl][dir - 1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); @@ -1192,9 +1176,9 @@ BENCHFUN float chmaxresid = 0.f; float chmaxresidtemp = 0.f; - adecomp = new wavelet_decomposition(labdn->a[0], labdn->W, labdn->H, levwav, 1, 1, max(1, denoiseNestedLevels)); + std::unique_ptr adecomp(new wavelet_decomposition(labdn->a[0], labdn->W, labdn->H, levwav, 1, 1, max(1, denoiseNestedLevels))); - if (adecomp->memoryAllocationFailed) { + if (adecomp->memory_allocation_failed()) { memoryAllocationFailed = true; } @@ -1226,12 +1210,12 @@ BENCHFUN adecomp->reconstruct(labdn->a[0]); } - delete adecomp; + adecomp.reset(); if (!memoryAllocationFailed) { - wavelet_decomposition* bdecomp = new wavelet_decomposition(labdn->b[0], labdn->W, labdn->H, levwav, 1, 1, max(1, denoiseNestedLevels)); + std::unique_ptr bdecomp(new wavelet_decomposition(labdn->b[0], labdn->W, labdn->H, levwav, 1, 1, max(1, denoiseNestedLevels))); - if (bdecomp->memoryAllocationFailed) { + if (bdecomp->memory_allocation_failed()) { memoryAllocationFailed = true; } @@ -1266,7 +1250,7 @@ BENCHFUN bdecomp->reconstruct(labdn->b[0]); } - delete bdecomp; + bdecomp.reset(); if (!memoryAllocationFailed) { if (denoiseLuminance) { @@ -1306,8 +1290,6 @@ BENCHFUN } } } - - delete Ldecomp; } if (!memoryAllocationFailed) { @@ -2035,14 +2017,10 @@ BENCHFUN delete[] ccalc; } -//#ifdef _DEBUG if (settings->verbose) { t2e.set(); printf("Denoise performed in %d usec:\n", t2e.etime(t1e)); } - -//#endif - }//end of main RGB_denoise @@ -2194,7 +2172,7 @@ void ImProcFunctions::Noise_residualAB(const wavelet_decomposition &WaveletCoeff const int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); const int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl); - float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); + const float* const* WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); const float madC = SQR(denoiseMethodRgb ? MadRgb(WavCoeffs_ab[dir], Wlvl_ab * Hlvl_ab) : Mad(WavCoeffs_ab[dir], Wlvl_ab * Hlvl_ab)); resid += madC; @@ -2209,12 +2187,12 @@ void ImProcFunctions::Noise_residualAB(const wavelet_decomposition &WaveletCoeff chmaxresid = maxresid; } -bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels) +bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(wavelet_decomposition& WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels) { int maxlvl = min(WaveletCoeffs_L.maxlevel(), 5); const float eps = 0.01f; - if (edge == 1 || edge == 3 || edge == 4) { + if (edge == 1 || edge == 3 || edge == 4 || edge == 5) { maxlvl = 4; //for refine denoise edge wavelet } @@ -2260,7 +2238,7 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &W int Wlvl_L = WaveletCoeffs_L.level_W(lvl); int Hlvl_L = WaveletCoeffs_L.level_H(lvl); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); if (lvl == maxlvl - 1) { // int edge = 0; @@ -2286,7 +2264,7 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &W for (int i = 0; i < Hlvl_L * Wlvl_L; ++i) { nvl[i] = 0.f; } - if ((edge == 1 || edge == 2 || edge == 3) && vari) { + if ((edge == 1 || edge == 2 || edge == 3 || edge == 5) && vari) { // nvl = blurBuffer; // we need one buffer, but fortunately we don't have to allocate a new one because we can use blurBuffer if ((edge == 1 || edge == 3)) { for (int i = 0; i < Hlvl_L * Wlvl_L; ++i) { @@ -2294,7 +2272,7 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &W } } - if (edge == 2 || edge == 4) { + if (edge == 2 || edge == 4 || edge == 5) { for (int i = 0; i < Hlvl_L * Wlvl_L; ++i) { nvl[i] = vari[lvl] * SQR(noisevarlum[i]); } @@ -2392,8 +2370,7 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &W } -bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(const wavelet_decomposition &WaveletCoeffs_L, const wavelet_decomposition &WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels) - +bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(wavelet_decomposition& WaveletCoeffs_L, wavelet_decomposition& WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels) { int maxlvl = WaveletCoeffs_L.maxlevel(); @@ -2449,7 +2426,7 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(const wavelet_decomposition & // compute median absolute deviation (MAD) of detail coefficients as robust noise estimator int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl); - float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); + const float* const* WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); if (!denoiseMethodRgb) { madab[lvl][dir - 1] = SQR(Mad(WavCoeffs_ab[dir], Wlvl_ab * Hlvl_ab)); @@ -2468,8 +2445,8 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(const wavelet_decomposition & int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); - float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); + float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + float* const* WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); if (lvl == maxlvl - 1) { ShrinkAllAB(WaveletCoeffs_L, WaveletCoeffs_ab, buffer, lvl, dir, noisevarchrom, noisevar_ab, useNoiseCCurve, autoch, denoiseMethodRgb, madL[lvl], nullptr, 0, madab[lvl], true); @@ -2563,13 +2540,13 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(const wavelet_decomposition & } -bool ImProcFunctions::WaveletDenoiseAllL(const wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels)//mod JD +bool ImProcFunctions::WaveletDenoiseAllL(wavelet_decomposition& WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels)//mod JD { int maxlvl = min(WaveletCoeffs_L.maxlevel(), 5); - if (edge == 1 || edge == 3) { + if (edge == 1 || edge == 3 || edge == 5) { maxlvl = 4; //for refine denoise edge wavelet } @@ -2624,7 +2601,7 @@ bool ImProcFunctions::WaveletDenoiseAllL(const wavelet_decomposition &WaveletCoe } -bool ImProcFunctions::WaveletDenoiseAllAB(const wavelet_decomposition &WaveletCoeffs_L, const wavelet_decomposition &WaveletCoeffs_ab, +bool ImProcFunctions::WaveletDenoiseAllAB(wavelet_decomposition& WaveletCoeffs_L, wavelet_decomposition& WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels)//mod JD { @@ -2688,7 +2665,7 @@ bool ImProcFunctions::WaveletDenoiseAllAB(const wavelet_decomposition &WaveletCo -void ImProcFunctions::ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, float **buffer, int level, int dir, +void ImProcFunctions::ShrinkAllL(wavelet_decomposition& WaveletCoeffs_L, float **buffer, int level, int dir, float *noisevarlum, float * madL, float * vari, int edge) { @@ -2702,7 +2679,7 @@ void ImProcFunctions::ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, f const int W_L = WaveletCoeffs_L.level_W(level); const int H_L = WaveletCoeffs_L.level_H(level); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(level); + float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(level); const float mad_L = madL[dir - 1] ; const float levelFactor = mad_L * 5.f / static_cast(level + 1); @@ -2713,7 +2690,7 @@ void ImProcFunctions::ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, f nvl[i] = 0.f; } - if ((edge == 1 || edge == 2 || edge == 3) && vari) { + if ((edge == 1 || edge == 2 || edge == 3 || edge == 5) && vari) { // nvl = blurBuffer; // we need one buffer, but fortunately we don't have to allocate a new one because we can use blurBuffer if ((edge == 1 || edge == 3)) { for (int i = 0; i < W_L * H_L; ++i) { @@ -2721,7 +2698,7 @@ void ImProcFunctions::ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, f } } - if (edge == 2 || edge == 4) { + if (edge == 2 || edge == 4 || edge == 5) { for (int i = 0; i < W_L * H_L; ++i) { nvl[i] = vari[level] * SQR(noisevarlum[i]); } @@ -2779,7 +2756,7 @@ void ImProcFunctions::ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, f } -void ImProcFunctions::ShrinkAllAB(const wavelet_decomposition & WaveletCoeffs_L, const wavelet_decomposition & WaveletCoeffs_ab, float **buffer, int level, int dir, +void ImProcFunctions::ShrinkAllAB(wavelet_decomposition& WaveletCoeffs_L, wavelet_decomposition& WaveletCoeffs_ab, float **buffer, int level, int dir, float * noisevarchrom, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, float * madL, float * variC, int local, float * madaab, bool madCalculated) @@ -2798,8 +2775,8 @@ void ImProcFunctions::ShrinkAllAB(const wavelet_decomposition & WaveletCoeffs_L, int W_ab = WaveletCoeffs_ab.level_W(level); int H_ab = WaveletCoeffs_ab.level_H(level); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(level); - float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(level); + float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(level); + float* const* WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(level); float madab; float mad_L = madL[dir - 1]; @@ -2918,7 +2895,7 @@ void ImProcFunctions::ShrinkAllAB(const wavelet_decomposition & WaveletCoeffs_L, delete [] nvc; } -void ImProcFunctions::ShrinkAll_info(float ** WavCoeffs_a, float ** WavCoeffs_b, +void ImProcFunctions::ShrinkAll_info(const float* const* WavCoeffs_a, const float* const* WavCoeffs_b, int W_ab, int H_ab, float **noisevarlum, float **noisevarchrom, float **noisevarhue, float & chaut, int &Nb, float & redaut, float & blueaut, float & maxredaut, float & maxblueaut, float & minredaut, float & minblueaut, int schoice, int lvl, float & chromina, float & sigma, float & lumema, float & sigma_L, float & redyel, float & skinc, float & nsknc, float & maxchred, float & maxchblue, float & minchred, float & minchblue, int &nb, float & chau, float & chred, float & chblue, bool denoiseMethodRgb) @@ -3048,8 +3025,8 @@ void ImProcFunctions::WaveletDenoiseAll_info(int levwav, const wavelet_decomposi int Wlvl_ab = WaveletCoeffs_a.level_W(lvl); int Hlvl_ab = WaveletCoeffs_a.level_H(lvl); - float ** WavCoeffs_a = WaveletCoeffs_a.level_coeffs(lvl); - float ** WavCoeffs_b = WaveletCoeffs_b.level_coeffs(lvl); + const float* const* WavCoeffs_a = WaveletCoeffs_a.level_coeffs(lvl); + const float* const* WavCoeffs_b = WaveletCoeffs_b.level_coeffs(lvl); ShrinkAll_info(WavCoeffs_a, WavCoeffs_b, Wlvl_ab, Hlvl_ab, noisevarlum, noisevarchrom, noisevarhue, chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 5fc7d4062..6e686c2f1 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -430,6 +430,7 @@ Camera constants: { // Quality B, some intermediate ISO samples missing, LENR samples missing so White Levels not properly indicated, some aperture scaling missing "make_model": "Canon EOS 5D Mark IV", + "global_green_equilibration" : true, "dcraw_matrix": [ 6446,-366,-864,-4436,12204,2513,-952,2496,6348 ], // DNG_V9.7 D65 "raw_crop": [ 136, 42, 6740, 4500 ], // full size 6880x4544, official crop 148,54,6867,4533 "masked_areas": [ 54, 4, 4534, 132 ], @@ -1295,12 +1296,6 @@ Camera constants: "ranges": { "white": 16100 } }, - { // Quality C - "make_model": [ "FUJIFILM X100V", "FUJIFILM X-T4" ], - "dcraw_matrix": [ 13426,-6334,-1177,-4244,12136,2371,-580,1303,5980 ], // DNG_v12.2 D65 - "raw_crop": [ 0, 5, 6252, 4140 ] - }, - { // Quality C "make_model": "Fujifilm X10", "ranges": { "white": 3788 } @@ -1384,7 +1379,7 @@ Camera constants: }, { // Quality C, only raw crop - "make_model": [ "FUJIFILM X-T3", "FUJIFILM X-T30", "FUJIFILM X-PRO3" ], + "make_model": [ "FUJIFILM X-T3", "FUJIFILM X-T30", "FUJIFILM X-PRO3", "FUJIFILM X100V", "FUJIFILM X-T4" ], "dcraw_matrix": [ 13426,-6334,-1177,-4244,12136,2371,-580,1303,5980 ], // DNG_v11, standard_v2 d65 "raw_crop": [ 0, 5, 6252, 4176] }, diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc index d9a10900c..f9850189c 100644 --- a/rtengine/canon_cr3_decoder.cc +++ b/rtengine/canon_cr3_decoder.cc @@ -3042,11 +3042,11 @@ bool crxSetupImageData( void crxFreeImageData(CrxImage* img) { - CrxTile* tile = img->tiles; - const int nTiles = img->tileRows * img->tileCols; - if (img->tiles) { - for (std::int32_t curTile = 0; curTile < nTiles; curTile++, tile++) { + CrxTile* const tile = img->tiles; + const int nTiles = img->tileRows * img->tileCols; + + for (std::int32_t curTile = 0; curTile < nTiles; ++curTile) { if (tile[curTile].comps) { for (std::int32_t curPlane = 0; curPlane < img->nPlanes; ++curPlane) { crxFreeSubbandData(img, tile[curTile].comps + curPlane); diff --git a/rtengine/ciecam02.cc b/rtengine/ciecam02.cc index 208ed4366..c591bcb2c 100644 --- a/rtengine/ciecam02.cc +++ b/rtengine/ciecam02.cc @@ -22,11 +22,6 @@ #include #include "sleef.h" -#ifdef _DEBUG -#include "settings.h" -#include -#endif - #undef CLIPD #define CLIPD(a) ((a)>0.f?((a)<1.f?(a):1.f):0.f) #define MAXR(a,b) ((a) > (b) ? (a) : (b)) @@ -420,13 +415,6 @@ void Ciecam02::initcam1float (float yb, float pilotd, float f, float la, float x aw = achromatic_response_to_whitefloat ( xw, yw, zw, d, fl, nbb); wh = ( 4.0f / c ) * ( aw + 4.0f ) * pow_F ( fl, 0.25f ); pfl = pow_F ( fl, 0.25f ); -#ifdef _DEBUG - - if (settings->verbose) { - printf ("Source float d=%f aw=%f fl=%f wh=%f c=%f awc=%f\n", d, aw, fl, wh, c, (4.f / c) * (aw + 4.f)); - } - -#endif } void Ciecam02::initcam2float (float yb, float pilotd, float f, float la, float xw, float yw, float zw, float &n, float &d, float &nbb, float &ncb, @@ -445,13 +433,6 @@ void Ciecam02::initcam2float (float yb, float pilotd, float f, float la, float x nbb = ncb = 0.725f * pow_F ( 1.0f / n, 0.2f ); cz = 1.48f + sqrt ( n ); aw = achromatic_response_to_whitefloat ( xw, yw, zw, d, fl, nbb); -#ifdef _DEBUG - - if (settings->verbose) { - printf ("Viewing float d=%f aw=%f fl=%f n=%f\n", d, aw, fl, n); - } - -#endif } void Ciecam02::xyz2jchqms_ciecam02float ( float &J, float &C, float &h, float &Q, float &M, float &s, float aw, float fl, float wh, diff --git a/rtengine/color.cc b/rtengine/color.cc index 89be69e9d..11668451e 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -25,10 +25,6 @@ #include "opthelper.h" #include "iccstore.h" -#ifdef _DEBUG -#include "mytime.h" -#endif - using namespace std; namespace rtengine @@ -45,6 +41,9 @@ LUTf Color::igammatab_srgb; LUTf Color::igammatab_srgb1; LUTf Color::gammatab_srgb; LUTf Color::gammatab_srgb1; +LUTf Color::gammatab_srgb327; +LUTf Color::gammatab_bt709; +LUTf Color::igammatab_bt709; LUTf Color::denoiseGammaTab; LUTf Color::denoiseIGammaTab; @@ -103,20 +102,6 @@ LUTf Color::_10GY30, Color::_10GY40, Color::_10GY50, Color::_10GY60, Color::_10G LUTf Color::_75GY30, Color::_75GY40, Color::_75GY50, Color::_75GY60, Color::_75GY70, Color::_75GY80; LUTf Color::_5GY30, Color::_5GY40, Color::_5GY50, Color::_5GY60, Color::_5GY70, Color::_5GY80; -#ifdef _DEBUG -MunsellDebugInfo::MunsellDebugInfo() -{ - reinitValues(); -} -void MunsellDebugInfo::reinitValues() -{ - maxdhue[0] = maxdhue[1] = maxdhue[2] = maxdhue[3] = 0.0f; - maxdhuelum[0] = maxdhuelum[1] = maxdhuelum[2] = maxdhuelum[3] = 0.0f; - depass = depassLum = 0; -} -#endif - - void Color::init () { @@ -130,9 +115,12 @@ void Color::init () gammatabThumb(maxindex, 0); igammatab_srgb(maxindex, 0); + igammatab_bt709(maxindex, 0); igammatab_srgb1(maxindex, 0); gammatab_srgb(maxindex, 0); + gammatab_bt709(maxindex, 0); gammatab_srgb1(maxindex, 0); + gammatab_srgb327(32768, 0); denoiseGammaTab(maxindex, 0); denoiseIGammaTab(maxindex, 0); @@ -197,6 +185,18 @@ void Color::init () } #ifdef _OPENMP #pragma omp section +#endif + { + for (int i = 0; i < 32768; i++) + { + gammatab_srgb327[i] = gamma2(i / 32767.0); + } + + gammatab_srgb327 *= 32767.f; + // gamma2curve.share(gammatab_srgb, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); // shares the buffer with gammatab_srgb but has different clip flags + } +#ifdef _OPENMP + #pragma omp section #endif { for (int i = 0; i < maxindex; i++) @@ -206,6 +206,7 @@ void Color::init () igammatab_srgb *= 65535.f; } + #ifdef _OPENMP #pragma omp section #endif @@ -282,6 +283,22 @@ void Color::init () break; } +#ifdef _OPENMP + #pragma omp section +#endif + + for (int i = 0; i < maxindex; i++) { + gammatab_bt709[i] = 65535.0 * gamma709(i / 65535.0); + } + +#ifdef _OPENMP + #pragma omp section +#endif + + for (int i = 0; i < maxindex; i++) { + igammatab_bt709[i] = 65535.0 * igamma709(i / 65535.0); + } + #ifdef _OPENMP #pragma omp section #endif @@ -1421,15 +1438,7 @@ void Color::interpolateRGBColor (const float balance, const float r1, const floa Color::Lab2Lch(a_1, b_1, c1, h1); Lr = L1 / 327.68f; //for gamutlch //gamut control on r1 g1 b1 -#ifndef NDEBUG - bool neg = false; - bool more_rgb = false; - - //gamut control : Lab values are in gamut - Color::gamutLchonly(h1, Lr, c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); -#else Color::gamutLchonly(h1, Lr, c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); -#endif L1 = Lr * 327.68f; @@ -1440,14 +1449,7 @@ void Color::interpolateRGBColor (const float balance, const float r1, const floa Lr = L2 / 327.68f; //for gamutlch //gamut control on r2 g2 b2 -#ifndef NDEBUG - neg = false; - more_rgb = false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(h2, Lr, c2, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); -#else Color::gamutLchonly(h2, Lr, c2, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); -#endif L2 = Lr * 327.68f; // interpolating Lch values @@ -1477,15 +1479,8 @@ void Color::interpolateRGBColor (const float balance, const float r1, const floa // here I have put gamut control with gamutlchonly on final process Lr = L1 / 327.68f; //for gamutlch -#ifndef NDEBUG - neg = false; - more_rgb = false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(h1, Lr, c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); -#else //gamut control : Lab values are in gamut Color::gamutLchonly(h1, Lr, c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); -#endif //convert CH ==> ab L1 = Lr * 327.68f; @@ -2264,11 +2259,7 @@ void Color::transitred (const float HH, float const Chprov1, const float dred, c * float correctlum : correction Hue for luminance (brigtness, contrast,...) * MunsellDebugInfo* munsDbgInfo: (Debug target only) object to collect information. */ -#ifdef _DEBUG -void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHuechroma, float &correctlum, MunsellDebugInfo* munsDbgInfo) -#else void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHuechroma, float &correctlum) -#endif { bool contin1, contin2; @@ -2292,22 +2283,6 @@ void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, fl contin1 = contin2 = false; correctL = false; MunsellLch (Lprov1, HH, Chprov1, CC, correctionHue, zo, correctionHueLum, correctL); //munsell chroma correction -#ifdef _DEBUG - float absCorrectionHue = fabs(correctionHue); - - if(correctionHue != 0.0) { - int idx = zo - 1; - #pragma omp critical (maxdhue) - { - munsDbgInfo->maxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); - } - } - - if(absCorrectionHue > 0.45) - #pragma omp atomic - munsDbgInfo->depass++; //verify if no bug in calculation - -#endif correctionHuechroma = correctionHue; //preserve if(lumaMuns) { @@ -2339,46 +2314,11 @@ void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, fl if(contin1 && contin2) { correctlum = correctlumprov2 - correctlumprov; } - -#ifdef _DEBUG - float absCorrectLum = fabs(correctlum); - - if(correctlum != 0.0) { - int idx = zo - 1; - #pragma omp critical (maxdhuelum) - { - munsDbgInfo->maxdhuelum[idx] = MAX(munsDbgInfo->maxdhuelum[idx], absCorrectLum); - } - } - - if(absCorrectLum > 0.35) - #pragma omp atomic - munsDbgInfo->depassLum++; //verify if no bug in calculation - -#endif } } } } - } - -#ifdef _DEBUG - - if (correctlum < -0.35f) { - correctlum = -0.35f; - } else if(correctlum > 0.35f) { - correctlum = 0.35f; - } - - if (correctionHuechroma < -0.45f) { - correctionHuechroma = -0.45f; - } else if(correctionHuechroma > 0.45f) { - correctionHuechroma = 0.45f; - } - -#endif - } /* @@ -2437,17 +2377,10 @@ void Color::AllMunsellLch(float Lprov1, float HH, float Chprov1, float CC, float * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 */ -#ifdef _DEBUG -void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) -#else void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) -#endif { const float ClipLevel = 65535.0f; bool inGamut; -#ifdef _DEBUG - neg = false, more_rgb = false; -#endif float2 sincosval = xsincosf(HH); do { @@ -2471,10 +2404,6 @@ void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, flo // gamut control before saturation to put Lab values in future gamut, but not RGB if (R < 0.0f || G < 0.0f || B < 0.0f) { -#ifdef _DEBUG - neg = true; -#endif - if (Lprov1 < 0.1f) { Lprov1 = 0.1f; } @@ -2520,10 +2449,6 @@ void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, flo } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut -#ifdef _DEBUG - more_rgb = true; -#endif - if (Lprov1 > 99.999f) { Lprov1 = 99.98f; } @@ -2558,17 +2483,10 @@ void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, flo * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 */ -#ifdef _DEBUG -void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) -#else void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) -#endif { constexpr float ClipLevel = 65535.0f; bool inGamut; -#ifdef _DEBUG - neg = false, more_rgb = false; -#endif float ChprovSave = Chprov1; do { @@ -2590,9 +2508,6 @@ void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chpr // gamut control before saturation to put Lab values in future gamut, but not RGB if (R < 0.0f || G < 0.0f || B < 0.0f) { -#ifdef _DEBUG - neg = true; -#endif if (isnan(HH)) { float atemp = ChprovSave * sincosval.y * 327.68; @@ -2645,10 +2560,6 @@ void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chpr } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut -#ifdef _DEBUG - more_rgb = true; -#endif - if (Lprov1 > 99.999f) { Lprov1 = 99.98f; } @@ -2770,17 +2681,10 @@ void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chpr } -#ifdef _DEBUG -void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) -#else void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) -#endif { const float ClipLevel = 65535.0f; bool inGamut; -#ifdef _DEBUG - neg = false, more_rgb = false; -#endif do { inGamut = true; @@ -2804,10 +2708,6 @@ void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const // gamut control before saturation to put Lab values in future gamut, but not RGB if (R < 0.0f || G < 0.0f || B < 0.0f) { -#ifdef _DEBUG - neg = true; -#endif - if (Lprov1 < 0.01f) { Lprov1 = 0.01f; } @@ -2822,10 +2722,6 @@ void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut -#ifdef _DEBUG - more_rgb = true; -#endif - if (Lprov1 > 99.999f) { Lprov1 = 99.98f; } @@ -2865,17 +2761,6 @@ void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const */ void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, bool corMunsell, bool lumaMuns, bool isHLEnabled, bool gamut, const double wip[3][3]) { -#ifdef _DEBUG - MyTime t1e, t2e; - t1e.set(); - int negat = 0, moreRGB = 0; - MunsellDebugInfo* MunsDebugInfo = nullptr; - - if (corMunsell) { - MunsDebugInfo = new MunsellDebugInfo(); - } - -#endif float correctlum = 0.f; float correctionHuechroma = 0.f; #ifdef __SSE2__ @@ -2914,9 +2799,6 @@ void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, float2 sincosval; if(gamut) { -#ifdef _DEBUG - bool neg, more_rgb; -#endif // According to mathematical laws we can get the sin and cos of HH by simple operations float R, G, B; @@ -2929,23 +2811,7 @@ void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, } //gamut control : Lab values are in gamut -#ifdef _DEBUG - gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, isHLEnabled, 0.15f, 0.96f, neg, more_rgb); -#else gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, isHLEnabled, 0.15f, 0.96f); -#endif - -#ifdef _DEBUG - - if(neg) { - negat++; - } - - if(more_rgb) { - moreRGB++; - } - -#endif } labL[j] = Lprov1 * 327.68f; @@ -2953,12 +2819,7 @@ void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, correctlum = 0.f; if(corMunsell) -#ifdef _DEBUG - AllMunsellLch(lumaMuns, Lprov1, Loldd, HH, Chprov1, Coldd, correctionHuechroma, correctlum, MunsDebugInfo); - -#else AllMunsellLch(lumaMuns, Lprov1, Loldd, HH, Chprov1, Coldd, correctionHuechroma, correctlum); -#endif if(correctlum == 0.f && correctionHuechroma == 0.f) { if(!gamut) { @@ -2979,28 +2840,6 @@ void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, laba[j] = Chprov1 * sincosval.y * 327.68f; labb[j] = Chprov1 * sincosval.x * 327.68f; } - -#ifdef _DEBUG - t2e.set(); - - if (settings->verbose) { - printf("Color::LabGamutMunsell (correction performed in %d usec):\n", t2e.etime(t1e)); - 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=%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"); - } - } - - if (MunsDebugInfo) { - delete MunsDebugInfo; - } - -#endif - } /* @@ -3105,11 +2944,6 @@ void Color::SkinSat (float lum, float hue, float chrom, float &satreduc) */ void Color::initMunsell () { -#ifdef _DEBUG - MyTime t1e, t2e; - t1e.set(); -#endif - const int maxInd = 140; const int maxInd2 = 90; const int maxInd3 = 50; @@ -5710,14 +5544,6 @@ void Color::initMunsell () //printf("5GY %1.2f %1.2f %1.2f\n",_5GY80[44],_5GY80[84],_5GY80[125] ); -#ifdef _DEBUG - t2e.set(); - - if (settings->verbose) { - printf("Lutf Munsell %d usec\n", t2e.etime(t1e)); - } - -#endif } } diff --git a/rtengine/color.h b/rtengine/color.h index 045e062ad..55ef52e36 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -36,23 +36,6 @@ namespace rtengine typedef std::array GammaValues; -#ifdef _DEBUG - -class MunsellDebugInfo -{ -public: - float maxdhuelum[4]; - float maxdhue[4]; - unsigned int depass; - unsigned int depassLum; - - MunsellDebugInfo(); - void reinitValues(); -}; - -#endif - - class Color { @@ -162,12 +145,15 @@ public: static LUTf igammatab_srgb; static LUTf igammatab_srgb1; static LUTf gammatab_srgb; + static LUTf gammatab_srgb327; static LUTf gammatab_srgb1; + static LUTf gammatab_bt709; static LUTf denoiseGammaTab; static LUTf denoiseIGammaTab; static LUTf igammatab_24_17; + static LUTf igammatab_bt709; static LUTf gammatab_24_17a; static LUTf gammatab_13_2; static LUTf igammatab_13_2; @@ -1150,23 +1136,25 @@ public: } - /* +/* * @brief Get the gamma value for Gamma=2.2 Slope=4.5 * @param x red, green or blue channel's value [0 ; 1] * @return the gamma modified's value [0 ; 1] * +*/ static inline double gamma709 (double x) { return x <= 0.0176 ? x*4.5 : 1.0954*exp(log(x)/2.2)-0.0954; } - +/* * @brief Get the inverse gamma value for Gamma=2.2 Slope=4.5 * @param x red, green or blue channel's value [0 ; 1] * @return the inverse gamma modified's value [0 ; 1] * +*/ static inline double igamma709 (double x) { return x <= 0.0795 ? x/4.5 : exp(log((x+0.0954)/1.0954)*2.2); } - */ + @@ -1390,11 +1378,7 @@ public: * @param munsDbgInfo (Debug target only) object to collect information */ -#ifdef _DEBUG - static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum, MunsellDebugInfo* munsDbgInfo); -#else static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum); -#endif static void AllMunsellLch (float Lprov1, float HH, float Chprov1, float CC, float &correctionHueChroma); @@ -1419,15 +1403,9 @@ public: * @param neg (Debug target only) to calculate iterations for negatives values * @param moreRGB (Debug target only) to calculate iterations for values >65535 */ -#ifdef _DEBUG - static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef, bool &neg, bool &more_rgb); - static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef, bool &neg, bool &more_rgb); - static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef, bool &neg, bool &more_rgb); -#else static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef); static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef); static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef); -#endif static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &saturation, const float wip[3][3], bool isHLEnabled, float lowerCoef, float higherCoef); @@ -1494,6 +1472,57 @@ public: static void skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s); // static void scaleredcdbl ( float skinprot, float param, float limit, float HH, float deltaHH, float &scale,float &scaleext); + static inline void pregamutlab(float lum, float hue, float &chr) //big approximation to limit gamut (Prophoto) before good gamut procedure for locallab chroma, to avoid crash + { + if (lum >= 95.0f) { + if (hue > 1.5f && hue < 2.f) { + chr = 120.f; + } else if (hue > 0.7f && hue <= 1.5f) { + chr = 60.f; + } else { + chr = 40.f; + } + } else if (lum > 75.f) { + if (hue > 1.f && hue < 3.14f) { + chr = 130.f; + } else if (hue > -0.4f && hue <= 1.f) { + chr = 80.f; + } else if (hue > -3.15f && hue < -2.f) { + chr = 80.f; + } else { + chr = 60.f; + } + + } else if (lum > 35.f) { + chr = 100.f; + } else if (lum > 20.f) { + if (hue < -1.f && hue > -2.f) { + chr = 120.f; + } else { + chr = 80.f; + } + } else if (lum > 7.f) { + if (hue < -1.f && hue > -1.8f) { + chr = 120.f; + } else { + chr = 60.f; + } + + } else { + if (hue < -1.f && hue > -1.6f) { + chr = 80.f; + } else { + chr = 40.f; + } + + } + + // if(lum < 4.f) { + // chr = 0.1f; + // } + } + + static inline void SkinSatCbdl (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 2780fcc84..417476876 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -2898,15 +2898,15 @@ void ColorTemp::icieCAT02float(float Xw, float Yw, float Zw, float &iCAM02BB00, float D = adap / 2.; //white destination Wd : RT use always D50 - cam_dest[0] = INVCAT02[0][0] * whiteD50p[0] + INVCAT02[0][1] * whiteD50p[1] + INVCAT02[0][2] * whiteD50p[2]; //Cone reponse RoD + cam_dest[0] = INVCAT02[0][0] * whiteD50p[0] + INVCAT02[0][1] * whiteD50p[1] + INVCAT02[0][2] * whiteD50p[2]; //Cone response RoD cam_dest[1] = INVCAT02[1][0] * whiteD50p[0] + INVCAT02[1][1] * whiteD50p[1] + INVCAT02[1][2] * whiteD50p[2]; //GaD cam_dest[2] = INVCAT02[2][0] * whiteD50p[0] + INVCAT02[2][1] * whiteD50p[1] + INVCAT02[2][2] * whiteD50p[2]; //BeD //origin white Ws : A, D65, custom, etc. - cam_orig[0] = INVCAT02[0][0] * Xw + INVCAT02[0][1] * Yw + INVCAT02[0][2] * Zw; //Cone reponse RoS + cam_orig[0] = INVCAT02[0][0] * Xw + INVCAT02[0][1] * Yw + INVCAT02[0][2] * Zw; //Cone response RoS cam_orig[1] = INVCAT02[1][0] * Xw + INVCAT02[1][1] * Yw + INVCAT02[1][2] * Zw; cam_orig[2] = INVCAT02[2][0] * Xw + INVCAT02[2][1] * Yw + INVCAT02[2][2] * Zw; -// cam_orig[0] = CAT02[0][0] * Xw + CAT02[0][1] * Yw + CAT02[0][2] * Zw; //Cone reponse RoS +// cam_orig[0] = CAT02[0][0] * Xw + CAT02[0][1] * Yw + CAT02[0][2] * Zw; //Cone response RoS // cam_orig[1] = CAT02[1][0] * Xw + CAT02[1][1] * Yw + CAT02[1][2] * Zw; // cam_orig[2] = CAT02[2][0] * Xw + CAT02[2][1] * Yw + CAT02[2][2] * Zw; @@ -3624,7 +3624,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float double XX; double ZZ; } WbTxyz; - //probbaly can be "passed" with rawimagesource.cc but I don't know how to do. + //probably can be "passed" with rawimagesource.cc but I don't know how to do this. constexpr WbTxyz Txyz[118] = {//temperature Xwb Zwb 118 values - same table as in Rawimagesource.cc x wb and y wb are calculated after {2001., 1.273842, 0.145295}, {2101., 1.244008, 0.167533}, diff --git a/rtengine/cplx_wavelet_dec.h b/rtengine/cplx_wavelet_dec.h index c127a7adf..592bd2f37 100644 --- a/rtengine/cplx_wavelet_dec.h +++ b/rtengine/cplx_wavelet_dec.h @@ -33,37 +33,38 @@ class wavelet_decomposition : public NonCopyable { public: - - typedef float internal_type; - float *coeff0; - bool memoryAllocationFailed; - -private: - - static const int maxlevels = 10;//should be greater than any conceivable order of decimation - - int lvltot, subsamp; - int m_w, m_h;//dimensions - - int wavfilt_len, wavfilt_offset; - float *wavfilt_anal; - float *wavfilt_synth; - - - wavelet_level * wavelet_decomp[maxlevels]; - -public: + using internal_type = float; template wavelet_decomposition(E * src, int width, int height, int maxlvl, int subsampling, int skipcrop = 1, int numThreads = 1, int Daub4Len = 6); ~wavelet_decomposition(); - internal_type ** level_coeffs(int level) const + bool memory_allocation_failed() const + { + return memoryAllocationFailed; + } + + const internal_type* const* level_coeffs(int level) const { return wavelet_decomp[level]->subbands(); } + internal_type* const* level_coeffs(int level) + { + return wavelet_decomp[level]->subbands(); + } + + const internal_type* get_coeff0() const + { + return coeff0; + } + + internal_type* get_coeff0() + { + return coeff0; + } + int level_W(int level) const { return wavelet_decomp[level]->width(); @@ -88,13 +89,47 @@ public: { return subsamp; } + template void reconstruct(E * dst, const float blend = 1.f); + +private: + static const int maxlevels = 10; // should be greater than any conceivable order of decimation + + int lvltot; + int subsamp; + // Dimensions + int m_w; + int m_h; + + int wavfilt_len; + int wavfilt_offset; + internal_type* wavfilt_anal; + internal_type* wavfilt_synth; + + internal_type* coeff0; + bool memoryAllocationFailed; + + wavelet_level* wavelet_decomp[maxlevels]; }; template -wavelet_decomposition::wavelet_decomposition(E * src, int width, int height, int maxlvl, int subsampling, int skipcrop, int numThreads, int Daub4Len) - : coeff0(nullptr), memoryAllocationFailed(false), lvltot(0), subsamp(subsampling), m_w(width), m_h(height) +wavelet_decomposition::wavelet_decomposition( + E * src, + int width, + int height, + int maxlvl, + int subsampling, + int skipcrop, + int numThreads, + int Daub4Len +) : + lvltot(0), + subsamp(subsampling), + m_w(width), + m_h(height), + coeff0(nullptr), + memoryAllocationFailed(false) { //initialize wavelet filters @@ -135,6 +170,14 @@ wavelet_decomposition::wavelet_decomposition(E * src, int width, int height, int //n=0 lopass, n=1 hipass } } +/* } else if(wavfilt_len == 22) { + for (int n = 0; n < 2; n++) { + for (int i = 0; i < wavfilt_len; i++) { + wavfilt_anal[wavfilt_len * (n) + i] = Daub4_anal22[n][i]; + wavfilt_synth[wavfilt_len * (n) + i] = Daub4_anal22[n][wavfilt_len - 1 - i]; + //n=0 lopass, n=1 hipass + } + } */ } else if(wavfilt_len == 4) { for (int n = 0; n < 2; n++) { for (int i = 0; i < wavfilt_len; i++) { @@ -144,7 +187,7 @@ wavelet_decomposition::wavelet_decomposition(E * src, int width, int height, int } } } - +//printf("OK cplx\n"); // after coefficient rotation, data structure is: // wavelet_decomp[scale][channel={lo,hi1,hi2,hi3}][pixel_array] diff --git a/rtengine/cplx_wavelet_filter_coeffs.h b/rtengine/cplx_wavelet_filter_coeffs.h index 5d191e50c..3386be8d0 100644 --- a/rtengine/cplx_wavelet_filter_coeffs.h +++ b/rtengine/cplx_wavelet_filter_coeffs.h @@ -48,11 +48,14 @@ const float Daub4_anal16[2][16] ALIGNED16 = {//Daub 14 {0.f, 0.f, 0.055049715f, 0.28039564f, 0.515574245f, 0.33218624f, -0.10175691f, -0.158417505f, 0.05042335f, 0.057001725f, -0.026891225f, -0.01171997f, 0.008874895f, 0.0003037575f, -0.0012739524f, 0.0002501134f}, { -0.0002501134f, -0.0012739524f, -0.0003037575f, 0.008874895f, 0.01171997f , -0.026891225f, -0.057001725f, 0.05042335f, 0.158417505f, -0.10175691f, -0.33218624f, 0.515574245f, -0.28039564f, 0.055049715f, 0.f, 0.f} }; -/* -const double Daub4_anal22[2][22] ALIGNED16 = {//Daub 20 - {0., 0., 0.01885858, 0.13306109, 0.37278754, 0.48681406, 0.19881887, -0.1766681, -0.13855494, 0.09006372, 0.0658015, -0.05048328, -0.02082962, 0.0234849, 0.0025502185, -0.0075895, 0.0009866625, 0.0014088433, -0.00048497392, -0.0000823545, 0.00006617718, -0.000009379205}, - {0.000009379205, -0.00006617718, 0.0000823545, 0.00048497392, -0.0014088433, -0.0009866627, 0.0075895, -0.0025502185, -0.0234849, 0.02082962, 0.05048328, -0.0658015, -0.09006372, 0.13855494, 0.1766681, -0.19881887, -0.48681406, -0.37278754, -0.13306109, -0.01885858, 0., 0.} + +const float Daub4_anal22[2][22] ALIGNED16 = {//Daub 20 + {0.f, 0.f, 0.01885858f, 0.13306109f, 0.37278535f, 0.48681406f, 0.19881887f, -0.1766681f, -0.13855494f, 0.09006372f, 0.0658015f, -0.05048328f, -0.02082962f, + 0.0234849f, 0.002550218f, -0.0075895f, 0.0009866627f, 0.001408843f, -0.000484973f, -0.0000823545f, 0.0000661271f, -0.00000939f}, + {0.00000939f, -0.0000661271f, 0.0000823545f, 0.000484973f, -0.001408843f, -0.0009866627f, 0.0075895f, -0.002550218f, -0.0234849f, + 0.02082962f, 0.05048328f, -0.0658015f, -0.09006372f, 0.13855494f, 0.1766681f, -0.19881887f, -0.48681406f, -0.37278535f, -0.13306109f, -0.01885858f, 0.f, 0.f} }; -*/ + +// if necessary ?? we can add D20 !! } diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 14711c730..7f74467be 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -39,7 +39,6 @@ using namespace std; namespace rtengine { - bool sanitizeCurve(std::vector& curve) { // A curve is valid under one of the following conditions: @@ -47,19 +46,19 @@ bool sanitizeCurve(std::vector& curve) // 2) Number of curve entries is > 3 and odd // 3) curve[0] == DCT_Parametric and curve size is >= 8 and curve[1] .. curve[3] are ordered ascending and are distinct if (curve.empty()) { - curve.push_back (DCT_Linear); + curve.push_back(DCT_Linear); return true; - } else if(curve.size() == 1 && curve[0] != DCT_Linear) { + } else if (curve.size() == 1 && curve[0] != DCT_Linear) { curve[0] = DCT_Linear; return true; - } else if((curve.size() % 2 == 0 || curve.size() < 5) && curve[0] != DCT_Parametric) { + } else if ((curve.size() % 2 == 0 || curve.size() < 5) && curve[0] != DCT_Parametric) { curve.clear(); - curve.push_back (DCT_Linear); + curve.push_back(DCT_Linear); return true; - } else if(curve[0] == DCT_Parametric) { + } else if (curve[0] == DCT_Parametric) { if (curve.size() < 8) { curve.clear(); - curve.push_back (DCT_Linear); + curve.push_back(DCT_Linear); return true; } else { // curve[1] to curve[3] must be ordered ascending and distinct @@ -73,12 +72,13 @@ bool sanitizeCurve(std::vector& curve) } } } + return false; } -Curve::Curve () : N(0), ppn(0), x(nullptr), y(nullptr), mc(0.0), mfc(0.0), msc(0.0), mhc(0.0), hashSize(1000 /* has to be initialized to the maximum value */), 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) {} +Curve::Curve() : N(0), ppn(0), x(nullptr), y(nullptr), mc(0.0), mfc(0.0), msc(0.0), mhc(0.0), hashSize(1000 /* has to be initialized to the maximum value */), 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) {} -void Curve::AddPolygons () +void Curve::AddPolygons() { if (firstPointIncluded) { poly_x.push_back(x1); @@ -93,8 +93,8 @@ void Curve::AddPolygons () double tr2t = tr * 2 * t; // adding a point to the polyline - poly_x.push_back( tr2 * x1 + tr2t * x2 + t2 * x3); - poly_y.push_back( tr2 * y1 + tr2t * y2 + t2 * y3); + poly_x.push_back(tr2 * x1 + tr2t * x2 + t2 * x3); + poly_y.push_back(tr2 * y1 + tr2t * y2 + t2 * y3); } // adding the last point of the sub-curve @@ -102,11 +102,11 @@ void Curve::AddPolygons () poly_y.push_back(y3); } -void Curve::fillDyByDx () +void Curve::fillDyByDx() { dyByDx.resize(poly_x.size() - 1); - for(unsigned int i = 0; i < poly_x.size() - 1; i++) { + for (unsigned int i = 0; i < poly_x.size() - 1; i++) { double dx = poly_x[i + 1] - poly_x[i]; double dy = poly_y[i + 1] - poly_y[i]; dyByDx[i] = dy / dx; @@ -123,7 +123,7 @@ void Curve::fillHash() double milestone = 0.; for (unsigned short i = 0; i < (hashSize + 1);) { - while(poly_x[polyIter] <= milestone) { + while (poly_x[polyIter] <= milestone) { ++polyIter; } @@ -136,7 +136,7 @@ void Curve::fillHash() polyIter = 0; for (unsigned int i = 0; i < hashSize + 1u;) { - while(poly_x[polyIter] < (milestone + increment)) { + while (poly_x[polyIter] < (milestone + increment)) { ++polyIter; } @@ -173,7 +173,7 @@ void Curve::fillHash() * This method return the number of control points of a curve. Not suitable for parametric curves. * @return number of control points of the curve. 0 will be sent back for Parametric curves */ -int Curve::getSize () const +int Curve::getSize() const { return N; } @@ -204,11 +204,11 @@ void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool nee { if (needed) { - for (int i = 0; i <= 0xffff; i += i < 0xffff - skip ? skip : 1 ) { + for (int i = 0; i <= 0xffff; i += i < 0xffff - skip ? skip : 1) { // change to [0,1] range float val = (float)i / 65535.f; // apply custom/parametric/NURBS curve, if any - val = diagCurve->getVal (val); + val = diagCurve->getVal(val); // store result in a temporary array outCurve[i] = val; } @@ -218,8 +218,8 @@ void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool nee float skipmul = 1.f / (float) skip; for (int i = 0; i <= 0x10000 - skip; i += skip) { - for(int j = 1; j < skip; j++) { - outCurve[i + j] = ( outCurve[i] * (skip - j) + outCurve[i + skip] * j ) * skipmul; + for (int j = 1; j < skip; j++) { + outCurve[i + j] = (outCurve[i] * (skip - j) + outCurve[i + skip] * j) * skipmul; } } } @@ -230,7 +230,7 @@ void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool nee } } -void CurveFactory::curveLightBrightColor (const std::vector& curvePoints1, const std::vector& curvePoints2, const std::vector& curvePoints3, +void CurveFactory::curveLightBrightColor(const std::vector& curvePoints1, const std::vector& curvePoints2, const std::vector& curvePoints3, const LUTu & histogram, LUTu & outBeforeCCurveHistogram,//for Luminance const LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma ColorAppearance & customColCurve1, ColorAppearance & customColCurve2, ColorAppearance & customColCurve3, int skip) @@ -289,9 +289,9 @@ void CurveFactory::curveLightBrightColor (const std::vector& curvePoints } } -void CurveFactory::curveBW ( const std::vector& curvePointsbw, const std::vector& curvePointsbw2, - const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance - ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) +void CurveFactory::curveBW(const std::vector& curvePointsbw, const std::vector& curvePointsbw2, + const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance + ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) { const float gamma_ = Color::sRGBGammaCurve; @@ -319,7 +319,7 @@ void CurveFactory::curveBW ( const std::vector& curvePointsbw, const std if (!curvePointsbw.empty() && curvePointsbw[0] > DCT_Linear && curvePointsbw[0] < DCT_Unchanged) { DiagonalCurve tcurve(curvePointsbw, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogrambw ) { + if (outBeforeCCurveHistogrambw) { histNeeded = true; } @@ -336,13 +336,13 @@ void CurveFactory::curveBW ( const std::vector& curvePointsbw, const std } // add curve Lab : C=f(L) -void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip) +void CurveFactory::curveCL(bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip) { clcutili = false; std::unique_ptr dCurve; if (!clcurvePoints.empty() && clcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(clcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(clcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { clcutili = true; @@ -352,7 +352,7 @@ void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurve fillCurveArray(dCurve.get(), clCurve, skip, clcutili); } -void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) +void CurveFactory::mapcurve(bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; std::unique_ptr dCurve; @@ -360,7 +360,7 @@ void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& m bool histNeeded = false; if (!mapcurvePoints.empty() && mapcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(mapcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(mapcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCurveHistogram) { histNeeded = true; @@ -379,7 +379,7 @@ void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& m fillCurveArray(dCurve.get(), mapcurve, skip, needed); } -void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) +void CurveFactory::curveDehaContL(bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; std::unique_ptr dCurve; @@ -387,7 +387,7 @@ void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector(new DiagonalCurve(dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCurveHistogram) { histNeeded = true; @@ -407,13 +407,13 @@ void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve, /*LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip) +void CurveFactory::curveWavContL(bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve, /*LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip) { bool needed = false; std::unique_ptr dCurve; if (!wavclcurvePoints.empty() && wavclcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(wavclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(wavclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { needed = true; @@ -425,13 +425,13 @@ void CurveFactory::curveWavContL ( bool & wavcontlutili, const std::vector& curvePoints, LUTf & ToningCurve, int skip) +void CurveFactory::curveToning(const std::vector& curvePoints, LUTf & ToningCurve, int skip) { bool needed = false; std::unique_ptr dCurve; if (!curvePoints.empty() && curvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { needed = true; @@ -441,12 +441,294 @@ void CurveFactory::curveToning ( const std::vector& curvePoints, LUTf & fillCurveArray(dCurve.get(), ToningCurve, skip, needed); } +void CurveFactory::curveLocal(bool & locallutili, const std::vector& curvePoints, LUTf & LocalLCurve, int skip) +{ + bool needed = false; + std::unique_ptr dCurve; + + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + + if (dCurve && !dCurve->isIdentity()) { + needed = true; + locallutili = true; + } + } + + fillCurveArray(dCurve.get(), LocalLCurve, skip, needed); + //LocalLCurve.dump("wav"); + +} + +void CurveFactory::curveCCLocal(bool & localcutili, const std::vector& curvePoints, LUTf & LocalCCurve, int skip) +{ + bool needed = false; + std::unique_ptr dCurve; + + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + + if (dCurve && !dCurve->isIdentity()) { + needed = true; + localcutili = true; + } + } + + fillCurveArray(dCurve.get(), LocalCCurve, skip, needed); + //LocalLCurve.dump("wav"); + +} + +void CurveFactory::curveskLocal(bool & localskutili, const std::vector& curvePoints, LUTf & LocalskCurve, int skip) +{ + bool needed = false; + std::unique_ptr dCurve; + +// if (localskutili && !curvePoints.empty() && curvePoints[0] != 0) { + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + + if (dCurve && !dCurve->isIdentity()) { + needed = true; + localskutili = true; + } + } + + fillCurveArray(dCurve.get(), LocalskCurve, skip, needed); + +} + +void CurveFactory::curveexLocal(bool & localexutili, const std::vector& curvePoints, LUTf & LocalexCurve, int skip) +{ + bool needed = false; + std::unique_ptr dCurve; + +// if (localexutili && !curvePoints.empty() && curvePoints[0] != 0) { + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + + if (dCurve && !dCurve->isIdentity()) { + needed = true; + localexutili = true; + } + } + + fillCurveArray(dCurve.get(), LocalexCurve, skip, needed); + +} + +void CurveFactory::curvemaskLocal(bool & localmaskutili, const std::vector& curvePoints, LUTf & LocalmaskCurve, int skip) +{ + bool needed = false; + std::unique_ptr dCurve; + +// if (localexutili && !curvePoints.empty() && curvePoints[0] != 0) { + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + + if (dCurve && !dCurve->isIdentity()) { + needed = true; + localmaskutili = true; + } + } + + fillCurveArray(dCurve.get(), LocalmaskCurve, skip, needed); + +} + + + +void CurveFactory::localLCurve(double br, double contr, /*const std::vector& curvePoints,*/ + LUTu & histogram, LUTf & outCurve, + int skip, bool & utili) +{ + + // curve without contrast + LUTf dcurve(65536, 0); + + // clear array that stores histogram valid before applying the custom curve + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // check if brightness curve is needed + if (br > 0.00001 || br < -0.00001) { + utili = true; + + std::vector brightcurvePoints; + brightcurvePoints.resize(9); + brightcurvePoints.at(0) = double (DCT_NURBS); + + brightcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + brightcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range + + if (br > 0) { + brightcurvePoints.at(3) = 0.1; // toe point + brightcurvePoints.at(4) = 0.1 + br / 150.0; //value at toe point + + brightcurvePoints.at(5) = 0.7; // shoulder point + brightcurvePoints.at(6) = min(1.0, 0.7 + br / 300.0); //value at shoulder point + } else { + brightcurvePoints.at(3) = 0.1 - br / 150.0; // toe point + brightcurvePoints.at(4) = 0.1; // value at toe point + + brightcurvePoints.at(5) = min(1.0, 0.7 - br / 300.0); // shoulder point + brightcurvePoints.at(6) = 0.7; // value at shoulder point + } + + brightcurvePoints.at(7) = 1.; // white point + brightcurvePoints.at(8) = 1.; // value at white point + + DiagonalCurve* brightcurve = new DiagonalCurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // Applying brightness curve + for (int i = 0; i < 32768; i++) { // L values range up to 32767, higher values are for highlight overflow + + // change to [0,1] range + float val = (float)i / 32767.0; + + // apply brightness curve + val = brightcurve->getVal(val); + + // store result in a temporary array + dcurve[i] = val; + } + + delete brightcurve; + } else { + for (int i = 0; i < 32768; i++) { // L values range up to 32767, higher values are for highlight overflow + // set the identity curve in the temporary array + dcurve[i] = (float)i / 32767.0; + } + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // check if contrast curve is needed + if (contr > 0.00001 || contr < -0.00001) { + utili = true; + + DiagonalCurve* contrastcurve = NULL; + + // compute mean luminance of the image with the curve applied + int sum = 0; + float avg = 0; + + //float sqavg = 0; + for (int i = 0; i < 32768; i++) { + avg += dcurve[i] * histogram[i]; + //sqavg += dcurve[i]*dcurve[i] * histogram[i]; + sum += histogram[i]; + } + + if (sum) { + avg /= sum; + //sqavg /= sum; + //float stddev = sqrt(sqavg-avg*avg); + // printf("avg=%f\n",avg); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + std::vector contrastcurvePoints; + contrastcurvePoints.resize(9); + contrastcurvePoints.at(0) = double (DCT_NURBS); + + contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range + + contrastcurvePoints.at(3) = avg - avg * (0.6 - contr / 250.0); // toe point + contrastcurvePoints.at(4) = avg - avg * (0.6 + contr / 250.0); // value at toe point + + contrastcurvePoints.at(5) = avg + (1 - avg) * (0.6 - contr / 250.0); // shoulder point + contrastcurvePoints.at(6) = avg + (1 - avg) * (0.6 + contr / 250.0); // value at shoulder point + + contrastcurvePoints.at(7) = 1.; // white point + contrastcurvePoints.at(8) = 1.; // value at white point + + contrastcurve = new DiagonalCurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } else { + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // sum has an invalid value (next to 0, producing a division by zero, so we create a fake contrast curve, producing a white image + std::vector contrastcurvePoints; + contrastcurvePoints.resize(5); + contrastcurvePoints.at(0) = double (DCT_NURBS); + + contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 1.; // black point. Value in [0 ; 1] range + + contrastcurvePoints.at(3) = 1.; // white point + contrastcurvePoints.at(4) = 1.; // value at white point + + contrastcurve = new DiagonalCurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } + + // apply contrast enhancement + for (int i = 0; i < 32768; i++) { + dcurve[i] = contrastcurve->getVal(dcurve[i]); + } + + delete contrastcurve; + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // create a curve if needed + /* DiagonalCurve* tcurve = NULL; + bool histNeeded = false; + if (!curvePoints.empty() && curvePoints[0]!=0) { + tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip); + } + if (tcurve && tcurve->isIdentity()) { + delete tcurve; + tcurve = NULL; + } + + if (tcurve) { + utili=true;//if active + + // L values go up to 32767, last stop is for highlight overflow + for (int i=0; i<32768; i++) { + float val; + // apply custom/parametric/NURBS curve, if any + val = tcurve->getVal (dcurve[i]); + + outCurve[i] = (32767.0 * val); + } + } + else + */ + { + // Skip the slow getval method if no curve is used (or an identity curve) + // L values go up to 32767, last stop is for highlight overflow + for (int i = 0; i < 32768; i++) { + outCurve[i] = 32767.0 * dcurve[i]; + } + } + + for (int i = 32768; i < 65536; i++) { + outCurve[i] = (float)i; + } + + // if (tcurve) + // delete tcurve; + +} + + + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutili, bool & cclutili, - const std::vector& acurvePoints, const std::vector& bcurvePoints, const std::vector& cccurvePoints, - const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, - int skip) +void CurveFactory::complexsgnCurve(bool & autili, bool & butili, bool & ccutili, bool & cclutili, + const std::vector& acurvePoints, const std::vector& bcurvePoints, const std::vector& cccurvePoints, + const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, + int skip) { autili = butili = ccutili = cclutili = false; @@ -454,7 +736,7 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil // create a curve if needed if (!acurvePoints.empty() && acurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(acurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(acurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { autili = true; @@ -468,7 +750,7 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil //----------------------------------------------------- if (!bcurvePoints.empty() && bcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(bcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(bcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { butili = true; @@ -482,7 +764,7 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil //----------------------------------------------- if (!cccurvePoints.empty() && cccurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(cccurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(cccurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { ccutili = true; @@ -496,7 +778,7 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil //---------------------------- if (!lccurvePoints.empty() && lccurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(lccurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = std::unique_ptr (new DiagonalCurve(lccurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { cclutili = true; @@ -522,13 +804,14 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou // the curve shapes are defined in sRGB gamma, but the output curves will operate on linear floating point data, // hence we do both forward and inverse gamma conversions here. const float gamma_ = Color::sRGBGammaCurve; - const float start = expf(gamma_ * logf( -0.055 / ((1.0 / gamma_ - 1.0) * 1.055 ))); - const float slope = 1.055 * powf (start, 1.0 / gamma_ - 1) - 0.055 / start; + const float start = expf(gamma_ * logf(-0.055 / ((1.0 / gamma_ - 1.0) * 1.055))); + const float slope = 1.055 * powf(start, 1.0 / gamma_ - 1) - 0.055 / start; const float mul = 1.055; const float add = 0.055; + // a: slope of the curve, black: starting point at the x axis - const float a = powf (2.0, ecomp); + const float a = powf(2.0, ecomp); // clear array that stores histogram valid before applying the custom curve outBeforeCCurveHistogram.clear(); @@ -548,14 +831,14 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou brightcurvePoints[1] = 0.; //black point. Value in [0 ; 1] range brightcurvePoints[2] = 0.; //black point. Value in [0 ; 1] range - if(br > 0) { + if (br > 0) { brightcurvePoints[3] = 0.1; //toe point brightcurvePoints[4] = 0.1 + br / 150.0; //value at toe point brightcurvePoints[5] = 0.7; //shoulder point - brightcurvePoints[6] = min(1.0, 0.7 + br / 300.0); //value at shoulder point + brightcurvePoints[6] = min(1.0, 0.7 + br / 300.0); //value at shoulder point } else { - brightcurvePoints[3] = max(0.0, 0.1 - br / 150.0); //toe point + brightcurvePoints[3] = max(0.0, 0.1 - br / 150.0); //toe point brightcurvePoints[4] = 0.1; //value at toe point brightcurvePoints[5] = 0.7 - br / 300.0; //shoulder point @@ -565,12 +848,12 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou brightcurvePoints[7] = 1.; // white point brightcurvePoints[8] = 1.; // value at white point - brightcurve = std::unique_ptr(new DiagonalCurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + brightcurve = std::unique_ptr (new DiagonalCurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip)); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - hlCurve.setClip(LUT_CLIP_BELOW); // used LUT_CLIP_BELOW, because we want to have a baseline of 2^expcomp in this curve. If we don't clip the lut we get wrong values, see Issue 2621 #14 for details + hlCurve.setClip(LUT_CLIP_BELOW); // used LUT_CLIP_BELOW, because we want to have a baseline of 2^expcomp in this curve. If we don't clip the lut we get wrong values, see Issue 2621 #14 for details float exp_scale = a; float scale = 65536.0; float comp = (max(0.0, ecomp) + 1.0) * hlcompr / 100.0; @@ -586,11 +869,11 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou #ifdef __SSE2__ int i = shoulder + 1; - if(i & 1) { // original formula, slower than optimized formulas below but only used once or none, so I let it as is for reference + if (i & 1) { // original formula, slower than optimized formulas below but only used once or none, so I let it as is for reference // change to [0,1] range float val = (float)i - shoulder; float R = val * comp / (scalemshoulder); - hlCurve[i] = xlog(1.0 + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + hlCurve[i] = xlog(1.0 + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision i++; } @@ -615,7 +898,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou for (int i = shoulder + 1; i < 0x10000; i++) { // change to [0,1] range - hlCurve[i] = xlog(1.0 + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + hlCurve[i] = xlog(1.0 + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision R += increment; } @@ -629,7 +912,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou //%%%%%%%%%%%%%%%%%%%%%%%%%% // change to [0,1] range - shCurve.setClip(LUT_CLIP_ABOVE); // used LUT_CLIP_ABOVE, because the curve converges to 1.0 at the upper end and we don't want to exceed this value. + shCurve.setClip(LUT_CLIP_ABOVE); // used LUT_CLIP_ABOVE, because the curve converges to 1.0 at the upper end and we don't want to exceed this value. if (black == 0.0) { shCurve.makeConstant(1.f); } else { @@ -709,7 +992,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // apply contrast enhancement for (int i = 0; i <= 0xffff; i++) { - dcurve[i] = contrastcurve.getVal (dcurve[i]); + dcurve[i] = contrastcurve.getVal(dcurve[i]); } } @@ -726,7 +1009,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou customToneCurve2.Set(tcurve, gamma_); } - if (outBeforeCCurveHistogram ) { + if (outBeforeCCurveHistogram) { histNeeded = true; } } @@ -762,7 +1045,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou for (int i = 0; i <= 0xffff; i += 4) { vfloat valv = LVFU(dcurve[i]); - valv = igamma (valv, gamma_v, startv, slopev, mulv, addv); + valv = igamma(valv, gamma_v, startv, slopev, mulv, addv); STVFU(outCurve[i], c65535v * valv); } @@ -770,7 +1053,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou for (int i = 0; i <= 0xffff; i++) { float val = dcurve[i]; - val = igamma (val, gamma_, start, slope, mul, add); + val = igamma(val, gamma_, start, slope, mul, add); outCurve[i] = (65535.f * val); } @@ -788,16 +1071,342 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou } +void CurveFactory::Curvelocalhl(double ecomp, double hlcompr, double hlcomprthresh, LUTf & hlCurve) +{ + + // a: slope of the curve + const float a = powf(2.0f, ecomp); + + + + + hlCurve.setClip(LUT_CLIP_BELOW); // used LUT_CLIP_BELOW, because we want to have a baseline of 2^expcomp in this curve. If we don't clip the lut we get wrong values, see Issue 2621 #14 for details + float exp_scale = a; + float maxran = 65536.f; + float scale = maxran; + float comp = (max(0.0, ecomp) + 1.0) * hlcompr / 100.0; + float shoulder = ((scale / max(1.0f, exp_scale)) * (hlcomprthresh / 200.0)) + 0.1; + + if (comp <= 0.0f) { + hlCurve.makeConstant(exp_scale); + } else { + hlCurve.makeConstant(exp_scale, shoulder + 1); + + float scalemshoulder = scale - shoulder; + +#ifdef __SSE2__ + int i = shoulder + 1; + + if (i & 1) { // original formula, slower than optimized formulas below but only used once or none, so I let it as is for reference + // change to [0,1] range + float val = (float)i - shoulder; + float R = val * comp / (scalemshoulder); + hlCurve[i] = xlog(1.0f + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + i++; + } + + vdouble onev = _mm_set1_pd(1.0); + vdouble Rv = _mm_set_pd((i + 1 - shoulder) * (double)comp / scalemshoulder, (i - shoulder) * (double)comp / scalemshoulder); + vdouble incrementv = _mm_set1_pd(2.0 * comp / scalemshoulder); + vdouble exp_scalev = _mm_set1_pd(exp_scale); + + // for (; i < 0x10000; i += 2) { + for (; i < maxran; i += 2) { + // change to [0,1] range + vdouble resultv = xlog(onev + Rv * exp_scalev) / Rv; + vfloat resultfv = _mm_cvtpd_ps(resultv); + _mm_store_ss(&hlCurve[i], resultfv); + resultfv = PERMUTEPS(resultfv, _MM_SHUFFLE(1, 1, 1, 1)); + _mm_store_ss(&hlCurve[i + 1], resultfv); + Rv += incrementv; + } + +#else + float R = comp / scalemshoulder; + float increment = R; + + // for (int i = shoulder + 1; i < 0x10000; i++) { + for (int i = shoulder + 1; i < maxran; i++) { + // change to [0,1] range + hlCurve[i] = xlog(1.0f + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + R += increment; + } + +#endif + + } +} + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +void CurveFactory::complexCurvelocal(double ecomp, double black, double hlcompr, double hlcomprthresh, + double shcompr, double br, double cont, double lumare, + LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTf & lightCurveloc, float avg, + int skip) +{ + + const float gamma_ = 2.22; //BT 709 + const float start = expf(gamma_ * logf(-0.0954f / ((1.0f / gamma_ - 1.0f) * 1.0954f))); + const float slope = 1.0954f * powf(start, 1.0f / gamma_ - 1.f) - 0.0954f / start; + const float mul = 1.0954f; + const float add = 0.0954f; + float maxran = 65536.f; //65536 + +// ecomp /= 100.; + + // check if brightness curve is needed + if (br > 0.00001 || br < -0.00001) { + // utili = true; + if(br > 0) { + br /= 4.f;//to avoid artifacts in some cases + } + std::vector brightcurvePoints; + brightcurvePoints.resize(9); + brightcurvePoints.at(0) = double (DCT_NURBS); + + brightcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + brightcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range + + if (br > 0) { + brightcurvePoints.at(3) = 0.2; // toe point + brightcurvePoints.at(4) = 0.2 + br / 250.0; //value at toe point + + brightcurvePoints.at(5) = 0.6; // shoulder point + brightcurvePoints.at(6) = min(1.0, 0.6 + br / 200.0); //value at shoulder point + } else { + brightcurvePoints.at(3) = 0.1 - br / 150.0; // toe point + brightcurvePoints.at(4) = 0.1; // value at toe point + + brightcurvePoints.at(5) = min(1.0, 0.7 - br / 300.0); // shoulder point + brightcurvePoints.at(6) = 0.7; // value at shoulder point + } + + brightcurvePoints.at(7) = 1.; // white point + brightcurvePoints.at(8) = 1.; // value at white point + + DiagonalCurve brightcurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // Applying brightness curve + for (int i = 0; i < 32768; i++) { // L values range up to 32767, higher values are for highlight overflow + + // change to [0,1] range + float val = (float)i / 32767.0; + + // apply brightness curve + val = brightcurve.getVal(val); + + // store result in a temporary array + lightCurveloc[i] = val; + } + + + + } else { + lightCurveloc.makeIdentity(32767.f); + } + + // check if contrast curve is needed + if (cont > 0.00001 || cont < -0.00001) { + + + int k = avg * 32768; + avg = lightCurveloc[k]; + // printf("avg=%f lumaref=%f\n", avg, lumare/100.f); + std::vector contrastcurvePoints; + bool lumm = true; + + if (lumm) { + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + contrastcurvePoints.resize(9); + contrastcurvePoints.at(0) = double (DCT_NURBS); + + contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range + + contrastcurvePoints.at(3) = avg - avg * (0.6 - cont / 250.0); // toe point + contrastcurvePoints.at(4) = avg - avg * (0.6 + cont / 250.0); // value at toe point + + contrastcurvePoints.at(5) = avg + (1 - avg) * (0.6 - cont / 250.0); // shoulder point + contrastcurvePoints.at(6) = avg + (1 - avg) * (0.6 + cont / 250.0); // value at shoulder point + + contrastcurvePoints.at(7) = 1.; // white point + contrastcurvePoints.at(8) = 1.; // value at white point + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } else { + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // sum has an invalid value (next to 0, producing a division by zero, so we create a fake contrast curve, producing a white image + contrastcurvePoints.resize(5); + contrastcurvePoints.at(0) = double (DCT_NURBS); + + contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 1.; // black point. Value in [0 ; 1] range + + contrastcurvePoints.at(3) = 1.; // white point + contrastcurvePoints.at(4) = 1.; // value at white point + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } + + DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); + + // apply contrast enhancement + for (int i = 0; i < 32768; i++) { + lightCurveloc[i] = contrastcurve.getVal(lightCurveloc[i]); + } + + } + + lightCurveloc *= 32767.f; + + for (int i = 32768; i < 32770; i++) { // set last two elements of lut to 32768 and 32769 to allow linear interpolation + lightCurveloc[i] = (float)i; + } + + + // a: slope of the curve, black: starting point at the x axis + const float a = powf(2.0f, ecomp); + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + hlCurve.setClip(LUT_CLIP_BELOW); // used LUT_CLIP_BELOW, because we want to have a baseline of 2^expcomp in this curve. If we don't clip the lut we get wrong values, see Issue 2621 #14 for details + float exp_scale = a; +// float scale = 65536.0; + float scale = maxran; + float comp = (max(0.0, ecomp) + 1.0) * hlcompr / 100.0; + float shoulder = ((scale / max(1.0f, exp_scale)) * (hlcomprthresh / 200.0)) + 0.1; + + if (comp <= 0.0f) { + hlCurve.makeConstant(exp_scale); + } else { + hlCurve.makeConstant(exp_scale, shoulder + 1); + + float scalemshoulder = scale - shoulder; + +#ifdef __SSE2__ + int i = shoulder + 1; + + if (i & 1) { // original formula, slower than optimized formulas below but only used once or none, so I let it as is for reference + // change to [0,1] range + float val = (float)i - shoulder; + float R = val * comp / (scalemshoulder); + hlCurve[i] = xlog(1.0f + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + i++; + } + + vdouble onev = _mm_set1_pd(1.0); + vdouble Rv = _mm_set_pd((i + 1 - shoulder) * (double)comp / scalemshoulder, (i - shoulder) * (double)comp / scalemshoulder); + vdouble incrementv = _mm_set1_pd(2.0 * comp / scalemshoulder); + vdouble exp_scalev = _mm_set1_pd(exp_scale); + + // for (; i < 0x10000; i += 2) { + for (; i < maxran; i += 2) { + // change to [0,1] range + vdouble resultv = xlog(onev + Rv * exp_scalev) / Rv; + vfloat resultfv = _mm_cvtpd_ps(resultv); + _mm_store_ss(&hlCurve[i], resultfv); + resultfv = PERMUTEPS(resultfv, _MM_SHUFFLE(1, 1, 1, 1)); + _mm_store_ss(&hlCurve[i + 1], resultfv); + Rv += incrementv; + } + +#else + float R = comp / scalemshoulder; + float increment = R; + + // for (int i = shoulder + 1; i < 0x10000; i++) { + for (int i = shoulder + 1; i < maxran; i++) { + // change to [0,1] range + hlCurve[i] = xlog(1.0f + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + R += increment; + } + +#endif + + } + + + // curve without contrast + LUTf dcurve(maxran); + + //%%%%%%%%%%%%%%%%%%%%%%%%%% + // change to [0,1] range + shCurve.setClip(LUT_CLIP_ABOVE); // used LUT_CLIP_ABOVE, because the curve converges to 1.0 at the upper end and we don't want to exceed this value. + if (black == 0.0) { + shCurve.makeConstant(1.f); + } else { + const float val = 1.f / (maxran - 1.f); + shCurve[0] = simplebasecurve(val, black, 0.015 * shcompr) / val; + } + + + + // gamma correction + + float val = Color::gammatab_bt709[0] / maxran; + // store result in a temporary array + dcurve[0] = LIM01(val); + + for (int i = 1; i < maxran; i++) { + float val = i / (maxran - 1.f); + +// float val2 = simplebasecurve(val, black, 0.015 * shcompr); +// shCurve[i] = val2 / val; + if (black != 0.0) { + const float val = i / 65535.f; + shCurve[i] = simplebasecurve(val, black, 0.015 * shcompr) / val; + } + + // gamma correction + val = Color::gammatab_bt709[i] / maxran; + // store result in a temporary array + dcurve[i] = val; + } + + +#ifdef __SSE2__ + vfloat gamma_v = F2V(gamma_); + vfloat startv = F2V(start); + vfloat slopev = F2V(slope); + vfloat mulv = F2V(mul); + vfloat addv = F2V(add); + // vfloat c65535v = F2V (65535.f); + vfloat c65535v = F2V(maxran - 1.f); + + for (int i = 0; i <= (maxran - 1.f); i += 4) { + vfloat valv = LVFU(dcurve[i]); + valv = igamma(valv, gamma_v, startv, slopev, mulv, addv); + STVFU(outCurve[i], c65535v * valv); + } + +#else + + for (int i = 0; i <= (maxran - 1.f); i++) { + float val = dcurve[i]; + val = igamma(val, gamma_, start, slope, mul, add); + outCurve[i] = ((maxran - 1.) * val); + } + +#endif + +} + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, - const LUTu & histogram, LUTf & outCurve, - LUTu & outBeforeCCurveHistogram, int skip, bool & utili) +void CurveFactory::complexLCurve(double br, double contr, const std::vector& curvePoints, + const LUTu & histogram, LUTf & outCurve, + LUTu & outBeforeCCurveHistogram, int skip, bool & utili) { utili = false; + // clear array that stores histogram valid before applying the custom curve if (outBeforeCCurveHistogram) { outBeforeCCurveHistogram.clear(); @@ -813,27 +1422,27 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector brightcurvePoints; brightcurvePoints.resize(9); - brightcurvePoints.at(0) = double(DCT_NURBS); + brightcurvePoints.at(0) = double (DCT_NURBS); - brightcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range - brightcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range + brightcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + brightcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range if (br > 0) { - brightcurvePoints.at(3) = 0.1; // toe point - brightcurvePoints.at(4) = 0.1 + br / 150.0; //value at toe point + brightcurvePoints.at(3) = 0.1; // toe point + brightcurvePoints.at(4) = 0.1 + br / 150.0; //value at toe point - brightcurvePoints.at(5) = 0.7; // shoulder point - brightcurvePoints.at(6) = min(1.0, 0.7 + br / 300.0); //value at shoulder point + brightcurvePoints.at(5) = 0.7; // shoulder point + brightcurvePoints.at(6) = min(1.0, 0.7 + br / 300.0); //value at shoulder point } else { - brightcurvePoints.at(3) = 0.1 - br / 150.0; // toe point - brightcurvePoints.at(4) = 0.1; // value at toe point + brightcurvePoints.at(3) = 0.1 - br / 150.0; // toe point + brightcurvePoints.at(4) = 0.1; // value at toe point - brightcurvePoints.at(5) = min(1.0, 0.7 - br / 300.0); // shoulder point - brightcurvePoints.at(6) = 0.7; // value at shoulder point + brightcurvePoints.at(5) = min(1.0, 0.7 - br / 300.0); // shoulder point + brightcurvePoints.at(6) = 0.7; // value at shoulder point } - brightcurvePoints.at(7) = 1.; // white point - brightcurvePoints.at(8) = 1.; // value at white point + brightcurvePoints.at(7) = 1.; // white point + brightcurvePoints.at(8) = 1.; // value at white point DiagonalCurve brightcurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -845,7 +1454,7 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector(val); @@ -874,37 +1483,37 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector contrastcurvePoints; - if(sum) { + if (sum) { avg /= sum; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% contrastcurvePoints.resize(9); - contrastcurvePoints.at(0) = double(DCT_NURBS); + contrastcurvePoints.at(0) = double (DCT_NURBS); - contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range - contrastcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range - contrastcurvePoints.at(3) = avg - avg * (0.6 - contr / 250.0); // toe point - contrastcurvePoints.at(4) = avg - avg * (0.6 + contr / 250.0); // value at toe point + contrastcurvePoints.at(3) = avg - avg * (0.6 - contr / 250.0); // toe point + contrastcurvePoints.at(4) = avg - avg * (0.6 + contr / 250.0); // value at toe point - contrastcurvePoints.at(5) = avg + (1 - avg) * (0.6 - contr / 250.0); // shoulder point - contrastcurvePoints.at(6) = avg + (1 - avg) * (0.6 + contr / 250.0); // value at shoulder point + contrastcurvePoints.at(5) = avg + (1 - avg) * (0.6 - contr / 250.0); // shoulder point + contrastcurvePoints.at(6) = avg + (1 - avg) * (0.6 + contr / 250.0); // value at shoulder point - contrastcurvePoints.at(7) = 1.; // white point - contrastcurvePoints.at(8) = 1.; // value at white point + contrastcurvePoints.at(7) = 1.; // white point + contrastcurvePoints.at(8) = 1.; // value at white point //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } else { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // sum has an invalid value (next to 0, producing a division by zero, so we create a fake contrast curve, producing a white image contrastcurvePoints.resize(5); - contrastcurvePoints.at(0) = double(DCT_NURBS); + contrastcurvePoints.at(0) = double (DCT_NURBS); - contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range - contrastcurvePoints.at(2) = 1.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 1.; // black point. Value in [0 ; 1] range - contrastcurvePoints.at(3) = 1.; // white point - contrastcurvePoints.at(4) = 1.; // value at white point + contrastcurvePoints.at(3) = 1.; // white point + contrastcurvePoints.at(4) = 1.; // value at white point //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } @@ -913,7 +1522,7 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector(new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip)); + tcurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCCurveHistogram) { histNeeded = true; @@ -950,7 +1559,7 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (outCurve[i]); + val = tcurve->getVal(outCurve[i]); outCurve[i] = (32767.f * val); } @@ -958,7 +1567,7 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, LUTf & outCurve, int skip) +void CurveFactory::RGBCurve(const std::vector& curvePoints, LUTf & outCurve, int skip) { // create a curve if needed std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] != 0) { - tcurve = std::unique_ptr(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + tcurve = std::unique_ptr (new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); } if (tcurve && tcurve->isIdentity()) { @@ -1008,6 +1617,1273 @@ void CurveFactory::RGBCurve (const std::vector& curvePoints, LUTf & outC } +LocretigainCurverab::LocretigainCurverab() : sum(0.f) {}; + +void LocretigainCurverab::Reset() +{ + lutLocretigainCurverab.reset(); + sum = 0.f; +} + +void LocretigainCurverab::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocretigainCurverab(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocretigainCurverab[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocretigainCurverab[i] < 0.02f) { + lutLocretigainCurverab[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocretigainCurverab[i]; + } + + //lutLocCurve.dump("wav"); +} + +void LocretigainCurverab::Set(const std::vector &curvePoints) +{ + + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + Set(tcurve); + } else { + Reset(); + } +} +LocHHmaskblCurve::LocHHmaskblCurve() : sum(0.f) {}; + +void LocHHmaskblCurve::Reset() +{ + lutLocHHmaskblCurve.reset(); + sum = 0.f; +} + + +void LocHHmaskblCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmaskblCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmaskblCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmaskblCurve[i] < 0.02f) { + lutLocHHmaskblCurve[i] = 0.02f; + } + + sum += lutLocHHmaskblCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + +void LocHHmaskblCurve::Set(const std::vector &curvePoints, bool & lhmasblutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmasblutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocLLmaskblCurve::LocLLmaskblCurve() : sum(0.f) {}; + +void LocLLmaskblCurve::Reset() +{ + lutLocLLmaskblCurve.reset(); + sum = 0.f; +} + +void LocLLmaskblCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmaskblCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmaskblCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmaskblCurve[i] < 0.02f) { + lutLocLLmaskblCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmaskblCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmaskblCurve::Set(const std::vector &curvePoints, bool & llmasblutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmasblutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocCCmaskblCurve::LocCCmaskblCurve() : sum(0.f) {}; + +void LocCCmaskblCurve::Reset() +{ + lutLocCCmaskblCurve.reset(); + sum = 0.f; +} + +void LocCCmaskblCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmaskblCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmaskblCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmaskblCurve[i] < 0.02f) { + lutLocCCmaskblCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmaskblCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmaskblCurve::Set(const std::vector &curvePoints, bool & lcmasblutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmasblutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + +LocHHmasktmCurve::LocHHmasktmCurve() : sum(0.f) {}; + +void LocHHmasktmCurve::Reset() +{ + lutLocHHmasktmCurve.reset(); + sum = 0.f; +} + + +void LocHHmasktmCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmasktmCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmasktmCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmasktmCurve[i] < 0.02f) { + lutLocHHmasktmCurve[i] = 0.02f; + } + + sum += lutLocHHmasktmCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + +void LocHHmasktmCurve::Set(const std::vector &curvePoints, bool & lhmastmutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmastmutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocLLmasktmCurve::LocLLmasktmCurve() : sum(0.f) {}; + +void LocLLmasktmCurve::Reset() +{ + lutLocLLmasktmCurve.reset(); + sum = 0.f; +} + +void LocLLmasktmCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmasktmCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmasktmCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmasktmCurve[i] < 0.02f) { + lutLocLLmasktmCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmasktmCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmasktmCurve::Set(const std::vector &curvePoints, bool & llmastmutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmastmutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocCCmasktmCurve::LocCCmasktmCurve() : sum(0.f) {}; + +void LocCCmasktmCurve::Reset() +{ + lutLocCCmasktmCurve.reset(); + sum = 0.f; +} + +void LocCCmasktmCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmasktmCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmasktmCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmasktmCurve[i] < 0.02f) { + lutLocCCmasktmCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmasktmCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmasktmCurve::Set(const std::vector &curvePoints, bool & lcmastmutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmastmutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + +LocHHmaskretiCurve::LocHHmaskretiCurve() : sum(0.f) {}; + +void LocHHmaskretiCurve::Reset() +{ + lutLocHHmaskretiCurve.reset(); + sum = 0.f; +} + + +void LocHHmaskretiCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmaskretiCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmaskretiCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmaskretiCurve[i] < 0.02f) { + lutLocHHmaskretiCurve[i] = 0.02f; + } + + sum += lutLocHHmaskretiCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + +void LocHHmaskretiCurve::Set(const std::vector &curvePoints, bool & lhmasretiutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmasretiutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocLLmaskretiCurve::LocLLmaskretiCurve() : sum(0.f) {}; + +void LocLLmaskretiCurve::Reset() +{ + lutLocLLmaskretiCurve.reset(); + sum = 0.f; +} + +void LocLLmaskretiCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmaskretiCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmaskretiCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmaskretiCurve[i] < 0.02f) { + lutLocLLmaskretiCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmaskretiCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmaskretiCurve::Set(const std::vector &curvePoints, bool & llmasretiutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmasretiutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocCCmaskretiCurve::LocCCmaskretiCurve() : sum(0.f) {}; + +void LocCCmaskretiCurve::Reset() +{ + lutLocCCmaskretiCurve.reset(); + sum = 0.f; +} + +void LocCCmaskretiCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmaskretiCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmaskretiCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmaskretiCurve[i] < 0.02f) { + lutLocCCmaskretiCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmaskretiCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmaskretiCurve::Set(const std::vector &curvePoints, bool & lcmasretiutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmasretiutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + + + + + +LocHHmaskcbCurve::LocHHmaskcbCurve() : sum(0.f) {}; + +void LocHHmaskcbCurve::Reset() +{ + lutLocHHmaskcbCurve.reset(); + sum = 0.f; +} + + +void LocHHmaskcbCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmaskcbCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmaskcbCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmaskcbCurve[i] < 0.02f) { + lutLocHHmaskcbCurve[i] = 0.02f; + } + + sum += lutLocHHmaskcbCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + +void LocHHmaskcbCurve::Set(const std::vector &curvePoints, bool & lhmascbutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmascbutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocLLmaskcbCurve::LocLLmaskcbCurve() : sum(0.f) {}; + +void LocLLmaskcbCurve::Reset() +{ + lutLocLLmaskcbCurve.reset(); + sum = 0.f; +} + +void LocLLmaskcbCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmaskcbCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmaskcbCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmaskcbCurve[i] < 0.02f) { + lutLocLLmaskcbCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmaskcbCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmaskcbCurve::Set(const std::vector &curvePoints, bool & llmascbutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmascbutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocCCmaskcbCurve::LocCCmaskcbCurve() : sum(0.f) {}; + +void LocCCmaskcbCurve::Reset() +{ + lutLocCCmaskcbCurve.reset(); + sum = 0.f; +} + +void LocCCmaskcbCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmaskcbCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmaskcbCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmaskcbCurve[i] < 0.02f) { + lutLocCCmaskcbCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmaskcbCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmaskcbCurve::Set(const std::vector &curvePoints, bool & lcmascbutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmascbutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + +LocHHmaskSHCurve::LocHHmaskSHCurve() : sum(0.f) {}; + +void LocHHmaskSHCurve::Reset() +{ + lutLocHHmaskSHCurve.reset(); + sum = 0.f; +} + + +void LocHHmaskSHCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmaskSHCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmaskSHCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmaskSHCurve[i] < 0.02f) { + lutLocHHmaskSHCurve[i] = 0.02f; + } + + sum += lutLocHHmaskSHCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocHHmaskSHCurve::Set(const std::vector &curvePoints, bool & lhmasSHutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmasSHutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + +LocLLmaskSHCurve::LocLLmaskSHCurve() : sum(0.f) {}; + +void LocLLmaskSHCurve::Reset() +{ + lutLocLLmaskSHCurve.reset(); + sum = 0.f; +} + +void LocLLmaskSHCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmaskSHCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmaskSHCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmaskSHCurve[i] < 0.02f) { + lutLocLLmaskSHCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmaskSHCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmaskSHCurve::Set(const std::vector &curvePoints, bool & llmasSHutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmasSHutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + +LocCCmaskSHCurve::LocCCmaskSHCurve() : sum(0.f) {}; + +void LocCCmaskSHCurve::Reset() +{ + lutLocCCmaskSHCurve.reset(); + sum = 0.f; +} + +void LocCCmaskSHCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmaskSHCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmaskSHCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmaskSHCurve[i] < 0.02f) { + lutLocCCmaskSHCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmaskSHCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmaskSHCurve::Set(const std::vector &curvePoints, bool & lcmasSHutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmasSHutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + + +LocHHmaskexpCurve::LocHHmaskexpCurve() : sum(0.f) {}; + +void LocHHmaskexpCurve::Reset() +{ + lutLocHHmaskexpCurve.reset(); + sum = 0.f; +} + + +void LocHHmaskexpCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmaskexpCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmaskexpCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmaskexpCurve[i] < 0.02f) { + lutLocHHmaskexpCurve[i] = 0.02f; + } + + sum += lutLocHHmaskexpCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocHHmaskexpCurve::Set(const std::vector &curvePoints, bool & lhmasexputili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmasexputili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + +LocLLmaskexpCurve::LocLLmaskexpCurve() : sum(0.f) {}; + +void LocLLmaskexpCurve::Reset() +{ + lutLocLLmaskexpCurve.reset(); + sum = 0.f; +} + +void LocLLmaskexpCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmaskexpCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmaskexpCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmaskexpCurve[i] < 0.02f) { + lutLocLLmaskexpCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmaskexpCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmaskexpCurve::Set(const std::vector &curvePoints, bool & llmasexputili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmasexputili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + +LocCCmaskexpCurve::LocCCmaskexpCurve() : sum(0.f) {}; + +void LocCCmaskexpCurve::Reset() +{ + lutLocCCmaskexpCurve.reset(); + sum = 0.f; +} + +void LocCCmaskexpCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmaskexpCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmaskexpCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmaskexpCurve[i] < 0.02f) { + lutLocCCmaskexpCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmaskexpCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmaskexpCurve::Set(const std::vector &curvePoints, bool & lcmasexputili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmasexputili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocHHmaskCurve::LocHHmaskCurve() : sum(0.f) {}; + +void LocHHmaskCurve::Reset() +{ + lutLocHHmaskCurve.reset(); + sum = 0.f; +} + + +void LocHHmaskCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHmaskCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHmaskCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHmaskCurve[i] < 0.02f) { + lutLocHHmaskCurve[i] = 0.02f; + } + + sum += lutLocHHmaskCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocHHmaskCurve::Set(const std::vector &curvePoints, bool & lhmasutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lhmasutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + +LocCCmaskCurve::LocCCmaskCurve() : sum(0.f) {}; + +void LocCCmaskCurve::Reset() +{ + lutLocCCmaskCurve.reset(); + sum = 0.f; +} + + +void LocCCmaskCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCCmaskCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCCmaskCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCCmaskCurve[i] < 0.02f) { + lutLocCCmaskCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCCmaskCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocCCmaskCurve::Set(const std::vector &curvePoints, bool & lcmasutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + lcmasutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + +LocLLmaskCurve::LocLLmaskCurve() : sum(0.f) {}; + +void LocLLmaskCurve::Reset() +{ + lutLocLLmaskCurve.reset(); + sum = 0.f; +} + +void LocLLmaskCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLLmaskCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLLmaskCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLLmaskCurve[i] < 0.02f) { + lutLocLLmaskCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLLmaskCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocLLmaskCurve::Set(const std::vector &curvePoints, bool & llmasutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + llmasutili = true; + Set(ttcurve); + } else { + Reset(); + } +} + + + + +LocHHCurve::LocHHCurve() : sum(0.f) {}; + +void LocHHCurve::Reset() +{ + lutLocHHCurve.reset(); + sum = 0.f; +} +void LocHHCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocHHCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocHHCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocHHCurve[i] < 0.02f) { + lutLocHHCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocHHCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +void LocHHCurve::Set(const std::vector &curvePoints, bool &HHutili) +{ + // if (HHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve ttcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + ttcurve.setIdentityValue(0.); + Set(ttcurve); + HHutili = true; + } else { + Reset(); + } +} + + +LocLHCurve::LocLHCurve() : sum(0.f) {}; + +void LocLHCurve::Reset() +{ + lutLocLHCurve.reset(); + sum = 0.f; +} + +void LocLHCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocLHCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocLHCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocLHCurve[i] < 0.02f) { + lutLocLHCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocLHCurve[i]; + } + + //lutLocCurve.dump("wav"); +} + + + + +void LocLHCurve::Set(const std::vector &curvePoints, bool &LHutili) +{ + + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { +// if (LHutili && !curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + Set(tcurve); + LHutili = true; + } else { + Reset(); + } +} + +LocwavCurve::LocwavCurve() : sum(0.f) {}; + +void LocwavCurve::Reset() +{ + lutLocwavCurve.reset(); + sum = 0.f; +} + +void LocwavCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocwavCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocwavCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocwavCurve[i] < 0.02f) { + lutLocwavCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocwavCurve[i]; + } + + //lutLocCurve.dump("wav"); +} +void LocwavCurve::Set(const std::vector &curvePoints, bool & lcwavutili) +{ + + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + lcwavutili = true; + Set(tcurve); + } else { + Reset(); + } +} + +LocretitransCurve::LocretitransCurve() : sum(0.f) {}; + +void LocretitransCurve::Reset() +{ + lutLocretitransCurve.reset(); + sum = 0.f; +} + +void LocretitransCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocretitransCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocretitransCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocretitransCurve[i] < 0.02f) { + lutLocretitransCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocretitransCurve[i]; + } + + //lutLocCurve.dump("wav"); +} +void LocretitransCurve::Set(const std::vector &curvePoints) +{ + + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + Set(tcurve); + } else { + Reset(); + } +} + + +LocretigainCurve::LocretigainCurve() : sum(0.f) {}; + +void LocretigainCurve::Reset() +{ + lutLocretigainCurve.reset(); + sum = 0.f; +} + +void LocretigainCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocretigainCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocretigainCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocretigainCurve[i] < 0.02f) { + lutLocretigainCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocretigainCurve[i]; + } + + //lutLocCurve.dump("wav"); +} +void LocretigainCurve::Set(const std::vector &curvePoints) +{ + + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + Set(tcurve); + } else { + Reset(); + } +} + + + void ColorAppearance::Reset() { lutColCurve.reset(); @@ -1019,7 +2895,7 @@ void ColorAppearance::Set(const Curve &pCurve) lutColCurve(65536); for (int i = 0; i < 65536; i++) { - lutColCurve[i] = pCurve.getVal(double(i) / 65535.) * 65535.; + lutColCurve[i] = pCurve.getVal(double (i) / 65535.) * 65535.; } } @@ -1038,10 +2914,10 @@ void RetinextransmissionCurve::Set(const Curve &pCurve) return; } - luttransmission(501); // raise this value if the quality suffers from this number of samples + luttransmission(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - luttransmission[i] = pCurve.getVal(double(i) / 500.); + luttransmission[i] = pCurve.getVal(double (i) / 500.); } } @@ -1071,10 +2947,10 @@ void RetinexgaintransmissionCurve::Set(const Curve &pCurve) return; } - lutgaintransmission(501); // raise this value if the quality suffers from this number of samples + lutgaintransmission(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - lutgaintransmission[i] = pCurve.getVal(double(i) / 500.); + lutgaintransmission[i] = pCurve.getVal(double (i) / 500.); } } @@ -1101,9 +2977,9 @@ void ToneCurve::Set(const Curve &pCurve, float gamma) if (gamma <= 0.0 || gamma == 1.) { for (int i = 0; i < 65536; i++) { - lutToneCurve[i] = (float)pCurve.getVal(float(i) / 65535.f) * 65535.f; + lutToneCurve[i] = (float)pCurve.getVal(float (i) / 65535.f) * 65535.f; } - } else if(gamma == (float)Color::sRGBGammaCurve) { + } else if (gamma == (float)Color::sRGBGammaCurve) { // for sRGB gamma we can use luts, which is much faster for (int i = 0; i < 65536; i++) { float val = Color::gammatab_srgb[i] / 65535.f; @@ -1113,17 +2989,17 @@ void ToneCurve::Set(const Curve &pCurve, float gamma) } } else { - const float start = expf(gamma * logf( -0.055 / ((1.0 / gamma - 1.0) * 1.055 ))); - const float slope = 1.055 * powf (start, 1.0 / gamma - 1) - 0.055 / start; + const float start = expf(gamma * logf(-0.055 / ((1.0 / gamma - 1.0) * 1.055))); + const float slope = 1.055 * powf(start, 1.0 / gamma - 1) - 0.055 / start; const float mul = 1.055; const float add = 0.055; // apply gamma, that is 'pCurve' is defined with the given gamma and here we convert it to a curve in linear space for (int i = 0; i < 65536; i++) { - float val = float(i) / 65535.f; - val = CurveFactory::gamma (val, gamma, start, slope, mul, add); + float val = float (i) / 65535.f; + val = CurveFactory::gamma(val, gamma, start, slope, mul, add); val = pCurve.getVal(val); - val = CurveFactory::igamma (val, gamma, start, slope, mul, add); + val = CurveFactory::igamma(val, gamma, start, slope, mul, add); lutToneCurve[i] = val * 65535.f; } } @@ -1141,10 +3017,10 @@ void OpacityCurve::Set(const Curve *pCurve) return; } - lutOpacityCurve(501); // raise this value if the quality suffers from this number of samples + lutOpacityCurve(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - lutOpacityCurve[i] = pCurve->getVal(double(i) / 500.); + lutOpacityCurve[i] = pCurve->getVal(double (i) / 500.); } //lutOpacityCurve.dump("opacity"); @@ -1155,7 +3031,7 @@ void OpacityCurve::Set(const std::vector &curvePoints, bool &opautili) std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); + tcurve = std::unique_ptr (new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); tcurve->setIdentityValue(0.); } @@ -1182,13 +3058,13 @@ void WavCurve::Set(const Curve &pCurve) return; } - lutWavCurve(501); // raise this value if the quality suffers from this number of samples + lutWavCurve(501); // raise this value if the quality suffers from this number of samples sum = 0.f; for (int i = 0; i < 501; i++) { - lutWavCurve[i] = pCurve.getVal(double(i) / 500.); + lutWavCurve[i] = pCurve.getVal(double (i) / 500.); - if(lutWavCurve[i] < 0.02f) { + if (lutWavCurve[i] < 0.02f) { lutWavCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value } @@ -1259,10 +3135,10 @@ void WavOpacityCurveRG::Set(const Curve &pCurve) return; } - lutOpacityCurveRG(501); // raise this value if the quality suffers from this number of samples + lutOpacityCurveRG(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - lutOpacityCurveRG[i] = pCurve.getVal(double(i) / 500.); + lutOpacityCurveRG[i] = pCurve.getVal(double (i) / 500.); } } @@ -1278,6 +3154,43 @@ void WavOpacityCurveRG::Set(const std::vector &curvePoints) } +WavOpacityCurveSH::WavOpacityCurveSH() {} + +void WavOpacityCurveSH::Reset() +{ + lutOpacityCurveSH.reset(); +} + +void WavOpacityCurveSH::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutOpacityCurveSH(501); // raise this value if the quality suffers from this number of samples + + for (int i = 0; i < 501; i++) { + lutOpacityCurveSH[i] = pCurve.getVal(double(i) / 500.); + } +} + +void WavOpacityCurveSH::Set(const std::vector &curvePoints) +{ + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + Set(tcurve); + } else { + Reset(); + } + +} + + + + + WavOpacityCurveBY::WavOpacityCurveBY() {} void WavOpacityCurveBY::Reset() @@ -1292,10 +3205,10 @@ void WavOpacityCurveBY::Set(const Curve &pCurve) return; } - lutOpacityCurveBY(501); // raise this value if the quality suffers from this number of samples + lutOpacityCurveBY(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - lutOpacityCurveBY[i] = pCurve.getVal(double(i) / 500.); + lutOpacityCurveBY[i] = pCurve.getVal(double (i) / 500.); } } @@ -1324,10 +3237,10 @@ void WavOpacityCurveW::Set(const Curve &pCurve) return; } - lutOpacityCurveW(501); // raise this value if the quality suffers from this number of samples + lutOpacityCurveW(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - lutOpacityCurveW[i] = pCurve.getVal(double(i) / 500.); + lutOpacityCurveW[i] = pCurve.getVal(double (i) / 500.); } } @@ -1356,10 +3269,10 @@ void WavOpacityCurveWL::Set(const Curve &pCurve) return; } - lutOpacityCurveWL(501); // raise this value if the quality suffers from this number of samples + lutOpacityCurveWL(501); // raise this value if the quality suffers from this number of samples for (int i = 0; i < 501; i++) { - lutOpacityCurveWL[i] = pCurve.getVal(double(i) / 500.); + lutOpacityCurveWL[i] = pCurve.getVal(double (i) / 500.); } } @@ -1390,13 +3303,13 @@ void NoiseCurve::Set(const Curve &pCurve) return; } - lutNoiseCurve(501); // raise this value if the quality suffers from this number of samples + lutNoiseCurve(501); // raise this value if the quality suffers from this number of samples sum = 0.f; for (int i = 0; i < 501; i++) { - lutNoiseCurve[i] = pCurve.getVal(double(i) / 500.); + lutNoiseCurve[i] = pCurve.getVal(double (i) / 500.); - if(lutNoiseCurve[i] < 0.01f) { + if (lutNoiseCurve[i] < 0.01f) { lutNoiseCurve[i] = 0.01f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value } @@ -1470,7 +3383,7 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], //lr1=low; for (int i = 0; i <= upperBound; ++i) { - double x = double(i) / double(upperBound); + double x = double (i) / double (upperBound); if (x > nextX) { ++ptNum; @@ -1486,13 +3399,13 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], } if (!ptNum) { - Color::hsv2rgb(float(prevY), satur, lr1, r, g, b); + Color::hsv2rgb(float (prevY), satur, lr1, r, g, b); Color::rgbxyz(r, g, b, xx, yy, zz, xyz_rgb); lut1[i] = xx; lut2[i] = yy; lut3[i] = zz; } else if (ptNum >= nPoints) { - Color::hsv2rgb(float(nextY), satur, lr2, r, g, b); + Color::hsv2rgb(float (nextY), satur, lr2, r, g, b); Color::rgbxyz(r, g, b, xx, yy, zz, xyz_rgb); lut1[i] = xx; lut2[i] = yy; @@ -1502,8 +3415,8 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], if (dY > 0.000001 || dY < -0.000001) { 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); + Color::hsv2rgb(float (prevY), satur, lr1, r1, g1, b1); + Color::hsv2rgb(float (nextY), satur, lr2, r2, g2, b2); 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); @@ -1511,34 +3424,27 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], //I use XYZ to mix color 1 and 2 rather than rgb (gamut) and rather than Lab artifacts X1 = X1 + (X2 - X1) * currY / dY; - if(X1 < 0.f) { + if (X1 < 0.f) { X1 = 0.f; //negative value not good } Y1 = Y1 + (Y2 - Y1) * currY / dY; - if(Y1 < 0.f) { + if (Y1 < 0.f) { Y1 = 0.f; } Z1 = Z1 + (Z2 - Z1) * currY / dY; - if(Z1 < 0.f) { + if (Z1 < 0.f) { Z1 = 0.f; } - Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1);//prepare to gamut control + Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1); //prepare to gamut control Color::Lab2Lch(a_1, b_1, c1, h1); float Lr = L1 / 327.68f; float RR, GG, BB; -#ifndef NDEBUG - bool neg = false; - bool more_rgb = false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(h1, Lr, c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); -#else Color::gamutLchonly(h1, Lr, c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); -#endif L1 = Lr * 327.68f; float La, Lb, X, Y, Z; // converting back to rgb @@ -1548,7 +3454,7 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], lut2[i] = Y; lut3[i] = Z; } else { - Color::hsv2rgb(float(nextY), satur, lumin, r, g, b); + Color::hsv2rgb(float (nextY), satur, lumin, r, g, b); Color::rgbxyz(r, g, b, xx, yy, zz, xyz_rgb); lut1[i] = xx; lut2[i] = yy; @@ -1556,14 +3462,6 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], } } } - - /* - #ifndef NDEBUG - lutRed.dump("red"); - lutGreen.dump("green"); - lutBlue.dump("blue"); - #endif - */ } void ColorGradientCurve::SetXYZ(const std::vector &curvePoints, const double xyz_rgb[3][3], float satur, float lumin) @@ -1571,7 +3469,7 @@ void ColorGradientCurve::SetXYZ(const std::vector &curvePoints, const do std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); + tcurve = std::unique_ptr (new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); } if (tcurve) { @@ -1607,7 +3505,7 @@ void ColorGradientCurve::SetRGB(const Curve *pCurve) Color::eInterpolationDirection dir = Color::ID_DOWN; for (int i = 0; i <= upperBound; ++i) { - double x = double(i) / double(upperBound); + double x = double (i) / double (upperBound); if (x > nextX) { ++ptNum; @@ -1621,12 +3519,12 @@ void ColorGradientCurve::SetRGB(const Curve *pCurve) } if (!ptNum) { - Color::hsv2rgb(float(prevY), 1.f, 1.f, r, g, b); + Color::hsv2rgb(float (prevY), 1.f, 1.f, r, g, b); lut1[i] = r; lut2[i] = g; lut3[i] = b; } else if (ptNum >= nPoints) { - Color::hsv2rgb(float(nextY), 1.f, 1.f, r, g, b); + Color::hsv2rgb(float (nextY), 1.f, 1.f, r, g, b); lut1[i] = r; lut2[i] = g; lut3[i] = b; @@ -1640,29 +3538,21 @@ void ColorGradientCurve::SetRGB(const Curve *pCurve) Color::hsv2rgb(h2, 1.f, 1.f, ro, go, bo); #else float r1, g1, b1, r2, g2, b2, ro, go, bo; - Color::hsv2rgb(float(prevY), 1., 1., r1, g1, b1); - Color::hsv2rgb(float(nextY), 1., 1., r2, g2, b2); + Color::hsv2rgb(float (prevY), 1., 1., r1, g1, b1); + Color::hsv2rgb(float (nextY), 1., 1., r2, g2, b2); Color::interpolateRGBColor(currY / dY, r1, g1, b1, r2, g2, b2, Color::CHANNEL_LIGHTNESS | Color::CHANNEL_CHROMATICITY | Color::CHANNEL_HUE, xyz_rgb, rgb_xyz, ro, go, bo); #endif lut1[i] = ro; lut2[i] = go; lut3[i] = bo; } else { - Color::hsv2rgb(float(nextY), 1.f, 1.f, r, g, b); + Color::hsv2rgb(float (nextY), 1.f, 1.f, r, g, b); lut1[i] = r; lut2[i] = g; lut3[i] = b; } } } - - /* - #ifndef NDEBUG - lut1.dump("red"); - lut2.dump("green"); - lut3.dump("blue"); - #endif - */ } void ColorGradientCurve::SetRGB(const std::vector &curvePoints) @@ -1670,7 +3560,7 @@ void ColorGradientCurve::SetRGB(const std::vector &curvePoints) std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); + tcurve = std::unique_ptr (new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); } if (tcurve) { @@ -1716,18 +3606,18 @@ void PerceptualToneCurve::cubic_spline(const float x[], const float y[], const i A[i][len - 1] = 6 * (b[i + 1] - b[i]); } - for(i = 1; i < len - 2; i++) { + for (i = 1; i < len - 2; i++) { float v = A[i + 1][i] / A[i][i]; - for(j = 1; j <= len - 1; j++) { + for (j = 1; j <= len - 1; j++) { A[i + 1][j] -= v * A[i][j]; } } - for(i = len - 2; i > 0; i--) { + for (i = len - 2; i > 0; i--) { float acc = 0; - for(j = i; j <= len - 2; j++) { + for (j = i; j <= len - 2; j++) { acc += A[i][j] * c[j]; } @@ -1847,7 +3737,7 @@ float PerceptualToneCurve::calculateToneCurveContrastValue() const // Note: the analysis is made on the gamma encoded curve, as the LUT is linear we make backwards gamma to struct find_tc_slope_fun_arg arg = { this }; - float k = find_minimum_interval_halving(find_tc_slope_fun, &arg, 0.1, 5.0, 0.01, 20); // normally found in 8 iterations + float k = find_minimum_interval_halving(find_tc_slope_fun, &arg, 0.1, 5.0, 0.01, 20); // normally found in 8 iterations //fprintf(stderr, "average slope: %f\n", k); float maxslope = 0; @@ -1904,7 +3794,7 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float if (oog_r && oog_g && oog_b) { continue; } - + float r = CLIP(rc[i]); float g = CLIP(gc[i]); float b = CLIP(bc[i]); @@ -1927,17 +3817,35 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float if (ar >= 65535.f && ag >= 65535.f && ab >= 65535.f) { // clip fast path, will also avoid strange colours of clipped highlights //rc[i] = gc[i] = bc[i] = 65535.f; - if (!oog_r) rc[i] = 65535.f; - if (!oog_g) gc[i] = 65535.f; - if (!oog_b) bc[i] = 65535.f; + if (!oog_r) { + rc[i] = 65535.f; + } + + if (!oog_g) { + gc[i] = 65535.f; + } + + if (!oog_b) { + bc[i] = 65535.f; + } + continue; } if (ar <= 0.f && ag <= 0.f && ab <= 0.f) { //rc[i] = gc[i] = bc[i] = 0; - if (!oog_r) rc[i] = 0.f; - if (!oog_g) gc[i] = 0.f; - if (!oog_b) bc[i] = 0.f; + if (!oog_r) { + rc[i] = 0.f; + } + + if (!oog_g) { + gc[i] = 0.f; + } + + if (!oog_b) { + bc[i] = 0.f; + } + continue; } @@ -1960,11 +3868,11 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float Color::Prophotoxyz(r, g, b, x, y, z); float J, C, h; - Ciecam02::xyz2jch_ciecam02float( J, C, h, - aw, fl, - x * 0.0015259022f, y * 0.0015259022f, z * 0.0015259022f, - xw, yw, zw, - c, nc, pow1, nbb, ncb, cz, d); + Ciecam02::xyz2jch_ciecam02float(J, C, h, + aw, fl, + x * 0.0015259022f, y * 0.0015259022f, z * 0.0015259022f, + xw, yw, zw, + c, nc, pow1, nbb, ncb, cz, d); if (!isfinite(J) || !isfinite(C) || !isfinite(h)) { @@ -1977,9 +3885,18 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float g = newg; b = newb; } - if (!oog_r) rc[i] = r; - if (!oog_g) gc[i] = g; - if (!oog_b) bc[i] = b; + + if (!oog_r) { + rc[i] = r; + } + + if (!oog_g) { + gc[i] = g; + } + + if (!oog_b) { + bc[i] = b; + } continue; } @@ -2071,10 +3988,10 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float C *= cmul; - Ciecam02::jch2xyz_ciecam02float( x, y, z, - J, C, h, - xw, yw, zw, - c, nc, pow1, nbb, ncb, fl, cz, d, aw ); + Ciecam02::jch2xyz_ciecam02float(x, y, z, + J, C, h, + xw, yw, zw, + c, nc, pow1, nbb, ncb, fl, cz, d, aw); if (!isfinite(x) || !isfinite(y) || !isfinite(z)) { // can happen for colours on the rim of being outside gamut, that worked without chroma scaling but not with. Then we return only the curve's result. @@ -2087,9 +4004,17 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float b = newb; } - if (!oog_r) rc[i] = r; - if (!oog_g) gc[i] = g; - if (!oog_b) bc[i] = b; + if (!oog_r) { + rc[i] = r; + } + + if (!oog_g) { + gc[i] = g; + } + + if (!oog_b) { + bc[i] = b; + } continue; } @@ -2150,9 +4075,18 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float g = newg; b = newb; } - if (!oog_r) rc[i] = r; - if (!oog_g) gc[i] = g; - if (!oog_b) bc[i] = b; + + if (!oog_r) { + rc[i] = r; + } + + if (!oog_g) { + gc[i] = g; + } + + if (!oog_b) { + bc[i] = b; + } } } float PerceptualToneCurve::cf_range[2]; @@ -2175,7 +4109,7 @@ void PerceptualToneCurve::init() Ciecam02::initcam1float(yb, 1.f, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); - pow1 = pow_F( 1.64f - pow_F( 0.29f, n ), 0.73f ); + pow1 = pow_F(1.64f - pow_F(0.29f, n), 0.73f); { // init contrast-value-to-chroma-scaling conversion curve @@ -2243,7 +4177,7 @@ void PerceptualToneCurve::initApplyState(PerceptualToneCurveState & state, const state.Working2Prophoto[i][j] += prophoto_xyz[i][k] * Work[k][j]; } - Work = ICCStore::getInstance()->workingSpaceInverseMatrix (workingSpace); + Work = ICCStore::getInstance()->workingSpaceInverseMatrix(workingSpace); memset(state.Prophoto2Working, 0, sizeof(state.Prophoto2Working)); for (int i = 0; i < 3; i++) diff --git a/rtengine/curves.h b/rtengine/curves.h index 03fa3e812..9eb3d8e56 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -74,7 +74,8 @@ inline void setUnlessOOG(vfloat &r, vfloat &g, vfloat &b, const vfloat rr, const bool sanitizeCurve(std::vector& curve); -namespace curves { +namespace curves +{ inline void setLutVal(const LUTf &lut, float &val) { @@ -124,33 +125,33 @@ class CurveFactory protected: // functions calculating the parameters of the contrast curve based on the desired slope at the center - static double solve_upper (double m, double c, double deriv); - static double solve_lower (double m, double c, double deriv); - static double dupper (const double b, const double m, const double c); - static double dlower (const double b, const double m, const double c); + static double solve_upper(double m, double c, double deriv); + static double solve_lower(double m, double c, double deriv); + static double dupper(const double b, const double m, const double c); + static double dlower(const double b, const double m, const double c); // basic convex function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point - static inline double basel (double x, double m1, double m2) + static inline double basel(double x, double m1, double m2) { if (x == 0.0) { return 0.0; } - double k = sqrt ((m1 - 1.0) * (m1 - m2) * 0.5) / (1.0 - m2); + double k = sqrt((m1 - 1.0) * (m1 - m2) * 0.5) / (1.0 - m2); double l = (m1 - m2) / (1.0 - m2) + k; double lx = xlog(x); return m2 * x + (1.0 - m2) * (2.0 - xexp(k * lx)) * xexp(l * lx); } // basic concave function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point - static inline double baseu (double x, double m1, double m2) + static inline double baseu(double x, double m1, double m2) { return 1.0 - basel(1.0 - x, m1, m2); } // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery - static inline double cupper (double x, double m, double hr) + static inline double cupper(double x, double m, double hr) { if (hr > 1.0) { - return baseu (x, m, 2.0 * (hr - 1.0) / m); + return baseu(x, m, 2.0 * (hr - 1.0) / m); } double x1 = (1.0 - hr) / m; @@ -167,12 +168,12 @@ protected: return 1.0 - hr + hr * baseu((x - x1) / hr, m, 0); } // concave curve between (0,0) and (1,1) with slope m at (1,1). sr controls the shadow recovery - static inline double clower (double x, double m, double sr) + static inline double clower(double x, double m, double sr) { return 1.0 - cupper(1.0 - x, m, sr); } // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery - static inline double cupper2 (double x, double m, double hr) + static inline double cupper2(double x, double m, double hr) { double x1 = (1.0 - hr) / m; double x2 = x1 + hr; @@ -187,7 +188,7 @@ protected: return 1.0 - hr + hr * baseu((x - x1) / hr, m, 0.3 * hr); } - static inline double clower2 (double x, double m, double sr) + static inline double clower2(double x, double m, double sr) { //curve for b<0; starts with positive slope and then rolls over toward straight line to x=y=1 double x1 = sr / 1.5 + 0.00001; @@ -201,7 +202,7 @@ protected: } // tone curve base. a: slope (from exp.comp.), b: black point normalized by 65535, // D: max. x value (can be>1), hr,sr: highlight,shadow recovery - static inline double basecurve (double x, double a, double b, double D, double hr, double sr) + static inline double basecurve(double x, double a, double b, double D, double hr, double sr) { if (b < 0) { double m = 0.5;//midpoint @@ -219,7 +220,7 @@ protected: double y = a * D > 1.0 ? 0.25 : (m - b / a) * slope; if (x <= m) { - return b == 0 ? x * slope : clower (x / m, slope * m / y, sr) * y; + return b == 0 ? x * slope : clower(x / m, slope * m / y, sr) * y; } else if (a * D > 1.0) { return y + (1.0 - y) * cupper2((x - m) / (D - m), slope * (D - m) / (1.0 - y), hr); } else { @@ -227,7 +228,7 @@ protected: } } } - static inline double simplebasecurve (double x, double b, double sr) + static inline double simplebasecurve(double x, double b, double sr) { // a = 1, D = 1, hr = 0 (unused for a = D = 1) if (b == 0.0) { @@ -248,7 +249,7 @@ protected: double y = (m - b) * slope; if (x <= m) { - return clower (x / m, slope * m / y, sr) * y; + return clower(x / m, slope * m / y, sr) * y; } else { return y + (x - m) * slope; } @@ -281,58 +282,58 @@ public: } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - static inline double centercontrast (double x, double b, double m); + static inline double centercontrast(double x, double b, double m); // standard srgb gamma and its inverse - static inline double gamma2 (double x) + static inline double gamma2(double x) { return x <= 0.00304 ? x * 12.92310 : 1.055 * exp(log(x) / sRGBGammaCurve) - 0.055; } - static inline double igamma2 (double x) + static inline double igamma2(double x) { return x <= 0.03928 ? x / 12.92310 : exp(log((x + 0.055) / 1.055) * sRGBGammaCurve); } - static inline float gamma2 (float x) + static inline float gamma2(float x) { return x <= 0.00304f ? x * 12.92310f : 1.055f * expf(logf(x) / static_cast(sRGBGammaCurve)) - 0.055f; } - static inline float igamma2 (float x) + static inline float igamma2(float x) { return x <= 0.03928f ? x / 12.92310f : expf(logf((x + 0.055f) / 1.055f) * static_cast(sRGBGammaCurve)); } // gamma function with adjustable parameters - static inline double gamma (double x, double gamma, double start, double slope, double mul, double add) + static inline double gamma(double x, double gamma, double start, double slope, double mul, double add) { return (x <= start ? x*slope : exp(log(x) / gamma) * mul - add); } - static inline double igamma (double x, double gamma, double start, double slope, double mul, double add) + static inline double igamma(double x, double gamma, double start, double slope, double mul, double add) { - return (x <= start * slope ? x / slope : exp(log((x + add) / mul) * gamma) ); + return (x <= start * slope ? x / slope : exp(log((x + add) / mul) * gamma)); } - static inline float gamma (float x, float gamma, float start, float slope, float mul, float add) + static inline float gamma(float x, float gamma, float start, float slope, float mul, float add) { return (x <= start ? x*slope : xexpf(xlogf(x) / gamma) * mul - add); } - static inline float igamma (float x, float gamma, float start, float slope, float mul, float add) + static inline float igamma(float x, float gamma, float start, float slope, float mul, float add) { - return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); + return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma)); } #ifdef __SSE2__ - static inline vfloat igamma (vfloat x, vfloat gamma, vfloat start, vfloat slope, vfloat mul, vfloat add) + static inline vfloat igamma(vfloat x, vfloat gamma, vfloat start, vfloat slope, vfloat mul, vfloat add) { #if !defined(__clang__) - return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); + return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma)); #else return vself(vmaskf_le(x, start * slope), x / slope, xexpf(xlogf((x + add) / mul) * gamma)); #endif } #endif - static inline float hlcurve (const float exp_scale, const float comp, const float hlrange, float level) + static inline float hlcurve(const float exp_scale, const float comp, const float hlrange, float level) { if (comp > 0.f) { float val = level + (hlrange - 65536.f); - if(val == 0.0f) { // to avoid division by zero + if (val == 0.0f) { // to avoid division by zero val = 0.000001f; } @@ -350,29 +351,49 @@ public: } } + public: - static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, - const std::vector& curvePoints, const std::vector& curvePoints2, - const LUTu & histogram, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, + static void complexCurve(double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, + const std::vector& curvePoints, const std::vector& curvePoints2, + const LUTu & histogram, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, + int skip = 1); - int skip = 1); - static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, - ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); - - static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip); - - static void curveWavContL ( bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve,/* LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip); - static void curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); - static void mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); - - static void curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip); - - static void complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & clcutili, const std::vector& acurvePoints, - const std::vector& bcurvePoints, const std::vector& cccurvePoints, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, + static void complexCurvelocal(double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double cont, double lumare, + LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTf & lightCurveloc, float avg, int skip = 1); - static void complexLCurve (double br, double contr, const std::vector& curvePoints, const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); - static void curveLightBrightColor ( + static void Curvelocalhl(double ecomp, double hlcompr, double hlcomprthresh, LUTf & hlCurve); + + static void curveBW(const std::vector& curvePointsbw, const std::vector& curvePointsbw2, const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, + ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); + + static void curveCL(bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip); + + static void curveWavContL(bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve,/* LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip); + static void curveDehaContL(bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); + static void mapcurve(bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); + + static void curveToning(const std::vector& curvePoints, LUTf & ToningCurve, int skip); + + static void curveLocal(bool & locallutili, const std::vector& curvePoints, LUTf & LocalLCurve, int skip); + static void curveCCLocal(bool & localcutili, const std::vector& curvePoints, LUTf & LocalCCurve, int skip); + static void curveskLocal(bool & localskutili, const std::vector& curvePoints, LUTf & LocalskCurve, int skip); + static void curveexLocal(bool & localexutili, const std::vector& curvePoints, LUTf & LocalexCurve, int skip); + static void curvemaskLocal(bool & localmaskutili, const std::vector& curvePoints, LUTf & LocalmaskCurve, int skip); + + static void complexsgnCurve(bool & autili, bool & butili, bool & ccutili, bool & clcutili, const std::vector& acurvePoints, + const std::vector& bcurvePoints, const std::vector& cccurvePoints, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, + int skip = 1); + + static void localLCurve(double br, double contr,/* const std::vector& curvePoints,*/ LUTu & histogram, LUTf & outCurve, int skip, bool & utili); + + static void updatechroma( + const std::vector& cccurvePoints, + LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma + int skip = 1); + static void complexLCurve(double br, double contr, const std::vector& curvePoints, const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); + + static void curveLightBrightColor( const std::vector& curvePoints, const std::vector& curvePoints2, const std::vector& curvePoints3, @@ -382,7 +403,7 @@ public: ColorAppearance & outColCurve2, ColorAppearance & outColCurve3, int skip = 1); - static void RGBCurve (const std::vector& curvePoints, LUTf & outCurve, int skip); + static void RGBCurve(const std::vector& curvePoints, LUTf & outCurve, int skip); }; @@ -420,23 +441,23 @@ protected: double increment; int nbr_points; - static inline double p00 (double x, double prot) + static inline double p00(double x, double prot) { - return CurveFactory::clower (x, 2.0, prot); + return CurveFactory::clower(x, 2.0, prot); } - static inline double p11 (double x, double prot) + static inline double p11(double x, double prot) { - return CurveFactory::cupper (x, 2.0, prot); + return CurveFactory::cupper(x, 2.0, prot); } - static inline double p01 (double x, double prot) + static inline double p01(double x, double prot) { - return x <= 0.5 ? CurveFactory::clower (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::cupper ((x - 0.5) * 2, 2.0, prot) * 0.5; + return x <= 0.5 ? CurveFactory::clower(x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::cupper((x - 0.5) * 2, 2.0, prot) * 0.5; } - static inline double p10 (double x, double prot) + static inline double p10(double x, double prot) { - return x <= 0.5 ? CurveFactory::cupper (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::clower ((x - 0.5) * 2, 2.0, prot) * 0.5; + return x <= 0.5 ? CurveFactory::cupper(x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::clower((x - 0.5) * 2, 2.0, prot) * 0.5; } - static inline double pfull (double x, double prot, double sh, double hl) + static inline double pfull(double x, double prot, double sh, double hl) { return (1 - sh) * (1 - hl) * p00(x, prot) + sh * hl * p11(x, prot) + (1 - sh) * hl * p01(x, prot) + sh * (1 - hl) * p10(x, prot); } @@ -445,15 +466,15 @@ protected: void fillDyByDx(); public: - Curve (); - virtual ~Curve () {}; - void AddPolygons (); - int getSize () const; // return the number of control points + Curve(); + virtual ~Curve() {}; + void AddPolygons(); + int getSize() const; // return the number of control points void getControlPoint(int cpNum, double &x, double &y) const; - virtual double getVal (double t) const = 0; - virtual void getVal (const std::vector& t, std::vector& res) const = 0; + virtual double getVal(double t) const = 0; + virtual void getVal(const std::vector& t, std::vector& res) const = 0; - virtual bool isIdentity () const = 0; + virtual bool isIdentity() const = 0; }; class DiagonalCurve final : public Curve @@ -462,23 +483,23 @@ class DiagonalCurve final : public Curve protected: DiagonalCurveType kind; - void spline_cubic_set (); + void spline_cubic_set(); void catmull_rom_set(); - void NURBS_set (); + void NURBS_set(); public: - explicit DiagonalCurve (const std::vector& points, int ppn = CURVES_MIN_POLY_POINTS); - ~DiagonalCurve () override; + DiagonalCurve(const std::vector& points, int ppn = CURVES_MIN_POLY_POINTS); + ~DiagonalCurve() override; - double getVal (double t) const override; - void getVal (const std::vector& t, std::vector& res) const override; - bool isIdentity () const override + double getVal(double t) const override; + void getVal(const std::vector& t, std::vector& res) const override; + bool isIdentity() const override { return kind == DCT_Empty; }; }; -class FlatCurve final : public Curve, public rtengine::NonCopyable +class FlatCurve final : public Curve { private: @@ -488,17 +509,17 @@ private: double identityValue; bool periodic; - void CtrlPoints_set (); + void CtrlPoints_set(); public: - explicit FlatCurve (const std::vector& points, bool isPeriodic = true, int ppn = CURVES_MIN_POLY_POINTS); - ~FlatCurve () override; + FlatCurve(const std::vector& points, bool isPeriodic = true, int ppn = CURVES_MIN_POLY_POINTS); + ~FlatCurve() override; - double getVal (double t) const override; - void getVal (const std::vector& t, std::vector& res) const override; - bool setIdentityValue (double iVal); - bool isIdentity () const override + double getVal(double t) const override; + void getVal(const std::vector& t, std::vector& res) const override; + bool setIdentityValue(double iVal); + bool isIdentity() const override { return kind == FCT_Empty; }; @@ -581,11 +602,11 @@ public: void Set(const std::vector &curvePoints, bool &opautili); // TODO: transfer this method to the Color class... - float blend (float x, float lower, float upper) const + float blend(float x, float lower, float upper) const { return (upper - lower) * lutOpacityCurve[x * 500.f] + lower; } - void blend3f (float x, float lower1, float upper1, float &result1, float lower2, float upper2, float &result2, float lower3, float upper3, float &result3) const + void blend3f(float x, float lower1, float upper1, float &result1, float lower2, float upper2, float &result2, float lower3, float upper3, float &result3) const { float opacity = lutOpacityCurve[x * 500.f]; result1 = (upper1 - lower1) * opacity + lower1; @@ -599,6 +620,795 @@ public: } }; +class LocLHCurve +{ +private: + LUTf lutLocLHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLHCurve() {}; + LocLHCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool &LHutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLHCurve[index]; + } + operator bool (void) const + { + return lutLocLHCurve; + } +}; + +class LocHHmaskblCurve +{ +private: + LUTf lutLocHHmaskblCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmaskblCurve() {}; + LocHHmaskblCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmasblutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmaskblCurve[index]; + } + operator bool (void) const + { + return lutLocHHmaskblCurve; + } +}; + +class LocCCmaskblCurve +{ +private: + LUTf lutLocCCmaskblCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmaskblCurve() {}; + LocCCmaskblCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmasblutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmaskblCurve[index]; + } + operator bool (void) const + { + return lutLocCCmaskblCurve; + } +}; + +class LocLLmaskblCurve +{ +private: + LUTf lutLocLLmaskblCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmaskblCurve() {}; + LocLLmaskblCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmasblutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmaskblCurve[index]; + } + operator bool (void) const + { + return lutLocLLmaskblCurve; + } +}; + + + +class LocHHmasktmCurve +{ +private: + LUTf lutLocHHmasktmCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmasktmCurve() {}; + LocHHmasktmCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmastmutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmasktmCurve[index]; + } + operator bool (void) const + { + return lutLocHHmasktmCurve; + } +}; + + +class LocCCmasktmCurve +{ +private: + LUTf lutLocCCmasktmCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmasktmCurve() {}; + LocCCmasktmCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmastmutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmasktmCurve[index]; + } + operator bool (void) const + { + return lutLocCCmasktmCurve; + } +}; + +class LocLLmasktmCurve +{ +private: + LUTf lutLocLLmasktmCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmasktmCurve() {}; + LocLLmasktmCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmastmutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmasktmCurve[index]; + } + operator bool (void) const + { + return lutLocLLmasktmCurve; + } +}; + + + +class LocHHmaskretiCurve +{ +private: + LUTf lutLocHHmaskretiCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmaskretiCurve() {}; + LocHHmaskretiCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmasretiutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmaskretiCurve[index]; + } + operator bool (void) const + { + return lutLocHHmaskretiCurve; + } +}; + + +class LocCCmaskretiCurve +{ +private: + LUTf lutLocCCmaskretiCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmaskretiCurve() {}; + LocCCmaskretiCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmasretiutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmaskretiCurve[index]; + } + operator bool (void) const + { + return lutLocCCmaskretiCurve; + } +}; + +class LocLLmaskretiCurve +{ +private: + LUTf lutLocLLmaskretiCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmaskretiCurve() {}; + LocLLmaskretiCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmasretiutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmaskretiCurve[index]; + } + operator bool (void) const + { + return lutLocLLmaskretiCurve; + } +}; + + + + + +class LocHHmaskcbCurve +{ +private: + LUTf lutLocHHmaskcbCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmaskcbCurve() {}; + LocHHmaskcbCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmascbutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmaskcbCurve[index]; + } + operator bool (void) const + { + return lutLocHHmaskcbCurve; + } +}; + + +class LocCCmaskcbCurve +{ +private: + LUTf lutLocCCmaskcbCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmaskcbCurve() {}; + LocCCmaskcbCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmascbutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmaskcbCurve[index]; + } + operator bool (void) const + { + return lutLocCCmaskcbCurve; + } +}; + +class LocLLmaskcbCurve +{ +private: + LUTf lutLocLLmaskcbCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmaskcbCurve() {}; + LocLLmaskcbCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmascbutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmaskcbCurve[index]; + } + operator bool (void) const + { + return lutLocLLmaskcbCurve; + } +}; + + + + +class LocHHmaskexpCurve +{ +private: + LUTf lutLocHHmaskexpCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmaskexpCurve() {}; + LocHHmaskexpCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmasexputili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmaskexpCurve[index]; + } + operator bool (void) const + { + return lutLocHHmaskexpCurve; + } +}; + + +class LocCCmaskexpCurve +{ +private: + LUTf lutLocCCmaskexpCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmaskexpCurve() {}; + LocCCmaskexpCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmasexputili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmaskexpCurve[index]; + } + operator bool (void) const + { + return lutLocCCmaskexpCurve; + } +}; + +class LocLLmaskexpCurve +{ +private: + LUTf lutLocLLmaskexpCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmaskexpCurve() {}; + LocLLmaskexpCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmasexputili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmaskexpCurve[index]; + } + operator bool (void) const + { + return lutLocLLmaskexpCurve; + } +}; + + +class LocHHmaskSHCurve +{ +private: + LUTf lutLocHHmaskSHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmaskSHCurve() {}; + LocHHmaskSHCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmasSHutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmaskSHCurve[index]; + } + operator bool (void) const + { + return lutLocHHmaskSHCurve; + } +}; + + +class LocCCmaskSHCurve +{ +private: + LUTf lutLocCCmaskSHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmaskSHCurve() {}; + LocCCmaskSHCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmasSHutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmaskSHCurve[index]; + } + operator bool (void) const + { + return lutLocCCmaskSHCurve; + } +}; + +class LocLLmaskSHCurve +{ +private: + LUTf lutLocLLmaskSHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmaskSHCurve() {}; + LocLLmaskSHCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmasSHutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmaskSHCurve[index]; + } + operator bool (void) const + { + return lutLocLLmaskSHCurve; + } +}; + + + + +class LocHHmaskCurve +{ +private: + LUTf lutLocHHmaskCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHmaskCurve() {}; + LocHHmaskCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lhmasutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHmaskCurve[index]; + } + operator bool (void) const + { + return lutLocHHmaskCurve; + } +}; + + +class LocCCmaskCurve +{ +private: + LUTf lutLocCCmaskCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCCmaskCurve() {}; + LocCCmaskCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & lcmasutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCCmaskCurve[index]; + } + operator bool (void) const + { + return lutLocCCmaskCurve; + } +}; + +class LocLLmaskCurve +{ +private: + LUTf lutLocLLmaskCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLLmaskCurve() {}; + LocLLmaskCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool & llmasutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocLLmaskCurve[index]; + } + operator bool (void) const + { + return lutLocLLmaskCurve; + } +}; + + +class LocHHCurve +{ +private: + LUTf lutLocHHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocHHCurve() {}; + LocHHCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool &HHutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHCurve[index]; + } + operator bool (void) const + { + return lutLocHHCurve; + } +}; + +class LocretigainCurve +{ +private: + LUTf lutLocretigainCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocretigainCurve() {}; + LocretigainCurve(); + void Reset(); + void Set(const std::vector &curvePoints); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocretigainCurve[index]; + } + operator bool (void) const + { + return lutLocretigainCurve; + } +}; + +class LocretitransCurve +{ +private: + LUTf lutLocretitransCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocretitransCurve() {}; + LocretitransCurve(); + void Reset(); + void Set(const std::vector &curvePoints); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocretitransCurve[index]; + } + operator bool (void) const + { + return lutLocretitransCurve; + } +}; + + +class LocwavCurve +{ +private: + LUTf lutLocwavCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocwavCurve() {}; + LocwavCurve(); + void Reset(); + void Set(const std::vector &curvePoints, bool &lcwavutili); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocwavCurve[index]; + } + +#ifdef __SSE2__ + vfloat operator[](vfloat index) const + { + return lutLocwavCurve[index]; + } +#endif + + operator bool (void) const + { + return lutLocwavCurve; + } +}; + + +class LocretigainCurverab +{ +private: + LUTf lutLocretigainCurverab; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocretigainCurverab() {}; + LocretigainCurverab(); + void Reset(); + void Set(const std::vector &curvePoints); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocretigainCurverab[index]; + } + operator bool (void) const + { + return lutLocretigainCurverab; + } +}; + + class WavCurve { private: @@ -673,6 +1483,32 @@ public: return lutOpacityCurveRG; } }; + +class WavOpacityCurveSH +{ +private: + LUTf lutOpacityCurveSH; // 0xffff range + void Set(const Curve &pCurve); +public: + virtual ~WavOpacityCurveSH() {}; + WavOpacityCurveSH(); + + void Reset(); + // void Set(const std::vector &curvePoints, bool &opautili); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutOpacityCurveSH[index]; + } + + operator bool (void) const + { + return lutOpacityCurveSH; + } +}; + + + class WavOpacityCurveBY { private: @@ -824,10 +1660,10 @@ public: }; //lightness curve -inline void Lightcurve::Apply (float& Li) const +inline void Lightcurve::Apply(float& Li) const { - assert (lutColCurve); + assert(lutColCurve); curves::setLutVal(lutColCurve, Li); } @@ -839,10 +1675,10 @@ public: }; //brightness curve -inline void Brightcurve::Apply (float& Br) const +inline void Brightcurve::Apply(float& Br) const { - assert (lutColCurve); + assert(lutColCurve); curves::setLutVal(lutColCurve, Br); } @@ -854,10 +1690,10 @@ public: }; //Chroma curve -inline void Chromacurve::Apply (float& Cr) const +inline void Chromacurve::Apply(float& Cr) const { - assert (lutColCurve); + assert(lutColCurve); curves::setLutVal(lutColCurve, Cr); } @@ -868,10 +1704,10 @@ public: }; //Saturation curve -inline void Saturcurve::Apply (float& Sa) const +inline void Saturcurve::Apply(float& Sa) const { - assert (lutColCurve); + assert(lutColCurve); curves::setLutVal(lutColCurve, Sa); } @@ -883,10 +1719,10 @@ public: }; //Colorfullness curve -inline void Colorfcurve::Apply (float& Cf) const +inline void Colorfcurve::Apply(float& Cf) const { - assert (lutColCurve); + assert(lutColCurve); curves::setLutVal(lutColCurve, Cf); } @@ -901,8 +1737,8 @@ public: // and ending at `r[end]` (and respectively for `b` and `g`). Uses SSE // and requires that `r`, `g`, and `b` pointers have the same alignment. void BatchApply( - const size_t start, const size_t end, - float *r, float *g, float *b) const; + const size_t start, const size_t end, + float *r, float *g, float *b) const; }; class AdobeToneCurve : public ToneCurve @@ -971,27 +1807,30 @@ public: }; // Standard tone curve -inline void StandardToneCurve::Apply (float& r, float& g, float& b) const +inline void StandardToneCurve::Apply(float& r, float& g, float& b) const { - assert (lutToneCurve); + assert(lutToneCurve); curves::setLutVal(lutToneCurve, r, g, b); } + inline void StandardToneCurve::BatchApply( - const size_t start, const size_t end, - float *r, float *g, float *b) const { - assert (lutToneCurve); - assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); - assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); + const size_t start, const size_t end, + float *r, float *g, float *b) const +{ + assert(lutToneCurve); + assert(lutToneCurve.getClip() & LUT_CLIP_BELOW); + assert(lutToneCurve.getClip() & LUT_CLIP_ABOVE); // All pointers must have the same alignment for SSE usage. In the loop body below, // we will only check `r`, assuming that the same result would hold for `g` and `b`. - assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); - assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); + assert(reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); + assert(reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); size_t i = start; + while (true) { if (i >= end) { // If we get to the end before getting to an aligned address, just return. @@ -1003,11 +1842,13 @@ inline void StandardToneCurve::BatchApply( break; #endif } + setUnlessOOG(r[i], g[i], b[i], lutToneCurve[r[i]], lutToneCurve[g[i]], lutToneCurve[b[i]]); i++; } #ifdef __SSE2__ + for (; i + 3 < end; i += 4) { vfloat r_val = LVF(r[i]); vfloat g_val = LVF(g[i]); @@ -1022,39 +1863,40 @@ inline void StandardToneCurve::BatchApply( for (; i < end; ++i) { setUnlessOOG(r[i], g[i], b[i], lutToneCurve[r[i]], lutToneCurve[g[i]], lutToneCurve[b[i]]); } + #endif } // Tone curve according to Adobe's reference implementation // values in 0xffff space // inlined to make sure there will be no cache flush when used -inline void AdobeToneCurve::Apply (float& ir, float& ig, float& ib) const +inline void AdobeToneCurve::Apply(float& ir, float& ig, float& ib) const { - assert (lutToneCurve); + assert(lutToneCurve); float r = CLIP(ir); float g = CLIP(ig); float b = CLIP(ib); if (r >= g) { - if (g > b) { - RGBTone (r, g, b); // Case 1: r >= g > b + if (g > b) { + RGBTone(r, g, b); // Case 1: r >= g > b } else if (b > r) { - RGBTone (b, r, g); // Case 2: b > r >= g + RGBTone(b, r, g); // Case 2: b > r >= g } else if (b > g) { - RGBTone (r, b, g); // Case 3: r >= b > g + RGBTone(r, b, g); // Case 3: r >= b > g } else { // Case 4: r == g == b r = lutToneCurve[r]; g = lutToneCurve[g]; b = g; } } else { - if (r >= b) { - RGBTone (g, r, b); // Case 5: g > r >= b + if (r >= b) { + RGBTone(g, r, b); // Case 5: g > r >= b } else if (b > g) { - RGBTone (b, g, r); // Case 6: b > g > r + RGBTone(b, g, r); // Case 6: b > g > r } else { - RGBTone (g, b, r); // Case 7: g >= b > r + RGBTone(g, b, r); // Case 7: g >= b > r } } @@ -1146,19 +1988,20 @@ inline void AdobeToneCurve::RGBTone (vfloat& maxval, vfloat& medval, vfloat& min // Modifying the Luminance channel only inline void LuminanceToneCurve::Apply(float &ir, float &ig, float &ib) const { - assert (lutToneCurve); + assert(lutToneCurve); float r = CLIP(ir); float g = CLIP(ig); float b = CLIP(ib); float currLuminance = r * 0.2126729f + g * 0.7151521f + b * 0.0721750f; + const float newLuminance = lutToneCurve[currLuminance]; currLuminance = currLuminance == 0.f ? 0.00001f : currLuminance; const float coef = newLuminance / currLuminance; - r = LIM(r * coef, 0.f, 65535.f); - g = LIM(g * coef, 0.f, 65535.f); - b = LIM(b * coef, 0.f, 65535.f); + r = LIM (r * coef, 0.f, 65535.f); + g = LIM (g * coef, 0.f, 65535.f); + b = LIM (b * coef, 0.f, 65535.f); setUnlessOOG(ir, ig, ib, r, g, b); } @@ -1184,21 +2027,21 @@ inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const #ifdef __SSE2__ inline vfloat WeightedStdToneCurve::Triangle(vfloat a, vfloat a1, vfloat b) const { - vmask eqmask = vmaskf_eq(b, a); - vfloat a2 = a1 - a; - vmask cmask = vmaskf_lt(b, a); - vfloat b3 = vself(cmask, b, F2V(65535.f) - b); - vfloat a3 = vself(cmask, a, F2V(65535.f) - a); - return vself(eqmask, a1, b + a2 * b3 / a3); + vmask eqmask = vmaskf_eq(b, a); + vfloat a2 = a1 - a; + vmask cmask = vmaskf_lt(b, a); + vfloat b3 = vself(cmask, b, F2V(65535.f) - b); + vfloat a3 = vself(cmask, a, F2V(65535.f) - a); + return vself(eqmask, a1, b + a2 * b3 / a3); } #endif // Tone curve modifying the value channel only, preserving hue and saturation // values in 0xffff space -inline void WeightedStdToneCurve::Apply (float& ir, float& ig, float& ib) const +inline void WeightedStdToneCurve::Apply(float& ir, float& ig, float& ib) const { - assert (lutToneCurve); + assert(lutToneCurve); float r = CLIP(ir); float g = CLIP(ig); @@ -1216,23 +2059,25 @@ inline void WeightedStdToneCurve::Apply (float& ir, float& ig, float& ib) const float g3 = Triangle(b, b3, g); r = CLIP(r1 * 0.50f + r2 * 0.25f + r3 * 0.25f); - g = CLIP(g1 * 0.25f + g2 * 0.50f + g3 * 0.25f); - b = CLIP(b1 * 0.25f + b2 * 0.25f + b3 * 0.50f); + g = CLIP (g1 * 0.25f + g2 * 0.50f + g3 * 0.25f); + b = CLIP (b1 * 0.25f + b2 * 0.25f + b3 * 0.50f); setUnlessOOG(ir, ig, ib, r, g, b); } -inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const { - assert (lutToneCurve); - assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); - assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); +inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const +{ + assert(lutToneCurve); + assert(lutToneCurve.getClip() & LUT_CLIP_BELOW); + assert(lutToneCurve.getClip() & LUT_CLIP_ABOVE); // All pointers must have the same alignment for SSE usage. In the loop body below, // we will only check `r`, assuming that the same result would hold for `g` and `b`. - assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); - assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); + assert(reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); + assert(reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); size_t i = start; + while (true) { if (i >= end) { // If we get to the end before getting to an aligned address, just return. @@ -1244,6 +2089,7 @@ inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t en break; #endif } + Apply(r[i], g[i], b[i]); i++; } @@ -1285,6 +2131,7 @@ inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t en for (; i < end; ++i) { Apply(r[i], g[i], b[i]); } + #endif } diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index edb7dc317..a166ecf15 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -10048,7 +10048,7 @@ canon_a5: } else if (!strncmp(model, "X-A3", 4) || !strncmp(model, "X-A5", 4)) { width = raw_width = 6016; height = raw_height = 4014; - } else if (!strcmp(model, "X-Pro3") || !strcmp(model, "X-T3") || !strcmp(model, "X-T30")) { + } else if (!strcmp(model, "X-Pro3") || !strcmp(model, "X-T3") || !strcmp(model, "X-T30") || !strcmp(model, "X-T4") || !strcmp(model, "X100V")) { width = raw_width = 6384; height = raw_height = 4182; } diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 11bf19edf..99bc2581d 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -34,6 +34,8 @@ #include "../rtgui/editcallbacks.h" #include "guidedfilter.h" +#pragma GCC diagnostic warning "-Wall" +#pragma GCC diagnostic warning "-Wextra" namespace { @@ -50,8 +52,8 @@ namespace rtengine { Crop::Crop(ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow) - : PipetteBuffer(editDataProvider), origCrop(nullptr), laboCrop(nullptr), labnCrop(nullptr), - cropImg(nullptr), transCrop(nullptr), cieCrop(nullptr), + : PipetteBuffer(editDataProvider), origCrop(nullptr), laboCrop(nullptr), labnCrop(nullptr), reservCrop(nullptr), lastorigCrop(nullptr), + cropImg(nullptr), shbuf_real(nullptr), transCrop(nullptr), cieCrop(nullptr), shbuffer(nullptr), updating(false), newUpdatePending(false), skip(10), cropx(0), cropy(0), cropw(-1), croph(-1), trafx(0), trafy(0), trafw(-1), trafh(-1), @@ -184,8 +186,8 @@ void Crop::update(int todo) setCropSizes(rqcropx, rqcropy, rqcropw, rqcroph, skip, true); } - // printf("x=%d y=%d crow=%d croh=%d skip=%d\n",rqcropx, rqcropy, rqcropw, rqcroph, skip); - // printf("trafx=%d trafyy=%d trafwsk=%d trafHs=%d \n",trafx, trafy, trafw*skip, trafh*skip); + // printf("x=%d y=%d crow=%d croh=%d skip=%d\n",rqcropx, rqcropy, rqcropw, rqcroph, skip); + // printf("trafx=%d trafyy=%d trafwsk=%d trafHs=%d \n",trafx, trafy, trafw*skip, trafh*skip); Imagefloat *calclum = nullptr;//for Luminance denoise curve NoiseCurve noiseLCurve; @@ -735,8 +737,8 @@ void Crop::update(int todo) } if (need_fattal) { - parent->ipf.dehaze(f); - parent->ipf.ToneMapFattal02(f); + parent->ipf.dehaze(f, params.dehaze); + parent->ipf.ToneMapFattal02(f, params.fattal, 3, 0, nullptr, 0, 0, 0); } // crop back to the size expected by the rest of the pipeline @@ -849,9 +851,13 @@ void Crop::update(int todo) }*/ // apply luminance operations - if (todo & (M_LUMINANCE + M_COLOR)) { + //bool tutu = true; + if (todo & (M_LUMINANCE + M_COLOR)) { // + //if (tutu) { // //I made a little change here. Rather than have luminanceCurve (and others) use in/out lab images, we can do more if we copy right here. labnCrop->CopyFrom(laboCrop); + reservCrop->CopyFrom(laboCrop); + lastorigCrop->CopyFrom(laboCrop); //parent->ipf.luminanceCurve (labnCrop, labnCrop, parent->lumacurve); @@ -862,10 +868,387 @@ void Crop::update(int todo) bool clcutili = parent->clcutili; bool cclutili = parent->cclutili; - LUTu dummy; + bool locallutili = parent->locallutili; + LUTf lllocalcurve2(65536, 0); + bool localclutili = parent->localclutili; + LUTf cllocalcurve2(65536, 0); + bool locallcutili = parent->locallcutili; + LUTf lclocalcurve2(65536, 0); + bool localcutili = parent->locallutili; + LUTf cclocalcurve2(65536, 0); + bool localrgbutili = parent->localrgbutili; + LUTf rgblocalcurve2(65536, 0); + bool localexutili = parent->localexutili; + LUTf exlocalcurve2(65536, 0); + bool localmaskutili = parent->localmaskutili; + bool localmaskexputili = parent->localmaskexputili; + bool localmaskSHutili = parent->localmaskSHutili; + bool localmaskvibutili = parent->localmaskvibutili; + bool localmasktmutili = parent->localmasktmutili; + bool localmaskretiutili = parent->localmaskretiutili; + bool localmaskcbutili = parent->localmaskcbutili; + bool localmaskblutili = parent->localmaskblutili; + bool localmasklcutili = parent->localmasklcutili; + LUTf lmasklocalcurve2(65536, 0); + LUTf lmaskexplocalcurve2(65536, 0); + LUTf lmaskSHlocalcurve2(65536, 0); + LUTf lmaskviblocalcurve2(65536, 0); + LUTf lmasktmlocalcurve2(65536, 0); + LUTf lmaskretilocalcurve2(65536, 0); + LUTf lmaskcblocalcurve2(65536, 0); + LUTf lmaskbllocalcurve2(65536, 0); + LUTf lmasklclocalcurve2(65536, 0); + LUTf hltonecurveloc2(65536, 0); //65536 + LUTf shtonecurveloc2(65536, 0); + LUTf tonecurveloc2(65536, 0); + LUTf lightCurveloc2(32770, 0); + bool LHutili = parent->LHutili; + bool HHutili = parent->HHutili; + bool llmasutili = parent->llmasutili; + bool lhmasutili = parent->lhmasutili; + bool lhhmasutili = parent->lhhmasutili; + bool lcmasutili = parent->lcmasutili; + bool lhmasexputili = parent->lhmasexputili; + bool lcmasexputili = parent->lcmasexputili; + bool llmasexputili = parent->llmasexputili; + bool lhmasSHutili = parent->lhmasSHutili; + bool lcmasSHutili = parent->lcmasSHutili; + bool llmasSHutili = parent->llmasSHutili; + bool lhmasvibutili = parent->lhmasvibutili; + bool lcmasvibutili = parent->lcmasvibutili; + bool llmasvibutili = parent->llmasvibutili; + bool lhmaslcutili = parent->lhmaslcutili; + bool lcmaslcutili = parent->lcmaslcutili; + bool llmaslcutili = parent->llmaslcutili; + bool lhmascbutili = parent->lhmascbutili; + bool lcmascbutili = parent->lcmascbutili; + bool llmascbutili = parent->llmascbutili; + bool lhmasretiutili = parent->lhmasretiutili; + bool lcmasretiutili = parent->lcmasretiutili; + bool llmasretiutili = parent->llmasretiutili; + bool lhmastmutili = parent->lhmastmutili; + bool lcmastmutili = parent->lcmastmutili; + bool llmastmutili = parent->llmastmutili; + bool lhmasblutili = parent->lhmasblutili; + bool lcmasblutili = parent->lcmasblutili; + bool llmasblutili = parent->llmasblutili; + bool locwavutili = parent->locwavutili; + bool locwavdenutili = parent->locwavdenutili; + bool loclevwavutili = parent->loclevwavutili; + bool locconwavutili = parent->locconwavutili; + bool loccompwavutili = parent->loccompwavutili; + bool loccomprewavutili = parent->loccomprewavutili; + bool locedgwavutili = parent->locedgwavutili; + bool lmasutiliblwav = parent->lmasutiliblwav; + bool lmasutilicolwav = parent->lmasutilicolwav; + // float avg = parent->avg; + LUTu dummy; + bool needslocal = params.locallab.enabled; + LocretigainCurve locRETgainCurve; + LocretitransCurve locRETtransCurve; + LocLHCurve loclhCurve; + LocHHCurve lochhCurve; + LocCCmaskCurve locccmasCurve; + LocLLmaskCurve locllmasCurve; + LocHHmaskCurve lochhmasCurve; + LocHHmaskCurve lochhhmasCurve; + LocCCmaskCurve locccmasexpCurve; + LocLLmaskCurve locllmasexpCurve; + LocHHmaskCurve lochhmasexpCurve; + LocCCmaskCurve locccmasSHCurve; + LocLLmaskCurve locllmasSHCurve; + LocHHmaskCurve lochhmasSHCurve; + // LocHHmaskCurve lochhhmasSHCurve; + LocCCmaskCurve locccmasvibCurve; + LocLLmaskCurve locllmasvibCurve; + LocHHmaskCurve lochhmasvibCurve; + LocCCmaskCurve locccmaslcCurve; + LocLLmaskCurve locllmaslcCurve; + LocHHmaskCurve lochhmaslcCurve; + LocCCmaskCurve locccmascbCurve; + LocLLmaskCurve locllmascbCurve; + LocHHmaskCurve lochhmascbCurve; + LocCCmaskCurve locccmasretiCurve; + LocLLmaskCurve locllmasretiCurve; + LocHHmaskCurve lochhmasretiCurve; + LocCCmaskCurve locccmastmCurve; + LocLLmaskCurve locllmastmCurve; + LocHHmaskCurve lochhmastmCurve; + LocCCmaskCurve locccmasblCurve; + LocLLmaskCurve locllmasblCurve; + LocHHmaskCurve lochhmasblCurve; + LocwavCurve locwavCurve; + LocwavCurve loclmasCurveblwav; + LocwavCurve loclmasCurvecolwav; + LocwavCurve loclevwavCurve; + LocwavCurve locconwavCurve; + LocwavCurve loccompwavCurve; + LocwavCurve loccomprewavCurve; + LocwavCurve locedgwavCurve; + LocwavCurve locwavCurveden; + + LocretigainCurverab locRETgainCurverab; + locallutili = false; + int sca = skip; + + // bool tyty = false; + // int maxspot = 1; + + if (needslocal) { + for (int sp = 0; sp < (int)params.locallab.spots.size(); sp++) { + locRETgainCurve.Set(params.locallab.spots.at(sp).localTgaincurve); + locRETtransCurve.Set(params.locallab.spots.at(sp).localTtranscurve); + loclhCurve.Set(params.locallab.spots.at(sp).LHcurve, LHutili); + lochhCurve.Set(params.locallab.spots.at(sp).HHcurve, HHutili); + locccmasCurve.Set(params.locallab.spots.at(sp).CCmaskcurve, lcmasutili); + locllmasCurve.Set(params.locallab.spots.at(sp).LLmaskcurve, llmasutili); + lochhmasCurve.Set(params.locallab.spots.at(sp).HHmaskcurve, lhmasutili); + lochhhmasCurve.Set(params.locallab.spots.at(sp).HHhmaskcurve, lhhmasutili); + locccmasexpCurve.Set(params.locallab.spots.at(sp).CCmaskexpcurve, lcmasexputili); + locllmasexpCurve.Set(params.locallab.spots.at(sp).LLmaskexpcurve, llmasexputili); + lochhmasexpCurve.Set(params.locallab.spots.at(sp).HHmaskexpcurve, lhmasexputili); + locccmasSHCurve.Set(params.locallab.spots.at(sp).CCmaskSHcurve, lcmasSHutili); + locllmasSHCurve.Set(params.locallab.spots.at(sp).LLmaskSHcurve, llmasSHutili); + lochhmasSHCurve.Set(params.locallab.spots.at(sp).HHmaskSHcurve, lhmasSHutili); + locccmasvibCurve.Set(params.locallab.spots.at(sp).CCmaskvibcurve, lcmasvibutili); + locllmasvibCurve.Set(params.locallab.spots.at(sp).LLmaskvibcurve, llmasvibutili); + lochhmasvibCurve.Set(params.locallab.spots.at(sp).HHmaskvibcurve, lhmasvibutili); + locccmascbCurve.Set(params.locallab.spots.at(sp).CCmaskcbcurve, lcmascbutili); + locllmascbCurve.Set(params.locallab.spots.at(sp).LLmaskcbcurve, llmascbutili); + lochhmascbCurve.Set(params.locallab.spots.at(sp).HHmaskcbcurve, lhmascbutili); + locccmasretiCurve.Set(params.locallab.spots.at(sp).CCmaskreticurve, lcmasretiutili); + locllmasretiCurve.Set(params.locallab.spots.at(sp).LLmaskreticurve, llmasretiutili); + lochhmasretiCurve.Set(params.locallab.spots.at(sp).HHmaskreticurve, lhmasretiutili); + locccmastmCurve.Set(params.locallab.spots.at(sp).CCmasktmcurve, lcmastmutili); + locllmastmCurve.Set(params.locallab.spots.at(sp).LLmasktmcurve, llmastmutili); + lochhmastmCurve.Set(params.locallab.spots.at(sp).HHmasktmcurve, lhmastmutili); + locccmasblCurve.Set(params.locallab.spots.at(sp).CCmaskblcurve, lcmasblutili); + locllmasblCurve.Set(params.locallab.spots.at(sp).LLmaskblcurve, llmasblutili); + lochhmasblCurve.Set(params.locallab.spots.at(sp).HHmaskblcurve, lhmasblutili); + loclmasCurveblwav.Set(params.locallab.spots.at(sp).LLmaskblcurvewav, lmasutiliblwav); + loclmasCurvecolwav.Set(params.locallab.spots.at(sp).LLmaskcolcurvewav, lmasutilicolwav); + locccmaslcCurve.Set(params.locallab.spots.at(sp).CCmasklccurve, lcmaslcutili); + locllmaslcCurve.Set(params.locallab.spots.at(sp).LLmasklccurve, llmaslcutili); + lochhmaslcCurve.Set(params.locallab.spots.at(sp).HHmasklccurve, lhmaslcutili); + + locwavCurve.Set(params.locallab.spots.at(sp).locwavcurve, locwavutili); + locwavCurveden.Set(params.locallab.spots.at(sp).locwavcurveden, locwavdenutili); + loclevwavCurve.Set(params.locallab.spots.at(sp).loclevwavcurve, loclevwavutili); + locconwavCurve.Set(params.locallab.spots.at(sp).locconwavcurve, locconwavutili); + loccompwavCurve.Set(params.locallab.spots.at(sp).loccompwavcurve, loccompwavutili); + loccomprewavCurve.Set(params.locallab.spots.at(sp).loccomprewavcurve, loccomprewavutili); + locedgwavCurve.Set(params.locallab.spots.at(sp).locedgwavcurve, locedgwavutili); + locallutili = false; + CurveFactory::curveLocal(locallutili, params.locallab.spots.at(sp).llcurve, lllocalcurve2, sca); + localclutili = false; + CurveFactory::curveLocal(localclutili, params.locallab.spots.at(sp).clcurve, cllocalcurve2, sca); + locallcutili = false; + CurveFactory::curveLocal(locallcutili, params.locallab.spots.at(sp).lccurve, lclocalcurve2, sca); + localrgbutili = false; + CurveFactory::curveLocal(localrgbutili, params.locallab.spots.at(sp).rgbcurve, rgblocalcurve2, sca); + localcutili = false; + CurveFactory::curveCCLocal(localcutili, params.locallab.spots.at(sp).cccurve, cclocalcurve2, sca); + localexutili = false; + CurveFactory::curveexLocal(localexutili, params.locallab.spots.at(sp).excurve, exlocalcurve2, sca); + localmaskutili = false; + CurveFactory::curvemaskLocal(localmaskutili, params.locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve2, sca); + localmaskexputili = false; + CurveFactory::curvemaskLocal(localmaskexputili, params.locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve2, sca); + localmaskSHutili = false; + CurveFactory::curvemaskLocal(localmaskSHutili, params.locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve2, sca); + localmaskvibutili = false; + CurveFactory::curvemaskLocal(localmaskvibutili, params.locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve2, sca); + localmasktmutili = false; + CurveFactory::curvemaskLocal(localmasktmutili, params.locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve2, sca); + localmaskretiutili = false; + CurveFactory::curvemaskLocal(localmaskretiutili, params.locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve2, sca); + localmaskcbutili = false; + CurveFactory::curvemaskLocal(localmaskcbutili, params.locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve2, sca); + localmasklcutili = false; + CurveFactory::curvemaskLocal(localmasklcutili, params.locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve2, sca); + localmaskblutili = false; + CurveFactory::curvemaskLocal(localmaskblutili, params.locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve2, sca); + + double ecomp = params.locallab.spots.at(sp).expcomp; + double black = params.locallab.spots.at(sp).black; + double hlcompr = params.locallab.spots.at(sp).hlcompr; + double hlcomprthresh = params.locallab.spots.at(sp).hlcomprthresh; + double shcompr = params.locallab.spots.at(sp).shcompr; + double br = params.locallab.spots.at(sp).lightness; + if(black < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) { + black *= 1.5; + } + + double cont = params.locallab.spots.at(sp).contrast; + double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre; + int lastsav; + float avge; + huerefblu = parent->huerefblurs[sp]; + chromarefblu = parent->chromarefblurs[sp]; + lumarefblu = parent->lumarefblurs[sp]; + huere = parent->huerefs[sp]; + chromare = parent->chromarefs[sp]; + lumare = parent->lumarefs[sp]; + sobelre = parent->sobelrefs[sp]; + avge = parent->avgs[sp]; + + lastsav = parent->lastsavrests[sp]; + + float minCD; + float maxCD; + float mini; + float maxi; + float Tmean; + float Tsigma; + float Tmin; + float Tmax; + CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumare, + hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2, avge, + sca); + // Locallab mask are only shown for selected spot + if (sp == params.locallab.selspot) { + parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop, lastorigCrop, cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve, + lllocalcurve2,locallutili, + cllocalcurve2, localclutili, + lclocalcurve2, locallcutili, + loclhCurve, lochhCurve, + lmasklocalcurve2, localmaskutili, + lmaskexplocalcurve2, localmaskexputili, + lmaskSHlocalcurve2, localmaskSHutili, + lmaskviblocalcurve2, localmaskvibutili, + lmasktmlocalcurve2, localmasktmutili, + lmaskretilocalcurve2, localmaskretiutili, + lmaskcblocalcurve2, localmaskcbutili, + lmaskbllocalcurve2, localmaskblutili, + lmasklclocalcurve2, localmasklcutili, + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, + locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, + locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili, + locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, + locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, + locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili, + locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili, + loclmasCurveblwav,lmasutiliblwav, + loclmasCurvecolwav,lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + LHutili, HHutili, cclocalcurve2, localcutili, rgblocalcurve2, localrgbutili, localexutili, exlocalcurve2, hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2, + huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, + parent->previewDeltaE, parent->locallColorMask, parent->locallColorMaskinv, parent->locallExpMask, parent->locallExpMaskinv, parent->locallSHMask, parent->locallSHMaskinv, parent->locallvibMask, parent->localllcMask, parent->locallsharMask, parent->locallcbMask, parent->locallretiMask, parent->locallsoftMask, parent->localltmMask, parent->locallblMask, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } else { + parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop, lastorigCrop, cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve, + lllocalcurve2,locallutili, + cllocalcurve2, localclutili, + lclocalcurve2, locallcutili, + loclhCurve, lochhCurve, + lmasklocalcurve2, localmaskutili, + lmaskexplocalcurve2, localmaskexputili, + lmaskSHlocalcurve2, localmaskSHutili, + lmaskviblocalcurve2, localmaskvibutili, + lmasktmlocalcurve2, localmasktmutili, + lmaskretilocalcurve2, localmaskretiutili, + lmaskcblocalcurve2, localmaskcbutili, + lmaskbllocalcurve2, localmaskblutili, + lmasklclocalcurve2, localmasklcutili, + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili,lochhhmasCurve, lhhmasutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, + locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, + locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili, + locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, + locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, + locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili, + locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili, + loclmasCurveblwav,lmasutiliblwav, + loclmasCurvecolwav,lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + LHutili, HHutili, cclocalcurve2, localcutili, rgblocalcurve2, localrgbutili, localexutili, exlocalcurve2, hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2, + huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } + + lastorigCrop->CopyFrom(labnCrop); + + lllocalcurve2.clear(); + lclocalcurve2.clear(); + cllocalcurve2.clear(); + lightCurveloc2.clear(); + rgblocalcurve2.clear(); + cclocalcurve2.clear(); + exlocalcurve2.clear(); + lmasklocalcurve2.clear(); + lmaskexplocalcurve2.clear(); + lmaskSHlocalcurve2.clear(); + lmaskviblocalcurve2.clear(); + lmasktmlocalcurve2.clear(); + lmaskretilocalcurve2.clear(); + lmaskcblocalcurve2.clear(); + lmaskbllocalcurve2.clear(); + hltonecurveloc2.clear(); + shtonecurveloc2.clear(); + tonecurveloc2.clear(); + locRETgainCurve.Reset(); + locRETtransCurve.Reset(); + loclhCurve.Reset(); + lochhCurve.Reset(); + locccmasCurve.Reset(); + locllmasCurve.Reset(); + lochhmasCurve.Reset(); + lochhhmasCurve.Reset(); + locllmasexpCurve.Reset(); + locccmasexpCurve.Reset(); + lochhmasexpCurve.Reset(); + locllmasSHCurve.Reset(); + locccmasSHCurve.Reset(); + lochhmasSHCurve.Reset(); + locllmasvibCurve.Reset(); + locccmasvibCurve.Reset(); + lochhmasvibCurve.Reset(); + locllmascbCurve.Reset(); + locccmascbCurve.Reset(); + lochhmascbCurve.Reset(); + locllmasretiCurve.Reset(); + locccmasretiCurve.Reset(); + lochhmasretiCurve.Reset(); + locllmastmCurve.Reset(); + locccmastmCurve.Reset(); + lochhmastmCurve.Reset(); + locllmasblCurve.Reset(); + locccmasblCurve.Reset(); + lochhmasblCurve.Reset(); + locllmaslcCurve.Reset(); + locccmaslcCurve.Reset(); + lochhmaslcCurve.Reset(); + locwavCurve.Reset(); + loclevwavCurve.Reset(); + locconwavCurve.Reset(); + locconwavCurve.Reset(); + locwavCurveden.Reset(); + loclmasCurveblwav.Reset(); + loclmasCurvecolwav.Reset(); + + if (skip <= 2) { + Glib::usleep(settings->cropsleep); //wait to avoid crash when crop 100% and move window + } + } + } + + // int moderetinex; parent->ipf.chromiLuminanceCurve(this, 1, labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->clcurve, parent->lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); - parent->ipf.vibrance(labnCrop); + parent->ipf.vibrance(labnCrop, params.vibrance, params.toneCurve.hrenabled, params.icm.workingProfile); parent->ipf.labColorCorrectionRegions(labnCrop); if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { @@ -969,12 +1352,14 @@ void Crop::update(int todo) WavCurve wavCLVCurve; Wavblcurve wavblcurve; WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveSH waOpacityCurveSH; WavOpacityCurveBY waOpacityCurveBY; WavOpacityCurveW waOpacityCurveW; WavOpacityCurveWL waOpacityCurveWL; + LUTf wavclCurve; - params.wavelet.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); + params.wavelet.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); LabImage *unshar = nullptr; Glib::ustring provis; LabImage *provradius = nullptr; @@ -1003,7 +1388,7 @@ void Crop::update(int todo) unshar = new LabImage(labnCrop->W, labnCrop->H); provis = params.wavelet.CLmethod; params.wavelet.CLmethod = "all"; - parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); + parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); unshar->CopyFrom(labnCrop); params.wavelet.CLmethod = provis; @@ -1016,7 +1401,11 @@ void Crop::update(int todo) WaveParams.expnoise = false; } - parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); + parent->ipf.softLight(labnCrop, params.softlight); + +// parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); + + parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { WaveParams.expcontrast = procont; @@ -1142,8 +1531,6 @@ void Crop::update(int todo) } - parent->ipf.softLight(labnCrop); - if (params.colorappearance.enabled) { float fnum = parent->imgsrc->getMetaData()->getFNumber(); // F number float fiso = parent->imgsrc->getMetaData()->getISOSpeed() ; // ISO @@ -1242,11 +1629,28 @@ void Crop::freeAll() laboCrop = nullptr; } + if (labnCrop) { delete labnCrop; labnCrop = nullptr; } + if (reservCrop) { + delete reservCrop; + reservCrop = nullptr; + } + + if (lastorigCrop) { + delete lastorigCrop; + lastorigCrop = nullptr; + } + + + /* if (lablocCrop ) { + delete lablocCrop; + lablocCrop = NULL; + } + */ if (cropImg) { delete cropImg; cropImg = nullptr; @@ -1257,6 +1661,11 @@ void Crop::freeAll() cieCrop = nullptr; } + if (shbuffer) { + delete [] shbuffer; + shbuffer = nullptr; + } + PipetteBuffer::flush(); } @@ -1409,12 +1818,32 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter laboCrop = new LabImage(cropw, croph); + // if (translabCrop) translabCrop->reallocLab(); + if (labnCrop) { delete labnCrop; // labnCrop can't be resized } labnCrop = new LabImage(cropw, croph); + if (reservCrop) { + delete reservCrop; // labnCrop can't be resized + } + + reservCrop = new LabImage(cropw, croph); + + if (lastorigCrop) { + delete lastorigCrop; // labnCrop can't be resized + } + + lastorigCrop = new LabImage(cropw, croph); + + /* if (lablocCrop) { + delete lablocCrop; // labnCrop can't be resized + } + + lablocCrop = new LabImage (cropw, croph); + */ if (!cropImg) { cropImg = new Image8; } @@ -1427,6 +1856,21 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter cieCrop = nullptr; } + if (shbuffer) { + delete [] shbuffer; + } + + if (shbuf_real) { + delete [] shbuf_real; + } + + shbuffer = new float*[croph]; + shbuf_real = new float[(croph + 2)*cropw]; + + for (int i = 0; i < croph; i++) { + shbuffer[i] = shbuf_real + cropw * i + cropw; + } + if (editType == ET_PIPETTE) { PipetteBuffer::resize(cropw, croph); } else if (PipetteBuffer::bufferCreated()) { diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index 0b33854c5..3f8a8ad6d 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -40,12 +40,16 @@ protected: Imagefloat* origCrop; // "one chunk" allocation LabImage* laboCrop; // "one chunk" allocation LabImage* labnCrop; // "one chunk" allocation + LabImage* reservCrop; // "one chunk" allocation + LabImage* lastorigCrop; // "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 * shbuf_real; // "one chunk" allocation // --- automatically allocated and deleted when necessary, and only renewed on size changes Imagefloat* transCrop; // "one chunk" allocation, allocated if necessary CieImage* cieCrop; // allocating 6 images, each in "one chunk" allocation // ----------------------------------------------------------------- + float** shbuffer; bool updating; /// Flag telling if an updater thread is currently processing bool newUpdatePending; /// Flag telling the updater thread that a new update is pending @@ -63,19 +67,19 @@ protected: ImProcCoordinator* const parent; const bool isDetailWindow; EditUniqueID getCurrEditID(); - bool setCropSizes (int cropX, int cropY, int cropW, int cropH, int skip, bool internal); - void freeAll (); + bool setCropSizes(int cropX, int cropY, int cropW, int cropH, int skip, bool internal); + void freeAll(); public: - Crop (ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow); + Crop(ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow); ~Crop () override; - +// MyMutex* locMutex; void setEditSubscriber(EditSubscriber* newSubscriber); bool hasListener(); - void update (int todo); + void update(int todo); void setWindow (int cropX, int cropY, int cropW, int cropH, int skip) override { - setCropSizes (cropX, cropY, cropW, cropH, skip, false); + setCropSizes(cropX, cropY, cropW, cropH, skip, false); } /** @brief Synchronously look out if a full update is necessary diff --git a/rtengine/dirpyr_equalizer.cc b/rtengine/dirpyr_equalizer.cc index 0624f4443..871c21ac4 100644 --- a/rtengine/dirpyr_equalizer.cc +++ b/rtengine/dirpyr_equalizer.cc @@ -25,9 +25,11 @@ #include "array2D.h" #include "cieimage.h" #include "color.h" +#include "curves.h" #include "improcfun.h" #include "LUT.h" #include "opthelper.h" +#include "boxblur.h" #include "rt_math.h" #include "settings.h" @@ -37,6 +39,7 @@ float rangeFn(float i) { return 1.f / (i + 1000.f); } + void dirpyr_channel(const float * const * data_fine, float ** data_coarse, int width, int height, int level, int scale) { // scale is spacing of directional averaging weights @@ -244,6 +247,48 @@ void fillLut(LUTf &irangefn, int level, double dirpyrThreshold, float mult, floa } } +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +void idirpyr_eq_channel_loc(float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float mult, const float blurcb, const double dirpyrThreshold, float ** hue, float ** chrom, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scaleprev, bool multiThread) +{ + LUTf irangefn(0x20000); + fillLut(irangefn, level, dirpyrThreshold, mult, skinprot); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + + float hipass = (data_fine[i][j] - data_coarse[i][j]); + buffer[i][j] += irangefn[hipass + 0x10000] * hipass; + + } + } + + if(blurcb > 0.f && choice == 0 && level != 5) { + float multbis; + if (level == 4 && mult > 1.f) { + multbis = 1.f + 0.65f * (mult - 1.f); + } else if (level == 5 && mult > 1.f) { + multbis = 1.f + 0.45f * (mult - 1.f); + } else { + multbis = mult; //multbis to reduce artifacts for high values mult + } + AlignedBuffer blurbufcbdl(width * height); + float rad = 0.05f * blurcb * fabs((level + 1) * (multbis - 1.f)) / scaleprev; + // printf("rad=%f level=%i\n", rad, level); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif +// rtengine::boxblur(buffer, buffer, blurbufcbdl.data, rad, rad, width, height); + rtengine::boxblur(buffer, buffer, rad, width, height, false); + blurbufcbdl.resize(0); + } + + irangefn.clear(); +} + void idirpyr_eq_channel(const float * const * data_coarse, const float * const * data_fine, float ** buffer, int width, int height, int level, float mult, const double dirpyrThreshold, const float * const * hue, const float * const * chrom, const double skinprot, float b_l, float t_l, float t_r) { const float skinprotneg = -skinprot; @@ -507,4 +552,162 @@ void ImProcFunctions::dirpyr_equalizercam(const CieImage *ncie, float ** src, fl } } +void ImProcFunctions::cbdl_local_temp(float ** src, float ** loctemp, int srcwidth, int srcheight, const float * mult, float kchro, const double dirpyrThreshold, const float mergeL, const float contres, const float blurcb, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scaleprev, bool multiThread) +{ + constexpr int maxlevelloc = 6; + constexpr int scalesloc[maxlevelloc] = {1, 2, 4, 8, 16, 32}; + const float atten123 = rtengine::LIM(settings->level123_cbdl, 0.f, 50.f); + const float atten0 = rtengine::LIM(settings->level0_cbdl, 0.f, 40.f); + int lastlevel = maxlevelloc; + + if (settings->verbose) { + printf("Dirpyr scaleprev=%i\n", scaleprev); + } + + while (lastlevel > 0 && fabs(mult[lastlevel - 1] - 1) < 0.001) { + + lastlevel--; + //printf("last level to process %d \n",lastlevel); + } + + if (lastlevel == 0) { + return; + } + + float multi[6]; + + for (int lv = 0; lv < 6; ++lv) { + if (scalesloc[lv] < scaleprev) { + const float factor = lv >= 1 ? atten123 : atten0; + multi[lv] = (factor * ((float) mult[lv] - 1.f) / 100.f) + 1.f; //modulate action if zoom < 100% + } else { + multi[lv] = mult[lv]; + } + } + + if (settings->verbose) { + printf("CbDL local mult0=%f 1=%f 2=%f 3=%f 4=%f 5%f\n", multi[0], multi[1], multi[2], multi[3], multi[4], multi[5]); + } + + multi_array2D dirpyrlo(srcwidth, srcheight); + + + dirpyr_channel(src, dirpyrlo[0], srcwidth, srcheight, 0, std::max(scalesloc[0] / scaleprev, 1)); + + + for (int level = 1; level < lastlevel; ++level) { + dirpyr_channel(dirpyrlo[level - 1], dirpyrlo[level], srcwidth, srcheight, level, std::max(scalesloc[level] / scaleprev, 1)); + } + + // with the current implementation of idirpyr_eq_channel we can safely use the buffer from last level as buffer, saves some memory +// float ** buffer = dirpyrlo[lastlevel - 1]; + array2D residbuff(srcwidth, srcheight); + array2D resid5(srcwidth, srcheight); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < srcheight; i++) + for (int j = 0; j < srcwidth; j++) { + residbuff[i][j] = 0.f; + } + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < srcheight; i++) + for (int j = 0; j < srcwidth; j++) { + residbuff[i][j] = dirpyrlo[lastlevel - 1][i][j]; + resid5[i][j] = dirpyrlo[lastlevel - 1][i][j]; + } + + + double avg = 0.f; + if(contres != 0.f) { + int ng = 0; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:avg, ng) +#endif + for (int i = 0; i < srcheight; i++) { + for (int j = 0; j < srcwidth; j++) { + avg += residbuff[i][j]; + ng++; + } + } + avg /= ng; + avg /= 32768.f; + avg = LIM01(avg); + } + float contreal = 0.3f * contres; + DiagonalCurve resid_contrast({ + DCT_NURBS, + 0, 0, + avg - avg * (0.6 - contreal / 250.0), avg - avg * (0.6 + contreal / 250.0), + avg + (1 - avg) * (0.6 - contreal / 250.0), avg + (1 - avg) * (0.6 + contreal / 250.0), + 1, 1 + }); + + if(contres != 0.f) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < srcheight; i++) + for (int j = 0; j < srcwidth; j++) { + float buf = LIM01(residbuff[i][j] / 32768.f); + buf = resid_contrast.getVal(buf); + buf *= 32768.f; + residbuff[i][j] = buf; + } + } + + + for (int level = lastlevel - 1; level > 0; level--) { + idirpyr_eq_channel_loc(dirpyrlo[level], dirpyrlo[level - 1], residbuff, srcwidth, srcheight, level, multi[level], blurcb, dirpyrThreshold, nullptr, nullptr, skinprot, gamutlab, b_l, t_l, t_r, b_r, choice, scaleprev, multiThread); + } + + scale = scalesloc[0]; + + idirpyr_eq_channel_loc(dirpyrlo[0], src, residbuff, srcwidth, srcheight, 0, multi[0], blurcb, dirpyrThreshold, nullptr, nullptr, skinprot, gamutlab, b_l, t_l, t_r, b_r, choice, scaleprev, multiThread); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + array2D loct(srcwidth, srcheight); +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < srcheight; i++) { + for (int j = 0; j < srcwidth; j++) { + loct[i][j] = LIM(residbuff[i][j],0.f,32768.f); // TODO: Really a clip necessary? + } + } + + float clar = 0.01f * mergeL; + +/* + if(clar == 0.f) { + clar = 0.0f; + } +// printf("clar=%f \n", clar); +*/ + if(clar > 0.f) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < srcheight; i++) { + for (int j = 0; j < srcwidth; j++) { + loctemp[i][j] = LIM((1.f + clar) * loct[i][j] - clar * resid5[i][j],0.f,32768.f); + } + } + } else { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < srcheight; i++) { + for (int j = 0; j < srcwidth; j++) { + loctemp[i][j] = LIM(loct[i][j],0.f,32768.f); + } + } + } +} + } diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index 6d4fe1ad6..30d0a052d 100644 --- a/rtengine/filmnegativeproc.cc +++ b/rtengine/filmnegativeproc.cc @@ -214,7 +214,7 @@ bool rtengine::RawImageSource::getFilmNegativeExponents(Coord2D spotA, Coord2D s std::array denseVals; // Get channel averages in the two spots, sampling from the original ri->data buffer. - // NOTE: rawData values might be affected by CA corection, FlatField, etc, so: + // NOTE: rawData values might be affected by CA correction, FlatField, etc, so: // rawData[y][x] == (ri->data[y][x] - cblacksom[c]) * scale_mul[c] // is not always true. To calculate exponents on the exact values, we should keep // a copy of the rawData buffer after preprocessing. Worth the memory waste? @@ -330,7 +330,7 @@ void rtengine::RawImageSource::filmNegativeProcess(const procparams::FilmNegativ // If film base values are set in params, use those if (filmBaseValues[0] <= 0.f) { // ...otherwise, the film negative tool might have just been enabled on this image, - // whithout any previous setting. So, estimate film base values from channel medians + // without any previous setting. So, estimate film base values from channel medians std::array medians; diff --git a/rtengine/gauss.cc b/rtengine/gauss.cc index 8d9e5de38..99201a860 100644 --- a/rtengine/gauss.cc +++ b/rtengine/gauss.cc @@ -1355,7 +1355,6 @@ template void gaussVerticalmult (T** src, T** dst, const int W, const i template void gaussianBlurImpl(T** src, T** dst, const int W, const int H, const double sigma, bool useBoxBlur, eGaussType gausstype = GAUSS_STANDARD, T** buffer2 = nullptr) { - static constexpr auto GAUSS_SKIP = 0.25; static constexpr auto GAUSS_3X3_LIMIT = 0.6; static constexpr auto GAUSS_5X5_LIMIT = 0.84; static constexpr auto GAUSS_7X7_LIMIT = 1.15; @@ -1405,6 +1404,9 @@ template void gaussianBlurImpl(T** src, T** dst, const int W, const int } else { if (sigma < GAUSS_SKIP) { // don't perform filtering +#ifdef _OPENMP +#pragma omp single +#endif if (src != dst) { for(int i = 0; i < H; ++i) { memcpy(dst[i], src[i], W * sizeof(T)); diff --git a/rtengine/gauss.h b/rtengine/gauss.h index e226bbc13..71e3506da 100644 --- a/rtengine/gauss.h +++ b/rtengine/gauss.h @@ -19,5 +19,7 @@ #pragma once enum eGaussType {GAUSS_STANDARD, GAUSS_MULT, GAUSS_DIV}; +static constexpr auto GAUSS_SKIP = 0.25; + void gaussianBlur(float** src, float** dst, const int W, const int H, const double sigma, bool useBoxBlur = false, eGaussType gausstype = GAUSS_STANDARD, float** buffer2 = nullptr); diff --git a/rtengine/guidedfilter.cc b/rtengine/guidedfilter.cc index f83560cfc..b3f843bc1 100644 --- a/rtengine/guidedfilter.cc +++ b/rtengine/guidedfilter.cc @@ -3,7 +3,6 @@ * This file is part of RawTherapee. * * Copyright (c) 2018 Alberto Griggio - * Optimized 2019 Ingo Weyrich * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,10 +15,10 @@ * 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 . -*/ + * along with RawTherapee. If not, see . + */ -/* +/** * This is a Fast Guided Filter implementation, derived directly from the * pseudo-code of the paper: * @@ -27,22 +26,36 @@ * by Kaiming He, Jian Sun * * available at https://arxiv.org/abs/1505.00996 -*/ + */ #include "array2D.h" #include "boxblur.h" #include "guidedfilter.h" -#include "imagefloat.h" +#include "boxblur.h" +#include "sleef.h" #include "rescale.h" +#include "imagefloat.h" -#define BENCHMARK -#include "StopWatch.h" +namespace rtengine { -namespace rtengine -{ +#if 0 +# define DEBUG_DUMP(arr) \ + do { \ + Imagefloat im(arr.width(), arr.height()); \ + const char *out = "/tmp/" #arr ".tif"; \ + for (int y = 0; y < im.getHeight(); ++y) { \ + for (int x = 0; x < im.getWidth(); ++x) { \ + im.r(y, x) = im.g(y, x) = im.b(y, x) = arr[y][x] * 65535.f; \ + } \ + } \ + im.saveTIFF(out, 16); \ + } while (false) +#else +# define DEBUG_DUMP(arr) +#endif -namespace -{ + +namespace { int calculate_subsampling(int w, int h, int r) { @@ -65,17 +78,21 @@ int calculate_subsampling(int w, int h, int r) } // namespace + void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling) { - enum Op {MUL, DIVEPSILON, SUBMUL}; + + const int W = src.width(); + const int H = src.height(); + + if (subsampling <= 0) { + subsampling = calculate_subsampling(W, H, r); + } + + enum Op { MUL, DIVEPSILON, ADD, SUB, ADDMUL, SUBMUL }; const auto apply = -#ifdef _OPENMP - [multithread, epsilon](Op op, array2D &res, const array2D &a, const array2D &b, const array2D &c=array2D()) -> void -#else - // removed multithread to fix clang warning on msys2 clang builds, which don't support OpenMp - [epsilon](Op op, array2D &res, const array2D &a, const array2D &b, const array2D &c=array2D()) -> void -#endif + [=](Op op, array2D &res, const array2D &a, const array2D &b, const array2D &c=array2D()) -> void { const int w = res.width(); const int h = res.height(); @@ -85,31 +102,49 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 #endif for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { + float r; + float aa = a[y][x]; + float bb = b[y][x]; switch (op) { - case MUL: - res[y][x] = a[y][x] * b[y][x]; - break; - case DIVEPSILON: - res[y][x] = a[y][x] / (b[y][x] + epsilon); // note: the value of epsilon intentionally has an impact on the result. It is not only to avoid divisions by zero - break; - case SUBMUL: - res[y][x] = c[y][x] - (a[y][x] * b[y][x]); - break; - default: - assert(false); - res[y][x] = 0; - break; + case MUL: + r = aa * bb; + break; + case DIVEPSILON: + r = aa / (bb + epsilon); + break; + case ADD: + r = aa + bb; + break; + case SUB: + r = aa - bb; + break; + case ADDMUL: + r = aa * bb + c[y][x]; + break; + case SUBMUL: + r = c[y][x] - (aa * bb); + break; + default: + assert(false); + r = 0; + break; } + res[y][x] = r; } } }; + // use the terminology of the paper (Algorithm 2) + const array2D &I = guide; + const array2D &p = src; + array2D &q = dst; + const auto f_subsample = - [multithread](array2D &d, const array2D &s) -> void + [=](array2D &d, const array2D &s) -> void { if (d.width() == s.width() && d.height() == s.height()) { #ifdef _OPENMP - #pragma omp parallel for if (multithread) +# pragma omp parallel for if (multithread) #endif for (int y = 0; y < s.height(); ++y) { for (int x = 0; x < s.width(); ++x) { @@ -121,84 +156,125 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 } }; + // const auto f_upsample = f_subsample; + + const size_t w = W / subsampling; + const size_t h = H / subsampling; + const auto f_mean = [multithread](array2D &d, array2D &s, int rad) -> void { rad = LIM(rad, 0, (min(s.width(), s.height()) - 1) / 2 - 1); + // boxblur(s, d, rad, s.width(), s.height(), multithread); boxblur(static_cast(s), static_cast(d), rad, s.width(), s.height(), multithread); }; - const int W = src.width(); - const int H = src.height(); - - if (subsampling <= 0) { - subsampling = calculate_subsampling(W, H, r); - } - - const size_t w = W / subsampling; - const size_t h = H / subsampling; - const float r1 = float(r) / subsampling; - array2D I1(w, h); array2D p1(w, h); - f_subsample(I1, guide); + f_subsample(I1, I); + f_subsample(p1, p); - if (&guide == &src) { - f_mean(p1, I1, r1); + DEBUG_DUMP(I); + DEBUG_DUMP(p); + DEBUG_DUMP(I1); + DEBUG_DUMP(p1); - apply(MUL, I1, I1, I1); // I1 = I1 * I1 + float r1 = float(r) / subsampling; - f_mean(I1, I1, r1); + array2D meanI(w, h); + f_mean(meanI, I1, r1); + DEBUG_DUMP(meanI); - apply(SUBMUL, I1, p1, p1, I1); // I1 = I1 - p1 * p1 - apply(DIVEPSILON, I1, I1, I1); // I1 = I1 / (I1 + epsilon) - apply(SUBMUL, p1, I1, p1, p1); // p1 = p1 - I1 * p1 + array2D meanp(w, h); + f_mean(meanp, p1, r1); + DEBUG_DUMP(meanp); - } else { - f_subsample(p1, src); + array2D &corrIp = p1; + apply(MUL, corrIp, I1, p1); + f_mean(corrIp, corrIp, r1); + DEBUG_DUMP(corrIp); - array2D meanI(w, h); - f_mean(meanI, I1, r1); + array2D &corrI = I1; + apply(MUL, corrI, I1, I1); + f_mean(corrI, corrI, r1); + DEBUG_DUMP(corrI); - array2D meanp(w, h); - f_mean(meanp, p1, r1); + array2D &varI = corrI; + apply(SUBMUL, varI, meanI, meanI, corrI); + DEBUG_DUMP(varI); - apply(MUL, p1, I1, p1); + array2D &covIp = corrIp; + apply(SUBMUL, covIp, meanI, meanp, corrIp); + DEBUG_DUMP(covIp); - f_mean(p1, p1, r1); + array2D &a = varI; + apply(DIVEPSILON, a, covIp, varI); + DEBUG_DUMP(a); - apply(MUL, I1, I1, I1); + array2D &b = covIp; + apply(SUBMUL, b, a, meanI, meanp); + DEBUG_DUMP(b); - f_mean(I1, I1, r1); + array2D &meana = a; + f_mean(meana, a, r1); + DEBUG_DUMP(meana); - apply(SUBMUL, I1, meanI, meanI, I1); - apply(SUBMUL, p1, meanI, meanp, p1); - apply(DIVEPSILON, I1, p1, I1); - apply(SUBMUL, p1, I1, meanI, meanp); - } + array2D &meanb = b; + f_mean(meanb, b, r1); + DEBUG_DUMP(meanb); - f_mean(I1, I1, r1); - f_mean(p1, p1, r1); - - const int Ws = I1.width(); - const int Hs = I1.height(); - const int Wd = dst.width(); - const int Hd = dst.height(); - - const float col_scale = static_cast(Ws) / static_cast(Wd); - const float row_scale = static_cast(Hs) / static_cast(Hd); + // speedup by heckflosse67 + const int Ws = meana.width(); + const int Hs = meana.height(); + const int Wd = q.width(); + const int Hd = q.height(); + const float col_scale = float(Ws) / float(Wd); + const float row_scale = float(Hs) / float(Hd); #ifdef _OPENMP - #pragma omp parallel for if (multithread) +# pragma omp parallel for if (multithread) #endif - for (int y = 0; y < Hd; ++y) { - const float ymrs = y * row_scale; + float ymrs = y * row_scale; for (int x = 0; x < Wd; ++x) { - dst[y][x] = getBilinearValue(I1, x * col_scale, ymrs) * guide[y][x] + getBilinearValue(p1, x * col_scale, ymrs); + q[y][x] = getBilinearValue(meana, x * col_scale, ymrs) * I[y][x] + getBilinearValue(meanb, x * col_scale, ymrs); } } } + +void guidedFilterLog(const array2D &guide, float base, array2D &chan, int r, float eps, bool multithread, int subsampling) +{ +#ifdef _OPENMP +# pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < chan.height(); ++y) { + for (int x = 0; x < chan.width(); ++x) { + chan[y][x] = xlin2log(max(chan[y][x], 0.f), base); + } + } + + guidedFilter(guide, chan, chan, r, eps, multithread, subsampling); + +#ifdef _OPENMP +# pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < chan.height(); ++y) { + for (int x = 0; x < chan.width(); ++x) { + chan[y][x] = xlog2lin(max(chan[y][x], 0.f), base); + } + } +} + + +void guidedFilterLog(float base, array2D &chan, int r, float eps, bool multithread, int subsampling) +{ + guidedFilterLog(chan, base, chan, r, eps, multithread, subsampling); +} + } // namespace rtengine + + + + diff --git a/rtengine/guidedfilter.h b/rtengine/guidedfilter.h index 2d8b70369..94147b411 100644 --- a/rtengine/guidedfilter.h +++ b/rtengine/guidedfilter.h @@ -15,7 +15,7 @@ * 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 . + * along with RawTherapee. If not, see . */ #pragma once @@ -28,4 +28,8 @@ namespace rtengine void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling=0); +void guidedFilterLog(float base, array2D &chan, int r, float eps, bool multithread, int subsampling=0); + +void guidedFilterLog(const array2D &guide, float base, array2D &chan, int r, float eps, bool multithread, int subsampling=0); + } // namespace rtengine diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc index 1ba42a68b..1a4c4c7f4 100644 --- a/rtengine/hilite_recon.cc +++ b/rtengine/hilite_recon.cc @@ -394,7 +394,9 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue int miny = height - 1; int maxy = 0; +#ifdef _OPENMP #pragma omp parallel for reduction(min:minx,miny) reduction(max:maxx,maxy) schedule(dynamic, 16) +#endif for (int i = 0; i < height; ++i) { for (int j = 0; j< width; ++j) { if (red[i][j] >= max_f[0] || green[i][j] >= max_f[1] || blue[i][j] >= max_f[2]) { diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index a631a6c8d..5025b31e5 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -39,17 +39,17 @@ using namespace rtengine; -extern "C" IptcData *iptc_data_new_from_jpeg_file (FILE* infile); +extern "C" IptcData *iptc_data_new_from_jpeg_file(FILE* infile); namespace { -Glib::ustring to_utf8 (const std::string& str) +Glib::ustring to_utf8(const std::string& str) { try { - return Glib::locale_to_utf8 (str); + return Glib::locale_to_utf8(str); } catch (Glib::Error&) { - return Glib::convert_with_fallback (str, "UTF-8", "ISO-8859-1", "?"); + return Glib::convert_with_fallback(str, "UTF-8", "ISO-8859-1", "?"); } } @@ -71,9 +71,9 @@ T getFromFrame( } -FramesMetaData* FramesMetaData::fromFile (const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) +FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) { - return new FramesData (fname, std::move(rml), firstFrameOnly); + return new FramesData(fname, std::move(rml), firstFrameOnly); } FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir) : @@ -113,36 +113,39 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* if (!tag) { newFrameRootDir = rootDir; tag = newFrameRootDir->findTag("Make"); + if (!tag) { // For some raw files (like Canon's CR2 files), the metadata are contained in the first root directory newFrameRootDir = firstRootDir; tag = newFrameRootDir->findTag("Make"); } } + if (tag) { make = tag->valueToString(); + // Same dcraw treatment for (const auto& corp : { - "Canon", - "NIKON", - "EPSON", - "KODAK", - "Kodak", - "OLYMPUS", - "PENTAX", - "RICOH", - "MINOLTA", - "Minolta", - "Konica", - "CASIO", - "Sinar", - "Phase One", - "SAMSUNG", - "Mamiya", - "MOTOROLA", - "Leaf", - "Panasonic" - }) { + "Canon", + "NIKON", + "EPSON", + "KODAK", + "Kodak", + "OLYMPUS", + "PENTAX", + "RICOH", + "MINOLTA", + "Minolta", + "Konica", + "CASIO", + "Sinar", + "Phase One", + "SAMSUNG", + "Mamiya", + "MOTOROLA", + "Leaf", + "Panasonic" + }) { if (make.find(corp) != std::string::npos) { // Simplify company names make = corp; break; @@ -153,6 +156,7 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } tag = newFrameRootDir->findTagUpward("Model"); + if (tag) { model = tag->valueToString(); } @@ -179,7 +183,7 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } - if (model.find( "Digital Camera ") != std::string::npos) { + if (model.find("Digital Camera ") != std::string::npos) { model.erase(0, 15); } } else { @@ -194,8 +198,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } tag = newFrameRootDir->findTagUpward("Orientation"); + if (tag) { - orientation = tag->valueToString (); + orientation = tag->valueToString(); } // Look for Rating metadata in the following order: @@ -217,45 +222,47 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* tag = newFrameRootDir->findTagUpward("MakerNote"); rtexif::TagDirectory* mnote = nullptr; + if (tag) { mnote = tag->getDirectory(); } rtexif::TagDirectory* exif = nullptr; tag = newFrameRootDir->findTagUpward("Exif"); + if (tag) { - exif = tag->getDirectory (); + exif = tag->getDirectory(); } if (exif) { // standard exif tags - if ((tag = exif->getTag ("ShutterSpeedValue"))) { - shutter = tag->toDouble (); + if ((tag = exif->getTag("ShutterSpeedValue"))) { + shutter = tag->toDouble(); } - if ((tag = exif->getTag ("ExposureTime"))) { - shutter = tag->toDouble (); + if ((tag = exif->getTag("ExposureTime"))) { + shutter = tag->toDouble(); } - if ((tag = exif->getTag ("ApertureValue"))) { - aperture = tag->toDouble (); + if ((tag = exif->getTag("ApertureValue"))) { + aperture = tag->toDouble(); } - if ((tag = exif->getTag ("FNumber"))) { - aperture = tag->toDouble (); + if ((tag = exif->getTag("FNumber"))) { + aperture = tag->toDouble(); } - if ((tag = exif->getTag ("ExposureBiasValue"))) { - expcomp = tag->toDouble (); + if ((tag = exif->getTag("ExposureBiasValue"))) { + expcomp = tag->toDouble(); } - if ((tag = exif->getTag ("FocalLength"))) { - focal_len = tag->toDouble (); + if ((tag = exif->getTag("FocalLength"))) { + focal_len = tag->toDouble(); } - if ((tag = exif->getTag ("FocalLengthIn35mmFilm"))) { - focal_len35mm = tag->toDouble (); + if ((tag = exif->getTag("FocalLengthIn35mmFilm"))) { + focal_len35mm = tag->toDouble(); } // Focus distance from EXIF or XMP. MakerNote ones are scattered and partly encrypted @@ -283,12 +290,12 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } - if ((tag = exif->getTag ("ISOSpeedRatings"))) { - iso_speed = tag->toDouble (); + if ((tag = exif->getTag("ISOSpeedRatings"))) { + iso_speed = tag->toDouble(); } if ((tag = exif->findTag("DateTimeOriginal", true))) { - if (sscanf ((const char*)tag->getValue(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { + if (sscanf((const char*)tag->getValue(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { time.tm_year -= 1900; time.tm_mon -= 1; time.tm_isdst = -1; @@ -296,10 +303,10 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } - tag = exif->findTag ("SerialNumber"); + tag = exif->findTag("SerialNumber"); - if(!tag) { - tag = exif->findTag ("InternalSerialNumber"); + if (!tag) { + tag = exif->findTag("InternalSerialNumber"); } if (tag) { @@ -311,15 +318,15 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* // Sometimes (e.g. DNG) EXIF already contains lens data - if(!make.compare (0, 8, "FUJIFILM")) { - if(exif->getTag ("LensModel")) { - lens = exif->getTag ("LensModel")->valueToString (); + if (!make.compare(0, 8, "FUJIFILM")) { + if (exif->getTag("LensModel")) { + lens = exif->getTag("LensModel")->valueToString(); } - } else if(!make.compare (0, 4, "SONY")) { + } else if (!make.compare(0, 4, "SONY")) { if (iso_speed == 65535 || iso_speed == 0) { - rtexif::Tag* isoTag = exif->getTag ("RecommendedExposureIndex"); + rtexif::Tag* isoTag = exif->getTag("RecommendedExposureIndex"); - if(isoTag) { + if (isoTag) { iso_speed = isoTag->toDouble(); } } @@ -362,7 +369,7 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* if (mnote) { - if (!make.compare (0, 5, "NIKON")) { + if (!make.compare(0, 5, "NIKON")) { // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { rtexif::Tag* isoTag = mnote->getTagP("ISOInfo/ISO"); @@ -374,25 +381,25 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* bool lensOk = false; - if (mnote->getTag ("LensData")) { - std::string ldata = mnote->getTag ("LensData")->valueToString (); + if (mnote->getTag("LensData")) { + std::string ldata = mnote->getTag("LensData")->valueToString(); size_t pos; - if (ldata.size() > 10 && (pos = ldata.find ("Lens = ")) != Glib::ustring::npos) { - lens = ldata.substr (pos + 7); + if (ldata.size() > 10 && (pos = ldata.find("Lens = ")) != Glib::ustring::npos) { + lens = ldata.substr(pos + 7); - if (lens.compare (0, 7, "Unknown")) { + if (lens.compare(0, 7, "Unknown")) { lensOk = true; } else { size_t pos = lens.find("$FL$"); // is there a placeholder for focallength? - if(pos != Glib::ustring::npos) { // then fill in focallength - lens = lens.replace(pos, 4, exif->getTag ("FocalLength")->valueToString ()); + if (pos != Glib::ustring::npos) { // then fill in focallength + lens = lens.replace(pos, 4, exif->getTag("FocalLength")->valueToString()); - if(mnote->getTag ("LensType")) { - std::string ltype = mnote->getTag ("LensType")->valueToString (); + if (mnote->getTag("LensType")) { + std::string ltype = mnote->getTag("LensType")->valueToString(); - if(ltype.find("MF = Yes") != Glib::ustring::npos) { // check, whether it's a MF lens, should be always + if (ltype.find("MF = Yes") != Glib::ustring::npos) { // check, whether it's a MF lens, should be always lens = lens.replace(0, 7, "MF"); } @@ -408,8 +415,8 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } - if (!lensOk && mnote->getTag ("Lens")) { - std::string ldata = mnote->getTag ("Lens")->valueToString (); + if (!lensOk && mnote->getTag("Lens")) { + std::string ldata = mnote->getTag("Lens")->valueToString(); size_t i = 0, j = 0; double n[4] = {0.0}; @@ -429,7 +436,7 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* int den = atoi(ldata.substr(j, i).c_str()); j = i + 2; i += 2; - n[m] = (double) nom / std::max(den,1); + n[m] = (double) nom / std::max(den, 1); } std::ostringstream str; @@ -445,17 +452,17 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* lens = str.str(); // Look whether it's MF or AF - if(mnote->getTag ("LensType")) { - std::string ltype = mnote->getTag ("LensType")->valueToString (); + if (mnote->getTag("LensType")) { + std::string ltype = mnote->getTag("LensType")->valueToString(); - if(ltype.find("MF = Yes") != Glib::ustring::npos) { // check, whether it's a MF lens + if (ltype.find("MF = Yes") != Glib::ustring::npos) { // check, whether it's a MF lens lens = lens.replace(0, 7, "MF"); // replace 'Unknwon' with 'MF' } else { lens = lens.replace(0, 7, "AF"); // replace 'Unknwon' with 'AF' } } } - } else if (!make.compare (0, 5, "Canon")) { + } else if (!make.compare(0, 5, "Canon")) { // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { rtexif::Tag* baseIsoTag = mnote->getTagP("CanonShotInfo/BaseISO"); @@ -469,7 +476,7 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* // canon EXIF have a string for lens model rtexif::Tag *lt = mnote->getTag("LensType"); - if ( lt ) { + if (lt) { if (lt->toInt()) { std::string ldata = lt->valueToString (); @@ -491,8 +498,8 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* if( !found || remaining_size < 7U ) { lt = mnote->findTag("LensID"); - if ( lt ) { - std::string ldata = lt->valueToString (); + if (lt) { + std::string ldata = lt->valueToString(); if (ldata.size() > 1) { lens = ldata; @@ -503,14 +510,17 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { const rtexif::Tag* const baseIsoTag = mnote->getTag("ISO"); + if (baseIsoTag) { const std::string isoData = baseIsoTag->valueToString(); + if (isoData.size() > 1) { iso_speed = std::stoi(isoData); } } } - if (mnote->getTag ("LensType")) { + + if (mnote->getTag("LensType")) { lens = mnote->getTag ("LensType")->valueToString(); // If MakeNotes are vague, fall back to Exif LensMake and LensModel if set // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html#LensType @@ -522,61 +532,61 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } // Try to get the FocalLength from the LensInfo structure, where length below 10mm will be correctly set - rtexif::Tag* flt = mnote->getTagP ("LensInfo/FocalLength"); + rtexif::Tag* flt = mnote->getTagP("LensInfo/FocalLength"); if (flt) { // Don't replace Exif focal_len if Makernotes focal_len is 0 if (flt->toDouble() > 0) { - focal_len = flt->toDouble (); + focal_len = flt->toDouble(); } } else if ((flt = mnote->getTagP ("FocalLength"))) { focal_len = mnote->getTag("FocalLength")->toDouble (); } - if (mnote->getTag ("FocalLengthIn35mmFilm")) { - focal_len35mm = mnote->getTag ("FocalLengthIn35mmFilm")->toDouble (); + if (mnote->getTag("FocalLengthIn35mmFilm")) { + focal_len35mm = mnote->getTag("FocalLengthIn35mmFilm")->toDouble(); } - } else if (mnote && (!make.compare (0, 4, "SONY") || !make.compare (0, 6, "KONICA"))) { + } else if (!make.compare (0, 4, "SONY") || !make.compare (0, 6, "KONICA")) { if (mnote->getTag ("LensID")) { lens = mnote->getTag ("LensID")->valueToString (); if (lens == "Unknown") { lens_from_make_and_model(); } } - } else if (!make.compare (0, 7, "OLYMPUS")) { - if (mnote->getTag ("Equipment")) { - rtexif::TagDirectory* eq = mnote->getTag ("Equipment")->getDirectory (); + } else if (!make.compare(0, 7, "OLYMPUS")) { + if (mnote->getTag("Equipment")) { + rtexif::TagDirectory* eq = mnote->getTag("Equipment")->getDirectory(); - if (eq->getTag ("LensType")) { - lens = eq->getTag ("LensType")->valueToString (); + if (eq->getTag("LensType")) { + lens = eq->getTag("LensType")->valueToString(); } } if (lens == "Unknown") { lens_from_make_and_model(); } - } else if (mnote && !make.compare (0, 9, "Panasonic")) { + } else if (!make.compare (0, 9, "Panasonic")) { if (mnote->getTag ("LensType")) { std::string panalens = mnote->getTag("LensType")->valueToString(); if (panalens.find("LUMIX") != Glib::ustring::npos) { lens = "Panasonic " + panalens; - } - else { + } else { lens = panalens; } } } - } else if (exif->getTag ("DNGLensInfo")) { - lens = exif->getTag ("DNGLensInfo")->valueToString (); + } else if (exif->getTag("DNGLensInfo")) { + lens = exif->getTag("DNGLensInfo")->valueToString(); } else if (!lens_from_make_and_model() && exif->getTag ("LensInfo")) { - lens = exif->getTag ("LensInfo")->valueToString (); + lens = exif->getTag("LensInfo")->valueToString(); } } } rtexif::Tag* t = newFrameRootDir->getTag(0x83BB); + if (t) { - iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); + iptc = iptc_data_new_from_data((unsigned char*)t->getValue(), (unsigned)t->getValueSize()); } @@ -590,8 +600,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* const rtexif::Tag* const pi = frameRootDir->findTag("PhotometricInterpretation"); const rtexif::Tag* const c = frameRootDir->findTag("Compression"); - if (mnote && (!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX")))) { + if (mnote && (!make.compare(0, 6, "PENTAX") || (!make.compare(0, 5, "RICOH") && !model.compare(0, 6, "PENTAX")))) { const rtexif::Tag* const hdr = mnote->findTag("HDR"); + if (hdr) { if (hdr->toInt() > 0) { isHDR = true; @@ -601,10 +612,12 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } else { const rtexif::Tag* const dm = mnote->findTag("DriveMode"); + if (dm) { char buffer[60]; dm->toString(buffer, 3); buffer[3] = 0; + if (!strcmp(buffer, "HDR")) { isHDR = true; #if PRINT_HDR_PS_DETECTION @@ -652,6 +665,7 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* samplesperpixel = spp->toInt(); photometric = pi->toInt(); + if (photometric == PHOTOMETRIC_LOGLUV) { if (!c) { compression = COMPRESSION_NONE; @@ -732,7 +746,8 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* sampleFormat = IIOSF_UNSIGNED_CHAR; } else if (bitspersample <= 16) { sampleFormat = IIOSF_UNSIGNED_SHORT; - if (mnote && (!make.compare (0, 4, "SONY")) && bitspersample >= 12 && samplesperpixel == 4) { + + if (mnote && (!make.compare(0, 4, "SONY")) && bitspersample >= 12 && samplesperpixel == 4) { isPixelShift = true; #if PRINT_HDR_PS_DETECTION printf("PixelShift detected ! -> \"Make\" = SONY, bitsPerPixel > 8, samplesPerPixel == 4\n"); @@ -757,20 +772,20 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } -FrameData::~FrameData () +FrameData::~FrameData() { if (iptc) { - iptc_data_free (iptc); + iptc_data_free(iptc); } } -procparams::IPTCPairs FrameData::getIPTCData () const +procparams::IPTCPairs FrameData::getIPTCData() const { return getIPTCData(iptc); } -procparams::IPTCPairs FrameData::getIPTCData (IptcData* iptc_) +procparams::IPTCPairs FrameData::getIPTCData(IptcData* iptc_) { procparams::IPTCPairs iptcc; @@ -782,34 +797,34 @@ procparams::IPTCPairs FrameData::getIPTCData (IptcData* iptc_) unsigned char buffer[2100]; for (int i = 0; i < 16; i++) { - IptcDataSet* ds = iptc_data_get_next_dataset (iptc_, nullptr, IPTC_RECORD_APP_2, strTags[i].tag); + IptcDataSet* ds = iptc_data_get_next_dataset(iptc_, nullptr, IPTC_RECORD_APP_2, strTags[i].tag); if (ds) { - iptc_dataset_get_data (ds, buffer, 2100); + iptc_dataset_get_data(ds, buffer, 2100); std::vector icValues; - icValues.push_back (to_utf8((char*)buffer)); + icValues.push_back(to_utf8((char*)buffer)); iptcc[strTags[i].field] = icValues; - iptc_dataset_unref (ds); + iptc_dataset_unref(ds); } } IptcDataSet* ds = nullptr; std::vector keywords; - while ((ds = iptc_data_get_next_dataset (iptc_, ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS))) { - iptc_dataset_get_data (ds, buffer, 2100); - keywords.push_back (to_utf8((char*)buffer)); + while ((ds = iptc_data_get_next_dataset(iptc_, ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS))) { + iptc_dataset_get_data(ds, buffer, 2100); + keywords.push_back(to_utf8((char*)buffer)); } iptcc["Keywords"] = keywords; ds = nullptr; std::vector suppCategories; - while ((ds = iptc_data_get_next_dataset (iptc_, ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY))) { - iptc_dataset_get_data (ds, buffer, 2100); - suppCategories.push_back (to_utf8((char*)buffer)); - iptc_dataset_unref (ds); + while ((ds = iptc_data_get_next_dataset(iptc_, ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY))) { + iptc_dataset_get_data(ds, buffer, 2100); + suppCategories.push_back(to_utf8((char*)buffer)); + iptc_dataset_unref(ds); } iptcc["SupplementalCategories"] = suppCategories; @@ -817,11 +832,11 @@ procparams::IPTCPairs FrameData::getIPTCData (IptcData* iptc_) } -bool FrameData::getPixelShift () const +bool FrameData::getPixelShift() const { return isPixelShift; } -bool FrameData::getHDR () const +bool FrameData::getHDR() const { return isHDR; } @@ -829,75 +844,75 @@ std::string FrameData::getImageType () const { return isPixelShift ? "PS" : isHDR ? "HDR" : "STD"; } -IIOSampleFormat FrameData::getSampleFormat () const +IIOSampleFormat FrameData::getSampleFormat() const { return sampleFormat; } -rtexif::TagDirectory* FrameData::getExifData () const +rtexif::TagDirectory* FrameData::getExifData() const { return frameRootDir; } -bool FrameData::hasExif () const +bool FrameData::hasExif() const { return frameRootDir && frameRootDir->getCount(); } -bool FrameData::hasIPTC () const +bool FrameData::hasIPTC() const { return iptc; } -tm FrameData::getDateTime () const +tm FrameData::getDateTime() const { return time; } -time_t FrameData::getDateTimeAsTS () const +time_t FrameData::getDateTimeAsTS() const { return timeStamp; } -int FrameData::getISOSpeed () const +int FrameData::getISOSpeed() const { return iso_speed; } -double FrameData::getFNumber () const +double FrameData::getFNumber() const { return aperture; } -double FrameData::getFocalLen () const +double FrameData::getFocalLen() const { return focal_len; } -double FrameData::getFocalLen35mm () const +double FrameData::getFocalLen35mm() const { return focal_len35mm; } -float FrameData::getFocusDist () const +float FrameData::getFocusDist() const { return focus_dist; } -double FrameData::getShutterSpeed () const +double FrameData::getShutterSpeed() const { return shutter; } -double FrameData::getExpComp () const +double FrameData::getExpComp() const { return expcomp; } -std::string FrameData::getMake () const +std::string FrameData::getMake() const { return make; } -std::string FrameData::getModel () const +std::string FrameData::getModel() const { return model; } -std::string FrameData::getLens () const +std::string FrameData::getLens() const { return lens; } -std::string FrameData::getSerialNumber () const +std::string FrameData::getSerialNumber() const { return serial; } -std::string FrameData::getOrientation () const +std::string FrameData::getOrientation() const { return orientation; } @@ -909,17 +924,17 @@ int FrameData::getRating () const -void FramesData::setDCRawFrameCount (unsigned int frameCount) +void FramesData::setDCRawFrameCount(unsigned int frameCount) { dcrawFrameCount = frameCount; } -unsigned int FramesData::getRootCount () const +unsigned int FramesData::getRootCount() const { return roots.size(); } -unsigned int FramesData::getFrameCount () const +unsigned int FramesData::getFrameCount() const { return dcrawFrameCount ? dcrawFrameCount : frames.size(); } @@ -933,14 +948,14 @@ bool FramesData::getPixelShift () const return frames.empty() ? false : frames.at(0)->getPixelShift (); } -bool FramesData::getHDR (unsigned int frame) const +bool FramesData::getHDR(unsigned int frame) const { // So far only Pentax provides multi-frame HDR file. // Only the first frame contains the HDR tag // If more brand have to be supported, this rule may need // to evolve - return frames.empty() || frame >= frames.size() ? false : frames.at(0)->getHDR (); + return frames.empty() || frame >= frames.size() ? false : frames.at(0)->getHDR(); } std::string FramesData::getImageType (unsigned int frame) const @@ -948,53 +963,58 @@ std::string FramesData::getImageType (unsigned int frame) const return frames.empty() || frame >= frames.size() ? "STD" : frames.at(0)->getImageType(); } -IIOSampleFormat FramesData::getSampleFormat (unsigned int frame) const +IIOSampleFormat FramesData::getSampleFormat(unsigned int frame) const { - return frames.empty() || frame >= frames.size() ? IIOSF_UNKNOWN : frames.at(frame)->getSampleFormat (); + return frames.empty() || frame >= frames.size() ? IIOSF_UNKNOWN : frames.at(frame)->getSampleFormat(); } -rtexif::TagDirectory* FramesData::getFrameExifData (unsigned int frame) const +rtexif::TagDirectory* FramesData::getFrameExifData(unsigned int frame) const { - return frames.empty() || frame >= frames.size() ? nullptr : frames.at(frame)->getExifData (); + return frames.empty() || frame >= frames.size() ? nullptr : frames.at(frame)->getExifData(); } -rtexif::TagDirectory* FramesData::getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const +rtexif::TagDirectory* FramesData::getBestExifData(ImageSource *imgSource, procparams::RAWParams *rawParams) const { rtexif::TagDirectory *td = nullptr; + if (frames.empty()) { return nullptr; } + if (imgSource && rawParams) { eSensorType sensorType = imgSource->getSensorType(); unsigned int imgNum = 0; + if (sensorType == ST_BAYER) { imgNum = rtengine::LIM(rawParams->bayersensor.imageNum, 0, frames.size() - 1); - /* - // might exist someday ? - } else if (sensorType == ST_FUJI_XTRANS) { - imgNum = rtengine::LIM(rawParams->xtranssensor.imageNum, 0, frames.size() - 1); - } else if (sensorType == ST_NONE && !imgSource->isRAW()) { - // standard image multiframe support should come here (when implemented in GUI) - */ + /* + // might exist someday ? + } else if (sensorType == ST_FUJI_XTRANS) { + imgNum = rtengine::LIM(rawParams->xtranssensor.imageNum, 0, frames.size() - 1); + } else if (sensorType == ST_NONE && !imgSource->isRAW()) { + // standard image multiframe support should come here (when implemented in GUI) + */ } - td = getFrameExifData (imgNum); + td = getFrameExifData(imgNum); rtexif::Tag* makeTag; + if (td && (makeTag = td->findTag("Make", true))) { td = makeTag->getParent(); } else { td = getRootExifData(0); } } + return td; } -rtexif::TagDirectory* FramesData::getRootExifData (unsigned int root) const +rtexif::TagDirectory* FramesData::getRootExifData(unsigned int root) const { return roots.empty() || root >= roots.size() ? nullptr : roots.at(root); } -procparams::IPTCPairs FramesData::getIPTCData (unsigned int frame) const +procparams::IPTCPairs FramesData::getIPTCData(unsigned int frame) const { if (frame < frames.size() && frames.at(frame)->hasIPTC()) { return frames.at(frame)->getIPTCData(); @@ -1214,62 +1234,62 @@ int FramesData::getRating(unsigned int frame) const //------inherited functions--------------// -std::string FramesMetaData::apertureToString (double aperture) +std::string FramesMetaData::apertureToString(double aperture) { char buffer[256]; - sprintf (buffer, "%0.1f", aperture); + sprintf(buffer, "%0.1f", aperture); return buffer; } -std::string FramesMetaData::shutterToString (double shutter) +std::string FramesMetaData::shutterToString(double shutter) { char buffer[256]; if (shutter > 0.0 && shutter <= 0.5) { - sprintf (buffer, "1/%0.0f", 1.0 / shutter); + sprintf(buffer, "1/%0.0f", 1.0 / shutter); } else { - sprintf (buffer, "%0.1f", shutter); + sprintf(buffer, "%0.1f", shutter); } return buffer; } -std::string FramesMetaData::expcompToString (double expcomp, bool maskZeroexpcomp) +std::string FramesMetaData::expcompToString(double expcomp, bool maskZeroexpcomp) { char buffer[256]; if (maskZeroexpcomp) { if (expcomp != 0.0) { - sprintf (buffer, "%0.2f", expcomp); + sprintf(buffer, "%0.2f", expcomp); return buffer; } else { return ""; } } else { - sprintf (buffer, "%0.2f", expcomp); + sprintf(buffer, "%0.2f", expcomp); return buffer; } } -double FramesMetaData::shutterFromString (std::string s) +double FramesMetaData::shutterFromString(std::string s) { - size_t i = s.find_first_of ('/'); + size_t i = s.find_first_of('/'); if (i == std::string::npos) { - return atof (s.c_str()); + return atof(s.c_str()); } else { - return atof (s.substr(0, i).c_str()) / atof (s.substr(i + 1).c_str()); + return atof(s.substr(0, i).c_str()) / atof(s.substr(i + 1).c_str()); } } -double FramesMetaData::apertureFromString (std::string s) +double FramesMetaData::apertureFromString(std::string s) { - return atof (s.c_str()); + return atof(s.c_str()); } extern "C" { @@ -1285,7 +1305,7 @@ extern "C" { }; IptcData * - iptc_data_new_from_jpeg_file (FILE *infile) + iptc_data_new_from_jpeg_file(FILE *infile) { IptcData *d; unsigned char * buf; @@ -1297,52 +1317,52 @@ extern "C" { return nullptr; } - d = iptc_data_new (); + d = iptc_data_new(); if (!d) { return nullptr; } - buf = (unsigned char*)iptc_mem_alloc (d->priv->mem, buf_len); + buf = (unsigned char*)iptc_mem_alloc(d->priv->mem, buf_len); if (!buf) { - iptc_data_unref (d); + iptc_data_unref(d); return nullptr; } - len = iptc_jpeg_read_ps3 (infile, buf, buf_len); + len = iptc_jpeg_read_ps3(infile, buf, buf_len); if (len <= 0) { goto failure; } - offset = iptc_jpeg_ps3_find_iptc (buf, len, &iptc_len); + offset = iptc_jpeg_ps3_find_iptc(buf, len, &iptc_len); if (offset <= 0) { goto failure; } - iptc_data_load (d, buf + offset, iptc_len); + iptc_data_load(d, buf + offset, iptc_len); - iptc_mem_free (d->priv->mem, buf); + iptc_mem_free(d->priv->mem, buf); return d; failure: - iptc_mem_free (d->priv->mem, buf); - iptc_data_unref (d); + iptc_mem_free(d->priv->mem, buf); + iptc_data_unref(d); return nullptr; } } -FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) : - iptc(nullptr), dcrawFrameCount (0) +FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) : + iptc(nullptr), dcrawFrameCount(0) { if (rml && (rml->exifBase >= 0 || rml->ciffBase >= 0)) { - FILE* f = g_fopen (fname.c_str (), "rb"); + FILE* f = g_fopen(fname.c_str(), "rb"); if (f) { - rtexif::ExifManager exifManager (f, std::move(rml), firstFrameOnly); + rtexif::ExifManager exifManager(f, std::move(rml), firstFrameOnly); if (exifManager.f && exifManager.rml) { if (exifManager.rml->exifBase >= 0) { exifManager.parseRaw (); @@ -1358,6 +1378,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } + for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); @@ -1367,29 +1388,34 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } - rewind (exifManager.f); // Not sure this is necessary - iptc = iptc_data_new_from_jpeg_file (exifManager.f); + + rewind(exifManager.f); // Not sure this is necessary + iptc = iptc_data_new_from_jpeg_file(exifManager.f); } - fclose (f); + + fclose(f); } } else if (hasTiffExtension(fname)) { - FILE* f = g_fopen (fname.c_str (), "rb"); + FILE* f = g_fopen(fname.c_str(), "rb"); if (f) { - rtexif::ExifManager exifManager (f, std::move(rml), firstFrameOnly); + rtexif::ExifManager exifManager(f, std::move(rml), firstFrameOnly); exifManager.parseTIFF(); roots = exifManager.roots; @@ -1398,26 +1424,28 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } + for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); if (t && !iptc) { - iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); + iptc = iptc_data_new_from_data((unsigned char*)t->getValue(), (unsigned)t->getValueSize()); break; } } - fclose (f); + + fclose(f); } } } -FramesData::~FramesData () +FramesData::~FramesData() { for (auto currRoot : roots) { delete currRoot; } if (iptc) { - iptc_data_free (iptc); + iptc_data_free(iptc); } } diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index fce181c3f..aa18f1265 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1483,6 +1483,19 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_ADOBE_DEFLATE); TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, (bps == 16 || bps == 32) && isFloat ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT); + [out]() + { + const std::vector default_tags = rtexif::ExifManager::getDefaultTIFFTags(nullptr); + + TIFFSetField (out, TIFFTAG_XRESOLUTION, default_tags[2]->toDouble()); + TIFFSetField (out, TIFFTAG_YRESOLUTION, default_tags[3]->toDouble()); + TIFFSetField (out, TIFFTAG_RESOLUTIONUNIT, default_tags[4]->toInt()); + + for (auto default_tag : default_tags) { + delete default_tag; + } + }(); + if (!uncompressed) { TIFFSetField (out, TIFFTAG_PREDICTOR, (bps == 16 || bps == 32) && isFloat ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL); } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f68616b96..019486198 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -26,6 +26,7 @@ #include "cieimage.h" #include "color.h" #include "colortemp.h" +#include "jaggedarray.h" #include "curves.h" #include "dcp.h" #include "iccstore.h" @@ -153,6 +154,7 @@ ImProcCoordinator::ImProcCoordinator() : pdSharpenAutoRadiusListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), + filmNegListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), @@ -181,7 +183,121 @@ ImProcCoordinator::ImProcCoordinator() : highQualityComputed(false), customTransformIn(nullptr), customTransformOut(nullptr), - ipf(params.get(), true) + ipf(params.get(), true), + + // Locallab + locallListener(nullptr), + reserv(nullptr), + lastorigimp(nullptr), + coordX(0), coordY(0), localX(0), localY(0), + lllocalcurve(65536, 0), + cllocalcurve(65536, 0), + lclocalcurve(65536, 0), + cclocalcurve(65536, 0), + rgblocalcurve(65536, 0), + exlocalcurve(65536, 0), + hltonecurveloc(65536, 0), //32768 + shtonecurveloc(65536, 0), + tonecurveloc(65536, 0), + lightCurveloc(32770, 0), + lmasklocalcurve(65536, 0), + lmaskexplocalcurve(65536, 0), + lmaskSHlocalcurve(65536, 0), + lmaskviblocalcurve(65536, 0), + lmasktmlocalcurve(65536, 0), + lmaskretilocalcurve(65536, 0), + lmaskcblocalcurve(65536, 0), + lmaskbllocalcurve(65536, 0), + lmasklclocalcurve(65536, 0), + locallutili(false), + localclutili(false), + locallcutili(false), + localcutili(false), + localrgbutili(false), + localexutili(false), + llmasutili(false), + lhmasutili(false), + lhhmasutili(false), + lcmasutili(false), + localmaskutili(false), + localmaskexputili(false), + localmaskSHutili(false), + localmaskvibutili(false), + localmasktmutili(false), + localmaskretiutili(false), + localmaskcbutili(false), + localmaskblutili(false), + localmasklcutili(false), + lcmasexputili(false), + lhmasexputili(false), + llmasexputili(false), + lcmasSHutili(false), + lhmasSHutili(false), + llmasSHutili(false), + lcmasvibutili(false), + lhmasvibutili(false), + llmasvibutili(false), + lcmaslcutili(false), + lhmaslcutili(false), + llmaslcutili(false), + lcmascbutili(false), + lhmascbutili(false), + llmascbutili(false), + lcmasretiutili(false), + lhmasretiutili(false), + llmasretiutili(false), + lcmastmutili(false), + lhmastmutili(false), + llmastmutili(false), + lcmasblutili(false), + lhmasblutili(false), + llmasblutili(false), + locwavutili(false), + locwavdenutili(false), + loclevwavutili(false), + locconwavutili(false), + loccompwavutili(false), + loccomprewavutili(false), + locedgwavutili(false), + lmasutiliblwav(false), + lmasutilicolwav(false), + LHutili(false), + HHutili(false), + lastsavrests(500, -10000), + huerefs(500, -100000.f), + huerefblurs(500, -100000.f), + chromarefblurs(500, -100000.f), + lumarefblurs(500, -100000.f), + chromarefs(500, -100000.f), + lumarefs(500, -100000.f), + sobelrefs(500, -100000.f), + avgs(500, -100000.f), + huer(0), + huerblu(0), + chromarblu(0), + lumarblu(0), + chromar(0), + lumar(0), + sobeler(0), + lastsav(0), + avg(0), + lastspotdup(false), + previewDeltaE(false), + locallColorMask(0), + locallColorMaskinv(0), + locallExpMask(0), + locallExpMaskinv(0), + locallSHMask(0), + locallSHMaskinv(0), + locallvibMask(0), + localllcMask(0), + locallcbMask(0), + locallretiMask(0), + locallsoftMask(0), + localltmMask(0), + locallblMask(0), + locallsharMask(0), + retistrsav(nullptr) { } @@ -245,6 +361,7 @@ DetailedCrop* ImProcCoordinator::createCrop(::EditDataProvider *editDataProvider // todo: bitmask containing desired actions, taken from changesSinceLast void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) { + // TODO Locallab printf MyMutex::MyLock processingLock(mProcessing); @@ -377,6 +494,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) xtransAutoContrastListener->autoContrastChanged(contrastThreshold); } + // if a demosaic happened we should also call getimage later, so we need to set the M_INIT flag todo |= (M_INIT | M_CSHARP); @@ -386,9 +504,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) double pdSharpencontrastThreshold = params->pdsharpening.contrast; double pdSharpenRadius = params->pdsharpening.deconvradius; imgsrc->captureSharpening(params->pdsharpening, sharpMask, pdSharpencontrastThreshold, pdSharpenRadius); + if (pdSharpenAutoContrastListener && params->pdsharpening.autoContrast) { pdSharpenAutoContrastListener->autoContrastChanged(pdSharpencontrastThreshold); } + if (pdSharpenAutoRadiusListener && params->pdsharpening.autoRadius) { pdSharpenAutoRadiusListener->autoRadiusChanged(pdSharpenRadius); } @@ -605,8 +725,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) fattal_11_dcrop_cache = nullptr; } - ipf.dehaze(orig_prev); - ipf.ToneMapFattal02(orig_prev); + ipf.dehaze(orig_prev, params->dehaze); + ipf.ToneMapFattal02(orig_prev, params->fattal, 3, 0, nullptr, 0, 0, 0); if (oprevi != orig_prev) { delete oprevi; @@ -674,6 +794,101 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) aeListener->autoMatchedToneCurveChanged(params->toneCurve.curveMode, params->toneCurve.curve); } } + + // Encoding log with locallab + if (params->locallab.enabled) { + const int sizespot = (int)params->locallab.spots.size(); + + float *sourceg = nullptr; + sourceg = new float[sizespot]; + float *targetg = nullptr; + targetg = new float[sizespot]; + bool *log = nullptr; + log = new bool[sizespot]; + bool *autocomput = nullptr; + autocomput = new bool[sizespot]; + float *blackev = nullptr; + blackev = new float[sizespot]; + float *whiteev = nullptr; + whiteev = new float[sizespot]; + bool *Autogr = nullptr; + Autogr = new bool[sizespot]; + + float *locx = nullptr; + locx = new float[sizespot]; + float *locy = nullptr; + locy = new float[sizespot]; + float *locxL = nullptr; + locxL = new float[sizespot]; + float *locyT = nullptr; + locyT = new float[sizespot]; + float *centx = nullptr; + centx = new float[sizespot]; + float *centy = nullptr; + centy = new float[sizespot]; + + for (int sp = 0; sp < sizespot; sp++) { + log[sp] = params->locallab.spots.at(sp).explog; + autocomput[sp] = params->locallab.spots.at(sp).autocompute; + blackev[sp] = params->locallab.spots.at(sp).blackEv; + whiteev[sp] = params->locallab.spots.at(sp).whiteEv; + sourceg[sp] = params->locallab.spots.at(sp).sourceGray; + Autogr[sp] = params->locallab.spots.at(sp).Autogray; + targetg[sp] = params->locallab.spots.at(sp).targetGray; + locx[sp] = params->locallab.spots.at(sp).loc.at(0) / 2000.0; + locy[sp] = params->locallab.spots.at(sp).loc.at(2) / 2000.0; + locxL[sp] = params->locallab.spots.at(sp).loc.at(1) / 2000.0; + locyT[sp] = params->locallab.spots.at(sp).loc.at(3) / 2000.0; + centx[sp] = params->locallab.spots.at(sp).centerX / 2000.0 + 0.5; + centy[sp] = params->locallab.spots.at(sp).centerY / 2000.0 + 0.5; + + const bool fullim = params->locallab.spots.at(sp).fullimage; + + if (log[sp] && autocomput[sp]) { + constexpr int SCALE = 10; + int fw, fh, tr = TR_NONE; + imgsrc->getFullSize(fw, fh, tr); + PreviewProps pp(0, 0, fw, fh, SCALE); + + float ysta = std::max(static_cast(centy[sp] - locyT[sp]), 0.f); + float yend = std::min(static_cast(centy[sp] + locy[sp]), 1.f); + float xsta = std::max(static_cast(centx[sp] - locxL[sp]), 0.f); + float xend = std::min(static_cast(centx[sp] + locx[sp]), 1.f); + + if (fullim) { + ysta = 0.f; + yend = 1.f; + xsta = 0.f; + xend = 1.f; + } + + ipf.getAutoLogloc(sp, imgsrc, sourceg, blackev, whiteev, Autogr, fw, fh, xsta, xend, ysta, yend, SCALE); + + params->locallab.spots.at(sp).blackEv = blackev[sp]; + params->locallab.spots.at(sp).whiteEv = whiteev[sp]; + params->locallab.spots.at(sp).sourceGray = sourceg[sp]; + + if (locallListener) { + locallListener->logencodChanged(blackev[sp], whiteev[sp], sourceg[sp], targetg[sp]); + } + } + } + + delete [] locx; + delete [] locy; + delete [] locxL; + delete [] locyT; + delete [] centx; + delete [] centy; + + delete [] Autogr; + delete [] whiteev; + delete [] blackev; + delete [] targetg; + delete [] sourceg; + delete [] log; + delete [] autocomput; + } } if (todo & (M_AUTOEXP | M_RGBCURVE)) { @@ -822,11 +1037,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // correct GUI black and white with value } + // ipf.Lab_Tile(oprevl, oprevl, scale); + // compute L channel histogram int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); } +// lhist16(32768); if (todo & (M_LUMACURVE | M_CROP)) { LUTu lhist16(32768); lhist16.clear(); @@ -866,13 +1084,358 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) params->labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16); } - if (todo & (M_LUMINANCE + M_COLOR)) { + //scale = 1; + + if ((todo & (M_LUMINANCE + M_COLOR)) || (todo & M_AUTOEXP)) { nprevl->CopyFrom(oprevl); + reserv->CopyFrom(oprevl); + lastorigimp->CopyFrom(oprevl); + + // int maxspot = 1; + //************************************************************* + // locallab + //************************************************************* + + if (params->locallab.enabled) { + /* + * 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 . + * 2017 2018 Jacques Desmis + * 2019 Pierre Cabrera + */ + + float **shbuffer = nullptr; + int sca = 1; + double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre; + float avge; + std::vector locallref; + std::vector locallretiminmax; + + for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) { + // Set local curves of current spot to LUT + LHutili = false; + HHutili = false; + locallutili = false; + localclutili = false; + locallcutili = false; + localexutili = false; + localrgbutili = false; + localcutili = false; + llmasutili = false; + lhmasutili = false; + lhhmasutili = false; + lcmasutili = false; + localmaskutili = false; + lcmasexputili = false; + lhmasexputili = false; + llmasexputili = false; + localmaskexputili = false; + localmaskSHutili = false; + localmaskvibutili = false; + localmasktmutili = false; + localmaskretiutili = false; + localmaskcbutili = false; + localmaskblutili = false; + localmasklcutili = false; + lcmasSHutili = false; + lhmasSHutili = false; + llmasSHutili = false; + lcmasvibutili = false; + lhmasvibutili = false; + llmasvibutili = false; + lcmascbutili = false; + lhmascbutili = false; + llmascbutili = false; + lcmaslcutili = false; + lhmaslcutili = false; + llmaslcutili = false; + lcmasretiutili = false; + lhmasretiutili = false; + llmasretiutili = false; + lcmastmutili = false; + lhmastmutili = false; + llmastmutili = false; + lcmasblutili = false; + lhmasblutili = false; + llmasblutili = false; + lcmasutili = false; + locwavutili = false; + locwavdenutili = false; + loclevwavutili = false; + locconwavutili = false; + loccompwavutili = false; + loccomprewavutili = false; + locedgwavutili = false; + lmasutiliblwav = false; + lmasutilicolwav = false; + locRETgainCurve.Set(params->locallab.spots.at(sp).localTgaincurve); + locRETtransCurve.Set(params->locallab.spots.at(sp).localTtranscurve); + loclhCurve.Set(params->locallab.spots.at(sp).LHcurve, LHutili); + lochhCurve.Set(params->locallab.spots.at(sp).HHcurve, HHutili); + locccmasCurve.Set(params->locallab.spots.at(sp).CCmaskcurve, lcmasutili); + locllmasCurve.Set(params->locallab.spots.at(sp).LLmaskcurve, llmasutili); + lochhmasCurve.Set(params->locallab.spots.at(sp).HHmaskcurve, lhmasutili); + lochhhmasCurve.Set(params->locallab.spots.at(sp).HHhmaskcurve, lhhmasutili); + locllmasexpCurve.Set(params->locallab.spots.at(sp).LLmaskexpcurve, llmasexputili); + locccmasexpCurve.Set(params->locallab.spots.at(sp).CCmaskexpcurve, lcmasexputili); + lochhmasexpCurve.Set(params->locallab.spots.at(sp).HHmaskexpcurve, lhmasexputili); + locllmasSHCurve.Set(params->locallab.spots.at(sp).LLmaskSHcurve, llmasSHutili); + locccmasSHCurve.Set(params->locallab.spots.at(sp).CCmaskSHcurve, lcmasSHutili); + lochhmasSHCurve.Set(params->locallab.spots.at(sp).HHmaskSHcurve, lhmasSHutili); + locllmasvibCurve.Set(params->locallab.spots.at(sp).LLmaskvibcurve, llmasvibutili); + locccmasvibCurve.Set(params->locallab.spots.at(sp).CCmaskvibcurve, lcmasvibutili); + lochhmasvibCurve.Set(params->locallab.spots.at(sp).HHmaskvibcurve, lhmasvibutili); + locllmascbCurve.Set(params->locallab.spots.at(sp).LLmaskcbcurve, llmascbutili); + locccmascbCurve.Set(params->locallab.spots.at(sp).CCmaskcbcurve, lcmascbutili); + lochhmascbCurve.Set(params->locallab.spots.at(sp).HHmaskcbcurve, lhmascbutili); + locllmaslcCurve.Set(params->locallab.spots.at(sp).LLmasklccurve, llmaslcutili); + locccmaslcCurve.Set(params->locallab.spots.at(sp).CCmasklccurve, lcmaslcutili); + lochhmaslcCurve.Set(params->locallab.spots.at(sp).HHmasklccurve, lhmaslcutili); + locllmasretiCurve.Set(params->locallab.spots.at(sp).LLmaskreticurve, llmasretiutili); + locccmasretiCurve.Set(params->locallab.spots.at(sp).CCmaskreticurve, lcmasretiutili); + lochhmasretiCurve.Set(params->locallab.spots.at(sp).HHmaskreticurve, lhmasretiutili); + locllmastmCurve.Set(params->locallab.spots.at(sp).LLmasktmcurve, llmastmutili); + locccmastmCurve.Set(params->locallab.spots.at(sp).CCmasktmcurve, lcmastmutili); + lochhmastmCurve.Set(params->locallab.spots.at(sp).HHmasktmcurve, lhmastmutili); + locllmasblCurve.Set(params->locallab.spots.at(sp).LLmaskblcurve, llmasblutili); + locccmasblCurve.Set(params->locallab.spots.at(sp).CCmaskblcurve, lcmasblutili); + lochhmasblCurve.Set(params->locallab.spots.at(sp).HHmaskblcurve, lhmasblutili); + loclmasCurveblwav.Set(params->locallab.spots.at(sp).LLmaskblcurvewav, lmasutiliblwav); + loclmasCurvecolwav.Set(params->locallab.spots.at(sp).LLmaskcolcurvewav, lmasutilicolwav); + locwavCurve.Set(params->locallab.spots.at(sp).locwavcurve, locwavutili); + loclevwavCurve.Set(params->locallab.spots.at(sp).loclevwavcurve, loclevwavutili); + locconwavCurve.Set(params->locallab.spots.at(sp).locconwavcurve, locconwavutili); + loccompwavCurve.Set(params->locallab.spots.at(sp).loccompwavcurve, loccompwavutili); + loccomprewavCurve.Set(params->locallab.spots.at(sp).loccomprewavcurve, loccomprewavutili); + locwavCurveden.Set(params->locallab.spots.at(sp).locwavcurveden, locwavdenutili); + locedgwavCurve.Set(params->locallab.spots.at(sp).locedgwavcurve, locedgwavutili); + CurveFactory::curveLocal(locallutili, params->locallab.spots.at(sp).llcurve, lllocalcurve, sca); + CurveFactory::curveLocal(localclutili, params->locallab.spots.at(sp).clcurve, cllocalcurve, sca); + CurveFactory::curveLocal(locallcutili, params->locallab.spots.at(sp).lccurve, lclocalcurve, sca); + CurveFactory::curveCCLocal(localcutili, params->locallab.spots.at(sp).cccurve, cclocalcurve, sca); + CurveFactory::curveLocal(localrgbutili, params->locallab.spots.at(sp).rgbcurve, rgblocalcurve, sca); + CurveFactory::curveexLocal(localexutili, params->locallab.spots.at(sp).excurve, exlocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskutili, params->locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskexputili, params->locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskSHutili, params->locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskvibutili, params->locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve, sca); + CurveFactory::curvemaskLocal(localmasktmutili, params->locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskretiutili, params->locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskcbutili, params->locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve, sca); + CurveFactory::curvemaskLocal(localmaskblutili, params->locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve, sca); + CurveFactory::curvemaskLocal(localmasklcutili, params->locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve, sca); + double ecomp = params->locallab.spots.at(sp).expcomp; + double black = params->locallab.spots.at(sp).black; + double hlcompr = params->locallab.spots.at(sp).hlcompr; + double hlcomprthresh = params->locallab.spots.at(sp).hlcomprthresh; + double shcompr = params->locallab.spots.at(sp).shcompr; + double br = params->locallab.spots.at(sp).lightness; + double cont = params->locallab.spots.at(sp).contrast; + + if (black < 0. && params->locallab.spots.at(sp).expMethod == "pde") { + black *= 1.5; + } + + // Reference parameters computation + if (params->locallab.spots.at(sp).spotMethod == "exc") { + ipf.calc_ref(sp, reserv, reserv, 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); + } else { + ipf.calc_ref(sp, nprevl, nprevl, 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); + } + + huerblu = huerefblurs[sp] = huerefblu; + chromarblu = chromarefblurs[sp] = chromarefblu; + lumarblu = lumarefblurs[sp] = lumarefblu; + huer = huerefs[sp] = huere; + chromar = chromarefs[sp] = chromare; + lumar = lumarefs[sp] = lumare ; + sobeler = sobelrefs[sp] = sobelre; + avg = avgs[sp] = avge; + CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumar, + hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, avg, + sca); + + // Save Locallab mask curve references for current spot + LocallabListener::locallabRef spotref; + spotref.huer = huer; + spotref.lumar = lumar; + spotref.chromar = chromar; + locallref.push_back(spotref); + + // Locallab tools computation + /* Notes: + * - shbuffer is used as nullptr + */ + // Locallab mask is only showed in detailed image + float minCD; + float maxCD; + float mini; + float maxi; + float Tmean; + float Tsigma; + float Tmin; + float Tmax; + ipf.Lab_Local(3, sp, (float**)shbuffer, nprevl, nprevl, reserv, lastorigimp, 0, 0, pW, pH, scale, locRETgainCurve, locRETtransCurve, + lllocalcurve, locallutili, + cllocalcurve, localclutili, + lclocalcurve, locallcutili, + loclhCurve, lochhCurve, + lmasklocalcurve, localmaskutili, + lmaskexplocalcurve, localmaskexputili, + lmaskSHlocalcurve, localmaskSHutili, + lmaskviblocalcurve, localmaskvibutili, + lmasktmlocalcurve, localmasktmutili, + lmaskretilocalcurve, localmaskretiutili, + lmaskcblocalcurve, localmaskcbutili, + lmaskbllocalcurve, localmaskblutili, + lmasklclocalcurve, localmasklcutili, + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, + locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, + locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili, + locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, + locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, + locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili, + locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili, + loclmasCurveblwav, lmasutiliblwav, + loclmasCurvecolwav, lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + LHutili, HHutili, cclocalcurve, localcutili, rgblocalcurve, localrgbutili, localexutili, exlocalcurve, hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, + huerblu, chromarblu, lumarblu, huer, chromar, lumar, sobeler, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + + lastorigimp->CopyFrom(nprevl); + + // Save Locallab Retinex min/max for current spot + LocallabListener::locallabRetiMinMax retiMinMax; + retiMinMax.cdma = maxCD; + retiMinMax.cdmin = minCD; + retiMinMax.mini = mini; + retiMinMax.maxi = maxi; + retiMinMax.Tmean = Tmean; + retiMinMax.Tsigma = Tsigma; + retiMinMax.Tmin = Tmin; + retiMinMax.Tmax = Tmax; + locallretiminmax.push_back(retiMinMax); + + // Recalculate references after + if (params->locallab.spots.at(sp).spotMethod == "exc") { + ipf.calc_ref(sp, reserv, reserv, 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huer, chromar, lumar, sobeler, avg, locwavCurveden, locwavdenutili); + } else { + ipf.calc_ref(sp, nprevl, nprevl, 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huer, chromar, lumar, sobeler, avg, locwavCurveden, locwavdenutili); + } + + // Update Locallab reference values according to recurs parameter + if (params->locallab.spots.at(sp).recurs) { + locallref.at(sp).chromar = chromar; + locallref.at(sp).lumar = lumar; + locallref.at(sp).huer = huer; + } + + /* + //very bad idea : it's the story of the cat biting its tail + // brings big bugs.. + //restore ref values + huerefs[sp] = huer; + chromarefs[sp] = chromar; + lumarefs[sp] = lumar ; + sobelrefs[sp] = sobeler; + */ + lllocalcurve.clear(); + lclocalcurve.clear(); + cllocalcurve.clear(); + lightCurveloc.clear(); + cclocalcurve.clear(); + rgblocalcurve.clear(); + exlocalcurve.clear(); + lmasklocalcurve.clear(); + lmaskexplocalcurve.clear(); + lmaskSHlocalcurve.clear(); + lmaskviblocalcurve.clear(); + lmasktmlocalcurve.clear(); + lmaskretilocalcurve.clear(); + lmaskcblocalcurve.clear(); + lmaskbllocalcurve.clear(); + lmasklclocalcurve.clear(); + hltonecurveloc.clear(); + shtonecurveloc.clear(); + tonecurveloc.clear(); + locRETgainCurve.Reset(); + locRETtransCurve.Reset(); + loclhCurve.Reset(); + lochhCurve.Reset(); + locccmasCurve.Reset(); + locllmasCurve.Reset(); + lochhmasCurve.Reset(); + lochhhmasCurve.Reset(); + locllmasexpCurve.Reset(); + locccmasexpCurve.Reset(); + lochhmasexpCurve.Reset(); + locllmasSHCurve.Reset(); + locccmasSHCurve.Reset(); + lochhmasSHCurve.Reset(); + locllmasvibCurve.Reset(); + locccmasvibCurve.Reset(); + lochhmasvibCurve.Reset(); + locllmascbCurve.Reset(); + locccmascbCurve.Reset(); + lochhmascbCurve.Reset(); + locllmasretiCurve.Reset(); + locccmasretiCurve.Reset(); + lochhmasretiCurve.Reset(); + locllmastmCurve.Reset(); + locccmastmCurve.Reset(); + lochhmastmCurve.Reset(); + locllmasblCurve.Reset(); + locccmasblCurve.Reset(); + lochhmasblCurve.Reset(); + locllmaslcCurve.Reset(); + locccmaslcCurve.Reset(); + lochhmaslcCurve.Reset(); + locwavCurve.Reset(); + loclevwavCurve.Reset(); + locconwavCurve.Reset(); + locwavCurveden.Reset(); + locwavCurve.Reset(); + loclmasCurveblwav.Reset(); + loclmasCurvecolwav.Reset(); + } + + // Transmit Locallab reference values and Locallab Retinex min/max to LocallabListener + if (locallListener) { + locallListener->refChanged(locallref, params->locallab.selspot); + locallListener->minmaxChanged(locallretiminmax, params->locallab.selspot); + } + } + + //************************************************************* + // end locallab + //************************************************************* histCCurve.clear(); histLCurve.clear(); ipf.chromiLuminanceCurve(nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); - ipf.vibrance(nprevl); + ipf.vibrance(nprevl, params->vibrance, params->toneCurve.hrenabled, params->icm.workingProfile); ipf.labColorCorrectionRegions(nprevl); if ((params->colorappearance.enabled && !params->colorappearance.tonecie) || (!params->colorappearance.enabled)) { @@ -891,7 +1454,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if ((params->wavelet.enabled)) { WaveletParams WaveParams = params->wavelet; - WaveParams.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); + WaveParams.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); int kall = 0; LabImage *unshar = nullptr; Glib::ustring provis; @@ -920,7 +1483,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) unshar = new LabImage(pW, pH); provis = params->wavelet.CLmethod; params->wavelet.CLmethod = "all"; - ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); + ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); unshar->CopyFrom(nprevl); @@ -934,7 +1497,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) WaveParams.expnoise = false; } - ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); + ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { @@ -1102,7 +1665,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } - ipf.softLight(nprevl); + ipf.softLight(nprevl, params->softlight); if (params->colorappearance.enabled) { // L histo and Chroma histo for ciecam @@ -1173,7 +1736,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) CAMBrightCurveJ.dirty = true; CAMBrightCurveQ.dirty = true; - ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, params.get(), customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 0 , scale, execsharp, d, dj, yb, 1); + ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, params.get(), customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 0, scale, execsharp, d, dj, yb, 1); if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); @@ -1219,7 +1782,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } - // process crop, if needed +// process crop, if needed for (size_t i = 0; i < crops.size(); i++) if (crops[i]->hasListener() && (panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar) || (todo & (M_MONITOR | M_RGBCURVE | M_LUMACURVE)) || crops[i]->get_skip() == 1)) { crops[i]->update(todo); // may call ourselves @@ -1285,6 +1848,10 @@ void ImProcCoordinator::freeAll() oprevl = nullptr; delete nprevl; nprevl = nullptr; + delete reserv; + reserv = nullptr; + delete lastorigimp; + lastorigimp = nullptr; if (ncie) { delete ncie; @@ -1338,6 +1905,10 @@ void ImProcCoordinator::setScale(int prevscale) oprevi = orig_prev; oprevl = new LabImage(pW, pH); nprevl = new LabImage(pW, pH); + reserv = new LabImage(pW, pH); + lastorigimp = new LabImage(pW, pH); + + // nprevloc = new LabImage (pW, pH); //ncie is only used in ImProcCoordinator::updatePreviewImage, it will be allocated on first use and deleted if not used anymore previmg = new Image8(pW, pH); workimg = new Image8(pW, pH); @@ -1578,7 +2149,7 @@ void ImProcCoordinator::getSoftProofing(bool &softProof, bool &gamutCheck) gamutCheck = this->gamutCheck; } -ProcEvent ImProcCoordinator::setSharpMask (bool sharpMask) +ProcEvent ImProcCoordinator::setSharpMask(bool sharpMask) { if (this->sharpMask != sharpMask) { sharpMaskChanged = true; @@ -1755,8 +2326,9 @@ void ImProcCoordinator::process() while (changeSinceLast) { const bool panningRelatedChange = - params->toneCurve.isPanningRelatedChange(nextParams->toneCurve) + params->toneCurve.isPanningRelatedChange(nextParams->toneCurve) || params->labCurve != nextParams->labCurve + || params->locallab != nextParams->locallab || params->localContrast != nextParams->localContrast || params->rgbCurves != nextParams->rgbCurves || params->colorToning != nextParams->colorToning diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index e17d88183..da253c072 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -92,7 +92,7 @@ protected: bool highDetailRawComputed; bool allocated; - void freeAll (); + void freeAll(); // Precomputed values used by DetailedCrop ---------------------------------------------- @@ -141,6 +141,7 @@ protected: WavCurve wavCLVCurve; Wavblcurve wavblcurve; WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveSH waOpacityCurveSH; WavOpacityCurveBY waOpacityCurveBY; WavOpacityCurveW waOpacityCurveW; WavOpacityCurveWL waOpacityCurveWL; @@ -176,12 +177,13 @@ protected: FrameCountListener *frameCountListener; ImageTypeListener *imageTypeListener; FilmNegListener *filmNegListener; - AutoColorTonListener* actListener; AutoChromaListener* adnListener; WaveletListener* awavListener; RetinexListener* dehaListener; +// LocallabListener* locallListener; + HistogramListener* hListener; std::vector sizeListeners; @@ -191,9 +193,9 @@ protected: MyMutex minit; // to gain mutually exclusive access to ... to what exactly? - void reallocAll (); - void updateLRGBHistograms (); - void setScale (int prevscale); + void reallocAll(); + void updateLRGBHistograms(); + void setScale(int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); MyMutex mProcessing; @@ -222,15 +224,165 @@ protected: bool clcutili; bool opautili; bool wavcontlutili; - void startProcessing (); - void process (); + void startProcessing(); + void process(); float colourToningSatLimit; float colourToningSatLimitOpacity; bool highQualityComputed; cmsHTRANSFORM customTransformIn; cmsHTRANSFORM customTransformOut; - ImProcFunctions ipf; + + //locallab + LocallabListener* locallListener; + LabImage *reserv; + LabImage *lastorigimp; + int coordX, coordY, localX, localY; + LUTf lllocalcurve; + LUTf cllocalcurve; + LUTf lclocalcurve; + LUTf cclocalcurve; + LUTf rgblocalcurve; + LUTf exlocalcurve; + LUTf hltonecurveloc; + LUTf shtonecurveloc; + LUTf tonecurveloc; + LUTf lightCurveloc; + LUTf lmasklocalcurve; + LUTf lmaskexplocalcurve; + LUTf lmaskSHlocalcurve; + LUTf lmaskviblocalcurve; + LUTf lmasktmlocalcurve; + LUTf lmaskretilocalcurve; + LUTf lmaskcblocalcurve; + LUTf lmaskbllocalcurve; + LUTf lmasklclocalcurve; +// LUTu lhist16loc; + LocretigainCurve locRETgainCurve; + LocretitransCurve locRETtransCurve; + LocretigainCurverab locRETgainCurverab; + LocLHCurve loclhCurve; + LocHHCurve lochhCurve; + LocCCmaskCurve locccmasCurve; + LocLLmaskCurve locllmasCurve; + LocHHmaskCurve lochhmasCurve; + LocHHmaskCurve lochhhmasCurve; + LocCCmaskCurve locccmasexpCurve; + LocLLmaskCurve locllmasexpCurve; + LocHHmaskCurve lochhmasexpCurve; + LocCCmaskCurve locccmasSHCurve; + LocLLmaskCurve locllmasSHCurve; + LocHHmaskCurve lochhmasSHCurve; + LocCCmaskCurve locccmasvibCurve; + LocLLmaskCurve locllmasvibCurve; + LocHHmaskCurve lochhmasvibCurve; + LocCCmaskCurve locccmaslcCurve; + LocLLmaskCurve locllmaslcCurve; + LocHHmaskCurve lochhmaslcCurve; + LocCCmaskCurve locccmascbCurve; + LocLLmaskCurve locllmascbCurve; + LocHHmaskCurve lochhmascbCurve; + LocCCmaskCurve locccmasretiCurve; + LocLLmaskCurve locllmasretiCurve; + LocHHmaskCurve lochhmasretiCurve; + LocCCmaskCurve locccmastmCurve; + LocLLmaskCurve locllmastmCurve; + LocHHmaskCurve lochhmastmCurve; + LocCCmaskCurve locccmasblCurve; + LocLLmaskCurve locllmasblCurve; + LocHHmaskCurve lochhmasblCurve; + LocwavCurve locwavCurve; + LocwavCurve loclmasCurveblwav; + LocwavCurve loclmasCurvecolwav; + LocwavCurve loclevwavCurve; + LocwavCurve locconwavCurve; + LocwavCurve loccompwavCurve; + LocwavCurve loccomprewavCurve; + LocwavCurve locwavCurveden; + LocwavCurve locedgwavCurve; + + bool locallutili; + bool localclutili; + bool locallcutili; + bool localcutili; + bool localrgbutili; + bool localexutili; + bool llmasutili; + bool lhmasutili; + bool lhhmasutili; + bool lcmasutili; + bool localmaskutili; + bool localmaskexputili; + bool localmaskSHutili; + bool localmaskvibutili; + bool localmasktmutili; + bool localmaskretiutili; + bool localmaskcbutili; + bool localmaskblutili; + bool localmasklcutili; + bool lcmasexputili; + bool lhmasexputili; + bool llmasexputili; + bool lcmasSHutili; + bool lhmasSHutili; + bool llmasSHutili; + bool lcmasvibutili; + bool lhmasvibutili; + bool llmasvibutili; + bool lcmaslcutili; + bool lhmaslcutili; + bool llmaslcutili; + bool lcmascbutili; + bool lhmascbutili; + bool llmascbutili; + bool lcmasretiutili; + bool lhmasretiutili; + bool llmasretiutili; + bool lcmastmutili; + bool lhmastmutili; + bool llmastmutili; + bool lcmasblutili; + bool lhmasblutili; + bool llmasblutili; + bool locwavutili; + bool locwavdenutili; + bool loclevwavutili; + bool locconwavutili; + bool loccompwavutili; + bool loccomprewavutili; + bool locedgwavutili; + bool lmasutiliblwav; + bool lmasutilicolwav; + bool LHutili; + bool HHutili; + LUTu lastsavrests; + LUTf huerefs; + LUTf huerefblurs; + LUTf chromarefblurs; + LUTf lumarefblurs; + LUTf chromarefs; + LUTf lumarefs; + LUTf sobelrefs; + LUTf avgs; + double huer, huerblu, chromarblu, lumarblu, chromar, lumar, sobeler; + int lastsav; + float avg; + bool lastspotdup; + bool previewDeltaE; + int locallColorMask; + int locallColorMaskinv; + int locallExpMask; + int locallExpMaskinv; + int locallSHMask; + int locallSHMaskinv; + int locallvibMask; + int localllcMask; + int locallcbMask; + int locallretiMask; + int locallsoftMask; + int localltmMask; + int locallblMask; + int locallsharMask; public: @@ -246,10 +398,11 @@ public: void endUpdateParams (int changeFlags) override; void stopProcessing () override; + std::string *retistrsav; void setPreviewScale (int scale) override { - setScale (scale); + setScale(scale); } int getPreviewScale () override { @@ -300,6 +453,25 @@ public: updaterThreadStart.unlock(); } + void setLocallabMaskVisibility(bool previewDeltaE, int locallColorMask, int locallColorMaskinv, int locallExpMask, int locallExpMaskinv, int locallSHMask, int locallSHMaskinv, int locallvibMask, int locallsoftMask, int locallblMask, int localltmMask, int locallretiMask, int locallsharMask, int localllcMask, int locallcbMask) override + { + this->previewDeltaE = previewDeltaE; + this->locallColorMask = locallColorMask; + this->locallColorMaskinv = locallColorMaskinv; + this->locallExpMask = locallExpMask; + this->locallExpMaskinv = locallExpMaskinv; + this->locallSHMask = locallSHMask; + this->locallSHMaskinv = locallSHMaskinv; + this->locallvibMask = locallvibMask; + this->locallsoftMask = locallsoftMask; + this->locallblMask = locallblMask; + this->localltmMask = localltmMask; + this->locallretiMask = locallretiMask; + this->locallsharMask = locallsharMask; + this->localllcMask = localllcMask; + this->locallcbMask = locallcbMask; + } + void setProgressListener (ProgressListener* pl) override { plistener = pl; @@ -310,14 +482,14 @@ public: } void setSizeListener (SizeListener* il) override { - sizeListeners.push_back (il); + sizeListeners.push_back(il); } void delSizeListener (SizeListener* il) override { - std::vector::iterator it = std::find (sizeListeners.begin(), sizeListeners.end(), il); + std::vector::iterator it = std::find(sizeListeners.begin(), sizeListeners.end(), il); if (it != sizeListeners.end()) { - sizeListeners.erase (it); + sizeListeners.erase(it); } } void setAutoExpListener (AutoExpListener* ael) override @@ -352,6 +524,10 @@ public: { dehaListener = adh; } + void setLocallabListener (LocallabListener* lla) override + { + locallListener = lla; + } void setWaveletListener (WaveletListener* awa) override { awavListener = awa; @@ -414,7 +590,7 @@ public: } struct DenoiseInfoStore { - DenoiseInfoStore () : chM (0), max_r{}, max_b{}, ch_M{}, 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 aa5515e79..6051b6b0b 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -51,10 +51,6 @@ #include "../rtgui/editcallbacks.h" -#ifdef _DEBUG -#include "mytime.h" -#endif - namespace { using namespace rtengine; @@ -173,31 +169,37 @@ void highlightToneCurve(const LUTf &hltonecurve, float *rtemp, float *gtemp, flo } } -void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize) { +void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize) +{ // this is a hack to avoid the blue=>black bug (Issue 2141) for (int i = istart, ti = 0; i < tH; i++, ti++) { int j = jstart, tj = 0; #ifdef __SSE2__ - for (; j < tW - 3; j+=4, tj+=4) { + + for (; j < tW - 3; j += 4, tj += 4) { vfloat rv = LVF(rtemp[ti * tileSize + tj]); vfloat gv = LVF(gtemp[ti * tileSize + tj]); vmask zeromask = vorm(vmaskf_eq(rv, ZEROV), vmaskf_eq(gv, ZEROV)); - if(_mm_movemask_ps((vfloat)zeromask)) { + + if (_mm_movemask_ps((vfloat)zeromask)) { for (int k = 0; k < 4; ++k) { float r = rtemp[ti * tileSize + tj + k]; float g = gtemp[ti * tileSize + tj + k]; + float b = btemp[ti * tileSize + tj + k]; if ((r == 0.0f || g == 0.0f) && rtengine::min(r, g, b) >= 0.f) { float h, s, v; - Color::rgb2hsv (r, g, b, h, s, v); + Color::rgb2hsv(r, g, b, h, s, v); s *= 0.99f; - Color::hsv2rgb (h, s, v, rtemp[ti * tileSize + tj + k], gtemp[ti * tileSize + tj + k], btemp[ti * tileSize + tj + k]); + Color::hsv2rgb(h, s, v, rtemp[ti * tileSize + tj + k], gtemp[ti * tileSize + tj + k], btemp[ti * tileSize + tj + k]); } } } } + #endif + for (; j < tW; j++, tj++) { float r = rtemp[ti * tileSize + tj]; float g = gtemp[ti * tileSize + tj]; @@ -205,9 +207,9 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH, if ((r == 0.0f || g == 0.0f) && rtengine::min(r, g, b) >= 0.f) { float h, s, v; - Color::rgb2hsv (r, g, b, h, s, v); + Color::rgb2hsv(r, g, b, h, s, v); s *= 0.99f; - Color::hsv2rgb (h, s, v, rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); + Color::hsv2rgb(h, s, v, rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); } } } @@ -253,7 +255,8 @@ void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, } } -void fillEditFloat(float *editIFloatTmpR, float *editIFloatTmpG, float *editIFloatTmpB, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize) { +void fillEditFloat(float *editIFloatTmpR, float *editIFloatTmpG, float *editIFloatTmpB, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize) +{ for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { editIFloatTmpR[ti * tileSize + tj] = Color::gamma2curve[rtemp[ti * tileSize + tj]] / 65535.f; @@ -274,22 +277,23 @@ using namespace procparams; ImProcFunctions::~ImProcFunctions () { if (monitorTransform) { - cmsDeleteTransform (monitorTransform); + cmsDeleteTransform(monitorTransform); } } -void ImProcFunctions::setScale (double iscale) +void ImProcFunctions::setScale(double iscale) { scale = iscale; } -void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck) +void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck) { // set up monitor transform if (monitorTransform) { - cmsDeleteTransform (monitorTransform); + cmsDeleteTransform(monitorTransform); } + gamutWarning.reset(nullptr); monitorTransform = nullptr; @@ -298,17 +302,17 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, if (!monitorProfile.empty()) { #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB - monitor = ICCStore::getInstance()->getProfile (monitorProfile); + monitor = ICCStore::getInstance()->getProfile(monitorProfile); #else monitor = ICCStore::getInstance()->getProfile (settings->srgb); #endif } if (monitor) { - MyMutex::MyLock lcmsLock (*lcmsMutex); + MyMutex::MyLock lcmsLock(*lcmsMutex); cmsUInt32Number flags; - cmsHPROFILE iprof = cmsCreateLab4Profile (nullptr); + cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); cmsHPROFILE gamutprof = nullptr; cmsUInt32Number gamutbpc = 0; RenderingIntent gamutintent = RI_RELATIVE; @@ -322,7 +326,8 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; if (!settings->printerProfile.empty()) { - oprof = ICCStore::getInstance()->getProfile (settings->printerProfile); + oprof = ICCStore::getInstance()->getProfile(settings->printerProfile); + if (settings->printerBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } @@ -332,6 +337,7 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, if (params->icm.outputBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } + outIntent = params->icm.outputIntent; } @@ -363,7 +369,7 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, make_gamma_table(softproof, cmsSigBlueTRCTag); } - monitorTransform = cmsCreateProofingTransform ( + monitorTransform = cmsCreateProofingTransform( iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_FLT, softproof, //oprof, @@ -381,9 +387,11 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, if (gamutCheck) { gamutprof = oprof; + if (params->icm.outputBPC) { gamutbpc = cmsFLAGS_BLACKPOINTCOMPENSATION; } + gamutintent = outIntent; } } @@ -399,9 +407,11 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, // softProofCreated = true; // } gamutprof = monitor; + if (settings->monitorBPC) { gamutbpc = cmsFLAGS_BLACKPOINTCOMPENSATION; } + gamutintent = monitorIntent; } @@ -412,18 +422,18 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } - monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_FLT, monitorIntent, flags); + monitorTransform = cmsCreateTransform(iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_FLT, monitorIntent, flags); } if (gamutCheck && gamutprof) { gamutWarning.reset(new GamutWarning(iprof, gamutprof, gamutintent, gamutbpc)); } - cmsCloseProfile (iprof); + cmsCloseProfile(iprof); } } -void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) +void ImProcFunctions::firstAnalysis(const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) { TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.workingProfile); @@ -434,7 +444,7 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro int W = original->getWidth(); int H = original->getHeight(); - float lumimulf[3] = {static_cast (lumimul[0]), static_cast (lumimul[1]), static_cast (lumimul[2])}; + float lumimulf[3] = {static_cast(lumimul[0]), static_cast(lumimul[1]), static_cast(lumimul[2])}; // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments histogram.clear(); @@ -442,11 +452,11 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro if (multiThread) { #ifdef _OPENMP - const int numThreads = min (max (W * H / (int)histogram.getSize(), 1), omp_get_max_threads()); + const int numThreads = min(max(W * H / (int)histogram.getSize(), 1), omp_get_max_threads()); #pragma omp parallel num_threads(numThreads) if(numThreads>1) #endif { - LUTu hist (histogram.getSize()); + LUTu hist(histogram.getSize()); hist.clear(); #ifdef _OPENMP #pragma omp for nowait @@ -455,9 +465,9 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { - float r = original->r (i, j); - float g = original->g (i, j); - float b = original->b (i, j); + float r = original->r(i, j); + float g = original->g(i, j); + float b = original->b(i, j); int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b); hist[y]++; @@ -471,15 +481,15 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro } #ifdef _OPENMP - static_cast (numThreads); // to silence cppcheck warning + static_cast(numThreads); // to silence cppcheck warning #endif } else { for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { - float r = original->r (i, j); - float g = original->g (i, j); - float b = original->b (i, j); + float r = original->r(i, j); + float g = original->g(i, j); + float b = original->b(i, j); int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b); histogram[y]++; @@ -488,27 +498,23 @@ void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const Pro } } + // Copyright (c) 2012 Jacques Desmis -void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pwb, LabImage* lab, const ProcParams* params, - const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2, const ColorAppearance & customColCurve3, - LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, float &d, float &dj, float &yb, int rtt, - bool showSharpMask) + +void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb, LabImage* lab, const ProcParams* params, + const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2, const ColorAppearance & customColCurve3, + LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, float &d, float &dj, float &yb, int rtt, + bool showSharpMask) { if (params->colorappearance.enabled) { - -#ifdef _DEBUG - MyTime t1e, t2e; - t1e.set(); -#endif - //preparate for histograms CIECAM LUTu hist16JCAM; LUTu hist16_CCAM; if (pW != 1 && params->colorappearance.datacie) { //only with improccoordinator - hist16JCAM (32768); + hist16JCAM(32768); hist16JCAM.clear(); - hist16_CCAM (48000); + hist16_CCAM(48000); hist16_CCAM.clear(); } @@ -527,13 +533,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw double Xwsc, Zwsc; const bool epdEnabled = params->epd.enabled; - bool ciedata = (params->colorappearance.datacie && pW != 1) && ! ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + bool ciedata = (params->colorappearance.datacie && pW != 1) && !((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) - || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); + || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); - ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB - ColorTemp::temp2mulxyz (params->colorappearance.tempout, "Custom", Xwout, Zwout); - ColorTemp::temp2mulxyz (params->colorappearance.tempsc, "Custom", Xwsc, Zwsc); + ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB + ColorTemp::temp2mulxyz(params->colorappearance.tempout, "Custom", Xwout, Zwout); + ColorTemp::temp2mulxyz(params->colorappearance.tempsc, "Custom", Xwsc, Zwsc); //viewing condition for surrsrc if (params->colorappearance.surrsrc == "Average") { @@ -581,7 +587,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw } */ //with which algorithm - if (params->colorappearance.algo == "JC") { + if (params->colorappearance.algo == "JC") { alg = 0; } else if (params->colorappearance.algo == "JS") { alg = 1; @@ -677,6 +683,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw const float deg = (params->colorappearance.degree) / 100.0f; const float pilot = params->colorappearance.autodegree ? 2.0f : deg; + const float degout = (params->colorappearance.degreeout) / 100.0f; const float pilotout = params->colorappearance.autodegreeout ? 2.0f : degout; @@ -751,19 +758,19 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw if ((needJ && CAMBrightCurveJ.dirty) || (needQ && CAMBrightCurveQ.dirty) || (std::isnan(mean) && settings->viewinggreySc != 0)) { if (needJ) { - hist16J (32768); + hist16J(32768); hist16J.clear(); } if (needQ) { - hist16Q (32768); + hist16Q(32768); hist16Q.clear(); } double sum = 0.0; // use double precision for large summations #ifdef _OPENMP - const int numThreads = min (max (width * height / 65536, 1), omp_get_max_threads()); + const int numThreads = min(max(width * height / 65536, 1), omp_get_max_threads()); #pragma omp parallel num_threads(numThreads) if(numThreads>1) #endif { @@ -771,12 +778,12 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw LUTu hist16Qthr; if (needJ) { - hist16Jthr (hist16J.getSize()); + hist16Jthr(hist16J.getSize()); hist16Jthr.clear(); } if (needQ) { - hist16Qthr (hist16Q.getSize()); + hist16Qthr(hist16Q.getSize()); hist16Qthr.clear(); } @@ -825,7 +832,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw } if (needJ) { - hist16Jthr[ (int) ((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J + hist16Jthr[(int)((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J } //estimation of wh only with La @@ -841,7 +848,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw } */ if (needQ) { - hist16Qthr[CLIP ((int) (32768.f * sqrt ((koef * (lab->L[i][j])) / 32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L + hist16Qthr[CLIP((int)(32768.f * sqrt((koef * (lab->L[i][j])) / 32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L //perhaps needs to introduce whestim ?? //hist16Qthr[ (int) (sqrtf ((koef * (lab->L[i][j])) * 32768.f))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L } @@ -882,7 +889,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // if (settings->viewinggreySc == 0) { //auto if (params->colorappearance.autoybscen && pwb == 2) {//auto - if (mean < 15.f) { + if (mean < 15.f) { yb = 3.0f; } else if (mean < 30.f) { yb = 5.0f; @@ -908,7 +915,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // } else if (settings->viewinggreySc == 1) { } else { - yb = (float) params->colorappearance.ybscen; + yb = (float) params->colorappearance.ybscen; } const bool highlight = params->toneCurve.hrenabled; //Get the value if "highlight reconstruction" is activated @@ -948,33 +955,33 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw Ciecam02::initcam1float (yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); //printf ("wh=%f \n", wh); - const float pow1 = pow_F ( 1.64f - pow_F ( 0.29f, n ), 0.73f ); + const float pow1 = pow_F(1.64f - pow_F(0.29f, n), 0.73f); float nj, nbbj, ncbj, czj, awj, flj; Ciecam02::initcam2float (yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj); #ifdef __SSE2__ const float reccmcz = 1.f / (c2 * czj); #endif - const float pow1n = pow_F ( 1.64f - pow_F ( 0.29f, nj ), 0.73f ); + const float pow1n = pow_F(1.64f - pow_F(0.29f, nj), 0.73f); const float epsil = 0.0001f; const float coefQ = 32767.f / wh; const float a_w = aw; const float c_ = c; const float f_l = fl; - const float coe = pow_F (fl, 0.25f); - const float QproFactor = ( 0.4f / c ) * ( aw + 4.0f ) ; - const bool LabPassOne = ! ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) - || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) - || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); + const float coe = pow_F(fl, 0.25f); + const float QproFactor = (0.4f / c) * (aw + 4.0f) ; + const bool LabPassOne = !((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) + || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); //printf("coQ=%f\n", coefQ); if (needJ) { if (!CAMBrightCurveJ) { - CAMBrightCurveJ (32768, LUT_CLIP_ABOVE); + CAMBrightCurveJ(32768, LUT_CLIP_ABOVE); } if (CAMBrightCurveJ.dirty) { - Ciecam02::curveJfloat (params->colorappearance.jlight, params->colorappearance.contrast, hist16J, CAMBrightCurveJ);//lightness and contrast J + Ciecam02::curveJfloat(params->colorappearance.jlight, params->colorappearance.contrast, hist16J, CAMBrightCurveJ); //lightness and contrast J CAMBrightCurveJ /= 327.68f; CAMBrightCurveJ.dirty = false; } @@ -982,11 +989,11 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw if (needQ) { if (!CAMBrightCurveQ) { - CAMBrightCurveQ (32768, LUT_CLIP_ABOVE); + CAMBrightCurveQ(32768, LUT_CLIP_ABOVE); } if (CAMBrightCurveQ.dirty) { - Ciecam02::curveJfloat (params->colorappearance.qbright, params->colorappearance.qcontrast, hist16Q, CAMBrightCurveQ);//brightness and contrast Q + Ciecam02::curveJfloat(params->colorappearance.qbright, params->colorappearance.qcontrast, hist16Q, CAMBrightCurveQ); //brightness and contrast Q // CAMBrightCurveQ /= coefQ; CAMBrightCurveQ.dirty = false; } @@ -1004,10 +1011,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw #ifdef __SSE2__ int bufferLength = ((width + 3) / 4) * 4; // bufferLength has to be a multiple of 4 #endif -#ifndef _DEBUG #ifdef _OPENMP #pragma omp parallel -#endif #endif { float minQThr = 10000.f; @@ -1021,10 +1026,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float Mbuffer[bufferLength] ALIGNED16; float sbuffer[bufferLength] ALIGNED16; #endif -#ifndef _DEBUG #ifdef _OPENMP #pragma omp for schedule(dynamic, 16) -#endif #endif for (int i = 0; i < height; i++) { @@ -1034,24 +1037,24 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw vfloat x, y, z; vfloat J, C, h, Q, M, s; - vfloat c655d35 = F2V (655.35f); + vfloat c655d35 = F2V(655.35f); for (k = 0; k < width - 3; k += 4) { - Color::Lab2XYZ (LVFU (lab->L[i][k]), LVFU (lab->a[i][k]), LVFU (lab->b[i][k]), x, y, z); + Color::Lab2XYZ(LVFU(lab->L[i][k]), LVFU(lab->a[i][k]), LVFU(lab->b[i][k]), x, y, z); x = x / c655d35; y = y / c655d35; z = z / c655d35; - Ciecam02::xyz2jchqms_ciecam02float ( J, C, h, - Q, M, s, F2V (aw), F2V (fl), F2V (wh), - x, y, z, - F2V (xw1), F2V (yw1), F2V (zw1), - F2V (c), F2V (nc), F2V (pow1), F2V (nbb), F2V (ncb), F2V (pfl), F2V (cz), F2V (d)); - STVF (Jbuffer[k], J); - STVF (Cbuffer[k], C); - STVF (hbuffer[k], h); - STVF (Qbuffer[k], Q); - STVF (Mbuffer[k], M); - STVF (sbuffer[k], s); + Ciecam02::xyz2jchqms_ciecam02float(J, C, h, + Q, M, s, F2V(aw), F2V(fl), F2V(wh), + x, y, z, + F2V(xw1), F2V(yw1), F2V(zw1), + F2V(c), F2V(nc), F2V(pow1), F2V(nbb), F2V(ncb), F2V(pfl), F2V(cz), F2V(d)); + STVF(Jbuffer[k], J); + STVF(Cbuffer[k], C); + STVF(hbuffer[k], h); + STVF(Qbuffer[k], Q); + STVF(Mbuffer[k], M); + STVF(sbuffer[k], s); } for (; k < width; k++) { @@ -1060,15 +1063,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float b = lab->b[i][k]; float x, y, z; //convert Lab => XYZ - Color::Lab2XYZ (L, a, b, x, y, z); + Color::Lab2XYZ(L, a, b, x, y, z); x = x / 655.35f; y = y / 655.35f; z = z / 655.35f; float J, C, h, Q, M, s; - Ciecam02::xyz2jchqms_ciecam02float ( J, C, h, - Q, M, s, aw, fl, wh, - x, y, z, - xw1, yw1, zw1, + Ciecam02::xyz2jchqms_ciecam02float(J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, c, nc, pow1, nbb, ncb, pfl, cz, d); Jbuffer[k] = J; Cbuffer[k] = C; @@ -1098,15 +1101,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float b = lab->b[i][j]; float x1, y1, z1; //convert Lab => XYZ - Color::Lab2XYZ (L, a, b, x1, y1, z1); + Color::Lab2XYZ(L, a, b, x1, y1, z1); x = (float)x1 / 655.35f; y = (float)y1 / 655.35f; z = (float)z1 / 655.35f; //process source==> normal - Ciecam02::xyz2jchqms_ciecam02float ( J, C, h, - Q, M, s, aw, fl, wh, - x, y, z, - xw1, yw1, zw1, + Ciecam02::xyz2jchqms_ciecam02float(J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, c, nc, pow1, nbb, ncb, pfl, cz, d); #endif float Jpro, Cpro, hpro, Qpro, Mpro, spro; @@ -1120,77 +1123,77 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // we cannot have all algorithms with all chroma curves if (alg == 0) { Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast - Qpro = QproFactor * sqrtf (Jpro); + Qpro = QproFactor * sqrtf(Jpro); float Cp = (spro * spro * Qpro) / (1000000.f); Cpro = Cp * 100.f; float sres; - Ciecam02::curvecolorfloat (chr, Cp, sres, 1.8f); - Color::skinredfloat (Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); + Ciecam02::curvecolorfloat(chr, Cp, sres, 1.8f); + Color::skinredfloat(Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); } else if (alg == 1) { // Lightness saturation Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast float sres; float Sp = spro / 100.0f; float parsat = 1.5f; //parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation) - Ciecam02::curvecolorfloat (schr, Sp, sres, parsat); + Ciecam02::curvecolorfloat(schr, Sp, sres, parsat); float dred = 100.f; // in C mode float protect_red = 80.0f; // in C mode - dred = 100.0f * sqrtf ((dred * coe) / Qpro); - protect_red = 100.0f * sqrtf ((protect_red * coe) / Qpro); - Color::skinredfloat (Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); - Qpro = QproFactor * sqrtf (Jpro); + dred = 100.0f * sqrtf((dred * coe) / Qpro); + protect_red = 100.0f * sqrtf((protect_red * coe) / Qpro); + Color::skinredfloat(Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); + Qpro = QproFactor * sqrtf(Jpro); Cpro = (spro * spro * Qpro) / (10000.0f); } else if (alg == 2) { //printf("Qp0=%f ", Qpro); - Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)] / coefQ; //brightness and contrast + Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)] / coefQ; //brightness and contrast //printf("Qpaf=%f ", Qpro); float Mp, sres; Mp = Mpro / 100.0f; - Ciecam02::curvecolorfloat (mchr, Mp, sres, 2.5f); + Ciecam02::curvecolorfloat(mchr, Mp, sres, 2.5f); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; //M mode - Color::skinredfloat (Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); - Jpro = SQR ((10.f * Qpro) / wh); + Color::skinredfloat(Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); + Jpro = SQR((10.f * Qpro) / wh); Cpro = Mpro / coe; Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero - spro = 100.0f * sqrtf ( Mpro / Qpro ); + spro = 100.0f * sqrtf(Mpro / Qpro); } else { /*if(alg == 3) */ - Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)] / coefQ; //brightness and contrast + Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)] / coefQ; //brightness and contrast float Mp, sres; Mp = Mpro / 100.0f; - Ciecam02::curvecolorfloat (mchr, Mp, sres, 2.5f); + Ciecam02::curvecolorfloat(mchr, Mp, sres, 2.5f); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; //M mode - Color::skinredfloat (Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); - Jpro = SQR ((10.f * Qpro) / wh); + Color::skinredfloat(Jpro, hpro, sres, Mp, dred, protect_red, 0, rstprotection, 100.f, Mpro); + Jpro = SQR((10.f * Qpro) / wh); Cpro = Mpro / coe; Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero - spro = 100.0f * sqrtf ( Mpro / Qpro ); + spro = 100.0f * sqrtf(Mpro / Qpro); if (Jpro > 99.9f) { Jpro = 99.9f; } - Jpro = CAMBrightCurveJ[ (float) (Jpro * 327.68f)]; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[(float)(Jpro * 327.68f)]; //lightness CIECAM02 + contrast float Sp = spro / 100.0f; - Ciecam02::curvecolorfloat (schr, Sp, sres, 1.5f); + Ciecam02::curvecolorfloat(schr, Sp, sres, 1.5f); dred = 100.f; // in C mode protect_red = 80.0f; // in C mode - dred = 100.0f * sqrtf ((dred * coe) / Q); - protect_red = 100.0f * sqrtf ((protect_red * coe) / Q); - Color::skinredfloat (Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); - Qpro = QproFactor * sqrtf (Jpro); + dred = 100.0f * sqrtf((dred * coe) / Q); + protect_red = 100.0f * sqrtf((protect_red * coe) / Q); + Color::skinredfloat(Jpro, hpro, sres, Sp, dred, protect_red, 0, rstprotection, 100.f, spro); + Qpro = QproFactor * sqrtf(Jpro); float Cp = (spro * spro * Qpro) / (1000000.f); Cpro = Cp * 100.f; - Ciecam02::curvecolorfloat (chr, Cp, sres, 1.8f); - Color::skinredfloat (Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); + Ciecam02::curvecolorfloat(chr, Cp, sres, 1.8f); + Color::skinredfloat(Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); // disabled this code, Issue 2690 // if(Jpro < 1.f && Cpro > 12.f) Cpro=12.f;//reduce artifacts by "pseudo gamut control CIECAM" // else if(Jpro < 2.f && Cpro > 15.f) Cpro=15.f; @@ -1198,7 +1201,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // else if(Jpro < 7.f && Cpro > 50.f) Cpro=50.f; hpro = hpro + hue; - if ( hpro < 0.0f ) { + if (hpro < 0.0f) { hpro += 360.0f; //hue } } @@ -1210,15 +1213,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float Jold100 = (float) Jpro; float redu = 25.f; float reduc = 1.f; - const Lightcurve& userColCurveJ1 = static_cast (customColCurve1); - userColCurveJ1.Apply (Jj); + const Lightcurve& userColCurveJ1 = static_cast(customColCurve1); + userColCurveJ1.Apply(Jj); if (Jj > Jold) { if (Jj < 65535.f) { if (Jold < 327.68f * redu) { Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility } else { - reduc = LIM ((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } @@ -1228,7 +1231,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } - Jpro = (float) (Jj / 327.68f); + Jpro = (float)(Jj / 327.68f); if (Jpro < 1.f) { Jpro = 1.f; @@ -1244,15 +1247,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float redu = 20.f; float reduc = 1.f; - const Brightcurve& userColCurveB1 = static_cast (customColCurve1); - userColCurveB1.Apply (Qq); + const Brightcurve& userColCurveB1 = static_cast(customColCurve1); + userColCurveB1.Apply(Qq); if (Qq > Qold) { if (Qq < 65535.f) { if (Qold < 327.68f * redu) { Qq = 0.25f * (Qq - Qold) + Qold; //divide sensibility } else { - reduc = LIM ((100.f - Qold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM((100.f - Qold100) / (100.f - redu), 0.f, 1.f); Qq = 0.25f * reduc * (Qq - Qold) + Qold; //reduct sensibility in highlights } } @@ -1282,15 +1285,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float Jold100 = (float) Jpro; float redu = 25.f; float reduc = 1.f; - const Lightcurve& userColCurveJ2 = static_cast (customColCurve2); - userColCurveJ2.Apply (Jj); + const Lightcurve& userColCurveJ2 = static_cast(customColCurve2); + userColCurveJ2.Apply(Jj); if (Jj > Jold) { if (Jj < 65535.f) { if (Jold < 327.68f * redu) { Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility } else { - reduc = LIM ((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } @@ -1308,7 +1311,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw } } - Jpro = (float) (Jj / 327.68f); + Jpro = (float)(Jj / 327.68f); if (Jpro < 1.f) { Jpro = 1.f; @@ -1325,15 +1328,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float redu = 20.f; float reduc = 1.f; - const Brightcurve& userColCurveB2 = static_cast (customColCurve2); - userColCurveB2.Apply (Qq); + const Brightcurve& userColCurveB2 = static_cast(customColCurve2); + userColCurveB2.Apply(Qq); if (Qq > Qold) { if (Qq < 65535.f) { if (Qold < 327.68f * redu) { Qq = 0.25f * (Qq - Qold) + Qold; //divide sensibility } else { - reduc = LIM ((100.f - Qold100) / (100.f - redu), 0.f, 1.f); + reduc = LIM((100.f - Qold100) / (100.f - redu), 0.f, 1.f); Qq = 0.25f * reduc * (Qq - Qold) + Qold; //reduct sensibility in highlights } } @@ -1354,10 +1357,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw coef = 2.f; //adapt Q to J approximation Qq = (float) Qpro * coef; Qold = Qq; - const Lightcurve& userColCurveJ1 = static_cast (customColCurve1); - userColCurveJ1.Apply (Qq); + const Lightcurve& userColCurveJ1 = static_cast(customColCurve1); + userColCurveJ1.Apply(Qq); Qq = 0.05f * (Qq - Qold) + Qold; //approximative adaptation - Qpro = (float) (Qq / coef); + Qpro = (float)(Qq / coef); Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f)); } @@ -1373,13 +1376,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float coef = 327.68f / parsat; float Cc = (float) Cpro * coef; float Ccold = Cc; - const Chromacurve& userColCurve = static_cast (customColCurve3); - userColCurve.Apply (Cc); + const Chromacurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Cc); float dred = 55.f; float protect_red = 30.0f; int sk = 1; float ko = 1.f / coef; - Color::skinredfloat (Jpro, hpro, Cc, Ccold, dred, protect_red, sk, rstprotection, ko, Cpro); + Color::skinredfloat(Jpro, hpro, Cc, Ccold, dred, protect_red, sk, rstprotection, ko, Cpro); /* if(Jpro < 1.f && Cpro > 12.f) { Cpro = 12.f; //reduce artifacts by "pseudo gamut control CIECAM" @@ -1396,32 +1399,32 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float coef = 327.68f / parsat; float Ss = (float) spro * coef; float Sold = Ss; - const Saturcurve& userColCurve = static_cast (customColCurve3); - userColCurve.Apply (Ss); + const Saturcurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Ss); Ss = 0.6f * (Ss - Sold) + Sold; //divide sensibility saturation float dred = 100.f; // in C mode float protect_red = 80.0f; // in C mode - dred = 100.0f * sqrtf ((dred * coe) / Qpro); - protect_red = 100.0f * sqrtf ((protect_red * coe) / Qpro); + dred = 100.0f * sqrtf((dred * coe) / Qpro); + protect_red = 100.0f * sqrtf((protect_red * coe) / Qpro); int sk = 0; float ko = 1.f / coef; - Color::skinredfloat (Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); - Qpro = ( 4.0f / c ) * sqrtf ( Jpro / 100.0f ) * ( aw + 4.0f ) ; + Color::skinredfloat(Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); + Qpro = (4.0f / c) * sqrtf(Jpro / 100.0f) * (aw + 4.0f) ; Cpro = (spro * spro * Qpro) / (10000.0f); } else if (curveMode3 == ColorAppearanceParams::CtcMode::COLORF) { // float parsat = 0.8f; //0.68; float coef = 327.68f / parsat; float Mm = (float) Mpro * coef; float Mold = Mm; - const Colorfcurve& userColCurve = static_cast (customColCurve3); - userColCurve.Apply (Mm); + const Colorfcurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Mm); float dred = 100.f; //in C mode float protect_red = 80.0f; // in C mode dred *= coe; //in M mode protect_red *= coe; int sk = 0; float ko = 1.f / coef; - Color::skinredfloat (Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); + Color::skinredfloat(Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); /* if(Jpro < 1.f && Mpro > 12.f * coe) { Mpro = 12.f * coe; //reduce artifacts by "pseudo gamut control CIECAM" @@ -1454,7 +1457,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw ncie->J_p[i][j] = (float)J + epsil; ncie->h_p[i][j] = (float)h; ncie->C_p[i][j] = (float)C + epsil; - ncie->sh_p[i][j] = (float) 3276.8f * (sqrtf ( J ) ) ; + ncie->sh_p[i][j] = (float) 3276.8f * (sqrtf(J)) ; if (epdEnabled) { if (ncie->Q_p[i][j] < minQThr) { @@ -1486,7 +1489,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw libr = J; //327 for J } - posl = (int) (libr * brli); + posl = (int)(libr * brli); hist16JCAM[posl]++; if (curveMode3 == ColorAppearanceParams::CtcMode::CHROMA) { @@ -1500,7 +1503,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw colch = M; } - posc = (int) (colch * chsacol); + posc = (int)(colch * chsacol); hist16_CCAM[posc]++; } @@ -1515,9 +1518,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float xx, yy, zz; //process normal==> viewing - Ciecam02::jch2xyz_ciecam02float ( xx, yy, zz, - J, C, h, - xw2, yw2, zw2, + Ciecam02::jch2xyz_ciecam02float(xx, yy, zz, + J, C, h, + xw2, yw2, zw2, c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj); float x, y, z; x = xx * 655.35f; @@ -1525,13 +1528,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw z = zz * 655.35f; float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab (x, y, z, Ll, aa, bb); + Color::XYZ2Lab(x, y, z, Ll, aa, bb); // gamut control in Lab mode; I must study how to do with cIECAM only if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; + Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; float2 sincosval; if (Chprov1 == 0.0f) { @@ -1543,16 +1546,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw } -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); -#endif - + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; lab->b[i][j] = 327.68f * Chprov1 * sincosval.x; @@ -1575,13 +1570,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float *zbuffer = sbuffer; for (k = 0; k < bufferLength; k += 4) { - Ciecam02::jch2xyz_ciecam02float ( x, y, z, - LVF (Jbuffer[k]), LVF (Cbuffer[k]), LVF (hbuffer[k]), - F2V (xw2), F2V (yw2), F2V (zw2), - F2V (nc2), F2V (pow1n), F2V (nbbj), F2V (ncbj), F2V (flj), F2V (dj), F2V (awj), F2V (reccmcz)); - STVF (xbuffer[k], x * c655d35); - STVF (ybuffer[k], y * c655d35); - STVF (zbuffer[k], z * c655d35); + Ciecam02::jch2xyz_ciecam02float(x, y, z, + LVF(Jbuffer[k]), LVF(Cbuffer[k]), LVF(hbuffer[k]), + F2V(xw2), F2V(yw2), F2V(zw2), + F2V(nc2), F2V(pow1n), F2V(nbbj), F2V(ncbj), F2V(flj), F2V(dj), F2V(awj), F2V(reccmcz)); + STVF(xbuffer[k], x * c655d35); + STVF(ybuffer[k], y * c655d35); + STVF(zbuffer[k], z * c655d35); } // XYZ2Lab uses a lookup table. The function behind that lut is a cube root. @@ -1589,13 +1584,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw for (int j = 0; j < width; j++) { float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab (xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); + Color::XYZ2Lab(xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); // gamut control in Lab mode; I must study how to do with cIECAM only if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; + Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; float2 sincosval; if (Chprov1 == 0.0f) { @@ -1606,15 +1601,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw sincosval.x = bb / (Chprov1 * 327.68f); } -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); -#endif + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; lab->b[i][j] = 327.68f * Chprov1 * sincosval.x; @@ -1647,26 +1635,16 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw if (ciedata) { //update histogram J - hist16JCAM.compressTo (histLCAM); + hist16JCAM.compressTo(histLCAM); //update histogram C - hist16_CCAM.compressTo (histCCAM); + hist16_CCAM.compressTo(histCCAM); } } -#ifdef _DEBUG - - if (settings->verbose) { - t2e.set(); - printf ("CIECAM02 performed in %d usec:\n", t2e.etime (t1e)); - // printf("minc=%f maxc=%f minj=%f maxj=%f\n",minc,maxc,minj,maxj); - } - -#endif - if (settings->autocielab) { if ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) - || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { + || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { @@ -1722,9 +1700,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // else if(params->dirpyrequalizer.algo=="LA") choice=1; if (rtt == 1) { - float b_l = static_cast (params->dirpyrequalizer.hueskin.getBottomLeft()) / 100.0f; - float t_l = static_cast (params->dirpyrequalizer.hueskin.getTopLeft()) / 100.0f; - float t_r = static_cast (params->dirpyrequalizer.hueskin.getTopRight()) / 100.0f; + float b_l = static_cast(params->dirpyrequalizer.hueskin.getBottomLeft()) / 100.0f; + float t_l = static_cast(params->dirpyrequalizer.hueskin.getTopLeft()) / 100.0f; + float t_r = static_cast(params->dirpyrequalizer.hueskin.getTopRight()) / 100.0f; lab->deleteLab(); dirpyr_equalizercam (ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, b_l, t_l, t_r, scale); //contrast by detail adapted to CIECAM lab->reallocLab(); @@ -1738,26 +1716,21 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw */ } - const float Qredi = ( 4.0f / c_) * ( a_w + 4.0f ); - const float co_e = (pow_F (f_l, 0.25f)); + const float Qredi = (4.0f / c_) * (a_w + 4.0f); + const float co_e = (pow_F(f_l, 0.25f)); -#ifndef _DEBUG #ifdef _OPENMP #pragma omp parallel -#endif #endif { -#ifndef _DEBUG #ifdef _OPENMP #pragma omp for schedule(dynamic, 10) #endif -#endif - for (int i = 0; i < height; i++) // update CieImages with new values after sharpening, defringe, contrast by detail level for (int j = 0; j < width; j++) { - float interm = fabsf (ncie->sh_p[i][j] / (32768.f)); - ncie->J_p[i][j] = 100.0f * SQR (interm); + float interm = fabsf(ncie->sh_p[i][j] / (32768.f)); + ncie->J_p[i][j] = 100.0f * SQR(interm); ncie->Q_p[i][j] = interm * Qredi; ncie->M_p[i][j] = ncie->C_p[i][j] * co_e; } @@ -1767,7 +1740,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw if ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) - || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { + || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { ciedata = (params->colorappearance.datacie && pW != 1); @@ -1781,12 +1754,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw constexpr float eps = 0.0001f; - const float co_e = (pow_F (f_l, 0.25f)) + eps; + const float co_e = (pow_F(f_l, 0.25f)) + eps; -#ifndef _DEBUG #ifdef _OPENMP #pragma omp parallel -#endif #endif { #ifdef __SSE2__ @@ -1799,10 +1770,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw float *zbuffer = hbuffer; // " #endif -#ifndef _DEBUG #ifdef _OPENMP #pragma omp for schedule(dynamic, 10) -#endif #endif for (int i = 0; i < height; i++) { // update CIECAM with new values after tone-mapping @@ -1810,7 +1779,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // 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) { - ncie->J_p[i][j] = (100.0f * ncie->Q_p[i][j] * ncie->Q_p[i][j]) / SQR ((4.f / c) * (aw + 4.f)); + ncie->J_p[i][j] = (100.0f * ncie->Q_p[i][j] * ncie->Q_p[i][j]) / SQR((4.f / c) * (aw + 4.f)); } const float ncie_C_p = (ncie->M_p[i][j]) / co_e; @@ -1832,7 +1801,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw libr = ncie->J_p[i][j]; //327 for J } - posl = (int) (libr * brli); + posl = (int)(libr * brli); hist16JCAM[posl]++; if (curveMode3 == ColorAppearanceParams::CtcMode::CHROMA) { @@ -1840,13 +1809,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw colch = ncie_C_p; } else if (curveMode3 == ColorAppearanceParams::CtcMode::SATUR) { chsacol = 450.0f; - colch = 100.f * sqrtf (ncie_C_p / ncie->Q_p[i][j]); + colch = 100.f * sqrtf(ncie_C_p / ncie->Q_p[i][j]); } else { /*if(curveMode3 == ColorAppearanceParams::CTCMode::COLORF)*/ chsacol = 400.f;//327.0f; colch = ncie->M_p[i][j]; } - posc = (int) (colch * chsacol); + posc = (int)(colch * chsacol); hist16_CCAM[posc]++; } @@ -1858,21 +1827,21 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw hbuffer[j] = ncie->h_p[i][j]; #else float xx, yy, zz; - Ciecam02::jch2xyz_ciecam02float ( xx, yy, zz, - ncie->J_p[i][j], ncie_C_p, ncie->h_p[i][j], - xw2, yw2, zw2, + Ciecam02::jch2xyz_ciecam02float(xx, yy, zz, + ncie->J_p[i][j], ncie_C_p, ncie->h_p[i][j], + xw2, yw2, zw2, c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj); float x = (float)xx * 655.35f; float y = (float)yy * 655.35f; float z = (float)zz * 655.35f; float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab (x, y, z, Ll, aa, bb); + Color::XYZ2Lab(x, y, z, Ll, aa, bb); if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; + Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; float2 sincosval; if (Chprov1 == 0.0f) { @@ -1884,15 +1853,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw } -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); -#endif + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; @@ -1910,19 +1872,19 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw // process line buffers int k; vfloat x, y, z; - vfloat c655d35 = F2V (655.35f); + vfloat c655d35 = F2V(655.35f); for (k = 0; k < bufferLength; k += 4) { - Ciecam02::jch2xyz_ciecam02float ( x, y, z, - LVF (Jbuffer[k]), LVF (Cbuffer[k]), LVF (hbuffer[k]), - F2V (xw2), F2V (yw2), F2V (zw2), - F2V (nc2), F2V (pow1n), F2V (nbbj), F2V (ncbj), F2V (flj), F2V (dj), F2V (awj), F2V (reccmcz)); + Ciecam02::jch2xyz_ciecam02float(x, y, z, + LVF(Jbuffer[k]), LVF(Cbuffer[k]), LVF(hbuffer[k]), + F2V(xw2), F2V(yw2), F2V(zw2), + F2V(nc2), F2V(pow1n), F2V(nbbj), F2V(ncbj), F2V(flj), F2V(dj), F2V(awj), F2V(reccmcz)); x *= c655d35; y *= c655d35; z *= c655d35; - STVF (xbuffer[k], x); - STVF (ybuffer[k], y); - STVF (zbuffer[k], z); + STVF(xbuffer[k], x); + STVF(ybuffer[k], y); + STVF(zbuffer[k], z); } // XYZ2Lab uses a lookup table. The function behind that lut is a cube root. @@ -1930,12 +1892,12 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw for (int j = 0; j < width; j++) { float Ll, aa, bb; //convert xyz=>lab - Color::XYZ2Lab (xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); + Color::XYZ2Lab(xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); if (gamu == 1) { float Lprov1, Chprov1; Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; + Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; float2 sincosval; if (Chprov1 == 0.0f) { @@ -1946,15 +1908,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw sincosval.x = bb / (Chprov1 * 327.68f); } -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); -#endif + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; lab->b[i][j] = 327.68f * Chprov1 * sincosval.x; @@ -1975,17 +1930,17 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw if (ciedata) { //update histogram J and Q //update histogram J - hist16JCAM.compressTo (histLCAM); + hist16JCAM.compressTo(histLCAM); //update color histogram M,s,C - hist16_CCAM.compressTo (histCCAM); + hist16_CCAM.compressTo(histCCAM); } } } } //end CIECAM -void ImProcFunctions::moyeqt (Imagefloat* working, float &moyS, float &eqty) +void ImProcFunctions::moyeqt(Imagefloat* working, float &moyS, float &eqty) { BENCHFUN @@ -2013,7 +1968,7 @@ void ImProcFunctions::moyeqt (Imagefloat* working, float &moyS, float &eqty) } static inline void -filmlike_clip_rgb_tone (float *r, float *g, float *b, const float L) +filmlike_clip_rgb_tone(float *r, float *g, float *b, const float L) { float r_ = *r > L ? L : *r; float b_ = *b > L ? L : *b; @@ -2024,18 +1979,18 @@ filmlike_clip_rgb_tone (float *r, float *g, float *b, const float L) } /*static*/ void -filmlike_clip (float *r, float *g, float *b) +filmlike_clip(float *r, float *g, float *b) { // This is Adobe's hue-stable film-like curve with a diagonal, ie only used for clipping. Can probably be further optimized. const float L = 65535.0; if (*r >= *g) { if (*g > *b) { // Case 1: r >= g > b - filmlike_clip_rgb_tone (r, g, b, L); + filmlike_clip_rgb_tone(r, g, b, L); } else if (*b > *r) { // Case 2: b > r >= g - filmlike_clip_rgb_tone (b, r, g, L); + filmlike_clip_rgb_tone(b, r, g, L); } else if (*b > *g) { // Case 3: r >= b > g - filmlike_clip_rgb_tone (r, b, g, L); + filmlike_clip_rgb_tone(r, b, g, L); } else { // Case 4: r >= g == b *r = *r > L ? L : *r; *g = *g > L ? L : *g; @@ -2043,11 +1998,11 @@ filmlike_clip (float *r, float *g, float *b) } } else { if (*r >= *b) { // Case 5: g > r >= b - filmlike_clip_rgb_tone (g, r, b, L); + filmlike_clip_rgb_tone(g, r, b, L); } else if (*b > *g) { // Case 6: b > g > r - filmlike_clip_rgb_tone (b, g, r, L); + filmlike_clip_rgb_tone(b, g, r, L); } else { // Case 7: g >= b > r - filmlike_clip_rgb_tone (g, b, r, L); + filmlike_clip_rgb_tone(g, b, r, L); } } } @@ -2087,7 +2042,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer EditUniqueID editID = pipetteBuffer ? pipetteBuffer->getEditID() : EUID_None; if (editID != EUID_None) { - switch (pipetteBuffer->getDataProvider()->getCurrSubscriber()->getPipetteBufferType()) { + switch (pipetteBuffer->getDataProvider()->getCurrSubscriber()->getPipetteBufferType()) { case (BT_IMAGEFLOAT): editImgFloat = pipetteBuffer->getImgFloatBuffer(); break; @@ -2119,7 +2074,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer static_cast(wprof[2][2] / static_cast(Color::D50z)) } }; - float maxFactorToxyz = max (toxyz[1][0], toxyz[1][1], toxyz[1][2]); + float maxFactorToxyz = max(toxyz[1][0], toxyz[1][1], toxyz[1][2]); float equalR = maxFactorToxyz / toxyz[1][0]; float equalG = maxFactorToxyz / toxyz[1][1]; float equalB = maxFactorToxyz / toxyz[1][2]; @@ -2138,7 +2093,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer }; bool mixchannels = params->chmixer.enabled && - (params->chmixer.red[0] != 100 || params->chmixer.red[1] != 0 || params->chmixer.red[2] != 0 || + (params->chmixer.red[0] != 100 || params->chmixer.red[1] != 0 || params->chmixer.red[2] != 0 || params->chmixer.green[0] != 0 || params->chmixer.green[1] != 100 || params->chmixer.green[2] != 0 || params->chmixer.blue[0] != 0 || params->chmixer.blue[1] != 0 || params->chmixer.blue[2] != 100); @@ -2147,10 +2102,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer FlatCurve* vCurve = nullptr; FlatCurve* bwlCurve = nullptr; - FlatCurveType hCurveType = (FlatCurveType)params->hsvequalizer.hcurve.at (0); - FlatCurveType sCurveType = (FlatCurveType)params->hsvequalizer.scurve.at (0); - FlatCurveType vCurveType = (FlatCurveType)params->hsvequalizer.vcurve.at (0); - FlatCurveType bwlCurveType = (FlatCurveType)params->blackwhite.luminanceCurve.at (0); + FlatCurveType hCurveType = (FlatCurveType)params->hsvequalizer.hcurve.at(0); + FlatCurveType sCurveType = (FlatCurveType)params->hsvequalizer.scurve.at(0); + FlatCurveType vCurveType = (FlatCurveType)params->hsvequalizer.vcurve.at(0); + FlatCurveType bwlCurveType = (FlatCurveType)params->blackwhite.luminanceCurve.at(0); bool hCurveEnabled = params->hsvequalizer.enabled && hCurveType > FCT_Linear; bool sCurveEnabled = params->hsvequalizer.enabled && sCurveType > FCT_Linear; bool vCurveEnabled = params->hsvequalizer.enabled && vCurveType > FCT_Linear; @@ -2158,7 +2113,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // TODO: We should create a 'skip' value like for CurveFactory::complexsgnCurve (rtengine/curves.cc) if (hCurveEnabled) { - hCurve = new FlatCurve (params->hsvequalizer.hcurve); + hCurve = new FlatCurve(params->hsvequalizer.hcurve); if (hCurve->isIdentity()) { delete hCurve; @@ -2168,7 +2123,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (sCurveEnabled) { - sCurve = new FlatCurve (params->hsvequalizer.scurve); + sCurve = new FlatCurve(params->hsvequalizer.scurve); if (sCurve->isIdentity()) { delete sCurve; @@ -2178,7 +2133,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (vCurveEnabled) { - vCurve = new FlatCurve (params->hsvequalizer.vcurve); + vCurve = new FlatCurve(params->hsvequalizer.vcurve); if (vCurve->isIdentity()) { delete vCurve; @@ -2188,7 +2143,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (bwlCurveEnabled) { - bwlCurve = new FlatCurve (params->blackwhite.luminanceCurve); + bwlCurve = new FlatCurve(params->blackwhite.luminanceCurve); if (bwlCurve->isIdentity()) { delete bwlCurve; @@ -2207,24 +2162,24 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer vfloat v_xyz2work[3][3] ALIGNED16; #endif - if ( params->filmSimulation.enabled && !params->filmSimulation.clutFilename.empty() ) { - hald_clut = CLUTStore::getInstance().getClut ( params->filmSimulation.clutFilename ); + if (params->filmSimulation.enabled && !params->filmSimulation.clutFilename.empty()) { + hald_clut = CLUTStore::getInstance().getClut(params->filmSimulation.clutFilename); - if ( hald_clut ) { + if (hald_clut) { clutAndWorkingProfilesAreSame = hald_clut->getProfile() == params->icm.workingProfile; - if ( !clutAndWorkingProfilesAreSame ) { - xyz2clut = ICCStore::getInstance()->workingSpaceInverseMatrix ( hald_clut->getProfile() ); - clut2xyz = ICCStore::getInstance()->workingSpaceMatrix ( hald_clut->getProfile() ); + if (!clutAndWorkingProfilesAreSame) { + xyz2clut = ICCStore::getInstance()->workingSpaceInverseMatrix(hald_clut->getProfile()); + clut2xyz = ICCStore::getInstance()->workingSpaceMatrix(hald_clut->getProfile()); #ifdef __SSE2__ for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - v_work2xyz[i][j] = F2V (wprof[i][j]); - v_xyz2clut[i][j] = F2V (xyz2clut[i][j]); - v_xyz2work[i][j] = F2V (wiprof[i][j]); - v_clut2xyz[i][j] = F2V (clut2xyz[i][j]); + v_work2xyz[i][j] = F2V(wprof[i][j]); + v_xyz2clut[i][j] = F2V(xyz2clut[i][j]); + v_xyz2work[i][j] = F2V(wiprof[i][j]); + v_clut2xyz[i][j] = F2V(clut2xyz[i][j]); } } @@ -2234,7 +2189,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } } - const float film_simulation_strength = static_cast (params->filmSimulation.strength) / 100.0f; + const float film_simulation_strength = static_cast(params->filmSimulation.strength) / 100.0f; const float exp_scale = pow(2.0, expcomp); const float comp = (max(0.0, expcomp) + 1.0) * hlcompr / 100.0; @@ -2340,7 +2295,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float mixerPurple = params->blackwhite.mixerPurple; int algm = 0; - if (params->blackwhite.method == "Desaturation") { + if (params->blackwhite.method == "Desaturation") { algm = 0; } else if (params->blackwhite.method == "LumEqualizer") { algm = 1; @@ -2379,7 +2334,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool hasgammabw = gammabwr != 1.f || gammabwg != 1.f || gammabwb != 1.f; if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled)) { - tmpImage = new Imagefloat (working->getWidth(), working->getHeight()); + tmpImage = new Imagefloat(working->getWidth(), working->getHeight()); } // For tonecurve histogram @@ -2388,11 +2343,11 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (toneCurveHistSize > 0) { histToneCurve.clear(); - histToneCurveCompression = log2 (65536 / toneCurveHistSize); + histToneCurveCompression = log2(65536 / toneCurveHistSize); } // For tonecurve histogram - const float lumimulf[3] = {static_cast (lumimul[0]), static_cast (lumimul[1]), static_cast (lumimul[2])}; + const float lumimulf[3] = {static_cast(lumimul[0]), static_cast(lumimul[1]), static_cast(lumimul[2])}; #define TS 112 @@ -2401,11 +2356,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #pragma omp parallel if (multiThread) #endif { - size_t perChannelSizeBytes = padToAlignment(sizeof (float) * TS * TS + 4 * 64); + size_t perChannelSizeBytes = padToAlignment(sizeof(float) * TS * TS + 4 * 64); AlignedBuffer buffer(3 * perChannelSizeBytes); char *editIFloatBuffer = nullptr; char *editWhateverBuffer = nullptr; - float *rtemp = buffer.data; float *gtemp = &rtemp[perChannelSizeBytes / sizeof(float)]; float *btemp = >emp[perChannelSizeBytes / sizeof(float)]; @@ -2421,17 +2375,17 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float *editIFloatTmpR = nullptr, *editIFloatTmpG = nullptr, *editIFloatTmpB = nullptr, *editWhateverTmp = nullptr; if (editImgFloat) { - editIFloatBuffer = (char *) malloc (3 * sizeof (float) * TS * TS + 20 * 64 + 63); - char *data = (char*) ( ( uintptr_t (editIFloatBuffer) + uintptr_t (63)) / 64 * 64); + editIFloatBuffer = (char *) malloc(3 * sizeof(float) * TS * TS + 20 * 64 + 63); + char *data = (char*)((uintptr_t (editIFloatBuffer) + uintptr_t (63)) / 64 * 64); editIFloatTmpR = (float (*))data; - editIFloatTmpG = (float (*)) ((char*)editIFloatTmpR + sizeof (float) * TS * TS + 4 * 64); - editIFloatTmpB = (float (*)) ((char*)editIFloatTmpG + sizeof (float) * TS * TS + 8 * 64); + editIFloatTmpG = (float (*))((char*)editIFloatTmpR + sizeof(float) * TS * TS + 4 * 64); + editIFloatTmpB = (float (*))((char*)editIFloatTmpG + sizeof(float) * TS * TS + 8 * 64); } if (editWhatever) { - editWhateverBuffer = (char *) malloc (sizeof (float) * TS * TS + 20 * 64 + 63); - char *data = (char*) ( ( uintptr_t (editWhateverBuffer) + uintptr_t (63)) / 64 * 64); + editWhateverBuffer = (char *) malloc(sizeof(float) * TS * TS + 20 * 64 + 63); + char *data = (char*)((uintptr_t (editWhateverBuffer) + uintptr_t (63)) / 64 * 64); editWhateverTmp = (float (*))data; } @@ -2444,7 +2398,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer LUTu histToneCurveThr; if (toneCurveHistSize > 0) { - histToneCurveThr (toneCurveHistSize); + histToneCurveThr(toneCurveHistSize); histToneCurveThr.clear(); } @@ -2456,15 +2410,15 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int jj = 0; jj < working->getWidth(); jj += TS) { istart = ii; jstart = jj; - tH = min (ii + TS, working->getHeight()); - tW = min (jj + TS, working->getWidth()); + tH = min(ii + TS, working->getHeight()); + tW = min(jj + TS, working->getWidth()); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - rtemp[ti * TS + tj] = working->r (i, j); - gtemp[ti * TS + tj] = working->g (i, j); - btemp[ti * TS + tj] = working->b (i, j); + rtemp[ti * TS + tj] = working->r(i, j); + gtemp[ti * TS + tj] = working->g(i, j); + btemp[ti * TS + tj] = working->b(i, j); } } @@ -2493,7 +2447,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (dcpProf) { - dcpProf->step2ApplyTile (rtemp, gtemp, btemp, tW - jstart, tH - istart, TS, asIn); + dcpProf->step2ApplyTile(rtemp, gtemp, btemp, tW - jstart, tH - istart, TS, asIn); } if (params->toneCurve.clampOOG) { @@ -2507,11 +2461,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (OOG(r) || OOG(g) || OOG(b)) { filmlike_clip(&r, &g, &b); } + rtemp[ti * TS + tj] = r; gtemp[ti * TS + tj] = g; btemp[ti * TS + tj] = b; } } + } if (histToneCurveThr) { @@ -2542,11 +2498,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer STVF(tmpr[0], tonecurve(LVF(rtemp[ti * TS + tj]))); STVF(tmpg[0], tonecurve(LVF(gtemp[ti * TS + tj]))); STVF(tmpb[0], tonecurve(LVF(btemp[ti * TS + tj]))); + for (int k = 0; k < 4; ++k) { setUnlessOOG(rtemp[ti * TS + tj + k], gtemp[ti * TS + tj + k], btemp[ti * TS + tj + k], tmpr[k], tmpg[k], tmpb[k]); } } + #endif + for (; j < tW; j++, tj++) { //brightness/contrast setUnlessOOG(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], tonecurve[rtemp[ti * TS + tj]], tonecurve[gtemp[ti * TS + tj]], tonecurve[btemp[ti * TS + tj]]); @@ -2625,9 +2584,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; float z = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; - float fx = x < MAXVALF ? Color::cachef[x] : 327.68f * std::cbrt (x / MAXVALF); - float fy = y < MAXVALF ? Color::cachef[y] : 327.68f * std::cbrt (y / MAXVALF); - float fz = z < MAXVALF ? Color::cachef[z] : 327.68f * std::cbrt (z / MAXVALF); + float fx = x < MAXVALF ? Color::cachef[x] : 327.68f * std::cbrt(x / MAXVALF); + float fy = y < MAXVALF ? Color::cachef[y] : 327.68f * std::cbrt(y / MAXVALF); + float fz = z < MAXVALF ? Color::cachef[z] : 327.68f * std::cbrt(z / MAXVALF); float a_1 = 500.0f * (fx - fy); float b_1 = 200.0f * (fy - fz); @@ -2656,7 +2615,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer //gamut control if (settings->rgbcurveslumamode_gamut) { float Lpro = L_2 / 327.68f; - float Chpro = sqrtf (SQR (a_1) + SQR (b_1)) / 327.68f; + float Chpro = sqrtf(SQR(a_1) + SQR(b_1)) / 327.68f; float HH = NAN; // we set HH to NAN, because then it will be calculated in Color::gamutLchonly only if needed // float HH = xatan2f(b_1, a_1); // According to mathematical laws we can get the sin and cos of HH by simple operations even if we don't calculate HH @@ -2670,21 +2629,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer sincosval.x = b_1 / (Chpro * 327.68f); } -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, Lpro, Chpro, r, g, b, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, Lpro, Chpro, r, g, b, wip, highlight, 0.15f, 0.96f); -#endif + Color::gamutLchonly(HH, sincosval, Lpro, Chpro, r, g, b, wip, highlight, 0.15f, 0.96f); //end of gamut control } else { float x_, y_, z_; //calculate RGB with L_2 and old value of a and b - Color::Lab2XYZ (L_2, a_1, b_1, x_, y_, z_) ; - Color::xyz2rgb (x_, y_, z_, r, g, b, wip); + Color::Lab2XYZ(L_2, a_1, b_1, x_, y_, z_) ; + Color::xyz2rgb(x_, y_, z_, r, g, b, wip); } setUnlessOOG(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], r, g, b); @@ -2697,7 +2649,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { float h, s, v; - Color::rgb2hsv (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], h, s, v); + Color::rgb2hsv(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], h, s, v); editWhateverTmp[ti * TS + tj] = h; } } @@ -2705,11 +2657,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (sat != 0 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { const float satby100 = sat / 100.f; + for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { float h, s, v; Color::rgb2hsvtc(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], h, s, v); h /= 6.f; + if (sat > 0) { s = std::max(0.f, intp(satby100, 1.f - SQR(SQR(1.f - std::min(s, 1.0f))), s)); } else { /*if (sat < 0)*/ @@ -2729,10 +2683,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (sCurveEnabled) { //shift saturation - float satparam = (sCurve->getVal (double (h)) - 0.5) * 2; + float satparam = (sCurve->getVal(double (h)) - 0.5) * 2; if (satparam > 0.00001f) { - s = (1.f - satparam) * s + satparam * (1.f - SQR (1.f - min (s, 1.0f))); + s = (1.f - satparam) * s + satparam * (1.f - SQR(1.f - min(s, 1.0f))); if (s < 0.f) { s = 0.f; @@ -2750,10 +2704,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer //shift value float valparam = vCurve->getVal(h) - 0.5; - valparam *= (1.f - SQR (SQR (1.f - min (s, 1.0f)))); + valparam *= (1.f - SQR(SQR(1.f - min(s, 1.0f)))); if (valparam > 0.00001f) { - v = (1.f - valparam) * v + valparam * (1.f - SQR (1.f - min (v, 1.0f))); // SQR (SQR to increase action and avoid artifacts + v = (1.f - valparam) * v + valparam * (1.f - SQR(1.f - min(v, 1.0f))); // SQR (SQR to increase action and avoid artifacts if (v < 0) { v = 0; @@ -2793,21 +2747,22 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer const float iplow = ctColorCurve.low; const float iphigh = ctColorCurve.high; //2 colours - ctColorCurve.getVal (iphigh, xh, yh, zh); - ctColorCurve.getVal (iplow, xl, yl, zl); + ctColorCurve.getVal(iphigh, xh, yh, zh); + ctColorCurve.getVal(iplow, xl, yl, zl); - Color::xyz2rgb (xh, yh, zh, rh, gh, bh, wip); - Color::xyz2rgb (xl, yl, zl, rl, gl, bl, wip); + Color::xyz2rgb(xh, yh, zh, rh, gh, bh, wip); + Color::xyz2rgb(xl, yl, zl, rl, gl, bl, wip); //reteave rgb value with s and l =1 - retreavergb (rl, gl, bl); + retreavergb(rl, gl, bl); const float krl = rl / (rl + gl + bl); const float kgl = gl / (rl + gl + bl); const float kbl = bl / (rl + gl + bl); - retreavergb (rh, gh, bh); + retreavergb(rh, gh, bh); const float krh = rh / (rh + gh + bh); const float kgh = gh / (rh + gh + bh); const float kbh = bh / (rh + gh + bh); constexpr int mode = 0; + for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { toning2col(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], iplow, iphigh, krl, kgl, kbl, krh, kgh, kbh, SatLow, SatHigh, balanS, balanH, reducac, mode, preser, strProtect); @@ -2847,13 +2802,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool twocol = true;//true=500 color false=2 color int metchrom = 0; - if (params->colorToning.twocolor == "Std" ) { + if (params->colorToning.twocolor == "Std") { metchrom = 0; - } else if (params->colorToning.twocolor == "All" ) { + } else if (params->colorToning.twocolor == "All") { metchrom = 1; } else if (params->colorToning.twocolor == "Separ") { metchrom = 2; - } else if (params->colorToning.twocolor == "Two" ) { + } else if (params->colorToning.twocolor == "Two") { metchrom = 3; } @@ -2876,7 +2831,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer twoc = 1; // 500 colours } - if (params->colorToning.method == "Lab") { + if (params->colorToning.method == "Lab") { algm = 1; } else if (params->colorToning.method == "Lch") { algm = 2; //in case of @@ -2889,12 +2844,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float g = gtemp[ti * TS + tj]; float b = btemp[ti * TS + tj]; float ro, go, bo; - labtoning (r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip); + labtoning(r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip); setUnlessOOG(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], ro, go, bo); } } } - } else if (params->colorToning.method.substr (0, 3) == "RGB" && opautili) { + } else if (params->colorToning.method.substr(0, 3) == "RGB" && opautili) { // color toning for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { @@ -2905,7 +2860,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // Luminance = (0.299f*r + 0.587f*g + 0.114f*b) float s, l; - Color::rgb2slfloat (r, g, b, s, l); + Color::rgb2slfloat(r, g, b, s, l); float l_ = Color::gammatab_srgb1[l * 65535.f]; @@ -2917,12 +2872,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } float r2, g2, b2; - ctColorCurve.getVal (l_, r2, g2, b2); // get the color from the color curve + ctColorCurve.getVal(l_, r2, g2, b2); // get the color from the color curve float h2, s2, l2; - Color::rgb2hslfloat (r2, g2, b2, h2, s2, l2); // transform this new color to hsl + Color::rgb2hslfloat(r2, g2, b2, h2, s2, l2); // transform this new color to hsl - Color::hsl2rgbfloat (h2, s + ((1.f - s) * (1.f - l) * 0.7f), l, r2, g2, b2); + Color::hsl2rgbfloat(h2, s + ((1.f - s) * (1.f - l) * 0.7f), l, r2, g2, b2); rtemp[ti * TS + tj] = r + (r2 - r) * opacity; // merge the color to the old color, depending on the opacity gtemp[ti * TS + tj] = g + (g2 - g) * opacity; @@ -2940,13 +2895,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = jstart, tj = 0; j < tW; j++, tj++) { float X, Y, Z, L, aa, bb; //rgb=>lab - Color::rgbxyz (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); + Color::rgbxyz(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); //convert Lab - Color::XYZ2Lab (X, Y, Z, L, aa, bb); + Color::XYZ2Lab(X, Y, Z, L, aa, bb); //end rgb=>lab - float HH = xatan2f (bb, aa); // HH hue in -3.141 +3.141 + float HH = xatan2f(bb, aa); // HH hue in -3.141 +3.141 - editWhateverTmp[ti * TS + tj] = float (Color::huelab_to_huehsv2 (HH)); + editWhateverTmp[ti * TS + tj] = float (Color::huelab_to_huehsv2(HH)); } } } @@ -2957,36 +2912,36 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (beforeCurveMode == BlackWhiteParams::TcMode::STD_BW) { // Standard for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const StandardToneCurve& userToneCurvebw = static_cast (customToneCurvebw1); - userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const StandardToneCurve& userToneCurvebw = static_cast(customToneCurvebw1); + userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (beforeCurveMode == BlackWhiteParams::TcMode::FILMLIKE_BW) { // Adobe like for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const AdobeToneCurve& userToneCurvebw = static_cast (customToneCurvebw1); - userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + const AdobeToneCurve& userToneCurvebw = static_cast(customToneCurvebw1); + userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (beforeCurveMode == BlackWhiteParams::TcMode::SATANDVALBLENDING_BW) { // apply the curve on the saturation and value channels for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const SatAndValueBlendingToneCurve& userToneCurvebw = static_cast (customToneCurvebw1); + const SatAndValueBlendingToneCurve& userToneCurvebw = static_cast(customToneCurvebw1); // rtemp[ti * TS + tj] = CLIP (rtemp[ti * TS + tj]); // gtemp[ti * TS + tj] = CLIP (gtemp[ti * TS + tj]); // btemp[ti * TS + tj] = CLIP (btemp[ti * TS + tj]); - userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } else if (beforeCurveMode == BlackWhiteParams::TcMode::WEIGHTEDSTD_BW) { // apply the curve to the rgb channels, weighted for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const WeightedStdToneCurve& userToneCurvebw = static_cast (customToneCurvebw1); + const WeightedStdToneCurve& userToneCurvebw = static_cast(customToneCurvebw1); // rtemp[ti * TS + tj] = CLIP (rtemp[ti * TS + tj]); // gtemp[ti * TS + tj] = CLIP (gtemp[ti * TS + tj]); // btemp[ti * TS + tj] = CLIP (btemp[ti * TS + tj]); - userToneCurvebw.Apply (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); + userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]); } } } @@ -3018,7 +2973,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer //gamma correction: pseudo TRC curve if (hasgammabw) { - Color::trcGammaBW (r, g, b, gammabwr, gammabwg, gammabwb); + Color::trcGammaBW(r, g, b, gammabwr, gammabwg, gammabwb); } #endif @@ -3031,7 +2986,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (hasgammabw) { //gamma correction: pseudo TRC curve - Color::trcGammaBWRow (&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], tW - jstart, gammabwr, gammabwg, gammabwb); + Color::trcGammaBWRow(&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], tW - jstart, gammabwr, gammabwg, gammabwb); } #endif @@ -3042,12 +2997,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = jstart, tj = 0; j < tW; j++, tj++) { //rgb => xyz float X, Y, Z; - Color::rgbxyz (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); + Color::rgbxyz(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], X, Y, Z, wp); //xyz => Lab float L, aa, bb; - Color::XYZ2Lab (X, Y, Z, L, aa, bb); - float CC = sqrtf (SQR (aa) + SQR (bb)) / 327.68f; //CC chromaticity in 0..180 or more - float HH = xatan2f (bb, aa); // HH hue in -3.141 +3.141 + Color::XYZ2Lab(X, Y, Z, L, aa, bb); + float CC = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; //CC chromaticity in 0..180 or more + float HH = xatan2f(bb, aa); // HH hue in -3.141 +3.141 float2 sincosval; if (CC == 0.0f) { @@ -3060,14 +3015,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (bwlCurveEnabled) { L /= 32768.f; - double hr = Color::huelab_to_huehsv2 (HH); + double hr = Color::huelab_to_huehsv2(HH); float valparam = (bwlCurve->getVal(hr) - 0.5) * 2.0; //get l_r=f(H) float kcc = (CC / 70.f); //take Chroma into account...70 "middle" of chromaticity (arbitrary and simple), one can imagine other algorithme //reduct action for low chroma and increase action for high chroma valparam *= kcc; if (valparam > 0.f) { - L = (1.f - valparam) * L + valparam * (1.f - SQR (SQR (SQR (SQR (1.f - min (L, 1.0f)))))); // SQR (SQR((SQR) to increase action in low light + L = (1.f - valparam) * L + valparam * (1.f - SQR(SQR(SQR(SQR(1.f - min(L, 1.0f)))))); // SQR (SQR((SQR) to increase action in low light } else { L *= (1.f + valparam); //for negative } @@ -3077,26 +3032,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float RR, GG, BB; L /= 327.68f; -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f); -#endif + Color::gamutLchonly(HH, sincosval, L, CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f); L *= 327.68f; //convert l => rgb - Color::L2XYZ (L, X, Y, Z); + Color::L2XYZ(L, X, Y, Z); float newRed; // We use the red channel for bw - Color::xyz2r (X, Y, Z, newRed, wip); + Color::xyz2r(X, Y, Z, newRed, wip); rtemp[ti * TS + tj] = gtemp[ti * TS + tj] = btemp[ti * TS + tj] = newRed; #ifndef __SSE2__ if (hasgammabw) { //gamma correction: pseudo TRC curve - Color::trcGammaBW (rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], gammabwr, gammabwg, gammabwb); + Color::trcGammaBW(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], gammabwr, gammabwg, gammabwb); } #endif @@ -3106,7 +3054,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (hasgammabw) { //gamma correction: pseudo TRC curve - Color::trcGammaBWRow (&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], tW - jstart, gammabwr, gammabwg, gammabwb); + Color::trcGammaBWRow(&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], tW - jstart, gammabwr, gammabwg, gammabwb); } #endif @@ -3127,19 +3075,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #ifdef __SSE2__ for (; j < tW - 3; j += 4, tj += 4) { - vfloat sourceR = LVF (rtemp[ti * TS + tj]); - vfloat sourceG = LVF (gtemp[ti * TS + tj]); - vfloat sourceB = LVF (btemp[ti * TS + tj]); + vfloat sourceR = LVF(rtemp[ti * TS + tj]); + vfloat sourceG = LVF(gtemp[ti * TS + tj]); + vfloat sourceB = LVF(btemp[ti * TS + tj]); vfloat x; vfloat y; vfloat z; - Color::rgbxyz (sourceR, sourceG, sourceB, x, y, z, v_work2xyz); - Color::xyz2rgb (x, y, z, sourceR, sourceG, sourceB, v_xyz2clut); + Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_work2xyz); + Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2clut); - STVF (clutr[tj], sourceR); - STVF (clutg[tj], sourceG); - STVF (clutb[tj], sourceB); + STVF(clutr[tj], sourceR); + STVF(clutg[tj], sourceG); + STVF(clutb[tj], sourceB); } #endif @@ -3150,8 +3098,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float sourceB = btemp[ti * TS + tj]; float x, y, z; - Color::rgbxyz ( sourceR, sourceG, sourceB, x, y, z, wprof ); - Color::xyz2rgb (x, y, z, clutr[tj], clutg[tj], clutb[tj], xyz2clut); + Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, wprof); + Color::xyz2rgb(x, y, z, clutr[tj], clutg[tj], clutb[tj], xyz2clut); } } else { memcpy(clutr, &rtemp[ti * TS], sizeof(float) * TS); @@ -3165,14 +3113,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = clutb[tj]; // Apply gamma sRGB (default RT) - sourceR = Color::gamma_srgbclipped (sourceR); - sourceG = Color::gamma_srgbclipped (sourceG); - sourceB = Color::gamma_srgbclipped (sourceB); + sourceR = Color::gamma_srgbclipped(sourceR); + sourceG = Color::gamma_srgbclipped(sourceG); + sourceB = Color::gamma_srgbclipped(sourceB); } - hald_clut->getRGB ( + hald_clut->getRGB( film_simulation_strength, - std::min (TS, tW - jstart), + std::min(TS, tW - jstart), clutr, clutg, clutb, @@ -3185,9 +3133,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = clutb[tj]; // Apply inverse gamma sRGB - sourceR = Color::igamma_srgb (out_rgbx[tj * 4 + 0]); - sourceG = Color::igamma_srgb (out_rgbx[tj * 4 + 1]); - sourceB = Color::igamma_srgb (out_rgbx[tj * 4 + 2]); + sourceR = Color::igamma_srgb(out_rgbx[tj * 4 + 0]); + sourceG = Color::igamma_srgb(out_rgbx[tj * 4 + 1]); + sourceB = Color::igamma_srgb(out_rgbx[tj * 4 + 2]); } if (!clutAndWorkingProfilesAreSame) { @@ -3198,19 +3146,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #ifdef __SSE2__ for (; j < tW - 3; j += 4, tj += 4) { - vfloat sourceR = LVF (clutr[tj]); - vfloat sourceG = LVF (clutg[tj]); - vfloat sourceB = LVF (clutb[tj]); + vfloat sourceR = LVF(clutr[tj]); + vfloat sourceG = LVF(clutg[tj]); + vfloat sourceB = LVF(clutb[tj]); vfloat x; vfloat y; vfloat z; - Color::rgbxyz (sourceR, sourceG, sourceB, x, y, z, v_clut2xyz); - Color::xyz2rgb (x, y, z, sourceR, sourceG, sourceB, v_xyz2work); + Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_clut2xyz); + Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2work); - STVF (clutr[tj], sourceR); - STVF (clutg[tj], sourceG); - STVF (clutb[tj], sourceB); + STVF(clutr[tj], sourceR); + STVF(clutg[tj], sourceG); + STVF(clutb[tj], sourceB); } #endif @@ -3221,8 +3169,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = clutb[tj]; float x, y, z; - Color::rgbxyz (sourceR, sourceG, sourceB, x, y, z, clut2xyz); - Color::xyz2rgb ( x, y, z, sourceR, sourceG, sourceB, wiprof ); + Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, clut2xyz); + Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, wiprof); } } @@ -3241,19 +3189,21 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // filling the pipette buffer by the content of the temp pipette buffers if (editImgFloat) { - editImgFloat->r (i, j) = editIFloatTmpR[ti * TS + tj]; - editImgFloat->g (i, j) = editIFloatTmpG[ti * TS + tj]; - editImgFloat->b (i, j) = editIFloatTmpB[ti * TS + tj]; + editImgFloat->r(i, j) = editIFloatTmpR[ti * TS + tj]; + editImgFloat->g(i, j) = editIFloatTmpG[ti * TS + tj]; + editImgFloat->b(i, j) = editIFloatTmpB[ti * TS + tj]; } else if (editWhatever) { - editWhatever->v (i, j) = editWhateverTmp[ti * TS + tj]; + editWhatever->v(i, j) = editWhateverTmp[ti * TS + tj]; } } } } + // ready, fill lab for (int i = istart, ti = 0; i < tH; i++, ti++) { Color::RGB2Lab(&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], &(lab->L[i][jstart]), &(lab->a[i][jstart]), &(lab->b[i][jstart]), toxyz, tW - jstart); } + if (hasColorToningLabGrid) { colorToningLabGrid(lab, jstart, tW, istart, tH, false); } @@ -3263,27 +3213,27 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = jstart, tj = 0; j < tW; j++, tj++) { // filling the pipette buffer by the content of the temp pipette buffers if (editImgFloat) { - editImgFloat->r (i, j) = editIFloatTmpR[ti * TS + tj]; - editImgFloat->g (i, j) = editIFloatTmpG[ti * TS + tj]; - editImgFloat->b (i, j) = editIFloatTmpB[ti * TS + tj]; + editImgFloat->r(i, j) = editIFloatTmpR[ti * TS + tj]; + editImgFloat->g(i, j) = editIFloatTmpG[ti * TS + tj]; + editImgFloat->b(i, j) = editIFloatTmpB[ti * TS + tj]; } else if (editWhatever) { - editWhatever->v (i, j) = editWhateverTmp[ti * TS + tj]; + editWhatever->v(i, j) = editWhateverTmp[ti * TS + tj]; } - tmpImage->r (i, j) = rtemp[ti * TS + tj]; - tmpImage->g (i, j) = gtemp[ti * TS + tj]; - tmpImage->b (i, j) = btemp[ti * TS + tj]; + tmpImage->r(i, j) = rtemp[ti * TS + tj]; + tmpImage->g(i, j) = gtemp[ti * TS + tj]; + tmpImage->b(i, j) = btemp[ti * TS + tj]; } } } } if (editIFloatBuffer) { - free (editIFloatBuffer); + free(editIFloatBuffer); } if (editWhateverBuffer) { - free (editWhateverBuffer); + free(editWhateverBuffer); } #ifdef _OPENMP @@ -3326,9 +3276,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer double kng = srgb / ng; double knb = srgb / nb; double sk = knr + kng + knb; - autor = (float) (100.0 * knr / sk); - autog = (float) (100.0 * kng / sk); - autob = (float) (100.0 * knb / sk); + autor = (float)(100.0 * knr / sk); + autog = (float)(100.0 * kng / sk); + autob = (float)(100.0 * knb / sk); } @@ -3345,9 +3295,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } float filcor; - Color::computeBWMixerConstants (params->blackwhite.setting, params->blackwhite.filter, params->blackwhite.algo, filcor, - bwr, bwg, bwb, mixerOrange, mixerYellow, mixerCyan, mixerPurple, mixerMagenta, - params->blackwhite.autoc, complem, kcorec, rrm, ggm, bbm); + Color::computeBWMixerConstants(params->blackwhite.setting, params->blackwhite.filter, params->blackwhite.algo, filcor, + bwr, bwg, bwb, mixerOrange, mixerYellow, mixerCyan, mixerPurple, mixerMagenta, + params->blackwhite.autoc, complem, kcorec, rrm, ggm, bbm); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 16) @@ -3357,13 +3307,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int j = 0; j < tW; j++) { //mix channel - tmpImage->r (i, j) = tmpImage->g (i, j) = tmpImage->b (i, j) = /*CLIP*/ ((bwr * tmpImage->r (i, j) + bwg * tmpImage->g (i, j) + bwb * tmpImage->b (i, j)) * kcorec); + tmpImage->r(i, j) = tmpImage->g(i, j) = tmpImage->b(i, j) = /*CLIP*/ ((bwr * tmpImage->r(i, j) + bwg * tmpImage->g(i, j) + bwb * tmpImage->b(i, j)) * kcorec); #ifndef __SSE2__ //gamma correction: pseudo TRC curve if (hasgammabw) { - Color::trcGammaBW (tmpImage->r (i, j), tmpImage->g (i, j), tmpImage->b (i, j), gammabwr, gammabwg, gammabwb); + Color::trcGammaBW(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j), gammabwr, gammabwg, gammabwb); } #endif @@ -3373,7 +3323,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (hasgammabw) { //gamma correction: pseudo TRC curve - Color::trcGammaBWRow (tmpImage->r (i), tmpImage->g (i), tmpImage->b (i), tW, gammabwr, gammabwg, gammabwb); + Color::trcGammaBWRow(tmpImage->r(i), tmpImage->g(i), tmpImage->b(i), tW, gammabwr, gammabwg, gammabwb); } #endif @@ -3387,7 +3337,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - editWhatever->v (i, j) = Color::gamma2curve[tmpImage->r (i, j)] / 65535.f; // assuming that r=g=b + editWhatever->v(i, j) = Color::gamma2curve[tmpImage->r(i, j)] / 65535.f; // assuming that r=g=b } } } @@ -3401,8 +3351,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - const StandardToneCurve& userToneCurve = static_cast (customToneCurvebw2); - userToneCurve.Apply (tmpImage->r (i, j), tmpImage->g (i, j), tmpImage->b (i, j)); + const StandardToneCurve& userToneCurve = static_cast(customToneCurvebw2); + userToneCurve.Apply(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j)); } } } else if (afterCurveMode == BlackWhiteParams::TcMode::WEIGHTEDSTD_BW) { // apply the curve to the rgb channels, weighted @@ -3412,13 +3362,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { //for ulterior usage if bw data modified for (int j = 0; j < tW; j++) { - const WeightedStdToneCurve& userToneCurve = static_cast (customToneCurvebw2); + const WeightedStdToneCurve& userToneCurve = static_cast(customToneCurvebw2); // tmpImage->r (i, j) = CLIP (tmpImage->r (i, j)); // tmpImage->g (i, j) = CLIP (tmpImage->g (i, j)); // tmpImage->b (i, j) = CLIP (tmpImage->b (i, j)); - userToneCurve.Apply (tmpImage->r (i, j), tmpImage->g (i, j), tmpImage->b (i, j)); + userToneCurve.Apply(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j)); } } } @@ -3435,9 +3385,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - const float r = tmpImage->r (i, j); - const float g = tmpImage->g (i, j); - const float b = tmpImage->b (i, j); + const float r = tmpImage->r(i, j); + const float g = tmpImage->g(i, j); + const float b = tmpImage->b(i, j); const float lumbefore = 0.299f * r + 0.587f * g + 0.114f * b; @@ -3479,19 +3429,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer const float iphigh = ctColorCurve.high; //2 colours - ctColorCurve.getVal (iphigh, xh, yh, zh); - ctColorCurve.getVal (iplow, xl, yl, zl); + ctColorCurve.getVal(iphigh, xh, yh, zh); + ctColorCurve.getVal(iplow, xl, yl, zl); - Color::xyz2rgb (xh, yh, zh, rh, gh, bh, wip); - Color::xyz2rgb (xl, yl, zl, rl, gl, bl, wip); + Color::xyz2rgb(xh, yh, zh, rh, gh, bh, wip); + Color::xyz2rgb(xl, yl, zl, rl, gl, bl, wip); //retrieve rgb value with s and l =1 - retreavergb (rl, gl, bl); + retreavergb(rl, gl, bl); const float krl = rl / (rl + gl + bl); const float kgl = gl / (rl + gl + bl); const float kbl = bl / (rl + gl + bl); - retreavergb (rh, gh, bh); + retreavergb(rh, gh, bh); const float krh = rh / (rh + gh + bh); const float kgh = gh / (rh + gh + bh); const float kbh = bh / (rh + gh + bh); @@ -3513,13 +3463,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer bool twocol = true; int metchrom = 0; - if (params->colorToning.twocolor == "Std" ) { + if (params->colorToning.twocolor == "Std") { metchrom = 0; - } else if (params->colorToning.twocolor == "All" ) { + } else if (params->colorToning.twocolor == "All") { metchrom = 1; } else if (params->colorToning.twocolor == "Separ") { metchrom = 2; - } else if (params->colorToning.twocolor == "Two" ) { + } else if (params->colorToning.twocolor == "Two") { metchrom = 3; } @@ -3543,7 +3493,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer twoc = 1; // 500 colours } - if (params->colorToning.method == "Lab") { + if (params->colorToning.method == "Lab") { algm = 1; } else if (params->colorToning.method == "Lch") { algm = 2; //in case of @@ -3556,18 +3506,18 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r (i, j); - float g = tmpImage->g (i, j); - float b = tmpImage->b (i, j); + float r = tmpImage->r(i, j); + float g = tmpImage->g(i, j); + float b = tmpImage->b(i, j); float ro, bo, go; - labtoning (r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip); + labtoning(r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip); setUnlessOOG(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j), ro, go, bo); } } } } - else if (params->colorToning.method.substr (0, 3) == "RGB" && opautili) { + else if (params->colorToning.method.substr(0, 3) == "RGB" && opautili) { // color toning #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 5) @@ -3634,6 +3584,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { Color::RGB2Lab(tmpImage->r(i), tmpImage->g(i), tmpImage->b(i), lab->L[i], lab->a[i], lab->b[i], toxyz, tW); + if (hasColorToningLabGrid) { colorToningLabGrid(lab, 0, tW, i, i + 1, false); } @@ -3663,7 +3614,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (params->localContrast.enabled) { // Alberto's local contrast - localContrast(lab); + localContrast(lab, lab->L, params->localContrast, false, scale); } } @@ -3673,10 +3624,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer * @param g green input and in exit new g * @param b blue input and in exit new b **/ -void ImProcFunctions::retreavergb (float &r, float &g, float &b) +void ImProcFunctions::retreavergb(float &r, float &g, float &b) { - float mini = min (r, g, b); - float maxi = max (r, g, b); + float mini = min(r, g, b); + float maxi = max(r, g, b); float kkm = 65535.f / maxi; if (b == mini && r == maxi) { @@ -3714,7 +3665,7 @@ void ImProcFunctions::retreavergb (float &r, float &g, float &b) * @param bb first degree parameter * @param cc third parameter **/ -void ImProcFunctions::secondeg_end (float reducac, float vinf, float &aa, float &bb, float &cc) +void ImProcFunctions::secondeg_end(float reducac, float vinf, float &aa, float &bb, float &cc) { float zrd = reducac; //value at me linear =0.5 float v0 = vinf; //max shadows @@ -3735,7 +3686,7 @@ void ImProcFunctions::secondeg_end (float reducac, float vinf, float &aa, float * @param aa second degree parameter * @param bb first degree parameter **/ -void ImProcFunctions::secondeg_begin (float reducac, float vend, float &aam, float &bbm) +void ImProcFunctions::secondeg_begin(float reducac, float vend, float &aam, float &bbm) { aam = (2.f - 4.f * reducac) / (vend * vend); bbm = 1.f / vend - aam * vend; @@ -3780,17 +3731,18 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, if (v > v0) { float aa, bb, cc; - secondeg_end (reducac, v0, aa, bb, cc); + secondeg_end(reducac, v0, aa, bb, cc); kl = aa * v * v + bb * v + cc; //verified ==> exact } else { float aab, bbb; - secondeg_begin (0.7f, v0, aab, bbb); + secondeg_begin(0.7f, v0, aab, bbb); kl = aab * v * v + bbb * v; } } else { //bw coefficient to preserve same results as before for satlimtopacity = 0.5 (default) rlo = strProtect * 0.8f; //0.4 rlm = strProtect * 2.2f; //1.1 rlh = strProtect * 2.4f; //1.2 + if (v > 0.15f) { kl = (-1.f / 0.85f) * v + 1.f / 0.85f; //Low light ==> decrease action after v=0.15 } @@ -3849,12 +3801,12 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, if (v < v0m) { float aam, bbm; float vend = v0m; - secondeg_begin (reducac, vend, aam, bbm); + secondeg_begin(reducac, vend, aam, bbm); km = aam * v * v + bbm * v; //verification = good } else { float v0mm = 0.5f; //max float aamm, bbmm, ccmm; - secondeg_end (reducac, v0mm, aamm, bbmm, ccmm); + secondeg_end(reducac, v0mm, aamm, bbmm, ccmm); km = aamm * v * v + bbmm * v + ccmm; //verification good } @@ -3870,6 +3822,7 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, g -= 20000.f * RedM; b -= 20000.f * RedM; } + // r = CLIP(r); // g = CLIP(g); // b = CLIP(b); @@ -3887,6 +3840,7 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, g += 10000.f * GreenM; b -= 20000.f * GreenM; } + // r = CLIP(r); // g = CLIP(g); // b = CLIP(b); @@ -3904,6 +3858,7 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, g -= 20000.f * BlueM; b += 10000.f * BlueM; } + // r = CLIP(r); // g = CLIP(g); // b = CLIP(b); @@ -3912,9 +3867,10 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, //high tones constexpr float v00 = 0.8f; //max action float aa0, bb0; - secondeg_begin (reducac, v00, aa0, bb0); + secondeg_begin(reducac, v00, aa0, bb0); float kh; + if (v > v00) { //max action kh = (1.f - v) / (1.f - v00); //High tones } else { @@ -3983,7 +3939,7 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, * @param balanH [0..1] balance for highlights (same slider than for balanS) * @param reducac value of the reduction in the middle of the range for second degree, increase or decrease action **/ -void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float krl, float kgl, float kbl, float krh, float kgh, float kbh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect) +void ImProcFunctions::toning2col(float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float krl, float kgl, float kbl, float krh, float kgh, float kbh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect) { const float lumbefore = 0.299f * r + 0.587f * g + 0.114f * b; const float v = max(r, g, b) / 65535.f; @@ -3995,22 +3951,25 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g //second degree float aa, bb, cc; //fixed value of reducac =0.4; - secondeg_end (reducac, iplow, aa, bb, cc); + secondeg_end(reducac, iplow, aa, bb, cc); float aab, bbb; - secondeg_begin (0.7f, iplow, aab, bbb); + secondeg_begin(0.7f, iplow, aab, bbb); if (SatLow > 0.f) { float kl = 1.f; + if (v > iplow) { kl = aa * v * v + bb * v + cc; } else if (mode == 0) { kl = aab * v * v + bbb * v; } + const float kmgb = min(r, g, b); + if (kmgb < 20000.f) { //I have tested ...0.85 compromise... - kl *= pow_F ((kmgb / 20000.f), 0.85f); + kl *= pow_F((kmgb / 20000.f), 0.85f); } const float factor = 20000.f * SatLow * kl * rlo * balanS; @@ -4043,10 +4002,11 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g //high tones float aa0, bb0; //fixed value of reducac ==0.4; - secondeg_begin (reducac, iphigh, aa0, bb0); + secondeg_begin(reducac, iphigh, aa0, bb0); if (SatHigh > 0.f) { float kh = 1.f; + if (v > iphigh) { kh = (1.f - v) / (1.f - iphigh); //Low light ==> decrease action after iplow } else { @@ -4054,11 +4014,13 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g } const float kmgb = max(r, g, b); + if (kmgb > 45535.f) { constexpr float cora = 1.f / (45535.f - 65535.f); constexpr float corb = 1.f - cora * 45535.f; kh *= kmgb * cora + corb; } + const float factor = 20000.f * SatHigh * kh * rlh * balanH; r += factor * (krh > 0.f ? krh : 0.f); g += factor * (kgh > 0.f ? kgh : 0.f); @@ -4070,6 +4032,7 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g } float preserv = 1.f; + if (preser == 1) { float lumafter = 0.299f * r + 0.587f * g + 0.114f * b; preserv = lumbefore / lumafter; @@ -4098,7 +4061,7 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go float realL; float h, s, l; - Color::rgb2hsl (ro, go, bo, h, s, l); + Color::rgb2hsl(ro, go, bo, h, s, l); float x2, y2, z2; float xl, yl, zl; @@ -4109,10 +4072,10 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go } if (twoc == 1) { - ctColorCurve.getVal (l, x2, y2, z2); + ctColorCurve.getVal(l, x2, y2, z2); } else { - ctColorCurve.getVal (iphigh, x2, y2, z2); - ctColorCurve.getVal (iplow, xl, yl, zl); + ctColorCurve.getVal(iphigh, x2, y2, z2); + ctColorCurve.getVal(iplow, xl, yl, zl); } realL = l; @@ -4142,9 +4105,9 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go } if (algm == 1) { - Color::interpolateRGBColor (realL, iplow, iphigh, algm, opacity, twoc, metchrom, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, wp, wip, ro, go, bo); + Color::interpolateRGBColor(realL, iplow, iphigh, algm, opacity, twoc, metchrom, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, wp, wip, ro, go, bo); } else { - Color::interpolateRGBColor (realL, iplow, iphigh, algm, opacity2, twoc, metchrom, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, wp, wip, ro, go, bo); + Color::interpolateRGBColor(realL, iplow, iphigh, algm, opacity2, twoc, metchrom, chromat, luma, r, g, b, xl, yl, zl, x2, y2, z2, wp, wip, ro, go, bo); } } @@ -4171,7 +4134,6 @@ void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, const LUTf void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, const LUTf& acurve, const LUTf& bcurve, const LUTf& satcurve, const LUTf& lhskcurve, const LUTf& clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLCurve) { - int W = lold->W; int H = lold->H; @@ -4184,7 +4146,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW if (editID != EUID_None) { - switch (pipetteBuffer->getDataProvider()->getCurrSubscriber()->getPipetteBufferType()) { + switch (pipetteBuffer->getDataProvider()->getCurrSubscriber()->getPipetteBufferType()) { case (BT_IMAGEFLOAT): break; @@ -4258,7 +4220,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW bool chutili = false; if (params->labCurve.chromaticity > -100) { - chCurve = new FlatCurve (params->labCurve.chcurve); + chCurve = new FlatCurve(params->labCurve.chcurve); if (chCurve->isIdentity()) { delete chCurve; @@ -4273,7 +4235,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW bool lhutili = false; if (params->labCurve.chromaticity > -100) { - lhCurve = new FlatCurve (params->labCurve.lhcurve); + lhCurve = new FlatCurve(params->labCurve.lhcurve); if (lhCurve->isIdentity()) { delete lhCurve; @@ -4288,7 +4250,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW bool hhutili = false; if (params->labCurve.chromaticity > -100) { - hhCurve = new FlatCurve (params->labCurve.hhcurve); + hhCurve = new FlatCurve(params->labCurve.hhcurve); if (hhCurve->isIdentity()) { delete hhCurve; @@ -4303,13 +4265,6 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW const float histLFactor = pW != 1 ? histLCurve.getSize() / 100.f : 1.f; const float histCFactor = pW != 1 ? histCCurve.getSize() / 48000.f : 1.f; -#ifdef _DEBUG - MyTime t1e, t2e; - t1e.set(); - // init variables to display Munsell corrections - MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); -#endif - float adjustr = 1.0f; // if(params->labCurve.avoidclip ){ @@ -4408,11 +4363,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW }; #ifdef _OPENMP -#ifdef _DEBUG - #pragma omp parallel default(shared) firstprivate(lold, lnew, MunsDebugInfo, pW) if (multiThread) -#else #pragma omp parallel if (multiThread) -#endif #endif { #ifdef __SSE2__ @@ -4428,27 +4379,27 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // only if user activate Lab adjustments if (autili || butili || ccutili || cclutili || chutili || lhutili || hhutili || clcutili || utili || chromaticity) { - Color::LabGamutMunsell (lold->L[i], lold->a[i], lold->b[i], W, /*corMunsell*/true, /*lumaMuns*/false, params->toneCurve.hrenabled, /*gamut*/true, wip); + Color::LabGamutMunsell(lold->L[i], lold->a[i], lold->b[i], W, /*corMunsell*/true, /*lumaMuns*/false, params->toneCurve.hrenabled, /*gamut*/true, wip); } #ifdef __SSE2__ // precalculate some values using SSE if (bwToning || (!autili && !butili)) { - __m128 c327d68v = _mm_set1_ps (327.68f); + __m128 c327d68v = _mm_set1_ps(327.68f); __m128 av, bv; int k; for (k = 0; k < W - 3; k += 4) { - av = LVFU (lold->a[i][k]); - bv = LVFU (lold->b[i][k]); - STVF (HHBuffer[k], xatan2f (bv, av)); + av = LVFU(lold->a[i][k]); + bv = LVFU(lold->b[i][k]); + STVF(HHBuffer[k], xatan2f(bv, av)); STVF (CCBuffer[k], vsqrtf (SQRV (av) + SQRV (bv)) / c327d68v); } for (; k < W; k++) { - HHBuffer[k] = xatan2f (lold->b[i][k], lold->a[i][k]); - CCBuffer[k] = sqrt (SQR (lold->a[i][k]) + SQR (lold->b[i][k])) / 327.68f; + HHBuffer[k] = xatan2f(lold->b[i][k], lold->a[i][k]); + CCBuffer[k] = sqrt(SQR(lold->a[i][k]) + SQR(lold->b[i][k])) / 327.68f; } } @@ -4470,8 +4421,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW HH = HHBuffer[j]; CC = CCBuffer[j]; #else - HH = xatan2f (lold->b[i][j], lold->a[i][j]); - CC = sqrt (SQR (lold->a[i][j]) + SQR (lold->b[i][j])) / 327.68f; + HH = xatan2f(lold->b[i][j], lold->a[i][j]); + CC = sqrt(SQR(lold->a[i][j]) + SQR(lold->b[i][j])) / 327.68f; #endif // According to mathematical laws we can get the sin and cos of HH by simple operations @@ -4489,7 +4440,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW } if (editPipette && editID == EUID_Lab_LCurve) { - editWhatever->v (i, j) = LIM01 (Lin / 32768.0f); // Lab L pipette + editWhatever->v(i, j) = LIM01 (Lin / 32768.0f); // Lab L pipette } lnew->L[i][j] = curve[Lin]; @@ -4499,10 +4450,10 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW if (editPipette) { if (editID == EUID_Lab_aCurve) { // Lab a pipette float chromapipa = lold->a[i][j] + (32768.f * 1.28f); - editWhatever->v (i, j) = LIM01 ((chromapipa) / (65536.f * 1.28f)); + editWhatever->v(i, j) = LIM01 ((chromapipa) / (65536.f * 1.28f)); } else if (editID == EUID_Lab_bCurve) { //Lab b pipette float chromapipb = lold->b[i][j] + (32768.f * 1.28f); - editWhatever->v (i, j) = LIM01 ((chromapipb) / (65536.f * 1.28f)); + editWhatever->v(i, j) = LIM01 ((chromapipb) / (65536.f * 1.28f)); } } @@ -4527,13 +4478,13 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW HH = HHBuffer[j]; CC = CCBuffer[j]; } else { - CC = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; - HH = xatan2f (btmp, atmp); + CC = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; + HH = xatan2f(btmp, atmp); } #else - CC = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; - HH = xatan2f (btmp, atmp); + CC = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; + HH = xatan2f(btmp, atmp); #endif // According to mathematical laws we can get the sin and cos of HH by simple operations @@ -4553,8 +4504,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW if (editPipette) if (editID == EUID_Lab_LHCurve || editID == EUID_Lab_CHCurve || editID == EUID_Lab_HHCurve) {//H pipette - float valpar = Color::huelab_to_huehsv2 (HH); - editWhatever->v (i, j) = valpar; + float valpar = Color::huelab_to_huehsv2(HH); + editWhatever->v(i, j) = valpar; } if (lhutili) { // L=f(H) @@ -4563,6 +4514,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW l_r = Lprov1 / 100.f; { float valparam = lhCurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5; //get l_r=f(H) + //float valparam = float ((lhCurve->getVal (hr - 0.5f)*2));//get l_r=f(H) + float valparamneg; valparamneg = valparam; float kcc = (CC / amountchroma); //take Chroma into account...40 "middle low" of chromaticity (arbitrary and simple), one can imagine other algorithme @@ -4571,7 +4524,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW valparamneg *= kcc; //slightly different for negative if (valparam > 0.f) { - l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR (((SQR (1.f - min (l_r, 1.0f)))))); + l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR(((SQR(1.f - min(l_r, 1.0f)))))); } else //for negative { @@ -4582,7 +4535,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW Lprov1 = l_r * 100.f; - float Chprov2 = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; + float Chprov2 = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; //Gamut control especially for negative values slightly different from gamutlchonly bool inRGB; @@ -4591,7 +4544,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float aprov1 = Chprov2 * sincosval.y; float bprov1 = Chprov2 * sincosval.x; - float fy = (Color::c1By116 * Lprov1 ) + Color::c16By116; + float fy = (Color::c1By116 * Lprov1) + Color::c16By116; float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); @@ -4599,7 +4552,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float z_ = 65535.f * Color::f2xyz (fz) * Color::D50z; float y_ = Lprov1 > Color::epskapf ? 65535.f * fy * fy * fy : 65535.f * Lprov1 / Color::kappaf; float R, G, B; - Color::xyz2rgb (x_, y_, z_, R, G, B, wip); + Color::xyz2rgb(x_, y_, z_, R, G, B, wip); if (R < 0.0f || G < 0.0f || B < 0.0f) { if (Lprov1 < 0.1f) { @@ -4624,8 +4577,9 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // calculate C=f(H) if (chutili) { - double hr = Color::huelab_to_huehsv2 (HH); + double hr = Color::huelab_to_huehsv2(HH); float chparam = (chCurve->getVal(hr) - 0.5) * 2.0; //get C=f(H) + float chromaChfactor = 1.0f + chparam; atmp *= chromaChfactor;//apply C=f(H) btmp *= chromaChfactor; @@ -4644,7 +4598,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW if (chromapro > 1.f) { float scale = scaleConst;//reduction in normal zone float scaleext = 1.f;//reduction in transition zone - Color::scalered ( rstprotection, chromapro, 0.0, HH, protect_redh, scale, scaleext);//1.0 + Color::scalered(rstprotection, chromapro, 0.0, HH, protect_redh, scale, scaleext); //1.0 float interm = (chromapro - 1.f); factorskin = 1.f + (interm * scale); factorskinext = 1.f + (interm * scaleext); @@ -4658,7 +4612,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW //simulate very approximative gamut f(L) : with pyramid transition float dred /*=55.f*/;//C red value limit - if (Lprov1 < 25.f) { + if (Lprov1 < 25.f) { dred = 40.f; } else if (Lprov1 < 30.f) { dred = 3.f * Lprov1 - 35.f; @@ -4673,12 +4627,12 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // end pyramid // Test if chroma is in the normal range first - Color::transitred ( HH, Chprov1, dred, factorskin, protect_red, factorskinext, protect_redh, factorsat, factorsat); + Color::transitred(HH, Chprov1, dred, factorskin, protect_red, factorskinext, protect_redh, factorsat, factorsat); atmp *= factorsat; btmp *= factorsat; if (editPipette && editID == EUID_Lab_CLCurve) { - editWhatever->v (i, j) = LIM01 (LL / 100.f); // Lab C=f(L) pipette + editWhatever->v(i, j) = LIM01 (LL / 100.f); // Lab C=f(L) pipette } if (clut && LL > 0.f) { // begin C=f(L) @@ -4712,7 +4666,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW deltaHH = protect_redhcur; //transition hue if (chromaCfactor > 0.f) { - Color::scalered ( rstprotection, chromaCfactor, 0.0, HH, deltaHH, scale, scaleext); //1.0 + Color::scalered(rstprotection, chromaCfactor, 0.0, HH, deltaHH, scale, scaleext); //1.0 } if (chromaCfactor > 1.f) { @@ -4726,7 +4680,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW factorsat = chromaCfactor; factor = factorsat; - Color::transitred ( HH, Chprov1, dred, factorskin, protect_redcur, factorskinext, deltaHH, factorsat, factor); + Color::transitred(HH, Chprov1, dred, factorskin, protect_redcur, factorskinext, deltaHH, factorsat, factor); atmp = LIM(atmp * factor, min(-42000.f, atmp), max(42000.f, atmp)); btmp = LIM(btmp * factor, min(-42000.f, btmp), max(42000.f, btmp)); } @@ -4737,13 +4691,13 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // I have placed C=f(C) after all C treatments to assure maximum amplitude of "C" if (editPipette && editID == EUID_Lab_CCurve) { - float chromapip = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); - editWhatever->v (i, j) = LIM01 ((chromapip) / (48000.f)); + float chromapip = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); + editWhatever->v(i, j) = LIM01 ((chromapip) / (48000.f)); }//Lab C=f(C) pipette if (ccut) { float factorskin, factorsat, factor, factorskinext; - float chroma = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); + float chroma = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); float chromaCfactor = (satcurve[chroma * adjustr]) / (chroma * adjustr); //apply C=f(C) float curf = 0.7f; //empirical coeff because curve is more progressive float scale = 100.0f / 100.1f; //reduction in normal zone for curve CC @@ -4773,7 +4727,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW deltaHH = protect_redhcur; //transition hue if (chromaCfactor > 0.f) { - Color::scalered ( rstprotection, chromaCfactor, 0.0, HH, deltaHH, scale, scaleext); //1.0 + Color::scalered(rstprotection, chromaCfactor, 0.0, HH, deltaHH, scale, scaleext); //1.0 } if (chromaCfactor > 1.f) { @@ -4790,7 +4744,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW factorsat = chromaCfactor; factor = factorsat; - Color::transitred ( HH, Chprov1, dred, factorskin, protect_redcur, factorskinext, deltaHH, factorsat, factor); + Color::transitred(HH, Chprov1, dred, factorskin, protect_redcur, factorskinext, deltaHH, factorsat, factor); atmp *= factor; btmp *= factor; } @@ -4804,8 +4758,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW } if (editPipette && editID == EUID_Lab_LCCurve) { - float chromapiplc = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); - editWhatever->v (i, j) = LIM01 ((chromapiplc) / (48000.f)); + float chromapiplc = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); + editWhatever->v(i, j) = LIM01 ((chromapiplc) / (48000.f)); }//Lab L=f(C) pipette @@ -4824,7 +4778,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float yy = 0.0f; if (Chprov1 < chrmin) { - yy = SQR (Chprov1 / chrmin) * xx; + yy = SQR(Chprov1 / chrmin) * xx; } else { yy = xx; //avoid artifact for low C } @@ -4835,7 +4789,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW skdeltaHH = 0.001f; } - if (HH > skbeg && HH < skend ) { + if (HH > skbeg && HH < skend) { zz = yy; } else if (HH > skbeg - skdeltaHH && HH <= skbeg) { //transition aa = yy / skdeltaHH; @@ -4847,7 +4801,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW zz = aa * HH + bb; } - float chroma = sqrt (SQR (atmp) + SQR (btmp) + 0.001f); + float chroma = sqrt(SQR(atmp) + SQR(btmp) + 0.001f); float Lc = (lhskcurve[chroma * adjustr]) / (chroma * adjustr); //apply L=f(C) Lc = (Lc - 1.0f) * zz + 1.0f; //reduct action Lprov1 *= Lc; //adjust luminance @@ -4858,7 +4812,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW histLCurve[Lprov1 * histLFactor]++; } - Chprov1 = sqrt (SQR (atmp) + SQR (btmp)) / 327.68f; + Chprov1 = sqrt(SQR(atmp) + SQR(btmp)) / 327.68f; // labCurve.bwtoning option allows to decouple modulation of a & b curves by saturation // with bwtoning enabled the net effect of a & b curves is visible @@ -4871,27 +4825,18 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW //gamutmap Lch ==> preserve Hue,but a little slower than gamutbdy for high values...and little faster for low values if (gamutLch) { float R, G, B; - -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); -#endif + Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); lnew->L[i][j] = Lprov1 * 327.68f; -// float2 sincosval = xsincosf(HH); lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; } else { //use gamutbdy //Luv limiter float Y, u, v; - Color::Lab2Yuv (lnew->L[i][j], atmp, btmp, Y, u, v); + Color::Lab2Yuv(lnew->L[i][j], atmp, btmp, Y, u, v); //Yuv2Lab includes gamut restriction map - Color::Yuv2Lab (Y, u, v, lnew->L[i][j], lnew->a[i][j], lnew->b[i][j], wp); + Color::Yuv2Lab(Y, u, v, lnew->L[i][j], lnew->a[i][j], lnew->b[i][j], wp); } if (utili || autili || butili || ccut || clut || cclutili || chutili || lhutili || hhutili || clcutili || chromaticity) { @@ -4899,16 +4844,11 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float correctlum = 0.f; Lprov1 = lnew->L[i][j] / 327.68f; - Chprov = sqrt (SQR (lnew->a[i][j]) + SQR (lnew->b[i][j])) / 327.68f; - -#ifdef _DEBUG - Color::AllMunsellLch (/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum, MunsDebugInfo); -#else - Color::AllMunsellLch (/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum); -#endif + Chprov = sqrt(SQR(lnew->a[i][j]) + SQR(lnew->b[i][j])) / 327.68f; + Color::AllMunsellLch(/*lumaMuns*/true, Lprov1, LL, HH, Chprov, memChprov, correctionHue, correctlum); if (correctionHue != 0.f || correctlum != 0.f) { - if (fabs (correctionHue) < 0.015f) { + if (fabs(correctionHue) < 0.015f) { HH += correctlum; // correct only if correct Munsell chroma very little. } @@ -4918,7 +4858,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW else if(fabs(correctionHue) < 0.1f) HH+=0.35f*correctlum; else if(fabs(correctionHue) < 0.015f) HH+=correctlum; // correct only if correct Munsell chroma very little. */ - sincosval = xsincosf (HH + correctionHue); + sincosval = xsincosf(HH + correctionHue); } lnew->a[i][j] = 327.68f * Chprov * sincosval.y; // apply Munsell @@ -4942,18 +4882,6 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW } } // end of parallelization -#ifdef _DEBUG - - 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=%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; -#endif - if (chCurve) { delete chCurve; } @@ -4976,84 +4904,84 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW //void ImProcFunctions::colorCurve (LabImage* lold, LabImage* lnew) //{ - /* LUT cmultiplier(181021); +/* LUT cmultiplier(181021); - double boost_a = ((float)params->colorBoost.amount + 100.0) / 100.0; - double boost_b = ((float)params->colorBoost.amount + 100.0) / 100.0; + double boost_a = ((float)params->colorBoost.amount + 100.0) / 100.0; + double boost_b = ((float)params->colorBoost.amount + 100.0) / 100.0; - double c, amul = 1.0, bmul = 1.0; - if (boost_a > boost_b) { - c = boost_a; - if (boost_a > 0) - bmul = boost_b / boost_a; - } - else { - c = boost_b; - if (boost_b > 0) - amul = boost_a / boost_b; + double c, amul = 1.0, bmul = 1.0; + if (boost_a > boost_b) { + c = boost_a; + if (boost_a > 0) + bmul = boost_b / boost_a; + } + else { + c = boost_b; + if (boost_b > 0) + amul = boost_a / boost_b; + } + + if (params->colorBoost.enable_saturationlimiter && c>1.0) { + // re-generate color multiplier lookup table + double d = params->colorBoost.saturationlimit / 3.0; + double alpha = 0.5; + double threshold1 = alpha * d; + double threshold2 = c*d*(alpha+1.0) - d; + for (int i=0; i<=181020; i++) { // lookup table stores multipliers with a 0.25 chrominance resolution + double chrominance = (double)i/4.0; + if (chrominance < threshold1) + cmultiplier[i] = c; + else if (chrominance < d) + cmultiplier[i] = (c / (2.0*d*(alpha-1.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; + else if (chrominance < threshold2) + cmultiplier[i] = (1.0 / (2.0*d*(c*(alpha+1.0)-2.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; + else + cmultiplier[i] = 1.0; } + } - if (params->colorBoost.enable_saturationlimiter && c>1.0) { - // re-generate color multiplier lookup table - double d = params->colorBoost.saturationlimit / 3.0; - double alpha = 0.5; - double threshold1 = alpha * d; - double threshold2 = c*d*(alpha+1.0) - d; - for (int i=0; i<=181020; i++) { // lookup table stores multipliers with a 0.25 chrominance resolution - double chrominance = (double)i/4.0; - if (chrominance < threshold1) - cmultiplier[i] = c; - else if (chrominance < d) - cmultiplier[i] = (c / (2.0*d*(alpha-1.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; - else if (chrominance < threshold2) - cmultiplier[i] = (1.0 / (2.0*d*(c*(alpha+1.0)-2.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; - else - cmultiplier[i] = 1.0; + float eps = 0.001; + double shift_a = params->colorShift.a + eps, shift_b = params->colorShift.b + eps; + + float** oa = lold->a; + float** ob = lold->b; + + #pragma omp parallel for if (multiThread) + for (int i=0; iH; i++) + for (int j=0; jW; j++) { + + double wanted_c = c; + if (params->colorBoost.enable_saturationlimiter && c>1) { + float chroma = (float)(4.0 * sqrt((oa[i][j]+shift_a)*(oa[i][j]+shift_a) + (ob[i][j]+shift_b)*(ob[i][j]+shift_b))); + wanted_c = cmultiplier [chroma]; } - } - float eps = 0.001; - double shift_a = params->colorShift.a + eps, shift_b = params->colorShift.b + eps; - - float** oa = lold->a; - float** ob = lold->b; - - #pragma omp parallel for if (multiThread) - for (int i=0; iH; i++) - for (int j=0; jW; j++) { - - double wanted_c = c; - if (params->colorBoost.enable_saturationlimiter && c>1) { - float chroma = (float)(4.0 * sqrt((oa[i][j]+shift_a)*(oa[i][j]+shift_a) + (ob[i][j]+shift_b)*(ob[i][j]+shift_b))); - wanted_c = cmultiplier [chroma]; + double real_c = wanted_c; + if (wanted_c >= 1.0 && params->colorBoost.avoidclip) { + double cclip = 100000.0; + double cr = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)*amul, (double)(ob[i][j]+shift_b)*bmul, 3.079935, -1.5371515, -0.54278342); + double cg = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)*amul, (double)(ob[i][j]+shift_b)*bmul, -0.92123418, 1.87599, 0.04524418); + double cb = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)*amul, (double)(ob[i][j]+shift_b)*bmul, 0.052889682, -0.20404134, 1.15115166); + if (cr>1.0 && cr1.0 && cg1.0 && cb= 1.0 && params->colorBoost.avoidclip) { - double cclip = 100000.0; - double cr = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)*amul, (double)(ob[i][j]+shift_b)*bmul, 3.079935, -1.5371515, -0.54278342); - double cg = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)*amul, (double)(ob[i][j]+shift_b)*bmul, -0.92123418, 1.87599, 0.04524418); - double cb = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa[i][j]+shift_a)*amul, (double)(ob[i][j]+shift_b)*bmul, 0.052889682, -0.20404134, 1.15115166); - if (cr>1.0 && cr1.0 && cg1.0 && cba[i][j] = LIM(nna,-32000.0f,32000.0f); - lnew->b[i][j] = LIM(nnb,-32000.0f,32000.0f); } - */ - //delete [] cmultiplier; + + float nna = ((oa[i][j]+shift_a) * real_c * amul); + float nnb = ((ob[i][j]+shift_b) * real_c * bmul); + lnew->a[i][j] = LIM(nna,-32000.0f,32000.0f); + lnew->b[i][j] = LIM(nnb,-32000.0f,32000.0f); + } +*/ +//delete [] cmultiplier; //} -void ImProcFunctions::impulsedenoise (LabImage* lab) +void ImProcFunctions::impulsedenoise(LabImage* lab) { if (params->impulseDenoise.enabled && lab->W >= 8 && lab->H >= 8) @@ -5063,7 +4991,7 @@ void ImProcFunctions::impulsedenoise (LabImage* lab) } } -void ImProcFunctions::impulsedenoisecam (CieImage* ncie, float **buffers[3]) +void ImProcFunctions::impulsedenoisecam(CieImage* ncie, float **buffers[3]) { if (params->impulseDenoise.enabled && ncie->W >= 8 && ncie->H >= 8) @@ -5073,57 +5001,57 @@ void ImProcFunctions::impulsedenoisecam (CieImage* ncie, float **buffers[3]) } } -void ImProcFunctions::defringe (LabImage* lab) +void ImProcFunctions::defringe(LabImage* lab) { if (params->defringe.enabled && lab->W >= 8 && lab->H >= 8) { - PF_correct_RT (lab, params->defringe.radius, params->defringe.threshold); + PF_correct_RT(lab, params->defringe.radius, params->defringe.threshold); } } -void ImProcFunctions::defringecam (CieImage* ncie) +void ImProcFunctions::defringecam(CieImage* ncie) { if (params->defringe.enabled && ncie->W >= 8 && ncie->H >= 8) { - PF_correct_RTcam (ncie, params->defringe.radius, params->defringe.threshold); + PF_correct_RTcam(ncie, params->defringe.radius, params->defringe.threshold); } } -void ImProcFunctions::badpixcam (CieImage* ncie, double rad, int thr, int mode, float chrom, bool hotbad) +void ImProcFunctions::badpixcam(CieImage* ncie, double rad, int thr, int mode, float chrom, bool hotbad) { if (ncie->W >= 8 && ncie->H >= 8) { - Badpixelscam (ncie, rad, thr, mode, chrom, hotbad); + Badpixelscam(ncie, rad, thr, mode, chrom, hotbad); } } -void ImProcFunctions::badpixlab (LabImage* lab, double rad, int thr, float chrom) +void ImProcFunctions::badpixlab(LabImage* lab, double rad, int thr, float chrom) { if (lab->W >= 8 && lab->H >= 8) { - BadpixelsLab (lab, rad, thr, chrom); + BadpixelsLab(lab, rad, thr, chrom); } } -void ImProcFunctions::dirpyrequalizer (LabImage* lab, int scale) +void ImProcFunctions::dirpyrequalizer(LabImage* lab, int scale) { if (params->dirpyrequalizer.enabled && lab->W >= 8 && lab->H >= 8) { - float b_l = static_cast (params->dirpyrequalizer.hueskin.getBottomLeft()) / 100.f; - float t_l = static_cast (params->dirpyrequalizer.hueskin.getTopLeft()) / 100.f; - float t_r = static_cast (params->dirpyrequalizer.hueskin.getTopRight()) / 100.f; + float b_l = static_cast(params->dirpyrequalizer.hueskin.getBottomLeft()) / 100.f; + float t_l = static_cast(params->dirpyrequalizer.hueskin.getTopLeft()) / 100.f; + float t_r = static_cast(params->dirpyrequalizer.hueskin.getTopRight()) / 100.f; // if (params->dirpyrequalizer.algo=="FI") choice=0; // else if(params->dirpyrequalizer.algo=="LA") choice=1; if (params->dirpyrequalizer.gamutlab && params->dirpyrequalizer.skinprotect != 0) { constexpr float artifact = 4.f; constexpr float chrom = 50.f; - ImProcFunctions::badpixlab (lab, artifact / scale, 5, chrom); //for artifacts + ImProcFunctions::badpixlab(lab, artifact / scale, 5, chrom); //for artifacts } //dirpyrLab_equalizer(lab, lab, params->dirpyrequalizer.mult); - dirpyr_equalizer (lab->L, lab->L, lab->W, lab->H, lab->a, lab->b, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, b_l, t_l, t_r, scale); + dirpyr_equalizer(lab->L, lab->L, lab->W, lab->H, lab->a, lab->b, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, b_l, t_l, t_r, scale); } } -void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wid, int Hei, float minQ, float maxQ, unsigned int Iterates, int skip) +void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid, int Hei, float minQ, float maxQ, unsigned int Iterates, int skip) { if (!params->epd.enabled) { @@ -5135,7 +5063,7 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wi } */ float stren = params->epd.strength; - float edgest = params->epd.edgeStopping; + const float edgest = std::min(params->epd.edgeStopping, params->localContrast.enabled ? 3.0 : 4.0); float sca = params->epd.scale; float gamm = params->epd.gamma; float rew = params->epd.reweightingIterates; @@ -5150,7 +5078,7 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wi Qpro = maxQ; } - EdgePreservingDecomposition epd (Wid, Hei); + EdgePreservingDecomposition epd(Wid, Hei); #ifdef _OPENMP #pragma omp parallel for @@ -5161,7 +5089,7 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wi ncie->Q_p[i][j] = gamm * ncie->Q_p[i][j] / (Qpro); } - float Compression = expf (-stren); //This modification turns numbers symmetric around 0 into exponents. + float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. float DetailBoost = stren; if (stren < 0.0f) { @@ -5175,16 +5103,13 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wi //Jacques Desmis : always Iterates=5 for compatibility images between preview and output - epd.CompressDynamicRange (Qpr, sca / (float)skip, edgest, Compression, DetailBoost, Iterates, rew); + epd.CompressDynamicRange(Qpr, sca / (float)skip, edgest, Compression, DetailBoost, Iterates, rew); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. - float s = (1.0f + 38.7889f) * powf (Compression, 1.5856f) / (1.0f + 38.7889f * powf (Compression, 1.5856f)); -#ifndef _DEBUG + float s = (1.0f + 38.7889f) * powf(Compression, 1.5856f) / (1.0f + 38.7889f * powf(Compression, 1.5856f)); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,10) #endif -#endif - for (int i = 0; i < Hei; i++) for (int j = 0; j < Wid; j++) { ncie->Q_p[i][j] = (ncie->Q_p[i][j] * Qpro) / gamm; @@ -5230,71 +5155,35 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wi */ } - -//Map tones by way of edge preserving decomposition. Is this the right way to include source? -//#include "EdgePreservingDecomposition.cc" -void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip) +void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, unsigned int Iterates, int skip) { - //Hasten access to the parameters. -// EPDParams *p = (EPDParams *)(¶ms->epd); - //Enabled? Leave now if not. -// if(!p->enabled) return; - if (!params->epd.enabled) { - return; - } -/* - if (params->wavelet.enabled && params->wavelet.tmrs != 0) { - return; - } -*/ - float stren = params->epd.strength; - float edgest = params->epd.edgeStopping; - float sca = params->epd.scale; - float gamm = params->epd.gamma; - float rew = params->epd.reweightingIterates; + float stren = ((float)params->locallab.spots.at(sp).stren); + const float edgest = std::min(params->locallab.spots.at(sp).estop, params->localContrast.enabled ? 3.0 : 4.0); + + float sca = ((float)params->locallab.spots.at(sp).scaltm); + float gamm = ((float)params->locallab.spots.at(sp).gamma); + float satur = ((float)params->locallab.spots.at(sp).satur) / 100.f; + float rew = ((float)params->locallab.spots.at(sp).rewei); //Pointers to whole data and size of it. float *L = lab->L[0]; float *a = lab->a[0]; float *b = lab->b[0]; - size_t N = lab->W * lab->H; - EdgePreservingDecomposition epd (lab->W, lab->H); + unsigned int i, N = lab->W * lab->H; + int WW = lab->W ; +// int HH = lab->H ; + EdgePreservingDecomposition epd(lab->W, lab->H); //Due to the taking of logarithms, L must be nonnegative. Further, scale to 0 to 1 using nominal range of L, 0 to 15 bit. - float minL = FLT_MAX; - float maxL = 0.f; -#ifdef _OPENMP - #pragma omp parallel -#endif - { - float lminL = FLT_MAX; - float lmaxL = 0.f; -#ifdef _OPENMP - #pragma omp for -#endif - - for (size_t i = 0; i < N; i++) { - if (L[i] < lminL) { - lminL = L[i]; - } - - if (L[i] > lmaxL) { - lmaxL = L[i]; - } - } + float minL = L[0]; + float maxL = minL; #ifdef _OPENMP - #pragma omp critical + #pragma omp parallel for reduction(max:maxL) reduction(min:minL) schedule(dynamic,16) #endif - { - if (lminL < minL) { - minL = lminL; - } - - if (lmaxL > maxL) { - maxL = lmaxL; - } - } + for (i = 0; i < N; i++) { + minL = rtengine::min(minL, L[i]); + maxL = rtengine::max(maxL, L[i]); } if (minL > 0.0f) { @@ -5304,20 +5193,18 @@ void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip if (maxL == 0.f) { // avoid division by zero maxL = 1.f; } - + #ifdef _OPENMP #pragma omp parallel for #endif - - for (size_t i = 0; i < N; ++i) - //{L[i] = (L[i] - minL)/32767.0f; + for (i = 0; i < N; i++) { L[i] = (L[i] - minL) / maxL; L[i] *= gamm; } //Some interpretations. - float Compression = expf (-stren); //This modification turns numbers symmetric around 0 into exponents. + float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. float DetailBoost = stren; if (stren < 0.0f) { @@ -5326,7 +5213,7 @@ void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. if (Iterates == 0) { - Iterates = (unsigned int) (edgest * 15.0f); + Iterates = (unsigned int)(edgest * 15.0f); } /* Debuggery. Saves L for toying with outside of RT. @@ -5336,24 +5223,104 @@ void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip fwrite(L, N, sizeof(float), f); fclose(f);*/ - epd.CompressDynamicRange (L, sca / float (skip), edgest, Compression, DetailBoost, Iterates, rew); + epd.CompressDynamicRange(L, sca / float (skip), edgest, Compression, DetailBoost, Iterates, rew); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. - float s = (1.0f + 38.7889f) * powf (Compression, 1.5856f) / (1.0f + 38.7889f * powf (Compression, 1.5856f)); + float s = (1.0f + 38.7889f) * powf(Compression, 1.5856f) / (1.0f + 38.7889f * powf(Compression, 1.5856f)); + float sat = s + 0.3f * s * satur; + //printf("s=%f sat=%f \n", s, sat); + if(sat == 1.f) sat = 1.001f; #ifdef _OPENMP #pragma omp parallel for // removed schedule(dynamic,10) #endif - for (size_t ii = 0; ii < N; ++ii) { - a[ii] *= s; - b[ii] *= s; - L[ii] = L[ii] * maxL * (1.f / gamm) + minL; + for (unsigned int i = 0; i < N; i++) { + int x = i / WW; + int y = i - x * WW; + + tmp1->L[x][y] = L[i] * maxL * (1.f / gamm) + minL; + tmp1->a[x][y] = sat * a[i]; + tmp1->b[x][y] = sat * b[i]; + } } -void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double clip, - double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh) + + + +//Map tones by way of edge preserving decomposition. +void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) +{ + + if (!params->epd.enabled) { + return; + } + + const float stren = params->epd.strength; + const float edgest = std::min(params->epd.edgeStopping, params->localContrast.enabled ? 3.0 : 4.0); + const float sca = params->epd.scale; + const float gamm = params->epd.gamma; + const float rew = params->epd.reweightingIterates; + //Pointers to whole data and size of it. + float *L = lab->L[0]; + float *a = lab->a[0]; + float *b = lab->b[0]; + const size_t N = lab->W * lab->H; + + EdgePreservingDecomposition epd(lab->W, lab->H); + + //Due to the taking of logarithms, L must be nonnegative. Further, scale to 0 to 1 using nominal range of L, 0 to 15 bit. + float minL = L[0]; + float maxL = L[0]; +#ifdef _OPENMP + #pragma omp parallel for reduction(min:minL) reduction(max:maxL) +#endif + for (size_t i = 1; i < N; i++) { + minL = std::min(minL, L[i]); + maxL = std::max(maxL, L[i]); + } + + if (maxL == 0.f) { // black input => do nothing + return; + } + + minL = std::min(minL, 0.f); //Disable the shift if there are no negative numbers. I wish there were just no negative numbers to begin with. + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (size_t i = 0; i < N; ++i) { + L[i] = (L[i] - minL) * (gamm / maxL); + } + + //Some interpretations. + const float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. + const float DetailBoost = std::max(stren, 0.f); //Go with effect of exponent only if uncompressing. + + //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. + if (Iterates == 0) { + Iterates = edgest * 15.f; + } + + epd.CompressDynamicRange (L, sca / skip, edgest, Compression, DetailBoost, Iterates, rew); + + //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. + const float s = (1.f + 38.7889f) * std::pow(Compression, 1.5856f) / (1.f + 38.7889f * std::pow(Compression, 1.5856f)); + + maxL /= gamm; +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (size_t ii = 0; ii < N; ++ii) { + a[ii] *= s; + b[ii] *= s; + L[ii] = L[ii] * maxL + minL; + } +} + + +void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh) { float scale = 65536.0f; @@ -5365,7 +5332,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double float ave = 0.f; //find average luminance - histogram.getSumAndAverage (sum, ave); + histogram.getSumAndAverage(sum, ave); //find median of luminance size_t median = 0, count = histogram[0]; @@ -5432,12 +5399,12 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double // lodev = (lodev / (log(2.f) * losum)); // hidev = (hidev / (log(2.f) * hisum)); - if (octile[6] > log1p ((float)imax) / log2 (2.f)) { //if very overxposed image + if (octile[6] > log1p((float)imax) / log2(2.f)) { //if very overxposed image octile[6] = 1.5f * octile[5] - 0.5f * octile[4]; overex = 2; } - if (octile[7] > log1p ((float)imax) / log2 (2.f)) { //if overexposed + if (octile[7] > log1p((float)imax) / log2(2.f)) { //if overexposed octile[7] = 1.5f * octile[6] - 0.5f * octile[5]; overex = 1; } @@ -5459,7 +5426,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double // compute weighted average separation of octiles // for future use in contrast setting for (int i = 1; i < 6; i++) { - ospread += (octile[i + 1] - octile[i]) / max (0.5f, (i > 2 ? (octile[i + 1] - octile[3]) : (octile[3] - octile[i]))); + ospread += (octile[i + 1] - octile[i]) / max(0.5f, (i > 2 ? (octile[i + 1] - octile[3]) : (octile[3] - octile[i]))); } ospread /= 5.f; @@ -5519,24 +5486,24 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double //sets the mean or median at middle gray, and the amount that sets the estimated top //of the histogram at or near clipping. //float expcomp1 = (log(/*(median/ave)*//*(hidev/lodev)*/midgray*scale/(ave-shc+midgray*shc))+log((hidev/lodev)))/log(2.f); - float expcomp1 = (log (/*(median/ave)*//*(hidev/lodev)*/midgray * scale / (ave - shc + midgray * shc))) / log (2.f); + float expcomp1 = (log(/*(median/ave)*//*(hidev/lodev)*/midgray * scale / (ave - shc + midgray * shc))) / log(2.f); float expcomp2; if (overex == 0) { // image is not overexposed - expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * oct7 - oct6)) + log (scale / rawmax) / log (2.f) ); + expcomp2 = 0.5f * ((15.5f - histcompr - (2.f * oct7 - oct6)) + log(scale / rawmax) / log(2.f)); } else { - expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * octile[7] - octile[6])) + log (scale / rawmax) / log (2.f) ); + expcomp2 = 0.5f * ((15.5f - histcompr - (2.f * octile[7] - octile[6])) + log(scale / rawmax) / log(2.f)); } - if (fabs (expcomp1) - fabs (expcomp2) > 1.f) { //for great expcomp - expcomp = (expcomp1 * fabs (expcomp2) + expcomp2 * fabs (expcomp1)) / (fabs (expcomp1) + fabs (expcomp2)); + if (fabs(expcomp1) - fabs(expcomp2) > 1.f) { //for great expcomp + expcomp = (expcomp1 * fabs(expcomp2) + expcomp2 * fabs(expcomp1)) / (fabs(expcomp1) + fabs(expcomp2)); } else { expcomp = 0.5 * (double)expcomp1 + 0.5 * (double) expcomp2; //for small expcomp } - float gain = exp ((float)expcomp * log (2.f)); + float gain = exp((float)expcomp * log(2.f)); - float corr = sqrt (gain * scale / rawmax); + float corr = sqrt(gain * scale / rawmax); black = (int) shc * corr; @@ -5546,11 +5513,11 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double //which is a transcendental equation double comp = (gain * whiteclip / scale - 1.f) * 2.3f; // 2.3 instead of 2 to increase slightly comp hlcompr = 100.0 * comp / (max(0.0, expcomp) + 1.0); - hlcompr = max (0, min (100, hlcompr)); + hlcompr = max(0, min(100, hlcompr)); //now find brightness if gain didn't bring ave to midgray using //the envelope of the actual 'control cage' brightness curve for simplicity - float midtmp = gain * sqrt (median * ave) / scale; + float midtmp = gain * sqrt(median * ave) / scale; if (midtmp < 0.1f) { bright = (midgray - midtmp) * 15.f / (midtmp); @@ -5558,11 +5525,11 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double bright = (midgray - midtmp) * 15.f / (0.10833f - 0.0833f * midtmp); } - bright = 0.25 */*(median/ave)*(hidev/lodev)*/max (0, bright); + bright = 0.25 */*(median/ave)*(hidev/lodev)*/max(0, bright); //compute contrast that spreads the average spacing of octiles contr = (int) 50.0f * (1.1f - ospread); - contr = max (0, min (100, contr)); + contr = max(0, min(100, contr)); //take gamma into account double whiteclipg = (int) (CurveFactory::gamma2(whiteclip * static_cast(corr) / 65536.0) * 65536.0); @@ -5589,7 +5556,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double whiteclipg = CurveFactory::igamma2(whiteclipg / 65535.0) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter //correction with gamma - black = (int) ((65535 * black) / whiteclipg); + black = (int)((65535 * black) / whiteclipg); //expcomp = log(65535.0 / (whiteclipg)) / log(2.0); //diagnostics @@ -5645,14 +5612,14 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double expcomp = 12.0; } - bright = max (-100, min (bright, 100)); + bright = max(-100, min(bright, 100)); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_size) +double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size) { if (!fname.empty()) { rtengine::RawMetaDataLocation ri; @@ -5660,13 +5627,13 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si int w_thumb = -1, h_thumb = thumb_size; eSensorType sensorType = rtengine::ST_NONE; - Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, w_thumb, h_thumb, 1, FALSE); + Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw(fname, ri, sensorType, w_thumb, h_thumb, 1, FALSE); if (!thumb) { return 0.0; } - Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, w_raw, h_raw, 1, 1.0, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, FALSE); if (!raw) { delete thumb; @@ -5689,8 +5656,8 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si unsigned char* thumbGray; unsigned char* rawGray; - thumbGray = thumb->getGrayscaleHistEQ (width); - rawGray = raw->getGrayscaleHistEQ (width); + thumbGray = thumb->getGrayscaleHistEQ(width); + rawGray = raw->getGrayscaleHistEQ(width); if (!thumbGray || !rawGray) { if (thumbGray) { @@ -5707,10 +5674,10 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si } double dist_amount; - int dist_result = calcDistortion (thumbGray, rawGray, width, h_thumb, 1, dist_amount); + int dist_result = calcDistortion(thumbGray, rawGray, width, h_thumb, 1, dist_amount); if (dist_result == -1) { // not enough features found, try increasing max. number of features by factor 4 - calcDistortion (thumbGray, rawGray, width, h_thumb, 4, dist_amount); + calcDistortion(thumbGray, rawGray, width, h_thumb, 4, dist_amount); } delete thumbGray; @@ -5723,13 +5690,13 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si } } -void ImProcFunctions::rgb2lab (const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace) +void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace) { - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix ( workingSpace ); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(workingSpace); const float wp[3][3] = { - {static_cast (wprof[0][0]), static_cast (wprof[0][1]), static_cast (wprof[0][2])}, - {static_cast (wprof[1][0]), static_cast (wprof[1][1]), static_cast (wprof[1][2])}, - {static_cast (wprof[2][0]), static_cast (wprof[2][1]), static_cast (wprof[2][2])} + {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, + {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, + {static_cast(wprof[2][0]), static_cast(wprof[2][1]), static_cast(wprof[2][2])} }; const int W = src.getWidth(); @@ -5742,20 +5709,20 @@ void ImProcFunctions::rgb2lab (const Imagefloat &src, LabImage &dst, const Glib: for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { float X, Y, Z; - Color::rgbxyz (src.r (i, j), src.g (i, j), src.b (i, j), X, Y, Z, wp); + Color::rgbxyz(src.r(i, j), src.g(i, j), src.b(i, j), X, Y, Z, wp); //convert Lab - Color::XYZ2Lab (X, Y, Z, dst.L[i][j], dst.a[i][j], dst.b[i][j]); + Color::XYZ2Lab(X, Y, Z, dst.L[i][j], dst.a[i][j], dst.b[i][j]); } } } -void ImProcFunctions::lab2rgb (const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) +void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace) { - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix ( workingSpace ); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(workingSpace); const float wip[3][3] = { - {static_cast (wiprof[0][0]), static_cast (wiprof[0][1]), static_cast (wiprof[0][2])}, - {static_cast (wiprof[1][0]), static_cast (wiprof[1][1]), static_cast (wiprof[1][2])}, - {static_cast (wiprof[2][0]), static_cast (wiprof[2][1]), static_cast (wiprof[2][2])} + {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, + {static_cast(wiprof[1][0]), static_cast(wiprof[1][1]), static_cast(wiprof[1][2])}, + {static_cast(wiprof[2][0]), static_cast(wiprof[2][1]), static_cast(wiprof[2][2])} }; const int W = dst.getWidth(); @@ -5765,7 +5732,7 @@ void ImProcFunctions::lab2rgb (const LabImage &src, Imagefloat &dst, const Glib: for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - wipv[i][j] = F2V (wiprof[i][j]); + wipv[i][j] = F2V(wiprof[i][j]); } } @@ -5782,19 +5749,19 @@ void ImProcFunctions::lab2rgb (const LabImage &src, Imagefloat &dst, const Glib: for (; j < W - 3; j += 4) { vfloat X, Y, Z; vfloat R, G, B; - Color::Lab2XYZ (LVFU (src.L[i][j]), LVFU (src.a[i][j]), LVFU (src.b[i][j]), X, Y, Z); - Color::xyz2rgb (X, Y, Z, R, G, B, wipv); - STVFU (dst.r (i, j), R); - STVFU (dst.g (i, j), G); - STVFU (dst.b (i, j), B); + Color::Lab2XYZ(LVFU(src.L[i][j]), LVFU(src.a[i][j]), LVFU(src.b[i][j]), X, Y, Z); + Color::xyz2rgb(X, Y, Z, R, G, B, wipv); + STVFU(dst.r(i, j), R); + STVFU(dst.g(i, j), G); + STVFU(dst.b(i, j), B); } #endif for (; j < W; j++) { float X, Y, Z; - Color::Lab2XYZ (src.L[i][j], src.a[i][j], src.b[i][j], X, Y, Z); - Color::xyz2rgb (X, Y, Z, dst.r (i, j), dst.g (i, j), dst.b (i, j), wip); + Color::Lab2XYZ(src.L[i][j], src.a[i][j], src.b[i][j], X, Y, Z); + Color::xyz2rgb(X, Y, Z, dst.r(i, j), dst.g(i, j), dst.b(i, j), wip); } } } @@ -5828,9 +5795,10 @@ void ImProcFunctions::colorToningLabGrid(LabImage *lab, int xstart, int xend, in float b_scale = (params->colorToning.labgridBHigh - params->colorToning.labgridBLow) / factor / scaling; float b_base = params->colorToning.labgridBLow / scaling; -#ifdef _OPENMP + #ifdef _OPENMP #pragma omp parallel for if (multiThread) #endif + for (int y = ystart; y < yend; ++y) { for (int x = xstart; x < xend; ++x) { lab->a[y][x] += lab->L[y][x] * a_scale + a_base; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index d003df644..355b5d435 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -23,6 +23,11 @@ #include "coord2d.h" #include "gamutwarning.h" +#include "jaggedarray.h" +#include "pipettebuffer.h" +#include "array2D.h" +#include "imagesource.h" +#include namespace Glib { @@ -48,6 +53,14 @@ class DCPProfileApplyState; class FlatCurve; class FramesMetaData; class LensCorrection; +class LocCCmaskCurve; +class LocLLmaskCurve; +class LocHHmaskCurve; +class LocwavCurve; +class LocretigainCurve; +class LocretitransCurve; +class LocLHCurve; +class LocHHCurve; class NoiseCurve; class OpacityCurve; class PipetteBuffer; @@ -55,6 +68,7 @@ class ToneCurve; class WavCurve; class Wavblcurve; class WavOpacityCurveBY; +class WavOpacityCurveSH; class WavOpacityCurveRG; class WavOpacityCurveW; class WavOpacityCurveWL; @@ -70,9 +84,15 @@ namespace procparams class ProcParams; +struct DehazeParams; +struct FattalToneMappingParams; struct ColorManagementParams; struct DirPyrDenoiseParams; +struct LocalContrastParams; +struct LocallabParams; struct SharpeningParams; +struct SoftLightParams; +struct VibranceParams; struct VignettingParams; struct WaveletParams; @@ -84,11 +104,18 @@ class ImProcFunctions { cmsHTRANSFORM monitorTransform; std::unique_ptr gamutWarning; + Cairo::RefPtr locImage; const procparams::ProcParams* params; double scale; bool multiThread; + bool lastcutpast; + int lastcxbuf; + int lastcybuf; + int lastcount; + LabImage *spotbuffer; + void calcVignettingParams(int oW, int oH, const procparams::VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); void transformLuminanceOnly(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH); @@ -105,7 +132,6 @@ class ImProcFunctions bool needsLensfun() const; // static cmsUInt8Number* Mempro = NULL; - public: enum class Median { TYPE_3X3_SOFT, @@ -129,7 +155,7 @@ public: bool needsTransform(int oW, int oH, int rawRotationDeg, const FramesMetaData *metadata) const; bool needsPCVignetting() const; - + float calcGradientFactor (const struct grad_params& gp, int x, int y); void firstAnalysis(const Imagefloat* const working, const procparams::ProcParams ¶ms, LUTu & vhist16); void updateColorProfiles(const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, @@ -155,12 +181,16 @@ public: void moyeqt(Imagefloat* working, float &moyS, float &eqty); void luminanceCurve(LabImage* lold, LabImage* lnew, const LUTf &curve); + void ciecamloc_02float(int sp, LabImage* lab); + void ciecam_02float(CieImage* ncie, float adap, int pW, int pwb, LabImage* lab, const procparams::ProcParams* params, const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, float &d, float &dj, float &yb, int rtt, bool showSharpMask = false); void chromiLuminanceCurve(PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, const LUTf& acurve, const LUTf& bcurve, const LUTf& satcurve, const LUTf& satclcurve, const LUTf& clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLurve); - void vibrance(LabImage* lab); //Jacques' vibrance + void vibrance(LabImage* lab, const procparams::VibranceParams &vibranceParams, bool highlight, const Glib::ustring &workingProfile); //Jacques' vibrance + void softprocess(const LabImage* bufcolorig, array2D &buflight, /* float ** bufchro, float ** buf_a, float ** buf_b, */ float rad, int bfh, int bfw, double epsilmax, double epsilmin, float thres, int sk, bool multiThread); + void softproc(const LabImage* bufcolorig, const LabImage* bufcolfin, float rad, int bfh, int bfw, float epsilmax, float epsilmin, float thres, int sk, bool multiThread, int flag); // void colorCurve (LabImage* lold, LabImage* lnew); void sharpening(LabImage* lab, const procparams::SharpeningParams &sharpenParam, bool showMask = false); void sharpeningcam(CieImage* ncie, float** buffer, bool showMask = false); @@ -172,6 +202,8 @@ public: void Lanczos(const Imagefloat* src, Imagefloat* dst, float scale); void deconvsharpening(float** luminance, float** buffer, const float* const * blend, int W, int H, const procparams::SharpeningParams &sharpenParam, double Scale); + void deconvsharpeningloc(float** luminance, float** buffer, int W, int H, float** loctemp, int damp, double radi, int ite, int amo, int contrast, double blurrad, int sk); + void MLsharpen(LabImage* lab); // Manuel's clarity / sharpening void MLmicrocontrast(float** luminance, int W, int H); //Manuel's microcontrast void MLmicrocontrast(LabImage* lab); //Manuel's microcontrast @@ -186,50 +218,179 @@ public: void dirpyrequalizer(LabImage* lab, int scale); //Emil's wavelet - void EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params& cp, int W_L, int H_L, float max0, float min0); + void EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, const struct cont_params& cp, int W_L, int H_L, float max0); void CompressDR(float *Source, int W_L, int H_L, float Compression, float DetailBoost); - void Compresslevels2(float **Source, int W_L, int H_L, float compression, float detailattenuator, float thres, float mean, float maxp, float meanN, float maxN, float madL); - void ContrastResid(float * WavCoeffs_L0, struct cont_params &cp, int W_L, int H_L, float max0, float min0); + void Compresslevels(float **Source, int W_L, int H_L, float compression, float detailattenuator, float thres, float mean, float maxp, float meanN, float maxN, float madL); + void ContrastResid(float * WavCoeffs_L0, const struct cont_params &cp, int W_L, int H_L, float max0); void EPDToneMap(LabImage *lab, unsigned int Iterates = 0, int skip = 1); + void EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, unsigned int Iterates, int skip); void EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid, int Hei, float minQ, float maxQ, unsigned int Iterates = 0, int skip = 1); // pyramid denoise // procparams::DirPyrDenoiseParams dnparams; void dirpyr(LabImage* data_fine, LabImage* data_coarse, int level, LUTf &rangefn_L, LUTf &rangefn_ab, - int pitch, int scale, const int luma, int chroma); + int pitch, int scale, const int luma, int chroma); void idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, LUTf &rangefn_L, LUTf & nrwt_l, LUTf & nrwt_ab, int pitch, int scale, const int luma, const int chroma/*, LUTf & Lcurve, LUTf & abcurve*/); + //locallab Local adjustments + void maskcalccol(bool invmask, bool pde, int bfw, int bfh, int xstart, int ystart, int sk, int cx, int cy, LabImage* bufcolorig, LabImage* bufmaskblurcol, LabImage* originalmaskcol, LabImage* original, LabImage* reserved, int inv, struct local_params & lp, + float strumask, bool astool, + const LocCCmaskCurve & locccmasCurve, bool lcmasutili, + const LocLLmaskCurve & locllmasCurve, bool llmasutili, + const LocHHmaskCurve & lochhmasCurve, bool lhmasutili, const LocHHmaskCurve & lochhhmasCurve, bool lhhmasutili, + bool multiThread, bool enaMask, bool showmaske, bool deltaE, bool modmask, bool zero, bool modif, float chrom, float rad, float lap, float gamma, float slope, float blendm, int shado, float amountcd, float anchorcd, + const LUTf& lmasklocalcurve, bool localmaskutili, + const LocwavCurve & loclmasCurvecolwav, bool lmasutilicolwav, int level_bl, int level_hl, int level_br, int level_hr, + int shortcu, bool delt, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope); + + void deltaEforMask(float **rdE, int bfw, int bfh, LabImage* bufcolorig, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh); + void discrete_laplacian_threshold(float * data_out, const float * data_in, size_t nx, size_t ny, float t); + void rex_poisson_dct(float * data, size_t nx, size_t ny, double m); + void mean_dt(const float * data, size_t size, double& mean_p, double& dt_p); + float *cos_table(size_t size); + void normalize_mean_dt(float *data, const float *ref, size_t size, float mod, float sigm); + void retinex_pde(const float *datain, float * dataout, int bfw, int bfh, float thresh, float multy, float *dE, int show, int dEenable, int normalize); + void exposure_pde(float *dataor, float *datain, float * dataout, int bfw, int bfh, float thresh, float mod); + void fftw_convol_blur(float *input, float *output, int bfw, int bfh, float radius, int fftkern, int algo); + void fftw_convol_blur2(float **input2, float **output2, int bfw, int bfh, float radius, int fftkern, int algo); + void fftw_tile_blur(int GW, int GH, int tilssize , int max_numblox_W, int min_numblox_W, float **tmp1, int numThreads, double radius); + + void maskforretinex(int sp, int before, float ** luminance, float ** out, int W_L, int H_L, int skip, + const LocCCmaskCurve & locccmasretiCurve, bool &lcmasretiutili, const LocLLmaskCurve & locllmasretiCurve, bool &llmasretiutili, const LocHHmaskCurve & lochhmasretiCurve, bool & lhmasretiutili, + int llretiMask, bool retiMasktmap, bool retiMask, float rad, float lap, bool pde, float gamm, float slop, float chro, float blend, + LUTf & lmaskretilocalcurve, bool & localmaskretiutili, + LabImage * bufreti, LabImage * bufmask, LabImage * buforig, LabImage * buforigmas, bool multiThread, + bool delt, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh, float lumask); + + //3 functions from Alberto Griggio, adapted J.Desmis 2019 + void filmGrain(Imagefloat *rgb, int isogr, int strengr, int scalegr, int bfw, int bfh); + void log_encode(Imagefloat *rgb, const struct local_params & lp, bool multiThread, int bfw, int bfh); + void getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, float *blackev, float *whiteev, bool *Autogr, int fw, int fh, float xsta, float xend, float ysta, float yend, int SCALE); + + void MSRLocal(int call, int sp, bool fftw, int lum, float** reducDE, LabImage * bufreti, LabImage * bufmask, LabImage * buforig, LabImage * buforigmas, float** luminance, const float* const *originalLuminance, + const int width, const int height, int bfwr, int bfhr, const procparams::LocallabParams &loc, const int skip, const LocretigainCurve &locRETgainCcurve, const LocretitransCurve &locRETtransCcurve, + const int chrome, const int scall, const float krad, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, + const LocCCmaskCurve & locccmasretiCurve, bool &lcmasretiutili, const LocLLmaskCurve & locllmasretiCurve, bool &llmasretiutili, const LocHHmaskCurve & lochhmasretiCurve, bool & lhmasretiutili, int llretiMask, + LUTf & lmaskretilocalcurve, bool & localmaskretiutili, + LabImage * transformed, bool retiMasktmap, bool retiMask, + bool delt, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh, float lumask); + + + void calc_ref(int sp, LabImage* original, LabImage* transformed, int cx, int cy, int oW, int oH, int sk, double &huerefblur, double &chromarefblur, double &lumarefblur, double &hueref, double &chromaref, double &lumaref, double &sobelref, float &avg, const LocwavCurve & locwavCurveden, bool locwavdenutili); + void copy_ref(LabImage* spotbuffer, LabImage* original, LabImage* transformed, int cx, int cy, int sk, const struct local_params & lp, double &huerefspot, double &chromarefspot, double &lumarefspot); + void paste_ref(LabImage* spotbuffer, LabImage* transformed, int cx, int cy, int sk, const struct local_params & lp); + void Lab_Local(int call, int sp, float** shbuffer, LabImage* original, LabImage* transformed, LabImage* reserved, LabImage* lastorig, int cx, int cy, int oW, int oH, int sk, const LocretigainCurve& locRETgainCcurve, const LocretitransCurve &locRETtransCcurve, + const LUTf& lllocalcurve, bool locallutili, + const LUTf& cllocalcurve, bool localclutili, + const LUTf& lclocalcurve, bool locallcutili, + const LocLHCurve& loclhCurve, const LocHHCurve& lochhCurve, + const LUTf& lmasklocalcurve, bool localmaskutili, + const LUTf& lmaskexplocalcurve, bool localmaskexputili, + const LUTf& lmaskSHlocalcurve, bool localmaskSHutili, + const LUTf& lmaskviblocalcurve, bool localmaskvibutili, + const LUTf& lmasktmlocalcurve, bool localmasktmutili, + LUTf& lmaskretilocalcurve, bool localmaskretiutili, + const LUTf& lmaskcblocalcurve, bool localmaskcbutili, + const LUTf& lmaskbllocalcurve, bool localmaskblutili, + const LUTf& lmasklclocalcurve, bool localmasklcutili, + const LocCCmaskCurve& locccmasCurve, bool lcmasutili, const LocLLmaskCurve& locllmasCurve, bool llmasutili, const LocHHmaskCurve& lochhmasCurve, bool lhmasutili, const LocHHmaskCurve& lochhhmasCurve, bool lhhmasutili, + const LocCCmaskCurve& locccmasexpCurve, bool lcmasexputili, const LocLLmaskCurve& locllmasexpCurve, bool llmasexputili, const LocHHmaskCurve& lochhmasexpCurve, bool lhmasexputili, + const LocCCmaskCurve& locccmasSHCurve, bool lcmasSHutili, const LocLLmaskCurve& locllmasSHCurve, bool llmasSHutili, const LocHHmaskCurve& lochhmasSHCurve, bool lhmasSHutili, + const LocCCmaskCurve& locccmasvibCurve, bool lcmasvibutili, const LocLLmaskCurve& locllmasvibCurve, bool llmasvibutili, const LocHHmaskCurve& lochhmasvibCurve, bool lhmasvibutili, + const LocCCmaskCurve& locccmascbCurve, bool lcmascbutili, const LocLLmaskCurve& locllmascbCurve, bool llmascbutili, const LocHHmaskCurve& lochhmascbCurve, bool lhmascbutili, + const LocCCmaskCurve& locccmasretiCurve, bool lcmasretiutili, const LocLLmaskCurve& locllmasretiCurve, bool llmasretiutili, const LocHHmaskCurve& lochhmasretiCurve, bool lhmasretiutili, + const LocCCmaskCurve& locccmastmCurve, bool lcmastmutili, const LocLLmaskCurve& locllmastmCurve, bool llmastmutili, const LocHHmaskCurve& lochhmastmCurve, bool lhmastmutili, + const LocCCmaskCurve& locccmasblCurve, bool lcmasblutili, const LocLLmaskCurve& locllmasblCurve, bool llmasblutili, const LocHHmaskCurve& lochhmasblCurve, bool lhmasblutili, + const LocCCmaskCurve& locccmaslcCurve, bool lcmaslcutili, const LocLLmaskCurve& locllmaslcCurve, bool llmaslcutili, const LocHHmaskCurve& lochhmaslcCurve, bool lhmaslcutili, + const LocwavCurve& loclmasCurveblwav, bool lmasutiliblwav, + const LocwavCurve& loclmasCurvecolwav, bool lmasutilicolwav, + const LocwavCurve& locwavCurve, bool locwavutili, + const LocwavCurve& loclevwavCurve, bool loclevwavutili, + const LocwavCurve& locconwavCurve, bool locconwavutili, + const LocwavCurve& loccompwavCurve, bool loccompwavutili, + const LocwavCurve& loccomprewavCurve, bool loccomprewavutili, + const LocwavCurve& locwavCurveden, bool locwavdenutili, + const LocwavCurve& locedgwavCurve, bool locedgwavutili, + bool LHutili, bool HHutili, const LUTf& cclocalcurve, bool localcutili, const LUTf& rgblocalcurve, bool localrgbutili, bool localexutili, const LUTf& exlocalcurve, const LUTf& hltonecurveloc, const LUTf& shtonecurveloc, const LUTf& tonecurveloc, const LUTf& lightCurveloc, + double& huerefblur, double &chromarefblur, double& lumarefblur, double &hueref, double &chromaref, double &lumaref, double &sobelref, int &lastsav, + bool prevDeltaE, int llColorMask, int llColorMaskinv, int llExpMask, int llExpMaskinv, int llSHMask, int llSHMaskinv, int llvibMask, int lllcMask, int llsharMask, int llcbMask, int llretiMask, int llsoftMask, int lltmMask, int llblMask, + float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); + + void addGaNoise(LabImage *lab, LabImage *dst, const float mean, const float variance, const int sk); + void BlurNoise_Localold(int call, const struct local_params& lp, LabImage* original, LabImage* transformed, const LabImage* const tmp1, int cx, int cy); + void InverseBlurNoise_Local(LabImage * originalmask, float **bufchro, const struct local_params& lp, const float hueref, const float chromaref, const float lumaref, LabImage* original, LabImage* transformed, const LabImage* const tmp1, int cx, int cy, int sk); + void InverseReti_Local(const struct local_params& lp, const float hueref, const float chromaref, const float lumaref, LabImage* original, LabImage* transformed, const LabImage* const tmp1, int cx, int cy, int chro, int sk); + void BlurNoise_Local(LabImage* tmp1, LabImage * originalmask, float **bufchro, const float hueref, const float chromaref, const float lumaref, local_params& lp, LabImage* original, LabImage* transformed, int cx, int cy, int sk); + static void strcurv_data(std::string retistr, int *s_datc, int &siz); + void blendstruc(int bfw, int bfh, LabImage* bufcolorig, float radius, float stru, array2D & blend2, int sk, bool multiThread); + + void wavcontrast4(struct local_params& lp, float ** tmp, float ** tmpa, float ** tmpb, float contrast, float radblur, float radlevblur, int bfw, int bfh, int level_bl, int level_hl, int level_br, int level_hr, int sk, int numThreads, const LocwavCurve & locwavCurve, bool locwavutili, bool wavcurve, + const LocwavCurve & loclevwavCurve, bool loclevwavutili, bool wavcurvelev, + const LocwavCurve & locconwavCurve, bool locconwavutili, bool wavcurvecon, + const LocwavCurve & loccompwavCurve, bool loccompwavutili, bool wavcurvecomp, + const LocwavCurve & loccomprewavCurve, bool loccomprewavutili, bool wavcurvecompre, + const LocwavCurve & locedgwavCurve, bool locedgwavutili, + float sigm, float offs,int & maxlvl, float fatdet, float fatanch, float chromalev, float chromablu, bool blurlc, bool blurena, bool levelena, bool comprena, bool compreena, float compress, float thres); + + void wavcont(const struct local_params& lp, float ** tmp, wavelet_decomposition &wdspot, int level_bl, int maxlvl, + const LocwavCurve & loclevwavCurve, bool loclevwavutili, + const LocwavCurve & loccompwavCurve, bool loccompwavutili, + const LocwavCurve & loccomprewavCurve, bool loccomprewavutili, + float radlevblur, int process, float chromablu, float thres, float sigmadc, float deltad); + + void wavcbd(wavelet_decomposition &wdspot, int level_bl, int maxlvl, + const LocwavCurve& locconwavCurve, bool locconwavutili, float sigm, float offs, float chromalev, int sk); + + void transit_shapedetect2(int call, int senstype, const LabImage * bufexporig, const LabImage * bufexpfin, LabImage * originalmask, const float hueref, const float chromaref, const float lumaref, float sobelref, float meansobel, float ** blend2, struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk); + + void transit_shapedetect_retinex(int call, int senstype, LabImage * bufexporig, LabImage * bufmask, LabImage * buforigmas, float **buflight, float **bufchro, const float hueref, const float chromaref, const float lumaref, const struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk); + void transit_shapedetect(int senstype, const LabImage *bufexporig, LabImage * originalmask, float **bufchro, bool HHutili, const float hueref, const float chromaref, const float lumaref, float sobelref, float meansobel, float ** blend2, const struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk); + void exlabLocal(local_params& lp, int bfh, int bfw, LabImage* bufexporig, LabImage* lab, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve); + void Exclude_Local(float **deltaso, float hueref, float chromaref, float lumaref, float sobelref, float meansobel, const struct local_params & lp, const LabImage * original, LabImage * transformed, const LabImage * rsv, const LabImage * reserv, int cx, int cy, int sk); + + void DeNoise_Local(int call, const struct local_params& lp, LabImage* originalmask, int levred, float hueref, float lumaref, float chromaref, LabImage* original, LabImage* transformed, const LabImage &tmp1, int cx, int cy, int sk); + void DeNoise(int call, int del, float * slidL, float * slida, float * slidb, int aut, bool noiscfactiv, const struct local_params& lp, LabImage* originalmaskbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage* original, LabImage* transformed, int cx, int cy, int sk); + + + void fftw_denoise(int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom); + + void ColorLight_Local(float moddE, float powdE, int call, LabImage * bufcolorig, LabImage * originalmask, float **buflight, float **bufchro, float **bufchroslid, float ** bufhh, float ** buflightslid, bool &LHutili, bool &HHutili, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, float sobelref, float ** blend2, LUTf & lllocalcurve, const LocLHCurve & loclhCurve, const LocHHCurve & lochhCurve, LUTf & lightCurveloc, const local_params& lp, LabImage* original, LabImage* transformed, int cx, int cy, int sk); + void InverseColorLight_Local(bool tonequ, bool tonecurv, int sp, int senstype, struct local_params& lp, LabImage * originalmask, const LUTf& lightCurveloc, const LUTf& hltonecurveloc, const LUTf& shtonecurveloc, const LUTf& tonecurveloc, const LUTf& exlocalcurve, const LUTf& cclocalcurve, float adjustr, bool localcutili, const LUTf& lllocalcurve, bool locallutili, LabImage* original, LabImage* transformed, int cx, int cy, const float hueref, const float chromaref, const float lumaref, int sk); + void Sharp_Local(int call, float **loctemp, int senstype, const float hueref, const float chromaref, const float lumaref, local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk); + + void InverseSharp_Local(float **loctemp, const float hueref, const float lumaref, const float chromaref, local_params& lp, LabImage* original, LabImage* transformed, int cx, int cy, int sk); + +//Wavelet and denoise void Tile_calc(int tilesize, int overlap, int kall, int imwidth, int imheight, int &numtiles_W, int &numtiles_H, int &tilewidth, int &tileheight, int &tileWskip, int &tileHskip); - void ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const Wavblcurve & wavblcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, const LUTf &wavclCurve, int skip); + void ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const Wavblcurve & wavblcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveSH & waOpacityCurveSH, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, const LUTf &wavclCurve, int skip); - void WaveletcontAllL(LabImage * lab, float **varhue, float **varchrom, const wavelet_decomposition &WaveletCoeffs_L, const Wavblcurve & wavblcurve, - struct cont_params &cp, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* ChCurve, bool Chutili); - void WaveletcontAllLfinal(const wavelet_decomposition &WaveletCoeffs_L, const cont_params &cp, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL); - void WaveletcontAllAB(LabImage * lab, float **varhue, float **varchrom, const wavelet_decomposition &WaveletCoeffs_a, const Wavblcurve & wavblcurve, const WavOpacityCurveW & waOpacityCurveW, - struct cont_params &cp, const bool useChannelA, int skip, float *meanab, float *sigmaab); - void WaveletAandBAllAB(const wavelet_decomposition &WaveletCoeffs_a, const wavelet_decomposition &WaveletCoeffs_b, - const cont_params &cp, FlatCurve* hhcurve, bool hhutili); - void ContAllL(float **koeLi, float *maxkoeLi, bool lipschitz, int maxlvl, LabImage * lab, float **varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, - int W_L, int H_L, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* ChCurve, bool Chutili); - void finalContAllL(float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, const cont_params &cp, - int W_L, int H_L, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL); - void ContAllAB(LabImage * lab, int maxlvl, float **varhue, float **varchrom, float ** WavCoeffs_a, float * WavCoeffs_a0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, - int W_ab, int H_ab, const bool useChannelA); - void Evaluate2(const wavelet_decomposition &WaveletCoeffs_L, - float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN); - void Eval2(float ** WavCoeffs_L, int level, - int W_L, int H_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN); + void WaveletcontAllL(LabImage * lab, float **varhue, float **varchrom, wavelet_decomposition& WaveletCoeffs_L, const Wavblcurve & wavblcurve, + struct cont_params &cp, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveSH & waOpacityCurveSH, FlatCurve* ChCurve, bool Chutili); + void WaveletcontAllLfinal(wavelet_decomposition& WaveletCoeffs_L, const cont_params &cp, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL); + void WaveletcontAllAB(LabImage * lab, float **varhue, float **varchrom, wavelet_decomposition& WaveletCoeffs_a, const Wavblcurve & wavblcurve, const WavOpacityCurveW & waOpacityCurveW, + struct cont_params &cp, const bool useChannelA, int skip, float *meanab, float *sigmaab); + void WaveletAandBAllAB(wavelet_decomposition& WaveletCoeffs_a, wavelet_decomposition& WaveletCoeffs_b, + const cont_params &cp, FlatCurve* hhcurve, bool hhutili); + void ContAllL(float** koeLi, float maxkoeLi, bool lipschitz, int maxlvl, LabImage * lab, const float* const* varhue, const float* const* varchrom, float* const* WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, + int W_L, int H_L, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveSH & waOpacityCurveSH, FlatCurve* ChCurve, bool Chutili); + void finalContAllL(float* const* WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, const cont_params &cp, + int W_L, int H_L, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL); + void ContAllAB(LabImage * lab, int maxlvl, float **varhue, float **varchrom, float* const* WavCoeffs_a, float * WavCoeffs_a0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, + int W_ab, int H_ab, const bool useChannelA, float *meanab, float *sigmaab); + void Evaluate2(const wavelet_decomposition &WaveletCoeffs_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, int numThreads); + void Eval2(const float* const* WavCoeffs_L, int level, int W_L, int H_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, int numThreads); void calceffect(int level, float *mean, float *sigma, float *mea, float effect, float offs); - void Aver(float * HH_Coeffs, int datalen, float &averagePlus, float &averageNeg, float &max, float &min); - void Sigma(float * HH_Coeffs, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg); - void calckoe(float ** WavCoeffs_LL, const cont_params& cp, float ** koeLi, int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC = nullptr); - - void softproc2(const LabImage* bufcolorig, const LabImage* bufcolfin, float rad, int bfh, int bfw, double epsilmax, double epsilmin, float thres, int sk, bool multiThread, int flag); - + void Aver(const float* HH_Coeffs, int datalen, float &averagePlus, float &averageNeg, float &max, float &min, int numThreads); + void Sigma(const float* HH_Coeffs, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg, int numThreads); + void calckoe(const float* const* WavCoeffs_LL, float gradw, float tloww, float ** koeLi, int level, int dir, int W_L, int H_L, float edd, float &maxkoeLi, float **tmC = nullptr); void Median_Denoise(float **src, float **dst, int width, int height, Median medianType, int iterations, int numThreads, float **buffer = nullptr); void Median_Denoise(float **src, float **dst, float upperBound, int width, int height, Median medianType, int iterations, int numThreads, float **buffer = nullptr); @@ -243,18 +404,18 @@ public: const wavelet_decomposition &WaveletCoeffs_b, float **noisevarlum, float **noisevarchrom, float **noisevarhue, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float & minblueaut, int schoice, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, float &maxchred, float &maxchblue, float &minchred, float &minchblue, int &nb, float &chau, float &chred, float &chblue, bool denoiseMethodRgb); - bool WaveletDenoiseAllL(const wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels); - bool WaveletDenoiseAllAB(const wavelet_decomposition &WaveletCoeffs_L, const wavelet_decomposition &WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels); + bool WaveletDenoiseAllL(wavelet_decomposition& WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels); + bool WaveletDenoiseAllAB(wavelet_decomposition& WaveletCoeffs_L, wavelet_decomposition& WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels); - bool WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels); - bool WaveletDenoiseAll_BiShrinkAB(const wavelet_decomposition &WaveletCoeffs_L, const wavelet_decomposition &WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels); + bool WaveletDenoiseAll_BiShrinkL(wavelet_decomposition& WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge, int denoiseNestedLevels); + bool WaveletDenoiseAll_BiShrinkAB(wavelet_decomposition& WaveletCoeffs_L, wavelet_decomposition& WaveletCoeffs_ab, float *noisevarchrom, float madL[8][3], float *variC, int local, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, int denoiseNestedLevels); - void ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, float **buffer, int level, int dir, float *noisevarlum, float * madL, float * vari, int edge); - void ShrinkAllAB(const wavelet_decomposition &WaveletCoeffs_L, const wavelet_decomposition &WaveletCoeffs_ab, float **buffer, int level, int dir, + void ShrinkAllL(wavelet_decomposition& WaveletCoeffs_L, float **buffer, int level, int dir, float *noisevarlum, float * madL, float * vari, int edge); + void ShrinkAllAB(wavelet_decomposition& WaveletCoeffs_L, wavelet_decomposition& WaveletCoeffs_ab, float **buffer, int level, int dir, float *noisevarchrom, float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb, float * madL, float * variC, int local, float * madaab = nullptr, bool madCalculated = false); - void ShrinkAll_info(float ** WavCoeffs_a, float ** WavCoeffs_b, + void ShrinkAll_info(const float* const* WavCoeffs_a, const float* const* WavCoeffs_b, int W_ab, int H_ab, float **noisevarlum, float **noisevarchrom, float **noisevarhue, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, int schoice, int lvl, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, float &maxchred, float &maxchblue, float &minchred, float &minchblue, int &nb, float &chau, float &chred, float &chblue, bool denoiseMethodRgb); void Noise_residualAB(const wavelet_decomposition &WaveletCoeffs_ab, float &chresid, float &chmaxresid, bool denoiseMethodRgb); @@ -263,6 +424,7 @@ public: float MadRgb(const float * DataList, int datalen); // pyramid wavelet + void cbdl_local_temp(float ** src, float ** loctemp, int srcwidth, int srcheight, const float * mult, float kchro, const double dirpyrThreshold, const float mergeL, const float contres, const float blurcb, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale, bool multiThread); void dirpyr_equalizer(const float * const * src, float ** dst, int srcwidth, int srcheight, const float * const * l_a, const float * const * l_b, const double * mult, double dirpyrThreshold, double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet void dirpyr_equalizercam(const CieImage* ncie, float ** src, float ** dst, int srcwidth, int srcheight, const float * const * h_p, const float * const * C_p, const double * mult, const double dirpyrThreshold, const double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet void defringe(LabImage* lab); @@ -275,13 +437,15 @@ public: void Badpixelscam(CieImage * ncie, double radius, int thresh, int mode, float chrom, bool hotbad); void BadpixelsLab(LabImage * lab, double radius, int thresh, float chrom); - void dehaze(Imagefloat *rgb); - void ToneMapFattal02(Imagefloat *rgb); - void localContrast(LabImage *lab); + void dehaze(Imagefloat *rgb, const procparams::DehazeParams &dehazeParams); + void dehazeloc(Imagefloat *rgb, const procparams::DehazeParams &dehazeParams); + void ToneMapFattal02(Imagefloat *rgb, const procparams::FattalToneMappingParams &fatParams, int detail_level, int Lalone, float **Lum, int WW, int HH, int algo); + void localContrast(LabImage *lab, float **destination, const procparams::LocalContrastParams &localContrastParams, bool fftwlc, double scale); void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread); //void shadowsHighlights(LabImage *lab); void shadowsHighlights(LabImage *lab, bool ena, int labmode, int hightli, int shado, int rad, int scal, int hltonal, int shtonal); - void softLight(LabImage *lab); + + void softLight(LabImage *lab, const procparams::SoftLightParams &softLightParams); void labColorCorrectionRegions(LabImage *lab); Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true); diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc index 53939b5c0..7d715a9b0 100644 --- a/rtengine/ipdehaze.cc +++ b/rtengine/ipdehaze.cc @@ -41,6 +41,8 @@ #include "procparams.h" #include "rescale.h" #include "rt_math.h" +//#define BENCHMARK +#include "StopWatch.h" #include "../rtgui/options.h" @@ -58,15 +60,18 @@ float normalize(Imagefloat *rgb, bool multithread) #ifdef _OPENMP #pragma omp parallel for reduction(max:maxval) schedule(dynamic, 16) if (multithread) #endif + for (int y = 0; y < H; ++y) { for (int x = 0; x < W; ++x) { maxval = max(maxval, rgb->r(y, x), rgb->g(y, x), rgb->b(y, x)); } } + maxval = max(maxval * 2.f, 65535.f); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 16) if (multithread) #endif + for (int y = 0; y < H; ++y) { for (int x = 0; x < W; ++x) { rgb->r(y, x) /= maxval; @@ -74,6 +79,7 @@ float normalize(Imagefloat *rgb, bool multithread) rgb->b(y, x) /= maxval; } } + return maxval; } @@ -81,10 +87,12 @@ void restore(Imagefloat *rgb, float maxval, bool multithread) { const int W = rgb->getWidth(); const int H = rgb->getHeight(); + if (maxval > 0.f && maxval != 1.f) { #ifdef _OPENMP -# pragma omp parallel for if (multithread) + # pragma omp parallel for if (multithread) #endif + for (int y = 0; y < H; ++y) { for (int x = 0; x < W; ++x) { rgb->r(y, x) *= maxval; @@ -103,8 +111,10 @@ int get_dark_channel(const array2D &R, const array2D &G, const arr #ifdef _OPENMP #pragma omp parallel for if (multithread) #endif + for (int y = 0; y < H; y += patchsize) { const int pH = min(y + patchsize, H); + for (int x = 0; x < W; x += patchsize) { float minR = RT_INFINITY_F; float minG = RT_INFINITY_F; @@ -115,21 +125,26 @@ int get_dark_channel(const array2D &R, const array2D &G, const arr vfloat minBv = F2V(minB); #endif const int pW = min(x + patchsize, W); + for (int yy = y; yy < pH; ++yy) { int xx = x; #ifdef __SSE2__ + for (; xx < pW - 3; xx += 4) { minRv = vminf(minRv, LVFU(R[yy][xx])); minGv = vminf(minGv, LVFU(G[yy][xx])); minBv = vminf(minBv, LVFU(B[yy][xx])); } + #endif + for (; xx < pW; ++xx) { minR = min(minR, R[yy][xx]); minG = min(minG, G[yy][xx]); minB = min(minB, B[yy][xx]); } } + #ifdef __SSE2__ minR = min(minR, vhmin(minRv)); minG = min(minG, vhmin(minGv)); @@ -137,13 +152,14 @@ int get_dark_channel(const array2D &R, const array2D &G, const arr #endif float val = min(minR / ambient[0], minG / ambient[1], minB / ambient[2]); val = 1.f - strength * LIM01(val); + for (int yy = y; yy < pH; ++yy) { std::fill(dst[yy] + x, dst[yy] + pW, val); } } } - return (W / patchsize + ((W % patchsize) > 0)) * (H / patchsize + ((H % patchsize) > 0)); + return (W / patchsize + ((W % patchsize) > 0)) * (H / patchsize + ((H % patchsize) > 0)); } int get_dark_channel_downsized(const array2D &R, const array2D &G, const array2D &B, const array2D &dst, int patchsize, bool multithread) @@ -154,23 +170,27 @@ int get_dark_channel_downsized(const array2D &R, const array2D &G, #ifdef _OPENMP #pragma omp parallel for if (multithread) #endif + for (int y = 0; y < H; y += patchsize) { const int pH = min(y + patchsize, H); + for (int x = 0; x < W; x += patchsize) { float val = RT_INFINITY_F; const int pW = min(x + patchsize, W); + for (int xx = x; xx < pW; ++xx) { for (int yy = y; yy < pH; ++yy) { val = min(val, R[yy][xx], G[yy][xx], B[yy][xx]); } } + for (int yy = y; yy < pH; ++yy) { std::fill(dst[yy] + x, dst[yy] + pW, val); } } } - return (W / patchsize + ((W % patchsize) > 0)) * (H / patchsize + ((H % patchsize) > 0)); + return (W / patchsize + ((W % patchsize) > 0)) * (H / patchsize + ((H % patchsize) > 0)); } float estimate_ambient_light(const array2D &R, const array2D &G, const array2D &B, const array2D &dark, int patchsize, int npatches, float ambient[3]) @@ -181,6 +201,7 @@ float estimate_ambient_light(const array2D &R, const array2D &G, c float darklim = RT_INFINITY_F; { std::vector p; + for (int y = 0; y < H; y += patchsize) { for (int x = 0; x < W; x += patchsize) { if (!OOG(dark[y][x], 1.f - 1e-5f)) { @@ -188,6 +209,7 @@ float estimate_ambient_light(const array2D &R, const array2D &G, c } } } + const int pos = p.size() * 0.95; std::nth_element(p.begin(), p.begin() + pos, p.end()); darklim = p[pos]; @@ -213,17 +235,18 @@ float estimate_ambient_light(const array2D &R, const array2D &G, c { std::vector l; l.reserve(patches.size() * patchsize * patchsize); - + for (auto &p : patches) { - const int pW = min(p.first+patchsize, W); - const int pH = min(p.second+patchsize, H); - + const int pW = min(p.first + patchsize, W); + const int pH = min(p.second + patchsize, H); + for (int y = p.second; y < pH; ++y) { for (int x = p.first; x < pW; ++x) { l.push_back(R[y][x] + G[y][x] + B[y][x]); } } } + const int pos = l.size() * 0.95; std::nth_element(l.begin(), l.begin() + pos, l.end()); bright_lim = l[pos]; @@ -231,15 +254,17 @@ float estimate_ambient_light(const array2D &R, const array2D &G, c double rr = 0, gg = 0, bb = 0; int n = 0; + for (auto &p : patches) { - const int pW = min(p.first+patchsize, W); - const int pH = min(p.second+patchsize, H); - + const int pW = min(p.first + patchsize, W); + const int pH = min(p.second + patchsize, H); + for (int y = p.second; y < pH; ++y) { for (int x = p.first; x < pW; ++x) { float r = R[y][x]; float g = G[y][x]; float b = B[y][x]; + if (r + g + b >= bright_lim) { rr += static_cast(r); gg += static_cast(g); @@ -249,6 +274,7 @@ float estimate_ambient_light(const array2D &R, const array2D &G, c } } } + n = std::max(n, 1); ambient[0] = rr / n; ambient[1] = gg / n; @@ -275,9 +301,9 @@ void extract_channels(Imagefloat *img, array2D &r, array2D &g, arr } // namespace -void ImProcFunctions::dehaze(Imagefloat *img) +void ImProcFunctions::dehaze(Imagefloat *img, const DehazeParams &dehazeParams) { - if (!params->dehaze.enabled || params->dehaze.strength == 0.0) { + if (!dehazeParams.enabled || dehazeParams.strength == 0.0) { return; } @@ -285,7 +311,7 @@ void ImProcFunctions::dehaze(Imagefloat *img) const int W = img->getWidth(); const int H = img->getHeight(); - const float strength = LIM01(float(params->dehaze.strength) / 100.f * 0.9f); + const float strength = LIM01(float(dehazeParams.strength) / 100.f * 0.9f); if (settings->verbose) { std::cout << "dehaze: strength = " << strength << std::endl; @@ -356,11 +382,11 @@ void ImProcFunctions::dehaze(Imagefloat *img) std::cout << "dehaze: max distance is " << maxDistance << std::endl; } - const float depth = -float(params->dehaze.depth) / 100.f; + const float depth = -float(dehazeParams.depth) / 100.f; const float t0 = max(1e-3f, std::exp(depth * maxDistance)); const float teps = 1e-3f; - const bool luminance = params->dehaze.luminance; + const bool luminance = dehazeParams.luminance; const TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); #ifdef __SSE2__ const vfloat wsv[3] = {F2V(ws[1][0]), F2V(ws[1][1]),F2V(ws[1][2])}; @@ -389,7 +415,7 @@ void ImProcFunctions::dehaze(Imagefloat *img) // ... t >= tl to avoid negative values const vfloat tlv = onev - vminf(r / ambient0v, vminf(g / ambient1v, b / ambient2v)); const vfloat mtv = vmaxf(LVFU(dark[y][x]), vmaxf(tlv + tepsv, t0v)); - if (params->dehaze.showDepthMap) { + if (dehazeParams.showDepthMap) { const vfloat valv = vclampf(onev - mtv, ZEROV, onev) * cmaxChannelv; STVFU(img->r(y, x), valv); STVFU(img->g(y, x), valv); @@ -416,7 +442,7 @@ void ImProcFunctions::dehaze(Imagefloat *img) // ... t >= tl to avoid negative values const float tl = 1.f - min(r / ambient[0], g / ambient[1], b / ambient[2]); const float mt = max(dark[y][x], t0, tl + teps); - if (params->dehaze.showDepthMap) { + if (dehazeParams.showDepthMap) { img->r(y, x) = img->g(y, x) = img->b(y, x) = LIM01(1.f - mt) * maxChannel; } else if (luminance) { const float Y = Color::rgbLuminance(img->r(y, x), img->g(y, x), img->b(y, x), ws); @@ -434,4 +460,167 @@ void ImProcFunctions::dehaze(Imagefloat *img) } } + + +void ImProcFunctions::dehazeloc(Imagefloat *img, const DehazeParams &dehazeParams) +{ + //J.Desmis 12 2019 - this version derived from ART, is slower than the main from maximum 10% - probably use of SSE + //Probably Ingo could solved this problem in some times + BENCHFUN + if (!dehazeParams.enabled || dehazeParams.strength == 0.0) { + return; + } + + + + const float maxChannel = normalize(img, multiThread); + + const int W = img->getWidth(); + const int H = img->getHeight(); + const float strength = LIM01(float(std::abs(dehazeParams.strength)) / 100.f * 0.9f); + const bool add_haze = dehazeParams.strength < 0; + + if (settings->verbose) { + std::cout << "dehaze: strength = " << strength << std::endl; + } + + array2D dark(W, H); + + int patchsize = max(int(5 / scale), 2); + float ambient[3]; + float maxDistance = 0.f; + + { + array2D& R = dark; // R and dark can safely use the same buffer, which is faster and reduces memory allocations/deallocations + array2D G(W, H); + array2D B(W, H); + extract_channels(img, R, G, B, patchsize, 1e-1, multiThread); + + { + constexpr int sizecap = 200; + const float r = static_cast(W) / static_cast(H); + const int hh = r >= 1.f ? sizecap : sizecap / r; + const int ww = r >= 1.f ? sizecap * r : sizecap; + + if (W <= ww && H <= hh) { + // don't rescale small thumbs + array2D D(W, H); + const int npatches = get_dark_channel_downsized(R, G, B, D, 2, multiThread); + maxDistance = estimate_ambient_light(R, G, B, D, patchsize, npatches, ambient); + } else { + array2D RR(ww, hh); + array2D GG(ww, hh); + array2D BB(ww, hh); + rescaleNearest(R, RR, multiThread); + rescaleNearest(G, GG, multiThread); + rescaleNearest(B, BB, multiThread); + array2D D(ww, hh); + + const int npatches = get_dark_channel_downsized(RR, GG, BB, D, 2, multiThread); + maxDistance = estimate_ambient_light(RR, GG, BB, D, patchsize, npatches, ambient); + } + } + + if (min(ambient[0], ambient[1], ambient[2]) < 0.01f) { + if (settings->verbose) { + std::cout << "dehaze: no haze detected" << std::endl; + } + + restore(img, maxChannel, multiThread); + return; // probably no haze at all + } + + patchsize = max(max(W, H) / 600, 2); + + if (settings->verbose) { + std::cout << "dehaze: ambient light is " + << ambient[0] << ", " << ambient[1] << ", " << ambient[2] + << std::endl; + } + + get_dark_channel(R, G, B, dark, patchsize, ambient, true, multiThread, strength); + } + + + const int radius = patchsize * 4; + constexpr float epsilon = 1e-5f; + + array2D guideB(W, H, img->b.ptrs, ARRAY2D_BYREFERENCE); + guidedFilter(guideB, dark, dark, radius, epsilon, multiThread); + + if (settings->verbose) { + std::cout << "dehaze: max distance is " << maxDistance << std::endl; + } + + const float depth = -float(dehazeParams.depth) / 100.f; + const float teps = 1e-6f; + const float t0 = max(teps, std::exp(depth * maxDistance)); + + const bool luminance = dehazeParams.luminance; + const TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + + const float ambientY = Color::rgbLuminance(ambient[0], ambient[1], ambient[2], ws); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + + for (int y = 0; y < H; ++y) { + int x = 0; + for (; x < W; ++x) { + // ensure that the transmission is such that to avoid clipping... + float rgb[3] = { img->r(y, x), img->g(y, x), img->b(y, x) }; + // ... t >= tl to avoid negative values + float tl = 1.f - min(rgb[0] / ambient[0], rgb[1] / ambient[1], rgb[2] / ambient[2]); + // // ... t >= tu to avoid values > 1 + // float tu = t0 - teps; + // for (int c = 0; c < 3; ++c) { + // if (ambient[c] < 1) { + // tu = max(tu, (rgb[c] - ambient[c])/(1.f - ambient[c])); + // } + // } + float &ir = img->r(y, x); + float &ig = img->g(y, x); + float &ib = img->b(y, x); + const float mt = max(dark[y][x], t0, tl + teps); + + if (dehazeParams.showDepthMap) { + img->r(y, x) = img->g(y, x) = img->b(y, x) = LIM01(1.f - mt) * maxChannel; + } else if (luminance) { + float Y = Color::rgbLuminance(img->r(y, x), img->g(y, x), img->b(y, x), ws); + float YY = (Y - ambientY) / mt + ambientY; + + if (Y > 1e-5f) { + if (add_haze) { + YY = Y + Y - YY; + } + + float f = YY / Y; + ir = rgb[0] * f; + ig = rgb[1] * f; + ib = rgb[2] * f; + + } + } else { + float r = ((rgb[0] - ambient[0]) / mt + ambient[0]); + float g = ((rgb[1] - ambient[1]) / mt + ambient[1]); + float b = ((rgb[2] - ambient[2]) / mt + ambient[2]); + + if (add_haze) { + ir += (ir - r); + ig += (ig - g); + ib += (ib - b); + } else { + ir = r; + ig = g; + ib = b; + } + + } + } + } + + restore(img, maxChannel, multiThread); + +} + } // namespace rtengine diff --git a/rtengine/ipgrain.cc b/rtengine/ipgrain.cc new file mode 100644 index 000000000..b9079606a --- /dev/null +++ b/rtengine/ipgrain.cc @@ -0,0 +1,371 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2018 Alberto Griggio + * Small adaptation to Rawtherapee Locallab October 2019 + * 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 . + */ + +/* film grain emulation. + * Ported from darktable (src/iop/grain.c). Original copyright/license follows + */ +/* + This file is part of darktable, + copyright (c) 2010-2012 Henrik Andersson. + + darktable 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. + + darktable 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 darktable. If not, see . +*/ + +#include "imagefloat.h" +#include "improcfun.h" +#include "rt_math.h" + + +namespace rtengine { + +namespace { + +constexpr float GRAIN_LIGHTNESS_STRENGTH_SCALE = 0.15f; +constexpr float GRAIN_SCALE_FACTOR = 213.2f; + +constexpr int GRAIN_LUT_SIZE = 128; +constexpr float GRAIN_LUT_DELTA_MAX = 2.0f; +constexpr float GRAIN_LUT_DELTA_MIN = 0.0001f; +constexpr float GRAIN_LUT_PAPER_GAMMA = 1.0f; + + +const int grad3[12][3] = { { 1, 1, 0 }, + { -1, 1, 0 }, + { 1, -1, 0 }, + { -1, -1, 0 }, + { 1, 0, 1 }, + { -1, 0, 1 }, + { 1, 0, -1 }, + { -1, 0, -1 }, + { 0, 1, 1 }, + { 0, -1, 1 }, + { 0, 1, -1 }, + { 0, -1, -1 } }; + +const int permutation[] + = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, + 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, + 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, + 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, + 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, + 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, + 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, + 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, + 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, + 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, + 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, + 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; + + +class GrainEvaluator { +public: + GrainEvaluator(int offset_x, int offset_y, int full_width, int full_height, double scale): + ox(offset_x), + oy(offset_y), + fw(full_width), + fh(full_height), + scale(scale) + { + simplex_noise_init(); + constexpr float mb = 100.f; + evaluate_grain_lut(mb); + } + + void operator()(int isogr, int strengr, int scalegr, Imagefloat *lab, bool multithread) + { + const double strength = (strengr / 100.0); + const double octaves = 3; + const double wd = std::min(fw, fh); + const double zoom = (1.0 + 8 * (double(isogr) / GRAIN_SCALE_FACTOR) / 100.0) / 800.0; + const double s = std::max(scale / 3.0, 1.0) / (double(std::max(scalegr, 1)) / 100.0); + + const int W = lab->getWidth(); + const int H = lab->getHeight(); + float **lab_L = lab->g.ptrs; + +#ifdef _OPENMP +# pragma omp parallel for if (multithread) +#endif + for (int j = 0; j < H; ++j) { + double wy = oy + j; + double y = wy / wd; + for (int i = 0; i < W; ++i) { + double wx = ox + i; + double x = wx / wd; + double noise = simplex_2d_noise(x, y, octaves, 1.0, zoom) / s; + lab_L[j][i] += lut_lookup(noise * strength * GRAIN_LIGHTNESS_STRENGTH_SCALE, lab_L[j][i] / 32768.f); + } + } + } + +private: + void simplex_noise_init() + { + for(int i = 0; i < 512; i++) perm[i] = permutation[i & 255]; + } + + double dot(const int *g, double x, double y, double z) + { + return g[0] * x + g[1] * y + g[2] * z; + } + + float FASTFLOOR(float x) + { + return (x > 0 ? (int)(x) : (int)(x)-1); + } + + double simplex_noise(double xin, double yin, double zin) + { + double n0, n1, n2, n3; // Noise contributions from the four corners + // Skew the input space to determine which simplex cell we're in + const double F3 = 1.0 / 3.0; + const double s = (xin + yin + zin) * F3; // Very nice and simple skew factor for 3D + const int i = FASTFLOOR(xin + s); + const int j = FASTFLOOR(yin + s); + const int k = FASTFLOOR(zin + s); + const double G3 = 1.0 / 6.0; // Very nice and simple unskew factor, too + const double t = (i + j + k) * G3; + const double X0 = i - t; // Unskew the cell origin back to (x,y,z) space + const double Y0 = j - t; + const double Z0 = k - t; + const double x0 = xin - X0; // The x,y,z distances from the cell origin + const double y0 = yin - Y0; + const double z0 = zin - Z0; + // For the 3D case, the simplex shape is a slightly irregular tetrahedron. + // Determine which simplex we are in. + int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords + int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords + if(x0 >= y0) + { + if(y0 >= z0) + { + i1 = 1; // X Y Z order + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } + else if(x0 >= z0) + { + i1 = 1; // X Z Y order + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 0; + k2 = 1; + } + else + { + i1 = 0; // Z X Y order + j1 = 0; + k1 = 1; + i2 = 1; + j2 = 0; + k2 = 1; + } + } + else // x0localContrast.enabled) { + if (!localContrastParams.enabled) { return; } const int width = lab->W; const int height = lab->H; - const float a = params->localContrast.amount; - const float dark = params->localContrast.darkness; - const float light = params->localContrast.lightness; + const float a = localContrastParams.amount; + const float dark = localContrastParams.darkness; + const float light = localContrastParams.lightness; array2D buf(width, height); - const float sigma = params->localContrast.radius / scale; - + float sigma = localContrastParams.radius / scale; + //printf("wi%i he=%i am=%f da=%f li=%f si=%f\n", width, height, a, dark, light, sigma); + if(!fftwlc) { #ifdef _OPENMP - #pragma omp parallel if(multiThread) + #pragma omp parallel if(multiThread) #endif - gaussianBlur(lab->L, buf, width, height, sigma); - + gaussianBlur(lab->L, buf, width, height, sigma); + } else { + float kr = 1.f; + //emprical adjustment between FFTW radius and Gaussainblur + //under 50 ==> 10.f + //above 400 ==> 1.f + if(settings->fftwsigma == false) {//empirical formula + float ak = -9.f / 350.f; + float bk = 10.f - 50.f * ak; + kr = ak * sigma + bk; + if(sigma < 50.f) kr = 10.f; + if(sigma > 400.f) kr = 1.f; + } else {//sigma *= sigma + kr = sigma; + } + //OPENMP disabled + ImProcFunctions::fftw_convol_blur2(lab->L, buf, width, height, kr * sigma, 0, 0); + } #ifdef _OPENMP #pragma omp parallel for if(multiThread) #endif + for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { float bufval = (lab->L[y][x] - buf[y][x]) * a; @@ -61,7 +80,7 @@ void ImProcFunctions::localContrast(LabImage *lab) bufval *= (bufval > 0.f) ? light : dark; } - lab->L[y][x] = std::max(0.0001f, lab->L[y][x] + bufval); + destination[y][x] = LIM(lab->L[y][x] + bufval, 0.0001f, 32767.f); } } } diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc new file mode 100644 index 000000000..7b27712e1 --- /dev/null +++ b/rtengine/iplocallab.cc @@ -0,0 +1,14608 @@ +/* + * 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 . + * 2016 - 2020 Jacques Desmis + * 2016 - 2020 Ingo Weyrich + + */ +#include +#include + +#include "improcfun.h" +#include "colortemp.h" +#include "curves.h" +#include "gauss.h" +#include "iccstore.h" +#include "imagefloat.h" +#include "labimage.h" +#include "color.h" +#include "rt_math.h" +#include "jaggedarray.h" +#include "rt_algo.h" +#include "settings.h" +#include "../rtgui/options.h" + +#include "utils.h" +#ifdef _OPENMP +#include +#endif +#include "../rtgui/thresholdselector.h" +#include "imagesource.h" + +#include "cplx_wavelet_dec.h" +#include "ciecam02.h" + +//#define BENCHMARK +#include "StopWatch.h" +#include "guidedfilter.h" + + +#pragma GCC diagnostic warning "-Wall" +#pragma GCC diagnostic warning "-Wextra" + +namespace +{ +constexpr int limscope = 80; +constexpr int mSPsharp = 39; //minimum size Spot Sharp due to buildblendmask +constexpr int mSPwav = 32; //minimum size Spot Wavelet +constexpr int mDEN = 64; //minimum size Spot Denoise +constexpr int mSP = 5; //minimum size Spot +constexpr float MAXSCOPE = 1.25f; +constexpr float MINSCOPE = 0.025f; +constexpr int TS = 64; // Tile size +constexpr float epsilonw = 0.001f / (TS * TS); //tolerance +constexpr int offset = 25; // shift between tiles + +constexpr float clipLoc(float x) { + return rtengine::LIM(x, 0.f, 32767.f); +} + +constexpr float clipDE(float x) { + return rtengine::LIM(x, 0.3f, 1.f); +} + +constexpr float clipC(float x) { + return rtengine::LIM(x, -42000.f, 42000.f); +} + +constexpr float clipChro(float x) { + return rtengine::LIM(x, 0.f, 140.f); +} + +float softlig(float a, float b, float minc, float maxc) +{ + // as Photoshop + if (2.f * b <= maxc - minc) { + return a * (2.f * b + a * (maxc - 2.f * b)); + } else { + return 2.f * a * (maxc - b) + std::sqrt(rtengine::LIM(a, 0.f, 2.f)) * (2.f * b - maxc); + } +} + +float softlig3(float a, float b) +{ + // as w3C + if (2.f * b <= 1.f) { + return a - (1.f - 2.f * b) * a * (1.f - a); + } else { + if (4.f * a <= 1.f) { + return a + (2.f * b - 1.f) * (4.f * a * (4.f * a + 1.f) * (a - 1.f) + 7.f * a); + } else { + return a + (2.f * a - 1.f) * (std::sqrt(a) - a); + } + } +} + +float softlig2(float a, float b) +{ + // illusions.hu + return pow_F(b, pow_F(2.f, (2.f * (0.5f - a)))); +} + +constexpr float colburn(float a, float b) +{ + // w3C + return b == 0.f ? 0.f : 1.f - rtengine::min(1.f, (1.f - a) / b); +} + +constexpr float coldodge(float a, float b) +{ + // w3C + return b == 1.f ? 1.f : rtengine::min(1.f, a / (1.f - b)); +} + +float overlay(float a, float b, float minc, float maxc) +{ + if (2.f * b <= maxc - minc) { + return 2.f * b * a; + } else { + return maxc - 2.f * (1.f - a) * (maxc - b); + } +} + +constexpr float screen(float a, float b, float maxc) +{ + return 1.f - (1.f - a) * (maxc - b); +} + +constexpr float exclusion(float a, float b) +{ + return a + b - 2.f * a * b; +} + +void calcGammaLut(double gamma, double ts, LUTf &gammaLut) +{ + double pwr = 1.0 / gamma; + double gamm = gamma; + const double gamm2 = gamma; + rtengine::GammaValues g_a; + + if (gamm2 < 1.0) { + std::swap(pwr, gamm); + } + + rtengine::Color::calcGamma(pwr, ts, 0, g_a); // call to calcGamma with selected gamma and slope + + const double start = gamm2 < 1. ? g_a[2] : g_a[3]; + const double add = g_a[4]; + const double mul = 1.0 + g_a[4]; + + if (gamm2 < 1.) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 1024) +#endif + for (int i = 0; i < 65536; i++) { + const double x = rtengine::Color::igammareti(i / 65535.0, gamm, start, ts, mul, add); + gammaLut[i] = 0.5 * rtengine::CLIP(x * 65535.0); // CLIP avoid in some case extra values + } + } else { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 1024) +#endif + for (int i = 0; i < 65536; i++) { + const double x = rtengine::Color::gammareti(i / 65535.0, gamm, start, ts, mul, add); + gammaLut[i] = 0.5 * rtengine::CLIP(x * 65535.0); // CLIP avoid in some case extra values + } + } +} + +float calcLocalFactor(const float lox, const float loy, const float lcx, const float dx, const float lcy, const float dy, const float ach, const float gradient) +{ + //ellipse x2/a2 + y2/b2=1 + //transition ellipsoidal + const float kelip = dx / dy; + const float belip = rtengine::max(0.0001f, std::sqrt((rtengine::SQR((lox - lcx) / kelip) + rtengine::SQR(loy - lcy)))); //determine position ellipse ==> a and b + + //gradient allows differentiation between transition x and y + const float rapy = std::fabs((loy - lcy) / belip); + const float aelip = belip * kelip; + const float degrad = aelip / dx; + const float gradreal = gradient * rapy + 1.f; + const float ap = rtengine::RT_PI_F / (1.f - ach); + const float bp = rtengine::RT_PI_F - ap; + return pow(0.5f * (1.f + xcosf(degrad * ap + bp)), rtengine::SQR(gradreal)); // trigo cos transition +} + +float calcLocalFactorrect(const float lox, const float loy, const float lcx, const float dx, const float lcy, const float dy, const float ach, const float gradient) +{ + constexpr float eps = 0.0001f; + const float krap = std::fabs(dx / dy); + const float kx = lox - lcx; + const float ky = loy - lcy; + + float ref; + //gradient allows differentiation between transition x and y + if (std::fabs(kx / (ky + eps)) < krap) { + ref = std::sqrt(rtengine::SQR(dy) * (1.f + rtengine::SQR(kx / (ky + eps)))); + } else { + ref = std::sqrt(rtengine::SQR(dx) * (1.f + rtengine::SQR(ky / (kx + eps)))); + } + + const float rad = rtengine::max(eps, std::sqrt(rtengine::SQR(kx) + rtengine::SQR(ky))); + const float rapy = std::fabs((loy - lcy) / rad); + const float gradreal = gradient * rapy + 1.f; + + const float coef = rad / ref; + const float fact = (coef - 1.f) / (ach - 1.f); + return pow(fact, rtengine::SQR(gradreal)); +} + +float calcreducdE(float dE, float maxdE, float mindE, float maxdElim, float mindElim, float iterat, int limscope, int scope) +{ + if (scope > limscope) {//80 arbitrary value, if we change we must change limscope + if (dE > maxdElim) { + return 0.f; + } else if (dE > mindElim) { + const float reducdElim = std::pow((dE - maxdElim) / (mindElim - maxdElim), iterat); + const float aalim = (1.f - reducdElim) / 20.f; + const float bblim = 1.f - 100.f * aalim; + return aalim * scope + bblim; + } else { + return 1.f; + } + } else { + if (dE > maxdE) { + return 0.f; + } else if (dE > mindE) { + return std::pow((dE - maxdE) / (mindE - maxdE), iterat); + } else { + return 1.f; + } + } +} + +void deltaEforLaplace(float *dE, const float lap, int bfw, int bfh, rtengine::LabImage* bufexporig, const float hueref, const float chromaref, const float lumaref) +{ + + const float refa = chromaref * cos(hueref); + const float refb = chromaref * sin(hueref); + const float refL = lumaref; + float maxdE = 5.f + MAXSCOPE * lap; + + std::unique_ptr dEforLaplace(new float [bfw * bfh]); + float maxC = std::sqrt((rtengine::SQR(refa - bufexporig->a[0][0]) + rtengine::SQR(refb - bufexporig->b[0][0])) + rtengine::SQR(refL - bufexporig->L[0][0])) / 327.68f; +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxC) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + dEforLaplace[y * bfw + x] = std::sqrt((rtengine::SQR(refa - bufexporig->a[y][x]) + rtengine::SQR(refb - bufexporig->b[y][x])) + rtengine::SQR(refL - bufexporig->L[y][x])) / 327.68f; + maxC = rtengine::max(maxC, dEforLaplace[y * bfw + x]); + } + } + + if (maxdE > maxC) { + maxdE = maxC - 1.f; + } + + const float ade = 1.f / (maxdE - maxC); + const float bde = -ade * maxC; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + dE[y * bfw + x] = dEforLaplace[y * bfw + x] >= maxdE ? ade * dEforLaplace[y * bfw + x] + bde : 1.f; + } + } +} + +float calclight(float lum, const LUTf &lightCurveloc) +{ + return clipLoc(lightCurveloc[lum]); +} + +float calclightinv(float lum, float koef, const LUTf &lightCurveloc) +{ + return koef != -100.f ? clipLoc(lightCurveloc[lum]) : 0.f; +} + +float balancedeltaE(float kL) +{ + constexpr float mincurs = 0.3f; // minimum slider balan_ + constexpr float maxcurs = 1.7f; // maximum slider balan_ + constexpr float maxkab = 1.35; // 0.5 * (3 - 0.3) + constexpr float minkab = 0.65; // 0.5 * (3 - 1.7) + constexpr float abal = (maxkab - minkab) / (mincurs - maxcurs); + constexpr float bbal = maxkab - mincurs * abal; + return abal * kL + bbal; +} + +void SobelCannyLuma(float **sobelL, float **luma, int bfw, int bfh, float radius) +{ + // base of the process to detect shape in complement of deltaE + // use for calculate Spot reference + // and for structure of the shape + // actually , as the program don't use these function, I just create a simple "Canny" near of Sobel. This can be completed after with teta, etc. + array2D tmL(bfw, bfh); + + //inspired from Chen Guanghua Zhang Xiaolong + //Sobel Horizontal + constexpr float GX[3][3] = { + {1.f, 0.f, -1.f}, + {2.f, 0.f, -2.f}, + {1.f, 0.f, -1.f} + }; + + //Sobel Vertical + constexpr float GY[3][3] = { + {1.f, 2.f, 1.f}, + {0.f, 0.f, 0.f}, + {-1.f, -2.f, -1.f} + }; + + if (radius > 0.f) { + gaussianBlur(luma, tmL, bfw, bfh, rtengine::max(radius / 2.f, 0.5f)); + } else { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw ; x++) { + tmL[y][x] = luma[y][x]; + } + } + } + + for (int x = 0; x < bfw; x++) { + sobelL[0][x] = 0.f; + } + for (int y = 1; y < bfh - 1; y++) { + sobelL[y][0] = 0.f; + for (int x = 1; x < bfw - 1; x++) { + float sumXL = 0.f; + float sumYL = 0.f; + for (int i = -1; i < 2; i += 2) { + for (int j = -1; j < 2; j += 1) { + sumXL += GX[j + 1][i + 1] * tmL[y + i][x + j]; + sumYL += GY[j + 1][i + 1] * tmL[y + i][x + j]; + } + } + //Edge strength + //we can add if need teta = atan2 (sumYr, sumXr) + sobelL[y][x] = rtengine::min(std::sqrt(rtengine::SQR(sumXL) + rtengine::SQR(sumYL)), 32767.f); + } + sobelL[y][bfw - 1] = 0.f; + } + for (int x = 0; x < bfw; x++) { + sobelL[bfh - 1][x] = 0.f; + } +} + +} + +namespace rtengine + +{ +extern MyMutex *fftwMutex; + +using namespace procparams; + +struct local_params { + float yc, xc; + float lx, ly; + float lxL, lyT; + float transweak; + float transgrad; + float iterat; + float balance; + float balanceh; + int colorde; + int cir; + float thr; + float stru; + int chro, cont, sens, sensh, senscb, sensbn, senstm, sensex, sensexclu, sensden, senslc, senssf, senshs, senscolor; + float clarityml; + float contresid; + float blurcbdl; + bool deltaem; + float struco; + float strengrid; + float struexc; + float blendmacol; + float radmacol; + float chromacol; + float gammacol; + float slomacol; + float blendmalc; + float radmalc; + float chromalc; + float radmaexp; + float chromaexp; + float gammaexp; + float slomaexp; + float strmaexp; + float angmaexp; + float strexp; + float angexp; + float strSH; + float angSH; + float strcol; + float strcolab; + float strcolh; + float angcol; + float strvib; + float strvibab; + float strvibh; + float angvib; + float angwav; + float strwav; + + float strengthw; + float radiusw; + float detailw; + float gradw; + float tloww; + float thigw; + float edgw; + float basew; + + float anglog; + float strlog; + float softradiusexp; + float softradiuscol; + float softradiuscb; + float softradiusret; + float softradiustm; + float blendmaexp; + float radmaSH; + float blendmaSH; + float chromaSH; + float gammaSH; + float slomaSH; + float radmavib; + float blendmavib; + float chromavib; + float gammavib; + float slomavib; + float radmacb; + float blendmacb; + float chromacbm; + float gammacb; + float slomacb; + float radmatm; + float blendmatm; + float chromatm; + float gammatm; + float slomatm; + + float radmabl; + float blendmabl; + float chromabl; + float gammabl; + float slomabl; + + float struexp; + float blurexp; + float blurcol; + float blurcolmask; + float contcolmask; + float blurSH; + float ligh; + float lowA, lowB, highA, highB; + float lowBmerg, highBmerg, lowAmerg, highAmerg; + int shamo, shdamp, shiter, senssha, sensv; + float neig; + float strng; + float lap; + float lcamount; + double shrad; + double shblurr; + double rad; + double stren; + int it; + int guidb; + float strbl; + float epsb; + float trans; + float feath; + int dehaze; + int depth; + bool inv; + bool invex; + bool invsh; + bool curvact; + bool invrad; + bool invret; + bool equret; + bool equtm; + bool invshar; + bool actsp; + bool ftwlc; + bool ftwreti; + float str; + int qualmet; + int qualcurvemet; + int gridmet; + bool prevdE; + int showmaskcolmet; + int showmaskcolmetinv; + int showmaskexpmet; + int showmaskexpmetinv; + int showmaskSHmet; + int showmaskSHmetinv; + int showmaskvibmet; + int showmasklcmet; + int showmasksharmet; + int showmaskcbmet; + int showmaskretimet; + int showmasksoftmet; + int showmasktmmet; + int showmaskblmet; + bool fftbl; + float laplacexp; + float balanexp; + float linear; + int expmet; + int softmet; + int blurmet; + int blmet; + int smasktyp; + int chromet; + int shmeth; + int medmet; + int locmet; + float noiself; + float noiself0; + float noiself2; + float noiseldetail; + int detailthr; + int noiselequal; + float noisechrodetail; + float bilat; + float noiselc; + float noisecf; + float noisecc; + float mulloc[6]; + int mullocsh[5]; + int detailsh; + float threshol; + float chromacb; + float strengt; + float gamm; + float esto; + float scalt; + float rewe; + float amo; + bool colorena; + bool blurena; + bool tonemapena; + bool retiena; + bool sharpena; + bool lcena; + bool sfena; + bool cbdlena; + bool denoiena; + bool expvib; + bool exposena; + bool hsena; + bool vibena; + bool logena; + bool cut_past; + float past; + float satur; + int blac; + int shcomp; + int shadex; + int hlcomp; + int hlcompthr; + float expcomp; + float expchroma; + int excmet; + int mergemet; + int mergecolMethod; + float opacol; + int war; + float adjch; + int shapmet; + int edgwmet; + int neiwmet; + bool enaColorMask; + bool fftColorMask; + bool enaColorMaskinv; + bool enaExpMask; + bool enaExpMaskinv; + bool enaSHMask; + bool enaSHMaskinv; + bool enavibMask; + bool enalcMask; + bool enasharMask; + bool enacbMask; + bool enaretiMask; + bool enaretiMasktmap; + bool enatmMask; + bool enablMask; + int highlihs; + int shadowhs; + int radiushs; + int hltonalhs; + int shtonalhs; + int scalereti; + float sourcegray; + float targetgray; + float blackev; + float whiteev; + float detail; + int sensilog; + bool Autogray; + bool autocompute; + float baselog; + bool wavgradl; + bool edgwena; + bool lip3; + int daubLen; + float sigmadr; + float sigmabl; + float sigmaed; + float sigmalc; + float sigmalc2; + float residsha; + float residshathr; + float residhi; + float residhithr; + bool blwh; + +}; + +static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locallab, struct local_params& lp, bool prevDeltaE, int llColorMask, int llColorMaskinv, int llExpMask, int llExpMaskinv, int llSHMask, int llSHMaskinv, int llvibMask, int lllcMask, int llsharMask, int llcbMask, int llretiMask, int llsoftMask, int lltmMask, int llblMask, const LocwavCurve & locwavCurveden, bool locwavdenutili) +{ + int w = oW; + int h = oH; + int circr = locallab.spots.at(sp).circrad; + float streng = ((float)locallab.spots.at(sp).stren); + float gam = ((float)locallab.spots.at(sp).gamma); + float est = ((float)locallab.spots.at(sp).estop); + float scal_tm = ((float)locallab.spots.at(sp).scaltm); + float rewe = ((float)locallab.spots.at(sp).rewei); + float amo = ((float)locallab.spots.at(sp).amount); + float strlight = ((float)locallab.spots.at(sp).streng); + float strucc = locallab.spots.at(sp).struc; + float laplac = ((float)locallab.spots.at(sp).laplace); + float thre = locallab.spots.at(sp).thresh; + + if (thre > 8.f || thre < 0.f) {//to avoid artifacts if user does not clear cache with new settings. Can be suppressed after + thre = 2.f; + } + + double local_x = locallab.spots.at(sp).loc.at(0) / 2000.0; + double local_y = locallab.spots.at(sp).loc.at(2) / 2000.0; + double local_xL = locallab.spots.at(sp).loc.at(1) / 2000.0; + double local_yT = locallab.spots.at(sp).loc.at(3) / 2000.0; + double local_center_x = locallab.spots.at(sp).centerX / 2000.0 + 0.5; + double local_center_y = locallab.spots.at(sp).centerY / 2000.0 + 0.5; + float iterati = (float) locallab.spots.at(sp).iter; + float balanc = (float) locallab.spots.at(sp).balan; + float balanch = (float) locallab.spots.at(sp).balanh; + int colorde = (int) locallab.spots.at(sp).colorde; + + if (iterati > 4.f || iterati < 0.2f) {//to avoid artifacts if user does not clear cache with new settings Can be suppressed after + iterati = 2.f; + } + + float neigh = float (locallab.spots.at(sp).neigh); + float chromaPastel = float (locallab.spots.at(sp).pastels) / 100.0f; + float chromaSatur = float (locallab.spots.at(sp).saturated) / 100.0f; + int local_sensiv = locallab.spots.at(sp).sensiv; + int local_sensiex = locallab.spots.at(sp).sensiex; + + if (locallab.spots.at(sp).qualityMethod == "enh") { + lp.qualmet = 1; + } else if (locallab.spots.at(sp).qualityMethod == "enhden") { + lp.qualmet = 2; + } + + if (locallab.spots.at(sp).qualitycurveMethod == "none") { + lp.qualcurvemet = 0; + } else if (locallab.spots.at(sp).qualitycurveMethod == "std") { + lp.qualcurvemet = 1; + } + + if (locallab.spots.at(sp).gridMethod == "one") { + lp.gridmet = 0; + } else if (locallab.spots.at(sp).gridMethod == "two") { + lp.gridmet = 1; + } + + if (locallab.spots.at(sp).expMethod == "std") { + lp.expmet = 0; + } else if (locallab.spots.at(sp).expMethod == "pde") { + lp.expmet = 1; + } + + if (locallab.spots.at(sp).localcontMethod == "loc") { + lp.locmet = 0; + } else if (locallab.spots.at(sp).localcontMethod == "wav") { + lp.locmet = 1; + } + + lp.laplacexp = locallab.spots.at(sp).laplacexp; + lp.balanexp = locallab.spots.at(sp).balanexp; + lp.linear = locallab.spots.at(sp).linear; + + lp.fftColorMask = locallab.spots.at(sp).fftColorMask; + lp.prevdE = prevDeltaE; + lp.showmaskcolmet = llColorMask; + lp.showmaskcolmetinv = llColorMaskinv; + lp.showmaskexpmet = llExpMask; + lp.showmaskexpmetinv = llExpMaskinv; + lp.showmaskSHmet = llSHMask; + lp.showmaskSHmetinv = llSHMaskinv; + lp.showmaskvibmet = llvibMask; + lp.showmasklcmet = lllcMask; + lp.showmasksharmet = llsharMask; + lp.showmaskcbmet = llcbMask; + lp.showmaskretimet = llretiMask; + lp.showmasksoftmet = llsoftMask; + + lp.showmasktmmet = lltmMask; + lp.showmaskblmet = llblMask; + lp.enaColorMask = locallab.spots.at(sp).enaColorMask && llsoftMask == 0 && llColorMask == 0 && lllcMask == 0 && llsharMask == 0 && llExpMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0;// Exposure mask is deactivated if Color & Light mask is visible + lp.enaColorMaskinv = locallab.spots.at(sp).enaColorMask && llColorMaskinv == 0 && llsoftMask == 0 && lllcMask == 0 && llsharMask == 0 && llExpMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0;// Exposure mask is deactivated if Color & Light mask is visible + lp.enaExpMask = locallab.spots.at(sp).enaExpMask && llExpMask == 0 && llColorMask == 0 && llsoftMask == 0 && lllcMask == 0 && llsharMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0;// Exposure mask is deactivated if Color & Light mask is visible + lp.enaExpMaskinv = locallab.spots.at(sp).enaExpMask && llExpMaskinv == 0 && llColorMask == 0 && llsoftMask == 0 && lllcMask == 0 && llsharMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0;// Exposure mask is deactivated if Color & Light mask is visible + lp.enaSHMask = locallab.spots.at(sp).enaSHMask && llSHMask == 0 && llColorMask == 0 && llsoftMask == 0 && lllcMask == 0 && llsharMask == 0 && llExpMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0; + lp.enaSHMaskinv = locallab.spots.at(sp).enaSHMask && llSHMaskinv == 0 && lllcMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0; + lp.enacbMask = locallab.spots.at(sp).enacbMask && llcbMask == 0 && lllcMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0; + lp.enaretiMask = locallab.spots.at(sp).enaretiMask && lllcMask == 0 && llsharMask == 0 && llsoftMask == 0 && llretiMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llcbMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0; + lp.enatmMask = locallab.spots.at(sp).enatmMask && lltmMask == 0 && lllcMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && llblMask == 0 && llvibMask == 0; + lp.enablMask = locallab.spots.at(sp).enablMask && llblMask == 0 && lllcMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0; + lp.enavibMask = locallab.spots.at(sp).enavibMask && llvibMask == 0 && lllcMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llSHMask == 0; + lp.enalcMask = locallab.spots.at(sp).enalcMask && lllcMask == 0 && llcbMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0; + lp.enasharMask = lllcMask == 0 && llcbMask == 0 && llsharMask == 0 && llsoftMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0; + + // printf("llColorMask=%i lllcMask=%i llExpMask=%i llSHMask=%i llcbMask=%i llretiMask=%i lltmMask=%i llblMask=%i llvibMask=%i\n", llColorMask, lllcMask, llExpMask, llSHMask, llcbMask, llretiMask, lltmMask, llblMask, llvibMask); + if (locallab.spots.at(sp).softMethod == "soft") { + lp.softmet = 0; + } else if (locallab.spots.at(sp).softMethod == "reti") { + lp.softmet = 1; + } + + if (locallab.spots.at(sp).blMethod == "blur") { + lp.blmet = 0; + } else if (locallab.spots.at(sp).blMethod == "med") { + lp.blmet = 1; + } else if (locallab.spots.at(sp).blMethod == "guid") { + lp.blmet = 2; + } + + if (locallab.spots.at(sp).chroMethod == "lum") { + lp.chromet = 0; + } else if (locallab.spots.at(sp).chroMethod == "chr") { + lp.chromet = 1; + } else if (locallab.spots.at(sp).chroMethod == "all") { + lp.chromet = 2; + } + + if (locallab.spots.at(sp).shMethod == "std") { + lp.shmeth = 0; + } else if (locallab.spots.at(sp).shMethod == "tone") { + lp.shmeth = 1; + } + + + if (locallab.spots.at(sp).medMethod == "none") { + lp.medmet = -1; + } else if (locallab.spots.at(sp).medMethod == "33") { + lp.medmet = 0; + } else if (locallab.spots.at(sp).medMethod == "55") { + lp.medmet = 1; + } else if (locallab.spots.at(sp).medMethod == "77") { + lp.medmet = 2; + } else if (locallab.spots.at(sp).medMethod == "99") { + lp.medmet = 3; + } + + if (locallab.spots.at(sp).blurMethod == "norm") { + lp.blurmet = 0; + } else if (locallab.spots.at(sp).blurMethod == "inv") { + lp.blurmet = 1; + } + + if (locallab.spots.at(sp).showmaskblMethodtyp == "blur") { + lp.smasktyp = 0; + } else if (locallab.spots.at(sp).showmaskblMethodtyp == "nois") { + lp.smasktyp = 1; + } else if (locallab.spots.at(sp).showmaskblMethodtyp == "all") { + lp.smasktyp = 2; + } + + + if (locallab.spots.at(sp).spotMethod == "norm") { + lp.excmet = 0; + } else if (locallab.spots.at(sp).spotMethod == "exc") { + lp.excmet = 1; + } + + if (locallab.spots.at(sp).merMethod == "mone") { + lp.mergemet = 0; + } else if (locallab.spots.at(sp).merMethod == "mtwo") { + lp.mergemet = 1; + } else if (locallab.spots.at(sp).merMethod == "mthr") { + lp.mergemet = 2; + } else if (locallab.spots.at(sp).merMethod == "mfou") { + lp.mergemet = 3; + } else if (locallab.spots.at(sp).merMethod == "mfiv") { + lp.mergemet = 4; + } + + if (locallab.spots.at(sp).mergecolMethod == "one") { + lp.mergecolMethod = 0; + } else if (locallab.spots.at(sp).mergecolMethod == "two") { + lp.mergecolMethod = 1; + } else if (locallab.spots.at(sp).mergecolMethod == "thr") { + lp.mergecolMethod = 2; + } else if (locallab.spots.at(sp).mergecolMethod == "fou") { + lp.mergecolMethod = 3; + } else if (locallab.spots.at(sp).mergecolMethod == "fiv") { + lp.mergecolMethod = 4; + } else if (locallab.spots.at(sp).mergecolMethod == "six") { + lp.mergecolMethod = 5; + } else if (locallab.spots.at(sp).mergecolMethod == "sev") { + lp.mergecolMethod = 6; + } else if (locallab.spots.at(sp).mergecolMethod == "sev0") { + lp.mergecolMethod = 7; + } else if (locallab.spots.at(sp).mergecolMethod == "sev1") { + lp.mergecolMethod = 8; + } else if (locallab.spots.at(sp).mergecolMethod == "sev2") { + lp.mergecolMethod = 9; + } else if (locallab.spots.at(sp).mergecolMethod == "hei") { + lp.mergecolMethod = 10; + } else if (locallab.spots.at(sp).mergecolMethod == "nin") { + lp.mergecolMethod = 11; + } else if (locallab.spots.at(sp).mergecolMethod == "ten") { + lp.mergecolMethod = 12; + } else if (locallab.spots.at(sp).mergecolMethod == "ele") { + lp.mergecolMethod = 13; + } else if (locallab.spots.at(sp).mergecolMethod == "twe") { + lp.mergecolMethod = 14; + } else if (locallab.spots.at(sp).mergecolMethod == "thi") { + lp.mergecolMethod = 15; + } else if (locallab.spots.at(sp).mergecolMethod == "for") { + lp.mergecolMethod = 16; + } else if (locallab.spots.at(sp).mergecolMethod == "hue") { + lp.mergecolMethod = 17; + } else if (locallab.spots.at(sp).mergecolMethod == "sat") { + lp.mergecolMethod = 18; + } else if (locallab.spots.at(sp).mergecolMethod == "col") { + lp.mergecolMethod = 19; + } else if (locallab.spots.at(sp).mergecolMethod == "lum") { + lp.mergecolMethod = 20; + } + + if (locallab.spots.at(sp).localedgMethod == "fir") { + lp.edgwmet = 0; + } else if (locallab.spots.at(sp).localedgMethod == "sec") { + lp.edgwmet = 1; + } else if (locallab.spots.at(sp).localedgMethod == "thr") { + lp.edgwmet = 2; + } + + if (locallab.spots.at(sp).localneiMethod == "none") { + lp.neiwmet = -1; + lp.lip3 = false; + } else if (locallab.spots.at(sp).localneiMethod == "low") { + lp.neiwmet = 0; + lp.lip3 = true; + } else if (locallab.spots.at(sp).localneiMethod == "high") { + lp.lip3 = true; + lp.neiwmet = 1; + } + + + if (locallab.spots.at(sp).wavMethod == "D2") { + lp.daubLen = 4; + } else if (locallab.spots.at(sp).wavMethod == "D4") { + lp.daubLen = 6; + } else if (locallab.spots.at(sp).wavMethod == "D6") { + lp.daubLen = 8; + } else if (locallab.spots.at(sp).wavMethod == "D10") { + lp.daubLen = 12; + } else if (locallab.spots.at(sp).wavMethod == "D14") { + lp.daubLen = 16; + } + + + lp.edgwena = locallab.spots.at(sp).wavedg; + + lp.opacol = 0.01 * locallab.spots.at(sp).opacol; + + if (locallab.spots.at(sp).shape == "ELI") { + lp.shapmet = 0; + } else /*if (locallab.spots.at(sp).shape == "RECT")*/ { + lp.shapmet = 1; + } + + lp.denoiena = locallab.spots.at(sp).expblur; + + bool wavcurveden = false; + float local_noiself = 0.f; + float local_noiself0 = 0.f; + float local_noiself2 = 0.f; + float local_noiselc = 0.f; + + if (locwavCurveden && locwavdenutili) { + if (lp.denoiena) { + for (int i = 0; i < 500; i++) { + if (locwavCurveden[i] != 0.f) { + wavcurveden = true; + } + } + } + } + + if (wavcurveden) { + if (lp.denoiena) { + local_noiself0 = 250.f * locwavCurveden[0]; + local_noiself = 250.f * locwavCurveden[166]; + local_noiself2 = 250.f * locwavCurveden[323]; + local_noiselc = 200.f * locwavCurveden[500]; + } + } + + float local_noiseldetail = (float)locallab.spots.at(sp).noiselumdetail; + int local_noiselequal = locallab.spots.at(sp).noiselequal; + float local_noisechrodetail = (float)locallab.spots.at(sp).noisechrodetail; + int local_sensiden = locallab.spots.at(sp).sensiden; + float local_detailthr = (float)locallab.spots.at(sp).detailthr; + + float local_noisecf = ((float)locallab.spots.at(sp).noisechrof) / 10.f; + float local_noisecc = ((float)locallab.spots.at(sp).noisechroc) / 10.f; + float multi[6]; + + for (int y = 0; y < 6; y++) { + multi[y] = ((float) locallab.spots.at(sp).mult[y]); + } + + float multish[5]; + + for (int y = 0; y < 5; y++) { + multish[y] = ((float) locallab.spots.at(sp).multsh[y]); + } + + float thresho = ((float)locallab.spots.at(sp).threshold); + float chromcbdl = (float)locallab.spots.at(sp).chromacbdl; + + int local_chroma = locallab.spots.at(sp).chroma; + int local_sensi = locallab.spots.at(sp).sensi; + int local_sensibn = locallab.spots.at(sp).sensibn; + int local_sensitm = locallab.spots.at(sp).sensitm; + int local_sensiexclu = locallab.spots.at(sp).sensiexclu; + float structexclude = (float) locallab.spots.at(sp).structexclu; + int local_sensilc = locallab.spots.at(sp).sensilc; + int local_warm = locallab.spots.at(sp).warm; + int local_sensih = locallab.spots.at(sp).sensih; + int local_dehaze = locallab.spots.at(sp).dehaz; + int local_depth = locallab.spots.at(sp).depth; + int local_sensicb = locallab.spots.at(sp).sensicb; + float local_clarityml = (float) locallab.spots.at(sp).clarityml; + float local_contresid = (float) locallab.spots.at(sp).contresid; + int local_blurcbdl = 0; //(float) locallab.spots.at(sp).blurcbdl; + int local_contrast = locallab.spots.at(sp).contrast; + float local_lightness = (float) locallab.spots.at(sp).lightness; + float labgridALowloc = locallab.spots.at(sp).labgridALow; + float labgridBLowloc = locallab.spots.at(sp).labgridBLow; + float labgridBHighloc = locallab.spots.at(sp).labgridBHigh; + float labgridAHighloc = locallab.spots.at(sp).labgridAHigh; + float strengthgrid = (float) locallab.spots.at(sp).strengthgrid; + float labgridBLowlocmerg = locallab.spots.at(sp).labgridBLowmerg; + float labgridBHighlocmerg = locallab.spots.at(sp).labgridBHighmerg; + float labgridALowlocmerg = locallab.spots.at(sp).labgridALowmerg; + float labgridAHighlocmerg = locallab.spots.at(sp).labgridAHighmerg; + + float blendmasklc = ((float) locallab.spots.at(sp).blendmasklc) / 100.f ; + float radmasklc = ((float) locallab.spots.at(sp).radmasklc); + float chromasklc = ((float) locallab.spots.at(sp).chromasklc); + float structcolor = (float) locallab.spots.at(sp).structcol; + float blendmaskcolor = ((float) locallab.spots.at(sp).blendmaskcol) / 100.f ; + float radmaskcolor = ((float) locallab.spots.at(sp).radmaskcol); + float chromaskcolor = ((float) locallab.spots.at(sp).chromaskcol); + float gammaskcolor = ((float) locallab.spots.at(sp).gammaskcol); + float slomaskcolor = ((float) locallab.spots.at(sp).slomaskcol); + float blendmaskexpo = ((float) locallab.spots.at(sp).blendmaskexp) / 100.f ; + float radmaskexpo = ((float) locallab.spots.at(sp).radmaskexp); + float chromaskexpo = ((float) locallab.spots.at(sp).chromaskexp); + float gammaskexpo = ((float) locallab.spots.at(sp).gammaskexp); + float slomaskexpo = ((float) locallab.spots.at(sp).slomaskexp); + float strmaskexpo = ((float) locallab.spots.at(sp).strmaskexp); + float angmaskexpo = ((float) locallab.spots.at(sp).angmaskexp); + float strexpo = ((float) locallab.spots.at(sp).strexp); + float angexpo = ((float) locallab.spots.at(sp).angexp); + float strSH = ((float) locallab.spots.at(sp).strSH); + float angSH = ((float) locallab.spots.at(sp).angSH); + float strcol = ((float) locallab.spots.at(sp).strcol); + float strcolab = ((float) locallab.spots.at(sp).strcolab); + float strcolh = ((float) locallab.spots.at(sp).strcolh); + float angcol = ((float) locallab.spots.at(sp).angcol); + float strvib = ((float) locallab.spots.at(sp).strvib); + float strvibab = ((float) locallab.spots.at(sp).strvibab); + float strvibh = ((float) locallab.spots.at(sp).strvibh); + float angvib = ((float) locallab.spots.at(sp).angvib); + float strwav = ((float) locallab.spots.at(sp).strwav); + float angwav = ((float) locallab.spots.at(sp).angwav); + float strlog = ((float) locallab.spots.at(sp).strlog); + float anglog = ((float) locallab.spots.at(sp).anglog); + float softradiusexpo = ((float) locallab.spots.at(sp).softradiusexp); + float softradiuscolor = ((float) locallab.spots.at(sp).softradiuscol); + float softradiusreti = ((float) locallab.spots.at(sp).softradiusret); + float softradiustma = ((float) locallab.spots.at(sp).softradiustm); + float softradiuscbdl = ((float) locallab.spots.at(sp).softradiuscb); + float blendmaskSH = ((float) locallab.spots.at(sp).blendmaskSH) / 100.f ; + float radmaskSH = ((float) locallab.spots.at(sp).radmaskSH); + float chromaskSH = ((float) locallab.spots.at(sp).chromaskSH); + float gammaskSH = ((float) locallab.spots.at(sp).gammaskSH); + float slomaskSH = ((float) locallab.spots.at(sp).slomaskSH); + float blendmaskvib = ((float) locallab.spots.at(sp).blendmaskvib) / 100.f ; + float radmaskvib = ((float) locallab.spots.at(sp).radmaskvib); + float chromaskvib = ((float) locallab.spots.at(sp).chromaskvib); + float gammaskvib = ((float) locallab.spots.at(sp).gammaskvib); + float slomaskvib = ((float) locallab.spots.at(sp).slomaskvib); + float structexpo = (float) locallab.spots.at(sp).structexp; + float blurexpo = (float) locallab.spots.at(sp).blurexpde; + float blurcolor = (float) locallab.spots.at(sp).blurcolde; + float blurcolmask = (float) locallab.spots.at(sp).blurcol; + float contcolmask = (float) locallab.spots.at(sp).contcol; + float blurSH = (float) locallab.spots.at(sp).blurSHde; + float local_transit = locallab.spots.at(sp).transit; + float local_feather = locallab.spots.at(sp).feather; + float local_transitweak = (float)locallab.spots.at(sp).transitweak; + float local_transitgrad = (float)locallab.spots.at(sp).transitgrad; + float radius = (float) locallab.spots.at(sp).radius; + int itera = locallab.spots.at(sp).itera; + int guidbl = locallab.spots.at(sp).guidbl; + float epsbl = (float) locallab.spots.at(sp).epsbl; + float sharradius = LIM(locallab.spots.at(sp).sharradius, 0.42, 3.5); + float lcamount = ((float) locallab.spots.at(sp).lcamount); + lcamount = LIM01(lcamount); //to prevent crash with old pp3 integer + float sharblurr = LIM(locallab.spots.at(sp).sharblur, 0.2, 3.); //to prevent crash with old pp3 integer + int local_sensisha = locallab.spots.at(sp).sensisha; + int local_sharamount = locallab.spots.at(sp).sharamount; + int local_shardamping = locallab.spots.at(sp).shardamping; + int local_shariter = locallab.spots.at(sp).shariter; + bool inverse = locallab.spots.at(sp).invers; + bool curvacti = locallab.spots.at(sp).curvactiv; + bool acti = locallab.spots.at(sp).activlum; + bool cupas = false; // Provision + int local_sensisf = locallab.spots.at(sp).sensisf; + bool inverseex = locallab.spots.at(sp).inversex; + bool inversesh = locallab.spots.at(sp).inverssh; + bool equiltm = locallab.spots.at(sp).equiltm; + bool fftwlc = locallab.spots.at(sp).fftwlc; + bool fftwreti = locallab.spots.at(sp).fftwreti; + + bool equilret = locallab.spots.at(sp).equilret; + bool inverserad = false; // Provision + bool inverseret = locallab.spots.at(sp).inversret; + bool inversesha = locallab.spots.at(sp).inverssha; + double strength = (double) locallab.spots.at(sp).strength; + float str = (float)locallab.spots.at(sp).str; + int scaleret = (float)locallab.spots.at(sp).scalereti; + + int local_sensihs = locallab.spots.at(sp).sensihs; + int highhs = locallab.spots.at(sp).highlights; + int hltonahs = locallab.spots.at(sp).h_tonalwidth; + int shadhs = locallab.spots.at(sp).shadows; + int shtonals = locallab.spots.at(sp).s_tonalwidth; + int radhs = locallab.spots.at(sp).sh_radius; + float blendmaskcb = ((float) locallab.spots.at(sp).blendmaskcb) / 100.f ; + float radmaskcb = ((float) locallab.spots.at(sp).radmaskcb); + float chromaskcb = ((float) locallab.spots.at(sp).chromaskcb); + float gammaskcb = ((float) locallab.spots.at(sp).gammaskcb); + float slomaskcb = ((float) locallab.spots.at(sp).slomaskcb); + bool enaretiMasktm = locallab.spots.at(sp).enaretiMasktmap; + lp.enaretiMasktmap = enaretiMasktm; + float blendmasktm = ((float) locallab.spots.at(sp).blendmasktm) / 100.f ; + float radmasktm = ((float) locallab.spots.at(sp).radmasktm); + float chromasktm = ((float) locallab.spots.at(sp).chromasktm); + float gammasktm = ((float) locallab.spots.at(sp).gammasktm); + float slomasktm = ((float) locallab.spots.at(sp).slomasktm); + bool wavgradl = locallab.spots.at(sp).wavgradl; + + float blendmaskbl = ((float) locallab.spots.at(sp).blendmaskbl) / 100.f ; + float radmaskbl = ((float) locallab.spots.at(sp).radmaskbl); + float chromaskbl = ((float) locallab.spots.at(sp).chromaskbl); + float gammaskbl = ((float) locallab.spots.at(sp).gammaskbl); + float slomaskbl = ((float) locallab.spots.at(sp).slomaskbl); + bool fftbl = locallab.spots.at(sp).fftwbl; + + + lp.sourcegray = (float) locallab.spots.at(sp).sourceGray; + lp.targetgray = (float) locallab.spots.at(sp).targetGray; + lp.blackev = (float) locallab.spots.at(sp).blackEv; + lp.whiteev = (float) locallab.spots.at(sp).whiteEv; + lp.detail = locallab.spots.at(sp).detail; + lp.sensilog = locallab.spots.at(sp).sensilog; + lp.Autogray = locallab.spots.at(sp).Autogray; + lp.autocompute = locallab.spots.at(sp).autocompute; + lp.baselog = (float) locallab.spots.at(sp).baselog; + + lp.deltaem = locallab.spots.at(sp).deltae; + lp.scalereti = scaleret; + lp.cir = circr; + lp.actsp = acti; + lp.xc = w * local_center_x; + lp.yc = h * local_center_y; + lp.lx = w * local_x; + lp.ly = h * local_y; + lp.lxL = w * local_xL; + lp.lyT = h * local_yT; + lp.chro = local_chroma; + lp.struco = structcolor; + lp.strengrid = strengthgrid; + lp.blendmalc = blendmasklc; + lp.radmalc = radmasklc; + lp.chromalc = chromasklc; + lp.blendmacol = blendmaskcolor; + lp.radmacol = radmaskcolor; + lp.chromacol = chromaskcolor; + lp.gammacol = gammaskcolor; + lp.slomacol = slomaskcolor; + lp.radmaexp = radmaskexpo; + lp.chromaexp = chromaskexpo; + lp.gammaexp = gammaskexpo; + lp.slomaexp = slomaskexpo; + lp.strmaexp = strmaskexpo; + lp.angmaexp = angmaskexpo; + lp.strexp = strexpo; + lp.angexp = angexpo; + lp.strSH = strSH; + lp.angSH = angSH; + lp.strcol = strcol; + lp.strcolab = strcolab; + lp.strcolh = strcolh; + lp.angcol = angcol; + lp.strvib = strvib; + lp.strvibab = strvibab; + lp.strvibh = strvibh; + lp.angvib = angvib; + lp.strwav = strwav; + lp.angwav = angwav; + lp.strlog = strlog; + lp.anglog = anglog; + lp.softradiusexp = softradiusexpo; + lp.softradiuscol = softradiuscolor; + lp.softradiusret = softradiusreti; + lp.softradiuscb = softradiuscbdl; + lp.softradiustm = softradiustma; + lp.struexc = structexclude; + lp.blendmaexp = blendmaskexpo; + lp.blendmaSH = blendmaskSH; + lp.radmaSH = radmaskSH; + lp.chromaSH = chromaskSH; + lp.gammaSH = gammaskSH; + lp.slomaSH = slomaskSH; + lp.blendmavib = blendmaskvib; + lp.radmavib = radmaskvib; + lp.chromavib = chromaskvib; + lp.gammavib = gammaskvib; + lp.slomavib = slomaskvib; + lp.blendmacb = blendmaskcb; + lp.radmacb = radmaskcb; + lp.chromacbm = chromaskcb; + lp.gammacb = gammaskcb; + lp.slomacb = slomaskcb; + lp.blendmatm = blendmasktm; + lp.radmatm = radmasktm; + lp.chromatm = chromasktm; + lp.gammatm = gammasktm; + lp.slomatm = slomasktm; + lp.wavgradl = wavgradl; + + lp.strengthw = ((float) locallab.spots.at(sp).strengthw); + lp.radiusw = ((float) locallab.spots.at(sp).radiusw); + lp.detailw = ((float) locallab.spots.at(sp).detailw); + lp.gradw = ((float) locallab.spots.at(sp).gradw); + lp.tloww = ((float) locallab.spots.at(sp).tloww); + lp.thigw = ((float) locallab.spots.at(sp).thigw); + lp.edgw = ((float) locallab.spots.at(sp).edgw); + lp.basew = ((float) locallab.spots.at(sp).basew); + + lp.blendmabl = blendmaskbl; + lp.radmabl = radmaskbl; + lp.chromabl = chromaskbl; + lp.gammabl = gammaskbl; + lp.slomabl = slomaskbl; + lp.fftbl = fftbl; + lp.it = itera; + lp.guidb = guidbl; + lp.strbl = 0.01f * (float) locallab.spots.at(sp).strbl; + + lp.epsb = epsbl; + lp.struexp = structexpo; + lp.blurexp = blurexpo; + lp.blurcol = blurcolor; + lp.blurcolmask = blurcolmask; + lp.contcolmask = 0.01f * contcolmask; + lp.blurSH = blurSH; + lp.sens = local_sensi; + lp.sensh = local_sensih; + lp.dehaze = local_dehaze; + lp.depth = local_depth; + lp.senscb = local_sensicb; + lp.clarityml = local_clarityml; + lp.contresid = local_contresid; + lp.blurcbdl = local_blurcbdl; + lp.cont = local_contrast; + lp.ligh = local_lightness; + lp.lowA = labgridALowloc; + lp.lowB = labgridBLowloc; + lp.highB = labgridBHighloc; + lp.highA = labgridAHighloc; + lp.lowBmerg = labgridBLowlocmerg; + lp.highBmerg = labgridBHighlocmerg; + lp.lowAmerg = labgridALowlocmerg; + lp.highAmerg = labgridAHighlocmerg; + + lp.senssf = local_sensisf; + lp.strng = strlight; + lp.neig = neigh; + lp.lap = laplac; + + if (lp.ligh >= -2.f && lp.ligh <= 2.f) { + lp.ligh /= 5.f; + } + + lp.trans = local_transit; + lp.feath = local_feather; + lp.transweak = local_transitweak; + lp.transgrad = local_transitgrad; + lp.rad = radius; + lp.stren = strength; + lp.sensbn = local_sensibn; + lp.sensexclu = local_sensiexclu; + lp.senslc = local_sensilc; + lp.lcamount = lcamount; + lp.inv = inverse; + lp.invex = inverseex; + lp.invsh = inversesh; + lp.curvact = curvacti; + lp.invrad = inverserad; + lp.invret = inverseret; + lp.equret = equilret; + lp.equtm = equiltm; + lp.invshar = inversesha; + lp.str = str; + lp.shrad = sharradius; + lp.shblurr = sharblurr; + lp.senssha = local_sensisha; + lp.shamo = local_sharamount; + lp.shdamp = local_shardamping; + lp.shiter = local_shariter; + lp.iterat = iterati; + lp.balance = balanc; + lp.balanceh = balanch; + lp.colorde = colorde; + lp.thr = thre; + lp.stru = strucc; + lp.noiself = local_noiself; + lp.noiself0 = local_noiself0; + lp.noiself2 = local_noiself2; + lp.noiseldetail = local_noiseldetail; + lp.detailthr = local_detailthr; + lp.noiselequal = local_noiselequal; + lp.noisechrodetail = local_noisechrodetail; + lp.noiselc = local_noiselc; + lp.noisecf = local_noisecf; + lp.noisecc = local_noisecc; + lp.sensden = local_sensiden; + lp.bilat = locallab.spots.at(sp).bilateral; + lp.adjch = (float) locallab.spots.at(sp).adjblur; + lp.strengt = streng; + lp.gamm = gam; + lp.esto = est; + lp.scalt = scal_tm; + lp.rewe = rewe; + lp.senstm = local_sensitm; + lp.amo = amo; + + for (int y = 0; y < 6; y++) { + lp.mulloc[y] = LIM(multi[y], 0.f, 4.f);//to prevent crash with old pp3 integer + } + + for (int y = 0; y < 5; y++) { + lp.mullocsh[y] = multish[y]; + } + + lp.logena = locallab.spots.at(sp).explog; + + lp.detailsh = locallab.spots.at(sp).detailSH; + lp.threshol = thresho; + lp.chromacb = chromcbdl; + lp.expvib = locallab.spots.at(sp).expvibrance; + lp.colorena = locallab.spots.at(sp).expcolor && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0; // Color & Light tool is deactivated if Exposure mask is visible or SHMask + lp.blurena = locallab.spots.at(sp).expblur && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0; + lp.tonemapena = locallab.spots.at(sp).exptonemap && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llColorMask == 0 && llvibMask == 0; + lp.retiena = locallab.spots.at(sp).expreti && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0 && llSHMask == 0; + lp.lcena = locallab.spots.at(sp).expcontrast && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && llsharMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0 && llSHMask == 0; + lp.cbdlena = locallab.spots.at(sp).expcbdl && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llretiMask == 0 && lllcMask == 0 && llsharMask == 0 && lllcMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0; + lp.exposena = locallab.spots.at(sp).expexpose && llColorMask == 0 && llsoftMask == 0 && llSHMask == 0 && lllcMask == 0 && llsharMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0; // Exposure tool is deactivated if Color & Light mask SHmask is visible + lp.hsena = locallab.spots.at(sp).expshadhigh && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0;// Shadow Highlight tool is deactivated if Color & Light mask or SHmask is visible + lp.vibena = locallab.spots.at(sp).expvibrance && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && llSHMask == 0;// vibrance tool is deactivated if Color & Light mask or SHmask is visible + lp.sharpena = locallab.spots.at(sp).expsharp && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && llSHMask == 0 && llvibMask == 0; + lp.sfena = locallab.spots.at(sp).expsoft && llColorMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && llSHMask == 0 && llvibMask == 0; + lp.sensv = local_sensiv; + lp.past = chromaPastel; + lp.satur = chromaSatur; + + lp.cut_past = cupas; + lp.blac = locallab.spots.at(sp).black; + lp.shcomp = locallab.spots.at(sp).shcompr; + lp.shadex = locallab.spots.at(sp).shadex; + lp.hlcomp = locallab.spots.at(sp).hlcompr; + lp.hlcompthr = locallab.spots.at(sp).hlcomprthresh; + lp.expcomp = LIM(locallab.spots.at(sp).expcomp, -2.0, 4.0); //to prevent crash with Old pp3 with integer + //increase sensitivity for low values + float proexp = lp.expcomp; + if (std::fabs(proexp) < 0.6f) { + float interm = std::fabs(proexp) / 0.6f; + interm = SQR(interm); + lp.expcomp = proexp * interm; + } + lp.expchroma = locallab.spots.at(sp).expchroma / 100.; + lp.sensex = local_sensiex; + lp.war = local_warm; + lp.highlihs = highhs; + lp.shadowhs = shadhs; + lp.radiushs = radhs; + lp.hltonalhs = hltonahs; + lp.shtonalhs = shtonals; + lp.senshs = local_sensihs; + lp.ftwlc = fftwlc; + lp.ftwreti = fftwreti; + lp.sigmadr = locallab.spots.at(sp).sigmadr; + lp.sigmabl = locallab.spots.at(sp).sigmabl; + lp.sigmaed = locallab.spots.at(sp).sigmaed; + lp.sigmalc = locallab.spots.at(sp).sigmalc; + lp.sigmalc2 = locallab.spots.at(sp).sigmalc2; + lp.residsha = locallab.spots.at(sp).residsha; + lp.residshathr = locallab.spots.at(sp).residshathr; + lp.residhi = locallab.spots.at(sp).residhi; + lp.residhithr = locallab.spots.at(sp).residhithr; + lp.blwh = locallab.spots.at(sp).blwh; + lp.senscolor = (int) locallab.spots.at(sp).colorscope; + //replace scope color exposure vibrance shadows + lp.sens = lp.senscolor; + lp.sensv = lp.senscolor; + lp.senshs = lp.senscolor; + if(lp.expmet == 0){ + lp.sensex = lp.senscolor; + } +} + +static void calcTransitionrect(const float lox, const float loy, const float ach, const local_params& lp, int &zone, float &localFactor) +{ + zone = 0; + + if (lox >= lp.xc && lox < lp.xc + lp.lx) { + if (loy >= lp.yc && loy < lp.yc + lp.ly) { + if (lox < lp.xc + lp.lx * ach && loy < lp.yc + lp.ly * ach) { + zone = 2; + } else { + zone = 1; + localFactor = pow_F(calcLocalFactorrect(lox, loy, lp.xc, lp.lx, lp.yc, lp.ly, ach, lp.transgrad), lp.transweak); + } + } else if (loy < lp.yc && loy > lp.yc - lp.lyT) { + if (lox < lp.xc + lp.lx * ach && loy > lp.yc - lp.lyT * ach) { + zone = 2; + } else { + zone = 1; + localFactor = pow_F(calcLocalFactorrect(lox, loy, lp.xc, lp.lx, lp.yc, lp.lyT, ach, lp.transgrad), lp.transweak); + } + } + } else if (lox < lp.xc && lox > lp.xc - lp.lxL) { + if (loy <= lp.yc && loy > lp.yc - lp.lyT) { + if (lox > (lp.xc - lp.lxL * ach) && loy > (lp.yc - lp.lyT * ach)) { + zone = 2; + } else { + zone = 1; + localFactor = pow_F(calcLocalFactorrect(lox, loy, lp.xc, lp.lxL, lp.yc, lp.lyT, ach, lp.transgrad), lp.transweak); + } + } else if (loy > lp.yc && loy < lp.yc + lp.ly) { + if (lox > (lp.xc - lp.lxL * ach) && loy < (lp.yc + lp.ly * ach)) { + zone = 2; + } else { + zone = 1; + localFactor = pow_F(calcLocalFactorrect(lox, loy, lp.xc, lp.lxL, lp.yc, lp.ly, ach, lp.transgrad), lp.transweak); + } + } + } +} + +static void calcTransition(const float lox, const float loy, const float ach, const local_params& lp, int &zone, float &localFactor) +{ + // returns the zone (0 = outside selection, 1 = transition zone between outside and inside selection, 2 = inside selection) + // and a factor to calculate the transition in case zone == 1 + + zone = 0; + + if (lox >= lp.xc && lox < lp.xc + lp.lx) { + if (loy >= lp.yc && loy < lp.yc + lp.ly) { + const float zoneVal = SQR((lox - lp.xc) / (ach * lp.lx)) + SQR((loy - lp.yc) / (ach * lp.ly)); + zone = zoneVal < 1.f ? 2 : 0; + + if (!zone) { + zone = (zoneVal > 1.f && ((SQR((lox - lp.xc) / (lp.lx)) + SQR((loy - lp.yc) / (lp.ly))) < 1.f)) ? 1 : 0; + if (zone == 1) { + localFactor = pow_F(calcLocalFactor(lox, loy, lp.xc, lp.lx, lp.yc, lp.ly, ach, lp.transgrad), lp.transweak); + } + } + } else if (loy < lp.yc && loy > lp.yc - lp.lyT) { + const float zoneVal = SQR((lox - lp.xc) / (ach * lp.lx)) + SQR((loy - lp.yc) / (ach * lp.lyT)); + zone = zoneVal < 1.f ? 2 : 0; + + if (!zone) { + zone = (zoneVal > 1.f && ((SQR((lox - lp.xc) / (lp.lx)) + SQR((loy - lp.yc) / (lp.lyT))) < 1.f)) ? 1 : 0; + if (zone == 1) { + localFactor = pow_F(calcLocalFactor(lox, loy, lp.xc, lp.lx, lp.yc, lp.lyT, ach, lp.transgrad), lp.transweak); + } + } + } + } else if (lox < lp.xc && lox > lp.xc - lp.lxL) { + if (loy <= lp.yc && loy > lp.yc - lp.lyT) { + const float zoneVal = SQR((lox - lp.xc) / (ach * lp.lxL)) + SQR((loy - lp.yc) / (ach * lp.lyT)); + zone = zoneVal < 1.f ? 2 : 0; + + if (!zone) { + zone = (zoneVal > 1.f && ((SQR((lox - lp.xc) / (lp.lxL)) + SQR((loy - lp.yc) / (lp.lyT))) < 1.f)) ? 1 : 0; + if (zone == 1) { + localFactor = pow_F(calcLocalFactor(lox, loy, lp.xc, lp.lxL, lp.yc, lp.lyT, ach, lp.transgrad), lp.transweak); + } + } + } else if (loy > lp.yc && loy < lp.yc + lp.ly) { + const float zoneVal = SQR((lox - lp.xc) / (ach * lp.lxL)) + SQR((loy - lp.yc) / (ach * lp.ly)); + zone = zoneVal < 1.f ? 2 : 0; + + if (!zone) { + zone = (zoneVal > 1.f && ((SQR((lox - lp.xc) / (lp.lxL)) + SQR((loy - lp.yc) / (lp.ly))) < 1.f)) ? 1 : 0; + if (zone == 1) { + localFactor = pow_F(calcLocalFactor(lox, loy, lp.xc, lp.lxL, lp.yc, lp.ly, ach, lp.transgrad), lp.transweak); + } + } + } + } +} + +// Copyright 2018 Alberto Griggio +//J.Desmis 12 2019 - I will try to port a raw process in local adjustments +// I choose this one because, it is "new" +// Perhaps - probably no result, but perhaps ?? + +float find_gray(float source_gray, float target_gray) +{ + // find a base such that log2lin(base, source_gray) = target_gray + // log2lin is (base^source_gray - 1) / (base - 1), so we solve + // + // (base^source_gray - 1) / (base - 1) = target_gray, that is + // + // base^source_gray - 1 - base * target_gray + target_gray = 0 + // + // use a bisection method (maybe later change to Netwon) + + if (source_gray <= 0.f) { + return 0.f; + } + + const auto f = + [ = ](float x) -> float { + return std::pow(x, source_gray) - 1 - target_gray * x + target_gray; + }; + + // first find the interval we are interested in + + float lo = 1.f; + + while (f(lo) <= 0.f) { + lo *= 2.f; + } + + float hi = lo * 2.f; + + while (f(hi) >= 0.f) { + hi *= 2.f; + } + + if (std::isinf(hi)) { + return 0.f; + } + + // now search for a zero + for (int iter = 0; iter < 100; ++iter) { + float mid = lo + (hi - lo) / 2.f; + float v = f(mid); + + if (std::abs(v) < 1e-4f || (hi - lo) / lo <= 1e-4f) { + return mid; + } + + if (v > 0.f) { + lo = mid; + } else { + hi = mid; + } + } + + return 0.f; // not found +} + + +// basic log encoding taken from ACESutil.Lin_to_Log2, from +// https://github.com/ampas/aces-dev +// (as seen on pixls.us) +void ImProcFunctions::log_encode(Imagefloat *rgb, const struct local_params & lp, bool multiThread, int bfw, int bfh) +{ + /* J.Desmis 12 2019 + small adaptations to local adjustments + replace log2 by log(lp.baselog) allows diferentiation between low and high lights + */ + BENCHFUN + const float gray = lp.sourcegray / 100.f; + const float shadows_range = lp.blackev; + const float dynamic_range = lp.whiteev - lp.blackev; + const float noise = pow_F(2.f, -16.f); + const float log2 = xlogf(lp.baselog); + const float base = lp.targetgray > 1 && lp.targetgray < 100 && dynamic_range > 0 ? find_gray(std::abs(lp.blackev) / dynamic_range, lp.targetgray / 100.f) : 0.f; + const float linbase = rtengine::max(base, 0.f); + TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + + const auto apply = + [ = ](float x, bool scale = true) -> float { + if (scale) + { + x /= 65535.f; + } + + x = rtengine::max(x, noise); + x = rtengine::max(x / gray, noise); + x = rtengine::max((xlogf(x) / log2 - shadows_range) / dynamic_range, noise); + assert(x == x); + + if (linbase > 0.f) + { + x = xlog2lin(x, linbase); + } + + if (scale) + { + return x * 65535.f; + } else { + return x; + } + }; + + const auto norm = + [&](float r, float g, float b) -> float { + return Color::rgbLuminance(r, g, b, ws); + + // other possible alternatives (so far, luminance seems to work + // fine though). See also + // https://discuss.pixls.us/t/finding-a-norm-to-preserve-ratios-across-non-linear-operations + // + // MAX + //return max(r, g, b); + // + // Euclidean + //return std::sqrt(SQR(r) + SQR(g) + SQR(b)); + + // weighted yellow power norm from https://youtu.be/Z0DS7cnAYPk + // float rr = 1.22f * r / 65535.f; + // float gg = 1.20f * g / 65535.f; + // float bb = 0.58f * b / 65535.f; + // float rr4 = SQR(rr) * SQR(rr); + // float gg4 = SQR(gg) * SQR(gg); + // float bb4 = SQR(bb) * SQR(bb); + // float den = (rr4 + gg4 + bb4); + // if (den > 0.f) { + // return 0.8374319f * ((rr4 * rr + gg4 * gg + bb4 * bb) / den) * 65535.f; + // } else { + // return 0.f; + // } + }; + + const float detail = lp.detail; + const int W = rgb->getWidth(), H = rgb->getHeight(); + + if (detail == 0.f) {//no local contrast +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float r = rgb->r(y, x); + float g = rgb->g(y, x); + float b = rgb->b(y, x); + float m = norm(r, g, b); + + if (m > noise) { + float mm = apply(m); + float f = mm / m; + r *= f; + b *= f; + g *= f; + } + + assert(r == r); + assert(g == g); + assert(b == b); + + rgb->r(y, x) = r; + rgb->g(y, x) = g; + rgb->b(y, x) = b; + } + } + } else {//local contrast + + array2D Y(W, H); + { + constexpr float base_posterization = 20.f; + array2D Y2(W, H); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + Y2[y][x] = norm(rgb->r(y, x), rgb->g(y, x), rgb->b(y, x)) / 65535.f; + float l = xlogf(rtengine::max(Y2[y][x], 1e-9f)); + float ll = round(l * base_posterization) / base_posterization; + Y[y][x] = xexpf(ll); + assert(std::isfinite(Y[y][x])); + } + } + const float radius = rtengine::max(rtengine::max(bfw, W), rtengine::max(bfh, H)) / 30.f; + const float epsilon = 0.005f; + rtengine::guidedFilter(Y2, Y, Y, radius, epsilon, multiThread); + } + const float blend = detail; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float &r = rgb->r(y, x); + float &g = rgb->g(y, x); + float &b = rgb->b(y, x); + float t = Y[y][x]; + float t2; + + if (t > noise && (t2 = norm(r, g, b)) > noise) { + float c = apply(t, false); + float f = c / t; + // float t2 = norm(r, g, b); + float f2 = apply(t2) / t2; + f = intp(blend, f, f2); + assert(std::isfinite(f)); + r *= f; + g *= f; + b *= f; + assert(std::isfinite(r)); + assert(std::isfinite(g)); + assert(std::isfinite(b)); + } + } + } + } +} + +void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, float *blackev, float *whiteev, bool *Autogr, int fw, int fh, float xsta, float xend, float ysta, float yend, int SCALE) +{ + BENCHFUN +//adpatation to local adjustments Jacques Desmis 12 2019 + const PreviewProps pp(0, 0, fw, fh, SCALE); + + Imagefloat img(int(fw / SCALE + 0.5), int(fh / SCALE + 0.5)); + const ProcParams neutral; + imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw); + imgsrc->convertColorSpace(&img, params->icm, imgsrc->getWB()); + float minVal = RT_INFINITY; + float maxVal = -RT_INFINITY; + const float ec = std::pow(2.f, params->toneCurve.expcomp); + + constexpr float noise = 1e-5; + const int h = fh / SCALE; + const int w = fw / SCALE; + + const int hsta = ysta * h; + const int hend = yend * h; + + const int wsta = xsta * w; + const int wend = xend * w; + + double mean = 0.0; + int nc = 0; + for (int y = hsta; y < hend; ++y) { + for (int x = wsta; x < wend; ++x) { + const float r = img.r(y, x), g = img.g(y, x), b = img.b(y, x); + mean += static_cast(0.2126f * Color::gamma_srgb(r) + 0.7152f * Color::gamma_srgb(g) + 0.0722f * Color::gamma_srgb(b)); + nc++; + + const float m = rtengine::max(0.f, r, g, b) / 65535.f * ec; + if (m > noise) { + const float l = rtengine::min(r, g, b) / 65535.f * ec; + minVal = rtengine::min(minVal, l > noise ? l : m); + maxVal = rtengine::max(maxVal, m); + } + } + } + + //approximation sourcegray yb source = 0.4 * yb + + if (maxVal > minVal) { + const float log2 = std::log(2.f); + const float dynamic_range = -xlogf(minVal / maxVal) / log2; + + if (settings->verbose) { + std::cout << "AutoLog: min = " << minVal << ", max = " << maxVal + << ", DR = " << dynamic_range << std::endl; + } + + if (Autogr[sp]) { + double tot = 0.0; + int n = 0; + const float gmax = rtengine::min(maxVal / 2.f, 0.25f); + const float gmin = rtengine::max(minVal * std::pow(2.f, rtengine::max((dynamic_range - 1.f) / 2.f, 1.f)), 0.05f); + + if (settings->verbose) { + std::cout << " gray boundaries: " << gmin << ", " << gmax << std::endl; + } + + for (int y = ysta; y < yend; ++y) { + for (int x = wsta; x < wend; ++x) { + const float l = img.g(y, x) / 65535.f; + + if (l >= gmin && l <= gmax) { + tot += static_cast(l); + ++n; + } + } + } + + if (n > 0) { + sourceg[sp] = tot / n * 100.0; + + if (settings->verbose) { + std::cout << " computed gray point from " << n << " samples: " << sourceg[sp] << std::endl; + } + } else { + mean /= (nc * 65535.0); + float yb; + + if (mean < 0.15) { + yb = 3.0f; + } else if (mean < 0.3) { + yb = 5.0f; + } else if (mean < 0.4) { + yb = 10.0f; + } else if (mean < 0.45) { + yb = 15.0f; + } else if (mean < 0.5) { + yb = 18.0f; + } else if (mean < 0.55) { + yb = 23.0f; + } else if (mean < 0.6) { + yb = 30.0f; + } else { + yb = 45.f; + } + sourceg[sp] = 0.4f * yb; + if (settings->verbose) { + std::cout << " no samples found in range, resorting to Yb gray point value " << sourceg[sp] << std::endl; + } + } + } + + const float gray = sourceg[sp] / 100.f; + whiteev[sp] = xlogf(maxVal / gray) / log2; + blackev[sp] = whiteev[sp] - dynamic_range; + } +} + +void tone_eq(array2D &R, array2D &G, array2D &B, const struct local_params & lp, const Glib::ustring &workingProfile, double scale, bool multithread) +// adapted from the tone equalizer of darktable +/* + Copyright 2019 Alberto Griggio + Small adaptation to Local Adjustment 10 2019 Jacques Desmis + This file is part of darktable, + copyright (c) 2018 Aurelien Pierre. + + darktable 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. + + darktable 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 darktable. If not, see . +*/ + +{ + BENCHFUN + + const int W = R.width(); + const int H = R.height(); + array2D Y(W, H); + + const auto log2 = + [](float x) -> float { + static const float l2 = xlogf(2); + return xlogf(x) / l2; + }; + + const auto exp2 = + [](float x) -> float { + return pow_F(2.f, x); + }; + // Build the luma channels: band-pass filters with gaussian windows of + // std 2 EV, spaced by 2 EV + const float centers[12] = { + -18.0f, -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f, + -4.0f, -2.0f, 0.0f, 2.0f, 4.0f + }; + + const auto conv = [&](int v, float lo, float hi) -> float { + const float f = v < 0 ? lo : hi; + return exp2(float(v) / 100.f * f); + }; + const float factors[12] = { + conv(lp.mullocsh[0], 2.f, 3.f), // -18 EV + conv(lp.mullocsh[0], 2.f, 3.f), // -16 EV + conv(lp.mullocsh[0], 2.f, 3.f), // -14 EV + conv(lp.mullocsh[0], 2.f, 3.f), // -12 EV + conv(lp.mullocsh[0], 2.f, 3.f), // -10 EV + conv(lp.mullocsh[0], 2.f, 3.f), // -8 EV + conv(lp.mullocsh[1], 2.f, 3.f), // -6 EV + conv(lp.mullocsh[2], 2.5f, 2.5f), // -4 EV + conv(lp.mullocsh[3], 3.f, 2.f), // -2 EV + conv(lp.mullocsh[4], 3.f, 2.f), // 0 EV + conv(lp.mullocsh[4], 3.f, 2.f), // 2 EV + conv(lp.mullocsh[4], 3.f, 2.f) // 4 EV + }; + + TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(workingProfile); + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + Y[y][x] = Color::rgbLuminance(R[y][x], G[y][x], B[y][x], ws); + } + } + + int detail = LIM(lp.detailsh + 5, 0, 5); + int radius = detail / scale + 0.5; + float epsilon2 = 0.01f + 0.002f * rtengine::max(detail - 3, 0); + + if (radius > 0) { + rtengine::guidedFilterLog(10.f, Y, radius, epsilon2, multithread); + } + + if (lp.detailsh > 0) { + array2D Y2(W, H); + constexpr float base_epsilon = 0.02f; + constexpr float base_posterization = 5.f; + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float l = LIM(log2(rtengine::max(Y[y][x], 1e-9f)), centers[0], centers[11]); + float ll = round(l * base_posterization) / base_posterization; + Y2[y][x] = Y[y][x]; + Y[y][x] = exp2(ll); + } + } + + radius = 350.0 / scale; + epsilon2 = base_epsilon / float(6 - rtengine::min(lp.detailsh, 5)); + rtengine::guidedFilter(Y2, Y, Y, radius, epsilon2, multithread); + } + + const auto gauss = + [](float b, float x) -> float { + return xexpf((-SQR(x - b) / 4.0f)); + }; + + // For every pixel luminance, the sum of the gaussian masks + float w_sum = 0.f; + + for (int i = 0; i < 12; ++i) { + w_sum += gauss(centers[i], 0.f); + } + + const auto process_pixel = + [&](float y) -> float { + // convert to log space + const float luma = rtengine::max(log2(rtengine::max(y, 0.f)), -18.0f); + + // build the correction as the sum of the contribution of each + // luminance channel to current pixel + float correction = 0.0f; + + for (int c = 0; c < 12; ++c) + { + correction += gauss(centers[c], luma) * factors[c]; + } + + correction /= w_sum; + + return correction; + }; + + LUTf lut(65536); + + for (int i = 0; i < 65536; ++i) { + float y = float(i) / 65535.f; + float c = process_pixel(y); + lut[i] = c; + } + + +#ifdef __SSE2__ + vfloat vfactors[12]; + vfloat vcenters[12]; + + for (int i = 0; i < 12; ++i) { + vfactors[i] = F2V(factors[i]); + vcenters[i] = F2V(centers[i]); + } + + const auto vgauss = + [](vfloat b, vfloat x) -> vfloat { + static const vfloat fourv = F2V(4.f); + return xexpf((-SQR(x - b) / fourv)); + }; + + vfloat zerov = F2V(0.f); + vfloat vw_sum = F2V(w_sum); + + const vfloat noisev = F2V(-18.f); + const vfloat xlog2v = F2V(xlogf(2.f)); + + const auto vprocess_pixel = + [&](vfloat y) -> vfloat { + const vfloat luma = vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, noisev); + + vfloat correction = zerov; + + for (int c = 0; c < 12; ++c) + { + correction += vgauss(vcenters[c], luma) * vfactors[c]; + } + + correction /= vw_sum; + + return correction; + }; + + + vfloat v1 = F2V(1.f); + vfloat v65535 = F2V(65535.f); +#endif // __SSE2__ + + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; ++y) { + int x = 0; + + +#ifdef __SSE2__ + + for (; x < W - 3; x += 4) { + vfloat cY = LVFU(Y[y][x]); + vmask m = vmaskf_gt(cY, v1); + vfloat corr; + + if (_mm_movemask_ps((vfloat)m)) { + corr = vprocess_pixel(cY); + } else { + corr = lut[cY * v65535]; + } + + STVF(R[y][x], LVF(R[y][x]) * corr); + STVF(G[y][x], LVF(G[y][x]) * corr); + STVF(B[y][x], LVF(B[y][x]) * corr); + } + +#endif // __SSE2__ + + for (; x < W; ++x) { + float cY = Y[y][x]; + float corr = cY > 1.f ? process_pixel(cY) : lut[cY * 65535.f]; + R[y][x] *= corr; + G[y][x] *= corr; + B[y][x] *= corr; + } + } + +} + + +void ImProcFunctions::ciecamloc_02float(int sp, LabImage* lab) +{ + //be careful quasi duplicate with branch cat02wb + BENCHFUN + + int width = lab->W, height = lab->H; + float Yw; + Yw = 1.0f; + double Xw, Zw; + float f = 0.f, nc = 0.f, la, c = 0.f, xw, yw, zw, f2 = 1.f, c2 = 1.f, nc2 = 1.f, yb2; + float fl, n, nbb, ncb, aw; //d + float xwd, ywd, zwd, xws, yws, zws; + // int alg = 0; + double Xwout, Zwout; + double Xwsc, Zwsc; + + int tempo; + + if (params->locallab.spots.at(sp).warm > 0) { + tempo = 5000 - 30 * params->locallab.spots.at(sp).warm; + } else { + tempo = 5000 - 49 * params->locallab.spots.at(sp).warm; + } + + ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB + ColorTemp::temp2mulxyz(tempo, "Custom", Xwout, Zwout); + ColorTemp::temp2mulxyz(5000, "Custom", Xwsc, Zwsc); + + //viewing condition for surrsrc + f = 1.00f; + c = 0.69f; + nc = 1.00f; + //viewing condition for surround + f2 = 1.0f, c2 = 0.69f, nc2 = 1.0f; + //with which algorithm + // alg = 0; + + + xwd = 100.0 * Xwout; + zwd = 100.0 * Zwout; + ywd = 100.f; + + xws = 100.0 * Xwsc; + zws = 100.0 * Zwsc; + yws = 100.f; + + + yb2 = 18; + //La and la2 = ambiant luminosity scene and viewing + la = 400.f; + const float la2 = 400.f; + const float pilot = 2.f; + const float pilotout = 2.f; + + //algoritm's params + // const float rstprotection = 100. ;//- params->colorappearance.rstprotection; + LUTu hist16J; + LUTu hist16Q; + float yb = 18.f; + float d, dj; + + // const int gamu = 0; //(params->colorappearance.gamut) ? 1 : 0; + xw = 100.0 * Xw; + yw = 100.f * Yw; + zw = 100.0 * Zw; + float xw1 = xws, yw1 = yws, zw1 = zws, xw2 = xwd, yw2 = ywd, zw2 = zwd; + + float cz, wh, pfl; + Ciecam02::initcam1float(yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c); +// const float chr = 0.f; + const float pow1 = pow_F(1.64f - pow_F(0.29f, n), 0.73f); + float nj, nbbj, ncbj, czj, awj, flj; + Ciecam02::initcam2float(yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj); +#ifdef __SSE2__ + const float reccmcz = 1.f / (c2 * czj); +#endif + const float pow1n = pow_F(1.64f - pow_F(0.29f, nj), 0.73f); + +#ifdef __SSE2__ + int bufferLength = ((width + 3) / 4) * 4; // bufferLength has to be a multiple of 4 +#endif +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + // one line buffer per channel and thread + float Jbuffer[bufferLength] ALIGNED16; + float Cbuffer[bufferLength] ALIGNED16; + float hbuffer[bufferLength] ALIGNED16; + float Qbuffer[bufferLength] ALIGNED16; + float Mbuffer[bufferLength] ALIGNED16; + float sbuffer[bufferLength] ALIGNED16; +#endif +#ifdef _OPENMP + #pragma omp for schedule(dynamic, 16) +#endif + for (int i = 0; i < height; i++) { +#ifdef __SSE2__ + // vectorized conversion from Lab to jchqms + int k; + vfloat x, y, z; + vfloat J, C, h, Q, M, s; + + vfloat c655d35 = F2V(655.35f); + + for (k = 0; k < width - 3; k += 4) { + Color::Lab2XYZ(LVFU(lab->L[i][k]), LVFU(lab->a[i][k]), LVFU(lab->b[i][k]), x, y, z); + x = x / c655d35; + y = y / c655d35; + z = z / c655d35; + Ciecam02::xyz2jchqms_ciecam02float(J, C, h, + Q, M, s, F2V(aw), F2V(fl), F2V(wh), + x, y, z, + F2V(xw1), F2V(yw1), F2V(zw1), + F2V(c), F2V(nc), F2V(pow1), F2V(nbb), F2V(ncb), F2V(pfl), F2V(cz), F2V(d)); + STVF(Jbuffer[k], J); + STVF(Cbuffer[k], C); + STVF(hbuffer[k], h); + STVF(Qbuffer[k], Q); + STVF(Mbuffer[k], M); + STVF(sbuffer[k], s); + } + + for (; k < width; k++) { + float L = lab->L[i][k]; + float a = lab->a[i][k]; + float b = lab->b[i][k]; + float x, y, z; + //convert Lab => XYZ + Color::Lab2XYZ(L, a, b, x, y, z); + x = x / 655.35f; + y = y / 655.35f; + z = z / 655.35f; + float J, C, h, Q, M, s; + Ciecam02::xyz2jchqms_ciecam02float(J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, + c, nc, pow1, nbb, ncb, pfl, cz, d); + Jbuffer[k] = J; + Cbuffer[k] = C; + hbuffer[k] = h; + Qbuffer[k] = Q; + Mbuffer[k] = M; + sbuffer[k] = s; + } + +#endif // __SSE2__ + + for (int j = 0; j < width; j++) { + float J, C, h, Q, M, s; + +#ifdef __SSE2__ + // use precomputed values from above + J = Jbuffer[j]; + C = Cbuffer[j]; + h = hbuffer[j]; + Q = Qbuffer[j]; + M = Mbuffer[j]; + s = sbuffer[j]; +#else + float x, y, z; + float L = lab->L[i][j]; + float a = lab->a[i][j]; + float b = lab->b[i][j]; + float x1, y1, z1; + //convert Lab => XYZ + Color::Lab2XYZ(L, a, b, x1, y1, z1); + x = x1 / 655.35f; + y = y1 / 655.35f; + z = z1 / 655.35f; + //process source==> normal + Ciecam02::xyz2jchqms_ciecam02float(J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, + c, nc, pow1, nbb, ncb, pfl, cz, d); +#endif + float Jpro, Cpro, hpro, Qpro, Mpro, spro; + Jpro = J; + Cpro = C; + hpro = h; + Qpro = Q; + Mpro = M; + spro = s; + /* + */ + + + //retrieve values C,J...s + C = Cpro; + J = Jpro; + Q = Qpro; + M = Mpro; + h = hpro; + s = spro; + +#ifdef __SSE2__ + // write to line buffers + Jbuffer[j] = J; + Cbuffer[j] = C; + hbuffer[j] = h; +#else + float xx, yy, zz; + //process normal==> viewing + + Ciecam02::jch2xyz_ciecam02float(xx, yy, zz, + J, C, h, + xw2, yw2, zw2, + c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj); + x = xx * 655.35f; + y = yy * 655.35f; + z = zz * 655.35f; + float Ll, aa, bb; + //convert xyz=>lab + Color::XYZ2Lab(x, y, z, Ll, aa, bb); + lab->L[i][j] = Ll; + lab->a[i][j] = aa; + lab->b[i][j] = bb; +#endif + } + +#ifdef __SSE2__ + // process line buffers + float *xbuffer = Qbuffer; + float *ybuffer = Mbuffer; + float *zbuffer = sbuffer; + + for (k = 0; k < bufferLength; k += 4) { + Ciecam02::jch2xyz_ciecam02float(x, y, z, + LVF(Jbuffer[k]), LVF(Cbuffer[k]), LVF(hbuffer[k]), + F2V(xw2), F2V(yw2), F2V(zw2), + F2V(nc2), F2V(pow1n), F2V(nbbj), F2V(ncbj), F2V(flj), F2V(dj), F2V(awj), F2V(reccmcz)); + STVF(xbuffer[k], x * c655d35); + STVF(ybuffer[k], y * c655d35); + STVF(zbuffer[k], z * c655d35); + } + + // XYZ2Lab uses a lookup table. The function behind that lut is a cube root. + // SSE can't beat the speed of that lut, so it doesn't make sense to use SSE + for (int j = 0; j < width; j++) { + float Ll, aa, bb; + //convert xyz=>lab + Color::XYZ2Lab(xbuffer[j], ybuffer[j], zbuffer[j], Ll, aa, bb); + + lab->L[i][j] = Ll; + lab->a[i][j] = aa; + lab->b[i][j] = bb; + } + +#endif + } + + } +} + +void ImProcFunctions::softproc(const LabImage* bufcolorig, const LabImage* bufcolfin, float rad, int bfh, int bfw, float epsilmax, float epsilmin, float thres, int sk, bool multiThread, int flag) +{ + if (rad > 0.f) { + array2D ble(bfw, bfh); + array2D guid(bfw, bfh); + if (flag == 0) { + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + guid[ir][jr] = Color::L2Y(bufcolorig->L[ir][jr]) / 32768.f; + ble[ir][jr] = Color::L2Y(bufcolfin->L[ir][jr]) / 32768.f; + } + } + + const float aepsil = (epsilmax - epsilmin) / 90.f; + const float bepsil = epsilmax - 100.f * aepsil; + const float epsil = aepsil * 0.1f * rad + bepsil; + const float blur = 10.f / sk * (thres + 0.8f * rad); + + rtengine::guidedFilter(guid, ble, ble, blur, epsil, multiThread, 4); + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufcolfin->L[ir][jr] = Color::computeXYZ2LabY(32768.f * ble[ir][jr]); + } + } + } else if (flag == 1) { + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + ble[ir][jr] = bufcolfin->L[ir][jr] / 32768.f; + guid[ir][jr] = bufcolorig->L[ir][jr] / 32768.f; + } + + const float aepsil = (epsilmax - epsilmin) / 90.f; + const float bepsil = epsilmax - 100.f * aepsil; + const float epsil = rad < 0.f ? 0.0001f : aepsil * 0.1f * rad + bepsil; + const float blur = rad < 0.f ? -1.f / rad : 1.f + rad; + const int r2 = rtengine::max(int(25 / sk * blur + 0.5f), 1); + + rtengine::guidedFilter(guid, ble, ble, r2, epsil, multiThread); + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufcolfin->L[ir][jr] = 32768.f * ble[ir][jr]; + } + } + } + } +} + +void ImProcFunctions::softprocess(const LabImage* bufcolorig, array2D &buflight, float rad, int bfh, int bfw, double epsilmax, double epsilmin, float thres, int sk, bool multiThread) +{ + float minlig = buflight[0][0]; + +#ifdef _OPENMP + #pragma omp parallel for reduction(min:minlig) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + minlig = rtengine::min(buflight[ir][jr], minlig); + } + } + + array2D guidsoft(bfw, bfh); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + buflight[ir][jr] = LIM01((buflight[ir][jr] - minlig) / (100.f - minlig)); + guidsoft[ir][jr] = bufcolorig->L[ir][jr] / 32768.f; + } + } + + double aepsil = (epsilmax - epsilmin) / 90.f; + double bepsil = epsilmax - 100.f * aepsil; + double epsil = aepsil * rad + bepsil; + float blur = 1.f / sk * (thres + 0.8f * rad); + guidedFilter(guidsoft, buflight, buflight, blur, epsil, multiThread, 4); + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + buflight[ir][jr] = (100.f - minlig) * buflight[ir][jr] + minlig; + } + } +} + +void ImProcFunctions::exlabLocal(local_params& lp, int bfh, int bfw, LabImage* bufexporig, LabImage* lab, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve) +{ + BENCHFUN + //exposure local + + constexpr float maxran = 65536.f; + const float cexp_scale = std::pow(2.f, lp.expcomp); + const float ccomp = (rtengine::max(0.f, lp.expcomp) + 1.f) * lp.hlcomp / 100.f; + const float cshoulder = ((maxran / rtengine::max(1.0f, cexp_scale)) * (lp.hlcompthr / 200.f)) + 0.1f; + const float chlrange = maxran - cshoulder; + const float linear = lp.linear; + constexpr float kl = 1.f; + const float hlcompthr = lp.hlcompthr / 200.f; + const float hlcomp = lp.hlcomp / 100.f; + if (lp.linear > 0.f && lp.expcomp == 0.f) { + lp.expcomp = 0.01f; + } + + if (lp.expmet == 1 && lp.linear > 0.f && lp.laplacexp > 0.1f && !lp.invex) { + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + float L = bufexporig->L[ir][jr]; + const float Llin = LIM01(L / 32768.f); + const float addcomp = linear * (-kl * Llin + kl);//maximum about 1. IL + const float exp_scale = pow_F(2.0, (lp.expcomp + addcomp)); + const float shoulder = ((maxran / rtengine::max(1.0f, exp_scale)) * hlcompthr) + 0.1f; + const float comp = (rtengine::max(0.f, (lp.expcomp + addcomp)) + 1.f) * hlcomp; + const float hlrange = maxran - shoulder; + + //highlight + const float hlfactor = (2 * L < MAXVALF ? hltonecurve[2 * L] : CurveFactory::hlcurve(exp_scale, comp, hlrange, 2 * L)); + L *= hlfactor * pow_F(2.f, addcomp);//approximation but pretty good with Laplacian and L < mean, hl aren't call + //shadow tone curve + L *= shtonecurve[2 * L]; + //tonecurve + lab->L[ir][jr] = 0.5f * tonecurve[2 * L]; + } + } + } else { +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + float L = bufexporig->L[ir][jr]; + //highlight + const float hlfactor = (2 * L < MAXVALF ? hltonecurve[2 * L] : CurveFactory::hlcurve(cexp_scale, ccomp, chlrange, 2 * L)); + L *= hlfactor;//approximation but pretty good with Laplacian and L < mean, hl aren't call + //shadow tone curve + L *= shtonecurve[2 * L]; + //tonecurve + lab->L[ir][jr] = 0.5f * tonecurve[2 * L]; + } + } + } +} + + +void ImProcFunctions::addGaNoise(LabImage *lab, LabImage *dst, const float mean, const float variance, const int sk) +{ +// BENCHFUN +//Box-Muller method. +// add luma noise to image + + srand(1); + + const float variaFactor = SQR(variance) / sk; + constexpr float randFactor1 = 1.f / RAND_MAX; + constexpr float randFactor2 = (2.f * rtengine::RT_PI_F) / RAND_MAX; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + float z0, z1; + bool generate = false; +#ifdef _OPENMP + #pragma omp for schedule(static) // static scheduling is important to avoid artefacts +#endif + for (int y = 0; y < lab->H; y++) { + for (int x = 0; x < lab->W; x++) { + generate = !generate; + float kvar = 1.f; + + if (lab->L[y][x] < 12000.f) { + constexpr float ah = -0.5f / 12000.f; + constexpr float bh = 1.5f; + kvar = ah * lab->L[y][x] + bh; //increase effect for low lights < 12000.f + } else if (lab->L[y][x] > 20000.f) { + constexpr float ah = -0.5f / 12768.f; + constexpr float bh = 1.f - 20000.f * ah; + kvar = ah * lab->L[y][x] + bh; //decrease effect for high lights > 20000.f + kvar = kvar < 0.5f ? 0.5f : kvar; + } + + float varia = SQR(kvar) * variaFactor; + + if (!generate) { + dst->L[y][x] = LIM(lab->L[y][x] + mean + varia * z1, 0.f, 32768.f); + continue; + } + + int u1 = 0; + int u2; + + while (u1 == 0) { + u1 = rand(); + u2 = rand(); + } + + float u1f = u1 * randFactor1; + float u2f = u2 * randFactor2; + + float2 sincosval = xsincosf(2.f * rtengine::RT_PI_F * u2f); + float factor = std::sqrt(-2.f * xlogf(u1f)); + z0 = factor * sincosval.y; + z1 = factor * sincosval.x; + + dst->L[y][x] = LIM(lab->L[y][x] + mean + varia * z0, 0.f, 32768.f); + + } + } + } +} + +void ImProcFunctions::DeNoise_Local(int call, const struct local_params& lp, LabImage* originalmask, int levred, float hueref, float lumaref, float chromaref, LabImage* original, LabImage* transformed, const LabImage &tmp1, int cx, int cy, int sk) +{ + //warning, but I hope used it next + // local denoise and impulse + //simple algo , perhaps we can improve as the others, but noise is here and not good for hue detection + // BENCHFUN + lumaref *= 327.68f; + const float ach = lp.trans / 100.f; + + const float factnoise1 = 1.f + (lp.noisecf) / 500.f; + const float factnoise2 = 1.f + (lp.noisecc) / 500.f; + const float factnoise = factnoise1 * factnoise2; + + const int GW = transformed->W; + const int GH = transformed->H; + + const float colorde = lp.colorde == 0 ? -1.f : lp.colorde; // -1.f to avoid black + const float amplabL = 2.f * colorde; + constexpr float darklim = 5000.f; + + const float refa = chromaref * std::cos(hueref) * 327.68f; + const float refb = chromaref * std::sin(hueref) * 327.68f; + const bool usemaskbl = lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 4; + const bool blshow = lp.showmaskblmet == 1 || lp.showmaskblmet == 2; + const bool previewbl = lp.showmaskblmet == 4; + + const std::unique_ptr origblur(new LabImage(GW, GH)); + const float radius = 3.f / sk; + + if (usemaskbl) { +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(originalmask->L, origblur->L, GW, GH, radius); + gaussianBlur(originalmask->a, origblur->a, GW, GH, radius); + gaussianBlur(originalmask->b, origblur->b, GW, GH, radius); + } + } else { +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + } + } + + const int begx = lp.xc - lp.lxL; + const int begy = lp.yc - lp.lyT; + constexpr float r327d68 = 1.f / 327.68f; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const LabImage* maskptr = origblur.get(); + const float mindE = 2.f + MINSCOPE * lp.sensden * lp.thr; + const float maxdE = 5.f + MAXSCOPE * lp.sensden * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + const int loy = cy + y; + const bool isZone0 = loy > lp.yc + lp.ly || loy < lp.yc - lp.lyT; // whole line is zone 0 => we can skip a lot of processing + + if (isZone0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + for (int x = 0, lox = cx + x; x < transformed->W; x++, lox++) { + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + float reducdEL = 1.f; + float reducdEa = 1.f; + float reducdEb = 1.f; + + if (levred == 7) { + const float dEL = std::sqrt(0.9f * SQR(refa - maskptr->a[y][x]) + 0.9f * SQR(refb - maskptr->b[y][x]) + 1.2f * SQR(lumaref - maskptr->L[y][x])) * r327d68; + const float dEa = std::sqrt(1.2f * SQR(refa - maskptr->a[y][x]) + 1.f * SQR(refb - maskptr->b[y][x]) + 0.8f * SQR(lumaref - maskptr->L[y][x])) * r327d68; + const float dEb = std::sqrt(1.f * SQR(refa - maskptr->a[y][x]) + 1.2f * SQR(refb - maskptr->b[y][x]) + 0.8f * SQR(lumaref - maskptr->L[y][x])) * r327d68; + reducdEL = SQR(calcreducdE(dEL, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensden)); + reducdEa = SQR(calcreducdE(dEa, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensden)); + reducdEb = SQR(calcreducdE(dEb, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensden)); + } + float difL, difa, difb; + + if (call == 2 /*|| call == 1 || call == 3 */) { //simpleprocess + difL = tmp1.L[loy - begy][lox - begx] - original->L[y][x]; + difa = tmp1.a[loy - begy][lox - begx] - original->a[y][x]; + difb = tmp1.b[loy - begy][lox - begx] - original->b[y][x]; + } else { //dcrop + difL = tmp1.L[y][x] - original->L[y][x]; + difa = tmp1.a[y][x] - original->a[y][x]; + difb = tmp1.b[y][x] - original->b[y][x]; + } + + difL *= localFactor * reducdEL; + difa *= localFactor * reducdEa; + difb *= localFactor * reducdEb; + transformed->L[y][x] = CLIP(original->L[y][x] + difL); + transformed->a[y][x] = clipC((original->a[y][x] + difa) * factnoise); + transformed->b[y][x] = clipC((original->b[y][x] + difb) * factnoise) ; + + if (blshow) { + transformed->L[y][x] = CLIP(12000.f + amplabL * difL);// * 10.f empirical to can visualize modifications + transformed->a[y][x] = clipC(amplabL * difa);// * 10.f empirical to can visualize modifications + transformed->b[y][x] = clipC(amplabL * difb);// * 10.f empirical to can visualize modifications + } else if (previewbl || lp.prevdE) { + const float difbdisp = (reducdEL + reducdEa + reducdEb) * 10000.f * colorde; + + if (transformed->L[y][x] < darklim) { //enhance dark luminance as user can see! + transformed->L[y][x] = darklim - transformed->L[y][x]; + } + + if (colorde <= 0) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = difbdisp; + } else { + transformed->a[y][x] = -difbdisp; + transformed->b[y][x] = 0.f; + } + } + } + } + } +} + +void ImProcFunctions::InverseReti_Local(const struct local_params & lp, const float hueref, const float chromaref, const float lumaref, LabImage * original, LabImage * transformed, const LabImage * const tmp1, int cx, int cy, int chro, int sk) +{ + // BENCHFUN +//inverse local retinex + float ach = lp.trans / 100.f; + int GW = transformed->W; + int GH = transformed->H; + float refa = chromaref * cos(hueref); + float refb = chromaref * sin(hueref); + + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + + const std::unique_ptr origblur(new LabImage(GW, GH)); + + float radius = 3.f / sk; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + + } +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const float mindE = 2.f + MINSCOPE * lp.sensh * lp.thr; + const float maxdE = 5.f + MAXSCOPE * lp.sensh * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + int loy = cy + y; + + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + + int zone; + float localFactor; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + float rL = origblur->L[y][x] / 327.68f; + float dE = std::sqrt(kab * SQR(refa - origblur->a[y][x] / 327.68f) + kab * SQR(refb - origblur->b[y][x] / 327.68f) + kL * SQR(lumaref - rL)); + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensh); + + switch (zone) { + case 0: { // outside selection and outside transition zone => full effect, no transition + if (chro == 0) { + float difL = tmp1->L[y][x] - original->L[y][x]; + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + } + + if (chro == 1) { + float difa = tmp1->a[y][x] - original->a[y][x]; + float difb = tmp1->b[y][x] - original->b[y][x]; + + transformed->a[y][x] = clipC(original->a[y][x] + difa * reducdE); + transformed->b[y][x] = clipC(original->b[y][x] + difb * reducdE); + } + break; + } + + case 1: { // inside transition zone + float factorx = 1.f - localFactor; + + if (chro == 0) { + float difL = tmp1->L[y][x] - original->L[y][x]; + difL *= factorx; + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + } + + if (chro == 1) { + float difa = tmp1->a[y][x] - original->a[y][x]; + float difb = tmp1->b[y][x] - original->b[y][x]; + + difa *= factorx; + difb *= factorx; + + transformed->a[y][x] = clipC(original->a[y][x] + difa * reducdE); + transformed->b[y][x] = clipC(original->b[y][x] + difb * reducdE); + } + break; + } + + case 2: { // inside selection => no effect, keep original values + if (chro == 0) { + transformed->L[y][x] = original->L[y][x]; + } + + if (chro == 1) { + transformed->a[y][x] = original->a[y][x]; + transformed->b[y][x] = original->b[y][x]; + } + } + } + } + } + } +} + + + + +void ImProcFunctions::InverseBlurNoise_Local(LabImage * originalmask, float **bufchro, const struct local_params & lp, const float hueref, const float chromaref, const float lumaref, LabImage * original, LabImage * transformed, const LabImage * const tmp1, int cx, int cy, int sk) +{ + // BENCHFUN +//inverse local blur and noise + float ach = lp.trans / 100.f; + int GW = transformed->W; + int GH = transformed->H; + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + + + const bool blshow = (lp.showmaskblmet == 1 || lp.showmaskblmet == 2); + const bool previewbl = (lp.showmaskblmet == 4); + + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + + const std::unique_ptr origblur(new LabImage(GW, GH)); + std::unique_ptr origblurmask; + const bool usemaskbl = (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 4); + const bool usemaskall = usemaskbl; + + float radius = 3.f / sk; + + if (usemaskall) { + origblurmask.reset(new LabImage(GW, GH)); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(originalmask->L, origblurmask->L, GW, GH, radius); + gaussianBlur(originalmask->a, origblurmask->a, GW, GH, radius); + gaussianBlur(originalmask->b, origblurmask->b, GW, GH, radius); + } + } + + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + + } +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const LabImage *maskptr = usemaskall ? origblurmask.get() : origblur.get(); + const float mindE = 2.f + MINSCOPE * lp.sensbn * lp.thr; + const float maxdE = 5.f + MAXSCOPE * lp.sensbn * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + int loy = cy + y; + + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + + int zone; + float localFactor; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + const float clc = (previewbl) ? settings->previewselection * 100.f : bufchro[y][x]; + float abdelta2 = SQR(refa - maskptr->a[y][x]) + SQR(refb - maskptr->b[y][x]); + float chrodelta2 = SQR(std::sqrt(SQR(maskptr->a[y][x]) + SQR(maskptr->b[y][x])) - (chromaref * 327.68f)); + float huedelta2 = abdelta2 - chrodelta2; + + float dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - maskptr->L[y][x])); + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensbn); + const float realstrchdE = reducdE * clc; + + switch (zone) { + + case 0: { // outside selection and outside transition zone => full effect, no transition + float difL = tmp1->L[y][x] - original->L[y][x]; + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + float difa = tmp1->a[y][x] - original->a[y][x]; + float difb = tmp1->b[y][x] - original->b[y][x]; + float flia = 1.f, flib = 1.f; + flia = flib = ((100.f + realstrchdE) / 100.f); + const float chra = tmp1->a[y][x]; + const float chrb = tmp1->b[y][x]; + + if (!lp.actsp) { + difa = chra * flia - original->a[y][x]; + difb = chrb * flib - original->b[y][x]; + transformed->a[y][x] = clipC(original->a[y][x] + difa); + transformed->b[y][x] = clipC(original->b[y][x] + difb); + } + + if (blshow) { + transformed->L[y][x] = CLIP(12000.f + difL); + transformed->a[y][x] = clipC(difa); + transformed->b[y][x] = clipC(difb); + } else if (previewbl || lp.prevdE) { + transformed->a[y][x] = 0.f; + transformed->b[y] [x] = (difb); + } + + break; + } + + case 1: { // inside transition zone + float difL = tmp1->L[y][x] - original->L[y][x]; + float difa = tmp1->a[y][x] - original->a[y][x]; + float difb = tmp1->b[y][x] - original->b[y][x]; + float flia = 1.f, flib = 1.f; + flia = flib = ((100.f + realstrchdE) / 100.f); + const float chra = tmp1->a[y][x]; + const float chrb = tmp1->b[y][x]; + + float factorx = 1.f - localFactor; + difL *= factorx; + + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + + if (!lp.actsp) { + difa = chra * flia - original->a[y][x]; + difb = chrb * flib - original->b[y][x]; + difa *= factorx; + difb *= factorx; + transformed->a[y][x] = clipC(original->a[y][x] + difa); + transformed->b[y][x] = clipC(original->b[y][x] + difb); + + } + + if (blshow) { + transformed->L[y][x] = CLIP(12000.f + difL); + transformed->a[y][x] = clipC(difa); + transformed->b[y][x] = clipC(difb); + } else if (previewbl) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = (difb); + } + + break; + } + + case 2: { // inside selection => no effect, keep original values + transformed->L[y][x] = original->L[y][x]; + + if (!lp.actsp) { + + transformed->a[y][x] = original->a[y][x]; + transformed->b[y][x] = original->b[y][x]; + } + } + } + } + } + } +} + +static void mean_fab(int xstart, int ystart, int bfw, int bfh, LabImage* bufexporig, const LabImage* original, float &fab, float &meanfab, float chrom, bool multiThread) +{ + const int nbfab = bfw * bfh; + + meanfab = 0.f; + fab = 50.f; + + if (nbfab > 0) { + double sumab = 0.0; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:sumab) if(multiThread) +#else + static_cast(multiThread); +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufexporig->a[y][x] = original->a[y + ystart][x + xstart]; + bufexporig->b[y][x] = original->b[y + ystart][x + xstart]; + sumab += std::fabs(bufexporig->a[y][x]); + sumab += std::fabs(bufexporig->b[y][x]); + } + } + + meanfab = sumab / (2.f * nbfab); + + double som = 0.0; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:som) if(multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + som += SQR(std::fabs(bufexporig->a[y][x]) - meanfab) + SQR(std::fabs(bufexporig->b[y][x]) - meanfab); + } + } + + const float multsigma = (chrom >= 0.f ? 0.035f : 0.018f) * chrom + 1.f; + + const float stddv = std::sqrt(som / nbfab); + fab = meanfab + multsigma * stddv; + + if (fab <= 0.f) { + fab = 50.f; + } + } +} + +struct grad_params { + bool angle_is_zero, transpose, bright_top; + float ta, yc, xc; + float ys, ys_inv; + float scale, botmul, topmul; + float top_edge_0; + int h; +}; + +void calclocalGradientParams(const struct local_params& lp, struct grad_params& gp, float ystart, float xstart, int bfw, int bfh, int indic) +{ + int w = bfw; + int h = bfh; + float stops = 0.f; + float angs = 0.f; + + if (indic == 0) { + stops = -lp.strmaexp; + angs = lp.angmaexp; + } else if (indic == 1) { + stops = lp.strexp; + angs = lp.angexp; + } else if (indic == 2) { + stops = lp.strSH; + angs = lp.angSH; + } else if (indic == 3) { + stops = lp.strcol; + angs = lp.angcol; + } else if (indic == 4) { + float redu = 1.f; + + if (lp.strcolab > 0.f) { + redu = 0.6f; + } else { + redu = 0.15f; + } + + stops = redu * lp.strcolab; + angs = lp.angcol; + } else if (indic == 5) { + stops = lp.strcolab; + angs = lp.angcol; + } else if (indic == 6) { + stops = lp.strcolh; + angs = lp.angcol; + } else if (indic == 7) { + stops = lp.strvib; + angs = lp.angvib; + } else if (indic == 8) { + float redu = 1.f; + + if (lp.strvibab > 0.f) { + redu = 0.7f; + } else { + redu = 0.5f; + } + + stops = redu * lp.strvibab; + angs = lp.angvib; + } else if (indic == 9) { + stops = lp.strvibh; + angs = lp.angvib; + } else if (indic == 10) { + stops = std::fabs(lp.strwav); + angs = lp.angwav; + } else if (indic == 11) { + stops = lp.strlog; + angs = lp.anglog; + } + + + double gradient_stops = stops; + double gradient_center_x = LIM01((lp.xc - xstart) / bfw); + double gradient_center_y = LIM01((lp.yc - ystart) / bfh); + double gradient_angle = angs / 180.0 * rtengine::RT_PI; + double varfeath = 0.01 * lp.feath; + + //printf("xstart=%f ysta=%f lpxc=%f lpyc=%f stop=%f bb=%f cc=%f ang=%f ff=%d gg=%d\n", xstart, ystart, lp.xc, lp.yc, gradient_stops, gradient_center_x, gradient_center_y, gradient_angle, w, h); + + // make 0.0 <= gradient_angle < 2 * rtengine::RT_PI + gradient_angle = fmod(gradient_angle, 2 * rtengine::RT_PI); + + if (gradient_angle < 0.0) { + gradient_angle += 2.0 * rtengine::RT_PI; + } + + gp.bright_top = false; + gp.transpose = false; + gp.angle_is_zero = false; + gp.h = h; + double cosgrad = cos(gradient_angle); + + if (std::fabs(cosgrad) < 0.707) { + // we transpose to avoid division by zero at 90 degrees + // (actually we could transpose only for 90 degrees, but this way we avoid + // division with extremely small numbers + gp.transpose = true; + gradient_angle += 0.5 * rtengine::RT_PI; + double gxc = gradient_center_x; + gradient_center_x = 1.0 - gradient_center_y; + gradient_center_y = gxc; + } + + gradient_angle = fmod(gradient_angle, 2 * rtengine::RT_PI); + + if (gradient_angle > 0.5 * rtengine::RT_PI && gradient_angle < rtengine::RT_PI) { + gradient_angle += rtengine::RT_PI; + gp.bright_top = true; + } else if (gradient_angle >= rtengine::RT_PI && gradient_angle < 1.5 * rtengine::RT_PI) { + gradient_angle -= rtengine::RT_PI; + gp.bright_top = true; + } + + if (std::fabs(gradient_angle) < 0.001 || std::fabs(gradient_angle - 2 * rtengine::RT_PI) < 0.001) { + gradient_angle = 0; + gp.angle_is_zero = true; + } + + if (gp.transpose) { + gp.bright_top = !gp.bright_top; + std::swap(w, h); + } + + gp.scale = 1.0 / pow(2, gradient_stops); + + if (gp.bright_top) { + gp.topmul = 1.0; + gp.botmul = gp.scale; + } else { + gp.topmul = gp.scale; + gp.botmul = 1.0; + } + + gp.ta = tan(gradient_angle); + gp.xc = w * gradient_center_x; + gp.yc = h * gradient_center_y; + gp.ys = std::sqrt((float)h * h + (float)w * w) * (varfeath / cos(gradient_angle)); + gp.ys_inv = 1.0 / gp.ys; + gp.top_edge_0 = gp.yc - gp.ys / 2.0; + + if (gp.ys < 1.0 / h) { + gp.ys_inv = 0; + gp.ys = 0; + } +} + +void ImProcFunctions::blendstruc(int bfw, int bfh, LabImage* bufcolorig, float radius, float stru, array2D & blend2, int sk, bool multiThread) +{ + SobelCannyLuma(blend2, bufcolorig->L, bfw, bfh, radius); + float rm = 20.f / sk; + + if (rm > 0) { + float **mb = blend2; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(mb, mb, bfw, bfh, rm); + } + } + + array2D ble(bfw, bfh); + array2D guid(bfw, bfh); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + float X, Y, Z; + float L = bufcolorig->L[ir][jr]; + float a = bufcolorig->a[ir][jr]; + float b = bufcolorig->b[ir][jr]; + Color::Lab2XYZ(L, a, b, X, Y, Z); + + guid[ir][jr] = Y / 32768.f; + + blend2[ir][jr] /= 32768.f; + } + } + + const float blur = 25 / sk * (10.f + 1.2f * stru); + + rtengine::guidedFilter(guid, blend2, ble, blur, 0.001, multiThread); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + blend2[ir][jr] = 32768.f * ble[ir][jr]; + } + } +} + + +static void blendmask(const local_params& lp, int xstart, int ystart, int cx, int cy, int bfw, int bfh, LabImage* bufexporig, LabImage* original, LabImage* bufmaskor, LabImage* originalmas, float bl, int inv) +{ +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + const int loy = y + ystart + cy; + + for (int x = 0; x < bfw; x++) { + const int lox = x + xstart + cx; + int zone; + + float localFactor = 1.f; + const float achm = lp.trans / 100.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, achm, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, achm, lp, zone, localFactor); + } + + if (inv == 0) { + if (zone > 0) { + bufexporig->L[y][x] += (bl * bufmaskor->L[y][x]); + bufexporig->a[y][x] *= (1.f + bl * bufmaskor->a[y][x]); + bufexporig->b[y][x] *= (1.f + bl * bufmaskor->b[y][x]); + + bufexporig->L[y][x] = CLIP(bufexporig->L[y][x]); + bufexporig->a[y][x] = clipC(bufexporig->a[y][x]); + bufexporig->b[y][x] = clipC(bufexporig->b[y][x]); + + originalmas->L[y][x] = CLIP(bufexporig->L[y][x] - bufmaskor->L[y][x]); + originalmas->a[y][x] = clipC(bufexporig->a[y][x] * (1.f - bufmaskor->a[y][x])); + originalmas->b[y][x] = clipC(bufexporig->b[y][x] * (1.f - bufmaskor->b[y][x])); + + original->L[y + ystart][x + xstart] += (bl * localFactor * bufmaskor->L[y][x]); + original->a[y + ystart][x + xstart] *= (1.f + bl * localFactor * bufmaskor->a[y][x]); + original->b[y + ystart][x + xstart] *= (1.f + bl * localFactor * bufmaskor->b[y][x]); + original->L[y + ystart][x + xstart] = CLIP(original->L[y + ystart][x + xstart]); + original->a[y + ystart][x + xstart] = clipC(original->a[y + ystart][x + xstart]); + original->b[y + ystart][x + xstart] = clipC(original->b[y + ystart][x + xstart]); + + } + } else if (inv == 1) { + localFactor = 1.f - localFactor; + + if (zone < 2) { + bufexporig->L[y][x] += (bl * bufmaskor->L[y][x]); + bufexporig->a[y][x] *= (1.f + bl * bufmaskor->a[y][x]); + bufexporig->b[y][x] *= (1.f + bl * bufmaskor->b[y][x]); + + bufexporig->L[y][x] = CLIP(bufexporig->L[y][x]); + bufexporig->a[y][x] = clipC(bufexporig->a[y][x]); + bufexporig->b[y][x] = clipC(bufexporig->b[y][x]); + + originalmas->L[y][x] = CLIP(bufexporig->L[y][x] - bufmaskor->L[y][x]); + originalmas->a[y][x] = clipC(bufexporig->a[y][x] * (1.f - bufmaskor->a[y][x])); + originalmas->b[y][x] = clipC(bufexporig->b[y][x] * (1.f - bufmaskor->b[y][x])); + + switch (zone) { + case 0: { + original->L[y + ystart][x + xstart] += (bl * bufmaskor->L[y][x]); + original->a[y + ystart][x + xstart] *= (1.f + bl * bufmaskor->a[y][x]); + original->b[y + ystart][x + xstart] *= (1.f + bl * bufmaskor->b[y][x]); + original->L[y + ystart][x + xstart] = CLIP(original->L[y + ystart][x + xstart]); + original->a[y + ystart][x + xstart] = clipC(original->a[y + ystart][x + xstart]); + original->b[y + ystart][x + xstart] = clipC(original->b[y + ystart][x + xstart]); + break; + } + + case 1: { + original->L[y + ystart][x + xstart] += (bl * localFactor * bufmaskor->L[y][x]); + original->a[y + ystart][x + xstart] *= (1.f + bl * localFactor * bufmaskor->a[y][x]); + original->b[y + ystart][x + xstart] *= (1.f + bl * localFactor * bufmaskor->b[y][x]); + original->L[y + ystart][x + xstart] = CLIP(original->L[y + ystart][x + xstart]); + original->a[y + ystart][x + xstart] = clipC(original->a[y + ystart][x + xstart]); + original->b[y + ystart][x + xstart] = clipC(original->b[y + ystart][x + xstart]); + } + + } + } + + } + } + } +} + +void ImProcFunctions::deltaEforMask(float **rdE, int bfw, int bfh, LabImage* bufcolorig, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh) +{ + const float refa = chromaref * cos(hueref); + const float refb = chromaref * sin(hueref); + const float refL = lumaref; + + const float kL = balance; + const float kab = balancedeltaE(kL); + const float kH = balanceh; + const float kch = balancedeltaE(kH); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + const float abdelta2 = SQR(refa - bufcolorig->a[y][x] / 327.68f) + SQR(refb - bufcolorig->b[y][x] / 327.68f); + const float chrodelta2 = SQR(std::sqrt(SQR(bufcolorig->a[y][x]) + SQR(bufcolorig->b[y][x])) / 327.68f - chromaref); + const float huedelta2 = abdelta2 - chrodelta2; + const float tempdE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - bufcolorig->L[y][x] / 327.68f)); + + float reducdE; + if (tempdE > maxdE) { + reducdE = 0.f; + } else if (tempdE > mindE && tempdE <= maxdE) { + const float ar = 1.f / (mindE - maxdE); + const float br = - ar * maxdE; + reducdE = pow(ar * tempdE + br, iterat); + } else { + reducdE = 1.f; + } + + if (scope > limscope) { + if (tempdE > maxdElim) { + reducdE = 0.f; + } else if (tempdE > mindElim && tempdE <= maxdElim) { + const float arlim = 1.f / (mindElim - maxdElim); + const float brlim = - arlim * maxdElim; + const float reducdElim = pow(arlim * tempdE + brlim, iterat); + const float aalim = (1.f - reducdElim) / 20.f; + const float bblim = 1.f - 100.f * aalim; + reducdE = aalim * scope + bblim; + } else { + reducdE = 1.f; + } + } + + rdE[y][x] = reducdE ; + } + } +} + +static void showmask(int lumask, const local_params& lp, int xstart, int ystart, int cx, int cy, int bfw, int bfh, LabImage* bufexporig, LabImage* transformed, LabImage* bufmaskorigSH, int inv) +{ +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh; y++) { + const int loy = y + ystart + cy; + + for (int x = 0; x < bfw; x++) { + const int lox = x + xstart + cx; + int zone; + float localFactor = 1.f; + const float achm = lp.trans / 100.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, achm, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, achm, lp, zone, localFactor); + } + + if (inv == 0) { + if (zone > 0) {//normal + transformed->L[y + ystart][x + xstart] = (lumask * 400.f) + clipLoc(bufmaskorigSH->L[y][x]); + transformed->a[y + ystart][x + xstart] = bufexporig->a[y][x] * bufmaskorigSH->a[y][x]; + transformed->b[y + ystart][x + xstart] = bufexporig->b[y][x] * bufmaskorigSH->b[y][x]; + } + } else if (inv == 1) { //inverse + if (zone == 0) { + transformed->L[y + ystart][x + xstart] = (lumask * 400.f) + clipLoc(bufmaskorigSH->L[y][x]); + transformed->a[y + ystart][x + xstart] = bufexporig->a[y][x] * bufmaskorigSH->a[y][x]; + transformed->b[y + ystart][x + xstart] = bufexporig->b[y][x] * bufmaskorigSH->b[y][x]; + } + } + } + } +} + +void ImProcFunctions::discrete_laplacian_threshold(float * data_out, const float * data_in, size_t nx, size_t ny, float t) +{ + BENCHFUN + + if (!data_in || !data_out) { + fprintf(stderr, "a pointer is NULL and should not be so\n"); + abort(); + } + + /* pointers to the data and neighbour values */ + /* + * y-1 + * x-1 ptr x+1 + * y+1 + * <---------------------nx-------> + */ + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (size_t j = 0; j < ny; j++) { + const float* ptr_in = &data_in[j * nx]; + float* ptr_out = &data_out[j * nx]; + for (size_t i = 0; i < nx; i++) { + float val = 0.f; + /* row differences */ + if (0 < i) { + const float diff = ptr_in[i] - ptr_in[i - 1]; + val += std::fabs(diff) > t ? diff : 0.f; + } + + if (nx - 1 > i) { + const float diff = ptr_in[i] - ptr_in[i + 1];; + val += std::fabs(diff) > t ? diff : 0.f; + } + + /* column differences */ + if (0 < j) { + const float diff = ptr_in[i] - ptr_in[i - nx];; + val += std::fabs(diff) > t ? diff : 0.f; + } + + if (ny - 1 > j) { + const float diff = ptr_in[i] - ptr_in[i + nx];; + val += std::fabs(diff) > t ? diff : 0.f; + } + + ptr_out[i] = val; + } + } + +} + +float *ImProcFunctions::cos_table(size_t size) +{ + float *table = NULL; + + /* allocate the cosinus table */ + if (NULL == (table = (float *) malloc(sizeof(*table) * size))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + /* + * fill the cosinus table, + * table[i] = cos(i Pi / n) for i in [0..n[ + */ + const double pi_size = rtengine::RT_PI / size; + + for (size_t i = 0; i < size; i++) { + table[i] = std::cos(pi_size * i); + } + + return table; +} + + +void ImProcFunctions::rex_poisson_dct(float * data, size_t nx, size_t ny, double m) +{ + /* + * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ + * + + * @file retinex_pde_lib.c discrete Poisson equation + * @brief laplacian, DFT and Poisson routines + * + * @author Nicolas Limare + * some adaptations for Rawtherapee + */ + BENCHFUN + + /* + * get the cosinus tables + * cosx[i] = cos(i Pi / nx) for i in [0..nx[ + * cosy[i] = cos(i Pi / ny) for i in [0..ny[ + */ + + float* cosx = cos_table(nx); + float* cosy = cos_table(ny); + + /* + * we will now multiply data[i, j] by + * m / (4 - 2 * cosx[i] - 2 * cosy[j])) + * and set data[0, 0] to 0 + */ + float m2 = m / 2.; + /* + * after that, by construction, we always have + * cosx[] + cosy[] != 2. + */ + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (size_t i = 0; i < ny; ++i) { + for (size_t j = 0; j < nx; ++j) { + data[i * nx + j] *= m2 / (2.f - cosx[j] - cosy[i]); + } + } + // handle the first value, data[0, 0] = 0 + data[0] = 0.f; + + free(cosx); + free(cosy); + +} + +void ImProcFunctions::mean_dt(const float* data, size_t size, double& mean_p, double& dt_p) +{ + + double mean = 0.; + double dt = 0.; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:mean,dt) if(multiThread) +#endif + for (size_t i = 0; i < size; i++) { + mean += data[i]; + dt += SQR(data[i]); + } + + mean /= size; + dt /= size; + dt -= SQR(mean); + mean_p = mean; + dt_p = std::sqrt(dt); +} + +void ImProcFunctions::normalize_mean_dt(float * data, const float * ref, size_t size, float mod, float sigm) +{ + /* + * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ + * + + * @file retinex_pde_lib.c discrete Poisson equation + * @brief laplacian, DFT and Poisson routines + * + * @author Nicolas Limare + * adapted for Rawtherapee - jacques Desmis july 2019 + */ + + if (NULL == data || NULL == ref) { + fprintf(stderr, "a pointer is NULL and should not be so\n"); + abort(); + } + + double mean_ref, mean_data, dt_ref, dt_data; + + /* compute mean and variance of the two arrays */ + mean_dt(ref, size, mean_ref, dt_ref); + mean_dt(data, size, mean_data, dt_data); + + /* compute the normalization coefficients */ + const double a = dt_ref / dt_data; + const double b = mean_ref - a * mean_data; + + const float modma = mod * a; + const float sigmmmodmb = sigm * mod * b; + const float onesmod = 1.f - mod; + /* normalize the array */ + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (size_t i = 0; i < size; i++) { + data[i] = (modma * data[i] + sigmmmodmb) + onesmod * ref[i];//normalize mean and stdv and balance PDE + } + +} + +void ImProcFunctions::retinex_pde(const float * datain, float * dataout, int bfw, int bfh, float thresh, float multy, float * dE, int show, int dEenable, int normalize) +{ + /* + * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ + * + + * @file retinex_pde_lib.c discrete Poisson equation + * @brief laplacian, DFT and Poisson routines + * + * @author Nicolas Limare + * adapted for Rawtherapee by Jacques Desmis 6-2019 + */ + + BENCHFUN +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_init_threads(); + fftwf_plan_with_nthreads(omp_get_max_threads()); + } +#endif + float *data_fft, *data_fft04, *data_tmp, *data, *data_tmp04; + float *datashow = nullptr; + + if (show != 0) { + if (NULL == (datashow = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + } + + if (NULL == (data_tmp = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (NULL == (data_tmp04 = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + //first call to laplacian with plein strength + ImProcFunctions::discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, thresh); + + if (NULL == (data_fft = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (show == 1) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + datashow[y * bfw + x] = data_tmp[y * bfw + x]; + } + } + } + + //second call to laplacian with 40% strength ==> reduce effect if we are far from ref (deltaE) + ImProcFunctions::discrete_laplacian_threshold(data_tmp04, datain, bfw, bfh, 0.4f * thresh); + + if (NULL == (data_fft04 = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (NULL == (data = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + //execute first + const auto dct_fw = fftwf_plan_r2r_2d(bfh, bfw, data_tmp, data_fft, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_fw); + + //execute second + if (dEenable == 1) { + const auto dct_fw04 = fftwf_plan_r2r_2d(bfh, bfw, data_tmp04, data_fft04, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_fw04); + fftwf_destroy_plan(dct_fw04); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) {//mix two fftw Laplacian : plein if dE near ref + for (int x = 0; x < bfw; x++) { + float prov = pow(dE[y * bfw + x], 4.5f); + data_fft[y * bfw + x] = prov * data_fft[y * bfw + x] + (1.f - prov) * data_fft04[y * bfw + x]; + } + } + } + + if (show == 2) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + datashow[y * bfw + x] = data_fft[y * bfw + x]; + } + } + } + + fftwf_free(data_fft04); + fftwf_free(data_tmp); + fftwf_free(data_tmp04); + + /* solve the Poisson PDE in Fourier space */ + /* 1. / (float) (bfw * bfh)) is the DCT normalisation term, see libfftw */ + ImProcFunctions::rex_poisson_dct(data_fft, bfw, bfh, 1. / (double)(bfw * bfh)); + + if (show == 3) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + datashow[y * bfw + x] = data_fft[y * bfw + x]; + } + } + } + + const auto dct_bw = fftwf_plan_r2r_2d(bfh, bfw, data_fft, data, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_bw); + fftwf_destroy_plan(dct_fw); + fftwf_destroy_plan(dct_bw); + fftwf_free(data_fft); + fftwf_cleanup(); + +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_cleanup_threads(); + } +#endif + if (show != 4 && normalize == 1) { + normalize_mean_dt(data, datain, bfw * bfh, 1.f, 1.f); + } + + if (show == 0 || show == 4) { + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + dataout[y * bfw + x] = clipLoc(multy * data[y * bfw + x]); + } + } + } else if (show == 1 || show == 2 || show == 3) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + dataout[y * bfw + x] = clipLoc(multy * datashow[y * bfw + x]); + } + } + + fftwf_free(datashow); + } + + fftwf_free(data); + +} + +void ImProcFunctions::maskcalccol(bool invmask, bool pde, int bfw, int bfh, int xstart, int ystart, int sk, int cx, int cy, LabImage* bufcolorig, LabImage* bufmaskblurcol, LabImage* originalmaskcol, LabImage* original, LabImage* reserved, int inv, struct local_params & lp, + float strumask, bool astool, + const LocCCmaskCurve & locccmasCurve, bool lcmasutili, + const LocLLmaskCurve & locllmasCurve, bool llmasutili, + const LocHHmaskCurve & lochhmasCurve, bool lhmasutili, const LocHHmaskCurve & lochhhmasCurve, bool lhhmasutili, + bool multiThread, bool enaMask, bool showmaske, bool deltaE, bool modmask, bool zero, bool modif, float chrom, float rad, float lap, float gamma, float slope, float blendm, int shado, float amountcd, float anchorcd, + const LUTf& lmasklocalcurve, bool localmaskutili, + const LocwavCurve & loclmasCurvecolwav, bool lmasutilicolwav, int level_bl, int level_hl, int level_br, int level_hr, + int shortcu, bool delt, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope + ) +{ + array2D ble(bfw, bfh); + array2D blechro(bfw, bfh); + array2D hue(bfw, bfh); + array2D guid(bfw, bfh); + const std::unique_ptr bufreserv(new LabImage(bfw, bfh)); + float meanfab, fab; + mean_fab(xstart, ystart, bfw, bfh, bufcolorig, original, fab, meanfab, chrom, multiThread); + float chromult = 1.f - 0.01f * chrom; + float kinv = 1.f; + float kneg = 1.f; + + if (invmask) { + kinv = 0.f; + kneg = -1.f; + } + + if (deltaE || modmask || enaMask || showmaske) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufmaskblurcol->L[y][x] = original->L[y + ystart][x + xstart]; + bufmaskblurcol->a[y][x] = original->a[y + ystart][x + xstart]; + bufmaskblurcol->b[y][x] = original->b[y + ystart][x + xstart]; + bufreserv->L[y][x] = reserved->L[y + ystart][x + xstart]; + bufreserv->a[y][x] = reserved->a[y + ystart][x + xstart]; + bufreserv->b[y][x] = reserved->b[y + ystart][x + xstart]; + } + } + + JaggedArray blendstru(bfw, bfh); + + if (lp.blurcolmask >= 0.25f && strumask == 0.f) { + strumask = 0.1f; // to enable a small mask make FFT good ...why ?? + } + + if (strumask > 0.f) { + float delstrumask = 4.1f - strumask;//4.1 = 2 * max slider strumask + 0.1 + buildBlendMask(bufcolorig->L, blendstru, bfw, bfh, delstrumask); + float radblur = 0.02f * std::fabs(0.1f * rad);//empirical value + float rm = radblur / sk; + + if (rm > 0) { + float **mb = blendstru; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(mb, mb, bfw, bfh, rm); + } + } + + } + + JaggedArray blendblur(bfw, bfh); + + JaggedArray blur(bfw, bfh); + + if (lp.contcolmask > 0.f) { + float contra = lp.contcolmask; + buildBlendMask(bufcolorig->L, blendblur, bfw, bfh, contra); + + + float radblur = 0.25f + 0.002f * std::fabs(rad);//empirical value + float rm = radblur / sk; + + if (lp.fftColorMask) { + if (rm < 0.3f) { + rm = 0.3f; + } + } + + if (rm > 0) { + float **mb = blendblur; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(mb, mb, bfw, bfh, rm); + } + } + + if (lp.blurcolmask >= 0.25f) { + if (!lp.fftColorMask) { // || (lp.fftColorMask && call != 2)) { +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufcolorig->L, blur, bfw, bfh, lp.blurcolmask / sk); + } + } else { + ImProcFunctions::fftw_convol_blur2(bufcolorig->L, blur, bfw, bfh, lp.blurcolmask / sk, 0, 0); + } + + for (int i = 0; i < bfh; i++) { + for (int j = 0; j < bfw; j++) { + blur[i][j] = intp(blendblur[i][j], bufcolorig->L[i][j], rtengine::max(blur[i][j], 0.0f)); + } + } + } + } + + bool HHmaskcurve = false; + + if (lochhhmasCurve && lhhmasutili) { + for (int i = 0; i < 500; i++) { + if (lochhhmasCurve[i] != 0.5) { + HHmaskcurve = true; + } + } + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + float atan2Buffer[bfw] ALIGNED64; +// float atan2BufferH[bfw] ALIGNED64; +#endif +#ifdef _OPENMP + #pragma omp for schedule(dynamic, 16) +#endif + for (int ir = 0; ir < bfh; ir++) { +#ifdef __SSE2__ + + if (lochhmasCurve && lhmasutili) { + int i = 0; + + for (; i < bfw - 3; i += 4) { + STVF(atan2Buffer[i], xatan2f(LVFU(bufcolorig->b[ir][i]), LVFU(bufcolorig->a[ir][i]))); + } + + for (; i < bfw; i++) { + atan2Buffer[i] = xatan2f(bufcolorig->b[ir][i], bufcolorig->a[ir][i]); + } + } + +#endif + + for (int jr = 0; jr < bfw; jr++) { + float kmaskL = 0.f; + float kmaskC = 0.f; + float kmaskHL = 0.f; + float kmaskH = 0.f; + float kmasstru = 0.f; + float kmasblur = 0.f; + + if (strumask > 0.f && !astool) { + kmasstru = bufcolorig->L[ir][jr] * blendstru[ir][jr]; + } + + if (lp.contcolmask > 0.f) { + + if (lp.blurcolmask >= 0.25f) { + + float prov = intp(blendstru[ir][jr], bufcolorig->L[ir][jr], rtengine::max(blur[ir][jr], 0.0f)); + kmasblur = bufcolorig->L[ir][jr] - prov ; + + } + } + + if (locllmasCurve && llmasutili) { + kmaskL = 32768.f * LIM01(kinv - kneg * locllmasCurve[(500.f / 32768.f) * bufcolorig->L[ir][jr]]); + + } + + if (!deltaE && locccmasCurve && lcmasutili) { + kmaskC = LIM01(kinv - kneg * locccmasCurve[500.f * (0.0001f + std::sqrt(SQR(bufcolorig->a[ir][jr]) + SQR(bufcolorig->b[ir][jr])) / fab)]); + } + + if (lochhmasCurve && lhmasutili) { +#ifdef __SSE2__ + const float huema = atan2Buffer[jr]; +#else + const float huema = xatan2f(bufcolorig->b[ir][jr], bufcolorig->a[ir][jr]); +#endif + float h = Color::huelab_to_huehsv2(huema); + h += 1.f / 6.f; + + if (h > 1.f) { + h -= 1.f; + } + + const float valHH = LIM01(kinv - kneg * lochhmasCurve[500.f * h]); + + if (!deltaE) { + kmaskH = valHH; + } + + kmaskHL = 32768.f * valHH; + } + + /* + //keep here in case of...but !! + if (lochhhmasCurve && HHmaskcurve) { + + #ifdef __SSE2__ + huemah = atan2BufferH[jr]; + #else + huemah = xatan2f(bufcolorig->b[ir][jr], bufcolorig->a[ir][jr]); + #endif + + float hh = Color::huelab_to_huehsv2(huemah); + hh += 1.f / 6.f; + + if (hh > 1.f) { + hh -= 1.f; + } + + const float val_HH = float (LIM01(((0.5f - lochhhmasCurve[500.f * hh])))); + kmaskHH = 2.f * val_HH; + const float hhro = kmaskHH; + + if (hhro != 0) { + newhr = huemah + hhro; + + if (newhr > rtengine::RT_PI_F) { + newhr -= 2 * rtengine::RT_PI_F; + } else if (newhr < -rtengine::RT_PI_F) { + newhr += 2 * rtengine::RT_PI_F; + } + } + sincosval = xsincosf(newhr); + + } + */ + bufmaskblurcol->L[ir][jr] = clipLoc(kmaskL + kmaskHL + kmasstru + kmasblur); + bufmaskblurcol->a[ir][jr] = clipC((kmaskC + chromult * kmaskH)); + bufmaskblurcol->b[ir][jr] = clipC((kmaskC + chromult * kmaskH)); + + if (shortcu == 1) { //short circuit all L curve + bufmaskblurcol->L[ir][jr] = 32768.f - bufcolorig->L[ir][jr]; + } + + ble[ir][jr] = bufmaskblurcol->L[ir][jr] / 32768.f; + hue[ir][jr] = xatan2f(bufmaskblurcol->b[ir][jr], bufmaskblurcol->a[ir][jr]); + const float chromah = std::sqrt(SQR(bufmaskblurcol->b[ir][jr]) + SQR(bufmaskblurcol->a[ir][jr])); + + blechro[ir][jr] = chromah / 32768.f;//must be good perhaps more or less, only incidence on LIM blea bleb + guid[ir][jr] = Color::L2Y(bufcolorig->L[ir][jr]) / 32768.f; + + } + } + } + + std::unique_ptr bufprov; + if (delt) { + bufprov.reset(new LabImage(bfw, bfh)); + bufprov->CopyFrom(bufmaskblurcol, multiThread); + } + + if (rad != 0.f) { + const float tmpblur = rad < 0.f ? -1.f / rad : 1.f + rad; + const int r1 = rtengine::max(4 / sk * tmpblur + 0.5, 1); + const int r2 = rtengine::max(25 / sk * tmpblur + 0.5, 1); + + constexpr float epsilmax = 0.0005f; + constexpr float epsilmin = 0.00001f; + + constexpr float aepsil = (epsilmax - epsilmin) / 90.f; + constexpr float bepsil = epsilmax - 100.f * aepsil; + const float epsil = rad < 0.f ? 0.001f : aepsil * 0.1f * rad + bepsil; + + rtengine::guidedFilter(guid, blechro, blechro, r1, epsil, multiThread); + rtengine::guidedFilter(guid, ble, ble, r2, 0.2f * epsil, multiThread); + } + + LUTf lutTonemaskexp(65536); + calcGammaLut(gamma, slope, lutTonemaskexp); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + float2 sincosval = xsincosf(hue[ir][jr]); + bufmaskblurcol->L[ir][jr] = lutTonemaskexp[ble[ir][jr] * 65536.f]; + bufmaskblurcol->a[ir][jr] = 32768.f * blechro[ir][jr] * sincosval.y; + bufmaskblurcol->b[ir][jr] = 32768.f * blechro[ir][jr] * sincosval.x; + } + } + + + if (strumask > 0.f && astool) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufmaskblurcol->L[ir][jr] *= (1.f + blendstru[ir][jr]); + } + } + } + + if (lmasklocalcurve && localmaskutili) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + bufmaskblurcol->L[ir][jr] = 0.5f * lmasklocalcurve[2.f * bufmaskblurcol->L[ir][jr]]; + } + } + + if (shado > 0) { + ImProcFunctions::shadowsHighlights(bufmaskblurcol, true, 1, 0, shado, 40, sk, 0, 60); + } + + int wavelet_level = level_br; + + int minwin = rtengine::min(bfw, bfh); + int maxlevelspot = 9; + + while ((1 << maxlevelspot) >= (minwin * sk) && maxlevelspot > 1) { + --maxlevelspot ; + } + + wavelet_level = rtengine::min(wavelet_level, maxlevelspot); + int maxlvl = wavelet_level; +// float contrast = 0.f; + bool wavcurvemask = false; + + if (loclmasCurvecolwav && lmasutilicolwav) { + for (int i = 0; i < 500; i++) { + if (loclmasCurvecolwav[i] != 0.5) { + wavcurvemask = true; + } + } + } + + if (wavcurvemask) { +#ifdef _OPENMP + const int numThreads = omp_get_max_threads(); +#else + const int numThreads = 1; + +#endif + wavelet_decomposition *wdspot = new wavelet_decomposition(bufmaskblurcol->L[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen); + if (wdspot->memory_allocation_failed()) { + return; + } + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + Evaluate2(*wdspot, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + float alow = 1.f; + float blow = 0.f; + if (level_hl != level_bl) { + alow = 1.f / (level_hl - level_bl); + blow = -alow * level_bl; + } + + float ahigh = 1.f; + float bhigh = 0.f; + + if (level_hr != level_br) { + ahigh = 1.f / (level_hr - level_br); + bhigh = -ahigh * level_br; + } + + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + int W_L = wdspot->level_W(level); + int H_L = wdspot->level_H(level); + float* const* wav_L = wdspot->level_coeffs(level); + + if (MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { + float insigma = 0.666f; //SD + float logmax = log(MaxP[level]); //log Max + float rapX = (mean[level] + sigma[level]) / MaxP[level]; //rapport between sD / max + float inx = log(insigma); + float iny = log(rapX); + float rap = inx / iny; //koef + float asig = 0.166f / (sigma[level]); + float bsig = 0.5f - asig * mean[level]; + float amean = 0.5f / mean[level]; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < W_L * H_L; i++) { + if(loclmasCurvecolwav && lmasutilicolwav) { + float absciss; + float &val = wav_L[dir][i]; + + if (fabsf(val) >= (mean[level] + sigma[level])) { //for max + float valcour = xlogf(fabsf(val)); + float valc = valcour - logmax; + float vald = valc * rap; + absciss = xexpf(vald); + } else if (fabsf(val) >= mean[level]) { + absciss = asig * fabsf(val) + bsig; + } else { + absciss = amean * fabsf(val); + } + + float klev = 1.f; + if (level >= level_hl && level <= level_hr) { + klev = 1.f; + } + + if (level_hl != level_bl) { + if (level >= level_bl && level < level_hl) { + klev = alow * level + blow; + } + } + + if (level_hr != level_br) { + if (level > level_hr && level <= level_br) { + klev = ahigh * level + bhigh; + } + } + + float kc = klev * (loclmasCurvecolwav[absciss * 500.f] - 0.5f); + float amplieffect = kc <= 0.f ? 1.f : 4.f; + + float kinterm = 1.f + amplieffect * kc; + kinterm = kinterm <= 0.f ? 0.01f : kinterm; + + val *= kinterm; + + } + } + } + + } + } + + wdspot->reconstruct(bufmaskblurcol->L[0], 1.f); + delete wdspot; + + } + + if (lochhhmasCurve && HHmaskcurve) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + float huemah = xatan2f(bufmaskblurcol->b[ir][jr], bufmaskblurcol->a[ir][jr]); + float chromah = std::sqrt(SQR(bufmaskblurcol->b[ir][jr]) + SQR(bufmaskblurcol->a[ir][jr])); + + + float hh = Color::huelab_to_huehsv2(huemah); + hh += 1.f / 6.f; + + if (hh > 1.f) { + hh -= 1.f; + } + + const float val_HH = float ((0.5f - lochhhmasCurve[500.f * hh])); + const float hhro = 1.5f * val_HH; + float newhr = 0.f; + + if (hhro != 0) { + newhr = huemah + hhro;//we add radians and other dim between 0 1.. always radians but addition "false" + + if (newhr > rtengine::RT_PI_F) { + newhr -= 2 * rtengine::RT_PI_F; + } else if (newhr < -rtengine::RT_PI_F) { + newhr += 2 * rtengine::RT_PI_F; + } + } + + float2 sincosval = xsincosf(newhr); + bufmaskblurcol->a[ir][jr] = clipC(chromah * sincosval.y); + bufmaskblurcol->b[ir][jr] = clipC(chromah * sincosval.x); + + } + } + + if (amountcd > 1.f) { //dynamic range compression for Mask + FattalToneMappingParams fatParams; + fatParams.enabled = true; + fatParams.threshold = 100.f; + fatParams.amount = amountcd; + fatParams.anchor = anchorcd; + int nlev = 1; + Imagefloat *tmpImagefat = nullptr; + tmpImagefat = new Imagefloat(bfw, bfh); + lab2rgb(*bufmaskblurcol, *tmpImagefat, params->icm.workingProfile); + ToneMapFattal02(tmpImagefat, fatParams, nlev, 0, nullptr, 0, 0, 0); + rgb2lab(*tmpImagefat, *bufmaskblurcol, params->icm.workingProfile); + delete tmpImagefat; + } + + if (delt) { + const std::unique_ptr> rdEBuffer(new JaggedArray(bfw, bfh)); + float** rdE = *(rdEBuffer.get()); + + deltaEforMask(rdE, bfw, bfh, bufreserv.get(), hueref, chromaref, lumaref, maxdE, mindE, maxdElim, mindElim, iterat, limscope, scope, lp.balance, lp.balanceh); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + const float rdEval = rdE[ir][jr]; + bufmaskblurcol->L[ir][jr] = bufprov->L[ir][jr] + rdEval * (bufmaskblurcol->L[ir][jr] - bufprov->L[ir][jr]); + bufmaskblurcol->a[ir][jr] = bufprov->a[ir][jr] + rdEval * (bufmaskblurcol->a[ir][jr] - bufprov->a[ir][jr]); + bufmaskblurcol->b[ir][jr] = bufprov->b[ir][jr] + rdEval * (bufmaskblurcol->b[ir][jr] - bufprov->b[ir][jr]); + } + } + } + + struct grad_params gp; + + if (lp.strmaexp != 0.f) { + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, 0); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufmaskblurcol->L[ir][jr] *= ImProcFunctions::calcGradientFactor(gp, jr, ir); + } + } + } + + if (lap > 0.f) { + const float *datain = bufmaskblurcol->L[0]; + const std::unique_ptr data_tmp(new float[bfh * bfw]); + + if (!pde) { + ImProcFunctions::discrete_laplacian_threshold(data_tmp.get(), datain, bfw, bfh, 200.f * lap); + } else { + ImProcFunctions::retinex_pde(datain, data_tmp.get(), bfw, bfh, 12.f * lap, 1.f, nullptr, 0, 0, 1); + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufmaskblurcol->L[y][x] = data_tmp[y * bfw + x]; + } + } + } + } + + const float radiusb = 1.f / sk; + + if (deltaE || modmask || enaMask || showmaske) { +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufmaskblurcol->L, bufmaskblurcol->L, bfw, bfh, radiusb); + gaussianBlur(bufmaskblurcol->a, bufmaskblurcol->a, bfw, bfh, 1.f + (0.5f * rad) / sk); + gaussianBlur(bufmaskblurcol->b, bufmaskblurcol->b, bfw, bfh, 1.f + (0.5f * rad) / sk); + } + + if (zero || modif || modmask || deltaE || enaMask) { + originalmaskcol->CopyFrom(bufcolorig, multiThread); + blendmask(lp, xstart, ystart, cx, cy, bfw, bfh, bufcolorig, original, bufmaskblurcol, originalmaskcol, blendm, inv); + } + } +} + +void ImProcFunctions::InverseSharp_Local(float **loctemp, const float hueref, const float lumaref, const float chromaref, local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ +//local sharp + // BENCHFUN + const float ach = lp.trans / 100.f; + const int GW = transformed->W; + const int GH = transformed->H; + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + const bool sharshow = lp.showmasksharmet == 1; + const bool previewshar = lp.showmasksharmet == 2; + + if (lp.colorde == 0) { + lp.colorde = -1;//to avoid black + } + + float ampli = 1.f + std::fabs(lp.colorde); + ampli = 2.f + 0.5f * (ampli - 2.f); + + constexpr float aadark = -1.f; + constexpr float bbdark = 5000.f; + + const std::unique_ptr origblur(new LabImage(GW, GH)); + + float radius = 3.f / sk; +#ifdef _OPENMP + #pragma omp parallel +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const float mindE = 2.f + MINSCOPE * lp.senssha * lp.thr; + const float maxdE = 5.f + MAXSCOPE * lp.senssha * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + int loy = cy + y; + + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + const float abdelta2 = SQR(refa - origblur->a[y][x]) + SQR(refb - origblur->b[y][x]); + const float chrodelta2 = SQR(std::sqrt(SQR(origblur->a[y][x]) + SQR(origblur->b[y][x])) - (chromaref * 327.68f)); + const float huedelta2 = abdelta2 - chrodelta2; + const float dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - origblur->L[y][x])); + + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.senssha); + + switch (zone) { + case 0: { // outside selection and outside transition zone => full effect, no transition + const float difL = loctemp[y][x] - original->L[y][x]; + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + + if (sharshow) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = ampli * 5.f * difL * reducdE; + } else if (previewshar) { + float difbdisp = reducdE * 10000.f * lp.colorde; + + if (transformed->L[y][x] < bbdark) { //enhance dark luminance as user can see! + float dark = transformed->L[y][x]; + transformed->L[y][x] = dark * aadark + bbdark; + } + + if (lp.colorde <= 0) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = difbdisp; + } else { + transformed->a[y][x] = -difbdisp; + transformed->b[y][x] = 0.f; + } + + } + + break; + } + + case 1: { // inside transition zone + const float difL = (loctemp[y][x] - original->L[y][x]) * (1.f - localFactor); + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + + if (sharshow) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = ampli * 5.f * difL * reducdE; + } else if (previewshar || lp.prevdE) { + const float difbdisp = reducdE * 10000.f * lp.colorde; + + if (transformed->L[y][x] < bbdark) { //enhance dark luminance as user can see! + const float dark = transformed->L[y][x]; + transformed->L[y][x] = dark * aadark + bbdark; + } + + if (lp.colorde <= 0) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = difbdisp; + } else { + transformed->a[y][x] = -difbdisp; + transformed->b[y][x] = 0.f; + } + } + break; + } + + case 2: { // inside selection => no effect, keep original values + transformed->L[y][x] = original->L[y][x]; + } + } + } + } + } +} + +void ImProcFunctions::Sharp_Local(int call, float **loctemp, int senstype, const float hueref, const float chromaref, const float lumaref, local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ + BENCHFUN + const float ach = lp.trans / 100.f; + const float varsens = senstype == 1 ? lp.senslc : lp.senssha; + const bool sharshow = (lp.showmasksharmet == 1); + const bool previewshar = (lp.showmasksharmet == 2); + + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + + if (lp.colorde == 0) { + lp.colorde = -1;//to avoid black + } + + float ampli = 1.f + std::fabs(lp.colorde); + ampli = 2.f + 0.5f * (ampli - 2.f); + + float darklim = 5000.f; + float aadark = -1.f; + float bbdark = darklim; + + const int GW = transformed->W; + const int GH = transformed->H; + + const std::unique_ptr origblur(new LabImage(GW, GH)); + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + const float radius = 3.f / sk; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const int begy = int (lp.yc - lp.lyT); + const int begx = int (lp.xc - lp.lxL); + const float mindE = 2.f + MINSCOPE * varsens * lp.thr; + const float maxdE = 5.f + MAXSCOPE * varsens * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + const int loy = cy + y; + const bool isZone0 = loy > lp.yc + lp.ly || loy < lp.yc - lp.lyT; // whole line is zone 0 => we can skip a lot of processing + + if (isZone0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + for (int x = 0; x < transformed->W; x++) { + const int lox = cx + x; + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + //deltaE + const float abdelta2 = SQR(refa - origblur->a[y][x]) + SQR(refb - origblur->b[y][x]); + const float chrodelta2 = SQR(std::sqrt(SQR(origblur->a[y][x]) + SQR(origblur->b[y][x])) - (chromaref * 327.68f)); + const float huedelta2 = abdelta2 - chrodelta2; + const float dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - origblur->L[y][x])); + + float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, varsens); + const float reducview = reducdE; + reducdE *= localFactor; + + float difL; + + if (call == 2) { + difL = loctemp[loy - begy][lox - begx] - original->L[y][x]; + } else { + difL = loctemp[y][x] - original->L[y][x]; + } + + transformed->L[y][x] = CLIP(original->L[y][x] + difL * reducdE); + + if (sharshow) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = ampli * 5.f * difL * reducdE; + } else if (previewshar || lp.prevdE) { + float difbdisp = reducview * 10000.f * lp.colorde; + + if (transformed->L[y][x] < darklim) { //enhance dark luminance as user can see! + transformed->L[y][x] = transformed->L[y][x] * aadark + bbdark; + } + + if (lp.colorde <= 0) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = difbdisp; + } else { + transformed->a[y][x] = -difbdisp; + transformed->b[y][x] = 0.f; + } + } + } + } + } +} + +void ImProcFunctions::Exclude_Local(float **deltaso, float hueref, float chromaref, float lumaref, float sobelref, float meansobel, const struct local_params & lp, const LabImage * original, LabImage * transformed, const LabImage * rsv, const LabImage * reserv, int cx, int cy, int sk) +{ + + BENCHFUN { + const float ach = lp.trans / 100.f; + const float varsens = lp.sensexclu; + const float mindE = 2.f + MINSCOPE * varsens * lp.thr; + const float maxdE = 5.f + MAXSCOPE * varsens * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + + const int GW = transformed->W; + const int GH = transformed->H; + + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + // lumaref *= 327.68f; + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + //sobel + sobelref = rtengine::min(sobelref / 100.f, 60.f); + + const bool recip = sobelref < meansobel && sobelref < lp.stru; + + sobelref = log1p(sobelref); + + const std::unique_ptr origblur(new LabImage(GW, GH)); + + const float radius = 3.f / sk; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(reserv->L, origblur->L, GW, GH, radius); + gaussianBlur(reserv->a, origblur->a, GW, GH, radius); + gaussianBlur(reserv->b, origblur->b, GW, GH, radius); + + +#ifdef _OPENMP + #pragma omp barrier + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) + { + const int loy = cy + y; + const bool isZone0 = loy > (lp.yc + lp.ly - 1) || loy < lp.yc - lp.lyT; // // -1 fix issue 5554 + + if (isZone0) { // outside selection and outside transition zone => no effect, keep original values + for (int x = 0; x < transformed->W; x++) { + transformed->L[y][x] = original->L[y][x]; + } + + continue; + } + + for (int x = 0; x < transformed->W; x++) { + const int lox = cx + x; + const bool isZone0x = lox > (lp.xc + lp.lx - 1) || lox < lp.xc - lp.lxL; // -1 fix issue 5554 + + if (isZone0x) { // outside selection and outside transition zone => no effect, keep original values + for (int x = 0; x < transformed->W; x++) { + transformed->L[y][x] = original->L[y][x]; + } + + continue; + } + + const int begx = int (lp.xc - lp.lxL); + const int begy = int (lp.yc - lp.lyT); + + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + transformed->L[y][x] = original->L[y][x]; + continue; + } + + float rs = 0.f; + + const float csob = xlogf(1.f + rtengine::min(deltaso[loy - begy][lox - begx] / 100.f, 60.f) + 0.001f); + + if (!recip) { + rs = sobelref / csob; + } else { + rs = csob / sobelref; + } + + float affsob = 1.f; + + if (lp.struexc > 0.f && rs > 0.f) { + const float rsob = 0.002f * lp.struexc * rs; + const float minrs = 1.3f + 0.05f * lp.stru; + + if (rs < minrs) { + affsob = 1.f; + } else { + affsob = 1.f / pow_F((1.f + rsob), SQR(SQR(rs - minrs))); + } + } + + float abdelta2 = SQR(refa - origblur->a[y][x]) + SQR(refb - origblur->b[y][x]); + float chrodelta2 = SQR(std::sqrt(SQR(origblur->a[y][x]) + SQR(origblur->b[y][x])) - (chromaref * 327.68f)); + float huedelta2 = abdelta2 - chrodelta2; + const float dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - origblur->L[y][x])); + const float rL = origblur->L[y][x]; + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, varsens); + + if (rL > 32.768f) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 + if (zone > 0) { + + const float difL = (rsv->L[loy - begy][lox - begx] - original->L[y][x]) * localFactor; + transformed->L[y][x] = CLIP(original->L[y][x] + difL * affsob * reducdE); + + const float difa = (rsv->a[loy - begy][lox - begx] - original->a[y][x]) * localFactor; + transformed->a[y][x] = clipC(original->a[y][x] + difa * affsob * reducdE); + + const float difb = (rsv->b[loy - begy][lox - begx] - original->b[y][x]) * localFactor; + transformed->b[y][x] = clipC(original->b[y][x] + difb * affsob * reducdE); + + } + } + } + } + } + } +} + + + +void ImProcFunctions::transit_shapedetect_retinex(int call, int senstype, LabImage * bufexporig, LabImage * bufmask, LabImage * buforigmas, float **buflight, float **bufchro, const float hueref, const float chromaref, const float lumaref, const struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ + + BENCHFUN { + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + + + const float ach = lp.trans / 100.f; + const float varsens = lp.sensh; + + int GW = transformed->W; + int GH = transformed->H; + + // const float refa = chromaref * cos(hueref); + // const float refb = chromaref * sin(hueref); + + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + + const bool retishow = ((lp.showmaskretimet == 1 || lp.showmaskretimet == 2)); + const bool previewreti = ((lp.showmaskretimet == 4)); + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + + const bool showmas = lp.showmaskretimet == 3 ; + + const std::unique_ptr origblur(new LabImage(GW, GH)); + const float radius = 3.f / sk; + const bool usemaskreti = lp.enaretiMask && senstype == 4 && !lp.enaretiMasktmap; + float strcli = 0.03f * lp.str; + + if (lp.scalereti == 1) + { + strcli = 0.015 * lp.str; + } + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + } + + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const float mindE = 2.f + MINSCOPE * varsens * lp.thr; + const float maxdE = 5.f + MAXSCOPE * varsens * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + const float previewint = settings->previewselection; + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = ystart; y < yend; y++) + { + const int loy = cy + y; + + for (int x = xstart; x < xend; x++) { + const int lox = cx + x; + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + float rL = origblur->L[y][x] / 327.68f; + float dE; + float abdelta2 = 0.f; + float chrodelta2 = 0.f; + float huedelta2 = 0.f; + + if (!usemaskreti) { + abdelta2 = SQR(refa - origblur->a[y][x]) + SQR(refb - origblur->b[y][x]); + chrodelta2 = SQR(std::sqrt(SQR(origblur->a[y][x]) + SQR(origblur->b[y][x])) - (chromaref * 327.68f)); + huedelta2 = abdelta2 - chrodelta2; + dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - origblur->L[y][x])); + } else { + if (call == 2) { + abdelta2 = SQR(refa - buforigmas->a[y - ystart][x - xstart]) + SQR(refb - buforigmas->b[y - ystart][x - xstart]); + chrodelta2 = SQR(std::sqrt(SQR(buforigmas->a[y - ystart][x - xstart]) + SQR(buforigmas->b[y - ystart][x - xstart])) - (chromaref * 327.68f)); + huedelta2 = abdelta2 - chrodelta2; + dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - buforigmas->L[y - ystart][x - xstart])); + + } else { + abdelta2 = SQR(refa - buforigmas->a[y][x]) + SQR(refb - buforigmas->b[y][x]); + chrodelta2 = SQR(std::sqrt(SQR(buforigmas->a[y][x]) + SQR(buforigmas->b[y][x])) - (chromaref * 327.68f)); + huedelta2 = abdelta2 - chrodelta2; + dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - buforigmas->L[y][x])); + } + } + + float cli, clc; + + if (call == 2) { + cli = buflight[y - ystart][x - xstart]; + clc = previewreti ? settings->previewselection * 100.f : bufchro[y - ystart][x - xstart]; + } else { + cli = buflight[y][x]; + clc = previewreti ? settings->previewselection * 100.f : bufchro[y][x]; + + } + + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, varsens) / 100.f; + + cli *= reducdE; + clc *= reducdE; + cli *= (1.f + strcli); + + if (rL > 0.1f) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 + if (senstype == 4) {//all except color and light (TODO) and exposure + float lightc; + + if (call == 2) { + lightc = bufexporig->L[y - ystart][x - xstart]; + } else { + lightc = bufexporig->L[y][x]; + } + + float fli = 1.f + cli; + float diflc = lightc * fli - original->L[y][x]; + diflc *= localFactor; + + if (!showmas) { + transformed->L[y][x] = CLIP(original->L[y][x] + diflc); + } else { + if (call == 2) { + + transformed->L[y][x] = bufmask->L[y - ystart][x - xstart]; + } else { + transformed->L[y][x] = bufmask->L[y][x]; + } + } ; + + if (retishow) { + transformed->L[y][x] = CLIP(12000.f + diflc); + } + } + + float fliab = 1.f; + float chra, chrb; + + if (call == 2) { + chra = bufexporig->a[y - ystart][x - xstart]; + chrb = bufexporig->b[y - ystart][x - xstart]; + } else { + chra = bufexporig->a[y][x]; + chrb = bufexporig->b[y][x]; + + } + + if (senstype == 5) { + fliab = 1.f + clc; + } + + const float difa = (chra * fliab - original->a[y][x]) * localFactor; + float difb = (chrb * fliab - original->b[y][x]) * localFactor; + + transformed->a[y][x] = clipC(original->a[y][x] + difa); + transformed->b[y][x] = clipC(original->b[y][x] + difb); + + if (showmas) { + if (call == 2) { + transformed->a[y][x] = bufmask->a[y - ystart][x - xstart]; + transformed->b[y][x] = bufmask->b[y - ystart][x - xstart]; + } else { + transformed->a[y][x] = bufmask->a[y][x]; + transformed->b[y][x] = bufmask->b[y][x]; + + } + } + + if (retishow) { + transformed->a[y][x] = clipC(difa); + transformed->b[y][x] = clipC(difb); + } + + if (previewreti) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = previewint * difb; + } + } + } + } + } + + if (showmas || retishow || previewreti) + { + return; + } + + } +} + + +void ImProcFunctions::transit_shapedetect(int senstype, const LabImage * bufexporig, LabImage * originalmask, float **bufchro, bool HHutili, const float hueref, const float chromaref, const float lumaref, float sobelref, float meansobel, float ** blend2, const struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ + + BENCHFUN + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + const int bfw = xend - xstart; + const int bfh = yend - ystart; + // printf("h=%f l=%f c=%f s=%f\n", hueref, lumaref, chromaref, sobelref); + const float ach = lp.trans / 100.f; + float varsens = lp.sensex; + + if (senstype == 6 || senstype == 7) //cbdl + { + varsens = lp.senscb; + } else if (senstype == 8) //TM + { + varsens = lp.senstm; + } else if (senstype == 10) //local contrast + { + varsens = lp.senslc; + } + + //sobel //keep in case of, not used + sobelref /= 100.f; + meansobel /= 100.f; + + sobelref = rtengine::min(sobelref, 60.f); + + const bool k = !(sobelref < meansobel && sobelref < lp.stru); //does not always work with noisy images + + sobelref = log1p(sobelref); + + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + const float previewint = settings->previewselection; + + const bool cbshow = ((lp.showmaskcbmet == 1 || lp.showmaskcbmet == 2) && senstype == 6); + const bool tmshow = ((lp.showmasktmmet == 1 || lp.showmasktmmet == 2) && senstype == 8); + const bool previewcb = ((lp.showmaskcbmet == 4) && senstype == 6); + const bool previewtm = ((lp.showmasktmmet == 4) && senstype == 8); + + const std::unique_ptr origblur(new LabImage(bfw, bfh)); + std::unique_ptr origblurmask; + + float radius = 3.f / sk; + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const bool usemaskcb = (lp.showmaskcbmet == 2 || lp.enacbMask || lp.showmaskcbmet == 4) && senstype == 6; + const bool usemasktm = (lp.showmasktmmet == 2 || lp.enatmMask || lp.showmasktmmet == 4) && senstype == 8; + const bool usemaskall = (usemaskcb || usemasktm); + + if (usemaskall) + { + origblurmask.reset(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(originalmask->L, origblurmask->L, bfw, bfh, radius); + gaussianBlur(originalmask->a, origblurmask->a, bfw, bfh, radius); + gaussianBlur(originalmask->b, origblurmask->b, bfw, bfh, radius); + } + } + if (lp.equtm && senstype == 8) //normalize luminance for Tone mapping , at this place we can use for others senstype! + { + float *datain = new float[bfh * bfw]; + float *data = new float[bfh * bfw]; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + for (int y = ystart; y < yend; y++) + for (int x = xstart; x < xend; x++) { + datain[(y - ystart) * bfw + (x - xstart)] = original->L[y][x]; + data[(y - ystart)* bfw + (x - xstart)] = bufexporig->L[y - ystart][x - xstart]; + } + + normalize_mean_dt(data, datain, bfh * bfw, 1.f, 1.f); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = ystart; y < yend; y++) + for (int x = xstart; x < xend; x++) { + bufexporig->L[y - ystart][x - xstart] = data[(y - ystart) * bfw + x - xstart]; + } + + delete [] datain; + delete [] data; + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh; y++) + { + for (int x = 0; x < bfw; x++) { + origblur->L[y][x] = original->L[y + ystart][x + xstart]; + origblur->a[y][x] = original->a[y + ystart][x + xstart]; + origblur->b[y][x] = original->b[y + ystart][x + xstart]; + } + } + + gaussianBlur(origblur->L, origblur->L, bfw, bfh, radius); + gaussianBlur(origblur->a, origblur->a, bfw, bfh, radius); + gaussianBlur(origblur->b, origblur->b, bfw, bfh, radius); + + } + + const LabImage *maskptr = usemaskall ? origblurmask.get() : origblur.get(); + const float mindE = 2.f + MINSCOPE * varsens * lp.thr; + const float maxdE = 5.f + MAXSCOPE * varsens * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + float atan2Buffer[transformed->W] ALIGNED16; +#endif + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = ystart; y < yend; y++) + { + const int loy = cy + y; + +#ifdef __SSE2__ + + if (HHutili || senstype == 7) { + int i = xstart; + + for (; i < xend - 3; i += 4) { + vfloat av = LVFU(origblur->a[y - ystart][i - xstart]); + vfloat bv = LVFU(origblur->b[y - ystart][i - xstart]); + STVFU(atan2Buffer[i], xatan2f(bv, av)); + } + + for (; i < xend; i++) { + atan2Buffer[i] = xatan2f(origblur->b[y - ystart][i - xstart], origblur->a[y - ystart][i - xstart]); + } + } + +#endif + + for (int x = xstart; x < xend; x++) { + const int lox = cx + x; + + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + float rhue = 0; + + if (HHutili || senstype == 7) { +#ifdef __SSE2__ + rhue = atan2Buffer[x]; +#else + rhue = xatan2f(origblur->b[y - ystart][x - xstart], origblur->a[y - ystart][x - xstart]); +#endif + } + + const float rL = origblur->L[y - ystart][x - xstart] / 327.68f; + float rsob = 0.f; + + if (blend2 && ((senstype == 1 && lp.struexp > 0.f) || ((senstype == 0 || senstype == 100) && lp.struco > 0.f))) {//keep in case of, not used + const float csob = xlogf(1.f + rtengine::min(blend2[y - ystart][x - xstart] / 100.f, 60.f) + 0.001f); + + float rs; + + if (k) { + rs = sobelref / csob; + } else { + rs = csob / sobelref; + } + + if (rs > 0.f && senstype == 1) { + rsob = 1.1f * lp.struexp * rs; + } else if (rs > 0.f && (senstype == 0 || senstype == 100)) { + rsob = 1.1f * lp.struco * rs; + } + } + + const float dE = rsob + std::sqrt(kab * (SQR(refa - maskptr->a[y - ystart][x - xstart]) + SQR(refb - maskptr->b[y - ystart][x - xstart])) + kL * SQR(refL - maskptr->L[y - ystart][x - xstart])); + const float clc = (previewcb) ? settings->previewselection * 100.f : bufchro[y - ystart][x - xstart]; + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, varsens); + const float realstrchdE = reducdE * clc; + + if (rL > 0.1f) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 + if (zone > 0) { + float factorx = localFactor; + float difL = 0.f; + + if (senstype == 6 || senstype == 8 || senstype == 10) { + difL = (bufexporig->L[y - ystart][x - xstart] - original->L[y][x]) * localFactor * reducdE; + transformed->L[y][x] = CLIP(original->L[y][x] + difL); + } + + if (senstype == 7) { + float difab = bufexporig->L[y - ystart][x - xstart] - std::sqrt(SQR(original->a[y][x]) + SQR(original->b[y][x])); + float2 sincosval = xsincosf(rhue); + float difa = difab * sincosval.y; + float difb = difab * sincosval.x; + difa *= factorx * (100.f + realstrchdE) / 100.f; + difb *= factorx * (100.f + realstrchdE) / 100.f; + transformed->a[y][x] = clipC(original->a[y][x] + difa); + transformed->b[y][x] = clipC(original->b[y][x] + difb); + } else { + float flia = 1.f; + float flib = 1.f; + float chra = bufexporig->a[y - ystart][x - xstart]; + float chrb = bufexporig->b[y - ystart][x - xstart]; + + if (senstype == 3 || senstype == 30 || senstype == 8 || senstype == 6 || senstype == 10) { + flia = flib = ((100.f + realstrchdE) / 100.f); + } + + + float difa = chra * flia - original->a[y][x]; + float difb = chrb * flib - original->b[y][x]; + difa *= factorx; + difb *= factorx; + + transformed->a[y][x] = clipC(original->a[y][x] + difa); + transformed->b[y][x] = clipC(original->b[y][x] + difb); + + + if (cbshow || tmshow) { + transformed->L[y][x] = CLIP(12000.f + difL); + transformed->a[y][x] = clipC(difa); + transformed->b[y][x] = clipC(difb); + } else if (previewcb || previewtm || lp.prevdE) { + if (std::fabs(difb) < 500.f) { + difb += difL; + } + + transformed->a[y][x] = 0.f; + transformed->b[y][x] = previewint * difb; + } + } + } + } + } + } + } +} + +void ImProcFunctions::InverseColorLight_Local(bool tonequ, bool tonecurv, int sp, int senstype, struct local_params & lp, LabImage * originalmask, const LUTf& lightCurveloc, const LUTf& hltonecurveloc, const LUTf& shtonecurveloc, const LUTf& tonecurveloc, const LUTf& exlocalcurve, const LUTf& cclocalcurve, float adjustr, bool localcutili, const LUTf& lllocalcurve, bool locallutili, LabImage * original, LabImage * transformed, int cx, int cy, const float hueref, const float chromaref, const float lumaref, int sk) +{ + // BENCHFUN + const float ach = lp.trans / 100.f; + const float facc = (100.f + lp.chro) / 100.f; //chroma factor transition + float varsens = lp.sens; + + if (senstype == 0) { //Color and Light + varsens = lp.sens; + } else if (senstype == 1) { //exposure + varsens = lp.sensex; + } else if (senstype == 2) { //shadows highlight + varsens = lp.senshs; + } + + const int GW = transformed->W; + const int GH = transformed->H; + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + + const std::unique_ptr temp(new LabImage(GW, GH)); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H; y++) { + for (int x = 0; x < transformed->W; x++) { + temp->L[y][x] = original->L[y][x]; + temp->a[y][x] = original->a[y][x]; + temp->b[y][x] = original->b[y][x]; + } + } + + if (senstype == 2) { // Shadows highlight + if (lp.shmeth == 0) { + ImProcFunctions::shadowsHighlights(temp.get(), lp.hsena, 1, lp.highlihs, lp.shadowhs, lp.radiushs, sk, lp.hltonalhs, lp.shtonalhs); + } else if (lp.shmeth == 1) { + const std::unique_ptr tmpImage(new Imagefloat(GW, GH)); + + lab2rgb(*temp, *tmpImage, params->icm.workingProfile); + + if (tonecurv) { //Tone response curve : does nothing if gamma=2.4 and slope=12.92 ==> gamma sRGB + const float gamtone = params->locallab.spots.at(sp).gamSH; + const float slotone = params->locallab.spots.at(sp).sloSH; + cmsHTRANSFORM dummy = nullptr; + workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, -5, params->icm.workingProfile, 2.4, 12.92310, dummy, true, false, false); + workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, 5, params->icm.workingProfile, gamtone, slotone, dummy, false, true, true); + } + + if (tonequ) { + tmpImage->normalizeFloatTo1(); + array2D Rtemp(GW, GH, tmpImage->r.ptrs, ARRAY2D_BYREFERENCE); + array2D Gtemp(GW, GH, tmpImage->g.ptrs, ARRAY2D_BYREFERENCE); + array2D Btemp(GW, GH, tmpImage->b.ptrs, ARRAY2D_BYREFERENCE); + tone_eq(Rtemp, Gtemp, Btemp, lp, params->icm.workingProfile, sk, multiThread); + tmpImage->normalizeFloatTo65535(); + } + + rgb2lab(*tmpImage, *temp, params->icm.workingProfile); + } + + } else if (senstype == 1) { //exposure + ImProcFunctions::exlabLocal(lp, GH, GW, original, temp.get(), hltonecurveloc, shtonecurveloc, tonecurveloc); + + if (exlocalcurve) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < temp->H; y++) { + for (int x = 0; x < temp->W; x++) { + const float lh = 0.5f * exlocalcurve[2.f * temp->L[y][x]]; // / ((lighn) / 1.9f) / 3.61f; //lh between 0 and 0 50 or more + temp->L[y][x] = lh; + } + } + } + + if (lp.expchroma != 0.f) { + const float ch = (1.f + 0.02f * lp.expchroma) ; + float chprosl; + + if (ch <= 1.f) {//convert data curve near values of slider -100 + 100, to be used after to detection shape + chprosl = 99.f * ch - 99.f; + } else { + constexpr float ampli = 70.f; + chprosl = clipChro(ampli * ch - ampli); //ampli = 25.f arbitrary empirical coefficient between 5 and 50 + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H; y++) { + for (int x = 0; x < transformed->W; x++) { + const float epsi = original->L[y][x] == 0.f ? 0.001f : 0.f; + const float rapexp = temp->L[y][x] / (original->L[y][x] + epsi); + temp->a[y][x] *= (1.f + chprosl * rapexp); + temp->b[y][x] *= (1.f + chprosl * rapexp); + } + } + } + } else if (senstype == 0) { //Color and Light curves L C + if (cclocalcurve && localcutili) { // C=f(C) curve +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H; y++) { + for (int x = 0; x < transformed->W; x++) { + //same as in "normal" + const float chromat = std::sqrt(SQR(original->a[y][x]) + SQR(original->b[y][x])); + constexpr float ampli = 25.f; + const float ch = (cclocalcurve[chromat * adjustr ]) / ((chromat + 0.00001f) * adjustr); //ch between 0 and 0 50 or more + const float chprocu = clipChro(ampli * ch - ampli); //ampli = 25.f arbitrary empirical coefficient between 5 and 50 + temp->a[y][x] = original->a[y][x] * (1.f + 0.01f * chprocu); + temp->b[y][x] = original->b[y][x] * (1.f + 0.01f * chprocu); + + } + } + } + + if (lllocalcurve && locallutili) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H; y++) { + for (int x = 0; x < transformed->W; x++) { + temp->L[y][x] = 0.5f * lllocalcurve[2.f * original->L[y][x]]; + } + } + } + } + + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + + const std::unique_ptr origblur(new LabImage(GW, GH)); + std::unique_ptr origblurmask; + const bool usemaskcol = (lp.enaColorMaskinv) && senstype == 0; + const bool usemaskexp = (lp.enaExpMaskinv) && senstype == 1; + const bool usemasksh = (lp.enaSHMaskinv) && senstype == 2; + const bool usemaskall = (usemaskcol || usemaskexp || usemasksh); + + float radius = 3.f / sk; + + if (usemaskall) { + origblurmask.reset(new LabImage(GW, GH)); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(originalmask->L, origblurmask->L, GW, GH, radius); + gaussianBlur(originalmask->a, origblurmask->a, GW, GH, radius); + gaussianBlur(originalmask->b, origblurmask->b, GW, GH, radius); + } + } + + if (senstype == 1) { + radius = (2.f + 0.2f * lp.blurexp) / sk; + } else if (senstype == 0) { + radius = (2.f + 0.2f * lp.blurcol) / sk; + } else if (senstype == 2) { + radius = (2.f + 0.2f * lp.blurSH) / sk; + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const LabImage *maskptr = usemaskall ? origblurmask.get() : origblur.get(); + const float mindE = 2.f + MINSCOPE * varsens * lp.thr; + const float maxdE = 5.f + MAXSCOPE * varsens * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + const int loy = cy + y; + + for (int x = 0; x < transformed->W; x++) { + const float rL = origblur->L[y][x] / 327.68f; + + if (std::fabs(origblur->b[y][x]) < 0.01f) { + origblur->b[y][x] = 0.01f; + } + + constexpr float th_r = 0.01f; + + if (rL > th_r) { //to avoid crash with very low gamut in rare cases ex : L=0.01 a=0.5 b=-0.9 + const int lox = cx + x; + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor);//rect not good + } + + //deltaE + float reducdE; + if (zone != 2) { + const float abdelta2 = SQR(refa - maskptr->a[y][x]) + SQR(refb - maskptr->b[y][x]); + const float chrodelta2 = SQR(std::sqrt(SQR(maskptr->a[y][x]) + SQR(maskptr->b[y][x])) - (chromaref * 327.68f)); + const float huedelta2 = abdelta2 - chrodelta2; + const float dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - maskptr->L[y][x])); + reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, varsens); + } + + switch (zone) { + case 2: { // outside selection and outside transition zone => no effect, keep original values + transformed->L[y][x] = original->L[y][x]; + transformed->a[y][x] = original->a[y][x]; + transformed->b[y][x] = original->b[y][x]; + break; + } + + case 1: { // inside transition zone + const float factorx = 1.f - localFactor; + + if (senstype == 0) { + const float epsia = original->a[y][x] == 0.f ? 0.0001f : 0.f; + const float epsib = original->b[y][x] == 0.f ? 0.0001f : 0.f; + float lumnew = original->L[y][x]; + const float difL = (temp->L[y][x] - original->L[y][x]) * (reducdE * factorx); + const float difa = (temp->a[y][x] - original->a[y][x]) * (reducdE * factorx); + const float difb = (temp->b[y][x] - original->b[y][x]) * (reducdE * factorx); + const float facCa = 1.f + (difa / (original->a[y][x] + epsia)); + const float facCb = 1.f + (difb / (original->b[y][x] + epsib)); + + if (lp.sens < 75.f) { + if ((lp.ligh != 0.f || lp.cont != 0)) { + lumnew = calclightinv(lumnew, lp.ligh, lightCurveloc); //replace L-curve + } + + const float fac = (100.f + factorx * lp.chro * reducdE) / 100.f; //chroma factor transition + const float diflc = (lumnew - original->L[y][x]) * (reducdE * factorx); + + transformed->L[y][x] = CLIP(1.f * (original->L[y][x] + diflc + difL)); + transformed->a[y][x] = clipC(original->a[y][x] * fac * facCa) ; + transformed->b[y][x] = clipC(original->b[y][x] * fac * facCb); + } else { + const float fac = (100.f + factorx * lp.chro) / 100.f; //chroma factor transition + + if ((lp.ligh != 0.f || lp.cont != 0)) { + lumnew = calclightinv(original->L[y][x], lp.ligh, lightCurveloc); + } + + const float diflc = (lumnew - original->L[y][x]) * factorx; + transformed->L[y][x] = CLIP(original->L[y][x] + diflc + difL); + transformed->a[y][x] = clipC(original->a[y][x] * fac * facCa); + transformed->b[y][x] = clipC(original->b[y][x] * fac * facCb); + } + } else if (senstype == 1 || senstype == 2) { + const float diflc = (temp->L[y][x] - original->L[y][x]) * (reducdE * factorx); + const float difa = (temp->a[y][x] - original->a[y][x]) * (reducdE * factorx); + const float difb = (temp->b[y][x] - original->b[y][x]) * (reducdE * factorx); + transformed->L[y][x] = CLIP(original->L[y][x] + diflc); + transformed->a[y][x] = clipC(original->a[y][x] + difa) ; + transformed->b[y][x] = clipC(original->b[y][x] + difb); + } + + break; + } + + case 0: { // inside selection => full effect, no transition + if (senstype == 0) { + const float epsia = original->a[y][x] == 0.f ? 0.0001f : 0.f; + const float epsib = original->b[y][x] == 0.f ? 0.0001f : 0.f; + float lumnew = original->L[y][x]; + const float difL = (temp->L[y][x] - original->L[y][x]) * reducdE; + const float difa = (temp->a[y][x] - original->a[y][x]) * reducdE; + const float difb = (temp->b[y][x] - original->b[y][x]) * reducdE; + const float facCa = 1.f + difa / (original->a[y][x] + epsia); + const float facCb = 1.f + difb / (original->b[y][x] + epsib); + + if (lp.sens < 75.f) { + if ((lp.ligh != 0.f || lp.cont != 0)) { + lumnew = calclightinv(lumnew, lp.ligh, lightCurveloc); //replace L-curve + } + + const float fac = (100.f + lp.chro * reducdE) / 100.f; //chroma factor transition + const float diflc = (lumnew - original->L[y][x]) * reducdE; + + transformed->L[y][x] = CLIP(original->L[y][x] + diflc + difL); + transformed->a[y][x] = clipC(original->a[y][x] * fac * facCa) ; + transformed->b[y][x] = clipC(original->b[y][x] * fac * facCb); + } else { + if ((lp.ligh != 0.f || lp.cont != 0)) { + lumnew = calclightinv(original->L[y][x], lp.ligh, lightCurveloc); + } + + transformed->L[y][x] = CLIP(lumnew + difL) ; + transformed->a[y][x] = clipC(original->a[y][x] * facc * facCa); + transformed->b[y][x] = clipC(original->b[y][x] * facc * facCb); + } + } else if (senstype == 1 || senstype == 2) { + const float diflc = (temp->L[y][x] - original->L[y][x]) * reducdE; + const float difa = (temp->a[y][x] - original->a[y][x]) * reducdE; + const float difb = (temp->b[y][x] - original->b[y][x]) * reducdE; + transformed->L[y][x] = CLIP(original->L[y][x] + diflc); + transformed->a[y][x] = clipC(original->a[y][x] + difa) ; + transformed->b[y][x] = clipC(original->b[y][x] + difb); + } + } + } + } + } + } + } +} + +void ImProcFunctions::calc_ref(int sp, LabImage * original, LabImage * transformed, int cx, int cy, int oW, int oH, int sk, double & huerefblur, double & chromarefblur, double & lumarefblur, double & hueref, double & chromaref, double & lumaref, double & sobelref, float & avg, const LocwavCurve & locwavCurveden, bool locwavdenutili) +{ + if (params->locallab.enabled) { + //always calculate hueref, chromaref, lumaref before others operations use in normal mode for all modules exceprt denoise + struct local_params lp; + calcLocalParams(sp, oW, oH, params->locallab, lp, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, locwavCurveden, locwavdenutili); + int begy = lp.yc - lp.lyT; + int begx = lp.xc - lp.lxL; + int yEn = lp.yc + lp.ly; + int xEn = lp.xc + lp.lx; + float avg2 = 0.f; + int nc2 = 0; + + for (int y = 0; y < transformed->H ; y++) //{ + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + int loy = cy + y; + + if (lox >= begx && lox < xEn && loy >= begy && loy < yEn) { + avg2 += original->L[y][x]; + nc2++; + } + } + + avg2 /= 32768.f; + avg = avg2 / nc2; +// double precision for large summations + double aveA = 0.; + double aveB = 0.; + double aveL = 0.; + double aveChro = 0.; + double aveAblur = 0.; + double aveBblur = 0.; + double aveLblur = 0.; + double aveChroblur = 0.; + + double avesobel = 0.; +// int precision for the counters + int nab = 0; + int nso = 0; + int nsb = 0; +// single precision for the result + float avA, avB, avL; + int spotSize = 0.88623f * rtengine::max(1, lp.cir / sk); //18 + //O.88623 = std::sqrt(PI / 4) ==> sqare equal to circle + int spotSise2; // = 0.88623f * max (1, lp.cir / sk); //18 + + // very small region, don't use omp here + LabImage *sobelL; + LabImage *deltasobelL; + LabImage *origsob; + LabImage *origblur = nullptr; + LabImage *blurorig = nullptr; + + int spotSi = 1 + 2 * rtengine::max(1, lp.cir / sk); + + if (spotSi < 5) { + spotSi = 5; + } + + spotSise2 = (spotSi - 1) / 2; + + JaggedArray blend3(spotSi, spotSi); + + origsob = new LabImage(spotSi, spotSi); + sobelL = new LabImage(spotSi, spotSi); + deltasobelL = new LabImage(spotSi, spotSi); + bool isdenoise = false; + + if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f) && lp.denoiena) { + isdenoise = true; + } + + if (isdenoise) { + origblur = new LabImage(spotSi, spotSi); + blurorig = new LabImage(spotSi, spotSi); + + for (int y = rtengine::max(cy, (int)(lp.yc - spotSise2)); y < rtengine::min(transformed->H + cy, (int)(lp.yc + spotSise2 + 1)); y++) { + for (int x = rtengine::max(cx, (int)(lp.xc - spotSise2)); x < rtengine::min(transformed->W + cx, (int)(lp.xc + spotSise2 + 1)); x++) { + int yb = rtengine::max(cy, (int)(lp.yc - spotSise2)); + + int xb = rtengine::max(cx, (int)(lp.xc - spotSise2)); + + int z = y - yb; + int u = x - xb; + origblur->L[z][u] = original->L[y - cy][x - cx]; + origblur->a[z][u] = original->a[y - cy][x - cx]; + origblur->b[z][u] = original->b[y - cy][x - cx]; + + } + } + + float radius = 3.f / sk; + { + //No omp + gaussianBlur(origblur->L, blurorig->L, spotSi, spotSi, radius); + gaussianBlur(origblur->a, blurorig->a, spotSi, spotSi, radius); + gaussianBlur(origblur->b, blurorig->b, spotSi, spotSi, radius); + + } + + for (int y = 0; y < spotSi; y++) { + for (int x = 0; x < spotSi; x++) { + aveLblur += blurorig->L[y][x]; + aveAblur += blurorig->a[y][x]; + aveBblur += blurorig->b[y][x]; + aveChroblur += std::sqrt(SQR(blurorig->b[y - cy][x - cx]) + SQR(blurorig->a[y - cy][x - cx])); + nsb++; + + } + } + } + + //ref for luma, chroma, hue + for (int y = rtengine::max(cy, (int)(lp.yc - spotSize)); y < rtengine::min(transformed->H + cy, (int)(lp.yc + spotSize + 1)); y++) { + for (int x = rtengine::max(cx, (int)(lp.xc - spotSize)); x < rtengine::min(transformed->W + cx, (int)(lp.xc + spotSize + 1)); x++) { + aveL += original->L[y - cy][x - cx]; + aveA += original->a[y - cy][x - cx]; + aveB += original->b[y - cy][x - cx]; + aveChro += std::sqrt(SQR(original->b[y - cy][x - cx]) + SQR(original->a[y - cy][x - cx])); + nab++; + } + } + + //ref for sobel + for (int y = rtengine::max(cy, (int)(lp.yc - spotSise2)); y < rtengine::min(transformed->H + cy, (int)(lp.yc + spotSise2 + 1)); y++) { + for (int x = rtengine::max(cx, (int)(lp.xc - spotSise2)); x < rtengine::min(transformed->W + cx, (int)(lp.xc + spotSise2 + 1)); x++) { + int yb = rtengine::max(cy, (int)(lp.yc - spotSise2)); + + int xb = rtengine::max(cx, (int)(lp.xc - spotSise2)); + + int z = y - yb; + int u = x - xb; + origsob->L[z][u] = original->L[y - cy][x - cx]; + nso++; + } + } + + const float radius = 3.f / (sk * 1.4f); //0 to 70 ==> see skip + + SobelCannyLuma(sobelL->L, origsob->L, spotSi, spotSi, radius); + int nbs = 0; + + for (int y = 0; y < spotSi ; y ++) + for (int x = 0; x < spotSi ; x ++) { + avesobel += sobelL->L[y][x]; + nbs++; + } + + sobelref = avesobel / nbs; + + delete sobelL; + + delete deltasobelL; + delete origsob; + aveL = aveL / nab; + aveA = aveA / nab; + aveB = aveB / nab; + aveChro = aveChro / nab; + aveChro /= 327.68f; + avA = aveA / 327.68f; + avB = aveB / 327.68f; + avL = aveL / 327.68f; + hueref = xatan2f(avB, avA); //mean hue + + if (isdenoise) { + aveLblur = aveLblur / nsb; + aveChroblur = aveChroblur / nsb; + aveChroblur /= 327.68f; + aveAblur = aveAblur / nsb; + aveBblur = aveBblur / nsb; + float avAblur = aveAblur / 327.68f; + float avBblur = aveBblur / 327.68f; + float avLblur = aveLblur / 327.68f; + huerefblur = xatan2f(avBblur, avAblur); + chromarefblur = aveChroblur; + lumarefblur = avLblur; + } else { + huerefblur = 0.f; + chromarefblur = 0.f; + lumarefblur = 0.f; + } + + chromaref = aveChro; + lumaref = avL; + + // printf("Calcref => sp=%i befend=%i huere=%2.1f chromare=%2.1f lumare=%2.1f sobelref=%2.1f\n", sp, befend, hueref, chromaref, lumaref, sobelref / 100.f); + + if (isdenoise) { + delete origblur; + delete blurorig; + } + + if (lumaref > 95.f) {//to avoid crash + lumaref = 95.f; + } + } +} +//doc fftw3 says optimum is with size 2^a * 3^b * 5^c * 7^d * 11^e * 13^f with e+f = 0 or 1 +//number for size between 18144 and 1 ==> 18000 pixels cover 99% all sensor +const int fftw_size[] = {18144, 18000, 17920, 17836, 17820, 17640, 17600, 17550, 17500, 17496, 17472, 17325, 17280, 17248, 17199, 17150, 17010, 16896, 16875, 16848, 16807, + 16800, 16640, 16632, 16500, 16464, 16384, 16380, 16250, 16200, 16170, 16128, 16038, 16000, 15925, 15876, 15840, 15795, 15750, 15680, 15625, 15600, 15552, 15435, 15400, + 15360, 15309, 15288, 15120, 15092, 15000, 14976, 14850, 14784, 14742, 14700, 14625, 14580, 14560, 14553, 14336, 14406, 14400, 14256, 14175, 14112, 14080, 14040, 14000, 13860, + 13824, 13750, 13720, 13650, 13608, 13500, 13475, 13440, 13377, 13365, 13312, 13230, 13200, 13125, 13122, 13104, 13000, 12960, 12936, 12800, 12740, 12672, 12636, 12600, + 12544, 12500, 12480, 12474, 12375, 12348, 12320, 12288, 12285, 12250, 12150, 12096, 12005, 12000, 11907, 11880, 11760, 11700, 11664, 11648, 11550, 11520, 11466, 11375, + 11340, 11319, 11264, 11250, 11232, 11200, 11088, 11025, 11000, 10976, 10935, 10920, 10800, 10780, 10752, 10692, 10584, 10560, 10530, 10400, 10395, 10368, 10290, 10240, + 10206, 10192, 10125, 10080, 10000, 9984, 9900, 9604, 9856, 9828, 9800, 9750, 9720, 9702, 9625, 9600, 9555, 9504, 9477, 9450, 9408, 9375, 9360, 9261, 9240, + 9216, 9100, 9072, 9000, 8960, 8918, 8910, 8820, 8800, 8775, 8750, 8748, 8736, 8640, 8624, 8575, 8505, 8448, 8424, 8400, 8320, 8316, 8250, 8232, 8192, 8190, 8125, + 8100, 8085, 8064, 8019, 8000, 7938, 7920, 7875, 7840, 7800, 7776, 7700, 7680, 7644, 7560, 7546, 7500, 7488, 7425, 7392, 7371, 7350, 7290, 7280, 7203, 7200, 7168, + 7128, 7056, 7040, 7020, 7000, 6930, 6912, 6875, 6860, 6825, 6804, 6750, 6720, 6656, 6615, 6600, 6561, 6552, 6500, 6480, 6468, 6400, 6370, 6336, 6318, 6300, + 6272, 6250, 6240, 6237, 6174, 6160, 6144, 6125, 6075, 6048, 6000, 5940, 5880, 5850, 5832, 5824, 5775, 5760, 5670, 5632, 5625, 5616, 5600, 5544, 5500, 5488, + 5460, 5400, 5390, 5376, 5346, 5292, 5280, 5265, 5250, 5200, 5184, 5145, 5120, 5103, 5096, 5040, 5000, 4992, 4950, 4928, 4914, 4900, 4875, 4860, 4851, 4802, + 4800, 4752, 4725, 4704, 4680, 4620, 4608, 4550, 4536, 4500, 4480, 4459, 4455, 4410, 4400, 4375, 4374, 4368, 4320, 4312, 4224, 4212, 4200, 4160, 4158, 4125, + 4116, 4096, 4095, 4050, 4032, 4000, 3969, 3960, 3920, 3900, 3888, 3850, 3840, 3822, 3780, 3773, 3750, 3744, 3696, 3675, 3645, 3640, 3600, 3584, 3564, 3528, + 3520, 3510, 3500, 3465, 3456, 3430, 3402, 3375, 3360, 3328, 3300, 3276, 3250, 3240, 3234, 3200, 3185, 3168, 3159, 3150, 3136, 3125, 3120, 3087, 3080, 3072, + 3024, 3000, 2970, 2940, 2925, 2916, 2912, 2880, 2835, 2816, 2808, 2800, 2772, 2750, 2744, 2730, 2700, 2695, 2688, 2673, 2646, 2640, 2625, 2600, 2592, 2560, + 2548, 2520, 2500, 2496, 2475, 2464, 2457, 2450, 2430, 2401, 2400, 2376, 2352, 2340, 2310, 2304, 2275, 2268, 2250, 2240, 2205, 2200, 2187, 2184, 2160, 2156, + 2112, 2106, 2100, 2080, 2079, 2058, 2048, 2025, 2016, 2000, 1980, 1960, 1950, 1944, 1936, 1925, 1920, 1911, 1890, 1875, 1872, 1848, 1820, 1800, 1792, 1782, + 1764, 1760, 1755, 1750, 1728, 1715, 1701, 1680, 1664, 1650, 1638, 1625, 1620, 1617, 1600, 1584, 1575, 1568, 1560, 1540, 1536, 1512, 1500, 1485, 1470, 1458, + 1456, 1440, 1408, 1404, 1400, 1386, 1375, 1372, 1365, 1350, 1344, 1323, 1320, 1300, 1296, 1280, 1274, 1260, 1250, 1248, 1232, 1225, 1215, 1200, 1188, 1176, + 1170, 1155, 1152, 1134, 1125, 1120, 1100, 1092, 1080, 1078, 1056, 1053, 1050, 1040, 1029, 1024, 1008, 1000, 990, 980, 975, 972, 960, 945, 936, 924, 910, 900, + 896, 891, 882, 880, 875, 864, 840, 832, 825, 819, 810, 800, 792, 784, 780, 770, 768, 756, 750, 735, 729, 728, 720, 704, 702, 700, 693, 686, 675, 672, 660, + 650, 648, 640, 637, 630, 625, 624, 616, 600, 594, 588, 585, 576, 567, 560, 550, 546, 540, 539, 528, 525, 520, 512, 504, 500, 495, 490, 486, 480, 468, 462, 455, + 450, 448, 441, 440, 432, 420, 416, 405, 400, 396, 392, 390, 385, 384, 378, 375, 364, 360, 352, 351, 350, 343, 336, 330, 325, 324, 320, 315, 312, 308, 300, 297, + 294, 288, 280, 275, 273, 270, 264, 260, 256, 252, 250, 245, 243, 240, 234, 231, 225, 224, 220, 216, 210, 208, 200, 198, 196, 195, 192, 189, 182, 180, 176, 175, + 168, 165, 162, 160, 156, 154, 150, 147, 144, 143, 140, 135, 132, 130, 128, 126, 125, 120, 117, 112, 110, 108, 105, 104, 100, 99, 98, 96, 91, 90, 88, 84, 81, + 80, 78, 77, 75, 72, 70, 66, 65, 64, 63, 60, 56, 55, 54, 52, 50, 49, 48, 45, 44, 42, 40, 39, 36, 35, 33, 32, 30, 28, 27, 26, 25, 24, 22, 21, 20, 18, 16, 15, + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 + }; + +int N_fftwsize = sizeof(fftw_size) / sizeof(fftw_size[0]); + + +void optfft(int N_fftwsize, int &bfh, int &bfw, int &bfhr, int &bfwr, struct local_params& lp, int H, int W, int &xstart, int &ystart, int &xend, int ¥d, int cx, int cy) +{ + int ftsizeH = 1; + int ftsizeW = 1; + + for (int ft = 0; ft < N_fftwsize; ft++) { //find best values + if (fftw_size[ft] <= bfh) { + ftsizeH = fftw_size[ft]; + break; + } + } + + for (int ft = 0; ft < N_fftwsize; ft++) { + if (fftw_size[ft] <= bfw) { + ftsizeW = fftw_size[ft]; + break; + } + } + + //optimize with size fftw + bool reduW = false; + bool reduH = false; + + if (ystart == 0 && yend < H) { + lp.ly -= (bfh - ftsizeH); + } else if (ystart != 0 && yend == H) { + lp.lyT -= (bfh - ftsizeH); + } else if (ystart != 0 && yend != H) { + if (lp.ly <= lp.lyT) { + lp.lyT -= (bfh - ftsizeH); + } else { + lp.ly -= (bfh - ftsizeH); + } + } else if (ystart == 0 && yend == H) { + bfhr = ftsizeH; + reduH = true; + } + + if (xstart == 0 && xend < W) { + lp.lx -= (bfw - ftsizeW); + } else if (xstart != 0 && xend == W) { + lp.lxL -= (bfw - ftsizeW); + } else if (xstart != 0 && xend != W) { + if (lp.lx <= lp.lxL) { + lp.lxL -= (bfw - ftsizeW); + } else { + lp.lx -= (bfw - ftsizeW); + } + } else if (xstart == 0 && xend == W) { + bfwr = ftsizeW; + reduW = true; + } + + //new values optimized + ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, H); + xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, W); + bfh = bfhr = yend - ystart; + bfw = bfwr = xend - xstart; + + if (reduH) { + bfhr = ftsizeH; + } + + if (reduW) { + bfwr = ftsizeW; + } + + if (settings->verbose) { + printf("Nyst=%i Nyen=%i lp.yc=%f lp.lyT=%f lp.ly=%f bfh=%i bfhr=%i origH=%i ftsizeH=%i\n", ystart, yend, lp.yc, lp.lyT, lp.ly, bfh, bfhr, H, ftsizeH); + printf("Nxst=%i Nxen=%i lp.xc=%f lp.lxL=%f lp.lx=%f bfw=%i bfwr=%i origW=%i ftsizeW=%i\n", xstart, xend, lp.xc, lp.lxL, lp.lx, bfw, bfwr, W, ftsizeW); + } +} + +void ImProcFunctions::BlurNoise_Local(LabImage *tmp1, LabImage * originalmask, float **bufchro, const float hueref, const float chromaref, const float lumaref, local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ +//local BLUR + BENCHFUN + + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + + const float ach = lp.trans / 100.f; + const int GW = transformed->W; + const int GH = transformed->H; + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + const bool blshow = lp.showmaskblmet == 1 || lp.showmaskblmet == 2; + const bool previewbl = lp.showmaskblmet == 4; + + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + + if (lp.colorde == 0) { + lp.colorde = -1;//to avoid black + } + + const float ampli = 1.5f + 0.5f * std::fabs(lp.colorde); + + constexpr float darklim = 5000.f; + constexpr float aadark = -1.f; + + const bool usemaskbl = lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 4; + const bool usemaskall = usemaskbl; + const float radius = 3.f / sk; + std::unique_ptr origblurmask; + + const std::unique_ptr origblur(new LabImage(GW, GH)); + + if (usemaskall) { + origblurmask.reset(new LabImage(GW, GH)); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(originalmask->L, origblurmask->L, GW, GH, radius); + gaussianBlur(originalmask->a, origblurmask->a, GW, GH, radius); + gaussianBlur(originalmask->b, origblurmask->b, GW, GH, radius); + } + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(original->L, origblur->L, GW, GH, radius); + gaussianBlur(original->a, origblur->a, GW, GH, radius); + gaussianBlur(original->b, origblur->b, GW, GH, radius); + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + const LabImage *maskptr = usemaskall ? origblurmask.get() : origblur.get(); + const float mindE = 4.f + MINSCOPE * lp.sensbn * lp.thr;//best usage ?? with blurnoise + const float maxdE = 5.f + MAXSCOPE * lp.sensbn * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = ystart; y < yend; y++) { + const int loy = cy + y; + + for (int x = xstart, lox = cx + x; x < xend; x++, lox++) { + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + const float abdelta2 = SQR(refa - maskptr->a[y][x]) + SQR(refb - maskptr->b[y][x]); + const float chrodelta2 = SQR(std::sqrt(SQR(maskptr->a[y][x]) + SQR(maskptr->b[y][x])) - chromaref * 327.68f); + const float huedelta2 = abdelta2 - chrodelta2; + const float dE = std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - maskptr->L[y][x])); + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensbn); + const float clc = previewbl ? settings->previewselection * 100.f : bufchro[y - ystart][x - xstart]; + const float realstrchdE = reducdE * clc; + + float difL = (tmp1->L[y - ystart][x - xstart] - original->L[y][x]) * localFactor * reducdE; + transformed->L[y][x] = CLIP(original->L[y][x] + difL); + const float fli = (100.f + realstrchdE) / 100.f; + const float difa = tmp1->a[y - ystart][x - xstart] * fli - original->a[y][x] * localFactor; + const float difb = tmp1->b[y - ystart][x - xstart] * fli - original->b[y][x] * localFactor; + + if (!lp.actsp) { + transformed->a[y][x] = clipC(original->a[y][x] + difa); + transformed->b[y][x] = clipC(original->b[y][x] + difb); + } + + const float maxdifab = rtengine::max(std::fabs(difa), std::fabs(difb)); + + if (blshow && lp.colorde < 0) { //show modifications with use "b" + // (origshow && lp.colorde < 0) { //original Retinex + transformed->a[y][x] = 0.f; + transformed->b[y][x] = ampli * 8.f * difL * reducdE; + transformed->L[y][x] = CLIP(12000.f + 0.5f * ampli * difL); + + } else if (blshow && lp.colorde > 0) {//show modifications without use "b" + if (difL < 1000.f) {//if too low to be view use ab + difL += 0.5f * maxdifab; + } + + transformed->L[y][x] = CLIP(12000.f + 0.5f * ampli * difL); + transformed->a[y][x] = clipC(ampli * difa); + transformed->b[y][x] = clipC(ampli * difb); + } else if (previewbl || lp.prevdE) {//show deltaE + const float difbdisp = reducdE * 10000.f * lp.colorde; + + if (transformed->L[y][x] < darklim) { //enhance dark luminance as user can see! + float dark = transformed->L[y][x]; + transformed->L[y][x] = dark * aadark + darklim; + } + + if (lp.colorde <= 0) { + transformed->a[y][x] = 0.f; + transformed->b[y][x] = difbdisp; + } else { + transformed->a[y][x] = -difbdisp; + transformed->b[y][x] = 0.f; + } + } + } + } + } +} + +void ImProcFunctions::transit_shapedetect2(int call, int senstype, const LabImage * bufexporig, const LabImage * bufexpfin, LabImage * originalmask, const float hueref, const float chromaref, const float lumaref, float sobelref, float meansobel, float ** blend2, struct local_params & lp, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ + //initialize coordinates + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfw = xend - xstart; + int bfh = yend - ystart; + + int bfhr = bfh; + int bfwr = bfw; + if (lp.blurcolmask >= 0.25f && lp.fftColorMask && call == 2) { + optfft(N_fftwsize, bfh, bfw, bfhr, bfwr, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + bfh = bfhr; + bfw = bfwr; + + //initialize scope + float varsens = lp.sensex;//exposure + + if (senstype == 0) { //Color and light + varsens = lp.sens; + } else if (senstype == 2) { //vibrance + varsens = lp.sensv; + } else if (senstype == 9) { //shadowshighlight + varsens = lp.senshs; + } else if (senstype == 3) { //softlight + varsens = lp.senssf; + } else if (senstype == 30) { //dehaze + varsens = lp.sensh; + } else if (senstype == 8) { //TM + varsens = lp.senstm; + } else if (senstype == 10) { //local contrast + varsens = lp.senslc; + } else if (senstype == 11) { //encoding log + varsens = lp.sensilog; + } + + bool delt = lp.deltaem; + + //sobel + sobelref /= 100.f; + meansobel /= 100.f; + + sobelref = rtengine::min(sobelref, 60.f); + + const bool k = !(sobelref < meansobel && sobelref < lp.stru); //does not always work with noisy images + + sobelref = log1p(sobelref); + + //references Spot + const float refa = chromaref * cos(hueref) * 327.68f; + const float refb = chromaref * sin(hueref) * 327.68f; + const float refL = lumaref * 327.68f; + + //to preview modifications, scope, mask + const bool expshow = ((lp.showmaskexpmet == 1 || lp.showmaskexpmet == 2) && senstype == 1); + const bool vibshow = ((lp.showmaskvibmet == 1 || lp.showmaskvibmet == 2) && senstype == 2); + const bool colshow = ((lp.showmaskcolmet == 1 || lp.showmaskcolmet == 2) && senstype == 0); + const bool SHshow = ((lp.showmaskSHmet == 1 || lp.showmaskSHmet == 2) && senstype == 9); + const bool tmshow = ((lp.showmasktmmet == 1 || lp.showmasktmmet == 2) && senstype == 8); + const bool lcshow = ((lp.showmasklcmet == 1 || lp.showmasklcmet == 2) && senstype == 10); + const bool origshow = ((lp.showmasksoftmet == 5) && senstype == 3 && lp.softmet == 1); + + + const bool previewvib = ((lp.showmaskvibmet == 4) && senstype == 2); + const bool previewexp = ((lp.showmaskexpmet == 5) && senstype == 1); + const bool previewcol = ((lp.showmaskcolmet == 5) && senstype == 0); + const bool previewSH = ((lp.showmaskSHmet == 4) && senstype == 9); + const bool previewtm = ((lp.showmasktmmet == 4) && senstype == 8); + const bool previewlc = ((lp.showmasklcmet == 4) && senstype == 10); + const bool previeworig = ((lp.showmasksoftmet == 6) && senstype == 3 && lp.softmet == 1); + + float radius = 3.f / sk; + + if (senstype == 1) { + radius = (2.f + 0.2f * lp.blurexp) / sk; + } else if (senstype == 0) { + radius = (2.f + 0.2f * lp.blurcol) / sk; + } else if (senstype == 9) { + radius = (2.f + 0.2f * lp.blurSH) / sk; + } + + const std::unique_ptr origblur(new LabImage(bfw, bfh)); + std::unique_ptr origblurmask; + + //balance deltaE + const float kL = lp.balance / SQR(327.68f); + const float kab = balancedeltaE(lp.balance) / SQR(327.68f); + const float kH = lp.balanceh; + const float kch = balancedeltaE(kH); + + if (lp.colorde == 0) { + lp.colorde = -1;//to avoid black + } + + float ampli = 1.f + std::fabs(lp.colorde); + ampli = 2.f + 0.5f * (ampli - 2.f); + + float darklim = 5000.f; + float aadark = -1.f; + float bbdark = darklim; + + const bool usemaskvib = (lp.showmaskvibmet == 2 || lp.enavibMask || lp.showmaskvibmet == 4) && senstype == 2; + const bool usemaskexp = (lp.showmaskexpmet == 2 || lp.enaExpMask || lp.showmaskexpmet == 5) && senstype == 1; + const bool usemaskcol = (lp.showmaskcolmet == 2 || lp.enaColorMask || lp.showmaskcolmet == 5) && senstype == 0; + const bool usemaskSH = (lp.showmaskSHmet == 2 || lp.enaSHMask || lp.showmaskSHmet == 4) && senstype == 9; + const bool usemasktm = (lp.showmasktmmet == 2 || lp.enatmMask || lp.showmasktmmet == 4) && senstype == 8; + const bool usemasklc = (lp.showmasklcmet == 2 || lp.enalcMask || lp.showmasklcmet == 4) && senstype == 10; + const bool usemaskall = (usemaskexp || usemaskvib || usemaskcol || usemaskSH || usemasktm || usemasklc); + + //blur a little mask + if (usemaskall) { + origblurmask.reset(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(originalmask->L, origblurmask->L, bfw, bfh, radius); + gaussianBlur(originalmask->a, origblurmask->a, bfw, bfh, radius); + gaussianBlur(originalmask->b, origblurmask->b, bfw, bfh, radius); + } + } + + if (lp.equtm && senstype == 8) { //normalize luminance for Tone mapping , at this place we can use for others senstype! + float *datain = new float[bfh * bfw]; + float *data = new float[bfh * bfw]; + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = ystart; y < yend; y++) + for (int x = xstart; x < xend; x++) { + datain[(y - ystart) * bfw + (x - xstart)] = original->L[y][x]; + data[(y - ystart)* bfw + (x - xstart)] = bufexpfin->L[y - ystart][x - xstart]; + } + + normalize_mean_dt(data, datain, bfh * bfw, 1.f, 1.f); +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = ystart; y < yend; y++) + for (int x = xstart; x < xend; x++) { + bufexpfin->L[y - ystart][x - xstart] = data[(y - ystart) * bfw + x - xstart]; + } + + delete [] datain; + delete [] data; + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + origblur->L[y][x] = original->L[y + ystart][x + xstart]; + origblur->a[y][x] = original->a[y + ystart][x + xstart]; + origblur->b[y][x] = original->b[y + ystart][x + xstart]; + } + } + + gaussianBlur(origblur->L, origblur->L, bfw, bfh, radius); + gaussianBlur(origblur->a, origblur->a, bfw, bfh, radius); + gaussianBlur(origblur->b, origblur->b, bfw, bfh, radius); + + } + + + //choice between original and mask + const LabImage *maskptr = usemaskall ? origblurmask.get() : origblur.get(); + + //parameters deltaE + const float mindE = 2.f + MINSCOPE * varsens * lp.thr; + const float maxdE = 5.f + MAXSCOPE * varsens * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ +// float atan2Buffer[transformed->W] ALIGNED16;//keep in case of +#endif + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh; y++) { + + const int loy = y + ystart + cy; +#ifdef __SSE2__ + /* //keep in case of + int i = 0; + + for (; i < bfw - 3; i += 4) { + vfloat av = LVFU(maskptr->a[y][i]); + vfloat bv = LVFU(maskptr->b[y][i]); + STVFU(atan2Buffer[i], xatan2f(bv, av)); + } + + for (; i < bfw; i++) { + atan2Buffer[i] = xatan2f(maskptr->b[y][i], maskptr->a[y][i]); + } + */ +#endif + + for (int x = 0; x < bfw; x++) { + const int lox = x + xstart + cx; + int zone; + float localFactor = 1.f; + const float achm = lp.trans / 100.f; + + //calculate transition + if (lp.shapmet == 0) { + calcTransition(lox, loy, achm, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, achm, lp, zone, localFactor); + } + +// float hueh = 0; +#ifdef __SSE2__ +// hueh = atan2Buffer[x]; +#else +// hueh = xatan2f(maskptr->b[y][x], maskptr->a[y][x]); +#endif + + float rsob = 0.f; + + //calculate additive sobel to deltaE + if (blend2 && ((senstype == 1 && lp.struexp > 0.f) || ((senstype == 0) && lp.struco > 0.f))) { + const float csob = xlogf(1.f + rtengine::min(blend2[y][x] / 100.f, 60.f) + 0.001f); + + float rs; + + if (k) { + rs = sobelref / csob; + } else { + rs = csob / sobelref; + } + + if (rs > 0.f && senstype == 1) { + rsob = 1.1f * lp.struexp * rs; + } else if (rs > 0.f && (senstype == 0)) { + rsob = 1.1f * lp.struco * rs; + } + } + + //deltaE + float abdelta2 = SQR(refa - maskptr->a[y][x]) + SQR(refb - maskptr->b[y][x]); + float chrodelta2 = SQR(std::sqrt(SQR(maskptr->a[y][x]) + SQR(maskptr->b[y][x])) - (chromaref * 327.68f)); + float huedelta2 = abdelta2 - chrodelta2; + + const float dE = rsob + std::sqrt(kab * (kch * chrodelta2 + kH * huedelta2) + kL * SQR(refL - maskptr->L[y][x])); + //reduction action with deltaE + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, varsens); + + float cli = (bufexpfin->L[y][x] - bufexporig->L[y][x]); + float cla = (bufexpfin->a[y][x] - bufexporig->a[y][x]); + float clb = (bufexpfin->b[y][x] - bufexporig->b[y][x]); + + if (delt) { + cli = bufexpfin->L[y][x] - original->L[y + ystart][x + xstart]; + cla = bufexpfin->a[y][x] - original->a[y + ystart][x + xstart]; + clb = bufexpfin->b[y][x] - original->b[y + ystart][x + xstart]; + } + if(lp.blwh) { + cla = 0.f; + clb = 0.f; + } + + // const float previewint = settings->previewselection; + + const float realstrdE = reducdE * cli; + const float realstradE = reducdE * cla; + const float realstrbdE = reducdE * clb; + + float factorx = localFactor; + + if (zone > 0) { + //simplified transformed with deltaE and transition + transformed->L[y + ystart][x + xstart] = clipLoc(original->L[y + ystart][x + xstart] + factorx * realstrdE); + float diflc = factorx * realstrdE; + transformed->a[y + ystart][x + xstart] = clipC(original->a[y + ystart][x + xstart] + factorx * realstradE); + const float difa = factorx * realstradE; + transformed->b[y + ystart][x + xstart] = clipC(original->b[y + ystart][x + xstart] + factorx * realstrbdE); + const float difb = factorx * realstrbdE; + float maxdifab = rtengine::max(std::fabs(difa), std::fabs(difb)); + + if ((expshow || vibshow || colshow || SHshow || tmshow || lcshow || origshow) && lp.colorde < 0) { //show modifications with use "b" + // (origshow && lp.colorde < 0) { //original Retinex + transformed->a[y + ystart][x + xstart] = 0.f; + transformed->b[y + ystart][x + xstart] = ampli * 8.f * diflc * reducdE; + transformed->L[y + ystart][x + xstart] = CLIP(12000.f + 0.5f * ampli * diflc); + + } else if ((expshow || vibshow || colshow || SHshow || tmshow || lcshow || origshow) && lp.colorde > 0) {//show modifications without use "b" + if (diflc < 1000.f) {//if too low to be view use ab + diflc += 0.5f * maxdifab; + } + + transformed->L[y + ystart][x + xstart] = CLIP(12000.f + 0.5f * ampli * diflc); + transformed->a[y + ystart][x + xstart] = clipC(ampli * difa); + transformed->b[y + ystart][x + xstart] = clipC(ampli * difb); + } else if (previewexp || previewvib || previewcol || previewSH || previewtm || previewlc || previeworig || lp.prevdE) {//show deltaE + float difbdisp = reducdE * 10000.f * lp.colorde; + + if (transformed->L[y + ystart][x + xstart] < darklim) { //enhance dark luminance as user can see! + float dark = transformed->L[y + ystart][x + xstart]; + transformed->L[y + ystart][x + xstart] = dark * aadark + bbdark; + } + + if (lp.colorde <= 0) { + transformed->a[y + ystart][x + xstart] = 0.f; + transformed->b[y + ystart][x + xstart] = difbdisp; + } else { + transformed->a[y + ystart][x + xstart] = -difbdisp; + transformed->b[y + ystart][x + xstart] = 0.f; + } + } + } + } + } + } +} + + + + +void ImProcFunctions::exposure_pde(float * dataor, float * datain, float * dataout, int bfw, int bfh, float thresh, float mod) +/* Jacques Desmis July 2019 +** adapted from Ipol Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ +*/ +{ + + BENCHFUN +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_init_threads(); + fftwf_plan_with_nthreads(omp_get_max_threads()); + } + +#endif + float *data_fft, *data_tmp, *data; + + if (NULL == (data_tmp = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + ImProcFunctions::discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, thresh); + + if (NULL == (data_fft = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (NULL == (data = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + const auto dct_fw = fftwf_plan_r2r_2d(bfh, bfw, data_tmp, data_fft, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_fw); + + fftwf_free(data_tmp); + + /* solve the Poisson PDE in Fourier space */ + /* 1. / (float) (bfw * bfh)) is the DCT normalisation term, see libfftw */ + ImProcFunctions::rex_poisson_dct(data_fft, bfw, bfh, 1. / (double)(bfw * bfh)); + + const auto dct_bw = fftwf_plan_r2r_2d(bfh, bfw, data_fft, data, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_bw); + fftwf_destroy_plan(dct_fw); + fftwf_destroy_plan(dct_bw); + fftwf_free(data_fft); + fftwf_cleanup(); + +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_cleanup_threads(); + } +#endif + + normalize_mean_dt(data, dataor, bfw * bfh, mod, 1.f); + { + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + dataout[y * bfw + x] = clipLoc(data[y * bfw + x]); + } + } + } + + fftwf_free(data); +} + +void ImProcFunctions::fftw_convol_blur(float * input, float * output, int bfw, int bfh, float radius, int fftkern, int algo) +{ + /* + ** Jacques Desmis june 2019 - inspired by Copyright 2013 IPOL Image Processing On Line http://www.ipol.im/ + ** when I read documentation on various FFT blur we found 2 possibilities + ** 0) kernel gauss is used with "normal" data + ** 1) kernel gauss is used with FFT + ** fftkern allows to change 0) or 1) and test It seems the good solution is with 0, but I keep the code in case of ?? + + ** input real data to blur + ** output real data blurred with radius + ** bfw bfh width and high area + ** radius = sigma for kernel + ** n_x n_y relative width and high for kernel + ** Gaussian blur is given by G(x,y) = (1/2*PI*sigma) * exp(-(x2 + y2) / 2* sigma2) + ** its traduction in Fourier transform is G(x,y) = exp((-sigma)*(PI * x2 + PI * y2)), for some authors it is not sigma but sigma^2..I have tried...huge differences with Gaussianblur + ** after several test the only result that works very well is with fftkern = 0 and algo = 0, and as there is differences with Gaussianblur, I put an empirical correction in Ipretinex and Iplocalcontrast + ** you can enabled or disabled this function with rtsettings.fftwsigma in options. By default empirical formula is disabled + ** in fact no importance....if it is this function (for sigma) or another... we are not in research :) + */ + BENCHFUN + +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_init_threads(); + fftwf_plan_with_nthreads(omp_get_max_threads()); + } +#endif + + + float *out; //for FFT data + float *kern = nullptr;//for kernel gauss + float *outkern = nullptr;//for FFT kernel + fftwf_plan p; + fftwf_plan pkern;//plan for FFT + int image_size, image_sizechange; + float n_x = 1.f; + float n_y = 1.f;//relative coordinates for kernel Gauss + float radsig = 1.f; + + out = (float*) fftwf_malloc(sizeof(float) * (bfw * bfh));//allocate real data for FFT + + if (fftkern == 1) { //allocate memory FFT if kernel fft = 1 + // kern = new float[bfw * bfh]; + kern = (float*) fftwf_malloc(sizeof(float) * (bfw * bfh));//allocate real data for FFT + outkern = (float*) fftwf_malloc(sizeof(float) * (bfw * bfh));//allocate real data for FFT + } + + /*compute the Fourier transform of the input data*/ + + p = fftwf_plan_r2r_2d(bfh, bfw, input, out, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE);//FFT 2 dimensions forward FFTW_MEASURE FFTW_ESTIMATE + + fftwf_execute(p); + fftwf_destroy_plan(p); + + /*define the gaussian constants for the convolution kernel*/ + if (algo == 0) { + n_x = rtengine::RT_PI / (double) bfw; //ipol + n_y = rtengine::RT_PI / (double) bfh; + } else if (algo == 1) { + n_x = 1.f / bfw; //gauss + n_y = 1.f / bfh; + radsig = 1.f / (2.f * rtengine::RT_PI * radius * radius);//gauss + } + + n_x = n_x * n_x; + n_y = n_y * n_y; + + image_size = bfw * bfh; + image_sizechange = 4 * image_size; + + if (fftkern == 1) { //convolution with FFT kernel +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int j = 0; j < bfh; j++) { + int index = j * bfw; + + for (int i = 0; i < bfw; i++) + if (algo == 0) { + kern[ i + index] = exp((float)(-radius) * (n_x * i * i + n_y * j * j)); //calculate Gauss kernel Ipol formula + } else if (algo == 1) { + kern[ i + index] = radsig * exp((float)(-(n_x * i * i + n_y * j * j) / (2.f * radius * radius))); //calculate Gauss kernel with Gauss formula + } + } + + /*compute the Fourier transform of the kernel data*/ + pkern = fftwf_plan_r2r_2d(bfh, bfw, kern, outkern, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE); //FFT 2 dimensions forward + fftwf_execute(pkern); + fftwf_destroy_plan(pkern); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int j = 0; j < bfh; j++) { + int index = j * bfw; + + for (int i = 0; i < bfw; i++) { + out[i + index] *= outkern[i + index]; //apply Gauss kernel with FFT + } + } + + fftwf_free(outkern); + fftwf_free(kern); + + // delete [] kern; + + } else if (fftkern == 0) {//without FFT kernel + if (algo == 0) { +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int j = 0; j < bfh; j++) { + int index = j * bfw; + + for (int i = 0; i < bfw; i++) { + out[i + index] *= exp((float)(-radius) * (n_x * i * i + n_y * j * j)); //apply Gauss kernel without FFT - some authors says radius*radius but differences with Gaussianblur + } + } + } else if (algo == 1) { +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int j = 0; j < bfh; j++) { + int index = j * bfw; + + for (int i = 0; i < bfw; i++) { + out[i + index] *= radsig * exp((float)(-(n_x * i * i + n_y * j * j) / (2.f * radius * radius))); //calculate Gauss kernel with Gauss formula + } + } + } + } + + p = fftwf_plan_r2r_2d(bfh, bfw, out, output, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE);//FFT 2 dimensions backward + fftwf_execute(p); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int index = 0; index < image_size; index++) { //restore data + output[index] /= image_sizechange; + } + + fftwf_destroy_plan(p); + fftwf_free(out); + +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_cleanup_threads(); + } +#endif +} + +void ImProcFunctions::fftw_convol_blur2(float **input2, float **output2, int bfw, int bfh, float radius, int fftkern, int algo) +{ + MyMutex::MyLock lock(*fftwMutex); + + float *input = nullptr; + + if (NULL == (input = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + float *output = nullptr; + + if (NULL == (output = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + input[y * bfw + x] = input2[y][x]; + } + } + + ImProcFunctions::fftw_convol_blur(input, output, bfw, bfh, radius, fftkern, algo); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + output2[y][x] = output[y * bfw + x]; + } + } + + fftwf_free(input); + fftwf_free(output); +} + + +void ImProcFunctions::fftw_tile_blur(int GW, int GH, int tilssize, int max_numblox_W, int min_numblox_W, float **tmp1, int numThreads, double radius) +{ + BENCHFUN + float epsil = 0.001f / (tilssize * tilssize); + fftwf_plan plan_forward_blox[2]; + fftwf_plan plan_backward_blox[2]; + + array2D tilemask_in(tilssize, tilssize); + array2D tilemask_out(tilssize, tilssize); + + float *Lbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * tilssize * tilssize * sizeof(float))); + float *fLbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * tilssize * tilssize * sizeof(float))); + + int nfwd[2] = {tilssize, tilssize}; + + //for DCT: + fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10}; + fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01}; + + // Creating the plans with FFTW_MEASURE instead of FFTW_ESTIMATE speeds up the execute a bit + plan_forward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, Lbloxtmp, nullptr, 1, tilssize * tilssize, fLbloxtmp, nullptr, 1, tilssize * tilssize, fwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + plan_backward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, fLbloxtmp, nullptr, 1, tilssize * tilssize, Lbloxtmp, nullptr, 1, tilssize * tilssize, bwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + plan_forward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, Lbloxtmp, nullptr, 1, tilssize * tilssize, fLbloxtmp, nullptr, 1, tilssize * tilssize, fwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + plan_backward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, fLbloxtmp, nullptr, 1, tilssize * tilssize, Lbloxtmp, nullptr, 1, tilssize * tilssize, bwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + fftwf_free(Lbloxtmp); + fftwf_free(fLbloxtmp); + const int border = rtengine::max(2, tilssize / 16); + + for (int i = 0; i < tilssize; ++i) { + float i1 = abs((i > tilssize / 2 ? i - tilssize + 1 : i)); + float vmask = (i1 < border ? SQR(sin((rtengine::RT_PI_F * i1) / (2 * border))) : 1.0f); + float vmask2 = (i1 < 2 * border ? SQR(sin((rtengine::RT_PI_F * i1) / (2 * border))) : 1.0f); + + for (int j = 0; j < tilssize; ++j) { + float j1 = abs((j > tilssize / 2 ? j - tilssize + 1 : j)); + tilemask_in[i][j] = (vmask * (j1 < border ? SQR(sin((rtengine::RT_PI_F * j1) / (2 * border))) : 1.0f)) + epsil; + tilemask_out[i][j] = (vmask2 * (j1 < 2 * border ? SQR(sin((rtengine::RT_PI_F * j1) / (2 * border))) : 1.0f)) + epsil; + + } + } + + float *LbloxArray[numThreads]; + float *fLbloxArray[numThreads]; + + const int numblox_W = ceil((static_cast(GW)) / offset) + 2; + const int numblox_H = ceil((static_cast(GH)) / offset) + 2; + + array2D Lresult(GW, GH, ARRAY2D_CLEAR_DATA); + array2D totwt(GW, GH, ARRAY2D_CLEAR_DATA); //weight for combining DCT blocks + + for (int i = 0; i < numThreads; ++i) { + LbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * tilssize * tilssize * sizeof(float))); + fLbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * tilssize * tilssize * sizeof(float))); + } + +#ifdef _OPENMP + int masterThread = omp_get_thread_num(); +#endif +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef _OPENMP + int subThread = masterThread * 1 + omp_get_thread_num(); +#else + int subThread = 0; +#endif + float *Lblox = LbloxArray[subThread]; + float *fLblox = fLbloxArray[subThread]; + float pBuf[GW + tilssize + 2 * offset] ALIGNED16; +#ifdef _OPENMP + #pragma omp for +#endif + for (int vblk = 0; vblk < numblox_H; ++vblk) { + + int top = (vblk - 1) * offset; + float * datarow = pBuf + offset; + + for (int i = 0; i < tilssize; ++i) { + int row = top + i; + int rr = row; + + if (row < 0) { + rr = rtengine::min(-row, GH - 1); + } else if (row >= GH) { + rr = rtengine::max(0, 2 * GH - 2 - row); + } + + for (int j = 0; j < GW; ++j) { + datarow[j] = (tmp1[rr][j]); + } + + for (int j = -1 * offset; j < 0; ++j) { + datarow[j] = datarow[rtengine::min(-j, GW - 1)]; + } + + for (int j = GW; j < GW + tilssize + offset; ++j) { + datarow[j] = datarow[rtengine::max(0, 2 * GW - 2 - j)]; + }//now we have a padded data row + + for (int hblk = 0; hblk < numblox_W; ++hblk) { + int left = (hblk - 1) * offset; + int indx = (hblk) * tilssize; //index of block in malloc + + if (top + i >= 0 && top + i < GH) { + int j; + + for (j = 0; j < rtengine::min((-left), tilssize); ++j) { + Lblox[(indx + i)*tilssize + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + } + + for (; j < rtengine::min(tilssize, GW - left); ++j) { + Lblox[(indx + i)*tilssize + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + totwt[top + i][left + j] += tilemask_in[i][j] * tilemask_out[i][j]; + } + + for (; j < tilssize; ++j) { + Lblox[(indx + i)*tilssize + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + } + } else { + for (int j = 0; j < tilssize; ++j) { + Lblox[(indx + i)*tilssize + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + } + } + + } + + }//end of filling block row + + //fftwf_print_plan (plan_forward_blox); + if (numblox_W == max_numblox_W) { + fftwf_execute_r2r(plan_forward_blox[0], Lblox, fLblox); // DCT an entire row of tiles + } else { + fftwf_execute_r2r(plan_forward_blox[1], Lblox, fLblox); // DCT an entire row of tiles + } + + const float n_xy = rtengine::SQR(rtengine::RT_PI / tilssize); + + //radius = 30.f; + for (int hblk = 0; hblk < numblox_W; ++hblk) { + int blkstart = hblk * tilssize * tilssize; + + for (int j = 0; j < tilssize; j++) { + int index = j * tilssize; + + for (int i = 0; i < tilssize; i++) { + fLblox[blkstart + index + i] *= exp((float)(-radius) * (n_xy * rtengine::SQR(i) + n_xy * rtengine::SQR(j))); + } + } + }//end of horizontal block loop + + //now perform inverse FT of an entire row of blocks + if (numblox_W == max_numblox_W) { + fftwf_execute_r2r(plan_backward_blox[0], fLblox, Lblox); //for DCT + } else { + fftwf_execute_r2r(plan_backward_blox[1], fLblox, Lblox); //for DCT + } + + int topproc = (vblk - 1) * offset; + const int numblox_W = ceil((static_cast(GW)) / offset); + const float DCTnorm = 1.0f / (4 * tilssize * tilssize); //for DCT + + int imin = rtengine::max(0, - topproc); + int bottom = rtengine::min(topproc + tilssize, GH); + int imax = bottom - topproc; + + for (int i = imin; i < imax; ++i) { + for (int hblk = 0; hblk < numblox_W; ++hblk) { + int left = (hblk - 1) * offset; + int right = rtengine::min(left + tilssize, GW); + int jmin = rtengine::max(0, -left); + int jmax = right - left; + int indx = hblk * tilssize; + + for (int j = jmin; j < jmax; ++j) { + Lresult[topproc + i][left + j] += tilemask_out[i][j] * Lblox[(indx + i) * tilssize + j] * DCTnorm; //for DCT + } + } + } + }//end of vertical block loop + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + tmp1[i][j] = Lresult[i][j] / totwt[i][j]; + tmp1[i][j] = clipLoc(tmp1[i][j]); + } + } + + for (int i = 0; i < numThreads; ++i) { + fftwf_free(LbloxArray[i]); + fftwf_free(fLbloxArray[i]); + } + + fftwf_destroy_plan(plan_forward_blox[0]); + fftwf_destroy_plan(plan_backward_blox[0]); + fftwf_destroy_plan(plan_forward_blox[1]); + fftwf_destroy_plan(plan_backward_blox[1]); + fftwf_cleanup(); +} + +void ImProcFunctions::wavcbd(wavelet_decomposition &wdspot, int level_bl, int maxlvl, + const LocwavCurve& locconwavCurve, bool locconwavutili, float sigm, float offs, float chromalev, int sk) +{ + if (locconwavCurve && locconwavutili) { + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + +#ifdef _OPENMP + const int numThreads = omp_get_max_threads(); +#else + const int numThreads = 1; +#endif + Evaluate2(wdspot, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) if (multiThread) +#endif + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + const int W_L = wdspot.level_W(level); + const int H_L = wdspot.level_H(level); + float mea[9]; + + float* const* wav_L = wdspot.level_coeffs(level); + //offset + float rap = offs * mean[level] - 2.f * sigm * sigma[level]; + + if (rap > 0.f) { + mea[0] = rap; + } else { + mea[0] = mean[level] / 6.f; + } + + rap = offs * mean[level] - sigm * sigma[level]; + + if (rap > 0.f) { + mea[1] = rap; + } else { + mea[1] = mean[level] / 2.f; + } + + mea[2] = offs * mean[level]; // 50% data + mea[3] = offs * mean[level] + sigm * sigma[level] / 2.f; + mea[4] = offs * mean[level] + sigm * sigma[level]; //66% + mea[5] = offs * mean[level] + sigm * 1.2f * sigma[level]; + mea[6] = offs * mean[level] + sigm * 1.5f * sigma[level]; // + mea[7] = offs * mean[level] + sigm * 2.f * sigma[level]; //95% + mea[8] = offs * mean[level] + sigm * 2.5f * sigma[level]; //99% + + float cpMul = 200.f * (locconwavCurve[level * 55.5f] - 0.5f); + + if (cpMul > 0.f) { + cpMul *= 3.5f; + } + + cpMul /= sk; + + for (int i = 0; i < W_L * H_L; i++) { + const float WavCL = std::fabs(wav_L[dir][i]); + float beta; + + //reduction amplification: max action between mean / 2 and mean + sigma + // arbitrary coefficient, we can add a slider !! + if (WavCL < mea[0]) { + beta = 0.6f; //preserve very low contrast (sky...) + } else if (WavCL < mea[1]) { + beta = 0.8f; + } else if (WavCL < mea[2]) { + beta = 1.f; //standard + } else if (WavCL < mea[3]) { + beta = 1.f; + } else if (WavCL < mea[4]) { + beta = 0.8f; //+sigma + } else if (WavCL < mea[5]) { + beta = 0.6f; + } else if (WavCL < mea[6]) { + beta = 0.4f; + } else if (WavCL < mea[7]) { + beta = 0.2f; // + 2 sigma + } else if (WavCL < mea[8]) { + beta = 0.1f; + } else { + beta = 0.0f; + } + + const float alpha = rtengine::max((1024.f + 15.f * cpMul * beta) / 1024.f, 0.02f) ; + wav_L[dir][i] *= alpha * chromalev; + } + } + } + } +} + +void ImProcFunctions::Compresslevels(float **Source, int W_L, int H_L, float compression, float detailattenuator, float thres, float mean, float maxp, float meanN, float maxN, float madL) +{ + //J.Desmis 12-2019 + + float exponent; + + if (detailattenuator > 0.f && detailattenuator < 0.05f) { + const float betemp = expf(-(2.f - detailattenuator + 0.693147f)) - 1.f; //0.69315 = log(2) + exponent = 1.2f * xlogf(-betemp); + exponent /= 20.f; + } else if (detailattenuator >= 0.05f && detailattenuator < 0.25f) { + const float betemp = expf(-(2.f - detailattenuator + 0.693147f)) - 1.f; + exponent = 1.2f * xlogf(-betemp); + exponent /= (-75.f * detailattenuator + 23.75f); + } else if (detailattenuator >= 0.25f) { + const float betemp = expf(-(2.f - detailattenuator + 0.693147f)) - 1.f; + exponent = 1.2f * xlogf(-betemp); + exponent /= (-2.f * detailattenuator + 5.5f); + } else { + exponent = (compression - 1.0f) / 20.f; + } + + float ap = (thres - 1.f) / (maxp - mean); + float bp = 1.f - ap * mean; + ap *= exponent; + bp *= exponent; + + float a0 = (1.33f * thres - 1.f) / (1.f - mean); + float b0 = 1.f - a0 * mean; + a0 *= exponent; + b0 *= exponent; + + float apn = (thres - 1.f) / (maxN - meanN); + float bpn = 1.f - apn * meanN; + apn *= -exponent; + bpn *= exponent; + + float a0n = (1.33f * thres - 1.f) / (1.f - meanN); + float b0n = 1.f - a0n * meanN; + a0n *= -exponent; + b0n *= exponent; + + madL *= 0.05f; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + const vfloat apv = F2V(ap); + const vfloat bpv = F2V(bp); + const vfloat a0v = F2V(a0); + const vfloat b0v = F2V(b0); + const vfloat apnv = F2V(apn); + const vfloat bpnv = F2V(bpn); + const vfloat a0nv = F2V(a0n); + const vfloat b0nv = F2V(b0n); + const vfloat madLv = F2V(madL); + const vfloat meanv = F2V(mean); + const vfloat onev = F2V(1.f); +#endif +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < H_L; y++) { + int x = 0; +#ifdef __SSE2__ + for (; x < W_L - 3; x += 4) { + vfloat exponev = onev; + vfloat valv = LVFU(Source[y][x]); + const vmask mask1v = vmaskf_ge(valv, ZEROV); + const vmask mask2v = vmaskf_gt(vself(mask1v, valv, -valv), meanv); + const vfloat av = vself(mask2v, vself(mask1v, apv, apnv), vself(mask1v, a0v, a0nv)); + const vfloat bv = vself(mask2v, vself(mask1v, bpv, bpnv), vself(mask1v, b0v, b0nv)); + exponev += av * valv + bv; + valv = vself(mask1v, valv, -valv); + const vfloat multv = vself(mask1v, onev, -onev); + const vfloat resultv = multv * xexpf(xlogf(valv + madLv) * exponev); + STVFU(Source[y][x], resultv); + } +#endif + for (; x < W_L; x++) { + float expone = 1.f; + + if (Source[y][x] >= 0.f) { + if (Source[y][x] > mean) { + expone += ap * Source[y][x] + bp; + } else { + expone += a0 * Source[y][x] + b0; + } + + Source[y][x] = xexpf(xlogf(Source[y][x] + madL) * expone); + } else { + if (-Source[y][x] > mean) { + expone += apn * Source[y][x] + bpn; + } else { + expone += a0n * Source[y][x] + b0n; + } + + Source[y][x] = -xexpf(xlogf(-Source[y][x] + madL) * expone); + } + } + } + } +} + +void ImProcFunctions::wavcont(const struct local_params& lp, float ** tmp, wavelet_decomposition& wdspot, int level_bl, int maxlvl, + const LocwavCurve & loclevwavCurve, bool loclevwavutili, + const LocwavCurve & loccompwavCurve, bool loccompwavutili, + const LocwavCurve & loccomprewavCurve, bool loccomprewavutili, + float radlevblur, int process, float chromablu, float thres, float sigmadc, float deltad) +{ + BENCHFUN + const int W_L = wdspot.level_W(0); + const int H_L = wdspot.level_H(0); + + const std::unique_ptr beta(new float[W_L * H_L]); + +#ifdef _OPENMP + const int numThreads = omp_get_max_threads(); +#else + const int numThreads = 1; +#endif + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + Evaluate2(wdspot, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + + if (process == 1 && loclevwavCurve && loclevwavutili) { //blur + array2D templevel(W_L, H_L); + for (int dir = 1; dir < 4; ++dir) { + for (int level = level_bl; level < maxlvl; ++level) { + const auto WavL = wdspot.level_coeffs(level)[dir]; + const float effect = lp.sigmabl; + constexpr float offs = 1.f; + float mea[10]; + calceffect(level, mean, sigma, mea, effect, offs); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int co = 0; co < H_L * W_L; co++) { + const float WavCL = std::fabs(WavL[co]); + + if (WavCL < mea[0]) { + beta[co] = 0.05f; + } else if (WavCL < mea[1]) { + beta[co] = 0.2f; + } else if (WavCL < mea[2]) { + beta[co] = 0.7f; + } else if (WavCL < mea[3]) { + beta[co] = 1.f; //standard + } else if (WavCL < mea[4]) { + beta[co] = 1.f; + } else if (WavCL < mea[5]) { + beta[co] = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta[co] = 0.5f; + } else if (WavCL < mea[7]) { + beta[co] = 0.3f; + } else if (WavCL < mea[8]) { + beta[co] = 0.2f; // + 2 sigma + } else if (WavCL < mea[9]) { + beta[co] = 0.1f; + } else { + beta[co] = 0.05f; + } + } + + const float klev = 0.25f * loclevwavCurve[level * 55.5f]; + float* src[H_L]; + for (int i = 0; i < H_L; ++i) { + src[i] = &wdspot.level_coeffs(level)[dir][i * W_L]; + } +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(src, templevel, W_L, H_L, radlevblur * klev * chromablu); + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + int j = y * W_L + x; + WavL[j] = intp(beta[j], templevel[y][x], WavL[j]); + } + } + } + } + } else if (process == 2 && loccompwavCurve && loccompwavutili) { //Directional contrast + for (int dir = 1; dir < 4; ++dir) { + for (int level = level_bl; level < maxlvl; ++level) { + const auto WavL = wdspot.level_coeffs(level)[dir]; + const float effect = sigmadc; + constexpr float offs = 1.f; + float mea[10]; + calceffect(level, mean, sigma, mea, effect, offs); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int co = 0; co < H_L * W_L; co++) { + const float WavCL = std::fabs(WavL[co]); + + if (WavCL < mea[0]) { + beta[co] = 0.05f; + } else if (WavCL < mea[1]) { + beta[co] = 0.2f; + } else if (WavCL < mea[2]) { + beta[co] = 0.7f; + } else if (WavCL < mea[3]) { + beta[co] = 1.f; //standard + } else if (WavCL < mea[4]) { + beta[co] = 1.f; + } else if (WavCL < mea[5]) { + beta[co] = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta[co] = 0.7f; + } else if (WavCL < mea[7]) { + beta[co] = 0.5f; + } else if (WavCL < mea[8]) { + beta[co] = 0.3f; // + 2 sigma + } else if (WavCL < mea[9]) { + beta[co] = 0.2f; + } else { + beta[co] = 0.1f; + } + } + + const int iteration = deltad; + const int itplus = 7 + iteration; + const int itmoins = 7 - iteration; + const int med = maxlvl / 2; + int it; + + if (level < med) { + it = itmoins; + } else if (level == med) { + it = 7; + } else { + it = itplus; + } + + const float itf = it; + const float factor = dir < 3 ? 0.3f : -0.6f; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + const vfloat c327d68v = F2V(327.68f); + const vfloat factorv = F2V(factor); + const vfloat sixv = F2V(6.f); + const vfloat zd5v = F2V(0.5f); + const vfloat onev = F2V(1.f); + const vfloat itfv = F2V(itf); +#endif +#ifdef _OPENMP + #pragma omp for +#endif + for (int i = 0; i < H_L; ++i) { + int j = 0; +#ifdef __SSE2__ + for (; j < W_L - 3; j += 4) { + const vfloat LL100v = LC2VFU(tmp[i * 2][j * 2]) / c327d68v; + const vfloat kbav = factorv * (loccompwavCurve[sixv * LL100v] - zd5v); //k1 between 0 and 0.5 0.5==> 1/6=0.16 + STVFU(WavL[i * W_L + j], LVFU(WavL[i * W_L + j]) * pow_F(onev + kbav * LVFU(beta[i * W_L + j]), itfv)); + } +#endif + for (; j < W_L; ++j) { + const float LL100 = tmp[i * 2][j * 2] / 327.68f; + const float kba = factor * (loccompwavCurve[6.f * LL100] - 0.5f); //k1 between 0 and 0.5 0.5==> 1/6=0.16 + WavL[i * W_L + j] *= pow_F(1.f + kba * beta[i * W_L + j], itf); + } + } + } + } + } + } else if (process == 3 && loccomprewavCurve && loccomprewavutili) { //Dynamic compression wavelet + float madL[10][3]; + array2D templevel(W_L, H_L); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) if (multiThread) +#endif + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + const int W_L = wdspot.level_W(level); + const int H_L = wdspot.level_H(level); + const auto wav_L = wdspot.level_coeffs(level)[dir]; + madL[level][dir - 1] = Mad(wav_L, W_L * H_L);//evaluate noise by level + } + } + + for (int dir = 1; dir < 4; ++dir) { + for (int level = level_bl; level < maxlvl; ++level) { + const auto WavL = wdspot.level_coeffs(level)[dir]; + const float effect = lp.sigmadr; + constexpr float offs = 1.f; + float mea[10]; + calceffect(level, mean, sigma, mea, effect, offs); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int co = 0; co < H_L * W_L; co++) { + const float WavCL = std::fabs(WavL[co]); + + if (WavCL < mea[0]) { + beta[co] = 0.05f; + } else if (WavCL < mea[1]) { + beta[co] = 0.2f; + } else if (WavCL < mea[2]) { + beta[co] = 0.7f; + } else if (WavCL < mea[3]) { + beta[co] = 1.f; //standard + } else if (WavCL < mea[4]) { + beta[co] = 1.f; + } else if (WavCL < mea[5]) { + beta[co] = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta[co] = 0.65f; + } else if (WavCL < mea[7]) { + beta[co] = 0.5f; + } else if (WavCL < mea[8]) { + beta[co] = 0.4f; // + 2 sigma + } else if (WavCL < mea[9]) { + beta[co] = 0.25f; + } else { + beta[co] = 0.1f; + } + } + + float klev = (loccomprewavCurve[level * 55.5f] - 0.75f); + if (klev < 0.f) { + klev *= 2.6666f;//compression increase contraste + } else { + klev *= 4.f;//dilatation reduce contraste - detailattenuator + } + const float compression = expf(-klev); + const float detailattenuator = std::max(klev, 0.f); + + const auto wav_L = wdspot.level_coeffs(level)[dir]; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + int j = y * W_L + x; + templevel[y][x] = wav_L[j]; + } + } + + Compresslevels(templevel, W_L, H_L, compression, detailattenuator, thres, mean[level], MaxP[level], meanN[level], MaxN[level], madL[level][dir - 1]); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + int j = y * W_L + x; + wav_L[j] = intp(beta[j], templevel[y][x], wav_L[j]); + } + } + } + } + } +} + + +void ImProcFunctions::wavcontrast4(struct local_params& lp, float ** tmp, float ** tmpa, float ** tmpb, float contrast, float radblur, float radlevblur, int bfw, int bfh, int level_bl, int level_hl, int level_br, int level_hr, int sk, int numThreads, + const LocwavCurve & locwavCurve, bool locwavutili, bool wavcurve, const LocwavCurve& loclevwavCurve, bool loclevwavutili, bool wavcurvelev, + const LocwavCurve & locconwavCurve, bool locconwavutili, bool wavcurvecon, + const LocwavCurve & loccompwavCurve, bool loccompwavutili, bool wavcurvecomp, + const LocwavCurve & loccomprewavCurve, bool loccomprewavutili, bool wavcurvecompre, + const LocwavCurve & locedgwavCurve, bool locedgwavutili, + float sigm, float offs, int & maxlvl, float sigmadc, float deltad, float chromalev, float chromablu, bool blurlc, bool blurena, bool levelena, bool comprena, bool compreena, float compress, float thres) +{ +BENCHFUN + wavelet_decomposition *wdspot = new wavelet_decomposition(tmp[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen); + + //first decomposition for compress dynamic range positive values and other process + if (wdspot->memory_allocation_failed()) { + return; + } + + struct grad_params gpwav; + + maxlvl = wdspot->maxlevel(); + + int W_Lm = wdspot->level_W(maxlvl - 1); //I assume all decomposition have same W and H + + int H_Lm = wdspot->level_H(maxlvl - 1); + + if (lp.strwav != 0.f && lp.wavgradl) { + array2D factorwav(W_Lm, H_Lm); + calclocalGradientParams(lp, gpwav, 0, 0, W_Lm, H_Lm, 10); + + + for (int y = 0; y < H_Lm; y++) { + for (int x = 0; x < W_Lm; x++) { + float factor = ImProcFunctions::calcGradientFactor(gpwav, x, y); + factorwav[y][x] = factor; + factorwav[y][x] = 1.f - factorwav[y][x]; + + if (lp.strwav < 0.f) { + factorwav[y][x] *= -1.f; + } + } + } + + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + Evaluate2(*wdspot, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + float alowg = 1.f; + float blowg = 0.f; + + if (level_hl != level_bl) { + alowg = 1.f / (level_hl - level_bl); + blowg = -alowg * level_bl; + } + + float ahighg = 1.f; + float bhighg = 0.f; + + if (level_hr != level_br) { + ahighg = 1.f / (level_hr - level_br); + bhighg = -ahighg * level_br; + } + + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + if (MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { + const int W_L = wdspot->level_W(level); + const int H_L = wdspot->level_H(level); + float* const* wav_L = wdspot->level_coeffs(level); + const float effect = lp.sigmalc2; + constexpr float offset = 1.f; + float mea[10]; + calceffect(level, mean, sigma, mea, effect, offset); + constexpr float insigma = 0.666f; //SD + const float logmax = std::log(MaxP[level]); //log Max + const float rapX = (mean[level] + lp.sigmalc2 * sigma[level]) / MaxP[level]; //rapport between sD / max + const float inx = std::log(insigma); + const float iny = std::log(rapX); + const float rap = inx / iny; //koef + const float asig = 0.166f / (sigma[level] * lp.sigmalc2); + const float bsig = 0.5f - asig * mean[level]; + const float amean = 0.5f / mean[level]; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + const float WavCL = std::fabs(wav_L[dir][y * W_L + x]); + float beta; + + if (WavCL < mea[0]) { + beta = 0.05f; + } else if (WavCL < mea[1]) { + beta = 0.2f; + } else if (WavCL < mea[2]) { + beta = 0.7f; + } else if (WavCL < mea[3]) { + beta = 1.f; //standard + } else if (WavCL < mea[4]) { + beta = 1.f; + } else if (WavCL < mea[5]) { + beta = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta = 0.6f; + } else if (WavCL < mea[7]) { + beta = 0.5f; + } else if (WavCL < mea[8]) { + beta = 0.4f; // + 2 sigma + } else if (WavCL < mea[9]) { + beta = 0.3f; + } else { + beta = 0.1f; + } + + float absciss; + float &val = wav_L[dir][y * W_L + x]; + + if (std::fabs(val) >= (mean[level] + lp.sigmalc2 * sigma[level])) { //for max + const float valc = xlogf(std::fabs(val)) - logmax; + absciss = xexpf(valc * rap); + } else if (std::fabs(val) >= mean[level]) { + absciss = asig * std::fabs(val) + bsig; + } else { + absciss = amean * std::fabs(val); + } + + float klev = 1.f; + + if (level_hl != level_bl) { + if (level >= level_bl && level < level_hl) { + klev = alowg * level + blowg; + } + } + + if (level_hr != level_br) { + if (level > level_hr && level <= level_br) { + klev = ahighg * level + bhighg; + } + } + + const float kc = 0.8f * klev * factorwav[y][x] * absciss; + const float reduceeffect = kc <= 0.f ? 1.f : 1.5f; + + float kinterm = 1.f + reduceeffect * kc; + kinterm = kinterm <= 0.f ? 0.01f : kinterm; + val *= (1.f + (kinterm - 1.f) * beta); + } + } + } + } + } + } + + //declare a and b if need + wavelet_decomposition *wdspota = nullptr; + wavelet_decomposition *wdspotb = nullptr; + + int W_L = wdspot->level_W(0); + int H_L = wdspot->level_H(0); + float *wav_L0 = wdspot->get_coeff0(); + + if (radblur > 0.f && blurena) { + array2D bufl(W_L, H_L); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + bufl[y][x] = wav_L0[y * W_L + x]; + } + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufl, bufl, W_L, H_L, radblur); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + wav_L0[y * W_L + x] = bufl[y][x]; + } + } + } + + if (compress != 0.f && compreena) { + + float Compression = expf(-compress); + float DetailBoost = compress; + + if (compress < 0.0f) { + DetailBoost = 0.0f; + } + + CompressDR(wav_L0, W_L, H_L, Compression, DetailBoost); + + } + + if ((lp.residsha != 0.f || lp.residhi != 0.f)) { + float tran = 5.f;//transition shadow + + if (lp.residshathr > (100.f - tran)) { + tran = 100.f - lp.residshathr; + } + constexpr float alp = 3.f; + const float aalp = (1.f - alp) / lp.residshathr; + const float ath = -lp.residsha / tran; + const float bth = lp.residsha - ath * lp.residshathr; + + //highlight + const float tranh = rtengine::min(5.f, lp.residhithr); + const float athH = lp.residhi / tranh; + const float bthH = lp.residhi - athH * lp.residhithr; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < W_L * H_L; i++) { + const float LL100 = wav_L0[i] / 327.68f; + + if (LL100 < lp.residshathr) { + const float kk = aalp * LL100 + alp; + wav_L0[i] *= (1.f + kk * lp.residsha / 200.f); + } else if (LL100 < lp.residshathr + tran) { + wav_L0[i] *= (1.f + (LL100 * ath + bth) / 200.f); + } + + if (LL100 > lp.residhithr) { + wav_L0[i] *= (1.f + lp.residhi / 200.f); + } else if (LL100 > (lp.residhithr - tranh)) { + wav_L0[i] *= (1.f + (LL100 * athH + bthH) / 200.f); + } + } + } + + if (contrast != 0.) { + + double avedbl = 0.0; // use double precision for large summations + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:avedbl) if (multiThread) +#endif + for (int i = 0; i < W_L * H_L; i++) { + avedbl += wav_L0[i]; + } + + float ave = avedbl / double(W_L * H_L); + + float avg = ave / 32768.f; + avg = LIM01(avg); + double contreal = 0.6 * contrast; + DiagonalCurve resid_contrast({ + DCT_NURBS, + 0, 0, + avg - avg * (0.6 - contreal / 250.0), avg - avg * (0.6 + contreal / 250.0), + avg + (1. - avg) * (0.6 - contreal / 250.0), avg + (1. - avg) * (0.6 + contreal / 250.0), + 1, 1 + }); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < W_L * H_L; i++) { + float buf = LIM01(wav_L0[i] / 32768.f); + buf = resid_contrast.getVal(buf); + buf *= 32768.f; + wav_L0[i] = buf; + } + + } + + float alow = 1.f; + float blow = 0.f; + + if (level_hl != level_bl) { + alow = 1.f / (level_hl - level_bl); + blow = -alow * level_bl; + } + + float ahigh = 1.f; + float bhigh = 0.f; + + if (level_hr != level_br) { + ahigh = 1.f / (level_hr - level_br); + bhigh = -ahigh * level_br; + } + + if (wavcurvelev || wavcurvecomp || wavcurvecompre) {//compress dynamic and blur + if (wavcurvelev && radlevblur > 0.f && blurena) { + wavcont(lp, tmp, *wdspot, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 1, 1.f, 0.f, 0.f, 0.f); + } + + if (wavcurvecomp && comprena) { + wavcont(lp, tmp, *wdspot, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 2, 1.f, 0.f, sigmadc, deltad); + } + + if (wavcurvecompre && compreena) { + wavcont(lp, tmp, *wdspot, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 3, 1.f, thres, 0.f, 0.f); + } + } + + if (wavcurvecon && levelena) {//contrast by levels for luminance + wavcbd(*wdspot, level_bl, maxlvl, locconwavCurve, locconwavutili, sigm, offs, 1.f, sk); + } + +//edge sharpness begin + if (lp.edgwena && level_bl == 0 && level_br >= 3 && locedgwavCurve && locedgwavutili && lp.strengthw > 0) { //needs the first levels to work! + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + Evaluate2(*wdspot, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + float edd = 3.f; + float eddlow = 15.f; + float eddlipinfl = 0.005f * lp.edgw + 0.4f; + float eddlipampl = 1.f + lp.basew / 50.f; + int W_L = wdspot->level_W(0);//provisory W_L H_L + int H_L = wdspot->level_H(0); + float *koeLi[12]; + float maxkoeLi[12] = {0.f}; + float *beta = new float[W_L * H_L]; + + float *koeLibuffer = new float[12 * H_L * W_L]; //12 + + for (int i = 0; i < 12; i++) { + koeLi[i] = &koeLibuffer[i * W_L * H_L]; + } + + for (int j = 0; j < 12; j++) { + for (int i = 0; i < W_L * H_L; i++) { + koeLi[j][i] = 0.f; + } + } + + array2D tmC(W_L, H_L); + + float gradw = lp.gradw; + float tloww = lp.tloww; +//StopWatch Stop1("test"); + for (int lvl = 0; lvl < 4; lvl++) { + for (int dir = 1; dir < 4; dir++) { + const int W_L = wdspot->level_W(lvl); + const int H_L = wdspot->level_H(lvl); + float* const* wav_L = wdspot->level_coeffs(lvl); + if (lvl == 3 && dir == 3) { + const float effect = lp.sigmaed; + constexpr float offset = 1.f; + float mea[10]; + calceffect(lvl, mean, sigma, mea, effect, offset); + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int co = 0; co < H_L * W_L; co++) { + const float WavCL = std::fabs(wav_L[dir][co]); + + if (WavCL < mea[0]) { + beta[co] = 0.05f; + } else if (WavCL < mea[1]) { + beta[co] = 0.2f; + } else if (WavCL < mea[2]) { + beta[co] = 0.7f; + } else if (WavCL < mea[3]) { + beta[co] = 1.f; //standard + } else if (WavCL < mea[4]) { + beta[co] = 1.f; + } else if (WavCL < mea[5]) { + beta[co] = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta[co] = 0.5f; + } else if (WavCL < mea[7]) { + beta[co] = 0.3f; + } else if (WavCL < mea[8]) { + beta[co] = 0.2f; // + 2 sigma + } else if (WavCL < mea[9]) { + beta[co] = 0.1f; + } else { + beta[co] = 0.05f; + } + } + } + calckoe(wav_L, gradw, tloww, koeLi, lvl, dir, W_L, H_L, edd, maxkoeLi[lvl * 3 + dir - 1], tmC); + // return convolution KoeLi and maxkoeLi of level 0 1 2 3 and Dir Horiz, Vert, Diag + } + } + tmC.free(); +//Stop1.stop(); + float aamp = 1.f + lp.thigw / 100.f; + + const float alipinfl = (eddlipampl - 1.f) / (1.f - eddlipinfl); + const float blipinfl = eddlipampl - alipinfl; + + for (int lvl = 0; lvl < 4; lvl++) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int i = 1; i < H_L - 1; i++) { + for (int j = 1; j < W_L - 1; j++) { + //treatment of koeLi and maxkoeLi + if (lp.lip3) {//Sobel Canny algo improve with parameters + // comparison between pixel and neighbors + const auto neigh = lp.neiwmet == 1; + const auto kneigh = neigh ? 28.f : 38.f; + const auto somm = neigh ? 40.f : 50.f; + + for (int dir = 1; dir < 4; dir++) { //neighbors proxi + koeLi[lvl * 3 + dir - 1][i * W_L + j] = (kneigh * koeLi[lvl * 3 + dir - 1][i * W_L + j] + + 2.f * koeLi[lvl * 3 + dir - 1][(i - 1) * W_L + j] + 2.f * koeLi[lvl * 3 + dir - 1][(i + 1) * W_L + j] + 2.f * koeLi[lvl * 3 + dir - 1][i * W_L + j + 1] + 2.f * koeLi[lvl * 3 + dir - 1][i * W_L + j - 1] + + koeLi[lvl * 3 + dir - 1][(i - 1) * W_L + j - 1] + koeLi[lvl * 3 + dir - 1][(i - 1) * W_L + j + 1] + koeLi[lvl * 3 + dir - 1][(i + 1) * W_L + j - 1] + koeLi[lvl * 3 + dir - 1][(i + 1) * W_L + j + 1]) / somm; + } + } + + float interm = 0.f; + for (int dir = 1; dir < 4; dir++) { + //here I evaluate combination of vert / diag / horiz...we are with multiplicators of the signal + interm += SQR(koeLi[lvl * 3 + dir - 1][i * W_L + j]); + } + + interm = std::sqrt(interm) * 0.57736721f; + + constexpr float eps = 0.0001f; + // I think this double ratio (alph, beta) is better than arctg + + float alph = koeLi[lvl * 3][i * W_L + j] / (koeLi[lvl * 3 + 1][i * W_L + j] + eps); //ratio between horizontal and vertical + float beta = koeLi[lvl * 3 + 2][i * W_L + j] / (koeLi[lvl * 3 + 1][i * W_L + j] + eps); //ratio between diagonal and horizontal + + //alph evaluate the direction of the gradient regularity Lipschitz + // if = 1 we are on an edge + // if 0 we are not + // we can change and use log..or Arctg but why ?? we can change if need ... + //Liamp=1 for eddlipinfl + //liamp > 1 for alp >eddlipinfl and alph < 1 + //Liamp < 1 for alp < eddlipinfl and alph > 0 + if (alph > 1.f) { + alph = 1.f / alph; + } + + if (beta > 1.f) { + beta = 1.f / beta; + } + + //take into account diagonal + //if in same value OK + //if not no edge or reduction + float bet = 1.f; + + if (alph > eddlipinfl && beta < 0.85f * eddlipinfl) { //0.85 arbitrary value ==> eliminate from edge if H V D too different + bet = beta; + } + + float kampli; + if (alph > eddlipinfl) { + kampli = alipinfl * alph + blipinfl; //If beta low reduce kampli + kampli = SQR(bet) * kampli * aamp; + } else { + kampli = SQR(SQR(alph * bet)) / eddlipinfl; //Strong Reduce if beta low + kampli = kampli / aamp; + } + + + interm *= kampli; + + if (interm * eddlow < lp.tloww) { + interm = 0.01f; //eliminate too low values + } + + //we can change this part of algo==> not equal but ponderate + koeLi[lvl * 3][i * W_L + j] = koeLi[lvl * 3 + 1][i * W_L + j] = koeLi[lvl * 3 + 2][i * W_L + j] = interm; //new value + //here KoeLi contains values where gradient is high and coef high, and eliminate low values... + } + } + } + + constexpr float scales[10] = {1.f, 2.f, 4.f, 8.f, 16.f, 32.f, 64.f, 128.f, 256.f, 512.f}; + float scaleskip[10]; + + for (int sc = 0; sc < 10; sc++) { + scaleskip[sc] = scales[sc] / sk; + } + + const float rad = lp.radiusw / 60.f; //radius ==> not too high value to avoid artifacts + float value = lp.strengthw / 8.f; //strength + + if (scaleskip[1] < 1.f) { + constexpr float atten01234 = 0.80f; + value *= atten01234 * scaleskip[1]; //for zoom < 100% reduce strength...I choose level 1...but!! + } + + constexpr float lim0 = 20.f; //arbitrary limit for low radius and level between 2 or 3 to 30 maxi + float repart = lp.detailw; + + if (lp.edgwmet != 1) { + float brepart; + if (lp.edgwmet == 0) { + brepart = 3.f; + } else /*if (lp.edgwmet == 2)*/ { + brepart = 0.5f; //arbitrary value to increase / decrease repart, between 1 and 0 + } + if (rad < lim0 / 60.f) { + const float arepart = - (brepart - 1.f) / (lim0 / 60.f); + repart *= arepart * rad + brepart; //linear repartition of repart + } + } + + const float bk = 1.f + repart / 50.f; + constexpr float al10 = 1.0f; //arbitrary value ==> less = take into account high levels + const float ak = - (bk - al10) / 10.f; //10 = maximum levels + + for (int lvl = 0; lvl < maxlvl; lvl++) { + if (MaxP[lvl] > 0.f) { //curve + const int W_L = wdspot->level_W(lvl); + const int H_L = wdspot->level_H(lvl); + float* const* wav_L = wdspot->level_coeffs(lvl); + const float koef = ak * lvl + bk; //modulate for levels : more levels high, more koef low ==> concentrated action on low levels, without or near for high levels + float expkoef = -pow_F(std::fabs(rad - lvl), koef); //reduce effect for high levels + if (lp.edgwmet == 2) { + if (rad < lim0 / 60.f && lvl == 0) { + expkoef *= abs(repart); //reduce effect for low values of rad and level=0==> quasi only level 1 is effective + } + } else if (lp.edgwmet == 0) { + if (rad < lim0 / 60.f && lvl == 1) { + expkoef /= repart; //increase effect for low values of rad and level=1==> quasi only level 0 is effective + } + } + //take into account local contrast + const float refin = value * xexpf(expkoef); + const float edgePrecalc = 1.f + refin; //estimate edge "pseudo variance" + constexpr float insigma = 0.666f; //SD + const float logmax = xlogf(MaxP[lvl]); //log Max + const float rapX = (mean[lvl] + sigma[lvl]) / MaxP[lvl]; //rapport between sD / max + const float inx = xlogf(insigma); + const float iny = xlogf(rapX); + const float rap = inx / iny; //koef + const float asig = 0.166f / sigma[lvl]; + const float bsig = 0.5f - asig * mean[lvl]; + const float amean = 0.5f / mean[lvl]; + constexpr int borderL = 1; + constexpr float abssd = 4.f; //amplification reference + constexpr float bbssd = 2.f; //mini ampli + constexpr float maxamp = 2.5f; //maxi ampli at end + constexpr float maxampd = 10.f; //maxi ampli at end + constexpr float a_abssd = (maxamp - abssd) / 0.333f; + constexpr float b_abssd = maxamp - a_abssd; + constexpr float da_abssd = (maxampd - abssd) / 0.333f; + constexpr float db_abssd = maxampd - da_abssd; + constexpr float am = (abssd - bbssd) / 0.666f; + for (int dir = 1; dir < 4; dir++) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) if(multiThread) +#endif + for (int i = borderL; i < H_L - borderL; i++) { + for (int j = borderL; j < W_L - borderL; j++) { + const int k = i * W_L + j; + + float edge; + if (lvl < 4) { + edge = 1.f + (edgePrecalc - 1.f) * (koeLi[lvl * 3][k]) / (1.f + 0.9f * maxkoeLi[lvl * 3 + dir - 1]); + } else { + edge = edgePrecalc; + } + + float absciss = 0.f; + if (std::fabs(wav_L[dir][k]) >= mean[lvl] + sigma[lvl]) { //for max + absciss = xexpf((xlogf(std::fabs(wav_L[dir][k])) - logmax) * rap); + } else if (std::fabs(wav_L[dir][k]) >= mean[lvl]) { + absciss = asig * std::fabs(wav_L[dir][k]) + bsig; + } else /*if (std::fabs(wav_L[dir][k]) < mean[lvl])*/ { + absciss = amean * std::fabs(wav_L[dir][k]); + } + + // Threshold adjuster settings==> approximative for curve + //kmul about average cbrt(3--40 / 10)==>1.5 to 2.5 + //kmul about SD 10--60 / 35 ==> 2 + // kmul about low cbrt((5.f+cp.edg_low)/5.f);==> 1.5 + // kmul about max ==> 9 + // we can change these values + // result is different not best or bad than threshold slider...but similar + float kmul; + float kmuld; + + if (absciss > 0.666f && absciss < 1.f) { + kmul = a_abssd * absciss + b_abssd; //about max ==> kinterm + kmuld = da_abssd * absciss + db_abssd; + } else { + kmul = kmuld = absciss * am + bbssd; + } + + const float kc = kmul * (locedgwavCurve[absciss * 500.f] - 0.5f); + + float kinterm; + if (kc >= 0.f) { + constexpr float reduceeffect = 0.6f; + kinterm = 1.f + reduceeffect * kc; //about 1 to 3 general and big amplification for max (under 0) + } else { + const float kcd = kmuld * (locedgwavCurve[absciss * 500.f] - 0.5f); + kinterm = 1.f - SQR(kcd) / 10.f; + } + + if (kinterm < 0.f) { + kinterm = 0.01f; + } + + edge = std::max(edge * kinterm, 1.f); + wav_L[dir][k] *= 1.f + (edge - 1.f) * beta[k]; + } + } + } + } + } + + if (koeLibuffer) { + delete [] koeLibuffer; + } + + delete[] beta; + } + +//edge sharpness end + + if (locwavCurve && locwavutili && wavcurve) {//simple local contrast in function luminance + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + Evaluate2(*wdspot, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + int W_L = wdspot->level_W(level); + int H_L = wdspot->level_H(level); + float klev = 1.f; + + if (level >= level_hl && level <= level_hr) { + klev = 1.f; + } + + if (level_hl != level_bl) { + if (level >= level_bl && level < level_hl) { + klev = alow * level + blow; + } + } + + if (level_hr != level_br) { + if (level > level_hr && level <= level_br) { + klev = ahigh * level + bhigh; + } + } + float* const* wav_L = wdspot->level_coeffs(level); + + if (MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { + constexpr float insigma = 0.666f; //SD + const float logmax = log(MaxP[level]); //log Max + const float rapX = (mean[level] + lp.sigmalc * sigma[level]) / MaxP[level]; //rapport between sD / max + const float inx = log(insigma); + const float iny = log(rapX); + const float rap = inx / iny; //koef + const float asig = 0.166f / (sigma[level] * lp.sigmalc); + const float bsig = 0.5f - asig * mean[level]; + const float amean = 0.5f / mean[level]; + const float limit1 = mean[level] + lp.sigmalc * sigma[level]; + const float limit2 = mean[level]; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16 * W_L) if (multiThread) +#endif + for (int i = 0; i < W_L * H_L; i++) { + const float val = wav_L[dir][i]; + + float absciss; + if (std::fabs(val) >= limit1) { //for max + const float valcour = xlogf(std::fabs(val)); + absciss = xexpf((valcour - logmax) * rap); + } else if (std::fabs(val) >= limit2) { + absciss = asig * std::fabs(val) + bsig; + } else { + absciss = amean * std::fabs(val); + } + + const float kc = klev * (locwavCurve[absciss * 500.f] - 0.5f); + const float reduceeffect = kc <= 0.f ? 1.f : 1.5f; + + float kinterm = 1.f + reduceeffect * kc; + kinterm = kinterm <= 0.f ? 0.01f : kinterm; + + wav_L[dir][i] *= kinterm <= 0.f ? 0.01f : kinterm; + } + } + } + } + } + + //reconstruct all for L + wdspot->reconstruct(tmp[0], 1.f); + delete wdspot; + + if (wavcurvecon && (chromalev != 1.f) && levelena) { // a and b if need ) {//contrast by levels for chroma a and b + wdspota = new wavelet_decomposition(tmpa[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen); + + if (wdspota->memory_allocation_failed()) { + return; + } + + wavcbd(*wdspota, level_bl, maxlvl, locconwavCurve, locconwavutili, sigm, offs, chromalev, sk); + wdspota->reconstruct(tmpa[0], 1.f); + delete wdspota; + + wdspotb = new wavelet_decomposition(tmpb[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen); + + if (wdspotb->memory_allocation_failed()) { + return; + } + + wavcbd(*wdspotb, level_bl, maxlvl, locconwavCurve, locconwavutili, sigm, offs, chromalev, sk); + wdspotb->reconstruct(tmpb[0], 1.f); + delete wdspotb; + + } + + if (wavcurvelev && radlevblur > 0.f && blurena) {//chroma blur if need + if (!blurlc) { + // a + wdspota = new wavelet_decomposition(tmpa[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen); + + if (wdspota->memory_allocation_failed()) { + return; + } + + if (radlevblur > 0.f && chromablu > 0.f) { + wavcont(lp, tmp, *wdspota, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 1, chromablu, 0.f, 0.f, 0.f); + } + + wdspota->reconstruct(tmpa[0], 1.f); + delete wdspota; + + //b + wdspotb = new wavelet_decomposition(tmpb[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen); + + if (wdspotb->memory_allocation_failed()) { + return; + } + + if (radlevblur > 0.f && chromablu > 0.f) { + wavcont(lp, tmp, *wdspotb, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 1, chromablu, 0.f, 0.f, 0.f); + } + + wdspotb->reconstruct(tmpb[0], 1.f); + delete wdspotb; + } + } + +} + + +void ImProcFunctions::fftw_denoise(int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom) +{ + BENCHFUN + + fftwf_plan plan_forward_blox[2]; + fftwf_plan plan_backward_blox[2]; + + array2D tilemask_in(TS, TS); + array2D tilemask_out(TS, TS); + + float *Lbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float))); + float *fLbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float))); + float params_Ldetail = 0.f; + + int nfwd[2] = {TS, TS}; + + //for DCT: + fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10}; + fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01}; + + // Creating the plans with FFTW_MEASURE instead of FFTW_ESTIMATE speeds up the execute a bit + plan_forward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, Lbloxtmp, nullptr, 1, TS * TS, fLbloxtmp, nullptr, 1, TS * TS, fwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + plan_backward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, fLbloxtmp, nullptr, 1, TS * TS, Lbloxtmp, nullptr, 1, TS * TS, bwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + plan_forward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, Lbloxtmp, nullptr, 1, TS * TS, fLbloxtmp, nullptr, 1, TS * TS, fwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + plan_backward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, fLbloxtmp, nullptr, 1, TS * TS, Lbloxtmp, nullptr, 1, TS * TS, bwdkind, FFTW_MEASURE | FFTW_DESTROY_INPUT); + fftwf_free(Lbloxtmp); + fftwf_free(fLbloxtmp); + const int border = rtengine::max(2, TS / 16); + + for (int i = 0; i < TS; ++i) { + float i1 = abs((i > TS / 2 ? i - TS + 1 : i)); + float vmask = (i1 < border ? SQR(sin((rtengine::RT_PI_F * i1) / (2 * border))) : 1.0f); + float vmask2 = (i1 < 2 * border ? SQR(sin((rtengine::RT_PI_F * i1) / (2 * border))) : 1.0f); + + for (int j = 0; j < TS; ++j) { + float j1 = abs((j > TS / 2 ? j - TS + 1 : j)); + tilemask_in[i][j] = (vmask * (j1 < border ? SQR(sin((rtengine::RT_PI_F * j1) / (2 * border))) : 1.0f)) + epsilonw; + tilemask_out[i][j] = (vmask2 * (j1 < 2 * border ? SQR(sin((rtengine::RT_PI_F * j1) / (2 * border))) : 1.0f)) + epsilonw; + + } + } + + + float *LbloxArray[numThreads]; + float *fLbloxArray[numThreads]; + + + + const int numblox_W = ceil((static_cast(GW)) / offset) + 2; + const int numblox_H = ceil((static_cast(GH)) / offset) + 2; + + + //residual between input and denoised L channel + array2D Ldetail(GW, GH, ARRAY2D_CLEAR_DATA); + array2D totwt(GW, GH, ARRAY2D_CLEAR_DATA); //weight for combining DCT blocks + array2D prov(GW, GH, ARRAY2D_CLEAR_DATA); + + for (int i = 0; i < numThreads; ++i) { + LbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float))); + fLbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float))); + } + +#ifdef _OPENMP + int masterThread = omp_get_thread_num(); +#endif +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef _OPENMP + int subThread = masterThread * 1 + omp_get_thread_num(); +#else + int subThread = 0; +#endif + float *Lblox = LbloxArray[subThread]; + float *fLblox = fLbloxArray[subThread]; + float pBuf[GW + TS + 2 * offset] ALIGNED16; +#ifdef _OPENMP + #pragma omp for +#endif + for (int vblk = 0; vblk < numblox_H; ++vblk) { + + int top = (vblk - 1) * offset; + float * datarow = pBuf + offset; + + for (int i = 0; i < TS; ++i) { + int row = top + i; + int rr = row; + + if (row < 0) { + rr = rtengine::min(-row, GH - 1); + } else if (row >= GH) { + rr = rtengine::max(0, 2 * GH - 2 - row); + } + + for (int j = 0; j < GW; ++j) { + datarow[j] = ((*Lin)[rr][j] - tmp1[rr][j]); + prov[rr][j] = std::fabs(tmp1[rr][j]); + + } + + for (int j = -1 * offset; j < 0; ++j) { + datarow[j] = datarow[rtengine::min(-j, GW - 1)]; + } + + for (int j = GW; j < GW + TS + offset; ++j) { + datarow[j] = datarow[rtengine::max(0, 2 * GW - 2 - j)]; + }//now we have a padded data row + + //now fill this row of the blocks with Lab high pass data + for (int hblk = 0; hblk < numblox_W; ++hblk) { + int left = (hblk - 1) * offset; + int indx = (hblk) * TS; //index of block in malloc + + if (top + i >= 0 && top + i < GH) { + int j; + + for (j = 0; j < rtengine::min((-left), TS); ++j) { + Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + } + + for (; j < rtengine::min(TS, GW - left); ++j) { + Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + totwt[top + i][left + j] += tilemask_in[i][j] * tilemask_out[i][j]; + } + + for (; j < TS; ++j) { + Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + } + } else { + for (int j = 0; j < TS; ++j) { + Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data + } + } + + } + + }//end of filling block row + + //fftwf_print_plan (plan_forward_blox); + if (numblox_W == max_numblox_W) { + fftwf_execute_r2r(plan_forward_blox[0], Lblox, fLblox); // DCT an entire row of tiles + } else { + fftwf_execute_r2r(plan_forward_blox[1], Lblox, fLblox); // DCT an entire row of tiles + } + + // now process the vblk row of blocks for noise reduction + + float noisevar_Ldetail = 1.f; + + if (chrom == 0) { + params_Ldetail = rtengine::min(float(lp.noiseldetail), 99.9f); // max out to avoid div by zero when using noisevar_Ldetail as divisor + noisevar_Ldetail = SQR(static_cast(SQR(100. - params_Ldetail) + 50.*(100. - params_Ldetail)) * TS * 0.5f); + } else if (chrom == 1) { + params_Ldetail = rtengine::min(float(lp.noisechrodetail), 99.9f); + // noisevar_Ldetail = 100.f * pow((static_cast(SQR(100. - params_Ldetail) + 50.*(100. - params_Ldetail)) * TS * 0.5f), 2);//to test ??? + noisevar_Ldetail = 100.f * pow((static_cast(SQR(100. - params_Ldetail)) * TS * 0.5f), 2);//to test ??? + } + + // float noisevar_Ldetail = SQR(static_cast(SQR(100. - params_Ldetail) + 50.*(100. - params_Ldetail)) * TS * 0.5f); + + + + for (int hblk = 0; hblk < numblox_W; ++hblk) { + ImProcFunctions::RGBtile_denoise(fLblox, hblk, noisevar_Ldetail); + + }//end of horizontal block loop + + + //now perform inverse FT of an entire row of blocks + if (numblox_W == max_numblox_W) { + fftwf_execute_r2r(plan_backward_blox[0], fLblox, Lblox); //for DCT + } else { + fftwf_execute_r2r(plan_backward_blox[1], fLblox, Lblox); //for DCT + } + + int topproc = (vblk - 1) * offset; + + //add row of blocks to output image tile + ImProcFunctions::RGBoutput_tile_row(Lblox, Ldetail, tilemask_out, GH, GW, topproc); + + }//end of vertical block loop + } + + //Threshold DCT from Alberto Grigio + const int detail_thresh = lp.detailthr; + array2D mask; + + if (detail_thresh > 0) { + mask(GW, GH); + float thr = log2lin(float(detail_thresh) / 200.f, 100.f); + buildBlendMask(prov, mask, GW, GH, thr); +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(mask, mask, GW, GH, 20.0); + } + array2D m2(GW, GH); + constexpr float alfa = 0.856f; + const float beta = 1.f + std::sqrt(log2lin(thr, 100.f)); + buildGradientsMask(GW, GH, prov, m2, params_Ldetail / 100.f, 7, 3, alfa, beta, multiThread); + + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + mask[i][j] *= m2[i][j]; + } + } + } + + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + float d = Ldetail[i][j] / totwt[i][j]; + + if (detail_thresh > 0) { + d *= mask[i][j]; + } + + //may want to include masking threshold for large hipass data to preserve edges/detail + tmp1[i][j] += d; + } + } + + mask.free(); +//end Threshold DCT + + + delete Lin; + + + for (int i = 0; i < numThreads; ++i) { + fftwf_free(LbloxArray[i]); + fftwf_free(fLbloxArray[i]); + } + + fftwf_destroy_plan(plan_forward_blox[0]); + fftwf_destroy_plan(plan_backward_blox[0]); + fftwf_destroy_plan(plan_forward_blox[1]); + fftwf_destroy_plan(plan_backward_blox[1]); + fftwf_cleanup(); + + +} + +void ImProcFunctions::DeNoise(int call, int del, float * slidL, float * slida, float * slidb, int aut, bool noiscfactiv, const struct local_params & lp, LabImage * originalmaskbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage * original, LabImage * transformed, int cx, int cy, int sk) +{ + +//local denoise + //all these variables are to prevent use of denoise when non necessary + // but with qualmet = 2 (default for best quality) we must denoise chroma with little values to prevent artifacts due to variations of Hue + // but if user select voluntary denoise, it is that choice the good (prioritary) + bool execcolor = (lp.chro != 0.f || lp.ligh != 0.f || lp.cont != 0); // only if one slider or more is engaged + bool execbdl = (lp.mulloc[0] != 1.f || lp.mulloc[1] != 1.f || lp.mulloc[2] != 1.f || lp.mulloc[3] != 1.f || lp.mulloc[4] != 1.f || lp.mulloc[5] != 1.f) ;//only if user want cbdl + bool execdenoi = noiscfactiv && ((lp.colorena && execcolor) || (lp.tonemapena && lp.strengt != 0.f) || (lp.cbdlena && execbdl) || (lp.sfena && lp.strng > 0.f) || (lp.lcena && lp.lcamount > 0.f) || (lp.sharpena && lp.shrad > 0.42) || (lp.retiena && lp.str > 0.f) || (lp.exposena && lp.expcomp != 0.f) || (lp.expvib && lp.past != 0.f)); + bool execmaskden = (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.smasktyp != 0; + + if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f +// || lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4 || aut == 1 || aut == 2) && lp.denoiena) || execdenoi) { // sk == 1 ?? + || execmaskden || aut == 1 || aut == 2) && lp.denoiena) || execdenoi) { // sk == 1 ?? + + StopWatch Stop1("locallab Denoise called"); + + if (aut == 0) { + MyMutex::MyLock lock(*fftwMutex); + } + + + if (lp.noisecf >= 0.01f || lp.noisecc >= 0.01f || aut == 1 || aut == 2) { + noiscfactiv = false; + levred = 7; + } + + int GW = transformed->W; + int GH = transformed->H; + + +#ifdef _OPENMP + const int numThreads = omp_get_max_threads(); +#else + const int numThreads = 1; + +#endif + + if (call == 1 && GW >= mDEN && GH >= mDEN) { + + + LabImage tmp1(transformed->W, transformed->H); + LabImage tmp2(transformed->W, transformed->H); + tmp2.clear(); + + array2D *Lin = nullptr; + array2D *Ain = nullptr; + array2D *Bin = nullptr; + + int max_numblox_W = ceil((static_cast(GW)) / offset) + 2; + // calculate min size of numblox_W. + int min_numblox_W = ceil((static_cast(GW)) / offset) + 2; + + + for (int ir = 0; ir < GH; ir++) + for (int jr = 0; jr < GW; jr++) { + tmp1.L[ir][jr] = original->L[ir][jr]; + tmp1.a[ir][jr] = original->a[ir][jr]; + tmp1.b[ir][jr] = original->b[ir][jr]; + } + + // int DaubLen = 6; + + int levwavL = levred; + int skip = 1; + + wavelet_decomposition Ldecomp(tmp1.L[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, lp.daubLen); + wavelet_decomposition adecomp(tmp1.a[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, lp.daubLen); + wavelet_decomposition bdecomp(tmp1.b[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, lp.daubLen); + + float madL[10][3]; + int edge = 2; + + if (!Ldecomp.memory_allocation_failed()) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) if (multiThread) +#endif + for (int lvl = 0; lvl < levred; lvl++) { + for (int dir = 1; dir < 4; dir++) { + int Wlvl_L = Ldecomp.level_W(lvl); + int Hlvl_L = Ldecomp.level_H(lvl); + const float* const* WavCoeffs_L = Ldecomp.level_coeffs(lvl); + + madL[lvl][dir - 1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); + } + } + + float vari[levred]; + float mxsl = 0.f; + // float mxsfl = 0.f; + + if (aut == 0) { + if (levred == 7) { + edge = 2; + vari[0] = 0.8f * SQR((lp.noiself0 / 125.0) * (1.0 + lp.noiself0 / 25.0)); + vari[1] = 0.8f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); + vari[2] = 0.8f * SQR((lp.noiself2 / 125.0) * (1.0 + lp.noiself2 / 25.0)); + + vari[3] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[4] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[5] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[6] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + } else if (levred == 4) { + edge = 3; + vari[0] = 0.8f * SQR((lp.noiself0 / 125.0) * (1.0 + lp.noiself0 / 25.0)); + vari[1] = 0.8f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); + vari[2] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[3] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + + } + } else if (aut == 1 || aut == 2) { + edge = 2; + vari[0] = SQR(slidL[0]); + vari[1] = SQR(slidL[1]); + vari[2] = SQR(slidL[2]); + vari[3] = SQR(slidL[3]); + vari[4] = SQR(slidL[4]); + vari[5] = SQR(slidL[5]); + vari[6] = SQR(slidL[6]); + float mxslid34 = rtengine::max(slidL[3], slidL[4]); + float mxslid56 = rtengine::max(slidL[5], slidL[6]); + mxsl = rtengine::max(mxslid34, mxslid56); + + } + + { + float kr3 = 0.f; + float kr4 = 0.f; + float kr5 = 0.f; + + if (aut == 0 || aut == 1) { + if ((lp.noiselc < 30.f && aut == 0) || (mxsl < 30.f && aut == 1)) { + kr3 = 0.f; + kr4 = 0.f; + kr5 = 0.f; + } else if ((lp.noiselc < 50.f && aut == 0) || (mxsl < 50.f && aut == 1)) { + kr3 = 0.5f; + kr4 = 0.3f; + kr5 = 0.2f; + } else if ((lp.noiselc < 70.f && aut == 0) || (mxsl < 70.f && aut == 1)) { + kr3 = 0.7f; + kr4 = 0.5f; + kr5 = 0.3f; + } else { + kr3 = 1.f; + kr4 = 1.f; + kr5 = 1.f; + } + } else if (aut == 2) { + kr3 = 1.f; + kr4 = 1.f; + kr5 = 1.f; + } + + vari[0] = rtengine::max(0.000001f, vari[0]); + vari[1] = rtengine::max(0.000001f, vari[1]); + vari[2] = rtengine::max(0.000001f, vari[2]); + vari[3] = rtengine::max(0.000001f, kr3 * vari[3]); + + if (levred == 7) { + vari[4] = rtengine::max(0.000001f, kr4 * vari[4]); + vari[5] = rtengine::max(0.000001f, kr5 * vari[5]); + vari[6] = rtengine::max(0.000001f, kr5 * vari[6]); + } + + float* noisevarlum = new float[GH * GW]; + int GW2 = (GW + 1) / 2; + + float nvlh[13] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 0.7f, 0.5f}; //high value + float nvll[13] = {0.1f, 0.15f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.45f, 0.7f, 0.8f, 1.f, 1.f, 1.f}; //low value + + float seuillow = 3000.f;//low + float seuilhigh = 18000.f;//high + int i = 10 - lp.noiselequal; + float ac = (nvlh[i] - nvll[i]) / (seuillow - seuilhigh); + float bc = nvlh[i] - seuillow * ac; + //ac and bc for transition +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) + for (int jr = 0; jr < GW; jr++) { + float lN = tmp1.L[ir][jr]; + + if (lN < seuillow) { + noisevarlum[(ir >> 1)*GW2 + (jr >> 1)] = nvlh[i]; + } else if (lN < seuilhigh) { + noisevarlum[(ir >> 1)*GW2 + (jr >> 1)] = ac * lN + bc; + } else { + noisevarlum[(ir >> 1)*GW2 + (jr >> 1)] = nvll[i]; + } + } + + if ((lp.noiselc < 0.02f && aut == 0) || (mxsl < 1.f && (aut == 1 || aut == 2))) { + WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads); + + } else { + + WaveletDenoiseAll_BiShrinkL(Ldecomp, noisevarlum, madL, vari, edge, numThreads); + + WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads); + + } + + delete[] noisevarlum; + + } + } + + + float variC[levred]; + float variCb[levred]; + + float noisecfr = lp.noisecf; + float noiseccr = lp.noisecc; + + if (lp.adjch > 0.f) { + noisecfr = lp.noisecf + 0.1f * lp.adjch; + noiseccr = lp.noisecc + 0.1f * lp.adjch; + } + + float noisecfb = lp.noisecf; + float noiseccb = lp.noisecc; + + if (lp.adjch < 0.f) { + noisecfb = lp.noisecf - 0.1f * lp.adjch; + noiseccb = lp.noisecc - 0.1f * lp.adjch; + } + + + if (noisecfr < 0.f) { + noisecfr = 0.00001f; + } + + if (noiseccr < 0.f) { + noiseccr = 0.00001f; + } + + if (noisecfb < 0.f) { + noisecfb = 0.00001f; + } + + if (noiseccb < 0.f) { + noiseccb = 0.00001f; + } + + if (!adecomp.memory_allocation_failed() && !bdecomp.memory_allocation_failed()) { + float maxcfine = 0.f; + float maxccoarse = 0.f; + + if (aut == 0) { + if (levred == 7) { + edge = 2; + variC[0] = SQR(noisecfr); + variC[1] = SQR(noisecfr); + variC[2] = SQR(noisecfr); + + variC[3] = SQR(noisecfr); + variC[4] = SQR(noisecfr); + variC[5] = SQR(noiseccr); + variC[6] = SQR(noiseccr); + + variCb[0] = SQR(noisecfb); + variCb[1] = SQR(noisecfb); + variCb[2] = SQR(noisecfb); + + variCb[3] = SQR(noisecfb); + variCb[4] = SQR(noisecfb); + variCb[5] = SQR(noiseccb); + variCb[6] = SQR(noiseccb); + + } else if (levred == 4) { + edge = 3; + variC[0] = SQR(lp.noisecf / 10.0); + variC[1] = SQR(lp.noisecf / 10.0); + variC[2] = SQR(lp.noisecf / 10.0); + variC[3] = SQR(lp.noisecf / 10.0); + + variCb[0] = SQR(lp.noisecf / 10.0); + variCb[1] = SQR(lp.noisecf / 10.0); + variCb[2] = SQR(lp.noisecf / 10.0); + variCb[3] = SQR(lp.noisecf / 10.0); + + } + } else if (aut == 1 || aut == 2) { + edge = 2; + variC[0] = SQR(slida[0]); + variC[1] = SQR(slida[1]); + variC[2] = SQR(slida[2]); + variC[3] = SQR(slida[3]); + variC[4] = SQR(slida[4]); + variC[5] = SQR(slida[5]); + variC[6] = SQR(slida[6]); + float maxc01 = rtengine::max(slida[0], slida[1]); + float maxc23 = rtengine::max(slida[2], slida[3]); + float max03 = rtengine::max(maxc01, maxc23); + float maxrf = rtengine::max(max03, slida[4]); + float maxrc = rtengine::max(slida[5], slida[6]); + + variCb[0] = SQR(slidb[0]); + variCb[1] = SQR(slidb[1]); + variCb[2] = SQR(slidb[2]); + variCb[3] = SQR(slidb[3]); + variCb[4] = SQR(slidb[4]); + variCb[5] = SQR(slidb[5]); + variCb[6] = SQR(slidb[6]); + float maxb01 = rtengine::max(slidb[0], slidb[1]); + float maxb23 = rtengine::max(slidb[2], slidb[3]); + float maxb03 = rtengine::max(maxb01, maxb23); + float maxbf = rtengine::max(maxb03, slidb[4]); + maxcfine = rtengine::max(maxrf, maxbf); + + float maxbc = rtengine::max(slidb[5], slidb[6]); + maxccoarse = rtengine::max(maxrc, maxbc); + + } + + { + float minic = 0.000001f; + + if (noiscfactiv) { + minic = 0.1f;//only for artifact shape detection + } + + float k1 = 0.f; + float k2 = 0.f; + float k3 = 0.f; + + if (aut == 0 || aut == 1) { + if ((lp.noisecf < 0.2f && aut == 0) || (maxcfine < 0.2f && aut == 1)) { + k1 = 0.05f; + k2 = 0.f; + k3 = 0.f; + } else if ((lp.noisecf < 0.3f && aut == 0) || (maxcfine < 0.3f && aut == 1)) { + k1 = 0.1f; + k2 = 0.0f; + k3 = 0.f; + } else if ((lp.noisecf < 0.5f && aut == 0) || (maxcfine < 0.5f && aut == 1)) { + k1 = 0.2f; + k2 = 0.1f; + k3 = 0.f; + } else if ((lp.noisecf < 0.8f && aut == 0) || (maxcfine < 0.8f && aut == 1)) { + k1 = 0.3f; + k2 = 0.25f; + k3 = 0.f; + } else if ((lp.noisecf < 1.f && aut == 0) || (maxcfine < 1.f && aut == 1)) { + k1 = 0.4f; + k2 = 0.25f; + k3 = 0.1f; + } else if ((lp.noisecf < 2.f && aut == 0) || (maxcfine < 2.f && aut == 1)) { + k1 = 0.5f; + k2 = 0.3f; + k3 = 0.15f; + } else if ((lp.noisecf < 3.f && aut == 0) || (maxcfine < 3.f && aut == 1)) { + k1 = 0.6f; + k2 = 0.45f; + k3 = 0.3f; + } else if ((lp.noisecf < 4.f && aut == 0) || (maxcfine < 4.f && aut == 1)) { + k1 = 0.7f; + k2 = 0.5f; + k3 = 0.4f; + } else if ((lp.noisecf < 5.f && aut == 0) || (maxcfine < 5.f && aut == 1)) { + k1 = 0.8f; + k2 = 0.6f; + k3 = 0.5f; + } else if ((lp.noisecf < 6.f && aut == 0) || (maxcfine < 10.f && aut == 1)) { + k1 = 0.85f; + k2 = 0.7f; + k3 = 0.6f; + } else if ((lp.noisecf < 8.f && aut == 0) || (maxcfine < 20.f && aut == 1)) { + k1 = 0.9f; + k2 = 0.8f; + k3 = 0.7f; + } else if ((lp.noisecf < 10.f && aut == 0) || (maxcfine < 50.f && aut == 1)) { + k1 = 1.f; + k2 = 1.f; + k3 = 0.9f; + + } else { + k1 = 1.f; + k2 = 1.f; + k3 = 1.f; + } + } else if (aut == 2) { + k1 = 1.f; + k2 = 1.f; + k3 = 1.f; + } + + + variC[0] = rtengine::max(minic, variC[0]); + variC[1] = rtengine::max(minic, k1 * variC[1]); + variC[2] = rtengine::max(minic, k2 * variC[2]); + variC[3] = rtengine::max(minic, k3 * variC[3]); + + variCb[0] = rtengine::max(minic, variCb[0]); + variCb[1] = rtengine::max(minic, k1 * variCb[1]); + variCb[2] = rtengine::max(minic, k2 * variCb[2]); + variCb[3] = rtengine::max(minic, k3 * variCb[3]); + + if (levred == 7) { + float k4 = 0.f; + float k5 = 0.f; + float k6 = 0.f; + + if ((lp.noisecc < 0.2f && aut == 0) || (maxccoarse < 0.2f && aut == 1)) { + k4 = 0.1f; + k5 = 0.02f; + } else if ((lp.noisecc < 0.5f && aut == 0) || (maxccoarse < 0.5f && aut == 1)) { + k4 = 0.15f; + k5 = 0.05f; + } else if ((lp.noisecc < 1.f && aut == 0) || (maxccoarse < 1.f && aut == 1)) { + k4 = 0.15f; + k5 = 0.1f; + } else if ((lp.noisecc < 3.f && aut == 0) || (maxccoarse < 3.f && aut == 1)) { + k4 = 0.3f; + k5 = 0.15f; + } else if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + k4 = 0.6f; + k5 = 0.4f; + } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + k4 = 0.8f; + k5 = 0.6f; + } else { + k4 = 1.f; + k5 = 1.f; + } + + variC[4] = rtengine::max(0.000001f, k4 * variC[4]); + variC[5] = rtengine::max(0.000001f, k5 * variC[5]); + variCb[4] = rtengine::max(0.000001f, k4 * variCb[4]); + variCb[5] = rtengine::max(0.000001f, k5 * variCb[5]); + + if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 4.f && aut == 1)) { + k6 = 0.f; + } else if ((lp.noisecc < 5.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + k6 = 0.4f; + } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + k6 = 0.7f; + } else { + k6 = 1.f; + } + + variC[6] = rtengine::max(0.00001f, k6 * variC[6]); + variCb[6] = rtengine::max(0.00001f, k6 * variCb[6]); + + } + + float* noisevarchrom = new float[GH * GW]; + //noisevarchrom in function chroma + int GW2 = (GW + 1) / 2; + float nvch = 0.6f;//high value + float nvcl = 0.1f;//low value + + if ((lp.noisecf > 100.f && aut == 0) || (maxcfine > 100.f && (aut == 1 || aut == 2))) { + nvch = 0.8f; + nvcl = 0.4f; + } + + float seuil = 4000.f;//low + float seuil2 = 15000.f;//high + //ac and bc for transition + float ac = (nvch - nvcl) / (seuil - seuil2); + float bc = nvch - seuil * ac; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) + for (int jr = 0; jr < GW; jr++) { + float cN = std::sqrt(SQR(tmp1.a[ir][jr]) + SQR(tmp1.b[ir][jr])); + + if (cN < seuil) { + noisevarchrom[(ir >> 1)*GW2 + (jr >> 1)] = nvch; + } else if (cN < seuil2) { + noisevarchrom[(ir >> 1)*GW2 + (jr >> 1)] = ac * cN + bc; + } else { + noisevarchrom[(ir >> 1)*GW2 + (jr >> 1)] = nvcl; + } + } + + + float noisevarab_r = 100.f; //SQR(lp.noisecc / 10.0); + + if ((lp.noisecc < 2.f && aut == 0) || (maxccoarse < 0.1f && (aut == 1 || aut == 2))) { + WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads); + WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads); + } else { + WaveletDenoiseAll_BiShrinkAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads); + WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads); + + WaveletDenoiseAll_BiShrinkAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads); + WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads); + } + + delete[] noisevarchrom; + + } + } + + if (!Ldecomp.memory_allocation_failed()) { + Lin = new array2D(GW, GH); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + (*Lin)[i][j] = tmp1.L[i][j]; + } + } + + Ldecomp.reconstruct(tmp1.L[0]); + } + + if (!Ldecomp.memory_allocation_failed() && aut == 0) { + if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f) { + fftw_denoise(GW, GH, max_numblox_W, min_numblox_W, tmp1.L, Lin, numThreads, lp, 0); + } + } + + if (!adecomp.memory_allocation_failed()) { + Ain = new array2D(GW, GH); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + (*Ain)[i][j] = tmp1.a[i][j]; + } + } + + adecomp.reconstruct(tmp1.a[0]); + } + + + if (!adecomp.memory_allocation_failed() && aut == 0) { + if ((lp.noisecf >= 0.01f || lp.noisecc >= 0.01f) && levred == 7 && lp.noisechrodetail != 100.f) { + fftw_denoise(GW, GH, max_numblox_W, min_numblox_W, tmp1.a, Ain, numThreads, lp, 1); + } + } + + + if (!bdecomp.memory_allocation_failed()) { + + Bin = new array2D(GW, GH); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + (*Bin)[i][j] = tmp1.b[i][j]; + } + } + + bdecomp.reconstruct(tmp1.b[0]); + } + + + if (!bdecomp.memory_allocation_failed() && aut == 0) { + if ((lp.noisecf >= 0.01f || lp.noisecc >= 0.01f) && levred == 7 && lp.noisechrodetail != 100.f) { + fftw_denoise(GW, GH, max_numblox_W, min_numblox_W, tmp1.b, Bin, numThreads, lp, 1); + } + + } + + // DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, tmp1, cx, cy, sk); + if(lp.smasktyp != 0) { + DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, tmp1, cx, cy, sk); + } else { + DeNoise_Local(call, lp, original, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, tmp1, cx, cy, sk); + } + + } else if (call == 2) { //simpleprocess + + int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone + int bfw = int (lp.lx + lp.lxL) + del; + + if (bfh >= mDEN && bfw >= mDEN) { + LabImage bufwv(bfw, bfh); + bufwv.clear(true); + array2D *Lin = nullptr; + array2D *Ain = nullptr; + array2D *Bin = nullptr; + + int max_numblox_W = ceil((static_cast(bfw)) / offset) + 2; + // calculate min size of numblox_W. + int min_numblox_W = ceil((static_cast(bfw)) / offset) + 2; + // these are needed only for creation of the plans and will be freed before entering the parallel loop + + + int begy = lp.yc - lp.lyT; + int begx = lp.xc - lp.lxL; + int yEn = lp.yc + lp.ly; + int xEn = lp.xc + lp.lx; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H ; y++) //{ + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + int loy = cy + y; + + if (lox >= begx && lox < xEn && loy >= begy && loy < yEn) { + bufwv.L[loy - begy][lox - begx] = original->L[y][x]; + bufwv.a[loy - begy][lox - begx] = original->a[y][x]; + bufwv.b[loy - begy][lox - begx] = original->b[y][x]; + } + + } + + // int DaubLen = 6; + + int levwavL = levred; + int skip = 1; + wavelet_decomposition Ldecomp(bufwv.L[0], bufwv.W, bufwv.H, levwavL, 1, skip, numThreads, lp.daubLen); + wavelet_decomposition adecomp(bufwv.a[0], bufwv.W, bufwv.H, levwavL, 1, skip, numThreads, lp.daubLen); + wavelet_decomposition bdecomp(bufwv.b[0], bufwv.W, bufwv.H, levwavL, 1, skip, numThreads, lp.daubLen); + float madL[10][3]; + int edge = 2; + + if (!Ldecomp.memory_allocation_failed()) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) if (multiThread) +#endif + for (int lvl = 0; lvl < levred; lvl++) { + for (int dir = 1; dir < 4; dir++) { + int Wlvl_L = Ldecomp.level_W(lvl); + int Hlvl_L = Ldecomp.level_H(lvl); + + const float* const* WavCoeffs_L = Ldecomp.level_coeffs(lvl); + + madL[lvl][dir - 1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); + } + } + + float vari[levred]; + float mxsl = 0.f; + // float mxsfl = 0.f; + + if (aut == 0) { + if (levred == 7) { + edge = 2; + vari[0] = 0.8f * SQR((lp.noiself0 / 125.0) * (1.0 + lp.noiself0 / 25.0)); + vari[1] = 0.8f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); + vari[2] = 0.8f * SQR((lp.noiself2 / 125.0) * (1.0 + lp.noiself2 / 25.0)); + + vari[3] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[4] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[5] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[6] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + } else if (levred == 4) { + edge = 3; + vari[0] = 0.8f * SQR((lp.noiself0 / 125.0) * (1.0 + lp.noiself0 / 25.0)); + vari[1] = 0.8f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0)); + vari[2] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + vari[3] = 0.8f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0)); + + } + } else if (aut == 1 || aut == 2) { + edge = 2; + vari[0] = SQR(slidL[0]); + vari[1] = SQR(slidL[1]); + vari[2] = SQR(slidL[2]); + vari[3] = SQR(slidL[3]); + vari[4] = SQR(slidL[4]); + vari[5] = SQR(slidL[5]); + vari[6] = SQR(slidL[6]); + float mxslid34 = rtengine::max(slidL[3], slidL[4]); + float mxslid56 = rtengine::max(slidL[5], slidL[6]); + mxsl = rtengine::max(mxslid34, mxslid56); + + } + + { + float kr3 = 0.f; + float kr4 = 0.f; + float kr5 = 0.f; + + if (aut == 0 || aut == 1) { + if ((lp.noiselc < 30.f && aut == 0) || (mxsl < 30.f && aut == 1)) { + kr3 = 0.f; + kr4 = 0.f; + kr5 = 0.f; + } else if ((lp.noiselc < 50.f && aut == 0) || (mxsl < 50.f && aut == 1)) { + kr3 = 0.5f; + kr4 = 0.3f; + kr5 = 0.2f; + } else if ((lp.noiselc < 70.f && aut == 0) || (mxsl < 70.f && aut == 1)) { + kr3 = 0.7f; + kr4 = 0.5f; + kr5 = 0.3f; + } else { + kr3 = 1.f; + kr4 = 1.f; + kr5 = 1.f; + } + } else if (aut == 2) { + kr3 = 1.f; + kr4 = 1.f; + kr5 = 1.f; + + } + + vari[0] = rtengine::max(0.000001f, vari[0]); + vari[1] = rtengine::max(0.000001f, vari[1]); + vari[2] = rtengine::max(0.000001f, vari[2]); + vari[3] = rtengine::max(0.000001f, kr3 * vari[3]); + + if (levred == 7) { + vari[4] = rtengine::max(0.000001f, kr4 * vari[4]); + vari[5] = rtengine::max(0.000001f, kr5 * vari[5]); + vari[6] = rtengine::max(0.000001f, kr5 * vari[6]); + } + + // float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL + float* noisevarlum = new float[bfh * bfw]; + int bfw2 = (bfw + 1) / 2; + + float nvlh[13] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 0.7f, 0.5f}; //high value + float nvll[13] = {0.1f, 0.15f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.45f, 0.7f, 0.8f, 1.f, 1.f, 1.f}; //low value + + float seuillow = 3000.f;//low + float seuilhigh = 18000.f;//high + int i = 10 - lp.noiselequal; + float ac = (nvlh[i] - nvll[i]) / (seuillow - seuilhigh); + float bc = nvlh[i] - seuillow * ac; + //ac and bc for transition +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + float lN = bufwv.L[ir][jr]; + + if (lN < seuillow) { + noisevarlum[(ir >> 1)*bfw2 + (jr >> 1)] = nvlh[i]; + } else if (lN < seuilhigh) { + noisevarlum[(ir >> 1)*bfw2 + (jr >> 1)] = ac * lN + bc; + } else { + noisevarlum[(ir >> 1)*bfw2 + (jr >> 1)] = nvll[i]; + } + } + + + if ((lp.noiselc < 0.02f && aut == 0) || (mxsl < 1.f && (aut == 1 || aut == 2))) { + WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads); + } else { + WaveletDenoiseAll_BiShrinkL(Ldecomp, noisevarlum, madL, vari, edge, numThreads); + WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads); + } + + delete [] noisevarlum; + + } + } + + + float variC[levred]; + float variCb[levred]; + + float noisecfr = lp.noisecf; + float noiseccr = lp.noisecc; + + if (lp.adjch > 0.f) { + noisecfr = lp.noisecf + 0.1f * lp.adjch; + noiseccr = lp.noisecc + 0.1f * lp.adjch; + } + + float noisecfb = lp.noisecf; + float noiseccb = lp.noisecc; + + if (lp.adjch < 0.f) { + noisecfb = lp.noisecf - 0.1f * lp.adjch; + noiseccb = lp.noisecc - 0.1f * lp.adjch; + } + + + if (noisecfr < 0.f) { + noisecfr = 0.00001f; + } + + if (noiseccr < 0.f) { + noiseccr = 0.00001f; + } + + if (noisecfb < 0.f) { + noisecfb = 0.00001f; + } + + if (noiseccb < 0.f) { + noiseccb = 0.00001f; + } + + + if (!adecomp.memory_allocation_failed() && !bdecomp.memory_allocation_failed()) { + float maxcfine = 0.f; + float maxccoarse = 0.f; + + if (aut == 0) { + + if (levred == 7) { + edge = 2; + variC[0] = SQR(noisecfr); + variC[1] = SQR(noisecfr); + variC[2] = SQR(noisecfr); + + variC[3] = SQR(noisecfr); + variC[4] = SQR(noisecfr); + variC[5] = SQR(noiseccr); + variC[6] = SQR(noiseccr); + + variCb[0] = SQR(noisecfb); + variCb[1] = SQR(noisecfb); + variCb[2] = SQR(noisecfb); + + variCb[3] = SQR(noisecfb); + variCb[4] = SQR(noisecfb); + variCb[5] = SQR(noiseccb); + variCb[6] = SQR(noiseccb); + + } else if (levred == 4) { + edge = 3; + variC[0] = SQR(lp.noisecf / 10.0); + variC[1] = SQR(lp.noisecf / 10.0); + variC[2] = SQR(lp.noisecf / 10.0); + variC[3] = SQR(lp.noisecf / 10.0); + + variCb[0] = SQR(lp.noisecf / 10.0); + variCb[1] = SQR(lp.noisecf / 10.0); + variCb[2] = SQR(lp.noisecf / 10.0); + variCb[3] = SQR(lp.noisecf / 10.0); + + + } + } else if (aut == 1 || aut == 2) { + edge = 2; + variC[0] = SQR(slida[0]); + variC[1] = SQR(slida[1]); + variC[2] = SQR(slida[2]); + variC[3] = SQR(slida[3]); + variC[4] = SQR(slida[4]); + variC[5] = SQR(slida[5]); + variC[6] = SQR(slida[6]); + float maxc01 = rtengine::max(slida[0], slida[1]); + float maxc23 = rtengine::max(slida[2], slida[3]); + float max03 = rtengine::max(maxc01, maxc23); + float maxrf = rtengine::max(max03, slida[4]); + float maxrc = rtengine::max(slida[5], slida[6]); + + variCb[0] = SQR(slidb[0]); + variCb[1] = SQR(slidb[1]); + variCb[2] = SQR(slidb[2]); + variCb[3] = SQR(slidb[3]); + variCb[4] = SQR(slidb[4]); + variCb[5] = SQR(slidb[5]); + variCb[6] = SQR(slidb[6]); + float maxb01 = rtengine::max(slidb[0], slidb[1]); + float maxb23 = rtengine::max(slidb[2], slidb[3]); + float maxb03 = rtengine::max(maxb01, maxb23); + float maxbf = rtengine::max(maxb03, slidb[4]); + maxcfine = rtengine::max(maxrf, maxbf); + + float maxbc = rtengine::max(slidb[5], slidb[6]); + maxccoarse = rtengine::max(maxrc, maxbc); + + } + + { + float minic = 0.000001f; + + if (noiscfactiv) { + minic = 0.1f;//only for artifact shape detection + } + + float k1 = 0.f; + float k2 = 0.f; + float k3 = 0.f; + + if (aut == 0 || aut == 1) { + if ((lp.noisecf < 0.2f && aut == 0) || (maxcfine < 0.2f && aut == 1)) { + k1 = 0.05f; + k2 = 0.f; + k3 = 0.f; + } else if ((lp.noisecf < 0.3f && aut == 0) || (maxcfine < 0.3f && aut == 1)) { + k1 = 0.1f; + k2 = 0.0f; + k3 = 0.f; + } else if ((lp.noisecf < 0.5f && aut == 0) || (maxcfine < 0.5f && aut == 1)) { + k1 = 0.2f; + k2 = 0.1f; + k3 = 0.f; + } else if ((lp.noisecf < 0.8f && aut == 0) || (maxcfine < 0.8f && aut == 1)) { + k1 = 0.3f; + k2 = 0.25f; + k3 = 0.f; + } else if ((lp.noisecf < 1.f && aut == 0) || (maxcfine < 1.f && aut == 1)) { + k1 = 0.4f; + k2 = 0.25f; + k3 = 0.1f; + } else if ((lp.noisecf < 2.f && aut == 0) || (maxcfine < 2.f && aut == 1)) { + k1 = 0.5f; + k2 = 0.3f; + k3 = 0.15f; + } else if ((lp.noisecf < 3.f && aut == 0) || (maxcfine < 3.f && aut == 1)) { + k1 = 0.6f; + k2 = 0.45f; + k3 = 0.3f; + } else if ((lp.noisecf < 4.f && aut == 0) || (maxcfine < 4.f && aut == 1)) { + k1 = 0.7f; + k2 = 0.5f; + k3 = 0.4f; + } else if ((lp.noisecf < 5.f && aut == 0) || (maxcfine < 5.f && aut == 1)) { + k1 = 0.8f; + k2 = 0.6f; + k3 = 0.5f; + } else if ((lp.noisecf < 6.f && aut == 0) || (maxcfine < 10.f && aut == 1)) { + k1 = 0.85f; + k2 = 0.7f; + k3 = 0.6f; + } else if ((lp.noisecf < 8.f && aut == 0) || (maxcfine < 20.f && aut == 1)) { + k1 = 0.9f; + k2 = 0.8f; + k3 = 0.7f; + } else if ((lp.noisecf < 10.f && aut == 0) || (maxcfine < 50.f && aut == 1)) { + k1 = 1.f; + k2 = 1.f; + k3 = 0.9f; + + } else { + k1 = 1.f; + k2 = 1.f; + k3 = 1.f; + } + } else if (aut == 2) { + k1 = 1.f; + k2 = 1.f; + k3 = 1.f; + } + + variC[0] = rtengine::max(minic, variC[0]); + variC[1] = rtengine::max(minic, k1 * variC[1]); + variC[2] = rtengine::max(minic, k2 * variC[2]); + variC[3] = rtengine::max(minic, k3 * variC[3]); + + variCb[0] = rtengine::max(minic, variCb[0]); + variCb[1] = rtengine::max(minic, k1 * variCb[1]); + variCb[2] = rtengine::max(minic, k2 * variCb[2]); + variCb[3] = rtengine::max(minic, k3 * variCb[3]); + + if (levred == 7) { + float k4 = 0.f; + float k5 = 0.f; + float k6 = 0.f; + + if ((lp.noisecc < 0.2f && aut == 0) || (maxccoarse < 0.2f && aut == 1)) { + k4 = 0.1f; + k5 = 0.02f; + } else if ((lp.noisecc < 0.5f && aut == 0) || (maxccoarse < 0.5f && aut == 1)) { + k4 = 0.15f; + k5 = 0.05f; + } else if ((lp.noisecc < 1.f && aut == 0) || (maxccoarse < 1.f && aut == 1)) { + k4 = 0.15f; + k5 = 0.1f; + } else if ((lp.noisecc < 3.f && aut == 0) || (maxccoarse < 3.f && aut == 1)) { + k4 = 0.3f; + k5 = 0.15f; + } else if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + k4 = 0.6f; + k5 = 0.4f; + } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + k4 = 0.8f; + k5 = 0.6f; + } else { + k4 = 1.f; + k5 = 1.f; + } + + + variC[4] = rtengine::max(0.000001f, k4 * variC[4]); + variC[5] = rtengine::max(0.000001f, k5 * variC[5]); + variCb[4] = rtengine::max(0.000001f, k4 * variCb[4]); + variCb[5] = rtengine::max(0.000001f, k5 * variCb[5]); + + if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 4.f && aut == 1)) { + k6 = 0.f; + } else if ((lp.noisecc < 5.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + k6 = 0.4f; + } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + k6 = 0.7f; + } else { + k6 = 1.f; + } + + variC[6] = rtengine::max(0.00001f, k6 * variC[6]); + variCb[6] = rtengine::max(0.00001f, k6 * variCb[6]); + } + + float* noisevarchrom = new float[bfh * bfw]; + int bfw2 = (bfw + 1) / 2; + float nvch = 0.6f;//high value + float nvcl = 0.1f;//low value + + if ((lp.noisecf > 30.f && aut == 0) || (maxcfine > 100.f && (aut == 1 || aut == 2))) { + nvch = 0.8f; + nvcl = 0.4f; + } + + float seuil = 4000.f;//low + float seuil2 = 15000.f;//high + //ac and bc for transition + float ac = (nvch - nvcl) / (seuil - seuil2); + float bc = nvch - seuil * ac; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + float cN = std::sqrt(SQR(bufwv.a[ir][jr]) + SQR(bufwv.b[ir][jr])); + + if (cN < seuil) { + noisevarchrom[(ir >> 1)*bfw2 + (jr >> 1)] = nvch; + } else if (cN < seuil2) { + noisevarchrom[(ir >> 1)*bfw2 + (jr >> 1)] = ac * cN + bc; + } else { + noisevarchrom[(ir >> 1)*bfw2 + (jr >> 1)] = nvcl; + } + } + + float noisevarab_r = 100.f; //SQR(lp.noisecc / 10.0); + + if ((lp.noisecc < 0.02f && aut == 0) || (maxccoarse < 0.1f && (aut == 1 || aut == 2))) { + WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads); + WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads); + } else { + WaveletDenoiseAll_BiShrinkAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads); + WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads); + + WaveletDenoiseAll_BiShrinkAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads); + WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads); + } + + delete[] noisevarchrom; + } + } + + if (!Ldecomp.memory_allocation_failed()) { + Lin = new array2D(bfw, bfh); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < bfh; ++i) { + for (int j = 0; j < bfw; ++j) { + (*Lin)[i][j] = bufwv.L[i][j]; + } + } + + Ldecomp.reconstruct(bufwv.L[0]); + } + + + if (!Ldecomp.memory_allocation_failed() && aut == 0) { + + + if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f) { + fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.L, Lin, numThreads, lp, 0); + } + } + + + if (!adecomp.memory_allocation_failed()) { + Ain = new array2D(bfw, bfh); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < bfh; ++i) { + for (int j = 0; j < bfw; ++j) { + (*Ain)[i][j] = bufwv.a[i][j]; + } + } + + adecomp.reconstruct(bufwv.a[0]); + } + + if (!adecomp.memory_allocation_failed() && aut == 0) { + if ((lp.noisecf >= 0.001f || lp.noisecc >= 0.001f) && levred == 7 && lp.noisechrodetail != 100.f) { + fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.a, Ain, numThreads, lp, 1); + } + } + + + if (!bdecomp.memory_allocation_failed()) { + Bin = new array2D(bfw, bfh); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < bfh; ++i) { + for (int j = 0; j < bfw; ++j) { + (*Bin)[i][j] = bufwv.b[i][j]; + } + } + + bdecomp.reconstruct(bufwv.b[0]); + } + + if (!bdecomp.memory_allocation_failed() && aut == 0) { + if ((lp.noisecf >= 0.001f || lp.noisecc >= 0.001f) && levred == 7 && lp.noisechrodetail != 100.f) { + fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.b, Bin, numThreads, lp, 1); + } + } + + if(lp.smasktyp != 0) { + DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, bufwv, cx, cy, sk); + } else { + DeNoise_Local(call, lp, original, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, bufwv, cx, cy, sk); + } + + // DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, bufwv, cx, cy, sk); + } + } + } + +} + +float triangle(float a, float a1, float b) +{ + if (a != b) { + float b1; + float a2 = a1 - a; + + if (b < a) { + b1 = b + a2 * b / a ; + } else { + b1 = b + a2 * (65535.f - b) / (65535.f - a); + } + + return b1; + } + + return a1; +} + +void rgbtone(float& maxval, float& medval, float& minval, const LUTf& lutToneCurve) +{ + float minvalold = minval, medvalold = medval, maxvalold = maxval; + + maxval = lutToneCurve[maxvalold]; + minval = lutToneCurve[minvalold]; + medval = minval + ((maxval - minval) * (medvalold - minvalold) / (maxvalold - minvalold)); +} + +void clarimerge(struct local_params& lp, float &mL, float &mC, bool &exec, LabImage *tmpresid, int wavelet_level, int sk, int numThreads) +{ + if (mL != 0.f && mC == 0.f) { + mC = 0.0001f; + exec = true; + } + + if (mC != 0.f && mL == 0.f) { + mL = 0.0001f; + exec = true; + } + + if (mL != 0.f && mC != 0.f) { + exec = true; + } + + if (mL != 0.f) { + + wavelet_decomposition *wdspotresid = new wavelet_decomposition(tmpresid->L[0], tmpresid->W, tmpresid->H, wavelet_level, 1, sk, numThreads, lp.daubLen); + + if (wdspotresid->memory_allocation_failed()) { + return; + } + + int maxlvlresid = wdspotresid->maxlevel(); + + if (maxlvlresid > 4) {//Clarity +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) +#endif + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < maxlvlresid; ++level) { + int W_L = wdspotresid->level_W(level); + int H_L = wdspotresid->level_H(level); + float* const* wav_Lresid = wdspotresid->level_coeffs(level); + + for (int i = 0; i < W_L * H_L; i++) { + wav_Lresid[dir][i] = 0.f; + } + } + } + } else {//Sharp + float *wav_L0resid = wdspotresid->get_coeff0(); + int W_L = wdspotresid->level_W(0); + int H_L = wdspotresid->level_H(0); + + for (int i = 0; i < W_L * H_L; i++) { + wav_L0resid[i] = 0.f; + } + } + + wdspotresid->reconstruct(tmpresid->L[0], 1.f); + delete wdspotresid; + } + + + if (mC != 0.f) { + + wavelet_decomposition *wdspotresida = new wavelet_decomposition(tmpresid->a[0], tmpresid->W, tmpresid->H, wavelet_level, 1, sk, numThreads, lp.daubLen); + + if (wdspotresida->memory_allocation_failed()) { + return; + } + + int maxlvlresid = wdspotresida->maxlevel(); + + if (maxlvlresid > 4) {//Clarity +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) +#endif + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < maxlvlresid; ++level) { + int W_L = wdspotresida->level_W(level); + int H_L = wdspotresida->level_H(level); + float* const* wav_Lresida = wdspotresida->level_coeffs(level); + + for (int i = 0; i < W_L * H_L; i++) { + wav_Lresida[dir][i] = 0.f; + } + } + } + } else {//Sharp + float *wav_L0resida = wdspotresida->get_coeff0(); + int W_L = wdspotresida->level_W(0); + int H_L = wdspotresida->level_H(0); + + for (int i = 0; i < W_L * H_L; i++) { + wav_L0resida[i] = 0.f; + } + } + + wdspotresida->reconstruct(tmpresid->a[0], 1.f); + delete wdspotresida; + + wavelet_decomposition *wdspotresidb = new wavelet_decomposition(tmpresid->b[0], tmpresid->W, tmpresid->H, wavelet_level, 1, sk, numThreads, lp.daubLen); + + if (wdspotresidb->memory_allocation_failed()) { + return; + } + + maxlvlresid = wdspotresidb->maxlevel(); + + if (maxlvlresid > 4) {//Clarity +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic) collapse(2) +#endif + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < maxlvlresid; ++level) { + int W_L = wdspotresidb->level_W(level); + int H_L = wdspotresidb->level_H(level); + float* const* wav_Lresidb = wdspotresidb->level_coeffs(level); + + for (int i = 0; i < W_L * H_L; i++) { + wav_Lresidb[dir][i] = 0.f; + } + } + } + } else {//Sharp + float *wav_L0residb = wdspotresidb->get_coeff0(); + int W_L = wdspotresidb->level_W(0); + int H_L = wdspotresidb->level_H(0); + + for (int i = 0; i < W_L * H_L; i++) { + wav_L0residb[i] = 0.f; + } + } + + wdspotresidb->reconstruct(tmpresid->b[0], 1.f); + delete wdspotresidb; + } +} + +void ImProcFunctions::Lab_Local( + int call, int sp, float** shbuffer, LabImage * original, LabImage * transformed, LabImage * reserved, LabImage * lastorig, int cx, int cy, int oW, int oH, int sk, + const LocretigainCurve& locRETgainCcurve, const LocretitransCurve& locRETtransCcurve, + const LUTf& lllocalcurve, bool locallutili, + const LUTf& cllocalcurve, bool localclutili, + const LUTf& lclocalcurve, bool locallcutili, + const LocLHCurve& loclhCurve, const LocHHCurve& lochhCurve, + const LUTf& lmasklocalcurve, bool localmaskutili, + const LUTf& lmaskexplocalcurve, bool localmaskexputili, + const LUTf& lmaskSHlocalcurve, bool localmaskSHutili, + const LUTf& lmaskviblocalcurve, bool localmaskvibutili, + const LUTf& lmasktmlocalcurve, bool localmasktmutili, + LUTf& lmaskretilocalcurve, bool localmaskretiutili, + const LUTf& lmaskcblocalcurve, bool localmaskcbutili, + const LUTf& lmaskbllocalcurve, bool localmaskblutili, + const LUTf& lmasklclocalcurve, bool localmasklcutili, + const LocCCmaskCurve& locccmasCurve, bool lcmasutili, const LocLLmaskCurve& locllmasCurve, bool llmasutili, const LocHHmaskCurve& lochhmasCurve, bool lhmasutili, const LocHHmaskCurve& lochhhmasCurve, bool lhhmasutili, + const LocCCmaskCurve& locccmasexpCurve, bool lcmasexputili, const LocLLmaskCurve& locllmasexpCurve, bool llmasexputili, const LocHHmaskCurve& lochhmasexpCurve, bool lhmasexputili, + const LocCCmaskCurve& locccmasSHCurve, bool lcmasSHutili, const LocLLmaskCurve& locllmasSHCurve, bool llmasSHutili, const LocHHmaskCurve& lochhmasSHCurve, bool lhmasSHutili, + const LocCCmaskCurve& locccmasvibCurve, bool lcmasvibutili, const LocLLmaskCurve& locllmasvibCurve, bool llmasvibutili, const LocHHmaskCurve& lochhmasvibCurve, bool lhmasvibutili, + const LocCCmaskCurve& locccmascbCurve, bool lcmascbutili, const LocLLmaskCurve& locllmascbCurve, bool llmascbutili, const LocHHmaskCurve& lochhmascbCurve, bool lhmascbutili, + const LocCCmaskCurve& locccmasretiCurve, bool lcmasretiutili, const LocLLmaskCurve& locllmasretiCurve, bool llmasretiutili, const LocHHmaskCurve& lochhmasretiCurve, bool lhmasretiutili, + const LocCCmaskCurve& locccmastmCurve, bool lcmastmutili, const LocLLmaskCurve& locllmastmCurve, bool llmastmutili, const LocHHmaskCurve& lochhmastmCurve, bool lhmastmutili, + const LocCCmaskCurve& locccmasblCurve, bool lcmasblutili, const LocLLmaskCurve& locllmasblCurve, bool llmasblutili, const LocHHmaskCurve& lochhmasblCurve, bool lhmasblutili, + const LocCCmaskCurve& locccmaslcCurve, bool lcmaslcutili, const LocLLmaskCurve& locllmaslcCurve, bool llmaslcutili, const LocHHmaskCurve& lochhmaslcCurve, bool lhmaslcutili, + const LocwavCurve& loclmasCurveblwav, bool lmasutiliblwav, + const LocwavCurve& loclmasCurvecolwav, bool lmasutilicolwav, + const LocwavCurve& locwavCurve, bool locwavutili, + const LocwavCurve& loclevwavCurve, bool loclevwavutili, + const LocwavCurve& locconwavCurve, bool locconwavutili, + const LocwavCurve& loccompwavCurve, bool loccompwavutili, + const LocwavCurve& loccomprewavCurve, bool loccomprewavutili, + const LocwavCurve& locwavCurveden, bool locwavdenutili, + const LocwavCurve& locedgwavCurve, bool locedgwavutili, + bool LHutili, bool HHutili, const LUTf& cclocalcurve, bool localcutili, const LUTf& rgblocalcurve, bool localrgbutili, bool localexutili, const LUTf& exlocalcurve, const LUTf& hltonecurveloc, const LUTf& shtonecurveloc, const LUTf& tonecurveloc, const LUTf& lightCurveloc, + double& huerefblur, double& chromarefblur, double& lumarefblur, double& hueref, double& chromaref, double& lumaref, double& sobelref, int &lastsav, + bool prevDeltaE, int llColorMask, int llColorMaskinv, int llExpMask, int llExpMaskinv, int llSHMask, int llSHMaskinv, int llvibMask, int lllcMask, int llsharMask, int llcbMask, int llretiMask, int llsoftMask, int lltmMask, int llblMask, + float& minCD, float& maxCD, float& mini, float& maxi, float& Tmean, float& Tsigma, float& Tmin, float& Tmax + ) +{ + //general call of others functions : important return hueref, chromaref, lumaref + if (!params->locallab.enabled) { + return; + } + + BENCHFUN + + constexpr int del = 3; // to avoid crash with [loy - begy] and [lox - begx] and bfh bfw // with gtk2 [loy - begy-1] [lox - begx -1 ] and del = 1 + struct local_params lp; + calcLocalParams(sp, oW, oH, params->locallab, lp, prevDeltaE, llColorMask, llColorMaskinv, llExpMask, llExpMaskinv, llSHMask, llSHMaskinv, llvibMask, lllcMask, llsharMask, llcbMask, llretiMask, llsoftMask, lltmMask, llblMask, locwavCurveden, locwavdenutili); + + const float radius = lp.rad / (sk * 1.4f); //0 to 70 ==> see skip + int levred; + bool noiscfactiv; + + if (lp.qualmet == 2) { //suppress artifacts with quality enhanced + levred = 4; + noiscfactiv = true; + } else { + levred = 7; + noiscfactiv = false; + } + +//lastsav for save restore image + lastsav = 0; + + if (lp.excmet == 1 && call <= 3) {//exclude + const int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone + const int bfw = int (lp.lx + lp.lxL) + del; + const int begy = lp.yc - lp.lyT; + const int begx = lp.xc - lp.lxL; + const int yEn = lp.yc + lp.ly; + const int xEn = lp.xc + lp.lx; + LabImage bufreserv(bfw, bfh); + array2D bufsob(bfw, bfh); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int y = rtengine::max(begy - cy, 0); y < rtengine::min(yEn - cy, original->H); y++) { + const int loy = cy + y; + + for (int x = rtengine::max(begx - cx, 0); x < rtengine::min(xEn - cx, original->W); x++) { + const int lox = cx + x; + + bufsob[loy - begy][lox - begx] = bufreserv.L[loy - begy][lox - begx] = reserved->L[y][x]; + bufreserv.a[loy - begy][lox - begx] = reserved->a[y][x]; + bufreserv.b[loy - begy][lox - begx] = reserved->b[y][x]; + } + } + + array2D ble(bfw, bfh); + const float radiussob = 1.f / (sk * 1.4f); + SobelCannyLuma(ble, bufsob, bfw, bfh, radiussob); + array2D &guid = bufsob; + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + ble[ir][jr] /= 32768.f; + guid[ir][jr] /= 32768.f; + } + + + const float blur = 25 / sk * (2.f + 2.5f * lp.struexp); + + rtengine::guidedFilter(guid, ble, ble, blur, 0.0001, multiThread); + +// const float blur = 25 / sk * (10.f + 0.8f * lp.struexp); + +// rtengine::guidedFilter(guid, ble, ble, blur, 0.001, multiThread); + + double sombel = 0.f; + const int ncsobel = bfh * bfw; + + array2D &deltasobelL = guid; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:sombel) if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + const float val = ble[ir][jr] * 32768.f; + sombel += val; + deltasobelL[ir][jr] = val; + } + } + + const float meansob = sombel / ncsobel; + Exclude_Local(deltasobelL, hueref, chromaref, lumaref, sobelref, meansob, lp, original, transformed, &bufreserv, reserved, cx, cy, sk); + } + +//encoding lab at the beginning + if (lp.logena) { + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + const int bfh = yend - ystart; + const int bfw = xend - xstart; + + if (bfh >= mSP && bfw >= mSP) { + const std::unique_ptr bufexporig(new LabImage(bfw, bfh)); //buffer for data in zone limit + const std::unique_ptr bufexpfin(new LabImage(bfw, bfh)); //buffer for data in zone limit + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufexporig->L[y - ystart][x - xstart] = original->L[y][x]; + bufexporig->a[y - ystart][x - xstart] = original->a[y][x]; + bufexporig->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + + bufexpfin->CopyFrom(bufexporig.get(), multiThread); + std::unique_ptr tmpImage(new Imagefloat(bfw, bfh)); + lab2rgb(*bufexpfin, *tmpImage, params->icm.workingProfile); + log_encode(tmpImage.get(), lp, multiThread, bfw, bfh); + rgb2lab(*(tmpImage.get()), *bufexpfin, params->icm.workingProfile); + tmpImage.reset(); + + //here begin graduated filter + //first solution "easy" but we can do other with log_encode...to see the results + if (lp.strlog != 0.f) { + struct grad_params gplog; + calclocalGradientParams(lp, gplog, ystart, xstart, bfw, bfh, 11); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufexpfin->L[ir][jr] *= ImProcFunctions::calcGradientFactor(gplog, jr, ir); + } + } + } + + //end graduated + transit_shapedetect2(call, 11, bufexporig.get(), bufexpfin.get(), nullptr, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + +//Prepare mask for Blur and noise and Denoise + bool denoiz = false; + + if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f || lp.bilat > 0.f) && lp.denoiena) { + denoiz = true; + } + + bool blurz = false; + bool delt = params->locallab.spots.at(sp).deltae; + bool astool = params->locallab.spots.at(sp).toolbl; + + if (((radius > 1.5 * GAUSS_SKIP) || lp.stren > 0.1 || lp.blmet == 1 || lp.guidb > 1 || lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.blurena) { + blurz = true; + } + + const int GW = transformed->W; + const int GH = transformed->H; + + LabImage * originalmaskbl = nullptr; + std::unique_ptr bufmaskorigbl; + std::unique_ptr bufmaskblurbl; + std::unique_ptr bufgb; + std::unique_ptr bufprov(new LabImage(GW, GH)); + + if (denoiz || blurz || lp.denoiena || lp.blurena) { + bufgb.reset(new LabImage(GW, GH)); + + if (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) { + bufmaskorigbl.reset(new LabImage(GW, GH)); + bufmaskblurbl.reset(new LabImage(GW, GH)); + originalmaskbl = new LabImage(GW, GH); + } + + array2D ble(GW, GH); + array2D blechro(GW, GH); + array2D hue(GW, GH); + array2D guid(GW, GH); + float meanfab, fab; + mean_fab(0, 0, GW, GH, bufgb.get(), original, fab, meanfab, lp.chromabl, multiThread); + float chromult = 1.f - 0.01f * lp.chromabl; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH; y++) { + for (int x = 0; x < GW; x++) { + bufgb->L[y][x] = original->L[y][x]; + bufgb->a[y][x] = original->a[y][x]; + bufgb->b[y][x] = original->b[y][x]; + } + } + + const float strumask = 0.02f * params->locallab.spots.at(sp).strumaskbl; + JaggedArray blendstru(GW, GH); + + if (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) { + if (strumask > 0.f) { + float delstrumask = 4.1f - strumask;//4.1 = 2 * max slider strumask + 0.1 + buildBlendMask(bufgb->L, blendstru, GW, GH, delstrumask); + const float radblur = 0.02f * 0.1f * std::fabs(lp.radmabl); + const float rm = radblur / sk; + + if (rm > 0) { +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(blendstru, blendstru, GW, GH, rm); + } + } + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) { + for (int jr = 0; jr < GW; jr++) { + float kmaskLexp = 0.f; + float kmaskCH = 0.f; + float kmasstru = 0.f; + + if (strumask > 0.f && !astool) { + kmasstru = bufgb->L[ir][jr] * blendstru[ir][jr]; + } + + if (locllmasblCurve && llmasblutili) { + const float ligh = bufgb->L[ir][jr] / 32768.f; + kmaskLexp = 32768.f * LIM01(1.f - locllmasblCurve[500.f * ligh]); + } + + if (lp.showmaskblmet != 4) { + if (locccmasblCurve && lcmasblutili) { + const float chromask = 0.0001f + std::sqrt(SQR((bufgb->a[ir][jr]) / fab) + SQR((bufgb->b[ir][jr]) / fab)); + kmaskCH = LIM01(1.f - locccmasblCurve[500.f * chromask]); + } + } + + if (lochhmasblCurve && lhmasblutili) { + const float huema = xatan2f(bufgb->b[ir][jr], bufgb->a[ir][jr]); + float h = Color::huelab_to_huehsv2(huema); + h += 1.f / 6.f; + + if (h > 1.f) { + h -= 1.f; + } + + const float valHH = LIM01(1.f - lochhmasblCurve[500.f * h]); + + if (lp.showmaskblmet != 4) { + kmaskCH += chromult * valHH; + } + + kmaskLexp += 32768.f * valHH; + } + + bufmaskblurbl->L[ir][jr] = clipLoc(kmaskLexp + kmasstru); + bufmaskblurbl->a[ir][jr] = kmaskCH; + bufmaskblurbl->b[ir][jr] = kmaskCH; + ble[ir][jr] = bufmaskblurbl->L[ir][jr] / 32768.f; + hue[ir][jr] = xatan2f(bufmaskblurbl->b[ir][jr], bufmaskblurbl->a[ir][jr]); + const float chromah = std::sqrt(SQR(bufmaskblurbl->b[ir][jr]) + SQR(bufmaskblurbl->a[ir][jr])); + blechro[ir][jr] = chromah / 32768.f; + guid[ir][jr] = Color::L2Y(bufgb->L[ir][jr]) / 32768.f; + } + } + + const std::unique_ptr bufprov(new LabImage(GW, GH)); + + bufprov->CopyFrom(bufmaskblurbl.get(), multiThread); + + if (lp.radmabl != 0.f) { + float blur = lp.radmabl; + blur = blur < 0.f ? -1.f / blur : 1.f + blur; + const int r1 = rtengine::max(4 / sk * blur + 0.5f, 1); + const int r2 = rtengine::max(25 / sk * blur + 0.5f, 1); + + constexpr float epsilmax = 0.0005f; + constexpr float epsilmin = 0.00001f; + + const float aepsil = (epsilmax - epsilmin) / 90.f; + const float bepsil = epsilmax - 100.f * aepsil; + const float epsil = lp.radmabl < 0.f ? 0.001f : aepsil * lp.radmabl + bepsil; + + rtengine::guidedFilter(guid, blechro, blechro, r1, epsil, multiThread); + rtengine::guidedFilter(guid, ble, ble, r2, 0.2 * epsil, multiThread); + + // guidedFilter(guid, ble, ble, lp.radmabl * 10.f / sk, 0.001, multiThread, 4); + } + + LUTf lutTonemaskbl(65536); + calcGammaLut(lp.gammabl, lp.slomabl, lutTonemaskbl); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) { + for (int jr = 0; jr < GW; jr++) { + const float2 sincosval = xsincosf(hue[ir][jr]); + bufmaskblurbl->L[ir][jr] = LIM01(ble[ir][jr]) * 32768.f; + const float L_ = 2.f * bufmaskblurbl->L[ir][jr]; + bufmaskblurbl->L[ir][jr] = lutTonemaskbl[L_]; + bufmaskblurbl->a[ir][jr] = 32768.f * sincosval.y * blechro[ir][jr]; + bufmaskblurbl->b[ir][jr] = 32768.f * sincosval.x * blechro[ir][jr]; + } + } + } + + if (strumask > 0.f && astool && (lp.enablMask || lp.showmaskblmet == 3)) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) { + for (int jr = 0; jr < GW; jr++) { + bufmaskblurbl->L[ir][jr] *= (1.f + blendstru[ir][jr]); + } + } + } + + if (lmaskbllocalcurve && localmaskblutili && (lp.enablMask || lp.showmaskblmet == 3)) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) + for (int jr = 0; jr < GW; jr++) { + bufmaskblurbl->L[ir][jr] = 0.5f * lmaskbllocalcurve[2.f * bufmaskblurbl->L[ir][jr]]; + } + } + + const int highli = params->locallab.spots.at(sp).shadmaskbl; + + if (highli > 0 && (lp.enablMask || lp.showmaskblmet == 3)) { + ImProcFunctions::shadowsHighlights(bufmaskblurbl.get(), true, 1, highli, 0, 40, sk, 50, 0); + } + + const int shado = params->locallab.spots.at(sp).shadmaskblsha; + + if (shado > 0 && (lp.enablMask || lp.showmaskblmet == 3)) { + ImProcFunctions::shadowsHighlights(bufmaskblurbl.get(), true, 1, 0, shado, 40, sk, 0, 60); + } + + int wavelet_level = params->locallab.spots.at(sp).shadmaskbl; + int maxlvl = wavelet_level; + + int minwin = rtengine::min(GW, GH); + int maxlevelspot = 9; + + while ((1 << maxlevelspot) >= (minwin * sk) && maxlevelspot > 1) { + --maxlevelspot ; + } + + wavelet_level = rtengine::min(wavelet_level, maxlevelspot); + bool wavcurvemask = false; + + if (loclmasCurveblwav && lmasutiliblwav && (lp.enablMask || lp.showmaskblmet == 3)) { + for (int i = 0; i < 500; i++) { + if (loclmasCurveblwav[i] != 0.5) { + wavcurvemask = true; + } + } + } + + if (wavcurvemask && (lp.enablMask || lp.showmaskblmet == 3)) { + const int level_bl = params->locallab.spots.at(sp).csthresholdblur.getBottomLeft(); + const int level_hl = params->locallab.spots.at(sp).csthresholdblur.getTopLeft(); + const int level_br = params->locallab.spots.at(sp).csthresholdblur.getBottomRight(); + const int level_hr = params->locallab.spots.at(sp).csthresholdblur.getTopRight(); + +#ifdef _OPENMP + const int numThreads = omp_get_max_threads(); +#else + const int numThreads = 1; + +#endif + + wavelet_decomposition *wdspotbl = new wavelet_decomposition(bufmaskblurbl->L[0], GW, GH, maxlvl, 1, sk, numThreads, lp.daubLen); + if (wdspotbl->memory_allocation_failed()) { + return; + } + + + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + + Evaluate2(*wdspotbl, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); + float alow = 1.f; + float blow = 0.f; + if (level_hl != level_bl) { + alow = 1.f / (level_hl - level_bl); + blow = -alow * level_bl; + } + + float ahigh = 1.f; + float bhigh = 0.f; + + if (level_hr != level_br) { + ahigh = 1.f / (level_hr - level_br); + bhigh = -ahigh * level_br; + } + + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + int W_L = wdspotbl->level_W(level); + int H_L = wdspotbl->level_H(level); + float* const *wav_L = wdspotbl->level_coeffs(level); + + if (MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { + float insigma = 0.666f; //SD + float logmax = log(MaxP[level]); //log Max + float rapX = (mean[level] + sigma[level]) / MaxP[level]; //rapport between sD / max + float inx = log(insigma); + float iny = log(rapX); + float rap = inx / iny; //koef + float asig = 0.166f / (sigma[level]); + float bsig = 0.5f - asig * mean[level]; + float amean = 0.5f / mean[level]; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < W_L * H_L; i++) { + if(loclmasCurveblwav && lmasutiliblwav) { + float absciss; + float &val = wav_L[dir][i]; + + if (fabsf(val) >= (mean[level] + sigma[level])) { //for max + float valcour = xlogf(fabsf(val)); + float valc = valcour - logmax; + float vald = valc * rap; + absciss = xexpf(vald); + } else if (fabsf(val) >= mean[level]) { + absciss = asig * fabsf(val) + bsig; + } else { + absciss = amean * fabsf(val); + } + + float klev = 1.f; + if (level >= level_hl && level <= level_hr) { + klev = 1.f; + } + + if (level_hl != level_bl) { + if (level >= level_bl && level < level_hl) { + klev = alow * level + blow; + } + } + + if (level_hr != level_br) { + if (level > level_hr && level <= level_br) { + klev = ahigh * level + bhigh; + } + } + float kc = klev * (loclmasCurveblwav[absciss * 500.f] - 0.5f); + float amplieffect = kc <= 0.f ? 1.f : 4.f; + + float kinterm = 1.f + amplieffect * kc; + kinterm = kinterm <= 0.f ? 0.01f : kinterm; + + val *= kinterm; + + } + } + } + + } + } + wdspotbl->reconstruct(bufmaskblurbl->L[0], 1.f); + delete wdspotbl; + + } + + + // deltae Mask with scope + int sco = params->locallab.spots.at(sp).scopemask; + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + + if (delt && lp.blurmet == 0 && (lp.enablMask || lp.showmaskblmet == 3)) { + JaggedArray rdE(GW, GH); + deltaEforMask(rdE, GW, GH, bufgb.get(), hueref, chromaref, lumaref, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, lp.balance, lp.balanceh); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) { + for (int jr = 0; jr < GW; jr++) { + bufmaskblurbl->L[ir][jr] = bufprov->L[ir][jr] + rdE[ir][jr] * (bufmaskblurbl->L[ir][jr] - bufprov->L[ir][jr]); + bufmaskblurbl->a[ir][jr] = bufprov->a[ir][jr] + rdE[ir][jr] * (bufmaskblurbl->a[ir][jr] - bufprov->a[ir][jr]); + bufmaskblurbl->b[ir][jr] = bufprov->b[ir][jr] + rdE[ir][jr] * (bufmaskblurbl->b[ir][jr] - bufprov->b[ir][jr]); + } + } + } + + const float lap = params->locallab.spots.at(sp).lapmaskbl; + const bool pde = params->locallab.spots.at(sp).laplac; + const float lumask = params->locallab.spots.at(sp).lumask; + + if (lap > 0.f && (lp.enablMask || lp.showmaskblmet == 3)) { + const float *datain = bufmaskblurbl->L[0]; + const std::unique_ptr data_tmp(new float[GH * GW]); + + if (!pde) { + ImProcFunctions::discrete_laplacian_threshold(data_tmp.get(), datain, GW, GH, 200.f * lap); + } else { + ImProcFunctions::retinex_pde(datain, data_tmp.get(), GW, GH, 12.f * lap, 1.f, nullptr, 0, 0, 1); + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < GH; y++) { + for (int x = 0; x < GW; x++) { + bufmaskblurbl->L[y][x] = data_tmp[y * GW + x]; + } + } + } + + const float radiusb = 1.f / sk; + + if (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) { + const int invers = lp.blurmet == 1 ? 1 : 0; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufmaskblurbl->L, bufmaskorigbl->L, GW, GH, radiusb); + gaussianBlur(bufmaskblurbl->a, bufmaskorigbl->a, GW, GH, 1.f + (0.005f * lp.radmabl) / sk); + gaussianBlur(bufmaskblurbl->b, bufmaskorigbl->b, GW, GH, 1.f + (0.005f * lp.radmabl) / sk); + } + + if (lp.showmaskblmet == 0 || lp.showmaskblmet == 1 || lp.showmaskblmet == 2 || lp.showmaskblmet == 4 || lp.enablMask) { + blendmask(lp, 0, 0, cx, cy, GW, GH, bufgb.get(), original, bufmaskorigbl.get(), originalmaskbl, lp.blendmabl, invers); + } else if (lp.showmaskblmet == 3) { + showmask(lumask, lp, 0, 0, cx, cy, GW, GH, bufgb.get(), transformed, bufmaskorigbl.get(), invers); + return; + } + } + +//end mask + } + + bool execmaskblur = (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.smasktyp != 1; + if (((radius > 1.5 * GAUSS_SKIP && lp.rad > 1.6) || lp.stren > 0.1 || lp.blmet == 1 || lp.guidb > 0 || execmaskblur) && lp.blurena) { // radius < GAUSS_SKIP means no gauss, just copy of original image + // if (((radius > 1.5 * GAUSS_SKIP && lp.rad > 1.6) || lp.stren > 0.1 || lp.blmet == 1 || lp.guidb > 0 || lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.blurena) { // radius < GAUSS_SKIP means no gauss, just copy of original image + std::unique_ptr tmp1; + std::unique_ptr tmp2; + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + int bfhr = bfh; + int bfwr = bfw; + + bool fft = params->locallab.spots.at(sp).fftwbl; + int isogr = params->locallab.spots.at(sp).isogr; + int strengr = params->locallab.spots.at(sp).strengr; + int scalegr = params->locallab.spots.at(sp).scalegr; + + + + if (bfw >= mSP && bfh >= mSP) { + if (lp.blurmet == 0 && (fft || lp.rad > 30.f)) { + optfft(N_fftwsize, bfh, bfw, bfhr, bfwr, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + const std::unique_ptr bufgbi(new LabImage(GW, GH)); + + //here mask is used with plain image for normal and inverse + //if it is possible to optimize with maskcalccol(), I don't to preserve visibility + if (lp.showmaskblmet == 0 || lp.showmaskblmet == 1 || lp.showmaskblmet == 2 || lp.showmaskblmet == 4 || lp.enablMask) { + + if (lp.blurmet == 0) { + if (bfw > 0 && bfh > 0) { + tmp1.reset(new LabImage(bfw, bfh)); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend ; y++) { + for (int x = xstart; x < xend; x++) { + tmp1->L[y - ystart][x - xstart] = original->L[y][x]; + tmp1->a[y - ystart][x - xstart] = original->a[y][x]; + tmp1->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + } + } else if (lp.blurmet == 1) { + tmp1.reset(new LabImage(transformed->W, transformed->H)); + tmp2.reset(new LabImage(transformed->W, transformed->H)); + + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + tmp2->L[y][x] = original->L[y][x]; + tmp2->a[y][x] = original->a[y][x]; + tmp2->b[y][x] = original->b[y][x]; + bufgbi->L[y][x] = original->L[y][x]; + bufgbi->a[y][x] = original->a[y][x]; + bufgbi->b[y][x] = original->b[y][x]; + } + } + + } + + + if (lp.blurmet == 0 && lp.blmet == 0 && radius > (1.5 * GAUSS_SKIP) && lp.rad > 1.6) { + if (fft || lp.rad > 30.f) { + if (lp.chromet == 0) { + ImProcFunctions::fftw_convol_blur2(tmp1->L, tmp1->L, bfwr, bfhr, radius, 0, 0); + } else if (lp.chromet == 1) { + ImProcFunctions::fftw_convol_blur2(tmp1->a, tmp1->a, bfwr, bfhr, radius, 0, 0); + ImProcFunctions::fftw_convol_blur2(tmp1->b, tmp1->b, bfwr, bfhr, radius, 0, 0); + } else if (lp.chromet == 2) { + ImProcFunctions::fftw_convol_blur2(tmp1->L, tmp1->L, bfwr, bfhr, radius, 0, 0); + ImProcFunctions::fftw_convol_blur2(tmp1->a, tmp1->a, bfwr, bfhr, radius, 0, 0); + ImProcFunctions::fftw_convol_blur2(tmp1->b, tmp1->b, bfwr, bfhr, radius, 0, 0); + } + } else { + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + if (lp.chromet == 0) + { + gaussianBlur(tmp1->L, tmp1->L, bfw, bfh, radius); + } + + else if (lp.chromet == 1) + { + gaussianBlur(tmp1->a, tmp1->a, bfw, bfh, radius); + gaussianBlur(tmp1->b, tmp1->b, bfw, bfh, radius); + } else if (lp.chromet == 2) + { + gaussianBlur(tmp1->L, tmp1->L, bfw, bfh, radius); + gaussianBlur(tmp1->a, tmp1->a, bfw, bfh, radius); + gaussianBlur(tmp1->b, tmp1->b, bfw, bfh, radius); + } + } + } + + } else if (lp.blurmet == 1 && lp.blmet == 0 && radius > (1.5 * GAUSS_SKIP) && lp.rad > 1.6) { + if (fft || lp.rad > 30.f) { + if (lp.chromet == 0) { + ImProcFunctions::fftw_convol_blur2(original->L, tmp1->L, GW, GH, radius, 0, 0); + } + + else if (lp.chromet == 1) { + ImProcFunctions::fftw_convol_blur2(original->a, tmp1->a, GW, GH, radius, 0, 0); + ImProcFunctions::fftw_convol_blur2(original->b, tmp1->b, GW, GH, radius, 0, 0); + } else if (lp.chromet == 2) { + ImProcFunctions::fftw_convol_blur2(original->L, tmp1->L, GW, GH, radius, 0, 0); + ImProcFunctions::fftw_convol_blur2(original->a, tmp1->a, GW, GH, radius, 0, 0); + ImProcFunctions::fftw_convol_blur2(original->b, tmp1->b, GW, GH, radius, 0, 0); + } + + } else { + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + if (lp.chromet == 0) + { + gaussianBlur(original->L, tmp1->L, GW, GH, radius); + } else if (lp.chromet == 1) + + { + gaussianBlur(original->a, tmp1->a, GW, GH, radius); + gaussianBlur(original->b, tmp1->b, GW, GH, radius); + } else if (lp.chromet == 2) + + { + gaussianBlur(original->L, tmp1->L, GW, GH, radius); + gaussianBlur(original->a, tmp1->a, GW, GH, radius); + gaussianBlur(original->b, tmp1->b, GW, GH, radius); + } + } + } + } + + + //add noise + if (tmp1.get() && lp.stren > 0.1f && lp.blmet == 0) { + float mean = 0.f;//0 best result + float variance = lp.stren ; + addGaNoise(tmp1.get(), tmp1.get(), mean, variance, sk) ; + } + + //add grain + if (lp.blmet == 0 && strengr > 0) { + int wi = bfw; + int he = bfh; + + if (lp.blurmet == 1) { + wi = GW; + he = GH; + } + + if (tmp1.get()) { + Imagefloat *tmpImage = nullptr; + tmpImage = new Imagefloat(wi, he); + + for (int y = 0; y < he ; y++) { + for (int x = 0; x < wi; x++) { + tmpImage->g(y, x) = tmp1->L[y][x]; + tmpImage->r(y, x) = tmp1->a[y][x]; + tmpImage->b(y, x) = tmp1->b[y][x]; + } + } + + + filmGrain(tmpImage, isogr, strengr, scalegr, wi, he); + + for (int y = 0; y < he ; y++) { + for (int x = 0; x < wi; x++) { + tmp1->L[y][x] = tmpImage->g(y, x); + tmp1->a[y][x] = tmpImage->r(y, x); + tmp1->b[y][x] = tmpImage->b(y, x); + } + } + + delete tmpImage; + } + } + + Median medianTypeL = Median::TYPE_3X3_STRONG; + Median medianTypeAB = Median::TYPE_3X3_STRONG; + + if (lp.medmet == 0) { + medianTypeL = medianTypeAB = Median::TYPE_3X3_STRONG; + } else if (lp.medmet == 1) { + medianTypeL = medianTypeAB = Median::TYPE_5X5_STRONG; + } else if (lp.medmet == 2) { + medianTypeL = medianTypeAB = Median::TYPE_7X7; + } else if (lp.medmet == 3) { + medianTypeL = medianTypeAB = Median::TYPE_9X9; + } + + if (lp.blurmet == 0 && lp.blmet == 1 && lp.medmet != -1) { + float** tmL; + int wid = bfw; + int hei = bfh; + tmL = new float*[hei]; + + for (int i = 0; i < hei; ++i) { + tmL[i] = new float[wid]; + } + + if (lp.chromet == 0) { + Median_Denoise(tmp1->L, tmp1->L, bfw, bfh, medianTypeL, lp.it, multiThread, tmL); + } + + else if (lp.chromet == 1) { + Median_Denoise(tmp1->a, tmp1->a, bfw, bfh, medianTypeAB, lp.it, multiThread, tmL); + Median_Denoise(tmp1->b, tmp1->b, bfw, bfh, medianTypeAB, lp.it, multiThread, tmL); + } else if (lp.chromet == 2) { + Median_Denoise(tmp1->L, tmp1->L, bfw, bfh, medianTypeL, lp.it, multiThread, tmL); + Median_Denoise(tmp1->a, tmp1->a, bfw, bfh, medianTypeAB, lp.it, multiThread, tmL); + Median_Denoise(tmp1->b, tmp1->b, bfw, bfh, medianTypeAB, lp.it, multiThread, tmL); + } + + for (int i = 0; i < hei; ++i) { + delete[] tmL[i]; + } + + delete[] tmL; + + } else if (lp.blurmet == 1 && lp.blmet == 1) { + float** tmL; + int wid = GW; + int hei = GH; + tmL = new float*[hei]; + + for (int i = 0; i < hei; ++i) { + tmL[i] = new float[wid]; + } + + if (lp.chromet == 0) { + Median_Denoise(tmp2->L, tmp1->L, GW, GH, medianTypeL, lp.it, multiThread, tmL); + } else if (lp.chromet == 1) { + Median_Denoise(tmp2->a, tmp1->a, GW, GH, medianTypeAB, lp.it, multiThread, tmL); + Median_Denoise(tmp2->b, tmp1->b, GW, GH, medianTypeAB, lp.it, multiThread, tmL); + } else if (lp.chromet == 2) { + Median_Denoise(tmp2->L, tmp1->L, GW, GH, medianTypeL, lp.it, multiThread, tmL); + Median_Denoise(tmp2->a, tmp1->a, GW, GH, medianTypeAB, lp.it, multiThread, tmL); + Median_Denoise(tmp2->b, tmp1->b, GW, GH, medianTypeAB, lp.it, multiThread, tmL); + } + + for (int i = 0; i < hei; ++i) { + delete[] tmL[i]; + } + + delete[] tmL; + } + + if (lp.blurmet == 0 && lp.blmet == 2) { + + if (lp.guidb > 0) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend ; y++) { + for (int x = xstart; x < xend; x++) { + tmp1->L[y - ystart][x - xstart] = original->L[y][x]; + tmp1->a[y - ystart][x - xstart] = original->a[y][x]; + tmp1->b[y - ystart][x - xstart] = original->b[y][x]; + bufgb->L[y - ystart][x - xstart] = original->L[y][x]; + } + } + + Imagefloat *tmpImage = nullptr; + tmpImage = new Imagefloat(bfw, bfh); + lab2rgb(*tmp1, *tmpImage, params->icm.workingProfile); + array2D LL(bfw, bfh); + array2D rr(bfw, bfh); + array2D gg(bfw, bfh); + array2D bb(bfw, bfh); + array2D guide(bfw, bfh); + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + LL[y][x] = tmp1->L[y][x]; + float ll = LL[y][x] / 32768.f; + guide[y][x] = xlin2log(rtengine::max(ll, 0.f), 10.f); + rr[y][x] = tmpImage->r(y, x); + gg[y][x] = tmpImage->g(y, x); + bb[y][x] = tmpImage->b(y, x); + + } + } + array2D iR(bfw, bfh, rr, 0); + array2D iG(bfw, bfh, gg, 0); + array2D iB(bfw, bfh, bb, 0); + array2D iL(bfw, bfh, LL, 0); + + int r = rtengine::max(int(lp.guidb / sk), 1); + + const float epsil = 0.001f * std::pow(2, - lp.epsb); + + if (lp.chromet == 0) { + rtengine::guidedFilterLog(guide, 10.f, LL, r, epsil, multiThread); + } else if (lp.chromet == 1) { + rtengine::guidedFilterLog(guide, 10.f, rr, r, epsil, multiThread); + rtengine::guidedFilterLog(guide, 10.f, bb, r, epsil, multiThread); + } else if (lp.chromet == 2) { + rtengine::guidedFilterLog(10.f, gg, r, epsil, multiThread); + rtengine::guidedFilterLog(10.f, rr, r, epsil, multiThread); + rtengine::guidedFilterLog(10.f, bb, r, epsil, multiThread); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + rr[y][x] = intp(lp.strbl, rr[y][x] , iR[y][x]); + gg[y][x] = intp(lp.strbl, gg[y][x] , iG[y][x]); + bb[y][x] = intp(lp.strbl, bb[y][x] , iB[y][x]); + tmpImage->r(y, x) = rr[y][x]; + tmpImage->g(y, x) = gg[y][x]; + tmpImage->b(y, x) = bb[y][x]; + + } + } + + rgb2lab(*tmpImage, *tmp1, params->icm.workingProfile); + + if (lp.chromet == 0) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + LL[y][x] = intp(lp.strbl, LL[y][x] , iL[y][x]); + tmp1->L[y][x] = LL[y][x]; + } + } + } + + delete tmpImage; + } + + } else if (lp.blurmet == 1 && lp.blmet == 2) { + + if (lp.guidb > 0) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + tmp1->L[y][x] = original->L[y][x]; + tmp1->a[y][x] = original->a[y][x]; + tmp1->b[y][x] = original->b[y][x]; + tmp2->L[y][x] = original->L[y][x]; + } + } + + Imagefloat *tmpImage = nullptr; + tmpImage = new Imagefloat(GW, GH); + lab2rgb(*tmp1, *tmpImage, params->icm.workingProfile); + array2D LL(GW, GH); + array2D rr(GW, GH); + array2D gg(GW, GH); + array2D bb(GW, GH); + array2D guide(GW, GH); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + LL[y][x] = tmp1->L[y][x]; + float ll = LL[y][x] / 32768.f; + guide[y][x] = xlin2log(rtengine::max(ll, 0.f), 10.f); + rr[y][x] = tmpImage->r(y, x); + gg[y][x] = tmpImage->g(y, x); + bb[y][x] = tmpImage->b(y, x); + + } + } + + array2D iR(GW, GH, rr, 0); + array2D iG(GW, GH, gg, 0); + array2D iB(GW, GH, bb, 0); + array2D iL(GW, GH, LL, 0); + + int r = rtengine::max(int(lp.guidb / sk), 1); + + const float epsil = 0.001f * std::pow(2, - lp.epsb); + + if (lp.chromet == 0) { + rtengine::guidedFilterLog(guide, 10.f, LL, r, epsil, multiThread); + } else if (lp.chromet == 1) { + rtengine::guidedFilterLog(guide, 10.f, rr, r, epsil, multiThread); + rtengine::guidedFilterLog(guide, 10.f, bb, r, epsil, multiThread); + } else if (lp.chromet == 2) { + rtengine::guidedFilterLog(10.f, gg, r, epsil, multiThread); + rtengine::guidedFilterLog(10.f, rr, r, epsil, multiThread); + rtengine::guidedFilterLog(10.f, bb, r, epsil, multiThread); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + rr[y][x] = intp(lp.strbl, rr[y][x] , iR[y][x]); + gg[y][x] = intp(lp.strbl, gg[y][x] , iG[y][x]); + bb[y][x] = intp(lp.strbl, bb[y][x] , iB[y][x]); + tmpImage->r(y, x) = rr[y][x]; + tmpImage->g(y, x) = gg[y][x]; + tmpImage->b(y, x) = bb[y][x]; + + } + } + + rgb2lab(*tmpImage, *tmp1, params->icm.workingProfile); + + if (lp.chromet == 0) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + LL[y][x] = intp(lp.strbl, LL[y][x] , iL[y][x]); + tmp1->L[y][x] = LL[y][x]; + } + } + } + delete tmpImage; + } + } + + if (tmp1.get()) { + JaggedArray bufchro(lp.blurmet == 1 ? GW : bfw, lp.blurmet == 1 ? GH : bfh); + float minC = std::sqrt(SQR(tmp1->a[0][0]) + SQR(tmp1->b[0][0])) - std::sqrt(SQR(bufgb->a[0][0]) + SQR(bufgb->b[0][0])); + float maxC = minC; +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxC) reduction(min:minC) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufchro[ir][jr] = std::sqrt(SQR(tmp1->a[ir][jr]) + SQR(tmp1->b[ir][jr])) - std::sqrt(SQR(bufgb->a[ir][jr]) + SQR(bufgb->b[ir][jr])); + minC = rtengine::min(minC, bufchro[ir][jr]); + maxC = rtengine::max(maxC, bufchro[ir][jr]); + } + } + + float coefC = 0.01f * rtengine::max(std::fabs(minC), std::fabs(maxC)); + + if (coefC > 0.f) { + coefC = 1.f / coefC; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufchro[y][x] *= coefC; + } + } + } + + if (lp.blurmet == 0) { //blur and noise (center) +// BlurNoise_Local(tmp1.get(), originalmaskbl, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + if(lp.smasktyp != 1) { + BlurNoise_Local(tmp1.get(), originalmaskbl, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + } else { + BlurNoise_Local(tmp1.get(), original, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + } + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } else if (lp.blurmet == 1) { + // InverseBlurNoise_Local(originalmaskbl, bufchro, lp, hueref, chromaref, lumaref, original, transformed, tmp1.get(), cx, cy, sk); + if(lp.smasktyp != 1) { + InverseBlurNoise_Local(originalmaskbl, bufchro, lp, hueref, chromaref, lumaref, original, transformed, tmp1.get(), cx, cy, sk); + } else { + InverseBlurNoise_Local(original, bufchro, lp, hueref, chromaref, lumaref, original, transformed, tmp1.get(), cx, cy, sk); + } + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + } + } + } + + //local impulse + if ((lp.bilat > 0.f) && lp.denoiena) { + const int bfh = int (lp.ly + lp.lyT) + del; //bfw bfh real size of square zone + const int bfw = int (lp.lx + lp.lxL) + del; + + std::unique_ptr bufwv; + + if (call == 2) {//simpleprocess + bufwv.reset(new LabImage(bfw, bfh)); //buffer for data in zone limit + + const int begy = lp.yc - lp.lyT; + const int begx = lp.xc - lp.lxL; + const int yEn = lp.yc + lp.ly; + const int xEn = lp.xc + lp.lx; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = rtengine::max(0, begy - cy); y < rtengine::min(transformed->H, yEn - cy); y++) { + const int loy = cy + y; + + for (int x = rtengine::max(0, begx - cx); x < rtengine::min(transformed->W, xEn - cx); x++) { + const int lox = cx + x; + bufwv->L[loy - begy][lox - begx] = original->L[y][x]; + bufwv->a[loy - begy][lox - begx] = original->a[y][x]; + bufwv->b[loy - begy][lox - begx] = original->b[y][x]; + } + } + } else {//dcrop.cc + bufwv.reset(new LabImage(transformed->W, transformed->H)); + bufwv->CopyFrom(original, multiThread); + } //end dcrop + + const double threshold = lp.bilat / 20.0; + + if (bfh > 8 && bfw > 8) { + ImProcFunctions::impulse_nr(bufwv.get(), threshold); + } + + DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, *(bufwv.get()), cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + +//local denoise + + if (lp.denoiena) { + float slidL[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + float slida[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + float slidb[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + constexpr int aut = 0; + DeNoise(call, del, slidL, slida, slidb, aut, noiscfactiv, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + + if (denoiz || blurz || lp.denoiena || lp.blurena) { + delete originalmaskbl; + } + +//begin cbdl + if ((lp.mulloc[0] != 1.f || lp.mulloc[1] != 1.f || lp.mulloc[2] != 1.f || lp.mulloc[3] != 1.f || lp.mulloc[4] != 1.f || lp.mulloc[5] != 1.f || lp.clarityml != 0.f || lp.contresid != 0.f || lp.enacbMask || lp.showmaskcbmet == 2 || lp.showmaskcbmet == 3 || lp.showmaskcbmet == 4 || lp.prevdE) && lp.cbdlena) { + if (call <= 3) { //call from simpleprocess dcrop improcc + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + + if (bfw > 65 && bfh > 65) { + array2D bufsh(bfw, bfh); + JaggedArray bufchrom(bfw, bfh, true); + const std::unique_ptr loctemp(new LabImage(bfw, bfh)); + const std::unique_ptr origcbdl(new LabImage(bfw, bfh)); + std::unique_ptr bufmaskorigcb; + std::unique_ptr bufmaskblurcb; + std::unique_ptr originalmaskcb; + + if (lp.showmaskcbmet == 2 || lp.enacbMask || lp.showmaskcbmet == 3 || lp.showmaskcbmet == 4) { + bufmaskorigcb.reset(new LabImage(bfw, bfh)); + bufmaskblurcb.reset(new LabImage(bfw, bfh)); + originalmaskcb.reset(new LabImage(bfw, bfh)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + loctemp->L[y][x] = original->L[y + ystart][x + xstart]; + } + } + + int inv = 0; + bool showmaske = false; + bool enaMask = false; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmaskcbmet == 3) { + showmaske = true; + } + + if (lp.enacbMask) { + enaMask = true; + } + + if (lp.showmaskcbmet == 4) { + deltaE = true; + } + + if (lp.showmaskcbmet == 2) { + modmask = true; + } + + if (lp.showmaskcbmet == 1) { + modif = true; + } + + if (lp.showmaskcbmet == 0) { + zero = true; + } + + float chrom = lp.chromacbm;; + float rad = lp.radmacb; + float gamma = lp.gammacb; + float slope = lp.slomacb; + float blendm = lp.blendmacb; + float lap = params->locallab.spots.at(sp).lapmaskcb; + bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int lumask = params->locallab.spots.at(sp).lumask; + int shado = 0; + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + bool lmasutilicolwav = false; + float amountcd = 0.f; + float anchorcd = 50.f; + int shortcu = 0; //lp.mergemet; //params->locallab.spots.at(sp).shortc; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, loctemp.get(), bufmaskorigcb.get(), originalmaskcb.get(), original, reserved, inv, lp, + 0.f, false, + locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmaskcblocalcurve, localmaskcbutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskcbmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, loctemp.get(), transformed, bufmaskorigcb.get(), 0); + + return; + } + + constexpr float b_l = -5.f; + constexpr float t_l = 25.f; + constexpr float t_r = 120.f; + constexpr float b_r = 170.f; + constexpr double skinprot = 0.; + int choice = 0; + + if (lp.showmaskcbmet == 0 || lp.showmaskcbmet == 1 || lp.showmaskcbmet == 2 || lp.showmaskcbmet == 4 || lp.enacbMask) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufsh[y - ystart][x - xstart] = origcbdl->L[y - ystart][x - xstart] = original->L[y][x]; + loctemp->a[y - ystart][x - xstart] = origcbdl->a[y - ystart][x - xstart] = original->a[y][x]; + loctemp->b[y - ystart][x - xstart] = origcbdl->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + + if (lp.clarityml != 0.f && lp.mulloc[5] == 1.0) { //enabled last level to retrieve level 5 and residual image in case user not select level 5 + lp.mulloc[5] = 1.001f; + } + + if (lp.contresid != 0.f && lp.mulloc[5] == 1.0) { //enabled last level to retrieve level 5 and residual image in case user not select level 5 + lp.mulloc[5] = 1.001f; + } + + ImProcFunctions::cbdl_local_temp(bufsh, loctemp->L, bfw, bfh, lp.mulloc, 1.f, lp.threshol, lp.clarityml, lp.contresid, lp.blurcbdl, skinprot, false, b_l, t_l, t_r, b_r, choice, sk, multiThread); + + if (lp.softradiuscb > 0.f) { + softproc(origcbdl.get(), loctemp.get(), lp.softradiuscb, bfh, bfw, 0.0001, 0.00001, 0.1f, sk, multiThread, 1); + } + + } + + transit_shapedetect(6, loctemp.get(), originalmaskcb.get(), bufchrom, false, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + bool nochroma = (lp.showmaskcbmet == 2 || lp.showmaskcbmet == 1); + + //chroma CBDL begin here + if (lp.chromacb > 0.f && !nochroma) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufsh[ir][jr] = std::sqrt(SQR(loctemp->a[ir][jr]) + SQR(loctemp->b[ir][jr])); + } + } + + float multc[6]; + float clarich = 0.5f * lp.clarityml; + + if (clarich > 0.f && lp.mulloc[0] == 1.f) { //to enabled in case of user select only clarity + lp.mulloc[0] = 1.01f; + } + + if (lp.contresid != 0.f && lp.mulloc[0] == 1.f) { //to enabled in case of user select only clarity + lp.mulloc[0] = 1.01f; + } + + for (int lv = 0; lv < 6; lv++) { + multc[lv] = rtengine::max((lp.chromacb * (lp.mulloc[lv] - 1.f)) + 1.f, 0.01f); + } + + choice = 1; + ImProcFunctions::cbdl_local_temp(bufsh, loctemp->L, bfw, bfh, multc, rtengine::max(lp.chromacb, 1.f), lp.threshol, clarich, 0.f, lp.blurcbdl, skinprot, false, b_l, t_l, t_r, b_r, choice, sk, multiThread); + + + float minC = loctemp->L[0][0] - std::sqrt(SQR(loctemp->a[0][0]) + SQR(loctemp->b[0][0])); + float maxC = minC; +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxC) reduction(min:minC) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufchrom[ir][jr] = (loctemp->L[ir][jr] - std::sqrt(SQR(loctemp->a[ir][jr]) + SQR(loctemp->b[ir][jr]))); + minC = rtengine::min(minC, bufchrom[ir][jr]); + maxC = rtengine::max(maxC, bufchrom[ir][jr]); + } + } + + float coefC = 0.01f * rtengine::max(std::fabs(minC), std::fabs(maxC)); + + if (coefC > 0.f) { + coefC = 1.f / coefC; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufchrom[ir][jr] *= coefC; + } + } + } + + transit_shapedetect(7, loctemp.get(), nullptr, bufchrom, false, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + bufsh.free(); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + } + } + + +//end cbdl_Local + +//vibrance + + if (lp.expvib && (lp.past != 0.f || lp.satur != 0.f || lp.strvib != 0.f || lp.war != 0 || lp.strvibab != 0.f || lp.strvibh != 0.f || lp.showmaskvibmet == 2 || lp.enavibMask || lp.showmaskvibmet == 3 || lp.showmaskvibmet == 4 || lp.prevdE) && lp.vibena) { //interior ellipse renforced lightness and chroma //locallutili + if (call <= 3) { //simpleprocess, dcrop, improccoordinator + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + const int bfh = yend - ystart; + const int bfw = xend - xstart; + + if (bfw >= mSP && bfh >= mSP) { + const std::unique_ptr bufexporig(new LabImage(bfw, bfh)); + const std::unique_ptr bufexpfin(new LabImage(bfw, bfh)); + std::unique_ptr bufmaskorigvib; + std::unique_ptr bufmaskblurvib; + std::unique_ptr originalmaskvib; + + if (lp.showmaskvibmet == 2 || lp.enavibMask || lp.showmaskvibmet == 3 || lp.showmaskvibmet == 4) { + bufmaskorigvib.reset(new LabImage(bfw, bfh)); + bufmaskblurvib.reset(new LabImage(bfw, bfh)); + originalmaskvib.reset(new LabImage(bfw, bfh)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufexporig->L[y][x] = original->L[y + ystart][x + xstart]; + } + } + + int inv = 0; + bool showmaske = false; + bool enaMask = false; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmaskvibmet == 3) { + showmaske = true; + } + + if (lp.enavibMask) { + enaMask = true; + } + + if (lp.showmaskvibmet == 4) { + deltaE = true; + } + + if (lp.showmaskvibmet == 2) { + modmask = true; + } + + if (lp.showmaskvibmet == 1) { + modif = true; + } + + if (lp.showmaskvibmet == 0) { + zero = true; + } + + float chrom = lp.chromavib; + float rad = lp.radmavib; + float gamma = lp.gammavib; + float slope = lp.slomavib; + float blendm = lp.blendmavib; + float lap = params->locallab.spots.at(sp).lapmaskvib; + bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool lmasutilicolwav = false; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = 0;//lp.mergemet; //params->locallab.spots.at(sp).shortc; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + int shado = 0; + int lumask = params->locallab.spots.at(sp).lumask; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + float amountcd = 0.f; + float anchorcd = 50.f; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskorigvib.get(), originalmaskvib.get(), original, reserved, inv, lp, + 0.f, false, + locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmaskviblocalcurve, localmaskvibutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskvibmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufexporig.get(), transformed, bufmaskorigvib.get(), 0); + + return; + } + + if (lp.showmaskvibmet == 0 || lp.showmaskvibmet == 1 || lp.showmaskvibmet == 2 || lp.showmaskvibmet == 4 || lp.enavibMask) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufexporig->L[y - ystart][x - xstart] = original->L[y][x]; + bufexporig->a[y - ystart][x - xstart] = original->a[y][x]; + bufexporig->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + + VibranceParams vibranceParams; + vibranceParams.enabled = params->locallab.spots.at(sp).expvibrance; + vibranceParams.pastels = params->locallab.spots.at(sp).pastels; + vibranceParams.saturated = params->locallab.spots.at(sp).saturated; + vibranceParams.psthreshold = params->locallab.spots.at(sp).psthreshold; + vibranceParams.protectskins = params->locallab.spots.at(sp).protectskins; + vibranceParams.avoidcolorshift = params->locallab.spots.at(sp).avoidcolorshift; + vibranceParams.pastsattog = params->locallab.spots.at(sp).pastsattog; + vibranceParams.skintonescurve = params->locallab.spots.at(sp).skintonescurve; + + + bufexpfin->CopyFrom(bufexporig.get(), multiThread); + + if (lp.strvibh != 0.f) { + struct grad_params gph; + calclocalGradientParams(lp, gph, ystart, xstart, bfw, bfh, 9); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + double factor = 1.0; + factor = ImProcFunctions::calcGradientFactor(gph, jr, ir); + float aa = bufexpfin->a[ir][jr]; + float bb = bufexpfin->b[ir][jr]; + float chrm = std::sqrt(SQR(aa) + SQR(bb)); + float HH = xatan2f(bb, aa); + + float newhr = 0.f; + float cor = 0.f; + + if (factor < 1.f) { + cor = - 2.5f * (1.f - factor); + } else if (factor > 1.f) { + cor = 0.03f * (factor - 1.f); + } + + newhr = HH + cor; + + if (newhr > rtengine::RT_PI_F) { + newhr -= 2 * rtengine::RT_PI_F; + } else if (newhr < -rtengine::RT_PI_F) { + newhr += 2 * rtengine::RT_PI_F; + } + + float2 sincosval = xsincosf(newhr); + bufexpfin->a[ir][jr] = clipC(chrm * sincosval.y); + bufexpfin->b[ir][jr] = clipC(chrm * sincosval.x); + } + } + + if (lp.strvib != 0.f) { + struct grad_params gp; + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, 7); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + double factor = 1.0; + factor = ImProcFunctions::calcGradientFactor(gp, jr, ir); + bufexpfin->L[ir][jr] *= factor; + } + } + + if (lp.strvibab != 0.f) { + struct grad_params gpab; + calclocalGradientParams(lp, gpab, ystart, xstart, bfw, bfh, 8); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + double factor = 1.0; + factor = ImProcFunctions::calcGradientFactor(gpab, jr, ir); + bufexpfin->a[ir][jr] *= factor; + bufexpfin->b[ir][jr] *= factor; + } + } + + ImProcFunctions::vibrance(bufexpfin.get(), vibranceParams, params->toneCurve.hrenabled, params->icm.workingProfile); + + if (params->locallab.spots.at(sp).warm != 0) { + ImProcFunctions::ciecamloc_02float(sp, bufexpfin.get()); + } + + + transit_shapedetect2(call, 2, bufexporig.get(), bufexpfin.get(), originalmaskvib.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + + } + + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + } + + +//Tone mapping + + if ((lp.strengt != 0.f || lp.showmasktmmet == 2 || lp.enatmMask || lp.showmasktmmet == 3 || lp.showmasktmmet == 4 || lp.prevdE) && lp.tonemapena && !params->epd.enabled) { + if (call <= 3) { //simpleprocess dcrop improcc + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + const int bfh = yend - ystart; + const int bfw = xend - xstart; + + if (bfw >= mSP && bfh >= mSP) { + array2D buflight(bfw, bfh); + JaggedArray bufchro(bfw, bfh); + std::unique_ptr bufgb(new LabImage(bfw, bfh)); + const std::unique_ptr tmp1(new LabImage(bfw, bfh)); + const std::unique_ptr bufgbm(new LabImage(bfw, bfh)); + const std::unique_ptr tmp1m(new LabImage(bfw, bfh)); + std::unique_ptr bufmaskorigtm; + std::unique_ptr bufmaskblurtm; + std::unique_ptr originalmasktm; + + // if (lp.showmasktmmet == 0 || lp.showmasktmmet == 2 || lp.enatmMask || lp.showmasktmmet == 3 || lp.showmasktmmet == 4) { + if (lp.showmasktmmet == 2 || lp.enatmMask || lp.showmasktmmet == 3 || lp.showmasktmmet == 4) { + bufmaskorigtm.reset(new LabImage(bfw, bfh)); + bufmaskblurtm.reset(new LabImage(bfw, bfh)); + originalmasktm.reset(new LabImage(bfw, bfh)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufgb->L[y - ystart][x - xstart] = original->L[y][x]; + bufgb->a[y - ystart][x - xstart] = original->a[y][x]; + bufgb->b[y - ystart][x - xstart] = original->b[y][x]; + bufgbm->L[y - ystart][x - xstart] = original->L[y][x]; + bufgbm->a[y - ystart][x - xstart] = original->a[y][x]; + bufgbm->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + + int inv = 0; + bool showmaske = false; + bool enaMask = false; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmasktmmet == 3) { + showmaske = true; + } + + if (lp.enatmMask) { + enaMask = true; + } + + if (lp.showmasktmmet == 4) { + deltaE = true; + } + + if (lp.showmasktmmet == 2) { + modmask = true; + } + + if (lp.showmasktmmet == 1) { + modif = true; + } + + if (lp.showmasktmmet == 0) { + zero = true; + } + + float chrom = lp.chromatm;; + float rad = lp.radmatm; + float gamma = lp.gammatm; + float slope = lp.slomatm; + float blendm = lp.blendmatm; + float lap = params->locallab.spots.at(sp).lapmasktm; + bool pde = params->locallab.spots.at(sp).laplac; + int lumask = params->locallab.spots.at(sp).lumask; + + if (!params->locallab.spots.at(sp).enatmMaskaft) { + LocwavCurve dummy; + bool lmasutilicolwav = false; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = 0; //lp.mergemet;// params->locallab.spots.at(sp).shortc; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + int shado = 0; + float amountcd = 0.f; + float anchorcd = 50.f; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufgbm.get(), bufmaskorigtm.get(), originalmasktm.get(), original, reserved, inv, lp, + 0.f, false, + locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmasktmlocalcurve, localmasktmutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmasktmmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufgbm.get(), transformed, bufmaskorigtm.get(), 0); + + return; + } + } + + if (lp.showmasktmmet == 0 || lp.showmasktmmet == 1 || lp.showmasktmmet == 2 || lp.showmasktmmet == 4 || lp.showmasktmmet == 3 || lp.enatmMask) { + constexpr int itera = 0; + ImProcFunctions::EPDToneMaplocal(sp, bufgb.get(), tmp1.get(), itera, sk);//iterate to 0 calculate with edgstopping, improve result, call=1 dcrop we can put iterate to 5 + + tmp1m->CopyFrom(tmp1.get(), multiThread); //save current result + bool enatmMasktmap = params->locallab.spots.at(sp).enatmMaskaft; + + if (enatmMasktmap) { + //calculate new values for original, originalmasktm, bufmaskorigtm...in function of tmp1 + LocwavCurve dummy; + bool lmasutilicolwav = false; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = 0;//lp.mergemet; //params->locallab.spots.at(sp).shortc; + int lumask = params->locallab.spots.at(sp).lumask; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + int shado = 0; + float amountcd = 0.f; + float anchorcd = 50.f; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, tmp1.get(), bufmaskorigtm.get(), originalmasktm.get(), original, reserved, inv, lp, + 0.f, false, + locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmasktmlocalcurve, localmasktmutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmasktmmet == 3) {//display mask + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, tmp1.get(), transformed, bufmaskorigtm.get(), 0); + + return; + } + + } + + tmp1->CopyFrom(tmp1m.get(), multiThread); //restore current result + + + float minL = tmp1->L[0][0] - bufgb->L[0][0]; + float maxL = minL; + float minC = std::sqrt(SQR(tmp1->a[0][0]) + SQR(tmp1->b[0][0])) - std::sqrt(SQR(bufgb->a[0][0]) + SQR(bufgb->b[0][0])); + float maxC = minC; + +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxL) reduction(min:minL) reduction(max:maxC) reduction(min:minC) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + buflight[ir][jr] = tmp1->L[ir][jr] - bufgb->L[ir][jr]; + minL = rtengine::min(minL, buflight[ir][jr]); + maxL = rtengine::max(maxL, buflight[ir][jr]); + bufchro[ir][jr] = std::sqrt(SQR(tmp1->a[ir][jr]) + SQR(tmp1->b[ir][jr])) - std::sqrt(SQR(bufgb->a[ir][jr]) + SQR(bufgb->b[ir][jr])); + minC = rtengine::min(minC, bufchro[ir][jr]); + maxC = rtengine::max(maxC, bufchro[ir][jr]); + } + } + + float coef = 0.01f * rtengine::max(std::fabs(minL), std::fabs(maxL)); + float coefC = 0.01f * rtengine::max(std::fabs(minC), std::fabs(maxC)); + + if (coef == 0.f) { + coef = 1.f; + } else { + coef = 1.f / coef; + } + + if (coefC == 0.f) { + coefC = 1.f; + } else { + coefC = 1.f / coefC; + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + buflight[y][x] *= coef; + bufchro[y][x] *= coefC; + } + } + + // transit_shapedetect_retinex(call, 4, bufgb.get(),bufmaskorigtm.get(), originalmasktm.get(), buflight, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + transit_shapedetect2(call, 8, bufgb.get(), tmp1.get(), originalmasktm.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + // transit_shapedetect(8, tmp1.get(), originalmasktm.get(), bufchro, false, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + bufgb.reset(); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + } + } + +//end TM + + +//shadow highlight + bool tonequ = false; + + if (lp.mullocsh[0] != 0 || lp.mullocsh[1] != 0 || lp.mullocsh[2] != 0 || lp.mullocsh[3] != 0 || lp.mullocsh[4] != 0) { + tonequ = true; + } + + bool tonecurv = false; + + if (params->locallab.spots.at(sp).gamSH != 2.4 || params->locallab.spots.at(sp).sloSH != 12.92) { + tonecurv = true; + } + + if (! lp.invsh && (lp.highlihs > 0.f || lp.shadowhs > 0.f || tonequ || tonecurv || lp.strSH != 0.f || lp.showmaskSHmet == 2 || lp.enaSHMask || lp.showmaskSHmet == 3 || lp.showmaskSHmet == 4 || lp.prevdE) && call < 3 && lp.hsena) { + const int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + const int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + const int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + const int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + const int bfh = yend - ystart; + const int bfw = xend - xstart; + + + if (bfw >= mSP && bfh >= mSP) { + + const std::unique_ptr bufexporig(new LabImage(bfw, bfh)); + const std::unique_ptr bufexpfin(new LabImage(bfw, bfh)); + std::unique_ptr bufmaskorigSH; + std::unique_ptr bufmaskblurSH; + std::unique_ptr originalmaskSH; + + if (lp.showmaskSHmet == 2 || lp.enaSHMask || lp.showmaskSHmet == 3 || lp.showmaskSHmet == 4) { + bufmaskorigSH.reset(new LabImage(bfw, bfh)); + bufmaskblurSH.reset(new LabImage(bfw, bfh)); + originalmaskSH.reset(new LabImage(bfw, bfh)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufexporig->L[y][x] = original->L[y + ystart][x + xstart]; + } + } + + int inv = 0; + bool showmaske = false; + bool enaMask = false; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmaskSHmet == 3) { + showmaske = true; + } + + if (lp.enaSHMask) { + enaMask = true; + } + + if (lp.showmaskSHmet == 4) { + deltaE = true; + } + + if (lp.showmaskSHmet == 2) { + modmask = true; + } + + if (lp.showmaskSHmet == 1) { + modif = true; + } + + if (lp.showmaskSHmet == 0) { + zero = true; + } + + float chrom = lp.chromaSH; + float rad = lp.radmaSH; + float gamma = lp.gammaSH; + float slope = lp.slomaSH; + float blendm = lp.blendmaSH; + float lap = params->locallab.spots.at(sp).lapmaskSH; + bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool lmasutilicolwav = false; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = 0;//lp.mergemet; //params->locallab.spots.at(sp).shortc; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + int shado = 0; + float amountcd = params->locallab.spots.at(sp).fatamountSH; + float anchorcd = params->locallab.spots.at(sp).fatanchorSH; + int lumask = params->locallab.spots.at(sp).lumask; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskorigSH.get(), originalmaskSH.get(), original, reserved, inv, lp, + 0.f, false, + locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmaskSHlocalcurve, localmaskSHutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskSHmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufexporig.get(), transformed, bufmaskorigSH.get(), 0); + + return; + } + + if (lp.showmaskSHmet == 0 || lp.showmaskSHmet == 1 || lp.showmaskSHmet == 2 || lp.showmaskSHmet == 4 || lp.enaSHMask) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufexporig->L[y][x] = original->L[y + ystart][x + xstart]; + bufexporig->a[y][x] = original->a[y + ystart][x + xstart]; + bufexporig->b[y][x] = original->b[y + ystart][x + xstart]; + bufexpfin->L[y][x] = original->L[y + ystart][x + xstart]; + bufexpfin->a[y][x] = original->a[y + ystart][x + xstart]; + bufexpfin->b[y][x] = original->b[y + ystart][x + xstart]; + } + } + + if (lp.shmeth == 0) { + ImProcFunctions::shadowsHighlights(bufexpfin.get(), lp.hsena, 1, lp.highlihs, lp.shadowhs, lp.radiushs, sk, lp.hltonalhs, lp.shtonalhs); + } + +//gradient + struct grad_params gp; + + if (lp.strSH != 0.f) { + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, 2); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + double factor = 1.0; + factor = ImProcFunctions::calcGradientFactor(gp, jr, ir); + bufexpfin->L[ir][jr] *= factor; + } + } + + if (lp.shmeth == 1) { + double scal = (double)(sk); + Imagefloat *tmpImage = nullptr; + tmpImage = new Imagefloat(bfw, bfh); + lab2rgb(*bufexpfin, *tmpImage, params->icm.workingProfile); + + if (tonecurv) { //Tone response curve : does nothing if gamma=2.4 and slope=12.92 ==> gamma sRGB + float gamtone = params->locallab.spots.at(sp).gamSH; + float slotone = params->locallab.spots.at(sp).sloSH; + cmsHTRANSFORM dummy = nullptr; + workingtrc(tmpImage, tmpImage, bfw, bfh, -5, params->icm.workingProfile, 2.4, 12.92310, dummy, true, false, false); + workingtrc(tmpImage, tmpImage, bfw, bfh, 5, params->icm.workingProfile, gamtone, slotone, dummy, false, true, true); + } + + if (tonequ) { + tmpImage->normalizeFloatTo1(); + array2D Rtemp(bfw, bfh, tmpImage->r.ptrs, ARRAY2D_BYREFERENCE); + array2D Gtemp(bfw, bfh, tmpImage->g.ptrs, ARRAY2D_BYREFERENCE); + array2D Btemp(bfw, bfh, tmpImage->b.ptrs, ARRAY2D_BYREFERENCE); + tone_eq(Rtemp, Gtemp, Btemp, lp, params->icm.workingProfile, scal, multiThread); + tmpImage->normalizeFloatTo65535(); + } + + rgb2lab(*tmpImage, *bufexpfin, params->icm.workingProfile); + + delete tmpImage; + } + } + + transit_shapedetect2(call, 9, bufexporig.get(), bufexpfin.get(), originalmaskSH.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } else if (lp.invsh && (lp.highlihs > 0.f || lp.shadowhs > 0.f || tonequ || tonecurv || lp.showmaskSHmetinv == 1 || lp.enaSHMaskinv) && call < 3 && lp.hsena) { + std::unique_ptr bufmaskblurcol; + std::unique_ptr originalmaskSH; + const std::unique_ptr bufcolorig(new LabImage(GW, GH)); + + if (lp.enaSHMaskinv || lp.showmaskSHmetinv == 1) { + bufmaskblurcol.reset(new LabImage(GW, GH, true)); + originalmaskSH.reset(new LabImage(GW, GH)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + bufcolorig->L[y][x] = original->L[y][x]; + } + } + + int inv = 1; + bool showmaske = false; + bool enaMask = false; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmaskSHmetinv == 1) { + showmaske = true; + } + + if (lp.enaSHMaskinv) { + enaMask = true; + } + + if (lp.showmaskSHmetinv == 0) { + zero = true; + } + + float chrom = lp.chromaSH; + float rad = lp.radmaSH; + float gamma = lp.gammaSH; + float slope = lp.slomaSH; + float blendm = lp.blendmaSH; + float lap = params->locallab.spots.at(sp).lapmaskSH; + bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool lmasutilicolwav = false; + // bool delt = params->locallab.spots.at(sp).deltae; + bool delt = false; + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = params->locallab.spots.at(sp).shortc; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + int shado = 0; + float amountcd = params->locallab.spots.at(sp).fatamountSH; + float anchorcd = params->locallab.spots.at(sp).fatanchorSH; + int lumask = params->locallab.spots.at(sp).lumask; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskSH.get(), original, reserved, inv, lp, + 0.f, false, + locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmaskSHlocalcurve, localmaskSHutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + + if (lp.showmaskSHmetinv == 1) { + showmask(lumask, lp, 0, 0, cx, cy, GW, GH, bufcolorig.get(), transformed, bufmaskblurcol.get(), inv); + + return; + } + + float adjustr = 2.f; + InverseColorLight_Local(tonequ, tonecurv, sp, 2, lp, originalmaskSH.get(), lightCurveloc, hltonecurveloc, shtonecurveloc, tonecurveloc, exlocalcurve, cclocalcurve, adjustr, localcutili, lllocalcurve, locallutili, original, transformed, cx, cy, hueref, chromaref, lumaref, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + +// soft light and retinex_pde + if (lp.strng > 0.f && call <= 3 && lp.sfena) { + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + //variable for fast FFTW + int bfhr = bfh; + int bfwr = bfw; + + if (bfw >= mSP && bfh >= mSP) { + + if (lp.softmet == 1) { + optfft(N_fftwsize, bfh, bfw, bfhr, bfwr, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + const std::unique_ptr bufexporig(new LabImage(bfw, bfh)); + const std::unique_ptr bufexpfin(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufexporig->L[y - ystart][x - xstart] = original->L[y][x]; + bufexporig->a[y - ystart][x - xstart] = original->a[y][x]; + bufexporig->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + + bufexpfin->CopyFrom(bufexporig.get(), multiThread); + SoftLightParams softLightParams; + softLightParams.enabled = true; + softLightParams.strength = lp.strng; + + if (lp.softmet == 0) { + ImProcFunctions::softLight(bufexpfin.get(), softLightParams); + } else if (lp.softmet == 1) { + + const std::unique_ptr datain(new float[bfwr * bfhr]); + const std::unique_ptr dataout(new float[bfwr * bfhr]); + const std::unique_ptr dE(new float[bfwr * bfhr]); + + deltaEforLaplace(dE.get(), lp.lap, bfwr, bfhr, bufexpfin.get(), hueref, chromaref, lumaref); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + datain[y * bfwr + x] = bufexpfin->L[y][x]; + } + } + + const int showorig = lp.showmasksoftmet >= 5 ? 0 : lp.showmasksoftmet; + MyMutex::MyLock lock(*fftwMutex); + ImProcFunctions::retinex_pde(datain.get(), dataout.get(), bfwr, bfhr, 8.f * lp.strng, 1.f, dE.get(), showorig, 1, 1); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + bufexpfin->L[y][x] = dataout[y * bfwr + x]; + } + } + } + + transit_shapedetect2(call, 3, bufexporig.get(), bufexpfin.get(), nullptr, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + + //local contrast + bool wavcurve = false; + bool wavcurvelev = false; + bool wavcurvecon = false; + bool wavcurvecomp = false; + bool wavcurvecompre = false; + + if (lp.locmet == 1) { + if (locwavCurve && locwavutili) { + for (int i = 0; i < 500; i++) { + if (locwavCurve[i] != 0.5) { + wavcurve = true; + break; + } + } + } + if (loclevwavCurve && loclevwavutili) { + for (int i = 0; i < 500; i++) { + if (loclevwavCurve[i] != 0.) { + wavcurvelev = true; + break; + } + } + } + if (locconwavCurve && locconwavutili) { + for (int i = 0; i < 500; i++) { + if (locconwavCurve[i] != 0.5) { + wavcurvecon = true; + break; + } + } + } + if (loccompwavCurve && loccompwavutili) { + for (int i = 0; i < 500; i++) { + if (loccompwavCurve[i] != 0.) { + wavcurvecomp = true; + break; + } + } + } + if (loccomprewavCurve && loccomprewavutili) { + for (int i = 0; i < 500; i++) { + if (loccomprewavCurve[i] != 0.75) { + wavcurvecompre = true; + break; + } + } + } + } + + if ((lp.lcamount > 0.f || wavcurve || lp.showmasklcmet == 2 || lp.enalcMask || lp.showmasklcmet == 3 || lp.showmasklcmet == 4 || lp.prevdE || lp.strwav != 0.f || wavcurvelev || wavcurvecon || wavcurvecomp || wavcurvecompre || lp.edgwena || params->locallab.spots.at(sp).residblur > 0.f || params->locallab.spots.at(sp).levelblur > 0.f || params->locallab.spots.at(sp).residcont != 0.f || params->locallab.spots.at(sp).clarilres != 0.f || params->locallab.spots.at(sp).claricres != 0.f) && call < 3 && lp.lcena) { + + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + int bfhr = bfh; + int bfwr = bfw; + + if (bfw >= mSPwav && bfh >= mSPwav) {//avoid too small spot for wavelet + if (lp.ftwlc) { + optfft(N_fftwsize, bfh, bfw, bfhr, bfwr, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + std::unique_ptr bufmaskblurlc; + std::unique_ptr originalmasklc; + std::unique_ptr bufmaskoriglc; + + if (lp.showmasklcmet == 2 || lp.enalcMask || lp.showmasklcmet == 3 || lp.showmasklcmet == 4) { + bufmaskblurlc.reset(new LabImage(bfw, bfh)); + originalmasklc.reset(new LabImage(bfw, bfh)); + bufmaskoriglc.reset(new LabImage(bfw, bfh)); + } + + array2D buflight(bfw, bfh); + JaggedArray bufchro(bfw, bfh); + const std::unique_ptr bufgb(new LabImage(bfw, bfh)); + std::unique_ptr tmp1(new LabImage(bfw, bfh)); + const std::unique_ptr tmpresid(new LabImage(bfw, bfh)); + const std::unique_ptr tmpres(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufgb->L[y - ystart][x - xstart] = original->L[y][x]; + bufgb->a[y - ystart][x - xstart] = original->a[y][x]; + bufgb->b[y - ystart][x - xstart] = original->b[y][x]; + tmp1->L[y - ystart][x - xstart] = original->L[y][x]; + tmp1->a[y - ystart][x - xstart] = original->a[y][x]; + tmp1->b[y - ystart][x - xstart] = original->b[y][x]; + tmpresid->L[y - ystart][x - xstart] = original->L[y][x]; + tmpresid->a[y - ystart][x - xstart] = original->a[y][x]; + tmpresid->b[y - ystart][x - xstart] = original->b[y][x]; + tmpres->L[y - ystart][x - xstart] = original->L[y][x]; + tmpres->a[y - ystart][x - xstart] = original->a[y][x]; + tmpres->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufgb->L[y][x] = original->L[y + ystart][x + xstart]; + } + } + + int inv = 0; + bool showmaske = false; + bool enaMask = false; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmasklcmet == 3) { + showmaske = true; + } + + if (lp.enalcMask) { + enaMask = true; + } + + if (lp.showmasklcmet == 4) { + deltaE = true; + } + + if (lp.showmasklcmet == 2) { + modmask = true; + } + + if (lp.showmasklcmet == 1) { + modif = true; + } + + if (lp.showmasklcmet == 0) { + zero = true; + } + + + float chrom = lp.chromalc; + float rad = lp.radmalc; + float blendm = lp.blendmalc; + float gamma = 1.f; + float slope = 0.f; + float lap = 0.f; //params->locallab.spots.at(sp).lapmaskexp; + bool pde = false; //params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool lmasutilicolwav = false; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int shado = 0; + int shortcu = 0;//lp.mergemet; //params->locallab.spots.at(sp).shortc; + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + float amountcd = 0.f; + float anchorcd = 50.f; + int lumask = params->locallab.spots.at(sp).lumask; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufgb.get(), bufmaskoriglc.get(), originalmasklc.get(), original, reserved, inv, lp, + 0.f, false, + locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmasklclocalcurve, localmasklcutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmasklcmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufgb.get(), transformed, bufmaskoriglc.get(), 0); + + return; + } + + if (lp.showmasklcmet == 0 || lp.showmasklcmet == 1 || lp.showmasklcmet == 2 || lp.showmasklcmet == 4 || lp.enalcMask) { + + if (lp.locmet == 0) { + LocalContrastParams localContrastParams; + LocallabParams locallabparams; + localContrastParams.enabled = true; + localContrastParams.radius = params->locallab.spots.at(sp).lcradius; + localContrastParams.amount = params->locallab.spots.at(sp).lcamount; + localContrastParams.darkness = params->locallab.spots.at(sp).lcdarkness; + localContrastParams.lightness = params->locallab.spots.at(sp).lightness; + bool fftwlc = false; + + if (!lp.ftwlc) { // || (lp.ftwlc && call != 2)) { + ImProcFunctions::localContrast(tmp1.get(), tmp1->L, localContrastParams, fftwlc, sk); + } else { + const std::unique_ptr tmpfftw(new LabImage(bfwr, bfhr)); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + tmpfftw->L[y][x] = tmp1->L[y][x]; + tmpfftw->a[y][x] = tmp1->a[y][x]; + tmpfftw->b[y][x] = tmp1->b[y][x]; + } + } + + fftwlc = true; + ImProcFunctions::localContrast(tmpfftw.get(), tmpfftw->L, localContrastParams, fftwlc, sk); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + tmp1->L[y][x] = tmpfftw->L[y][x]; + tmp1->a[y][x] = tmpfftw->a[y][x]; + tmp1->b[y][x] = tmpfftw->b[y][x]; + } + } + + } + } else if (lp.locmet == 1) { //wavelet && sk ==1 + int wavelet_level = 1 + params->locallab.spots.at(sp).csthreshold.getBottomRight();//retrieve with +1 maximum wavelet_level + float mL = params->locallab.spots.at(sp).clarilres / 100.f; + float mC = params->locallab.spots.at(sp).claricres / 100.f; + float softr = params->locallab.spots.at(sp).clarisoft; + float mL0 = 0.f; + float mC0 = 0.f; +#ifdef _OPENMP + const int numThreads = omp_get_max_threads(); +#else + const int numThreads = 1; + +#endif + // adap maximum level wavelet to size of RT-spot + int minwin = rtengine::min(bfw, bfh); + int maxlevelspot = 10;//maximum possible + + // adap maximum level wavelet to size of crop + while ((1 << maxlevelspot) >= (minwin * sk) && maxlevelspot > 1) { + --maxlevelspot ; + } + + // printf("minwin=%i maxlevelavant=%i maxlespot=%i\n", minwin, wavelet_level, maxlevelspot); + + wavelet_level = rtengine::min(wavelet_level, maxlevelspot); + // printf("maxlevel=%i\n", wavelet_level); + bool exec = false; + bool origlc = params->locallab.spots.at(sp).origlc; + + if (origlc) {//merge only with original + clarimerge(lp, mL, mC, exec, tmpresid.get(), wavelet_level, sk, numThreads); + } + + int maxlvl = wavelet_level; + const float contrast = params->locallab.spots.at(sp).residcont; + int level_bl = params->locallab.spots.at(sp).csthreshold.getBottomLeft(); + int level_hl = params->locallab.spots.at(sp).csthreshold.getTopLeft(); + int level_br = params->locallab.spots.at(sp).csthreshold.getBottomRight(); + int level_hr = params->locallab.spots.at(sp).csthreshold.getTopRight(); + const float radblur = (params->locallab.spots.at(sp).residblur) / sk; + const bool blurlc = params->locallab.spots.at(sp).blurlc; + const float radlevblur = (params->locallab.spots.at(sp).levelblur) / sk; + const float sigma = params->locallab.spots.at(sp).sigma; + const float offs = params->locallab.spots.at(sp).offset; + const float sigmadc = params->locallab.spots.at(sp).sigmadc; + const float deltad = params->locallab.spots.at(sp).deltad; + // const float fatres = params->locallab.spots.at(sp).fatres; + const float chrol = params->locallab.spots.at(sp).chromalev; + const float chrobl = params->locallab.spots.at(sp).chromablu; + const bool blurena = params->locallab.spots.at(sp).wavblur; + const bool levelena = params->locallab.spots.at(sp).wavcont; + const bool comprena = params->locallab.spots.at(sp).wavcomp; + const bool compreena = params->locallab.spots.at(sp).wavcompre; + const float compress = params->locallab.spots.at(sp).residcomp; + const float thres = params->locallab.spots.at(sp).threswav; + + wavcontrast4(lp, tmp1->L, tmp1->a, tmp1->b, contrast, radblur, radlevblur, tmp1->W, tmp1->H, level_bl, level_hl, level_br, level_hr, sk, numThreads, locwavCurve, locwavutili, wavcurve, loclevwavCurve, loclevwavutili, wavcurvelev, locconwavCurve, locconwavutili, wavcurvecon, loccompwavCurve, loccompwavutili, wavcurvecomp, loccomprewavCurve, loccomprewavutili, wavcurvecompre, locedgwavCurve, locedgwavutili, sigma, offs, maxlvl, sigmadc, deltad, chrol, chrobl, blurlc, blurena, levelena, comprena, compreena, compress, thres); + + const float satur = params->locallab.spots.at(sp).residchro; + + + if (satur != 0.f || radblur > 0.f) {//blur residual a and satur + + wavelet_decomposition *wdspota = new wavelet_decomposition(tmp1->a[0], tmp1->W, tmp1->H, wavelet_level, 1, sk, numThreads, lp.daubLen); + + if (wdspota->memory_allocation_failed()) { + return; + } + + float *wav_ab0a = wdspota->get_coeff0(); + // int maxlvla = wdspota->maxlevel(); + int W_La = wdspota->level_W(0); + int H_La = wdspota->level_H(0); + + if (radblur > 0.f && !blurlc && blurena) { + array2D bufa(W_La, H_La); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < H_La; y++) { + for (int x = 0; x < W_La; x++) { + bufa[y][x] = wav_ab0a [y * W_La + x]; + } + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufa, bufa, W_La, H_La, radblur); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < H_La; y++) { + for (int x = 0; x < W_La; x++) { + wav_ab0a[y * W_La + x] = bufa[y][x]; + } + } + + } + + if (satur != 0.f) { +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < W_La * H_La; i++) { + wav_ab0a[i] *= (1.f + sin(rtengine::RT_PI * (satur / 200.f)));//more progressive than linear + wav_ab0a[i] = clipC(wav_ab0a[i]); + } + } + + wdspota->reconstruct(tmp1->a[0], 1.f); + delete wdspota; + + wavelet_decomposition *wdspotb = new wavelet_decomposition(tmp1->b[0], tmp1->W, tmp1->H, wavelet_level, 1, sk, numThreads, lp.daubLen); + + if (wdspotb->memory_allocation_failed()) { + return; + } + + float *wav_ab0b = wdspotb->get_coeff0(); + int W_Lb = wdspotb->level_W(0); + int H_Lb = wdspotb->level_H(0); + + if (radblur > 0.f && !blurlc && blurena) { + array2D bufb(W_Lb, H_Lb); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < H_Lb; y++) { + for (int x = 0; x < W_Lb; x++) { + bufb[y][x] = wav_ab0b [y * W_Lb + x]; + } + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufb, bufb, W_Lb, H_Lb, radblur); + } + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < H_Lb; y++) { + for (int x = 0; x < W_Lb; x++) { + wav_ab0b[y * W_Lb + x] = bufb[y][x]; + } + } + + } + + if (satur != 0.f) { + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int i = 0; i < W_Lb * H_Lb; i++) { + wav_ab0b[i] *= (1.f + sin(rtengine::RT_PI * (satur / 200.f))); + wav_ab0b[i] = clipC(wav_ab0b[i]); + } + } + + wdspotb->reconstruct(tmp1->b[0], 1.f); + delete wdspotb; + } + + if (!origlc) {//merge all files + exec = false; + //copy previous calculation in merge possibilities +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + tmpresid->L[y][x] = tmp1->L[y][x]; + tmpresid->a[y][x] = tmp1->a[y][x]; + tmpresid->b[y][x] = tmp1->b[y][x]; + } + } + clarimerge(lp, mL, mC, exec, tmpresid.get(), wavelet_level, sk, numThreads); + } + + float thr = 0.001f; + int flag = 0; + + if (maxlvl <= 4) { + mL0 = 0.f; + mC0 = 0.f; + mL = -1.5f * mL;//increase only for sharpen + mC = -mC; + thr = 1.f; + flag = 0; + + } else { + mL0 = mL; + mC0 = mC; + thr = 1.f; + flag = 1; + } + + if (exec || compreena || comprena || levelena || blurena || lp.wavgradl || locwavCurve || lp.edgwena) { + LabImage *mergfile = tmp1.get(); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int x = 0; x < bfh; x++) + for (int y = 0; y < bfw; y++) { + tmp1->L[x][y] = clipLoc((1.f + mL0) * mergfile->L[x][y] - mL * tmpresid->L[x][y]); + tmp1->a[x][y] = clipC((1.f + mC0) * mergfile->a[x][y] - mC * tmpresid->a[x][y]); + tmp1->b[x][y] = clipC((1.f + mC0) * mergfile->b[x][y] - mC * tmpresid->b[x][y]); + } + + if (softr != 0.f && (compreena || locwavCurve || comprena || blurena || levelena || lp.wavgradl || lp.edgwena || std::fabs(mL) > 0.001f)) { + softproc(tmpres.get(), tmp1.get(), softr, bfh, bfw, 0.0001, 0.00001, thr, sk, multiThread, flag); + } + } + } + + + transit_shapedetect2(call, 10, bufgb.get(), tmp1.get(), originalmasklc.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + tmp1.reset(); + } + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + + if (!lp.invshar && lp.shrad > 0.42 && call < 3 && lp.sharpena && sk == 1) { //interior ellipse for sharpening, call = 1 and 2 only with Dcrop and simpleprocess + int bfh = call == 2 ? int (lp.ly + lp.lyT) + del : original->H; //bfw bfh real size of square zone + int bfw = call == 2 ? int (lp.lx + lp.lxL) + del : original->W; + JaggedArray loctemp(bfw, bfh); + + if (call == 2) { //call from simpleprocess + // printf("bfw=%i bfh=%i\n", bfw, bfh); + + if (bfw < mSPsharp || bfh < mSPsharp) { + printf("too small RT-spot - minimum size 39 * 39\n"); + return; + } + + JaggedArray bufsh(bfw, bfh, true); + JaggedArray hbuffer(bfw, bfh); + int begy = lp.yc - lp.lyT; + int begx = lp.xc - lp.lxL; + int yEn = lp.yc + lp.ly; + int xEn = lp.xc + lp.lx; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H ; y++) { + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + int loy = cy + y; + + if (lox >= begx && lox < xEn && loy >= begy && loy < yEn) { + bufsh[loy - begy][lox - begx] = original->L[y][x]; + } + } + } + + //sharpen only square area instead of all image + ImProcFunctions::deconvsharpeningloc(bufsh, hbuffer, bfw, bfh, loctemp, params->locallab.spots.at(sp).shardamping, (double)params->locallab.spots.at(sp).sharradius, params->locallab.spots.at(sp).shariter, params->locallab.spots.at(sp).sharamount, params->locallab.spots.at(sp).sharcontrast, (double)params->locallab.spots.at(sp).sharblur, 1); + } else { //call from dcrop.cc + ImProcFunctions::deconvsharpeningloc(original->L, shbuffer, bfw, bfh, loctemp, params->locallab.spots.at(sp).shardamping, (double)params->locallab.spots.at(sp).sharradius, params->locallab.spots.at(sp).shariter, params->locallab.spots.at(sp).sharamount, params->locallab.spots.at(sp).sharcontrast, (double)params->locallab.spots.at(sp).sharblur, sk); + } + + //sharpen ellipse and transition + Sharp_Local(call, loctemp, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + + } else if (lp.invshar && lp.shrad > 0.42 && call < 3 && lp.sharpena && sk == 1) { + int GW = original->W; + int GH = original->H; + JaggedArray loctemp(GW, GH); + + ImProcFunctions::deconvsharpeningloc(original->L, shbuffer, GW, GH, loctemp, params->locallab.spots.at(sp).shardamping, (double)params->locallab.spots.at(sp).sharradius, params->locallab.spots.at(sp).shariter, params->locallab.spots.at(sp).sharamount, params->locallab.spots.at(sp).sharcontrast, (double)params->locallab.spots.at(sp).sharblur, sk); + + InverseSharp_Local(loctemp, hueref, lumaref, chromaref, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + + if (lp.dehaze != 0 && lp.retiena) { + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + + if (bfh >= mSP && bfw >= mSP) { + const std::unique_ptr bufexporig(new LabImage(bfw, bfh)); //buffer for data in zone limit + const std::unique_ptr bufexpfin(new LabImage(bfw, bfh)); //buffer for data in zone limit + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufexporig->L[y - ystart][x - xstart] = original->L[y][x]; + bufexporig->a[y - ystart][x - xstart] = original->a[y][x]; + bufexporig->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + + bufexpfin->CopyFrom(bufexporig.get(), multiThread); + //calc dehaze + const std::unique_ptr tmpImage(new Imagefloat(bfw, bfh)); + + DehazeParams dehazeParams; + dehazeParams.enabled = true; + dehazeParams.strength = lp.dehaze; + dehazeParams.showDepthMap = false; + dehazeParams.depth = lp.depth; + dehazeParams.luminance = params->locallab.spots.at(sp).lumonly; + lab2rgb(*bufexpfin, *tmpImage.get(), params->icm.workingProfile); + dehazeloc(tmpImage.get(), dehazeParams); + rgb2lab(*tmpImage.get(), *bufexpfin, params->icm.workingProfile); + + transit_shapedetect2(call, 30, bufexporig.get(), bufexpfin.get(), nullptr, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + + lp.invret = false;//always disabled inverse RETI too complex todo !! + + if (lp.str >= 0.2f && lp.retiena && call != 2) { + LabImage *bufreti = nullptr; + LabImage *bufmask = nullptr; + LabImage *buforig = nullptr; + LabImage *buforigmas = nullptr; + + if (GW >= mSP && GH >= mSP) + + { + + array2D buflight(GW, GH); + JaggedArray bufchro(GW, GH); + + int Hd, Wd; + Hd = GH; + Wd = GW; + + bufreti = new LabImage(GW, GH); + bufmask = new LabImage(GW, GH); + + if (!lp.enaretiMasktmap && lp.enaretiMask) { + buforig = new LabImage(GW, GH); + buforigmas = new LabImage(GW, GH); + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < GH; ir++) //fill with 0 + for (int jr = 0; jr < GW; jr++) { + bufreti->L[ir][jr] = 0.f; + bufreti->a[ir][jr] = 0.f; + bufreti->b[ir][jr] = 0.f; + buflight[ir][jr] = 0.f; + bufchro[ir][jr] = 0.f; + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H ; y++) //{ + for (int x = 0; x < transformed->W; x++) { + bufreti->L[y][x] = original->L[y][x]; + bufreti->a[y][x] = original->a[y][x]; + bufreti->b[y][x] = original->b[y][x]; + bufmask->L[y][x] = original->L[y][x]; + bufmask->a[y][x] = original->a[y][x]; + bufmask->b[y][x] = original->b[y][x]; + + if (!lp.enaretiMasktmap && lp.enaretiMask) { + buforig->L[y][x] = original->L[y][x]; + buforig->a[y][x] = original->a[y][x]; + buforig->b[y][x] = original->b[y][x]; + } + + } + + float raddE = params->locallab.spots.at(sp).softradiusret; + + //calc dE and reduction to use in MSR to reduce artifacts + const float mindE = 4.f + MINSCOPE * lp.sensh * lp.thr; + const float maxdE = 5.f + MAXSCOPE * lp.sensh * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + const float refa = chromaref * cos(hueref); + const float refb = chromaref * sin(hueref); + + const std::unique_ptr> reducDEBuffer(new JaggedArray(Wd, Hd)); + float** reducDE = *(reducDEBuffer.get()); + + float ade = 0.01f * raddE; + float bde = 100.f - raddE; + float sensibefore = ade * lp.sensh + bde;//we can change sensitivity 0.1 90 or 0.3 70 or 0.4 60 +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < transformed->H ; y++) + for (int x = 0; x < transformed->W; x++) { + float dE = std::sqrt(SQR(refa - bufreti->a[y][x] / 327.68f) + SQR(refb - bufreti->b[y][x] / 327.68f) + SQR(lumaref - bufreti->b[y][x] / 327.68f)); + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sensibefore); + reducDE[y][x] = clipDE(reducdE); + } + + const std::unique_ptr> origBuffer(new JaggedArray(Wd, Hd)); + float** orig = *(origBuffer.get()); + + const std::unique_ptr> origBuffer1(new JaggedArray(Wd, Hd)); + float** orig1 = *(origBuffer1.get()); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) + for (int jr = 0; jr < Wd; jr += 1) { + orig[ir][jr] = bufreti->L[ir][jr]; + orig1[ir][jr] = bufreti->L[ir][jr]; + } + + LabImage *tmpl = new LabImage(Wd, Hd); + + // float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; + bool fftw = lp.ftwreti; + //fftw = false; + //for Retinex Mask are incorporated in MSR + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + float lumask = params->locallab.spots.at(sp).lumask; + + const float mindE2 = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE2 = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim2 = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim2 = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + ImProcFunctions::MSRLocal(call, sp, fftw, 1, reducDE, bufreti, bufmask, buforig, buforigmas, orig, orig1, + Wd, Hd, Wd, Hd, params->locallab, sk, locRETgainCcurve, locRETtransCcurve, 0, 4, 1.f, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, llretiMask, + lmaskretilocalcurve, localmaskretiutili, + transformed, lp.enaretiMasktmap, lp.enaretiMask, + delt, hueref, chromaref, lumaref, + maxdE2, mindE2, maxdElim2, mindElim2, lp.iterat, limscope, sco, lp.balance, lp.balanceh, lumask); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) { + for (int jr = 0; jr < Wd; jr += 1) { + tmpl->L[ir][jr] = orig[ir][jr]; + } + } + + if (lp.equret) { //equilibrate luminance before / after MSR + float *datain = new float[Hd * Wd]; + float *data = new float[Hd * Wd]; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) + for (int jr = 0; jr < Wd; jr += 1) { + datain[ir * Wd + jr] = orig1[ir][jr]; + data[ir * Wd + jr] = orig[ir][jr]; + } + + normalize_mean_dt(data, datain, Hd * Wd, 1.f, 1.f); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) + for (int jr = 0; jr < Wd; jr += 1) { + tmpl->L[ir][jr] = data[ir * Wd + jr]; + } + + delete [] datain; + delete [] data; + } + + + float minL = tmpl->L[0][0] - bufreti->L[0][0]; + float maxL = minL; +#ifdef _OPENMP + #pragma omp parallel for reduction(min:minL) reduction(max:maxL) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + buflight[ir][jr] = tmpl->L[ir][jr] - bufreti->L[ir][jr]; + minL = rtengine::min(minL, buflight[ir][jr]); + maxL = rtengine::max(maxL, buflight[ir][jr]); + } + } + + const float coef = 0.01f * rtengine::max(std::fabs(minL), std::fabs(maxL)); + + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + buflight[ir][jr] /= coef; + } + } + + transit_shapedetect_retinex(call, 4, bufreti, bufmask, buforigmas, buflight, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + + if (params->locallab.spots.at(sp).chrrt > 0) { + + if (call == 1) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) + for (int jr = 0; jr < Wd; jr += 1) { + + orig[ir][jr] = std::sqrt(SQR(bufreti->a[ir][jr]) + SQR(bufreti->b[ir][jr])); + orig1[ir][jr] = std::sqrt(SQR(bufreti->a[ir][jr]) + SQR(bufreti->b[ir][jr])); + } + + } + + float maxChro = orig1[0][0]; +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxChro) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + maxChro = rtengine::max(maxChro, orig1[ir][jr]); + } + } + + float divchro = maxChro; + + //first step change saturation without Retinex ==> gain of time and memory + float satreal = lp.str * params->locallab.spots.at(sp).chrrt / 100.f; + + if (params->locallab.spots.at(sp).chrrt <= 0.2f) { + satreal /= 10.f; + } + + DiagonalCurve reti_satur({ + DCT_NURBS, + 0, 0, + 0.2, 0.2 + satreal / 250.0, + 0.6, rtengine::min(1.0, 0.6 + satreal / 250.0), + 1, 1 + }); + + if (call == 1) { + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) + for (int jr = 0; jr < Wd; jr += 1) { + const float Chprov = orig1[ir][jr]; + float2 sincosval; + sincosval.y = Chprov == 0.0f ? 1.f : bufreti->a[ir][jr] / Chprov; + sincosval.x = Chprov == 0.0f ? 0.f : bufreti->b[ir][jr] / Chprov; + + if (params->locallab.spots.at(sp).chrrt <= 100.f) { //first step + float buf = LIM01(orig[ir][jr] / divchro); + buf = reti_satur.getVal(buf); + buf *= divchro; + orig[ir][jr] = buf; + } + + tmpl->a[ir][jr] = orig[ir][jr] * sincosval.y; + tmpl->b[ir][jr] = orig[ir][jr] * sincosval.x; + } + + float minC = std::sqrt(SQR(tmpl->a[0][0]) + SQR(tmpl->b[0][0])) - orig1[0][0]; + float maxC = minC; +#ifdef _OPENMP + #pragma omp parallel for reduction(min:minC) reduction(max:maxC) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + bufchro[ir][jr] = std::sqrt(SQR(tmpl->a[ir][jr]) + SQR(tmpl->b[ir][jr])) - orig1[ir][jr]; + minC = rtengine::min(minC, bufchro[ir][jr]); + maxC = rtengine::max(maxC, bufchro[ir][jr]); + } + } + + float coefC = 0.01f * rtengine::max(std::fabs(minC), std::fabs(maxC)); + + if (coefC > 0.f) { + coefC = 1.f / coefC; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + bufchro[ir][jr] *= coefC; + } + } + } + } + + transit_shapedetect_retinex(call, 5, tmpl, bufmask, buforigmas, buflight, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + + delete tmpl; + delete bufmask; + + if (!lp.enaretiMasktmap && lp.enaretiMask) { + if (buforig) { + delete buforig; + } + + if (buforigmas) { + delete buforigmas; + } + } + delete bufreti; + } + } + + + + if (lp.str >= 0.2f && lp.retiena && call == 2) { + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + + LabImage *bufreti = nullptr; + LabImage *bufmask = nullptr; + LabImage *buforig = nullptr; + LabImage *buforigmas = nullptr; + int bfhr = bfh; + int bfwr = bfw; + + if (bfw >= mSP && bfh > mSP) { + if (lp.ftwreti) { + optfft(N_fftwsize, bfh, bfw, bfhr, bfwr, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + array2D buflight(bfw, bfh); + JaggedArray bufchro(bfw, bfh); + + int Hd, Wd; + Hd = GH; + Wd = GW; + + if (!lp.invret && call == 2) { + + Hd = bfh; + Wd = bfw; + bufreti = new LabImage(bfw, bfh); + bufmask = new LabImage(bfw, bfh); + + if (!lp.enaretiMasktmap && lp.enaretiMask) { + buforig = new LabImage(bfw, bfh); + buforigmas = new LabImage(bfw, bfh); + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) //fill with 0 + for (int jr = 0; jr < bfw; jr++) { + bufreti->L[ir][jr] = 0.f; + bufreti->a[ir][jr] = 0.f; + bufreti->b[ir][jr] = 0.f; + buflight[ir][jr] = 0.f; + bufchro[ir][jr] = 0.f; + } + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufreti->L[y - ystart][x - xstart] = original->L[y][x]; + bufreti->a[y - ystart][x - xstart] = original->a[y][x]; + bufreti->b[y - ystart][x - xstart] = original->b[y][x]; + bufmask->L[y - ystart][x - xstart] = original->L[y][x]; + bufmask->a[y - ystart][x - xstart] = original->a[y][x]; + bufmask->b[y - ystart][x - xstart] = original->b[y][x]; + + if (!lp.enaretiMasktmap && lp.enaretiMask) { + buforig->L[y - ystart][x - xstart] = original->L[y][x]; + buforig->a[y - ystart][x - xstart] = original->a[y][x]; + buforig->b[y - ystart][x - xstart] = original->b[y][x]; + } + } + } + } + + float raddE = params->locallab.spots.at(sp).softradiusret; + + //calc dE and reduction to use in MSR to reduce artifacts + const float mindE = 4.f + MINSCOPE * lp.sensh * lp.thr; + const float maxdE = 5.f + MAXSCOPE * lp.sensh * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + const float refa = chromaref * cos(hueref); + const float refb = chromaref * sin(hueref); + + const std::unique_ptr> reducDEBuffer(new JaggedArray(Wd, Hd)); + float** reducDE = *(reducDEBuffer.get()); + float ade = 0.01f * raddE; + float bde = 100.f - raddE; + float sensibefore = ade * lp.sensh + bde;//we can change sensitivity 0.1 90 or 0.3 70 or 0.4 60 +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend ; y++) { + for (int x = xstart; x < xend; x++) { + const float dE = std::sqrt(SQR(refa - bufreti->a[y - ystart][x - xstart] / 327.68f) + SQR(refb - bufreti->b[y - ystart][x - xstart] / 327.68f) + SQR(lumaref - bufreti->b[y - ystart][x - xstart] / 327.68f)); + const float reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sensibefore); + reducDE[y - ystart][x - xstart] = clipDE(reducdE); + } + } + + const std::unique_ptr> origBuffer(new JaggedArray(Wd, Hd)); + float** orig = *(origBuffer.get()); + + const std::unique_ptr> origBuffer1(new JaggedArray(Wd, Hd)); + float** orig1 = *(origBuffer1.get()); + + LabImage *tmpl = nullptr; + + if (!lp.invret && call == 2) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) { + for (int jr = 0; jr < Wd; jr += 1) { + orig[ir][jr] = bufreti->L[ir][jr]; + orig1[ir][jr] = bufreti->L[ir][jr]; + } + } + + tmpl = new LabImage(Wd, Hd); + } + + // float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; + bool fftw = lp.ftwreti; + //for Retinex Mask are incorporated in MSR + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + float lumask = params->locallab.spots.at(sp).lumask; + + const float mindE2 = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE2 = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim2 = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim2 = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + + ImProcFunctions::MSRLocal(call, sp, fftw, 1, reducDE, bufreti, bufmask, buforig, buforigmas, orig, orig1, + Wd, Hd, bfwr, bfhr, params->locallab, sk, locRETgainCcurve, locRETtransCcurve, 0, 4, 1.f, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, llretiMask, + lmaskretilocalcurve, localmaskretiutili, + transformed, lp.enaretiMasktmap, lp.enaretiMask, + delt, hueref, chromaref, lumaref, + maxdE2, mindE2, maxdElim2, mindElim2, lp.iterat, limscope, sco, lp.balance, lp.balanceh, lumask); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) + for (int jr = 0; jr < Wd; jr += 1) { + tmpl->L[ir][jr] = orig[ir][jr]; + } + + + if (lp.equret) { //equilibrate luminance before / after MSR + const std::unique_ptr datain(new float[Hd * Wd]); + const std::unique_ptr data(new float[Hd * Wd]); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) { + for (int jr = 0; jr < Wd; jr += 1) { + datain[ir * Wd + jr] = orig1[ir][jr]; + data[ir * Wd + jr] = orig[ir][jr]; + } + } + + normalize_mean_dt(data.get(), datain.get(), Hd * Wd, 1.f, 1.f); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) { + for (int jr = 0; jr < Wd; jr += 1) { + tmpl->L[ir][jr] = data[ir * Wd + jr]; + } + } + } + + if (!lp.invret) { + float minL = tmpl->L[0][0] - bufreti->L[0][0]; + float maxL = minL; +#ifdef _OPENMP + #pragma omp parallel for reduction(min:minL) reduction(max:maxL) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + buflight[ir][jr] = tmpl->L[ir][jr] - bufreti->L[ir][jr]; + minL = rtengine::min(minL, buflight[ir][jr]); + maxL = rtengine::max(maxL, buflight[ir][jr]); + } + } + + float coef = 0.01f * rtengine::max(std::fabs(minL), std::fabs(maxL)); + + if (coef > 0.f) { + coef = 1.f / coef; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + buflight[ir][jr] *= coef; + } + } + } + + transit_shapedetect_retinex(call, 4, bufreti, bufmask, buforigmas, buflight, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + + if (params->locallab.spots.at(sp).chrrt > 0) { + if (!lp.invret && call == 2) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) { + for (int jr = 0; jr < Wd; jr += 1) { + orig[ir][jr] = std::sqrt(SQR(bufreti->a[ir][jr]) + SQR(bufreti->b[ir][jr])); + orig1[ir][jr] = std::sqrt(SQR(bufreti->a[ir][jr]) + SQR(bufreti->b[ir][jr])); + } + } + } + + float maxChro = orig1[0][0]; +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxChro) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + maxChro = rtengine::max(maxChro, orig1[ir][jr]); + } + } + + //first step change saturation without Retinex ==> gain of time and memory + float satreal = lp.str * params->locallab.spots.at(sp).chrrt / 100.f; + + if (params->locallab.spots.at(sp).chrrt <= 0.2f) { + satreal /= 10.f; + } + + DiagonalCurve reti_satur({ + DCT_NURBS, + 0, 0, + 0.2, 0.2 + satreal / 250.0, + 0.6, rtengine::min(1.0, 0.6 + satreal / 250.0), + 1, 1 + }); + + if (!lp.invret && call == 2) { + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir += 1) { + for (int jr = 0; jr < Wd; jr += 1) { + const float Chprov = orig1[ir][jr]; + float2 sincosval; + sincosval.y = Chprov == 0.0f ? 1.f : bufreti->a[ir][jr] / Chprov; + sincosval.x = Chprov == 0.0f ? 0.f : bufreti->b[ir][jr] / Chprov; + + if (params->locallab.spots.at(sp).chrrt <= 40.f) { //first step + orig[ir][jr] = reti_satur.getVal(LIM01(orig[ir][jr] / maxChro)) * maxChro; + } + + tmpl->a[ir][jr] = orig[ir][jr] * sincosval.y; + tmpl->b[ir][jr] = orig[ir][jr] * sincosval.x; + } + } + + float minC = std::sqrt(SQR(tmpl->a[0][0]) + SQR(tmpl->b[0][0])) - orig1[0][0]; + float maxC = minC; +#ifdef _OPENMP + #pragma omp parallel for reduction(min:minC) reduction(max:maxC) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + bufchro[ir][jr] = std::sqrt(SQR(tmpl->a[ir][jr]) + SQR(tmpl->b[ir][jr])) - orig1[ir][jr]; + minC = rtengine::min(minC, bufchro[ir][jr]); + maxC = rtengine::max(maxC, bufchro[ir][jr]); + } + } + + float coefC = 0.01f * rtengine::max(std::fabs(minC), std::fabs(maxC)); + + if (coefC > 0.f) { + coefC = 1.f / coefC; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < Hd; ir++) { + for (int jr = 0; jr < Wd; jr++) { + bufchro[ir][jr] *= coefC; + } + } + } + } + + if (!lp.invret) { + transit_shapedetect_retinex(call, 5, tmpl, bufmask, buforigmas, buflight, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + + delete tmpl; + delete bufmask; + + if (!lp.enaretiMasktmap && lp.enaretiMask) { + if (buforig) { + delete buforig; + } + + if (buforigmas) { + delete buforigmas; + } + } + delete bufreti; + } + } + + bool enablefat = false; + + if (params->locallab.spots.at(sp).fatamount > 1.f) { + enablefat = true;; + } + + bool execex = (lp.exposena && (lp.expcomp != 0.f || lp.blac != 0 || lp.laplacexp > 0.1f || lp.strexp != 0.f || enablefat || lp.showmaskexpmet == 2 || lp.enaExpMask || lp.showmaskexpmet == 3 || lp.showmaskexpmet == 4 || lp.showmaskexpmet == 5 || lp.prevdE || (exlocalcurve && localexutili))); + + if (!lp.invex && execex) { + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + //variable for fast FFTW + int bfhr = bfh; + int bfwr = bfw; + + + if (bfw >= mSP && bfh >= mSP) { + + if (lp.expmet == 1) { + optfft(N_fftwsize, bfh, bfw, bfhr, bfwr, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + const std::unique_ptr bufexporig(new LabImage(bfw, bfh)); + const std::unique_ptr bufexpfin(new LabImage(bfw, bfh)); + + std::unique_ptr bufmaskblurexp; + std::unique_ptr originalmaskexp; + + array2D blend2; + + if (call <= 3) { //simpleprocess, dcrop, improccoordinator + if (lp.showmaskexpmet == 2 || lp.enaExpMask || lp.showmaskexpmet == 3 || lp.showmaskexpmet == 5) { + bufmaskblurexp.reset(new LabImage(bfw, bfh)); + originalmaskexp.reset(new LabImage(bfw, bfh)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend; y++) { + for (int x = xstart; x < xend; x++) { + bufexporig->L[y - ystart][x - xstart] = original->L[y][x]; + } + } + + const int spotSi = rtengine::max(1 + 2 * rtengine::max(1, lp.cir / sk), 5); + + if (bfw > 2 * spotSi && bfh > 2 * spotSi && lp.struexp > 0.f) { + blend2(bfw, bfh); + ImProcFunctions::blendstruc(bfw, bfh, bufexporig.get(), 3.f / (sk * 1.4f), 0.5f * lp.struexp, blend2, sk, multiThread); + + if (lp.showmaskexpmet == 4) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend ; y++) { + for (int x = xstart; x < xend; x++) { + const int lox = cx + x; + const int loy = cy + y; + int zone; + float localFactor = 1.f; + const float achm = lp.trans / 100.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, achm, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, achm, lp, zone, localFactor); + } + + if (zone > 0) { + transformed->L[y][x] = CLIP(blend2[y - ystart][x - xstart]); + transformed->a[y][x] = 0.f; + transformed->b[y][x] = 0.f; + } + } + } + + return; + } + } + + int inv = 0; + bool showmaske = false; + const bool enaMask = lp.enaExpMask; + bool deltaE = false; + bool modmask = false; + bool zero = false; + bool modif = false; + + if (lp.showmaskexpmet == 3) { + showmaske = true; + } else if (lp.showmaskexpmet == 5) { + deltaE = true; + } else if (lp.showmaskexpmet == 2) { + modmask = true; + } else if (lp.showmaskexpmet == 1) { + modif = true; + } else if (lp.showmaskexpmet == 0) { + zero = true; + } + + float chrom = lp.chromaexp; + float rad = lp.radmaexp; + float gamma = lp.gammaexp; + float slope = lp.slomaexp; + float blendm = lp.blendmaexp; + float lap = params->locallab.spots.at(sp).lapmaskexp; + bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool lmasutilicolwav = false; + bool delt = params->locallab.spots.at(sp).deltae; + int sco = params->locallab.spots.at(sp).scopemask; + int shado = 0; + int shortcu = 0;//lp.mergemet; //params->locallab.spots.at(sp).shortc; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + float amountcd = 0.f; + float anchorcd = 50.f; + int lumask = params->locallab.spots.at(sp).lumask; + LocHHmaskCurve lochhhmasCurve; + bool lhhmasutili = false; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskblurexp.get(), originalmaskexp.get(), original, reserved, inv, lp, + 0.f, false, + locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmaskexplocalcurve, localmaskexputili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskexpmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufexporig.get(), transformed, bufmaskblurexp.get(), 0); + + return; + } + + if (lp.showmaskexpmet == 4) { + return; + } + + if (lp.showmaskexpmet == 0 || lp.showmaskexpmet == 1 || lp.showmaskexpmet == 2 || lp.showmaskexpmet == 5 || lp.enaExpMask) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + bufexpfin->L[y][x] = original->L[y + ystart][x + xstart]; + bufexpfin->a[y][x] = original->a[y + ystart][x + xstart]; + bufexpfin->b[y][x] = original->b[y + ystart][x + xstart]; + } + } + + + + if (exlocalcurve && localexutili) {// L=f(L) curve enhanced +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + bufexpfin->L[ir][jr] = 0.5f * exlocalcurve[2.f * bufexporig->L[ir][jr]]; + } + + if (lp.expcomp == 0.f) { + lp.expcomp = 0.011f; // to enabled + } + + ImProcFunctions::exlabLocal(lp, bfh, bfw, bufexpfin.get(), bufexpfin.get(), hltonecurveloc, shtonecurveloc, tonecurveloc); + + + } else { + + ImProcFunctions::exlabLocal(lp, bfh, bfw, bufexporig.get(), bufexpfin.get(), hltonecurveloc, shtonecurveloc, tonecurveloc); + } + +//gradient + struct grad_params gp; + + if (lp.strexp != 0.f) { + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, 1); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + bufexpfin->L[ir][jr] *= ImProcFunctions::calcGradientFactor(gp, jr, ir); + } + } + } + +//exposure_pde + if (lp.expmet == 1) { + if (enablefat) { + const std::unique_ptr datain(new float[bfwr * bfhr]); + const std::unique_ptr dataout(new float[bfwr * bfhr]); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + datain[y * bfwr + x] = bufexpfin->L[y][x]; + } + } + + FattalToneMappingParams fatParams; + fatParams.enabled = true; + fatParams.threshold = params->locallab.spots.at(sp).fatdetail; + fatParams.amount = params->locallab.spots.at(sp).fatamount; + fatParams.anchor = 50.f; //params->locallab.spots.at(sp).fatanchor; + const float sigm = params->locallab.spots.at(sp).fatlevel; + const float mean = params->locallab.spots.at(sp).fatanchor; + const std::unique_ptr tmpImagefat(new Imagefloat(bfwr, bfhr)); + lab2rgb(*bufexpfin, *(tmpImagefat.get()), params->icm.workingProfile); + ToneMapFattal02(tmpImagefat.get(), fatParams, 3, 0, nullptr, 0, 0, 1);//last parameter = 1 ==>ART algorithm + rgb2lab(*(tmpImagefat.get()), *bufexpfin, params->icm.workingProfile); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + dataout[y * bfwr + x] = bufexpfin->L[y][x]; + } + } + + normalize_mean_dt(dataout.get(), datain.get(), bfwr * bfhr, mean, sigm); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + bufexpfin->L[y][x] = dataout[y * bfwr + x]; + } + } + } + + if (lp.laplacexp > 0.1f) { + MyMutex::MyLock lock(*fftwMutex); + std::unique_ptr datain(new float[bfwr * bfhr]); + std::unique_ptr dataout(new float[bfwr * bfhr]); + const float gam = params->locallab.spots.at(sp).gamm; + const float igam = 1.f / gam; + + if (params->locallab.spots.at(sp).exnoiseMethod == "med" || params->locallab.spots.at(sp).exnoiseMethod == "medhi") { + if (lp.blac < -100.f && lp.linear > 0.01f) { + float evnoise = lp.blac - lp.linear * 2000.f; + if (params->locallab.spots.at(sp).exnoiseMethod == "med") { + evnoise *= 0.4f; + } + + //soft denoise, user must use Local Denoise to best result + Median med; + if (evnoise < -18000.f) { + med = Median::TYPE_5X5_STRONG; + } else if (evnoise < -15000.f) { + med = Median::TYPE_5X5_SOFT; + } else if (evnoise < -10000.f) { + med = Median::TYPE_3X3_STRONG; + } else { + med = Median:: TYPE_3X3_SOFT; + } + + Median_Denoise(bufexpfin->L, bufexpfin->L, bfwr, bfhr, med, 1, multiThread); + Median_Denoise(bufexpfin->a, bufexpfin->a, bfwr, bfhr, Median::TYPE_3X3_SOFT, 1, multiThread); + Median_Denoise(bufexpfin->b, bufexpfin->b, bfwr, bfhr, Median::TYPE_3X3_SOFT, 1, multiThread); + } + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + float L = LIM01(bufexpfin->L[y][x] / 32768.f);//change gamma for Laplacian + datain[y * bfwr + x] = pow_F(L, gam) * 32768.f; + } + } + + //call PDE equation - with Laplacian threshold + ImProcFunctions::exposure_pde(datain.get(), datain.get(), dataout.get(), bfwr, bfhr, 12.f * lp.laplacexp, lp.balanexp); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfhr; y++) { + for (int x = 0; x < bfwr; x++) { + const float Y = dataout[y * bfwr + x] / 32768.f;//inverse Laplacian gamma + bufexpfin->L[y][x] = pow_F(Y, igam) * 32768.f; + } + } + } + } + + //shadows with ipshadowshighlight + if ((lp.expcomp != 0.f && lp.expcomp != 0.01f) || (exlocalcurve && localexutili)) { + if (lp.shadex > 0) { + ImProcFunctions::shadowsHighlights(bufexpfin.get(), true, 1, 0, lp.shadex, 40, sk, 0, lp.shcomp); + } + } + + if (lp.expchroma != 0.f) { + if ((lp.expcomp != 0.f && lp.expcomp != 0.01f) || (exlocalcurve && localexutili) || lp.laplacexp > 0.1f) { + constexpr float ampli = 70.f; + const float ch = (1.f + 0.02f * lp.expchroma); + const float chprosl = ch <= 1.f ? 99.f * ch - 99.f : clipChro(ampli * ch - ampli); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + const float epsi = bufexporig->L[ir][jr] == 0.f ? 0.001f : 0.f; + const float rapexp = bufexpfin->L[ir][jr] / (bufexporig->L[ir][jr] + epsi); + bufexpfin->a[ir][jr] *= 1.f + chprosl * rapexp; + bufexpfin->b[ir][jr] *= 1.f + chprosl * rapexp; + } + } + } + } + + if (lp.softradiusexp > 0.f && lp.expmet == 0) { + softproc(bufexporig.get(), bufexpfin.get(), lp.softradiusexp, bfh, bfw, 0.0001, 0.00001, 0.1f, sk, multiThread, 1); + } + float meansob = 0.f; + transit_shapedetect2(call, 1, bufexporig.get(), bufexpfin.get(), originalmaskexp.get(), hueref, chromaref, lumaref, sobelref, meansob, blend2, lp, original, transformed, cx, cy, sk); + } + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + } +//inverse + + else if (lp.invex && (lp.expcomp != 0.0 || lp.laplacexp > 0.1f || params->locallab.spots.at(sp).fatamount > 1.f || (exlocalcurve && localexutili) || lp.enaExpMaskinv || lp.showmaskexpmetinv == 1) && lp.exposena) { + constexpr float adjustr = 2.f; + std::unique_ptr bufmaskblurexp; + std::unique_ptr originalmaskexp; + const std::unique_ptr bufexporig(new LabImage(GW, GH)); + + if (lp.enaExpMaskinv || lp.showmaskexpmetinv == 1) { + bufmaskblurexp.reset(new LabImage(GW, GH, true)); + originalmaskexp.reset(new LabImage(GW, GH)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + bufexporig->L[y][x] = original->L[y][x]; + } + } + + constexpr int inv = 1; + const bool showmaske = lp.showmaskexpmetinv == 1; + const bool enaMask = lp.enaExpMaskinv; + constexpr bool deltaE = false; + constexpr bool modmask = false; + const bool zero = lp.showmaskexpmetinv == 0; + constexpr bool modif = false; + const float chrom = lp.chromaexp; + const float rad = lp.radmaexp; + const float gamma = lp.gammaexp; + const float slope = lp.slomaexp; + const float blendm = lp.blendmaexp; + const float lap = params->locallab.spots.at(sp).lapmaskexp; + const bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + const bool lmasutilicolwav = false; + // bool delt = params->locallab.spots.at(sp).deltae; + const bool delt = false; + const int sco = params->locallab.spots.at(sp).scopemask; + constexpr int shado = 0; + constexpr int shortcu = 0;//lp.mergemet; //params->locallab.spots.at(sp).shortc; + const int lumask = params->locallab.spots.at(sp).lumask; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + constexpr float amountcd = 0.f; + constexpr float anchorcd = 50.f; + LocHHmaskCurve lochhhmasCurve; + constexpr bool lhhmasutili = false; + + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufexporig.get(), bufmaskblurexp.get(), originalmaskexp.get(), original, reserved, inv, lp, + 0.f, false, + locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmaskexplocalcurve, localmaskexputili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskexpmetinv == 1) { + showmask(lumask, lp, 0, 0, cx, cy, GW, GH, bufexporig.get(), transformed, bufmaskblurexp.get(), inv); + return; + } + + InverseColorLight_Local(false, false, sp, 1, lp, originalmaskexp.get(), lightCurveloc, hltonecurveloc, shtonecurveloc, tonecurveloc, exlocalcurve, cclocalcurve, adjustr, localcutili, lllocalcurve, locallutili, original, transformed, cx, cy, hueref, chromaref, lumaref, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + +//local color and light + const float factor = LocallabParams::LABGRIDL_CORR_MAX * 3.276f; + const float scaling = LocallabParams::LABGRIDL_CORR_SCALE; + const float scaledirect = LocallabParams::LABGRIDL_DIRECT_SCALE; + const float a_scale = (lp.highA - lp.lowA) / factor / scaling; + const float a_base = lp.lowA / scaling; + const float b_scale = (lp.highB - lp.lowB) / factor / scaling; + const float b_base = lp.lowB / scaling; + const bool ctoning = (a_scale != 0.f || b_scale != 0.f || a_base != 0.f || b_base != 0.f); + const float a_scalemerg = (lp.highAmerg - lp.lowAmerg) / factor / scaling; + const float a_basemerg = lp.lowAmerg / scaling; + const float b_scalemerg = (lp.highBmerg - lp.lowBmerg) / factor / scaling; + const float b_basemerg = lp.lowBmerg / scaling; + const bool ctoningmerg = (a_scalemerg != 0.f || b_scalemerg != 0.f || a_basemerg != 0.f || b_basemerg != 0.f); + + if (!lp.inv && (lp.chro != 0 || lp.ligh != 0.f || lp.cont != 0 || ctoning || lp.mergemet > 0 || lp.strcol != 0.f || lp.strcolab != 0.f || lp.qualcurvemet != 0 || lp.showmaskcolmet == 2 || lp.enaColorMask || lp.showmaskcolmet == 3 || lp.showmaskcolmet == 4 || lp.showmaskcolmet == 5 || lp.prevdE) && lp.colorena) { // || lllocalcurve)) { //interior ellipse renforced lightness and chroma //locallutili + int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); + int yend = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H); + int xstart = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0); + int xend = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W); + int bfh = yend - ystart; + int bfw = xend - xstart; + const bool spez = params->locallab.spots.at(sp).special; + + if (bfw >= mSP && bfh >= mSP) { + + if (lp.blurcolmask >= 0.25f && lp.fftColorMask && call == 2) { + optfft(N_fftwsize, bfh, bfw, bfh, bfw, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + + std::unique_ptr bufcolorig; + std::unique_ptr bufcolfin; + std::unique_ptr bufmaskblurcol; + std::unique_ptr originalmaskcol; + std::unique_ptr bufcolreserv; + std::unique_ptr buftemp; + array2D blend2; + + float adjustr = 1.0f; + + //adapt chroma to working profile + if (params->icm.workingProfile == "ProPhoto") { + adjustr = 1.2f; // 1.2 instead 1.0 because it's very rare to have C>170.. + } else if (params->icm.workingProfile == "Adobe RGB") { + adjustr = 1.8f; + } else if (params->icm.workingProfile == "sRGB") { + adjustr = 2.0f; + } else if (params->icm.workingProfile == "WideGamut") { + adjustr = 1.2f; + } else if (params->icm.workingProfile == "Beta RGB") { + adjustr = 1.4f; + } else if (params->icm.workingProfile == "BestRGB") { + adjustr = 1.4f; + } else if (params->icm.workingProfile == "BruceRGB") { + adjustr = 1.8f; + } + + if (call <= 3) { //simpleprocess, dcrop, improccoordinator + bufcolorig.reset(new LabImage(bfw, bfh)); + bufcolfin.reset(new LabImage(bfw, bfh)); + buftemp.reset(new LabImage(bfw, bfh)); + + if (lp.showmaskcolmet == 2 || lp.enaColorMask || lp.showmaskcolmet == 3 || lp.showmaskcolmet == 5) { + bufmaskblurcol.reset(new LabImage(bfw, bfh, true)); + originalmaskcol.reset(new LabImage(bfw, bfh)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufcolorig->L[y][x] = original->L[y + ystart][x + xstart]; + bufcolorig->a[y][x] = original->a[y + ystart][x + xstart]; + bufcolorig->b[y][x] = original->b[y + ystart][x + xstart]; + bufcolfin->L[y][x] = original->L[y + ystart][x + xstart]; + bufcolfin->a[y][x] = original->a[y + ystart][x + xstart]; + bufcolfin->b[y][x] = original->b[y + ystart][x + xstart]; + buftemp->L[y][x] = original->L[y + ystart][x + xstart]; + buftemp->a[y][x] = original->a[y + ystart][x + xstart]; + buftemp->b[y][x] = original->b[y + ystart][x + xstart]; + } + } + + const int spotSi = rtengine::max(1 + 2 * rtengine::max(1, lp.cir / sk), 5); + const bool blends = bfw > 2 * spotSi && bfh > 2 * spotSi && lp.struco > 0.f; + + if (blends) { + blend2(bfw, bfh); + ImProcFunctions::blendstruc(bfw, bfh, bufcolorig.get(), 3.f / (sk * 1.4f), 0.5f * lp.struco, blend2, sk, multiThread); + + if (lp.showmaskcolmet == 4) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = ystart; y < yend ; y++) { + for (int x = xstart; x < xend; x++) { + const int lox = cx + x; + const int loy = cy + y; + int zone; + float localFactor = 1.f; + const float achm = lp.trans / 100.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, achm, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, achm, lp, zone, localFactor); + } + + if (zone > 0) { + transformed->L[y][x] = CLIP(blend2[y - ystart][x - xstart]); + transformed->a[y][x] = 0.f; + transformed->b[y][x] = 0.f; + } + } + } + return; + } + } + + const int inv = 0; + const bool showmaske = lp.showmaskcolmet == 3; + const bool enaMask = lp.enaColorMask; + const bool deltaE = lp.showmaskcolmet == 5; + const bool modmask = lp.showmaskcolmet == 2; + const bool zero = lp.showmaskcolmet == 0; + const bool modif = lp.showmaskcolmet == 1; + const float chrom = lp.chromacol; + const float rad = lp.radmacol; + const float gamma = lp.gammacol; + const float slope = lp.slomacol; + const float blendm = lp.blendmacol; + const float lap = params->locallab.spots.at(sp).lapmaskcol; + const bool pde = params->locallab.spots.at(sp).laplac; + const int shado = params->locallab.spots.at(sp).shadmaskcol; + const int sco = params->locallab.spots.at(sp).scopemask; + const int level_bl = params->locallab.spots.at(sp).csthresholdcol.getBottomLeft(); + const int level_hl = params->locallab.spots.at(sp).csthresholdcol.getTopLeft(); + const int level_br = params->locallab.spots.at(sp).csthresholdcol.getBottomRight(); + const int level_hr = params->locallab.spots.at(sp).csthresholdcol.getTopRight(); + const int shortcu = lp.mergemet; //params->locallab.spots.at(sp).shortc; + const int lumask = params->locallab.spots.at(sp).lumask; + const float strumask = 0.02f * params->locallab.spots.at(sp).strumaskcol; + float conthr = 0.01f * params->locallab.spots.at(sp).conthrcol; + const float mercol = params->locallab.spots.at(sp).mercol; + const float merlucol = params->locallab.spots.at(sp).merlucol; + + int tonemod = 0; + if (params->locallab.spots.at(sp).toneMethod == "one") { + tonemod = 0; + } else if (params->locallab.spots.at(sp).toneMethod == "two") { + tonemod = 1; + } else if (params->locallab.spots.at(sp).toneMethod == "thr") { + tonemod = 2; + } else if (params->locallab.spots.at(sp).toneMethod == "fou") { + tonemod = 3; + } + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + const float amountcd = 0.f; + const float anchorcd = 50.f; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, reserved, inv, lp, + strumask, astool, + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmasklocalcurve, localmaskutili, loclmasCurvecolwav, lmasutilicolwav, + level_bl, level_hl, level_br, level_hr, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskcolmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufcolorig.get(), transformed, bufmaskblurcol.get(), 0); + return; + } else if (lp.showmaskcolmet == 4) { + return; + } + + if (lp.showmaskcolmet == 0 || lp.showmaskcolmet == 1 || lp.showmaskcolmet == 2 || lp.showmaskcolmet == 5 || lp.enaColorMask) { + //RGB Curves + bool usergb = false; + + if (rgblocalcurve && localrgbutili && lp.qualcurvemet != 0) { + usergb = true; + const std::unique_ptr tmpImage(new Imagefloat(bfw, bfh)); + + lab2rgb(*buftemp, *(tmpImage.get()), params->icm.workingProfile); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) + for (int x = 0; x < bfw; x++) { + + //std + if (tonemod == 0) { + curves::setLutVal(rgblocalcurve, tmpImage->r(y, x), tmpImage->g(y, x), tmpImage->b(y, x)); + } else { + float r = CLIP(tmpImage->r(y, x)); + float g = CLIP(tmpImage->g(y, x)); + float b = CLIP(tmpImage->b(y, x)); + + if (tonemod == 1) { // weightstd + const float r1 = rgblocalcurve[r]; + const float g1 = triangle(r, r1, g); + const float b1 = triangle(r, r1, b); + + const float g2 = rgblocalcurve[g]; + const float r2 = triangle(g, g2, r); + const float b2 = triangle(g, g2, b); + + const float b3 = rgblocalcurve[b]; + const float r3 = triangle(b, b3, r); + const float g3 = triangle(b, b3, g); + r = CLIP(r1 * 0.50f + r2 * 0.25f + r3 * 0.25f); + g = CLIP(g1 * 0.25f + g2 * 0.50f + g3 * 0.25f); + b = CLIP(b1 * 0.25f + b2 * 0.25f + b3 * 0.50f); + } else if (tonemod == 2) { // Luminance + float currLuminance = r * 0.2126729f + g * 0.7151521f + b * 0.0721750f; + + const float newLuminance = rgblocalcurve[currLuminance]; + currLuminance = currLuminance == 0.f ? 0.00001f : currLuminance; + const float coef = newLuminance / currLuminance; + r = LIM(r * coef, 0.f, 65535.f); + g = LIM(g * coef, 0.f, 65535.f); + b = LIM(b * coef, 0.f, 65535.f); + } else if (tonemod == 3) { // Film like Adobe + if (r >= g) { + if (g > b) { + rgbtone(r, g, b, rgblocalcurve); // Case 1: r >= g > b + } else if (b > r) { + rgbtone(b, r, g, rgblocalcurve); // Case 2: b > r >= g + } else if (b > g) { + rgbtone(r, b, g, rgblocalcurve); // Case 3: r >= b > g + } else { // Case 4: r == g == b + r = rgblocalcurve[r]; + g = rgblocalcurve[g]; + b = g; + } + } else { + if (r >= b) { + rgbtone(g, r, b, rgblocalcurve); // Case 5: g > r >= b + } else if (b > g) { + rgbtone(b, g, r, rgblocalcurve); // Case 6: b > g > r + } else { + rgbtone(g, b, r, rgblocalcurve); // Case 7: g >= b > r + } + } + } + + setUnlessOOG(tmpImage->r(y, x), tmpImage->g(y, x), tmpImage->b(y, x), r, g, b); + } + } + + rgb2lab(*(tmpImage.get()), *buftemp, params->icm.workingProfile); + + // end rgb curves + } + + if (usergb && spez) {//special use of rgb curves ex : negative + const float achm = lp.trans / 100.f; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh; y++) { + const int loy = y + ystart + cy; + + for (int x = 0; x < bfw; x++) { + const int lox = x + xstart + cx; + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, achm, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, achm, lp, zone, localFactor); + } + + if (zone > 0) { + transformed->L[y + ystart][x + xstart] = buftemp->L[y][x] * localFactor + (1.f - localFactor) * original->L[y + ystart][x + xstart]; + transformed->a[y + ystart][x + xstart] = buftemp->a[y][x] * localFactor + (1.f - localFactor) * original->a[y + ystart][x + xstart]; + transformed->b[y + ystart][x + xstart] = buftemp->b[y][x] * localFactor + (1.f - localFactor) * original->b[y + ystart][x + xstart]; + } + } + } + } + + //others curves + + const LabImage *origptr = usergb ? buftemp.get() : bufcolorig.get(); + + bool execcolor = false; + + if (localcutili || HHutili || locallutili || lp.ligh != 0.f || lp.cont != 0 || lp.chro != 0 || LHutili || ctoning) { + execcolor = true; + } + + bool HHcurve = false; + if (lochhCurve && HHutili) { + for (int i = 0; i < 500; i++) { + if (lochhCurve[i] != 0.5) { + HHcurve = true; + break; + } + } + } + + const float kd = 10.f * 0.01f * lp.strengrid;//correction to ctoning + + //chroma slider with curve instead of linear + const float satreal = lp.chro; + + DiagonalCurve color_satur({ + DCT_NURBS, + 0, 0, + 0.2, 0.2 + satreal / 250.0, + 0.6, rtengine::min(1.0, 0.6 + satreal / 250.0), + 1, 1 + }); + + DiagonalCurve color_saturmoins({ + DCT_NURBS, + 0, 0, + 0.1 - satreal / 150., 0.1, + rtengine::min(1.0, 0.7 - satreal / 300.), 0.7, + 1, 1 + }); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + float bufcolcalca = origptr->a[ir][jr]; + float bufcolcalcb = origptr->b[ir][jr]; + float bufcolcalcL = origptr->L[ir][jr]; + + if (lp.chro != 0.f) {//slider chroma with curve DCT_NURBS + float Chprov = std::sqrt(SQR(bufcolcalca) + SQR(bufcolcalcb)); + float2 sincosval; + sincosval.y = Chprov == 0.0f ? 1.f : bufcolcalca / Chprov; + sincosval.x = Chprov == 0.0f ? 0.f : bufcolcalcb / Chprov; + + // 35000 must be globally good, more than 32768...and less than !! to avoid calculation min max + if (lp.chro > 0.f) { + Chprov = color_satur.getVal(LIM01(Chprov / 35000.f)) * 35000.f; + } else { + Chprov = color_saturmoins.getVal(LIM01(Chprov / 35000.f)) * 35000.f; + } + + if (lp.chro == -100.f) { + Chprov = 0.f; + } + + bufcolcalca = Chprov * sincosval.y; + bufcolcalcb = Chprov * sincosval.x; + } + + if (cclocalcurve && lp.qualcurvemet != 0 && localcutili) { // C=f(C) curve + const float chromat = std::sqrt(SQR(bufcolcalca) + SQR(bufcolcalcb)); + const float ch = cclocalcurve[chromat * adjustr] / ((chromat + 0.00001f) * adjustr); //ch between 0 and 0 50 or more + bufcolcalca *= ch; + bufcolcalcb *= ch; + } + + if (cllocalcurve && lp.qualcurvemet != 0 && localclutili) { // C=f(L) curve + float chromaCfactor = (cllocalcurve[bufcolcalcL * 2.f]) / (bufcolcalcL * 2.f); + bufcolcalca *= chromaCfactor; + bufcolcalcb *= chromaCfactor; + } + + if (lclocalcurve && lp.qualcurvemet != 0 && locallcutili) { // L=f(C) curve + const float chromat = std::sqrt(SQR(bufcolcalca) + SQR(bufcolcalcb)); + float Lc = lclocalcurve[chromat * adjustr] / ((chromat + 0.00001f) * adjustr); + + if (Lc > 1.f) { + Lc = (Lc - 1.0f) * 0.1f + 1.0f; //reduct action + } else { + Lc = (Lc - 1.0f) * 0.3f + 1.0f; + } + + bufcolcalcL *= Lc; + } + + if (lochhCurve && HHcurve && lp.qualcurvemet != 0 && !ctoning) { // H=f(H) + const float chromat = std::sqrt(SQR(bufcolcalca) + SQR(bufcolcalcb)); + const float hhforcurv = xatan2f(bufcolcalcb, bufcolcalca); + const float valparam = float ((lochhCurve[500.f * Color::huelab_to_huehsv2(hhforcurv)] - 0.5f)); //get H=f(H) + float2 sincosval = xsincosf(valparam); + bufcolcalca = chromat * sincosval.y; + bufcolcalcb = chromat * sincosval.x; + } + + if (lp.ligh != 0.f || lp.cont != 0) {//slider luminance or slider contrast with curve + bufcolcalcL = calclight(bufcolcalcL, lightCurveloc); + } + + if (lllocalcurve && locallutili && lp.qualcurvemet != 0) {// L=f(L) curve + bufcolcalcL = 0.5f * lllocalcurve[bufcolcalcL * 2.f]; + } + + if (loclhCurve && LHutili && lp.qualcurvemet != 0) {//L=f(H) curve + const float rhue = xatan2f(bufcolcalcb, bufcolcalca); + float l_r = bufcolcalcL / 32768.f; //Luminance Lab in 0..1 + const float valparam = loclhCurve[500.f * Color::huelab_to_huehsv2(rhue)] - 0.5f; //get l_r=f(H) + + if (valparam > 0.f) { + l_r = (1.f - valparam) * l_r + valparam * (1.f - SQR(((SQR(1.f - rtengine::min(l_r, 1.0f)))))); + } else { + constexpr float khu = 1.9f; //in reserve in case of! + //for negative + l_r *= (1.f + khu * valparam); + } + + bufcolcalcL = l_r * 32768.f; + + } + + if (ctoning) {//color toning and direct change color + if (lp.gridmet == 0) { + bufcolcalca += kd * bufcolcalcL * a_scale + a_base; + bufcolcalcb += kd * bufcolcalcL * b_scale + b_base; + } else if (lp.gridmet == 1) { + bufcolcalca += kd * scaledirect * a_scale; + bufcolcalcb += kd * scaledirect * b_scale; + } + + bufcolcalca = clipC(bufcolcalca); + bufcolcalcb = clipC(bufcolcalcb); + + } + + bufcolfin->L[ir][jr] = bufcolcalcL; + bufcolfin->a[ir][jr] = bufcolcalca; + bufcolfin->b[ir][jr] = bufcolcalcb; + } + } + + if (HHcurve && ctoning) {//not use ctoning and H(H) simultaneous but priority to ctoning + HHcurve = false; + } + + if (!execcolor) {//if we don't use color and light sliders, curves except RGB +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + bufcolfin->L[ir][jr] = origptr->L[ir][jr]; + bufcolfin->a[ir][jr] = origptr->a[ir][jr]; + bufcolfin->b[ir][jr] = origptr->b[ir][jr]; + } + } + + bool nottransit = false; + if (lp.mergemet >= 2) { //merge result with original + nottransit = true; + bufcolreserv.reset(new LabImage(bfw, bfh)); + JaggedArray lumreserv(bfw, bfh); + const std::unique_ptr bufreser(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + lumreserv[y][x] = 32768.f - reserved->L[y + ystart][x + xstart]; + bufreser->L[y][x] = reserved->L[y + ystart][x + xstart]; + bufreser->a[y][x] = reserved->a[y + ystart][x + xstart]; + bufreser->b[y][x] = reserved->b[y + ystart][x + xstart]; + + if (lp.mergemet == 2) { + bufcolreserv->L[y][x] = reserved->L[y + ystart][x + xstart]; + bufcolreserv->a[y][x] = reserved->a[y + ystart][x + xstart]; + bufcolreserv->b[y][x] = reserved->b[y + ystart][x + xstart]; + } else if (lp.mergemet == 3) { + bufcolreserv->L[y][x] = lastorig->L[y + ystart][x + xstart]; + bufcolreserv->a[y][x] = lastorig->a[y + ystart][x + xstart]; + bufcolreserv->b[y][x] = lastorig->b[y + ystart][x + xstart]; + } else if (lp.mergemet == 4 && ctoningmerg) { + bufcolreserv->L[y][x] = merlucol * 327.68f; + bufcolreserv->a[y][x] = 9.f * scaledirect * a_scalemerg; + bufcolreserv->b[y][x] = 9.f * scaledirect * b_scalemerg; + } + } + } + + if (lp.strcol != 0.f) { + struct grad_params gp; + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, 3); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + const float corrFactor = ImProcFunctions::calcGradientFactor(gp, jr, ir); + bufcolfin->L[ir][jr] *= corrFactor; + } + } + } + + if (lp.strcolab != 0.f) { + struct grad_params gpab; + calclocalGradientParams(lp, gpab, ystart, xstart, bfw, bfh, 4); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + const float corrFactor = ImProcFunctions::calcGradientFactor(gpab, jr, ir); + bufcolfin->a[ir][jr] *= corrFactor; + bufcolfin->b[ir][jr] *= corrFactor; + } + } + } + + if (lp.strcolh != 0.f) { + struct grad_params gph; + calclocalGradientParams(lp, gph, ystart, xstart, bfw, bfh, 6); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + const float corrFactor = ImProcFunctions::calcGradientFactor(gph, jr, ir); + const float aa = bufcolfin->a[ir][jr]; + const float bb = bufcolfin->b[ir][jr]; + const float chrm = std::sqrt(SQR(aa) + SQR(bb)); + const float HH = xatan2f(bb, aa); + + float cor = 0.f; + if (corrFactor < 1.f) { + cor = - 2.5f * (1.f - corrFactor); + } else if (corrFactor > 1.f) { + cor = 0.03f * (corrFactor - 1.f); + } + + float newhr = HH + cor; + if (newhr > rtengine::RT_PI_F) { + newhr -= 2 * rtengine::RT_PI_F; + } else if (newhr < -rtengine::RT_PI_F) { + newhr += 2 * rtengine::RT_PI_F; + } + + const float2 sincosval = xsincosf(newhr); + bufcolfin->a[ir][jr] = clipC(chrm * sincosval.y); + bufcolfin->b[ir][jr] = clipC(chrm * sincosval.x); + } + } + } + + JaggedArray blend(bfw, bfh); + buildBlendMask(lumreserv, blend, bfw, bfh, conthr); + const float rm = 20.f / sk; + + if (rm > 0) { + float **mb = blend; +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(mb, mb, bfw, bfh, rm); + } + } + + const std::unique_ptr> rdEBuffer(new JaggedArray(bfw, bfh)); + float** rdE = *(rdEBuffer.get()); + + deltaEforMask(rdE, bfw, bfh, bufreser.get(), hueref, chromaref, lumaref, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, mercol, lp.balance, lp.balanceh); + + if (lp.mergecolMethod == 0) { //normal + + if (lp.mergemet == 4) { + bufprov.reset(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + rdE[y][x] *= SQR(rdE[y][x]); + bufprov->L[y][x] = intp(rdE[y][x], bufcolreserv->L[y][x], bufcolfin->L[y][x]); + bufprov->a[y][x] = intp(rdE[y][x], bufcolreserv->a[y][x], bufcolfin->a[y][x]); + bufprov->b[y][x] = intp(rdE[y][x], bufcolreserv->b[y][x], bufcolfin->b[y][x]); + + bufcolfin->L[y][x] = intp(lp.opacol, bufprov->L[y][x], bufcolfin->L[y][x]); + bufcolfin->a[y][x] = intp(lp.opacol, bufprov->a[y][x], bufcolfin->a[y][x]); + bufcolfin->b[y][x] = intp(lp.opacol, bufprov->b[y][x], bufcolfin->b[y][x]); + } + } + } else { + bufprov.reset(new LabImage(bfw, bfh)); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufprov->L[y][x] = intp(rdE[y][x], bufcolfin->L[y][x], bufcolreserv->L[y][x]); + bufprov->a[y][x] = intp(rdE[y][x], bufcolfin->a[y][x], bufcolreserv->a[y][x]); + bufprov->b[y][x] = intp(rdE[y][x], bufcolfin->b[y][x], bufcolreserv->b[y][x]); + + bufcolfin->L[y][x] = intp(lp.opacol, bufprov->L[y][x], bufcolreserv->L[y][x]); + bufcolfin->a[y][x] = intp(lp.opacol, bufprov->a[y][x], bufcolreserv->a[y][x]); + bufcolfin->b[y][x] = intp(lp.opacol, bufprov->b[y][x], bufcolreserv->b[y][x]); + } + } + } + + if (conthr > 0.f && lp.mergemet != 4) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufcolfin->L[y][x] = intp(blend[y][x], bufcolfin->L[y][x], bufreser->L[y][x]); + bufcolfin->a[y][x] = intp(blend[y][x], bufcolfin->a[y][x], bufreser->a[y][x]); + bufcolfin->b[y][x] = intp(blend[y][x], bufcolfin->b[y][x], bufreser->b[y][x]); + } + } + } + } + + if (lp.mergecolMethod > 16) { //hue sat chroma luma + bufprov.reset(new LabImage(bfw, bfh)); + + if (lp.mergemet == 4) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + rdE[y][x] *= SQR(rdE[y][x]); + bufprov->L[y][x] = intp(rdE[y][x], bufcolreserv->L[y][x], bufcolfin->L[y][x]); + bufprov->a[y][x] = intp(rdE[y][x], bufcolreserv->a[y][x], bufcolfin->a[y][x]); + bufprov->b[y][x] = intp(rdE[y][x], bufcolreserv->b[y][x], bufcolfin->b[y][x]); + } + } + } else { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufprov->L[y][x] = intp(rdE[y][x], bufcolfin->L[y][x], bufcolreserv->L[y][x]); + bufprov->a[y][x] = intp(rdE[y][x], bufcolfin->a[y][x], bufcolreserv->a[y][x]); + bufprov->b[y][x] = intp(rdE[y][x], bufcolfin->b[y][x], bufcolreserv->b[y][x]); + } + } + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + if (lp.mergecolMethod == 17) { + const float huefin = xatan2f(bufprov->b[y][x], bufprov->a[y][x]); + const float2 sincosval1 = xsincosf(huefin); + const float chrores = std::sqrt(SQR(bufcolreserv->a[y][x]) + SQR(bufcolreserv->b[y][x])); + buftemp->a[y][x] = chrores * sincosval1.y; + buftemp->b[y][x] = chrores * sincosval1.x; + buftemp->L[y][x] = bufcolreserv->L[y][x]; + } else if (lp.mergecolMethod == 18) { + const float hueres = xatan2f(bufcolreserv->b[y][x], bufcolreserv->a[y][x]); + const float2 sincosval2 = xsincosf(hueres); + const float chrofin = std::sqrt(SQR(bufprov->a[y][x]) + SQR(bufprov->b[y][x])); + buftemp->a[y][x] = chrofin * sincosval2.y; + buftemp->b[y][x] = chrofin * sincosval2.x; + buftemp->L[y][x] = bufcolreserv->L[y][x]; + } else if (lp.mergecolMethod == 19) { + const float huefin = xatan2f(bufprov->b[y][x], bufprov->a[y][x]); + const float2 sincosval3 = xsincosf(huefin); + const float chrofin = std::sqrt(SQR(bufprov->a[y][x]) + SQR(bufprov->b[y][x])); + buftemp->a[y][x] = chrofin * sincosval3.y; + buftemp->b[y][x] = chrofin * sincosval3.x; + buftemp->L[y][x] = bufcolreserv->L[y][x]; + } else if (lp.mergecolMethod == 20) { + const float hueres = xatan2f(bufcolreserv->b[y][x], bufcolreserv->a[y][x]); + const float2 sincosval4 = xsincosf(hueres); + const float chrores = std::sqrt(SQR(bufcolreserv->a[y][x]) + SQR(bufcolreserv->b[y][x])); + buftemp->a[y][x] = chrores * sincosval4.y; + buftemp->b[y][x] = chrores * sincosval4.x; + buftemp->L[y][x] = bufprov->L[y][x]; + } + + if (lp.mergemet == 4) { + bufcolfin->L[y][x] = intp(lp.opacol, bufprov->L[y][x], bufcolfin->L[y][x]); + bufcolfin->a[y][x] = intp(lp.opacol, bufprov->a[y][x], bufcolfin->a[y][x]); + bufcolfin->b[y][x] = intp(lp.opacol, bufprov->b[y][x], bufcolfin->b[y][x]); + } else { + bufcolfin->L[y][x] = intp(lp.opacol, bufprov->L[y][x], bufcolreserv->L[y][x]); + bufcolfin->a[y][x] = intp(lp.opacol, bufprov->a[y][x], bufcolreserv->a[y][x]); + bufcolfin->b[y][x] = intp(lp.opacol, bufprov->b[y][x], bufcolreserv->b[y][x]); + } + } + } + + if (conthr > 0.f && lp.mergemet != 4) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufcolfin->L[y][x] = intp(blend[y][x], bufcolfin->L[y][x], bufcolreserv->L[y][x]); + bufcolfin->a[y][x] = intp(blend[y][x], bufcolfin->a[y][x], bufcolreserv->a[y][x]); + bufcolfin->b[y][x] = intp(blend[y][x], bufcolfin->b[y][x], bufcolreserv->b[y][x]); + } + } + } + } + + + if (lp.mergecolMethod > 0 && lp.mergecolMethod <= 16) { + //first deltaE +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufcolfin->L[y][x] = intp(rdE[y][x], bufcolfin->L[y][x], bufcolreserv->L[y][x]); + bufcolfin->a[y][x] = intp(rdE[y][x], bufcolfin->a[y][x], bufcolreserv->a[y][x]); + bufcolfin->b[y][x] = intp(rdE[y][x], bufcolfin->b[y][x], bufcolreserv->b[y][x]); + } + } + + //prepare RGB values in 0 1(or more)for current image and reserved + std::unique_ptr tmpImageorig(new Imagefloat(bfw, bfh)); + lab2rgb(*bufcolfin, *(tmpImageorig.get()), params->icm.workingProfile); + tmpImageorig->normalizeFloatTo1(); + + std::unique_ptr tmpImagereserv(new Imagefloat(bfw, bfh)); + lab2rgb(*bufcolreserv, *(tmpImagereserv.get()), params->icm.workingProfile); + tmpImagereserv->normalizeFloatTo1(); + + float minR = tmpImagereserv->r(0, 0); + float maxR = minR; + float minG = tmpImagereserv->g(0, 0); + float maxG = minG; + float minB = tmpImagereserv->b(0, 0); + float maxB = minB; + if (lp.mergecolMethod == 6 || lp.mergecolMethod == 9 || lp.mergecolMethod == 10 || lp.mergecolMethod == 11) { +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxR,maxG,maxB) reduction(min:minR,minG,minB) schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) { + for (int jr = 0; jr < bfw; jr++) { + minR = rtengine::min(minR, tmpImagereserv->r(ir, jr)); + maxR = rtengine::max(maxR, tmpImagereserv->r(ir, jr)); + minG = rtengine::min(minG, tmpImagereserv->g(ir, jr)); + maxG = rtengine::max(maxG, tmpImagereserv->g(ir, jr)); + minB = rtengine::min(minB, tmpImagereserv->b(ir, jr)); + maxB = rtengine::max(maxB, tmpImagereserv->b(ir, jr)); + } + } + } + + //various combinations subtract, multiply, difference, etc + if (lp.mergecolMethod == 1) { //subtract +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) {//LIM(x 0 2) 2 arbitrary value but limit... + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, tmpImageorig->r(y, x) - tmpImagereserv->r(y, x), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, tmpImageorig->g(y, x) - tmpImagereserv->g(y, x), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, tmpImageorig->b(y, x) - tmpImagereserv->b(y, x), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 2) { //difference +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, std::fabs(tmpImageorig->r(y, x) - tmpImagereserv->r(y, x)), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, std::fabs(tmpImageorig->g(y, x) - tmpImagereserv->g(y, x)), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, std::fabs(tmpImageorig->b(y, x) - tmpImagereserv->b(y, x)), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 3) { //multiply +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, tmpImageorig->r(y, x) * tmpImagereserv->r(y, x), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, tmpImageorig->g(y, x) * tmpImagereserv->g(y, x), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, tmpImageorig->b(y, x) * tmpImagereserv->b(y, x), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 4) { //addition +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, tmpImageorig->r(y, x) + tmpImagereserv->r(y, x), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, tmpImageorig->g(y, x) + tmpImagereserv->g(y, x), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, tmpImageorig->b(y, x) + tmpImagereserv->b(y, x), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 5) { //divide +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, tmpImageorig->r(y, x) / (tmpImagereserv->r(y, x) + 0.00001f), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, tmpImageorig->g(y, x) / (tmpImagereserv->g(y, x) + 0.00001f), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, tmpImageorig->b(y, x) / (tmpImagereserv->b(y, x) + 0.00001f), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 6) { //soft light as Photoshop +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, softlig(tmpImageorig->r(y, x), tmpImagereserv->r(y, x), minR, maxR), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, softlig(tmpImageorig->g(y, x), tmpImagereserv->g(y, x), minG, maxG), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, softlig(tmpImageorig->b(y, x), tmpImagereserv->b(y, x), minB, maxB), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 7) { //soft light as illusions.hu +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, softlig2(LIM01(tmpImageorig->r(y, x)), LIM01(tmpImageorig->r(y, x))), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, softlig2(LIM01(tmpImageorig->g(y, x)), LIM01(tmpImageorig->g(y, x))), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, softlig2(LIM01(tmpImageorig->b(y, x)), LIM01(tmpImageorig->b(y, x))), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 8) { //soft light as W3C +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, softlig3(LIM01(tmpImageorig->r(y, x)), tmpImagereserv->r(y, x)), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, softlig3(LIM01(tmpImageorig->g(y, x)), tmpImagereserv->g(y, x)), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, softlig3(LIM01(tmpImageorig->b(y, x)), tmpImagereserv->b(y, x)), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 9) { //hard light overlay (float &b, float &a) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, overlay(tmpImagereserv->r(y, x), tmpImageorig->r(y, x), minR, maxR), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, overlay(tmpImagereserv->g(y, x), tmpImageorig->g(y, x), minG, maxG), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, overlay(tmpImagereserv->b(y, x), tmpImageorig->b(y, x), minB, maxB), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 10) { //overlay overlay(float &a, float &b) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, overlay(tmpImageorig->r(y, x), tmpImagereserv->r(y, x), minR, maxR), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, overlay(tmpImageorig->g(y, x), tmpImagereserv->g(y, x), minG, maxG), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, overlay(tmpImageorig->b(y, x), tmpImagereserv->b(y, x), minB, maxB), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 11) { //screen screen (float &a, float &b) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, screen(tmpImageorig->r(y, x), tmpImagereserv->r(y, x), maxR), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, screen(tmpImageorig->g(y, x), tmpImagereserv->g(y, x), maxG), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, screen(tmpImageorig->b(y, x), tmpImagereserv->b(y, x), maxB), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 12) { //darken only +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, rtengine::min(tmpImageorig->r(y, x), tmpImagereserv->r(y, x)), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, rtengine::min(tmpImageorig->g(y, x), tmpImagereserv->g(y, x)), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, rtengine::min(tmpImageorig->b(y, x), tmpImagereserv->b(y, x)), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 13) { //lighten only +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, rtengine::max(tmpImageorig->r(y, x), tmpImagereserv->r(y, x)), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, rtengine::max(tmpImageorig->g(y, x), tmpImagereserv->g(y, x)), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, rtengine::max(tmpImageorig->b(y, x), tmpImagereserv->b(y, x)), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 14) { //exclusion exclusion (float &a, float &b) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, exclusion(tmpImageorig->r(y, x), tmpImagereserv->r(y, x)), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, exclusion(tmpImageorig->g(y, x), tmpImagereserv->g(y, x)), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, exclusion(tmpImageorig->b(y, x), tmpImagereserv->b(y, x)), tmpImageorig->b(y, x)); + } + } + + } else if (lp.mergecolMethod == 15) { //Color burn +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, colburn(LIM01(tmpImageorig->r(y, x)), LIM01(tmpImagereserv->r(y, x))), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, colburn(LIM01(tmpImageorig->g(y, x)), LIM01(tmpImagereserv->g(y, x))), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, colburn(LIM01(tmpImageorig->b(y, x)), LIM01(tmpImagereserv->b(y, x))), tmpImageorig->b(y, x)); + } + } + } else if (lp.mergecolMethod == 16) { //Color dodge +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = intp(lp.opacol, coldodge(LIM01(tmpImageorig->r(y, x)), LIM01(tmpImagereserv->r(y, x))), tmpImageorig->r(y, x)); + tmpImageorig->g(y, x) = intp(lp.opacol, coldodge(LIM01(tmpImageorig->g(y, x)), LIM01(tmpImagereserv->g(y, x))), tmpImageorig->g(y, x)); + tmpImageorig->b(y, x) = intp(lp.opacol, coldodge(LIM01(tmpImageorig->b(y, x)), LIM01(tmpImagereserv->b(y, x))), tmpImageorig->b(y, x)); + } + } + } + + tmpImageorig->normalizeFloatTo65535(); + rgb2lab(*tmpImageorig, *bufcolfin, params->icm.workingProfile); + + if (conthr > 0.f && lp.mergemet != 4) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + bufcolfin->L[y][x] = intp(blend[y][x], bufcolfin->L[y][x], bufcolreserv->L[y][x]); + bufcolfin->a[y][x] = intp(blend[y][x], bufcolfin->a[y][x], bufcolreserv->a[y][x]); + bufcolfin->b[y][x] = intp(blend[y][x], bufcolfin->b[y][x], bufcolreserv->b[y][x]); + } + } + } + } + + if (lp.softradiuscol > 0.f) { + softproc(bufcolreserv.get(), bufcolfin.get(), lp.softradiuscol, bfh, bfw, 0.0001, 0.00001, 0.1f, sk, multiThread, 1); + } + float meansob = 0.f; + transit_shapedetect2(call, 0, bufcolreserv.get(), bufcolfin.get(), originalmaskcol.get(), hueref, chromaref, lumaref, sobelref, meansob, blend2, lp, original, transformed, cx, cy, sk); + } + + if (!nottransit) { +//gradient + if (lp.strcol != 0.f) { + struct grad_params gp; + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, 3); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + const float corrFactor = ImProcFunctions::calcGradientFactor(gp, jr, ir); + bufcolfin->L[ir][jr] *= corrFactor; + } + } + + if (lp.strcolab != 0.f) { + struct grad_params gpab; + calclocalGradientParams(lp, gpab, ystart, xstart, bfw, bfh, 5); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + const float corrFactor = ImProcFunctions::calcGradientFactor(gpab, jr, ir); + bufcolfin->a[ir][jr] *= corrFactor; + bufcolfin->b[ir][jr] *= corrFactor; + } + } + + if (lp.strcolh != 0.f) { + struct grad_params gph; + calclocalGradientParams(lp, gph, ystart, xstart, bfw, bfh, 6); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int ir = 0; ir < bfh; ir++) + for (int jr = 0; jr < bfw; jr++) { + const float corrFactor = ImProcFunctions::calcGradientFactor(gph, jr, ir); + const float aa = bufcolfin->a[ir][jr]; + const float bb = bufcolfin->b[ir][jr]; + const float chrm = std::sqrt(SQR(aa) + SQR(bb)); + const float HH = xatan2f(bb, aa); + + float cor = 0.f; + + if (corrFactor < 1.f) { + cor = - 2.5f * (1.f - corrFactor); + } else if (corrFactor > 1.f) { + cor = 0.03f * (corrFactor - 1.f); + } + + float newhr = HH + cor; + + if (newhr > rtengine::RT_PI_F) { + newhr -= 2 * rtengine::RT_PI_F; + } else if (newhr < -rtengine::RT_PI_F) { + newhr += 2 * rtengine::RT_PI_F; + } + + const float2 sincosval = xsincosf(newhr); + bufcolfin->a[ir][jr] = clipC(chrm * sincosval.y); + bufcolfin->b[ir][jr] = clipC(chrm * sincosval.x); + } + } + + + if (lp.softradiuscol > 0.f) { + softproc(bufcolorig.get(), bufcolfin.get(), lp.softradiuscol, bfh, bfw, 0.0001, 0.00001, 0.1f, sk, multiThread, 1); + } + float meansob = 0.f; + transit_shapedetect2(call, 0, bufcolorig.get(), bufcolfin.get(), originalmaskcol.get(), hueref, chromaref, lumaref, sobelref, meansob, blend2, lp, original, transformed, cx, cy, sk); + } + + } + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + + } + } + } + +//inverse + else if (lp.inv && (lp.chro != 0 || lp.ligh != 0 || exlocalcurve || lp.showmaskcolmetinv == 0 || lp.enaColorMaskinv) && lp.colorena) { + float adjustr = 1.0f; + +//adapt chroma to working profile + if (params->icm.workingProfile == "ProPhoto") { + adjustr = 1.2f; // 1.2 instead 1.0 because it's very rare to have C>170.. + } else if (params->icm.workingProfile == "Adobe RGB") { + adjustr = 1.8f; + } else if (params->icm.workingProfile == "sRGB") { + adjustr = 2.0f; + } else if (params->icm.workingProfile == "WideGamut") { + adjustr = 1.2f; + } else if (params->icm.workingProfile == "Beta RGB") { + adjustr = 1.4f; + } else if (params->icm.workingProfile == "BestRGB") { + adjustr = 1.4f; + } else if (params->icm.workingProfile == "BruceRGB") { + adjustr = 1.8f; + } + + std::unique_ptr bufmaskblurcol; + std::unique_ptr originalmaskcol; + const std::unique_ptr bufcolorig(new LabImage(GW, GH)); + + if (lp.enaColorMaskinv || lp.showmaskcolmetinv == 1) { + bufmaskblurcol.reset(new LabImage(GW, GH, true)); + originalmaskcol.reset(new LabImage(GW, GH)); + } + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + bufcolorig->L[y][x] = original->L[y][x]; + } + } + + constexpr int inv = 1; + const bool showmaske = lp.showmaskcolmetinv == 1; + const bool enaMask = lp.enaColorMaskinv; + constexpr bool deltaE = false; + constexpr bool modmask = false; + const bool zero = lp.showmaskcolmetinv == 0; + constexpr bool modif = false; + + const float chrom = lp.chromacol; + const float rad = lp.radmacol; + const float gamma = lp.gammacol; + const float slope = lp.slomacol; + const float blendm = lp.blendmacol; + const float lap = params->locallab.spots.at(sp).lapmaskcol; + const bool pde = params->locallab.spots.at(sp).laplac; + int shado = params->locallab.spots.at(sp).shadmaskcol; + int level_bl = params->locallab.spots.at(sp).csthresholdcol.getBottomLeft(); + int level_hl = params->locallab.spots.at(sp).csthresholdcol.getTopLeft(); + int level_br = params->locallab.spots.at(sp).csthresholdcol.getBottomRight(); + int level_hr = params->locallab.spots.at(sp).csthresholdcol.getTopRight(); + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = lp.mergemet; //params->locallab.spots.at(sp).shortc; + int lumask = params->locallab.spots.at(sp).lumask; + float strumask = 0.02f * params->locallab.spots.at(sp).strumaskcol; + + const float mindE = 2.f + MINSCOPE * sco * lp.thr; + const float maxdE = 5.f + MAXSCOPE * sco * (1 + 0.1f * lp.thr); + const float mindElim = 2.f + MINSCOPE * limscope * lp.thr; + const float maxdElim = 5.f + MAXSCOPE * limscope * (1 + 0.1f * lp.thr); + constexpr float amountcd = 0.f; + constexpr float anchorcd = 50.f; + + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, reserved, inv, lp, + strumask, params->locallab.spots.at(sp).toolcol, + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, shado, amountcd, anchorcd, lmasklocalcurve, localmaskutili, loclmasCurvecolwav, lmasutilicolwav, + level_bl, level_hl, level_br, level_hr, + shortcu, false, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco + ); + + if (lp.showmaskcolmetinv == 1) { + showmask(lumask, lp, 0, 0, cx, cy, GW, GH, bufcolorig.get(), transformed, bufmaskblurcol.get(), inv); + return; + } + + if (lp.showmaskcolmetinv == 0 || lp.enaColorMaskinv) { + InverseColorLight_Local(false, false, sp, 0, lp, originalmaskcol.get(), lightCurveloc, hltonecurveloc, shtonecurveloc, tonecurveloc, exlocalcurve, cclocalcurve, adjustr, localcutili, lllocalcurve, locallutili, original, transformed, cx, cy, hueref, chromaref, lumaref, sk); + + if (params->locallab.spots.at(sp).recurs) { + original->CopyFrom(transformed, multiThread); + float avge; + calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); + } + } + } + +// Gamut and Munsell control - very important do not deactivated to avoid crash + if (params->locallab.spots.at(sp).avoid) { + const float ach = lp.trans / 100.f; + + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); + const float wip[3][3] = { + {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, + {static_cast(wiprof[1][0]), static_cast(wiprof[1][1]), static_cast(wiprof[1][2])}, + {static_cast(wiprof[2][0]), static_cast(wiprof[2][1]), static_cast(wiprof[2][2])} + }; + const bool highlight = params->toneCurve.hrenabled; + const bool needHH = (lp.chro != 0.f); +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + float atan2Buffer[transformed->W] ALIGNED16; + float sqrtBuffer[transformed->W] ALIGNED16; + float sincosyBuffer[transformed->W] ALIGNED16; + float sincosxBuffer[transformed->W] ALIGNED16; + vfloat c327d68v = F2V(327.68f); + vfloat onev = F2V(1.f); +#endif + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + for (int y = 0; y < transformed->H; y++) { + const int loy = cy + y; + const bool isZone0 = loy > lp.yc + lp.ly || loy < lp.yc - lp.lyT; // whole line is zone 0 => we can skip a lot of processing + + if (isZone0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + +#ifdef __SSE2__ + int i = 0; + + for (; i < transformed->W - 3; i += 4) { + vfloat av = LVFU(transformed->a[y][i]); + vfloat bv = LVFU(transformed->b[y][i]); + + if (needHH) { // only do expensive atan2 calculation if needed + STVF(atan2Buffer[i], xatan2f(bv, av)); + } + + vfloat Chprov1v = vsqrtf(SQRV(bv) + SQRV(av)); + STVF(sqrtBuffer[i], Chprov1v / c327d68v); + vfloat sincosyv = av / Chprov1v; + vfloat sincosxv = bv / Chprov1v; + vmask selmask = vmaskf_eq(Chprov1v, ZEROV); + sincosyv = vself(selmask, onev, sincosyv); + sincosxv = vselfnotzero(selmask, sincosxv); + STVF(sincosyBuffer[i], sincosyv); + STVF(sincosxBuffer[i], sincosxv); + } + + for (; i < transformed->W; i++) { + float aa = transformed->a[y][i]; + float bb = transformed->b[y][i]; + + if (needHH) { // only do expensive atan2 calculation if needed + atan2Buffer[i] = xatan2f(bb, aa); + } + + float Chprov1 = std::sqrt(SQR(bb) + SQR(aa)); + sqrtBuffer[i] = Chprov1 / 327.68f; + + if (Chprov1 == 0.0f) { + sincosyBuffer[i] = 1.f; + sincosxBuffer[i] = 0.0f; + } else { + sincosyBuffer[i] = aa / Chprov1; + sincosxBuffer[i] = bb / Chprov1; + } + } + +#endif + + for (int x = 0; x < transformed->W; x++) { + int lox = cx + x; + int zone; + float localFactor = 1.f; + + if (lp.shapmet == 0) { + calcTransition(lox, loy, ach, lp, zone, localFactor); + } else /*if (lp.shapmet == 1)*/ { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + + if (zone == 0) { // outside selection and outside transition zone => no effect, keep original values + continue; + } + + float Lprov1 = transformed->L[y][x] / 327.68f; + float2 sincosval; +#ifdef __SSE2__ + float HH = atan2Buffer[x]; // reading HH from line buffer even if line buffer is not filled is faster than branching + float Chprov1 = sqrtBuffer[x]; + sincosval.y = sincosyBuffer[x]; + sincosval.x = sincosxBuffer[x]; + float chr = 0.f; + +#else + const float aa = transformed->a[y][x]; + const float bb = transformed->b[y][x]; + float HH = 0.f, chr = 0.f; + + if (needHH) { // only do expensive atan2 calculation if needed + HH = xatan2f(bb, aa); + } + + float Chprov1 = std::sqrt(SQR(aa) + SQR(bb)) / 327.68f; + + if (Chprov1 == 0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } else { + sincosval.y = aa / (Chprov1 * 327.68f); + sincosval.x = bb / (Chprov1 * 327.68f); + } +#endif + + Color::pregamutlab(Lprov1, HH, chr); + Chprov1 = rtengine::min(Chprov1, chr); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.92f); + transformed->L[y][x] = Lprov1 * 327.68f; + transformed->a[y][x] = 327.68f * Chprov1 * sincosval.y; + transformed->b[y][x] = 327.68f * Chprov1 * sincosval.x; + + if (needHH) { + const float Lprov2 = original->L[y][x] / 327.68f; + float correctionHue = 0.f; // Munsell's correction + float correctlum = 0.f; + const float memChprov = std::sqrt(SQR(original->a[y][x]) + SQR(original->b[y][x])) / 327.68f; + float Chprov = std::sqrt(SQR(transformed->a[y][x]) + SQR(transformed->b[y][x])) / 327.68f; + Color::AllMunsellLch(true, Lprov1, Lprov2, HH, Chprov, memChprov, correctionHue, correctlum); + + if (std::fabs(correctionHue) < 0.015f) { + HH += correctlum; // correct only if correct Munsell chroma very little. + } + + sincosval = xsincosf(HH + correctionHue); + transformed->a[y][x] = 327.68f * Chprov * sincosval.y; // apply Munsell + transformed->b[y][x] = 327.68f * Chprov * sincosval.x; + } + } + } + } + } + +} + +} diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 6768eca93..02d04c270 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -45,21 +45,68 @@ #include "curves.h" #include "gauss.h" #include "improcfun.h" -#include "jaggedarray.h" +#include "labimage.h" #include "median.h" #include "opthelper.h" #include "procparams.h" #include "rawimagesource.h" #include "rtengine.h" #include "shmap.h" +#define BENCHMARK #include "StopWatch.h" +#include "guidedfilter.h" + +#define clipretinex( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val ) +#define CLIPLOC(x) LIM(x,0.f,32767.f) +#define CLIPC(a) LIM(a, -42000.f, 42000.f) // limit a and b to 130 probably enough ? namespace { -void retinex_scales( float* scales, int nscales, int mode, int s, float high) + +void calcGammaLut(double gamma, double ts, LUTf &gammaLut) { - if ( nscales == 1 ) { - scales[0] = (float)s / 2.f; + double pwr = 1.0 / gamma; + double gamm = gamma; + const double gamm2 = gamma; + rtengine::GammaValues g_a; + + if (gamm2 < 1.0) { + std::swap(pwr, gamm); + } + + rtengine::Color::calcGamma(pwr, ts, 0, g_a); // call to calcGamma with selected gamma and slope + + const double start = gamm2 < 1. ? g_a[2] : g_a[3]; + const double add = g_a[4]; + const double mul = 1.0 + g_a[4]; + + if (gamm2 < 1.) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 1024) +#endif + for (int i = 0; i < 65536; i++) { + const double x = rtengine::Color::igammareti(i / 65535.0, gamm, start, ts, mul, add); + gammaLut[i] = 0.5 * rtengine::CLIP(x * 65535.0); // CLIP avoid in some case extra values + } + } else { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 1024) +#endif + for (int i = 0; i < 65536; i++) { + const double x = rtengine::Color::gammareti(i / 65535.0, gamm, start, ts, mul, add); + gammaLut[i] = 0.5 * rtengine::CLIP(x * 65535.0); // CLIP avoid in some case extra values + } + } +} + +void retinex_scales(float* scales, int nscales, int mode, int s, float high) +{ + if (s < 3) { + s = 3; //to avoid crash in MSRlocal if nei small + } + + if (nscales == 1) { + scales[0] = (float)s / 2.f; } else if (nscales == 2) { scales[1] = (float) s / 2.f; scales[0] = (float) s; @@ -67,32 +114,32 @@ void retinex_scales( float* scales, int nscales, int mode, int s, float high) float size_step = (float) s / (float) nscales; if (mode == 0) { - for (int i = 0; i < nscales; ++i ) { + for (int i = 0; i < nscales; ++i) { scales[nscales - i - 1] = 2.0f + (float)i * size_step; } } else if (mode == 1) { size_step = (float)log(s - 2.0f) / (float) nscales; - for (int i = 0; i < nscales; ++i ) { - scales[nscales - i - 1] = 2.0f + (float)pow (10.f, (i * size_step) / log (10.f)); + for (int i = 0; i < nscales; ++i) { + scales[nscales - i - 1] = 2.0f + (float)pow(10.f, (i * size_step) / log(10.f)); } } else if (mode == 2) { size_step = (float) log(s - 2.0f) / (float) nscales; - for ( int i = 0; i < nscales; ++i ) { - scales[i] = s - (float)pow (10.f, (i * size_step) / log (10.f)); + for (int i = 0; i < nscales; ++i) { + scales[i] = s - (float)pow(10.f, (i * size_step) / log(10.f)); } } else if (mode == 3) { size_step = (float) log(s - 2.0f) / (float) nscales; - for ( int i = 0; i < nscales; ++i ) { - scales[i] = high * s - (float)pow (10.f, (i * size_step) / log (10.f)); + for (int i = 0; i < nscales; ++i) { + scales[i] = high * s - (float)pow(10.f, (i * size_step) / log(10.f)); } } } } -void mean_stddv2( float **dst, float &mean, float &stddv, int W_L, int H_L, float &maxtr, float &mintr) +void mean_stddv2(float **dst, float &mean, float &stddv, int W_L, int H_L, float &maxtr, float &mintr) { // summation using double precision to avoid too large summation error for large pictures double vsquared = 0.f; @@ -108,7 +155,7 @@ void mean_stddv2( float **dst, float &mean, float &stddv, int W_L, int H_L, floa #pragma omp for reduction(+:sum,vsquared) nowait // this leads to differences, but parallel summation is more accurate #endif - for (int i = 0; i < H_L; i++ ) + for (int i = 0; i < H_L; i++) for (int j = 0; j < W_L; j++) { sum += static_cast(dst[i][j]); vsquared += rtengine::SQR(dst[i][j]); @@ -126,7 +173,7 @@ void mean_stddv2( float **dst, float &mean, float &stddv, int W_L, int H_L, floa } } - mean = sum / (double) (W_L * H_L); + mean = sum / (double)(W_L * H_L); vsquared /= (double) W_L * H_L; stddv = vsquared - rtengine::SQR(mean); stddv = std::sqrt(stddv); @@ -140,7 +187,8 @@ namespace rtengine void RawImageSource::MSR(float** luminance, float** originalLuminance, float **exLuminance, const LUTf& mapcurve, bool mapcontlutili, int width, int height, const procparams::RetinexParams &deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) { -BENCHFUN + BENCHFUN + if (!deh.enabled) { return; } @@ -184,7 +232,7 @@ BENCHFUN bool higplus = false ; int moderetinex = 2; // default to 2 ( deh.retinexMethod == "high" ) - if(deh.retinexMethod == "highliplus") { + if (deh.retinexMethod == "highliplus") { higplus = true; moderetinex = 3; } else if (deh.retinexMethod == "uni") { @@ -249,6 +297,7 @@ BENCHFUN //adjust sc in function of choice of scale by user if iterations if (scal < 3) { sc -= 1; + if (sc < 1.f) {//avoid 0 sc = 1.f; } @@ -324,11 +373,11 @@ BENCHFUN int mapmet = 0; - if(deh.mapMethod == "map") { + if (deh.mapMethod == "map") { mapmet = 2; - } else if(deh.mapMethod == "mapT") { + } else if (deh.mapMethod == "mapT") { mapmet = 3; - } else if(deh.mapMethod == "gaus") { + } else if (deh.mapMethod == "gaus") { mapmet = 4; } @@ -336,13 +385,13 @@ BENCHFUN int viewmet = 0; - if(deh.viewMethod == "mask") { + if (deh.viewMethod == "mask") { viewmet = 1; - } else if(deh.viewMethod == "tran") { + } else if (deh.viewMethod == "tran") { viewmet = 2; - } else if(deh.viewMethod == "tran2") { + } else if (deh.viewMethod == "tran2") { viewmet = 3; - } else if(deh.viewMethod == "unsharp") { + } else if (deh.viewMethod == "unsharp") { viewmet = 4; } @@ -365,16 +414,18 @@ BENCHFUN const float logBetaGain = xlogf(16384.f); float pond = logBetaGain / (float) scal; - if(!useHslLin) { + if (!useHslLin) { pond /= log(elogt); } std::unique_ptr shmap; + if (((mapmet == 2 || mapmet == 3 || mapmet == 4) && it == 1)) { shmap.reset(new SHMap(W_L, H_L)); } std::unique_ptr buffer; + if (mapmet > 0) { buffer.reset(new float[W_L * H_L]); } @@ -384,7 +435,7 @@ BENCHFUN gaussianBlur(src, out, W_L, H_L, RetinexScales[scale], true); } else { // reuse result of last iteration // out was modified in last iteration => restore it - if((((mapmet == 2 && scale > 1) || mapmet == 3 || mapmet == 4) || (mapmet > 0 && mapcontlutili)) && it == 1) { + if ((((mapmet == 2 && scale > 1) || mapmet == 3 || mapmet == 4) || (mapmet > 0 && mapcontlutili)) && it == 1) { #ifdef _OPENMP #pragma omp parallel for #endif @@ -411,8 +462,10 @@ BENCHFUN } } } + int h_th = 0; int s_th = 0; + if (((mapmet == 2 && scale > 2) || mapmet == 3 || mapmet == 4) && it == 1) { shmap->updateL(out, shradius, true, 1); h_th = shmap->max_f - deh.htonalwidth * (shmap->max_f - shmap->avg) / 100; @@ -468,7 +521,8 @@ BENCHFUN const vfloat pondv = F2V(pond); const vfloat limMinv = F2V(ilimdx); const vfloat limMaxv = F2V(limdx); - if( useHslLin) { + + if (useHslLin) { for (; j < W_L - 3; j += 4) { STVFU(luminance[i][j], LVFU(luminance[i][j]) + pondv * vclampf(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv)); } @@ -480,7 +534,7 @@ BENCHFUN #endif - if(useHslLin) { + if (useHslLin) { for (; j < W_L; j++) { luminance[i][j] += pond * LIM(src[i][j] / out[i][j], ilimdx, limdx); } @@ -522,9 +576,10 @@ BENCHFUN #pragma omp parallel for schedule(dynamic,16) #endif - for (int i = 0; i < H_L; i++ ) { + for (int i = 0; i < H_L; i++) { for (int j = 0; j < W_L; j++) { //for mintr to maxtr evalate absciss in function of original transmission float absciss; + if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { absciss = asig * luminance[i][j] + bsig; } else if (luminance[i][j] >= mean) { @@ -536,7 +591,7 @@ BENCHFUN //TODO : move multiplication by 4.f and subtraction of 1.f inside the curve luminance[i][j] *= (-1.f + 4.f * dehatransmissionCurve[absciss]); //new transmission - if(viewmet == 3 || viewmet == 2) { + if (viewmet == 3 || viewmet == 2) { tran[i][j] = luminance[i][j]; } } @@ -561,7 +616,7 @@ BENCHFUN #pragma omp parallel for #endif - for (int i = borderL; i < H_L - borderL; i++ ) { + for (int i = borderL; i < H_L - borderL; i++) { for (int j = borderL; j < W_L - borderL; j++) { luminance[i][j] = tmL[i][j]; } @@ -590,7 +645,7 @@ BENCHFUN 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 ) { + if (!delta) { delta = 1.0f; } @@ -642,7 +697,7 @@ BENCHFUN #pragma omp parallel for reduction(max:maxCD) reduction(min:minCD) schedule(dynamic, 16) #endif - for ( int i = 0; i < H_L; i ++ ) { + for (int i = 0; i < H_L; i ++) { for (int j = 0; j < W_L; j++) { float gan; @@ -677,7 +732,7 @@ BENCHFUN const float HH = exLuminance[i][j]; float valparam; - if(useHsl || useHslLin) { + if (useHsl || useHslLin) { valparam = shcurve->getVal(HH) - 0.5; } else { valparam = shcurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5; @@ -698,7 +753,7 @@ BENCHFUN } else if (viewmet == 4) { luminance[i][j] = originalLuminance[i][j] + str * (originalLuminance[i][j] - out[i][j]);//unsharp } else if (viewmet == 2) { - if(tran[i][j] <= mean) { + if (tran[i][j] <= mean) { luminance[i][j] = azb + aza * tran[i][j]; //auto values } else { luminance[i][j] = bzb + bza * tran[i][j]; @@ -722,4 +777,884 @@ BENCHFUN } } + +void ImProcFunctions::maskforretinex(int sp, int before, float ** luminance, float ** out, int W_L, int H_L, int skip, + const LocCCmaskCurve & locccmasretiCurve, bool &lcmasretiutili, const LocLLmaskCurve & locllmasretiCurve, bool &llmasretiutili, const LocHHmaskCurve & lochhmasretiCurve, bool & lhmasretiutili, + int llretiMask, bool retiMasktmap, bool retiMask, float rad, float lap, bool pde, float gamm, float slop, float chro, float blend, + LUTf & lmaskretilocalcurve, bool & localmaskretiutili, + LabImage * bufreti, LabImage * bufmask, LabImage * buforig, LabImage * buforigmas, bool multiThread, + bool delt, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh, float lumask) +{ + array2D loctemp(W_L, H_L); + array2D ble(W_L, H_L); + array2D blechro(W_L, H_L); + array2D hue(W_L, H_L); + array2D guid(W_L, H_L); + std::unique_ptr bufmaskblurreti; + bufmaskblurreti.reset(new LabImage(W_L, H_L)); + std::unique_ptr bufmaskorigreti; + bufmaskorigreti.reset(new LabImage(W_L, H_L)); + std::unique_ptr bufprov; + bufprov.reset(new LabImage(W_L, H_L)); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + if (before == 1 && retiMasktmap) { + loctemp[y][x] = LIM(luminance[y][x], 0.f, 32768.f); + } else if (before == 0 && retiMasktmap) { + loctemp[y][x] = out[y][x]; + } else { + loctemp[y][x] = bufreti->L[y][x]; + } + } + } + + float chromult = 1.f - 0.01f * chro; +//fab + float fab = 50.f; + float meanfab = 0.f; + const int nbfab = W_L * H_L; + + double sumab = 0.0; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:sumab) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + sumab += fabs(bufreti->a[y][x]); + sumab += fabs(bufreti->b[y][x]); + } + } + + meanfab = sumab / (2.f * nbfab); + double som = 0.0; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:som) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + som += SQR(fabs(bufreti->a[y][x]) - meanfab) + SQR(fabs(bufreti->b[y][x]) - meanfab); + } + } + const float multsigma = (chro >= 0.f ? 0.035f : 0.018f) * chro + 1.f; + const float stddv = sqrt(som / nbfab); + fab = meanfab + multsigma * stddv; + + if (fab <= 0.f) { + fab = 50.f; + } +//end fab + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int ir = 0; ir < H_L; ir++) { + for (int jr = 0; jr < W_L; jr++) { + float kmaskLexp = 0; + float kmaskCH = 0; + + if (locllmasretiCurve && llmasretiutili) { + float ligh = loctemp[ir][jr] / 32768.f; + kmaskLexp = 32768.f * LIM01(1.f - locllmasretiCurve[500.f * ligh]); + + } + + + if (locllmasretiCurve && llmasretiutili && retiMasktmap) { + } + + if (llretiMask != 4) { + if (locccmasretiCurve && lcmasretiutili) { + float chromask = 0.0001f + sqrt(SQR((bufreti->a[ir][jr]) / fab) + SQR((bufreti->b[ir][jr]) / fab)); + kmaskCH = LIM01(1.f - locccmasretiCurve[500.f * chromask]); + } + } + + if (lochhmasretiCurve && lhmasretiutili) { + float huema = xatan2f(bufreti->b[ir][jr], bufreti->a[ir][jr]); + float h = Color::huelab_to_huehsv2(huema); + h += 1.f / 6.f; + + if (h > 1.f) { + h -= 1.f; + } + + float valHH = LIM01(1.f - lochhmasretiCurve[500.f * h]); + + if (llretiMask != 4) { + kmaskCH += chromult * valHH; + } + + kmaskLexp += 32768.f * valHH; + } + + bufmaskblurreti->L[ir][jr] = kmaskLexp; + bufmaskblurreti->a[ir][jr] = kmaskCH; + bufmaskblurreti->b[ir][jr] = kmaskCH; + ble[ir][jr] = bufmaskblurreti->L[ir][jr] / 32768.f; + hue[ir][jr] = xatan2f(bufmaskblurreti->b[ir][jr], bufmaskblurreti->a[ir][jr]); + float chromah = sqrt(SQR(bufmaskblurreti->b[ir][jr]) + SQR(bufmaskblurreti->a[ir][jr])); + blechro[ir][jr] = chromah / 32768.f; + guid[ir][jr] = bufreti->L[ir][jr] / 32768.f; + bufprov->L[ir][jr] = bufmaskblurreti->L[ir][jr]; + bufprov->a[ir][jr] = bufmaskblurreti->a[ir][jr]; + bufprov->b[ir][jr] = bufmaskblurreti->b[ir][jr]; + + } + } + + if (rad != 0.f) { +// guidedFilter(guid, ble, ble, rad * 10.f / skip, 0.001, multiThread, 4); + float blur = rad; + blur = blur < 0.f ? -1.f / blur : 1.f + blur; + int r1 = max(int(4 / skip * blur + 0.5), 1); + int r2 = max(int(25 / skip * blur + 0.5), 1); + + double epsilmax = 0.0005; + double epsilmin = 0.00001; + + double aepsil = (epsilmax - epsilmin) / 90.f; + double bepsil = epsilmax - 100.f * aepsil; + double epsil = aepsil * 0.1 * rad + bepsil; + if (rad < 0.f) { + epsil = 0.001; + } + rtengine::guidedFilter(guid, blechro, blechro, r1, epsil, multiThread); + rtengine::guidedFilter(guid, ble, ble, r2, 0.2 * epsil, multiThread); + + } + + LUTf lutTonemaskreti(65536); + calcGammaLut(gamm, slop, lutTonemaskreti); + float radiusb = 1.f / skip; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int ir = 0; ir < H_L; ir++) + for (int jr = 0; jr < W_L; jr++) { + float L_; + float2 sincosval = xsincosf(hue[ir][jr]); + bufmaskblurreti->L[ir][jr] = LIM01(ble[ir][jr]) * 32768.f; + L_ = 2.f * bufmaskblurreti->L[ir][jr]; + bufmaskblurreti->L[ir][jr] = lutTonemaskreti[L_]; + bufmaskblurreti->a[ir][jr] = 32768.f * sincosval.y * blechro[ir][jr]; + bufmaskblurreti->b[ir][jr] = 32768.f * sincosval.x * blechro[ir][jr]; + } + + if (lmaskretilocalcurve && localmaskretiutili) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int ir = 0; ir < H_L; ir++) + for (int jr = 0; jr < W_L; jr++) { + bufmaskblurreti->L[ir][jr] = 0.5f * lmaskretilocalcurve[2.f * bufmaskblurreti->L[ir][jr]]; + } + } + + + if (delt) { + float *rdE[H_L] ALIGNED16; + float *rdEBuffer = new float[H_L * W_L]; + + for (int i = 0; i < H_L; i++) { + rdE[i] = &rdEBuffer[i * W_L]; + } + + deltaEforMask(rdE, W_L, H_L, bufreti, hueref, chromaref, lumaref, maxdE, mindE, maxdElim, mindElim, iterat, limscope, scope, balance, balanceh); + // printf("rde1=%f rde2=%f\n", rdE[1][1], rdE[100][100]); + std::unique_ptr delta(new LabImage(W_L, H_L)); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int ir = 0; ir < H_L; ir++) + for (int jr = 0; jr < W_L; jr++) { + delta->L[ir][jr] = bufmaskblurreti->L[ir][jr] - bufprov->L[ir][jr]; + delta->a[ir][jr] = bufmaskblurreti->a[ir][jr] - bufprov->a[ir][jr]; + delta->b[ir][jr] = bufmaskblurreti->b[ir][jr] - bufprov->b[ir][jr]; + + bufmaskblurreti->L[ir][jr] = bufprov->L[ir][jr] + rdE[ir][jr] * delta->L[ir][jr]; + bufmaskblurreti->a[ir][jr] = bufprov->a[ir][jr] + rdE[ir][jr] * delta->a[ir][jr]; + bufmaskblurreti->b[ir][jr] = bufprov->b[ir][jr] + rdE[ir][jr] * delta->b[ir][jr]; + } + + delete [] rdEBuffer; + + } + + + if (lap > 0.f) { + float *datain = new float[H_L * W_L]; + float *data_tmp = new float[H_L * W_L]; + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + datain[y * W_L + x] = bufmaskblurreti->L[y][x]; + } + } + + if (!pde) { + ImProcFunctions::discrete_laplacian_threshold(data_tmp, datain, W_L, H_L, 200.f * lap); + } else { + ImProcFunctions::retinex_pde(datain, data_tmp, W_L, H_L, 12.f * lap, 1.f, nullptr, 0, 0, 1); + } + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + bufmaskblurreti->L[y][x] = data_tmp[y * W_L + x]; + } + } + + delete [] datain; + delete [] data_tmp; + + } + +//blend +#ifdef _OPENMP + #pragma omp parallel +#endif + { + gaussianBlur(bufmaskblurreti->L, bufmaskorigreti->L, W_L, H_L, radiusb); + gaussianBlur(bufmaskblurreti->a, bufmaskorigreti->a, W_L, H_L, 1.f + (0.5f * rad) / skip); + gaussianBlur(bufmaskblurreti->b, bufmaskorigreti->b, W_L, H_L, 1.f + (0.5f * rad) / skip); + } + + float modr = 0.01f * (float) blend; + + if (llretiMask != 3 && retiMask) { +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + if (before == 0 && retiMasktmap) { + out[y][x] += fabs(modr) * bufmaskorigreti->L[y][x]; + out[y][x] = LIM(out[y][x], 0.f, 100000.f); + } else { + bufreti->L[y][x] += bufmaskorigreti->L[y][x] * modr; + bufreti->L[y][x] = CLIPLOC(bufreti->L[y][x]); + + } + + bufreti->a[y][x] *= (1.f + bufmaskorigreti->a[y][x] * modr * (1.f + 0.01f * chro)); + bufreti->b[y][x] *= (1.f + bufmaskorigreti->b[y][x] * modr * (1.f + 0.01f * chro)); + bufreti->a[y][x] = CLIPC(bufreti->a[y][x]); + bufreti->b[y][x] = CLIPC(bufreti->b[y][x]); + } + } + + + } + + if (!retiMasktmap && retiMask) { //new original blur mask for deltaE +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + + buforig->L[y][x] += (modr * bufmaskorigreti->L[y][x]); + buforig->a[y][x] *= (1.f + modr * bufmaskorigreti->a[y][x]); + buforig->b[y][x] *= (1.f + modr * bufmaskorigreti->b[y][x]); + + buforig->L[y][x] = CLIP(buforig->L[y][x]); + buforig->a[y][x] = CLIPC(buforig->a[y][x]); + buforig->b[y][x] = CLIPC(buforig->b[y][x]); + + buforig->L[y][x] = CLIP(buforig->L[y][x] - bufmaskorigreti->L[y][x]); + buforig->a[y][x] = CLIPC(buforig->a[y][x] * (1.f - bufmaskorigreti->a[y][x])); + buforig->b[y][x] = CLIPC(buforig->b[y][x] * (1.f - bufmaskorigreti->b[y][x])); + } + } + + float radius = 3.f / skip; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(buforig->L, buforigmas->L, W_L, H_L, radius); + gaussianBlur(buforig->a, buforigmas->a, W_L, H_L, radius); + gaussianBlur(buforig->b, buforigmas->b, W_L, H_L, radius); + } + + } + + + if (llretiMask == 3) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + bufmask->L[y][x] = (lumask * 400.f) + CLIPLOC(bufmaskorigreti->L[y][x]); + bufmask->a[y][x] = CLIPC(bufreti->a[y][x] * bufmaskorigreti->a[y][x]); + bufmask->b[y][x] = CLIPC(bufreti->b[y][x] * bufmaskorigreti->b[y][x]); + } + } + } + +} + + + +void ImProcFunctions::MSRLocal(int call, int sp, bool fftw, int lum, float** reducDE, LabImage * bufreti, LabImage * bufmask, LabImage * buforig, LabImage * buforigmas, float** luminance, const float* const *originalLuminance, + const int width, const int height, int bfwr, int bfhr, const procparams::LocallabParams &loc, const int skip, const LocretigainCurve &locRETgainCcurve, const LocretitransCurve &locRETtransCcurve, + const int chrome, const int scall, const float krad, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, + const LocCCmaskCurve & locccmasretiCurve, bool &lcmasretiutili, const LocLLmaskCurve & locllmasretiCurve, bool &llmasretiutili, const LocHHmaskCurve & lochhmasretiCurve, bool & lhmasretiutili, int llretiMask, + LUTf & lmaskretilocalcurve, bool & localmaskretiutili, + LabImage * transformed, bool retiMasktmap, bool retiMask, + bool delt, const float hueref, const float chromaref, const float lumaref, + float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh, float lumask) + +{ + BENCHFUN + bool py = true; + + if (py) {//enabled + float mean, stddv, maxtr, mintr; + mean = 0.f; + stddv = 0.f; + maxtr = 0.f; + mintr = 0.f; + float delta; + constexpr float eps = 2.f; + bool useHslLin = false; + const float offse = loc.spots.at(sp).offs; + const float chrT = (float)(loc.spots.at(sp).chrrt) / 100.f; + const int scal = (loc.spots.at(sp).scalereti); + float vart = loc.spots.at(sp).vart / 100.f;//variance + const float strength = loc.spots.at(sp).str / 100.f; // Blend with original L channel data + const float dar = loc.spots.at(sp).darkness; + const float lig = loc.spots.at(sp).lightnessreti; + float value = pow(strength, 0.4f); + float value_1 = pow(strength, 0.3f); + bool logli = loc.spots.at(sp).loglin; + float limD = loc.spots.at(sp).limd;//10.f + limD = pow(limD, 1.7f); //about 2500 enough + float ilimD = 1.f / limD; + float threslum = loc.spots.at(sp).limd; + const float elogt = 2.71828f; + + if (!logli) { + useHslLin = true; + } + + //empirical skip evaluation : very difficult because quasi all parameters interfere + //to test on several images + int nei = (int)(krad * loc.spots.at(sp).neigh); + // printf("neigh=%i\n", nei); + //several test to find good values ???!!! + //very difficult to do because 4 factor are correlate with skip and cannot been solved easily + // size of spots + // radius - neigh + // scal + // variance vart + //not too bad proposition + float divsca = 1.f; + + if (scal >= 3) { + divsca = sqrt(scal / 3.f); + } + + if (skip >= 4) { + //nei = (int)(0.1f * nei + 2.f); //not too bad + nei = (int)(nei / (1.5f * skip)) / divsca; + vart *= sqrt(skip); + } else if (skip > 1 && skip < 4) { + //nei = (int)(0.3f * nei + 2.f); + nei = (int)(nei / skip) / divsca; + vart *= sqrt(skip); + } + + int moderetinex = 0; + + if (loc.spots.at(sp).retinexMethod == "uni") { + moderetinex = 0; + } else if (loc.spots.at(sp).retinexMethod == "low") { + moderetinex = 1; + } else if (loc.spots.at(sp).retinexMethod == "high") { + moderetinex = 2; + } + + const float high = 0.f; // Dummy to pass to retinex_scales(...) + + constexpr auto maxRetinexScales = 10; + float RetinexScales[maxRetinexScales]; + + retinex_scales(RetinexScales, scal, moderetinex, nei, high); + + + const int H_L = height; + const int W_L = width; + std::unique_ptr> srcBuffer(new JaggedArray(W_L, H_L)); + float** src = *(srcBuffer.get()); + + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H_L; i++) + for (int j = 0; j < W_L; j++) { + src[i][j] = luminance[i][j] + eps; + luminance[i][j] = 0.f; + } + + JaggedArray out(W_L, H_L); + + float clipt = loc.spots.at(sp).cliptm; + + const float logBetaGain = xlogf(16384.f); + float pond = logBetaGain / (float) scal; + + if (!useHslLin) { + pond /= log(elogt); + } + + float kr = 1.f;//on FFTW + float kg = 1.f;//on Gaussianblur + std::unique_ptr buffer; + buffer.reset(new float[W_L * H_L]); + + for (int scale = scal - 1; scale >= 0; --scale) { + // printf("retscale=%f scale=%i \n", mulradiusfftw * RetinexScales[scale], scale); + //emprical adjustment between FFTW radius and Gaussainblur + //under 50 ==> 10.f + // 400 ==> 1.f + float sigm = 1.f; + + if (settings->fftwsigma == false) { //empirical formula + sigm = RetinexScales[scale]; + float ak = -9.f / 350.f; + float bk = 10.f - 50.f * ak; + kr = ak * sigm + bk; + + if (sigm < 50.f) { + kr = 10.f; + } + + //above 400 at 5000 ==> 20.f + if (sigm > 400.f) { //increase ==> 5000 + float ka = 19.f / 4600.f; + float kb = 1.f - 400 * ka; + kr = ka * sigm + kb; + float kga = -0.14f / 4600.f;//decrease + float kgb = 1.f - 400.f * kga; + kg = kga * sigm + kgb; + + if (sigm > 5000.f) { + kr = ka * 5000.f + kb; + kg = kga * 5000.f + kgb; + } + + } + } else {//sigma *= sigma + kg = 1.f; + kr = sigm; + } + printf("call=%i\n", call); + if (!fftw) { // || (fftw && call != 2)) { + if (scale == scal - 1) { + gaussianBlur(src, out, W_L, H_L, kg * RetinexScales[scale], true); + } else { // reuse result of last iteration + // out was modified in last iteration => restore it + gaussianBlur(out, out, W_L, H_L, sqrtf(SQR(kg * RetinexScales[scale]) - SQR(kg * RetinexScales[scale + 1])), true); + } + } else { + if (scale == scal - 1) { + if (settings->fftwsigma == false) { //empirical formula + ImProcFunctions::fftw_convol_blur2(src, out, bfwr, bfhr, (kr * RetinexScales[scale]), 0, 0); + } else { + ImProcFunctions::fftw_convol_blur2(src, out, bfwr, bfhr, (SQR(RetinexScales[scale])), 0, 0); + } + } else { // reuse result of last iteration + // out was modified in last iteration => restore it + if (settings->fftwsigma == false) { //empirical formula + ImProcFunctions::fftw_convol_blur2(out, out, bfwr, bfhr, sqrtf(SQR(kr * RetinexScales[scale]) - SQR(kr * RetinexScales[scale + 1])), 0, 0); + } else { + ImProcFunctions::fftw_convol_blur2(out, out, bfwr, bfhr, (SQR(RetinexScales[scale]) - SQR(RetinexScales[scale + 1])), 0, 0); + } + } + } + + if (scale == 1) { //equalize last scale with darkness and lightness of course acts on TM! + if (dar != 1.f || lig != 1.f) { + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H_L; ++y) { + for (int x = 0; x < W_L; ++x) { + float buf = (src[y][x] - out[y][x]) * value; + buf *= (buf > 0.f) ? lig : dar; + out[y][x] = LIM(out[y][x] + buf, -100000.f, 100000.f); + } + } + } + + } + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H_L; i++) { + int j = 0; + +#ifdef __SSE2__ + const vfloat pondv = F2V(pond); + const vfloat limMinv = F2V(ilimD); + const vfloat limMaxv = F2V(limD); + + if (useHslLin) { + for (; j < W_L - 3; j += 4) { + STVFU(luminance[i][j], LVFU(luminance[i][j]) + pondv * vclampf(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv)); + } + } else { + for (; j < W_L - 3; j += 4) { + STVFU(luminance[i][j], LVFU(luminance[i][j]) + pondv * xlogf(vclampf(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv))); + } + } + +#endif + + if (useHslLin) { + for (; j < W_L; j++) { + luminance[i][j] += pond * (LIM(src[i][j] / out[i][j], ilimD, limD)); + } + } else { + for (; j < W_L; j++) { + luminance[i][j] += pond * xlogf(LIM(src[i][j] / out[i][j], ilimD, limD)); + } + } + } + + } + +// srcBuffer.reset(); + + + if (scal == 1) {//only if user select scal = 1 + + float kval = 1.f; +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H_L; ++y) { + for (int x = 0; x < W_L; ++x) { + float threslow = threslum * 163.f; + + if (src[y][x] < threslow) { + kval = src[y][x] / threslow; + } + } + } + + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H_L; ++y) { + for (int x = 0; x < W_L; ++x) { + float buf = (src[y][x] - out[y][x]) * value_1; + buf *= (buf > 0.f) ? lig : dar; + luminance[y][x] = LIM(src[y][x] + (1.f + kval) * buf, -32768.f, 32768.f); + } + } + + double avg = 0.f; + int ng = 0; + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + avg += luminance[i][j]; + ng++; + } + } + + avg /= ng; + avg /= 32768.f; + avg = LIM01(avg); + float contreal = 0.5f * vart; + DiagonalCurve reti_contrast({ + DCT_NURBS, + 0, 0, + avg - avg * (0.6 - contreal / 250.0), avg - avg * (0.6 + contreal / 250.0), + avg + (1 - avg) * (0.6 - contreal / 250.0), avg + (1 - avg) * (0.6 + contreal / 250.0), + 1, 1 + }); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H_L; i++) + for (int j = 0; j < W_L; j++) { + float buf = LIM01(luminance[i][j] / 32768.f); + buf = reti_contrast.getVal(buf); + buf *= 32768.f; + luminance[i][j] = buf; + } + + } + + srcBuffer.reset(); + + float str = strength * (chrome == 0 ? 1.f : 0.8f * (chrT - 0.4f)); + const float maxclip = (chrome == 0 ? 32768.f : 50000.f); + + if (scal != 1) { + mean = 0.f; + stddv = 0.f; + + mean_stddv2(luminance, mean, stddv, W_L, H_L, maxtr, mintr); + // printf("mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", mean, stddv, delta, maxtr, mintr); + + if (locRETtransCcurve && mean != 0.f && stddv != 0.f) { //if curve + float asig = 0.166666f / stddv; + float bsig = 0.5f - asig * mean; + float amax = 0.333333f / (maxtr - mean - stddv); + float bmax = 1.f - amax * maxtr; + float amin = 0.333333f / (mean - stddv - mintr); + float bmin = -amin * mintr; + + asig *= 500.f; + bsig *= 500.f; + amax *= 500.f; + bmax *= 500.f; + amin *= 500.f; + bmin *= 500.f; + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + float absciss; +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int i = 0; i < H_L; i++) + for (int j = 0; j < W_L; j++) { //for mintr to maxtr evalate absciss in function of original transmission + if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { + absciss = asig * luminance[i][j] + bsig; + } else if (luminance[i][j] >= mean) { + absciss = amax * luminance[i][j] + bmax; + } else { /*if(luminance[i][j] <= mean - stddv)*/ + absciss = amin * luminance[i][j] + bmin; + } + + //TODO : move multiplication by 4.f and subtraction of 1.f inside the curve + luminance[i][j] *= (-1.f + 4.f * locRETtransCcurve[absciss]); //new transmission + + } + } + } + + mean = 0.f; + stddv = 0.f; + mean_stddv2(luminance, mean, stddv, W_L, H_L, maxtr, mintr);//new calculation of mean... + + float epsil = 0.1f; + + mini = mean - vart * stddv; + + if (mini < mintr) { + mini = mintr + epsil; + } + + maxi = mean + vart * stddv; + + if (maxi > maxtr) { + maxi = maxtr - epsil; + } + + 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) { + delta = 1.0f; + } + + + float *copylum[H_L] ALIGNED16; + float *copylumBuffer = new float[H_L * W_L]; + + for (int i = 0; i < H_L; i++) { + copylum[i] = ©lumBuffer[i * W_L]; + } + + float cdfactor = (clipt * 32768.f) / delta; + maxCD = -9999999.f; + minCD = 9999999.f; + //prepare work for curve gain +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + luminance[i][j] = luminance[i][j] - mini; + } + } + + mean = 0.f; + stddv = 0.f; + + mean_stddv2(luminance, mean, stddv, W_L, H_L, maxtr, mintr); +// printf("meanun=%f stdun=%f maxtr=%f mintr=%f\n", mean, stddv, maxtr, mintr); + + float asig = 0.f, bsig = 0.f, amax = 0.f, bmax = 0.f, amin = 0.f, bmin = 0.f; + const bool hasRetGainCurve = locRETgainCcurve && mean != 0.f && stddv != 0.f; + + if (hasRetGainCurve) { //if curve + asig = 0.166666f / stddv; + bsig = 0.5f - asig * mean; + amax = 0.333333f / (maxtr - mean - stddv); + bmax = 1.f - amax * maxtr; + amin = 0.333333f / (mean - stddv - mintr); + bmin = -amin * mintr; + + asig *= 500.f; + bsig *= 500.f; + amax *= 500.f; + bmax *= 500.f; + amin *= 500.f; + bmin *= 500.f; + cdfactor *= 2.f; + } + + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + // float absciss; + float cdmax = -999999.f, cdmin = 999999.f; + float gan = 0.5f; + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int i = 0; i < H_L; i ++) + for (int j = 0; j < W_L; j++) { + + if (hasRetGainCurve) { + float absciss; + + if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { + absciss = asig * luminance[i][j] + bsig; + } else if (luminance[i][j] >= mean) { + absciss = amax * luminance[i][j] + bmax; + } else { + absciss = amin * luminance[i][j] + bmin; + } + + gan = locRETgainCcurve[absciss]; //new gain function transmission + } + + //but we don't update mean stddv for display only... + copylum[i][j] = gan * luminance[i][j];//update data for display + float cd = gan * cdfactor * luminance[i][j] + offse; + + cdmax = cd > cdmax ? cd : cdmax; + cdmin = cd < cdmin ? cd : cdmin; + luminance[i][j] = intp(str * reducDE[i][j], clipretinex(cd, 0.f, maxclip), originalLuminance[i][j]); + } + + + +#ifdef _OPENMP + #pragma omp critical +#endif + { + maxCD = maxCD > cdmax ? maxCD : cdmax; + minCD = minCD < cdmin ? minCD : cdmin; + } + } + mean = 0.f; + stddv = 0.f; + + mean_stddv2(copylum, mean, stddv, W_L, H_L, maxtr, mintr); + delete [] copylumBuffer; + copylumBuffer = nullptr; + +// printf("mean=%f std=%f maxtr=%f mintr=%f\n", mean, stddv, maxtr, mintr); + + } else { +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int i = 0; i < H_L; i ++) + for (int j = 0; j < W_L; j++) { + luminance[i][j] = LIM(luminance[i][j], 0.f, maxclip) * str + (1.f - str) * originalLuminance[i][j]; + + } + + } + + float rad = loc.spots.at(sp).radmaskreti; + float slop = loc.spots.at(sp).slomaskreti; + float gamm = loc.spots.at(sp).gammaskreti; + float blend = loc.spots.at(sp).blendmaskreti; + float chro = loc.spots.at(sp).chromaskreti; + float lap = loc.spots.at(sp).lapmaskreti; + bool pde = params->locallab.spots.at(sp).laplac; + + if (lum == 1 && (llretiMask == 3 || llretiMask == 0 || llretiMask == 2 || llretiMask == 4)) { //only mask with luminance on last scale + int before = 1; + maskforretinex(sp, before, luminance, nullptr, W_L, H_L, skip, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, llretiMask, retiMasktmap, retiMask, + rad, lap, pde, gamm, slop, chro, blend, + lmaskretilocalcurve, localmaskretiutili, + bufreti, bufmask, buforig, buforigmas, multiThread, + delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, iterat, limscope, scope, balance, balanceh, lumask + ); + } + + //mask does not interfered with data displayed + + Tmean = mean; + Tsigma = stddv; + Tmin = mintr; + Tmax = maxtr; + } +} } diff --git a/rtengine/ipshadowshighlights.cc b/rtengine/ipshadowshighlights.cc index 0eb3df9c5..fd2ab3db4 100644 --- a/rtengine/ipshadowshighlights.cc +++ b/rtengine/ipshadowshighlights.cc @@ -38,14 +38,12 @@ void ImProcFunctions::shadowsHighlights(LabImage *lab, bool ena, int labmode, in if (!ena || (!hightli && !shado)){ return; } - const int width = lab->W; const int height = lab->H; const bool lab_mode = labmode; array2D mask(width, height); array2D L(width, height); -// const float radius = params->sh.radius * 10 / scale; const float radius = float(rad) * 10 / scal; LUTf f(lab_mode ? 32768 : 65536); diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 0e46cd596..afe6f8aa3 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -244,6 +244,110 @@ BENCHFUN delete blurbuffer; } +void ImProcFunctions::deconvsharpeningloc (float** luminance, float** tmp, int W, int H, float** loctemp, int damp, double radi, int ite, int amo, int contrast, double blurrad, int sk) +{ + // BENCHFUN + + if (amo < 1) { + return; + } + JaggedArray blend(W, H); + float contras = contrast / 100.f; + buildBlendMask(luminance, blend, W, H, contras, 1.f); + + + JaggedArray tmpI(W, H); + + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < H; i++) { + for (int j = 0; j < W; j++) { + tmpI[i][j] = max(luminance[i][j], 0.f); + } + } + + // calculate contrast based blend factors to reduce sharpening in regions with low contrast + + JaggedArray* blurbuffer = nullptr; + + if (blurrad >= 0.25) { + blurbuffer = new JaggedArray(W, H); + JaggedArray &blur = *blurbuffer; +#ifdef _OPENMP + #pragma omp parallel +#endif + { + gaussianBlur(tmpI, blur, W, H, blurrad); +#ifdef _OPENMP + #pragma omp for +#endif + for (int i = 0; i < H; ++i) { + for (int j = 0; j < W; ++j) { + blur[i][j] = intp(blend[i][j], luminance[i][j], std::max(blur[i][j], 0.0f)); + } + } + } + } + + float damping = (float) damp / 5.0; + bool needdamp = damp > 0; + double sigma = radi / sk; + const float amount = (float) amo / 100.f; + + if (sigma < 0.26f) { + sigma = 0.26f; + } + + int itera = ite; + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + for (int k = 0; k < itera; k++) { + if (!needdamp) { + // apply gaussian blur and divide luminance by result of gaussian blur + // gaussianBlur (tmpI, tmp, W, H, sigma, nullptr, GAUSS_DIV, luminance); + gaussianBlur(tmpI, tmp, W, H, sigma, false, GAUSS_DIV, luminance); + } else { + // apply gaussian blur + damping + gaussianBlur (tmpI, tmp, W, H, sigma); + dcdamping (tmp, luminance, damping, W, H); + } + + gaussianBlur (tmp, tmpI, W, H, sigma, false, GAUSS_MULT); + } // end for + + +#ifdef _OPENMP + #pragma omp for +#endif + + for (int i = 0; i < H; i++) + for (int j = 0; j < W; j++) { + loctemp[i][j] = intp(blend[i][j] * amount, max(tmpI[i][j], 0.0f), luminance[i][j]); + } + + if (blurrad >= 0.25) { + JaggedArray &blur = *blurbuffer; +#ifdef _OPENMP + #pragma omp for +#endif + for (int i = 0; i < H; ++i) { + for (int j = 0; j < W; ++j) { + loctemp[i][j] = intp(blend[i][j], loctemp[i][j], max(blur[i][j], 0.0f)); + } + } + } + + } // end parallel + delete blurbuffer; + + +} + void ImProcFunctions::sharpening (LabImage* lab, const procparams::SharpeningParams &sharpenParam, bool showMask) { diff --git a/rtengine/ipsoftlight.cc b/rtengine/ipsoftlight.cc index 41d0d48bf..7df44702e 100644 --- a/rtengine/ipsoftlight.cc +++ b/rtengine/ipsoftlight.cc @@ -26,7 +26,11 @@ #include "procparams.h" -namespace { +namespace rtengine +{ + +namespace +{ inline float sl(float blend, float x) { @@ -43,8 +47,10 @@ inline float sl(float blend, float x) // using optimized formula (heckflosse67@gmx.de) return rtengine::intp(blend, rtengine::Color::igamma_srgb(v * v * (3.f - 2.f * v) * rtengine::MAXVALF), x); } + return x; } +} // namespace #ifdef __SSE2__ inline vfloat sl(vfloat blend, vfloat x) @@ -54,11 +60,11 @@ inline vfloat sl(vfloat blend, vfloat x) } #endif -} // namespace +//} // namespace -void rtengine::ImProcFunctions::softLight(LabImage *lab) +void ImProcFunctions::softLight(LabImage *lab, const rtengine::procparams::SoftLightParams &softLightParams) { - if (!params->softlight.enabled || !params->softlight.strength) { + if (!softLightParams.enabled || !softLightParams.strength) { return; } @@ -94,30 +100,35 @@ void rtengine::ImProcFunctions::softLight(LabImage *lab) #pragma omp parallel #endif { - const float blend = params->softlight.strength / 100.f; + const float blend = softLightParams.strength / 100.f; #ifdef __SSE2__ const vfloat blendv = F2V(blend); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif + for (int i = 0; i < lab->H; ++i) { int j = 0; #ifdef __SSE2__ + for (; j < lab->W - 3; j += 4) { vfloat Xv, Yv, Zv; vfloat Rv, Gv, Bv; - Color::Lab2XYZ(LVFU(lab->L[i][j]),LVFU (lab->a[i][j]),LVFU (lab->b[i][j]), Xv, Yv, Zv); + Color::Lab2XYZ(LVFU(lab->L[i][j]), LVFU(lab->a[i][j]), LVFU(lab->b[i][j]), Xv, Yv, Zv); Color::xyz2rgb(Xv, Yv, Zv, Rv, Gv, Bv, wipv); Rv = sl(blendv, Rv); Gv = sl(blendv, Gv); Bv = sl(blendv, Bv); Color::rgbxyz(Rv, Gv, Bv, Xv, Yv, Zv, wpv); + for (int k = 0; k < 4; ++k) { - Color::XYZ2Lab(Xv[k], Yv[k], Zv[k], lab->L[i][j + k], lab->a[i][j + k], lab->b[i][j+ k]); + Color::XYZ2Lab(Xv[k], Yv[k], Zv[k], lab->L[i][j + k], lab->a[i][j + k], lab->b[i][j + k]); } } + #endif + for (; j < lab->W; j++) { float X, Y, Z; float R, G, B; @@ -132,3 +143,4 @@ void rtengine::ImProcFunctions::softLight(LabImage *lab) } } } +} \ No newline at end of file diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index aa22aac56..99a02a319 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -491,15 +491,8 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, for (size_t i = 0; i < src.size(); i++) { double x_d = src[i].x, y_d = src[i].y; - if (pLCPMap && params->lensProf.useDist) { - pLCPMap->correctDistortion(x_d, y_d, 0, 0, ascale); - } else { - x_d *= ascale; - y_d *= ascale; - } - - x_d += ascale * (0 - w2); // centering x coord & scale - y_d += ascale * (0 - h2); // centering y coord & scale + y_d = ascale * (y_d - h2); // centering x coord & scale + x_d = ascale * (x_d - w2); // centering x coord & scale switch (perspectiveType) { case PerspType::NONE: @@ -522,6 +515,10 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, break; } + if (pLCPMap && params->lensProf.useDist) { + pLCPMap->correctDistortion(x_d, y_d, 0, 0); + } + // rotate double Dx = x_d * cost - y_d * sint; double Dy = x_d * sint + y_d * cost; @@ -817,7 +814,7 @@ static void calcGradientParams (int oW, int oH, const GradientParams& gradient, } } -static float calcGradientFactor (const struct grad_params& gp, int x, int y) +float ImProcFunctions::calcGradientFactor (const struct grad_params& gp, int x, int y) { if (gp.angle_is_zero) { int gy = gp.transpose ? x : y; @@ -1219,15 +1216,8 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I double x_d = x; double y_d = y; - if (enableLCPDist) { - pLCPMap->correctDistortion(x_d, y_d, cx, cy, ascale); // must be first transform - } else { - x_d *= ascale; - y_d *= ascale; - } - - x_d += ascale * centerFactorx; // centering x coord & scale - y_d += ascale * centerFactory; // centering y coord & scale + x_d = ascale * (x_d + centerFactorx); // centering x coord & scale + y_d = ascale * (y_d + centerFactory); // centering y coord & scale switch (perspectiveType) { case PerspType::NONE: @@ -1250,6 +1240,10 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I break; } + if (enableLCPDist) { + pLCPMap->correctDistortion(x_d, y_d, w2, h2); + } + // rotate const double Dxc = x_d * cost - y_d * sint; const double Dyc = x_d * sint + y_d * cost; diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 8636ecb95..43002c2a3 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -61,16 +61,16 @@ void fillCurveArrayVib (DiagonalCurve* diagCurve, LUTf &outCurve) * copyright (c)2011 Jacques Desmis and Jean-Christophe Frisch * */ -void ImProcFunctions::vibrance (LabImage* lab) +void ImProcFunctions::vibrance (LabImage* lab, const procparams::VibranceParams &vibranceParams, bool highlight, const Glib::ustring &workingProfile) { - if (!params->vibrance.enabled) { + if (!vibranceParams.enabled) { return; } BENCHFUN // int skip=1; //scale==1 ? 1 : 16; bool skinCurveIsSet = false; - DiagonalCurve* dcurve = new DiagonalCurve (params->vibrance.skintonescurve, CURVES_MIN_POLY_POINTS); + DiagonalCurve* dcurve = new DiagonalCurve (vibranceParams.skintonescurve, CURVES_MIN_POLY_POINTS); if (dcurve) { if (!dcurve->isIdentity()) { @@ -81,7 +81,7 @@ void ImProcFunctions::vibrance (LabImage* lab) } } - if (!skinCurveIsSet && !params->vibrance.pastels && !params->vibrance.saturated) { + if (!skinCurveIsSet && !vibranceParams.pastels && !vibranceParams.saturated) { if (dcurve) { delete dcurve; dcurve = nullptr; @@ -96,10 +96,10 @@ void ImProcFunctions::vibrance (LabImage* lab) // skin hue curve // I use diagonal because I think it's better - const float chromaPastel = params->vibrance.pastels / 100.f; - const float chromaSatur = params->vibrance.saturated / 100.f; + const float chromaPastel = vibranceParams.pastels / 100.f; + const float chromaSatur = vibranceParams.saturated / 100.f; constexpr float p00 = 0.07f; - const float limitpastelsatur = (static_cast(params->vibrance.psthreshold.getTopLeft()) / 100.f) * (1.f - p00) + p00; + const float limitpastelsatur = (static_cast(vibranceParams.psthreshold.getTopLeft()) / 100.f) * (1.f - p00) + p00; const float maxdp = (limitpastelsatur - p00) / 4.f; const float maxds = (1.f - limitpastelsatur) / 4.f; const float p0 = p00 + maxdp; @@ -108,7 +108,7 @@ void ImProcFunctions::vibrance (LabImage* lab) const float s0 = limitpastelsatur + maxds; const float s1 = limitpastelsatur + 2.f * maxds; const float s2 = limitpastelsatur + 3.f * maxds; - const float transitionweighting = static_cast(params->vibrance.psthreshold.getBottomLeft()) / 100.f; + const float transitionweighting = static_cast(vibranceParams.psthreshold.getBottomLeft()) / 100.f; float chromamean = 0.f; if (chromaPastel != chromaSatur) { @@ -144,6 +144,7 @@ void ImProcFunctions::vibrance (LabImage* lab) if (skinCurveIsSet) { fillCurveArrayVib (dcurve, skin_curve); skin_curve /= ask; +// skin_curve *= 2.f; } if (dcurve) { @@ -151,12 +152,10 @@ void ImProcFunctions::vibrance (LabImage* lab) dcurve = nullptr; } + const bool protectskins = vibranceParams.protectskins; + const bool avoidcolorshift = vibranceParams.avoidcolorshift; - const bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated - const bool protectskins = params->vibrance.protectskins; - const bool avoidcolorshift = params->vibrance.avoidcolorshift; - - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (workingProfile); //inverse matrix user select const float wip[3][3] = { {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index f415c9c8e..949dbafbd 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -110,9 +110,12 @@ struct cont_params { bool lip3; bool tonemap; bool diag; - int TMmeth; float tmstrength; float balan; + float sigmafin; + float sigmaton; + float sigmacol; + float sigmadir; int ite; int contmet; bool opaW; @@ -142,19 +145,28 @@ struct cont_params { float balchrom; float chromfi; float chromco; + float factor; + float scaling; + float scaledirect; + float a_scale; + float a_base; + float b_scale; + float b_base; + float a_high; + float a_low; + float b_high; + float b_low; + float rangeab; + float protab; }; int wavNestedLevels = 1; -void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const Wavblcurve & wavblcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, const LUTf &wavclCurve, int skip) +void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const Wavblcurve & wavblcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveSH & waOpacityCurveSH, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, const LUTf &wavclCurve, int skip) { -#ifdef _DEBUG - // init variables to display Munsell corrections - MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); -#endif TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); const double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, @@ -191,6 +203,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.ite = params->wavelet.iter; cp.tonemap = params->wavelet.tmrs != 0; cp.bam = false; + cp.sigmafin = params->wavelet.sigmafin; + cp.sigmaton = params->wavelet.sigmaton; + cp.sigmacol = params->wavelet.sigmacol; + cp.sigmadir = params->wavelet.sigmadir; if (params->wavelet.TMmethod == "cont") { cp.contmet = 1; @@ -310,6 +326,20 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.mulC[m] = waparams.ch[m]; } + cp.factor = WaveletParams::LABGRID_CORR_MAX * 3.276f; + cp.scaling = WaveletParams::LABGRID_CORR_SCALE; + cp.scaledirect = WaveletParams::LABGRIDL_DIRECT_SCALE; + cp.a_scale = (params->wavelet.labgridAHigh - params->wavelet.labgridALow) / cp.factor / cp.scaling; + cp.a_base = params->wavelet.labgridALow / cp.scaling; + cp.b_scale = (params->wavelet.labgridBHigh - params->wavelet.labgridBLow) / cp.factor / cp.scaling; + cp.b_base = params->wavelet.labgridBLow / cp.scaling; + cp.a_high = 3.276f * params->wavelet.labgridAHigh; + cp.a_low = 3.276f * params->wavelet.labgridALow; + cp.b_high = 3.276f * params->wavelet.labgridBHigh; + cp.b_low = 3.276f * params->wavelet.labgridBLow; + cp.rangeab = params->wavelet.rangeab; + cp.protab = params->wavelet.protab; + if (waOpacityCurveRG) { cp.opaRG = true; } @@ -427,16 +457,14 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.t_ly = static_cast(params->wavelet.hueskin2.getTopLeft()) / 100.0f; cp.b_ry = static_cast(params->wavelet.hueskin2.getBottomRight()) / 100.0f; cp.t_ry = static_cast(params->wavelet.hueskin2.getTopRight()) / 100.0f; - cp.numlevH = params->wavelet.threshold; + cp.numlevH = params->wavelet.threshold -1; //shadows cp.b_lsl = static_cast(params->wavelet.bllev.getBottomLeft()); cp.t_lsl = static_cast(params->wavelet.bllev.getTopLeft()); cp.b_rsl = static_cast(params->wavelet.bllev.getBottomRight()); cp.t_rsl = static_cast(params->wavelet.bllev.getTopRight()); - cp.numlevS = params->wavelet.threshold2; - int maxlevS = 9 - cp.numlevH; - cp.numlevS = rtengine::min(cp.numlevS, maxlevS); + cp.numlevS = params->wavelet.threshold2; //rtengine::max(cp.numlevS, maxlevS); //highlight cp.b_lhl = static_cast(params->wavelet.hllev.getBottomLeft()); cp.t_lhl = static_cast(params->wavelet.hllev.getTopLeft()); @@ -505,11 +533,6 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const levwav = rtengine::min(maxlevelcrop, levwav); - // determine number of levels to process. - // for(levwav=rtengine::min(maxlevelcrop,levwav);levwav>0;levwav--) - // if(cp.mul[levwav-1]!=0.f || cp.curv) - // if(cp.mul[levwav-1]!=0.f) - // break; // I suppress this fonctionality ==> crash for level < 3 if (levwav < 1) { return; // nothing to do @@ -705,7 +728,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } #ifdef _OPENMP - #pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = tiletop; i < tilebottom; i++) { @@ -764,7 +787,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } #ifdef _OPENMP - #pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = 1; i < hei - 1; i++) { @@ -838,11 +861,11 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (exblurL) { if (cp.mul[0] == 0.f) { - cp.mul[0] = 0.01f;//to always enable WaveletcontAllL if no contrast is nead + cp.mul[0] = 0.01f;//to always enable WaveletcontAllL if no contrast is needed } } - if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.tonemap && cp.conres == 0.f && cp.conresH == 0.f && cp.val == 0 && !ref0 && params->wavelet.CLmethod == "all") { // no processing of residual L or edge=> we probably can reduce the number of levels + if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.tonemap && cp.conres == 0.f && cp.conresH == 0.f && cp.val == 0 && !ref0 && params->wavelet.CLmethod == "all") { // no processing of residual L or edge=> we probably can reduce the number of levels while (levwavL > 0 && cp.mul[levwavL - 1] == 0.f) { // cp.mul[level] == 0.f means no changes to level levwavL--; } @@ -866,13 +889,13 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (levwavL > 0) { const std::unique_ptr Ldecomp(new wavelet_decomposition(labco->data, labco->W, labco->H, levwavL, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); - float madL[8][3]; - if (!Ldecomp->memoryAllocationFailed) { + if (!Ldecomp->memory_allocation_failed()) { + float madL[10][3]; // float madL[8][3]; #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic) collapse(2) num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for schedule(dynamic) collapse(2) num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int lvl = 0; lvl < levwavL; lvl++) { @@ -880,9 +903,13 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const int Wlvl_L = Ldecomp->level_W(lvl); int Hlvl_L = Ldecomp->level_H(lvl); - float ** WavCoeffs_L = Ldecomp->level_coeffs(lvl); + const float* const* WavCoeffs_L = Ldecomp->level_coeffs(lvl); madL[lvl][dir - 1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); + + if (settings->verbose) { + printf("sqrt madL=%f lvl=%i dir=%i\n", sqrt(madL[lvl][dir - 1]), lvl, dir - 1); + } } } @@ -901,16 +928,16 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } if (cp.val > 0 || ref || contr) { //edge - Evaluate2(*Ldecomp, mean, meanN, sigma, sigmaN, MaxP, MaxN); + Evaluate2(*Ldecomp, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavNestedLevels); } //init for edge and denoise float vari[4]; - vari[0] = 8.f * SQR((cp.lev0n / 125.f) * (1.f + cp.lev0n / 25.f)); - vari[1] = 8.f * SQR((cp.lev1n / 125.f) * (1.f + cp.lev1n / 25.f)); - vari[2] = 8.f * SQR((cp.lev2n / 125.f) * (1.f + cp.lev2n / 25.f)); - vari[3] = 8.f * SQR((cp.lev3n / 125.f) * (1.f + cp.lev3n / 25.f)); + vari[0] = 0.8f * SQR((cp.lev0n / 125.f) * (1.f + cp.lev0n / 25.f)); + vari[1] = 0.8f * SQR((cp.lev1n / 125.f) * (1.f + cp.lev1n / 25.f)); + vari[2] = 0.8f * SQR((cp.lev2n / 125.f) * (1.f + cp.lev2n / 25.f)); + vari[3] = 0.8f * SQR((cp.lev3n / 125.f) * (1.f + cp.lev3n / 25.f)); float kr3 = 1.f; if (cp.lev3n < 10.f) { @@ -924,11 +951,16 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } if ((cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f) && cp.noiseena) { - int edge = 4; - vari[0] = rtengine::max(0.0001f, vari[0]); - vari[1] = rtengine::max(0.0001f, vari[1]); - vari[2] = rtengine::max(0.0001f, vari[2]); - vari[3] = rtengine::max(0.0001f, kr3 * vari[3]); + int edge = 5; + vari[0] = rtengine::max(0.000001f, vari[0]); + vari[1] = rtengine::max(0.000001f, vari[1]); + vari[2] = rtengine::max(0.000001f, vari[2]); + vari[3] = rtengine::max(0.000001f, kr3 * vari[3]); + + if (settings->verbose) { + printf("LUM var0=%f var1=%f var2=%f var3=%f\n", vari[0], vari[1], vari[2], vari[3]); + } + // float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL int GWL = labco->W; int GHL = labco->H; @@ -962,14 +994,14 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } } - if (cp.lev3n < 0.5f) { + if (cp.lev3n < 20.f) { WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge, 1); } else { WaveletDenoiseAll_BiShrinkL(*Ldecomp, noisevarlum, madL, vari, edge, 1); WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge, 1); } - } + } //Flat curve for Contrast=f(H) in levels FlatCurve* ChCurve = new FlatCurve(params->wavelet.Chcurve); //curve C=f(H) @@ -984,10 +1016,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const Chutili = true; } - WaveletcontAllL(labco, varhue, varchro, *Ldecomp, wavblcurve, cp, skip, mean, sigma, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, ChCurve, Chutili); + WaveletcontAllL(labco, varhue, varchro, *Ldecomp, wavblcurve, cp, skip, mean, sigma, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, waOpacityCurveSH, ChCurve, Chutili); if (cp.val > 0 || ref || contr || cp.diagcurv) { //edge - Evaluate2(*Ldecomp, mean, meanN, sigma, sigmaN, MaxP, MaxN); + Evaluate2(*Ldecomp, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavNestedLevels); } WaveletcontAllLfinal(*Ldecomp, cp, mean, sigma, MaxP, waOpacityCurveWL); @@ -1009,29 +1041,29 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float noiseccr = cp.chromco; if (cp.balchrom > 0.f) { - noisecfr = cp.chromfi * ((100.f + cp.balchrom) / 10.f); - noiseccr = cp.chromco + ((100.f + cp.balchrom) / 10.f); + noisecfr = cp.chromfi + 0.1f * cp.balchrom; + noiseccr = cp.chromco + 0.1f * cp.balchrom; } float noisecfb = cp.chromfi; float noiseccb = cp.chromco; if (cp.balchrom < 0.f) { - noisecfb = cp.chromfi * ((100.f - cp.balchrom) / 10.f); - noiseccb = cp.chromco * ((100.f - cp.balchrom) / 10.f); + noisecfb = cp.chromfi - 0.1f * cp.balchrom; + noiseccb = cp.chromco - 0.1f * cp.balchrom; } if (noisecfr < 0.f) { - noisecfr = 0.0001f; + noisecfr = 0.00001f; } if (noiseccr < 0.f) { - noiseccr = 0.0001f; + noiseccr = 0.00001f; } if (noisecfb < 0.f) { - noisecfb = 0.0001f; + noisecfb = 0.00001f; } if (noiseccb < 0.f) { @@ -1062,7 +1094,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float k3 = 0.f; if (cp.chromfi < 0.2f) { - k1 = 0.f; + k1 = 0.05f; k2 = 0.f; k3 = 0.f; } else if (cp.chromfi < 0.3f) { @@ -1116,7 +1148,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const k3 = 1.f; } - float minic = 0.0001f; + float minic = 0.000001f; variC[0] = max(minic, variC[0]); variC[1] = max(minic, k1 * variC[1]); variC[2] = max(minic, k2 * variC[2]); @@ -1131,15 +1163,12 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float k5 = 0.f; float k6 = 0.f; - if (cp.chromco == 0.01f) { - k4 = 0.f; - k5 = 0.0f; - } else if (cp.chromco < 0.2f) { + if (cp.chromco < 0.2f) { k4 = 0.1f; - k5 = 0.0f; + k5 = 0.02f; } else if (cp.chromco < 0.5f) { k4 = 0.15f; - k5 = 0.0f; + k5 = 0.05f; } else if (cp.chromco < 1.f) { k4 = 0.15f; k5 = 0.1f; @@ -1157,10 +1186,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const k5 = 1.f; } - variC[4] = max(0.0001f, k4 * variC[4]); - variC[5] = max(0.0001f, k5 * variC[5]); - variCb[4] = max(0.0001f, k4 * variCb[4]); - variCb[5] = max(0.0001f, k5 * variCb[5]); + variC[4] = max(0.000001f, k4 * variC[4]); + variC[5] = max(0.000001f, k5 * variC[5]); + variCb[4] = max(0.000001f, k4 * variCb[4]); + variCb[5] = max(0.000001f, k5 * variCb[5]); if (cp.chromco < 4.f) { k6 = 0.f; @@ -1172,8 +1201,13 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const k6 = 1.f; } - variC[6] = max(0.0001f, k6 * variC[6]); - variCb[6] = max(0.0001f, k6 * variCb[6]); + variC[6] = max(0.00001f, k6 * variC[6]); + variCb[6] = max(0.00001f, k6 * variCb[6]); + + if (settings->verbose) { + printf("CHRO var0=%f va1=%f va2=%f va3=%f va4=%f val5=%f va6=%f\n", variC[0], variC[1], variC[2], variC[3], variC[4], variC[5], variC[6]); + } + /* for (int y = 0; y < 7; y++) { printf("y=%i madL=%f varia=%f variab=%f\n", y, madL[y][1], variC[y], variCb[y]); @@ -1250,13 +1284,16 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (levwava > 0) { const std::unique_ptr adecomp(new wavelet_decomposition(labco->data + datalen, labco->W, labco->H, levwava, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); - if (!adecomp->memoryAllocationFailed) { - if (cp.noiseena && (cp.chromfi > 0.f || cp.chromfi > 0.f)) { + if (!adecomp->memory_allocation_failed()) { + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f )) { + WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, 1); + } else if (cp.chromfi > 0.f && cp.chromco >= 2.f){ + WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, 1); WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, 1); } - Evaluate2(*adecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); + Evaluate2(*adecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab, wavNestedLevels); WaveletcontAllAB(labco, varhue, varchro, *adecomp, wavblcurve, waOpacityCurveW, cp, true, skip, meanab, sigmaab); adecomp->reconstruct(labco->data + datalen, cp.strength); } @@ -1284,13 +1321,15 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (levwavb > 0) { const std::unique_ptr bdecomp(new wavelet_decomposition(labco->data + 2 * datalen, labco->W, labco->H, levwavb, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); - if (!bdecomp->memoryAllocationFailed) { - if (cp.noiseena && (cp.chromfi > 0.f || cp.chromfi > 0.f)) { + if (!bdecomp->memory_allocation_failed()) { + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f )) { + WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); + } else if (cp.chromfi > 0.f && cp.chromco >= 2.f){ WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); } - Evaluate2(*bdecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); + Evaluate2(*bdecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab, wavNestedLevels); WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip, meanab, sigmaab); bdecomp->reconstruct(labco->data + 2 * datalen, cp.strength); } @@ -1298,12 +1337,6 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } else {// a and b int levwavab = levwav; - if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !hhutili && params->wavelet.CLmethod == "all") { // no processing of residual ab => we probably can reduce the number of levels - while (levwavab > 0 && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavab - 1] == 0.f)) || (cp.CHmet != 2 && (levwavab == 10 || (!cp.curv || cp.mulC[levwavab - 1] == 0.f))))) && (!cp.opaRG || levwavab == 10 || (cp.opaRG && cp.mulopaRG[levwavab - 1] == 0.f)) && ((levwavab == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavab - 1] == 0.f)))) { - levwavab--; - } - } - if (cp.chromfi > 0.f || cp.chromco > 0.f) { if (levwavab < 7) { levwavab = 7; @@ -1314,23 +1347,28 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const const std::unique_ptr adecomp(new wavelet_decomposition(labco->data + datalen, labco->W, labco->H, levwavab, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); const std::unique_ptr bdecomp(new wavelet_decomposition(labco->data + 2 * datalen, labco->W, labco->H, levwavab, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); - if (!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) { - if (cp.noiseena && (cp.chromfi > 0.f || cp.chromfi > 0.f)) { + if (!adecomp->memory_allocation_failed() && !bdecomp->memory_allocation_failed()) { + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f)) { + WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, 1); + } else if (cp.chromfi > 0.f && cp.chromco >= 2.f){ WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, 1); WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, 1); } - Evaluate2(*adecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); - WaveletcontAllAB(labco, varhue, varchro, *adecomp, wavblcurve, waOpacityCurveW, cp, true, skip, meanab, sigmaab); - WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); - WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); - Evaluate2(*bdecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); - - if (cp.noiseena && (cp.chromfi > 0.f || cp.chromfi > 0.f)) { - WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip, meanab, sigmaab); - WaveletAandBAllAB(*adecomp, *bdecomp, cp, hhCurve, hhutili); + Evaluate2(*adecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab, wavNestedLevels); + WaveletcontAllAB(labco, varhue, varchro, *adecomp, wavblcurve, waOpacityCurveW, cp, true, skip, meanab, sigmaab); + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f)) { + WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); + } else if (cp.chromfi > 0.f && cp.chromco >= 2.f){ + WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); + WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); } + Evaluate2(*bdecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab, wavNestedLevels); + + WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip, meanab, sigmaab); + WaveletAandBAllAB(*adecomp, *bdecomp, cp, hhCurve, hhutili); + adecomp->reconstruct(labco->data + datalen, cp.strength); bdecomp->reconstruct(labco->data + 2 * datalen, cp.strength); @@ -1388,7 +1426,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const bool highlight = params->toneCurve.hrenabled; #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for schedule(dynamic,16) num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = tiletop; i < tilebottom; i++) { @@ -1468,13 +1506,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float Lprov2 = Lold[i][j] / 327.68f; float memChprov = varchro[i1][j1]; float R, G, B; -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; - Color::gamutLchonly(HH, sincosv, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else Color::gamutLchonly(HH, sincosv, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); -#endif L = Lprov1 * 327.68f; a = 327.68f * Chprov1 * sincosv.y; //gamut @@ -1483,11 +1515,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float correctlum = 0.0f; Lprov1 = L / 327.68f; const float Chprov = sqrtf(SQR(a) + SQR(b)) / 327.68f; -#ifdef _DEBUG - Color::AllMunsellLch(true, Lprov1, Lprov2, HH, Chprov, memChprov, correctionHue, correctlum, MunsDebugInfo); -#else Color::AllMunsellLch(true, Lprov1, Lprov2, HH, Chprov, memChprov, correctionHue, correctlum); -#endif if (correctionHue != 0.f || correctlum != 0.f) { // only calculate sin and cos if HH changed if (std::fabs(correctionHue) < 0.015f) { @@ -1596,15 +1624,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } } } - -#ifdef _DEBUG - delete MunsDebugInfo; -#endif - } -void ImProcFunctions::Aver(float * RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min) +void ImProcFunctions::Aver(const float* RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min, int numThreads) { //find absolute mean @@ -1615,7 +1638,7 @@ void ImProcFunctions::Aver(float * RESTRICT DataList, int datalen, float &averag max = 0.f; min = RT_INFINITY_F; #ifdef _OPENMP - #pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel num_threads(numThreads) if (numThreads>1) #endif { float lmax = 0.f, lmin = 0.f; @@ -1659,14 +1682,14 @@ void ImProcFunctions::Aver(float * RESTRICT DataList, int datalen, float &averag } -void ImProcFunctions::Sigma(float * RESTRICT DataList, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg) +void ImProcFunctions::Sigma(const float* RESTRICT DataList, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg, int numThreads) { int countP = 0, countN = 0; double variP = 0.0, variN = 0.0; // use double precision for large summations float thres = 32.7f;//different fom zero to take into account only data large enough 32.7 = 0.1 in range 0..100 #ifdef _OPENMP - #pragma omp parallel for reduction(+:variP,variN,countP,countN) num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for reduction(+:variP,variN,countP,countN) num_threads(numThreads) if (numThreads>1) #endif for (int i = 0; i < datalen; i++) { @@ -1693,8 +1716,7 @@ void ImProcFunctions::Sigma(float * RESTRICT DataList, int datalen, float avera } -void ImProcFunctions::Evaluate2(const wavelet_decomposition &WaveletCoeffs_L, - float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN) +void ImProcFunctions::Evaluate2(const wavelet_decomposition &WaveletCoeffs_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, int numThreads) { //StopWatch Stop1("Evaluate2"); int maxlvl = WaveletCoeffs_L.maxlevel(); @@ -1704,9 +1726,9 @@ void ImProcFunctions::Evaluate2(const wavelet_decomposition &WaveletCoeffs_L, int Wlvl_L = WaveletCoeffs_L.level_W(lvl); int Hlvl_L = WaveletCoeffs_L.level_H(lvl); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + const float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); - Eval2(WavCoeffs_L, lvl, Wlvl_L, Hlvl_L, mean, meanN, sigma, sigmaN, MaxP, MaxN); + Eval2(WavCoeffs_L, lvl, Wlvl_L, Hlvl_L, mean, meanN, sigma, sigmaN, MaxP, MaxN, numThreads); } } @@ -1763,8 +1785,7 @@ void ImProcFunctions::calceffect(int level, float *mean, float *sigma, float *me mea[9] = offs * mean[level] + effect * 2.5f * sigma[level]; //99% } -void ImProcFunctions::Eval2(float ** WavCoeffs_L, int level, - int W_L, int H_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN) +void ImProcFunctions::Eval2(const float* const* WavCoeffs_L, int level, int W_L, int H_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, int numThreads) { float avLP[4], avLN[4]; @@ -1773,8 +1794,8 @@ void ImProcFunctions::Eval2(float ** WavCoeffs_L, int level, float AvL, AvN, SL, SN, maxLP, maxLN; for (int dir = 1; dir < 4; dir++) { - Aver(WavCoeffs_L[dir], W_L * H_L, avLP[dir], avLN[dir], maxL[dir], minL[dir]); - Sigma(WavCoeffs_L[dir], W_L * H_L, avLP[dir], avLN[dir], sigP[dir], sigN[dir]); + Aver(WavCoeffs_L[dir], W_L * H_L, avLP[dir], avLN[dir], maxL[dir], minL[dir], numThreads); + Sigma(WavCoeffs_L[dir], W_L * H_L, avLP[dir], avLN[dir], sigP[dir], sigN[dir], numThreads); } AvL = 0.f; @@ -1865,219 +1886,128 @@ void ImProcFunctions::CompressDR(float *Source, int W_L, int H_L, float Compress } -void ImProcFunctions::ContrastResid(float * WavCoeffs_L0, struct cont_params &cp, int W_L, int H_L, float max0, float min0) +void ImProcFunctions::ContrastResid(float * WavCoeffs_L0, const cont_params &cp, int W_L, int H_L, float max0) { - float stren = cp.tmstrength; - float gamm = params->wavelet.gamma; - cp.TMmeth = 2; //default after testing - - if (cp.TMmeth == 1) { - min0 = 0.0f; - max0 = 32768.f; - } else if (cp.TMmeth == 2) { - min0 = 0.0f; - } + const float stren = cp.tmstrength; + const float gamm = params->wavelet.gamma; #ifdef _OPENMP #pragma omp parallel for #endif for (int i = 0; i < W_L * H_L; i++) { - WavCoeffs_L0[i] = (WavCoeffs_L0[i] - min0) / max0; - WavCoeffs_L0[i] *= gamm; - } - - float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. - float DetailBoost = stren; - - if (stren < 0.0f) { - DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. + WavCoeffs_L0[i] *= (gamm / max0); } + const float Compression = std::exp(-stren); //This modification turns numbers symmetric around 0 into exponents. + const float DetailBoost = std::max(stren, 0.f); //Go with effect of exponent only if uncompressing. CompressDR(WavCoeffs_L0, W_L, H_L, Compression, DetailBoost); - + max0 /= gamm; #ifdef _OPENMP #pragma omp parallel for // removed schedule(dynamic,10) #endif for (int ii = 0; ii < W_L * H_L; ii++) { - WavCoeffs_L0[ii] = WavCoeffs_L0[ii] * max0 * (1.f / gamm) + min0; + WavCoeffs_L0[ii] *= max0; } } - - - -void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params& cp, int W_L, int H_L, float max0, float min0) +void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, const cont_params& cp, int W_L, int H_L, float max0) { - float stren = cp.tmstrength; - float edgest = params->wavelet.edgs; - float sca = params->wavelet.scale; - float gamm = params->wavelet.gamma; - int rew = 0; //params->epd.reweightingIterates; + const float stren = cp.tmstrength; + const float edgest = params->wavelet.edgs; + const float sca = params->wavelet.scale; + const float gamm = params->wavelet.gamma; + constexpr int rew = 0; //params->epd.reweightingIterates; + EdgePreservingDecomposition epd2(W_L, H_L); - cp.TMmeth = 2; //default after testing - if (cp.TMmeth == 1) { - min0 = 0.0f; - max0 = 32768.f; - } else if (cp.TMmeth == 2) { - min0 = 0.0f; - } - - // max0=32768.f; #ifdef _OPENMP #pragma omp parallel for #endif for (int i = 0; i < W_L * H_L; i++) { - WavCoeffs_L0[i] = (WavCoeffs_L0[i] - min0) / max0; - WavCoeffs_L0[i] *= gamm; + WavCoeffs_L0[i] *= (gamm / max0); } - float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. - float DetailBoost = stren; - - if (stren < 0.0f) { - DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. - } + const float Compression = std::exp(-stren); //This modification turns numbers symmetric around 0 into exponents. + const float DetailBoost = std::max(stren, 0.f); //Go with effect of exponent only if uncompressing. //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. if (Iterates == 0) { Iterates = (unsigned int)(edgest * 15.0f); } + epd2.CompressDynamicRange(WavCoeffs_L0, sca / skip, edgest, Compression, DetailBoost, Iterates, rew); - epd2.CompressDynamicRange(WavCoeffs_L0, (float)sca / skip, edgest, Compression, DetailBoost, Iterates, rew); - + max0 /= gamm; //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. #ifdef _OPENMP #pragma omp parallel for // removed schedule(dynamic,10) #endif for (int ii = 0; ii < W_L * H_L; ii++) { - WavCoeffs_L0[ii] = WavCoeffs_L0[ii] * max0 * (1.f / gamm) + min0; + WavCoeffs_L0[ii] *= max0; } } -void ImProcFunctions::WaveletcontAllLfinal(const wavelet_decomposition &WaveletCoeffs_L, const cont_params &cp, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL) +void ImProcFunctions::WaveletcontAllLfinal(wavelet_decomposition& WaveletCoeffs_L, const cont_params &cp, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL) { int maxlvl = WaveletCoeffs_L.maxlevel(); - float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0; + float* WavCoeffs_L0 = WaveletCoeffs_L.get_coeff0(); for (int dir = 1; dir < 4; dir++) { for (int lvl = 0; lvl < maxlvl; lvl++) { int Wlvl_L = WaveletCoeffs_L.level_W(lvl); int Hlvl_L = WaveletCoeffs_L.level_H(lvl); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); finalContAllL(WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, mean, sigma, MaxP, waOpacityCurveWL); } } } -void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float **varchrom, const wavelet_decomposition &WaveletCoeffs_L, const Wavblcurve & wavblcurve, - struct cont_params &cp, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* ChCurve, bool Chutili) +void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition& WaveletCoeffs_L, const Wavblcurve & wavblcurve, + struct cont_params &cp, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveSH & waOpacityCurveSH, FlatCurve* ChCurve, bool Chutili) { const int maxlvl = WaveletCoeffs_L.maxlevel(); const int W_L = WaveletCoeffs_L.level_W(0); const int H_L = WaveletCoeffs_L.level_H(0); - float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0; + float* WavCoeffs_L0 = WaveletCoeffs_L.get_coeff0(); - float contrast = cp.contrast; + const float contrast = cp.contrast; double avedbl = 0.0; // use double precision for large summations float max0 = 0.f; - float min0 = FLT_MAX; - if (contrast != 0.f || (cp.tonemap && cp.resena)) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step + if (contrast != 0.f || (cp.tonemap && cp.resena)) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step #ifdef _OPENMP - #pragma omp parallel for reduction(+:avedbl) num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for reduction(+:avedbl) reduction(max:max0) num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = 0; i < W_L * H_L; i++) { avedbl += static_cast(WavCoeffs_L0[i]); + max0 = std::max(WavCoeffs_L0[i], max0); } - -#ifdef _OPENMP - #pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - { - float lminL = FLT_MAX; - float lmaxL = 0.f; - -#ifdef _OPENMP - #pragma omp for -#endif - - for (int i = 0; i < W_L * H_L; i++) { - if (WavCoeffs_L0[i] < lminL) { - lminL = WavCoeffs_L0[i]; - } - - if (WavCoeffs_L0[i] > lmaxL) { - lmaxL = WavCoeffs_L0[i]; - } - - } - -#ifdef _OPENMP - #pragma omp critical -#endif - { - if (lminL < min0) { - min0 = lminL; - } - - if (lmaxL > max0) { - max0 = lmaxL; - } - } - - } - } - //tone mapping - if (cp.tonemap && cp.contmet == 2 && cp.resena) { + if (cp.tonemap && cp.contmet == 2 && cp.resena) { //iterate = 5 - EPDToneMapResid(WavCoeffs_L0, 0, skip, cp, W_L, H_L, max0, min0); - + EPDToneMapResid(WavCoeffs_L0, 0, skip, cp, W_L, H_L, max0); } //end tonemapping max0 /= 327.68f; - min0 /= 327.68f; - float ave = avedbl / (double)(W_L * H_L); - float avg = ave / 32768.f; - float *koeLi[12]; - float maxkoeLi[12]; + const float ave = avedbl / (W_L * H_L); + const float avg = LIM01(ave / 32768.f); - float *koeLibuffer = nullptr; - - for (int y = 0; y < 12; y++) { - maxkoeLi[y] = 0.f; //9 - } - - koeLibuffer = new float[12 * H_L * W_L]; //12 - - for (int i = 0; i < 12; i++) { //9 - koeLi[i] = &koeLibuffer[i * W_L * H_L]; - } - - for (int j = 0; j < 12; j++) //9 - for (int i = 0; i < W_L * H_L; i++) { - koeLi[j][i] = 0.f; - } - - avg = LIM01(avg); - double contreal = 0.6 * contrast; + const double contreal = 0.6 * contrast; DiagonalCurve resid_contrast({ DCT_NURBS, 0, 0, @@ -2086,43 +2016,29 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * 1, 1 }); + if (contrast != 0.f && cp.resena && max0 > 0.f) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step #ifdef _OPENMP - #pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - { - if (contrast != 0.f && cp.resena && max0 > 0.f) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step - { - -#ifdef _OPENMP - #pragma omp for + #pragma omp parallel for num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif - for (int i = 0; i < W_L * H_L; i++) { - float buf = LIM01(WavCoeffs_L0[i] / 32768.f); - buf = resid_contrast.getVal(buf); - buf *= 32768.f; - WavCoeffs_L0[i] = buf; - } - } - } - - - if (cp.tonemap && cp.contmet == 1 && cp.resena) { - float maxp = max0 * 256.f; - float minp = min0 * 256.f; -#ifdef _OPENMP - #pragma omp single -#endif - ContrastResid(WavCoeffs_L0, cp, W_L, H_L, maxp, minp); + for (int i = 0; i < W_L * H_L; i++) { + float buf = LIM01(WavCoeffs_L0[i] / 32768.f); + buf = resid_contrast.getVal(buf); + buf *= 32768.f; + WavCoeffs_L0[i] = buf; } } - if ((cp.conres >= 0.f || cp.conresH >= 0.f) && cp.resena && !cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step - LabImage *temp = nullptr; - temp = new LabImage(W_L, H_L); + if (cp.tonemap && cp.contmet == 1 && cp.resena) { + const float maxp = max0 * 256.f; + ContrastResid(WavCoeffs_L0, cp, W_L, H_L, maxp); + } + + if ((cp.conres >= 0.f || cp.conresH >= 0.f) && cp.resena && !cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step + const std::unique_ptr temp(new LabImage(W_L, H_L)); #ifdef _OPENMP - #pragma omp for + #pragma omp parallel for num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = 0; i < H_L; i++) { @@ -2131,12 +2047,10 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * } } - { - ImProcFunctions::shadowsHighlights(temp, true, 1, cp.conresH, cp.conres, cp.radius, skip, cp.thH, cp.th); - } + ImProcFunctions::shadowsHighlights(temp.get(), true, 1, cp.conresH, cp.conres, cp.radius, skip, cp.thH, cp.th); #ifdef _OPENMP - #pragma omp for + #pragma omp parallel for num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = 0; i < H_L; i++) { @@ -2144,18 +2058,11 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * WavCoeffs_L0[i * W_L + j] = temp->L[i][j]; } } - - delete temp; - } -#ifdef _OPENMP - #pragma omp barrier -#endif - if ((cp.conres != 0.f || cp.conresH != 0.f) && cp.resena && cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step #ifdef _OPENMP - #pragma omp for nowait + #pragma omp parallel for #endif for (int i = 0; i < W_L * H_L; i++) { @@ -2163,13 +2070,13 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * float LL100 = LL / 327.68f; float tran = 5.f;//transition //shadow - float alp = 3.f; //increase contrast sahdow in lowlights between 1 and ?? if (cp.th > (100.f - tran)) { tran = 100.f - cp.th; } if (LL100 < cp.th) { + constexpr float alp = 3.f; //increase contrast sahdow in lowlights between 1 and ?? float aalp = (1.f - alp) / cp.th; //no changes for LL100 = cp.th float kk = aalp * LL100 + alp; WavCoeffs_L0[i] *= (1.f + kk * cp.conres / 200.f); @@ -2198,30 +2105,45 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * //Blur luma if (cp.blurres != 0.f && cp.resena) { - float rad = 0.7f * cp.blurres / skip; - float * bef = new float[W_L * H_L]; - float * aft = new float[W_L * H_L]; + int minWL = min(W_L, H_L); - for (int i = 0; i < H_L * W_L; i++) { - bef[i] = WavCoeffs_L0[i]; + //printf("skip=%i WL=%i HL=%i min=%i\n", skip, W_L, H_L, minWL); + if (minWL > 140) { //disabled if too low windows + constexpr float k = 0.5f; + float rad = k * cp.blurres / skip; + float * bef = new float[W_L * H_L]; + float * aft = new float[W_L * H_L]; + + for (int i = 0; i < H_L * W_L; i++) { + bef[i] = WavCoeffs_L0[i]; + } + + boxblur(bef, aft, rad, W_L, H_L, false); + + for (int i = 0; i < H_L * W_L; i++) { + WavCoeffs_L0[i] = aft[i]; + } + + delete[] bef; + delete[] aft; } - - boxblur(bef, aft, rad, W_L, H_L, false); - - for (int i = 0; i < H_L * W_L; i++) { - WavCoeffs_L0[i] = aft[i]; - } - - delete[] bef; - delete[] aft; } // int n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n32; n0 = n1 = n2 = n3 = n4 = n5 = n6 = n7 = n8 = n9 = n10 = n32 = 0; + float *koeLi[12]; + + const std::unique_ptr koeLibuffer(new float[12 * H_L * W_L]()); + + for (int i = 0; i < 12; i++) { + koeLi[i] = &koeLibuffer[i * W_L * H_L]; + } + + float maxkoeLi[12] = {0.f}; #ifdef _OPENMP - #pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif { //enabled Lipschitz..replace simple by complex edge detection @@ -2235,14 +2157,15 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * float eddlipinfl = 0.005f * cp.edgsens + 0.4f; float eddlipampl = 1.f + cp.edgampl / 50.f; - if (cp.detectedge) { //enabled Lipschitz control...more memory..more time... - float *tmCBuffer = new float[H_L * W_L]; + const std::unique_ptr tmCBuffer(new float[H_L * W_L]); float *tmC[H_L]; for (int i = 0; i < H_L; i++) { tmC[i] = &tmCBuffer[i * W_L]; } + float gradw = cp.eddet; + float tloww = cp.eddetthr; #ifdef _OPENMP #pragma omp for schedule(dynamic) collapse(2) @@ -2250,14 +2173,14 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * for (int lvl = 0; lvl < 4; lvl++) { for (int dir = 1; dir < 4; dir++) { - float ** WavCoeffs_LL = WaveletCoeffs_L.level_coeffs(lvl); - calckoe(WavCoeffs_LL, cp, koeLi, lvl, dir, WaveletCoeffs_L.level_W(lvl), WaveletCoeffs_L.level_H(lvl), edd, maxkoeLi, tmC); + const float* const* WavCoeffs_LL = WaveletCoeffs_L.level_coeffs(lvl); + float tempkoeli; + calckoe (WavCoeffs_LL, gradw, tloww, koeLi, lvl , dir, W_L, H_L, edd, tempkoeli, tmC); + maxkoeLi[lvl * 3 + dir - 1] = tempkoeli; // return convolution KoeLi and maxkoeLi of level 0 1 2 3 and Dir Horiz, Vert, Diag } } - delete [] tmCBuffer; - float aamp = 1.f + cp.eddetthrHi / 100.f; for (int lvl = 0; lvl < 4; lvl++) { @@ -2322,12 +2245,10 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * //if not no edge or reduction float bet = 1.f; - //if(cp.lip3) {//enhance algorithm if (alph > eddlipinfl && beta < 0.85f * eddlipinfl) { //0.85 arbitrary value ==> eliminate from edge if H V D too different bet = beta; } - //} float AmpLip = 1.f; if (alph > eddlipinfl) { @@ -2338,16 +2259,6 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * kampli = AmpLip / aamp; } - // comparison betwwen pixel and neighbours to do ==> I think 3 dir above is better - /* if(cp.lip3){ - koeLi[lvl*3][i*W_L + j] = (koeLi[lvl*3][i*W_L + j] + koeLi[lvl*3][(i-1)*W_L + j] + koeLi[lvl*3][(i+1)*W_L + j] - + koeLi[lvl*3][i*W_L + j+1] + koeLi[lvl*3][i*W_L + j-1] + koeLi[lvl*3][(i-1)*W_L + j-1] - + koeLi[lvl*3][(i-1)*W_L + j+1] +koeLi[lvl*3][(i+1)*W_L + j-1] +koeLi[lvl*3][(i+1)*W_L + j+1])/9.f; - } - */ - // apply to each direction Wavelet level : horizontal / vertiacle / diagonal - //interm += SQR(koeLi[lvl*3 + dir-1][i*W_L + j]); - interm *= kampli; if (interm < cp.eddetthr / eddlow) { @@ -2385,97 +2296,96 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * int Wlvl_L = WaveletCoeffs_L.level_W(lvl); int Hlvl_L = WaveletCoeffs_L.level_H(lvl); - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + float* const* WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); - ContAllL(koeLi, maxkoeLi, true, maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, sigma, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, ChCurve, Chutili); - //blur level - float klev = 1.f; + ContAllL(koeLi, maxkoeLi[lvl * 3 + dir - 1], true, maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, sigma, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, waOpacityCurveSH, ChCurve, Chutili); + int minWL = min(Wlvl_L, Hlvl_L); - if (wavblcurve && wavcurvecomp && cp.blena) { - // printf("Blur level L\n"); - float mea[10]; - float effect = cp.bluwav; - float beta = 0.f; - float offs = 1.f; + if(minWL > 180) { + if (wavblcurve && wavcurvecomp && cp.blena) { + // printf("Blur level L\n"); + float mea[10]; + const float effect = cp.bluwav; + constexpr float offs = 1.f; + float * beta = new float[Wlvl_L * Hlvl_L]; - calceffect(lvl, mean, sigma, mea, effect, offs); + calceffect(lvl, mean, sigma, mea, effect, offs); - float * bef = new float[Wlvl_L * Hlvl_L]; - float * aft = new float[Wlvl_L * Hlvl_L]; + float * bef = new float[Wlvl_L * Hlvl_L]; + float * aft = new float[Wlvl_L * Hlvl_L]; - for (int co = 0; co < Hlvl_L * Wlvl_L; co++) { - bef[co] = WavCoeffs_L[dir][co]; - float WavCL = std::fabs(WavCoeffs_L[dir][co]); + for (int co = 0; co < Hlvl_L * Wlvl_L; co++) { + bef[co] = WavCoeffs_L[dir][co]; + float WavCL = std::fabs(WavCoeffs_L[dir][co]); - if (WavCL < mea[0]) { - beta = 0.05f; - n0++; + if (WavCL < mea[0]) { + beta[co] = 0.05f; + n0++; - if (WavCL < 32.7) { - n32++; + if (WavCL < 32.7) { + n32++; + } + } else if (WavCL < mea[1]) { + beta[co] = 0.2f; + n1++; + } else if (WavCL < mea[2]) { + beta[co] = 0.7f; + n2++; + } else if (WavCL < mea[3]) { + beta[co] = 1.f; //standard + n3++; + } else if (WavCL < mea[4]) { + beta[co] = 1.f; + n4++; + } else if (WavCL < mea[5]) { + beta[co] = 0.8f; //+sigma + n5++; + } else if (WavCL < mea[6]) { + beta[co] = 0.6f; + n6++; + } else if (WavCL < mea[7]) { + beta[co] = 0.4f; + n7++; + } else if (WavCL < mea[8]) { + beta[co] = 0.2f; // + 2 sigma + n8++; + } else if (WavCL < mea[9]) { + beta[co] = 0.1f; + n9++; + } else { + beta[co] = 0.01f; + n10++; } - } else if (WavCL < mea[1]) { - beta = 0.2f; - n1++; - } else if (WavCL < mea[2]) { - beta = 0.7f; - n2++; - } else if (WavCL < mea[3]) { - beta = 1.f; //standard - n3++; - } else if (WavCL < mea[4]) { - beta = 1.f; - n4++; - } else if (WavCL < mea[5]) { - beta = 0.8f; //+sigma - n5++; - } else if (WavCL < mea[6]) { - beta = 0.6f; - n6++; - } else if (WavCL < mea[7]) { - beta = 0.4f; - n7++; - } else if (WavCL < mea[8]) { - beta = 0.2f; // + 2 sigma - n8++; - } else if (WavCL < mea[9]) { - beta = 0.1f; - n9++; - } else { - beta = 0.01f; - n10++; + + } + if (settings->verbose) { + printf("lvl=%i n0=%i n32=%i n1=%i n2=%i n3=%i n4=%i n5=%i n6=%i n7=%i n8=%i n9=%i n10=%i\n", lvl, n0, n0 - n32, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); + } + float klev = (wavblcurve[lvl * 55.5f]); + + //blur level + klev *= 80.f / skip; + boxblur(bef, aft, klev, Wlvl_L, Hlvl_L, false); + + for (int co = 0; co < Hlvl_L * Wlvl_L; co++) { + aft[co] = bef[co] * (1.f - beta[co]) + aft[co] * beta[co]; + WavCoeffs_L[dir][co] = aft[co]; + } + + delete[] bef; + delete[] aft; + delete[] beta; } - - if (settings->verbose) { - printf("lvl=%i n0=%i n32=%i n1=%i n2=%i n3=%i n4=%i n5=%i n6=%i n7=%i n8=%i n9=%i n10=%i\n", lvl, n0, n0 - n32, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); - } - - klev = (wavblcurve[lvl * 55.5f]); - - klev *= beta * 100.f / skip; - boxblur(bef, aft, klev, Wlvl_L, Hlvl_L, false); - - for (int co = 0; co < Hlvl_L * Wlvl_L; co++) { - WavCoeffs_L[dir][co] = aft[co]; - } - - delete[] bef; - delete[] aft; } } } } - - //delete edge detection - if (koeLibuffer) { - delete [] koeLibuffer; - } } -void ImProcFunctions::WaveletAandBAllAB(const wavelet_decomposition &WaveletCoeffs_a, const wavelet_decomposition &WaveletCoeffs_b, +void ImProcFunctions::WaveletAandBAllAB(wavelet_decomposition& WaveletCoeffs_a, wavelet_decomposition& WaveletCoeffs_b, const cont_params &cp, FlatCurve* hhCurve, bool hhutili) { // StopWatch Stop1("WaveletAandBAllAB"); @@ -2483,10 +2393,10 @@ void ImProcFunctions::WaveletAandBAllAB(const wavelet_decomposition &WaveletCoef int W_L = WaveletCoeffs_a.level_W(0); int H_L = WaveletCoeffs_a.level_H(0); - float * WavCoeffs_a0 = WaveletCoeffs_a.coeff0; - float * WavCoeffs_b0 = WaveletCoeffs_b.coeff0; + float* WavCoeffs_a0 = WaveletCoeffs_a.get_coeff0(); + float* WavCoeffs_b0 = WaveletCoeffs_b.get_coeff0(); #ifdef _OPENMP - #pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif { #ifdef __SSE2__ @@ -2541,18 +2451,18 @@ void ImProcFunctions::WaveletAandBAllAB(const wavelet_decomposition &WaveletCoef } -void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float **varchrom, const wavelet_decomposition &WaveletCoeffs_ab, const Wavblcurve & wavblcurve, const WavOpacityCurveW & waOpacityCurveW, - struct cont_params &cp, const bool useChannelA, int skip, float *meanab, float *sigmaab) +void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition& WaveletCoeffs_ab, const Wavblcurve & wavblcurve, const WavOpacityCurveW & waOpacityCurveW, + struct cont_params &cp, const bool useChannelA, int skip, float *meanab, float *sigmaab) { int maxlvl = WaveletCoeffs_ab.maxlevel(); int W_L = WaveletCoeffs_ab.level_W(0); int H_L = WaveletCoeffs_ab.level_H(0); - float * WavCoeffs_ab0 = WaveletCoeffs_ab.coeff0; + float* WavCoeffs_ab0 = WaveletCoeffs_ab.get_coeff0(); #ifdef _OPENMP - #pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif { if (cp.chrores != 0.f && cp.resena) { // cp.chrores == 0.f means all will be multiplied by 1.f, so we can skip the processing of residual @@ -2587,20 +2497,6 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float if ((modhue > cp.t_ry || modhue < cp.t_ly)) { scale = (100.f + cp.sky) / 100.1f; } - - /* else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { - scale=(100.f+cp.sky)/100.1f; - float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); - float br=scale-cp.t_ry*ar; - scale=ar*modhue+br; - } - else if((modhue > cp.b_ly && modhue < cp.t_ly)) { - scale=(100.f+cp.sky)/100.1f; - float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); - float bl=scale-cp.t_ly*al; - scale=al*modhue+bl; - } - */ } WavCoeffs_ab0[i] *= (1.f + cp.chrores * (scale) / 100.f); @@ -2619,7 +2515,7 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float int jj = i - ii * W_L; float LL = (labco->L[ii * 2][jj * 2]) / 327.68f; //I use labco but I can use also WavCoeffs_L0 (more exact but more memory) - float sca = 1.f; //amplifer - reducter...about 1, but perhaps 0.6 or 1.3 + float sca = 1.f; //amplifier - reducter...about 1, but perhaps 0.6 or 1.3 if (useChannelA) { //green red (little magenta) //transition to avoid artifacts with 6 between 30 to 36 and 63 to 69 @@ -2667,22 +2563,28 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float //Blur chroma if (cp.blurcres != 0.f && cp.resena) { - float rad = 0.7f * cp.blurcres / skip; - float * bef = new float[W_L * H_L]; - float * aft = new float[W_L * H_L]; + int minWL = min(W_L, H_L); - for (int i = 0; i < H_L * W_L; i++) { - bef[i] = WavCoeffs_ab0[i]; + //printf("skip=%i WL=%i HL=%i min=%i\n", skip, W_L, H_L, minWL); + if (minWL > 140) { //disabled if too low windows + constexpr float k = 0.5f; + float rad = k * cp.blurcres / skip; + float * bef = new float[W_L * H_L]; + float * aft = new float[W_L * H_L]; + + for (int i = 0; i < H_L * W_L; i++) { + bef[i] = WavCoeffs_ab0[i]; + } + + boxblur(bef, aft, rad, W_L, H_L, false); + + for (int i = 0; i < H_L * W_L; i++) { + WavCoeffs_ab0[i] = aft[i]; + } + + delete[] bef; + delete[] aft; } - - boxblur(bef, aft, rad, W_L, H_L, false); - - for (int i = 0; i < H_L * W_L; i++) { - WavCoeffs_ab0[i] = aft[i]; - } - - delete[] bef; - delete[] aft; } @@ -2706,68 +2608,76 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl); - float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); - ContAllAB(labco, maxlvl, varhue, varchrom, WavCoeffs_ab, WavCoeffs_ab0, lvl, dir, waOpacityCurveW, cp, Wlvl_ab, Hlvl_ab, useChannelA); + float* const* WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); + ContAllAB(labco, maxlvl, varhue, varchrom, WavCoeffs_ab, WavCoeffs_ab0, lvl, dir, waOpacityCurveW, cp, Wlvl_ab, Hlvl_ab, useChannelA, meanab, sigmaab); + int minWL = min(Wlvl_ab, Hlvl_ab); + + if(minWL > 180) { + if (wavblcurve && wavcurvecomp && cp.blena && cp.chrwav > 0.f) { - if (wavblcurve && wavcurvecomp && cp.blena && cp.chrwav > 0.f) { + float mea[10]; + float effect = cp.bluwav; + float offs = 1.f; + float * beta = new float[Wlvl_ab * Hlvl_ab]; - float mea[10]; - float effect = cp.bluwav; - float beta = 0.f; - float offs = 1.f; - - calceffect(lvl, meanab, sigmaab, mea, effect, offs); - - float * bef = new float[Wlvl_ab * Hlvl_ab]; - float * aft = new float[Wlvl_ab * Hlvl_ab]; - float klev; - - for (int co = 0; co < Hlvl_ab * Wlvl_ab; co++) { - bef[co] = WavCoeffs_ab[dir][co]; - float WavCab = std::fabs(WavCoeffs_ab[dir][co]); - - if (WavCab < mea[0]) { - beta = 0.05f; - } else if (WavCab < mea[1]) { - beta = 0.2f; - } else if (WavCab < mea[2]) { - beta = 0.7f; - } else if (WavCab < mea[3]) { - beta = 1.f; //standard - } else if (WavCab < mea[4]) { - beta = 1.f; - } else if (WavCab < mea[5]) { - beta = 0.8f; //+sigma - } else if (WavCab < mea[6]) { - beta = 0.6f; - } else if (WavCab < mea[7]) { - beta = 0.4f; - } else if (WavCab < mea[8]) { - beta = 0.2f; // + 2 sigma - } else if (WavCab < mea[9]) { - beta = 0.1f; - } else { - beta = 0.0f; + for (int co = 0; co < Wlvl_ab * Hlvl_ab; co++) { + beta[co] = 1.f; } + calceffect(lvl, meanab, sigmaab, mea, effect, offs); + float * bef = new float[Wlvl_ab * Hlvl_ab]; + float * aft = new float[Wlvl_ab * Hlvl_ab]; + float klev; + + for (int co = 0; co < Hlvl_ab * Wlvl_ab; co++) { + bef[co] = WavCoeffs_ab[dir][co]; + float WavCab = std::fabs(WavCoeffs_ab[dir][co]); + + if (WavCab < mea[0]) { + beta[co] = 0.05f; + } else if (WavCab < mea[1]) { + beta[co] = 0.2f; + } else if (WavCab < mea[2]) { + beta[co] = 0.7f; + } else if (WavCab < mea[3]) { + beta[co] = 1.f; //standard + } else if (WavCab < mea[4]) { + beta[co] = 1.f; + } else if (WavCab < mea[5]) { + beta[co] = 0.8f; //+sigma + } else if (WavCab < mea[6]) { + beta[co] = 0.6f; + } else if (WavCab < mea[7]) { + beta[co] = 0.4f; + } else if (WavCab < mea[8]) { + beta[co] = 0.2f; // + 2 sigma + } else if (WavCab < mea[9]) { + beta[co] = 0.1f; + } else { + beta[co] = 0.0f; + } + + + } + + klev = (wavblcurve[lvl * 55.5f]); + + klev *= cp.chrwav * 80.f / skip; + + boxblur(bef, aft, klev, Wlvl_ab, Hlvl_ab, false); + + for (int co = 0; co < Hlvl_ab * Wlvl_ab; co++) { + aft[co] = bef[co] * (1.f - beta[co]) + aft[co] * beta[co]; + WavCoeffs_ab[dir][co] = aft[co]; + } + + delete[] bef; + delete[] aft; + delete[] beta; } - - klev = (wavblcurve[lvl * 55.5f]); - - klev *= beta * cp.chrwav * 100.f / skip; - - boxblur(bef, aft, klev, Wlvl_ab, Hlvl_ab, false); - - for (int co = 0; co < Hlvl_ab * Wlvl_ab; co++) { - WavCoeffs_ab[dir][co] = aft[co]; - } - - delete[] bef; - delete[] aft; } - } } @@ -2778,18 +2688,19 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, float *koeLi[12], int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC) +//void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, float *koeLi[12], int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC) +void ImProcFunctions::calckoe (const float* const* WavCoeffs_LL, float gradw, float tloww, float *koeLi[12], int level, int dir, int W_L, int H_L, float edd, float &maxkoeLi, float **tmC) { int borderL = 2; - if (cp.eddetthr < 30.f) { + if (tloww < 30.f) { borderL = 1; // I calculate coefficients with r size matrix 3x3 r=1 ; 5x5 r=2; 7x7 r=3 /* float k[2*r][2*r]; - for(int i=1;i<=(2*r+1);i++) { - for(int j=1;j<=(2*r+1);j++) { + for (int i=1;i<=(2*r+1);i++) { + for (int j=1;j<=(2*r+1);j++) { k[i][j]=(1.f/6.283*sigma*sigma)*exp(-SQR(i-r-1)+SQR(j-r-1)/2.f*SQR(sigma)); } } @@ -2806,7 +2717,7 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa } } - } else if (cp.eddetthr >= 30.f && cp.eddetthr < 50.f) { + } else if (tloww < 50.f) { borderL = 1; for (int i = 1; i < H_L - 1; i++) { //sigma=0.85 @@ -2822,7 +2733,7 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa } - else if (cp.eddetthr >= 50.f && cp.eddetthr < 75.f) { + else if (tloww < 75.f) { borderL = 1; for (int i = 1; i < H_L - 1; i++) { @@ -2834,12 +2745,10 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa } } - else if (cp.eddetthr >= 75.f) { + else if (tloww >= 75.f) { borderL = 2; - //if(cp.lip3 && level > 1) { if (level > 1) { // do not activate 5x5 if level 0 or 1 - for (int i = 2; i < H_L - 2; i++) { for (int j = 2; j < W_L - 2; j++) { // Gaussian 1.1 @@ -2856,7 +2765,7 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa // 4 9 12 9 4 // 2 4 5 4 2 // divi 159 - if (cp.eddetthr < 85.f) { //sigma=1.1 + if (tloww < 85.f) { //sigma=1.1 tmC[i][j] = (15.f * WavCoeffs_LL[dir][i * W_L + j] + 10.f * WavCoeffs_LL[dir][(i - 1) * W_L + j] + 10.f * WavCoeffs_LL[dir][(i + 1) * W_L + j] + 10.f * WavCoeffs_LL[dir][i * W_L + j + 1] + 10.f * WavCoeffs_LL[dir][i * W_L + j - 1] + 7.f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 1] + 7.f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 1] + 7.f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 1] + 7.f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 1] @@ -2887,25 +2796,10 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa } - - /* - // I suppress these 2 convolutions ==> lees good results==> probably because structure data different and also I compare to original value which have + and - - for(int i = borderL; i < H_L-borderL; i++ ) {//[-1 0 1] x==>j - for(int j = borderL; j < W_L-borderL; j++) { - tmC[i][j]=- WavCoeffs_LL[dir][(i)*W_L + j-1] + WavCoeffs_LL[dir][(i)*W_L + j+1]; - } - } - for(int i = borderL; i < H_L-borderL; i++ ) {//[1 0 -1] y==>i - for(int j = borderL; j < W_L-borderL; j++) { - tmC[i][j]= - WavCoeffs_LL[dir][(i-1)*W_L + j] + WavCoeffs_LL[dir][(i+1)*W_L + j]; - } - } - */ - float thr = 40.f; //avoid artifact eg. noise...to test float thr2 = 1.5f * edd; //edd can be modified in option ed_detect - thr2 += cp.eddet / 30.f; //to test - float diffFactor = (cp.eddet / 100.f); + thr2 += gradw / 30.f; //to test + float diffFactor = (gradw / 100.f); for (int i = 0; i < H_L; i++) { for (int j = 0; j < W_L; j++) { @@ -2917,47 +2811,44 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa for (int j = borderL; j < W_L - borderL; j++) { // my own algo : probably a little false, but simpler as Lipschitz ! // Thr2 = maximum of the function ==> Lipsitch says = probably edge -// float temp = WavCoeffs_LL[dir][i*W_L + j]; -// if(temp>=0.f && temp < thr) temp = thr; -// if(temp < 0.f && temp > -thr) temp = -thr; float temp = rtengine::max(std::fabs(WavCoeffs_LL[dir][i * W_L + j]), thr); koeLi[level * 3 + dir - 1][i * W_L + j] = rtengine::min(thr2, std::fabs(tmC[i][j] / temp)); // limit maxi //it will be more complicated to calculate both Wh and Wv, but we have also Wd==> pseudo Lipschitz - if (koeLi[level * 3 + dir - 1][i * W_L + j] > maxkoeLi[level * 3 + dir - 1]) { - maxkoeLi[level * 3 + dir - 1] = koeLi[level * 3 + dir - 1][i * W_L + j]; + if (koeLi[level * 3 + dir - 1][i * W_L + j] > maxkoeLi) { + maxkoeLi = koeLi[level * 3 + dir - 1][i * W_L + j]; } - float diff = maxkoeLi[level * 3 + dir - 1] - koeLi[level * 3 + dir - 1][i * W_L + j]; + float diff = maxkoeLi - koeLi[level * 3 + dir - 1][i * W_L + j]; diff *= diffFactor; - koeLi[level * 3 + dir - 1][i * W_L + j] = maxkoeLi[level * 3 + dir - 1] - diff; + koeLi[level * 3 + dir - 1][i * W_L + j] = maxkoeLi - diff; } } } -void ImProcFunctions::finalContAllL(float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, const cont_params &cp, +void ImProcFunctions::finalContAllL(float* const* WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, const cont_params &cp, int W_L, int H_L, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL) { if (cp.diagcurv && cp.finena && MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { //curve float insigma = 0.666f; //SD float logmax = log(MaxP[level]); //log Max - float rapX = (mean[level] + sigma[level]) / MaxP[level]; //rapport between sD / max + float rapX = (mean[level] + cp.sigmafin * sigma[level]) / MaxP[level]; //rapport between sD / max float inx = log(insigma); float iny = log(rapX); float rap = inx / iny; //koef - float asig = 0.166f / sigma[level]; + float asig = 0.166f / (sigma[level] * cp.sigmafin); float bsig = 0.5f - asig * mean[level]; float amean = 0.5f / mean[level]; #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, W_L * 16) num_threads(wavNestedLevels) if(wavNestedLevels>1) + #pragma omp parallel for schedule(dynamic, W_L * 16) num_threads(wavNestedLevels) if (wavNestedLevels>1) #endif for (int i = 0; i < W_L * H_L; i++) { float absciss; - if (std::fabs(WavCoeffs_L[dir][i]) >= (mean[level] + sigma[level])) { //for max + if (std::fabs(WavCoeffs_L[dir][i]) >= (mean[level] + cp.sigmafin * sigma[level])) { //for max float valcour = xlogf(std::fabs(WavCoeffs_L[dir][i])); float valc = valcour - logmax; float vald = valc * rap; @@ -3090,8 +2981,8 @@ void ImProcFunctions::finalContAllL(float ** WavCoeffs_L, float * WavCoeffs_L0, } -void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz, int maxlvl, LabImage * labco, float ** varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, - int W_L, int H_L, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* ChCurve, bool Chutili) +void ImProcFunctions::ContAllL(float *koeLi[12], float maxkoeLi, bool lipschitz, int maxlvl, LabImage * labco, const float* const* varhue, const float* const* varchrom, float* const* WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, + int W_L, int H_L, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveSH & waOpacityCurveSH, FlatCurve* ChCurve, bool Chutili) { assert(level >= 0); assert(maxlvl > level); @@ -3115,12 +3006,16 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz constexpr float aedstr = (eddstrength - 1.f) / 90.f; constexpr float bedstr = 1.f - 10.f * aedstr; - float mea[10]; - float beta = 1.f; + std::unique_ptr beta(new float[W_L * H_L]); + + for (int co = 0; co < H_L * W_L; co++) { + beta[co] = 1.f; + } if (cp.eff < 2.5f) { float effect = cp.eff; float offs = 1.f; + float mea[10]; calceffect(level, mean, sigma, mea, effect, offs); @@ -3128,27 +3023,27 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float WavCL = std::fabs(WavCoeffs_L[dir][co]); if (WavCL < mea[0]) { - beta = 0.05f; + beta[co] = 0.05f; } else if (WavCL < mea[1]) { - beta = 0.2f; + beta[co] = 0.2f; } else if (WavCL < mea[2]) { - beta = 0.7f; + beta[co] = 0.7f; } else if (WavCL < mea[3]) { - beta = 1.f; //standard + beta[co] = 1.f; //standard } else if (WavCL < mea[4]) { - beta = 1.f; + beta[co] = 1.f; } else if (WavCL < mea[5]) { - beta = 0.8f; //+sigma + beta[co] = 0.8f; //+sigma } else if (WavCL < mea[6]) { - beta = 0.6f; + beta[co] = 0.6f; } else if (WavCL < mea[7]) { - beta = 0.4f; + beta[co] = 0.4f; } else if (WavCL < mea[8]) { - beta = 0.2f; // + 2 sigma + beta[co] = 0.2f; // + 2 sigma } else if (WavCL < mea[9]) { - beta = 0.1f; + beta[co] = 0.1f; } else { - beta = 0.0f; + beta[co] = 0.0f; } } @@ -3247,7 +3142,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz value *= (atten01234 * scaleskip[1]); //for zoom < 100% reduce strength...I choose level 1...but!! } - value *= beta; + // value *= beta; float edge = 1.f; float lim0 = 20.f; //arbitrary limit for low radius and level between 2 or 3 to 30 maxi float lev = float (level); @@ -3312,7 +3207,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float edgePrecalc = 1.f + refin; //estimate edge "pseudo variance" if (cp.EDmet == 2 && MaxP[level] > 0.f) { //curve - // if(exa) {//curve + // if (exa) {//curve float insigma = 0.666f; //SD float logmax = log(MaxP[level]); //log Max float rapX = (mean[level] + sigma[level]) / MaxP[level]; //rapport between sD / max @@ -3342,7 +3237,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz if (lipschitz) { if (level < 4) { - edge = 1.f + (edgePrecalc - 1.f) * (koeLi[level * 3][k]) / (1.f + 0.9f * maxkoeLi[level * 3 + dir - 1]); + edge = 1.f + (edgePrecalc - 1.f) * (koeLi[level * 3][k]) / (1.f + 0.9f * maxkoeLi); } else { edge = edgePrecalc; } @@ -3407,7 +3302,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz edge = rtengine::max(edge, 1.f); } - WavCoeffs_L[dir][k] *= edge; + WavCoeffs_L[dir][k] *= (1.f + (edge - 1.f) * beta[k]); } } } else if (cp.EDmet == 1) { //threshold adjuster @@ -3448,7 +3343,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz if (lipschitz) { if (level < 4) { - edge = 1.f + (edgePrecalc - 1.f) * (koeLi[level * 3][k]) / (1.f + 0.9f * maxkoeLi[level * 3 + dir - 1]); + edge = 1.f + (edgePrecalc - 1.f) * (koeLi[level * 3][k]) / (1.f + 0.9f * maxkoeLi); } else { edge = edgePrecalc; } @@ -3524,7 +3419,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz } } - WavCoeffs_L[dir][k] *= edge; + WavCoeffs_L[dir][k] *= (1.f + (edge - 1.f) * beta[k]); } } } @@ -3532,6 +3427,9 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz if (!lipschitz) { delete [] koe; } + if (!(cp.bam && cp.finena)) { + beta.reset(); + } } @@ -3571,7 +3469,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz const float lowthr = params->wavelet.lowthr; float mea[10]; float effect = cp.sigm; - float beta; + float lbeta; calceffect(level, mean, sigma, mea, effect, offs); @@ -3581,39 +3479,42 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float red0 = 0.005f * (110.f - lowthr); float red1 = 0.008f * (110.f - lowthr); float red2 = 0.011f * (110.f - lowthr); - +// int n = 0; +// int m = 0; +// int p = 0; +// int q = 0; for (int i = 0; i < W_L * H_L; i++) { float kLlev = 1.f; if (cpMul < 0.f) { - beta = 1.f; // disabled for negatives values "less contrast" + lbeta = 1.f; // disabled for negatives values "less contrast" } else { float WavCL = std::fabs(WavCoeffs_L[dir][i]); //reduction amplification: max action between mean / 2 and mean + sigma // arbitrary coefficient, we can add a slider !! if (WavCL < mea[0]) { - beta = 0.4f * red0;//preserve very low contrast (sky...) + lbeta = 0.4f * red0;//preserve very low contrast (sky...) } else if (WavCL < mea[1]) { - beta = 0.5f * red1; + lbeta = 0.5f * red1; } else if (WavCL < mea[2]) { - beta = 0.7f * red2; + lbeta = 0.7f * red2; } else if (WavCL < mea[3]) { - beta = 1.f; //standard + lbeta = 1.f; //standard } else if (WavCL < mea[4]) { - beta = 1.f; + lbeta = 1.f; } else if (WavCL < mea[5]) { - beta = 0.8f; //+sigma + lbeta = 0.8f; //+sigma } else if (WavCL < mea[6]) { - beta = 0.6f; + lbeta = 0.6f; } else if (WavCL < mea[7]) { - beta = 0.4f; + lbeta = 0.4f; } else if (WavCL < mea[8]) { - beta = 0.2f; // + 2 sigma + lbeta = 0.2f; // + 2 sigma } else if (WavCL < mea[9]) { - beta = 0.1f; + lbeta = 0.1f; } else { - beta = 0.0f; + lbeta = 0.0f; } } @@ -3673,9 +3574,10 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz //linear transition HL float diagacc = 1.f; - float alpha = (1024.f + 15.f * (float) cpMul * scale * scale2 * beta * diagacc) / 1024.f ; + float alpha = (1024.f + 15.f * (float) cpMul * scale * scale2 * lbeta * diagacc) / 1024.f ; - if (cp.HSmet && cp.contena) { + // if (cp.HSmet && cp.contena) { + if (cp.HSmet && cp.contena && waOpacityCurveSH) { float aaal = (1.f - alpha) / ((cp.b_lhl - cp.t_lhl) * kH[level]); float bbal = 1.f - aaal * cp.b_lhl * kH[level]; float aaar = (alpha - 1.f) / (cp.t_rhl - cp.b_rhl) * kH[level]; @@ -3698,15 +3600,20 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz } } - if (level >= (9 - cp.numlevS)) { + if (level >= cp.numlevS - 1) { + // if(klevred < 0.f && level >= 3) {//level > 3 to avoid bad use of the curve if user put positives values negatives if ((LL100 > cp.t_lsl && LL100 < cp.t_rsl)) { kLlev = alpha; + // n++; } else if ((LL100 > cp.b_lsl && LL100 <= cp.t_lsl)) { kLlev = aaalS * LL100 + bbalS; + // m++; } else if ((LL100 > cp.t_rsl && LL100 <= cp.b_rsl)) { kLlev = aaarS * LL100 + bbbrS; + // p++; } else { kLlev = 1.f; + // q++; } } @@ -3716,6 +3623,8 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz WavCoeffs_L[dir][i] *= (kLlev); } + + // printf("lev=%i n=%i m=%i p=%i q=%i\n", level, n, m, p, q); } if (waOpacityCurveW) { @@ -3723,6 +3632,40 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz } if (cp.bam && cp.finena) { + const float effect = cp.sigmadir; + constexpr float offs = 1.f; + float mea[10]; + + calceffect(level, mean, sigma, mea, effect, offs); + + for (int co = 0; co < H_L * W_L; co++) { + float WavCL = std::fabs(WavCoeffs_L[dir][co]); + + if (WavCL < mea[0]) { + beta[co] = 0.05f; + } else if (WavCL < mea[1]) { + beta[co] = 0.2f; + } else if (WavCL < mea[2]) { + beta[co] = 0.7f; + } else if (WavCL < mea[3]) { + beta[co] = 1.f; //standard + } else if (WavCL < mea[4]) { + beta[co] = 1.f; + } else if (WavCL < mea[5]) { + beta[co] = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta[co] = 0.6f; + } else if (WavCL < mea[7]) { + beta[co] = 0.4f; + } else if (WavCL < mea[8]) { + beta[co] = 0.2f; // + 2 sigma + } else if (WavCL < mea[9]) { + beta[co] = 0.1f; + } else { + beta[co] = 0.01f; + } + } + if (cp.opaW && cp.BAmet == 2) { int iteration = cp.ite; int itplus = 7 + iteration; @@ -3734,7 +3677,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz it = itmoins; } else if (level == med) { it = 7; - } else { /*if(level > med)*/ + } else { /*if (level > med)*/ it = itplus; } @@ -3742,8 +3685,8 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz //float bal = cp.balan;//-100 +100 float kba = 1.f; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; + // if (dir <3) kba= 1.f + bal/600.f; + // if (dir==3) kba = 1.f - bal/300.f; for (int i = 0; i < W_L * H_L; i++) { int ii = i / W_L; int jj = i - ii * W_L; @@ -3759,7 +3702,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz kba = 1.f - k2; } - WavCoeffs_L[dir][i] *= (kba); + WavCoeffs_L[dir][i] *= (1.f + (kba - 1.f) * beta[i]); } } } @@ -3775,7 +3718,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz it = itmoins; } else if (level == med) { it = 7; - } else { /*if(level > med)*/ + } else { /*if (level > med)*/ it = itplus; } @@ -3783,8 +3726,8 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float bal = cp.balan;//-100 +100 float kba = 1.f; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; + // if (dir <3) kba= 1.f + bal/600.f; + // if (dir==3) kba = 1.f - bal/300.f; for (int i = 0; i < W_L * H_L; i++) { int ii = i / W_L; int jj = i - ii * W_L; @@ -3818,11 +3761,10 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz kba = 1.f - bal / k2; } - WavCoeffs_L[dir][i] *= (kba); + WavCoeffs_L[dir][i] *= (1.f + (kba - 1.f) * beta[i]); } } } - } // to see each level of wavelet ...level from 0 to 8 @@ -3830,8 +3772,8 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz // choicelevel = choicelevel == -1 ? 4 : choicelevel; } -void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, float **varchrom, float ** WavCoeffs_ab, float * WavCoeffs_ab0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, - int W_ab, int H_ab, const bool useChannelA) +void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, float **varchrom, float* const* WavCoeffs_ab, float * WavCoeffs_ab0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, + int W_ab, int H_ab, const bool useChannelA, float *meanab, float *sigmaab) { float cpMul = cp.mul[level]; @@ -3843,9 +3785,43 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f //to adjust increase contrast with local contrast bool useSkinControl = (skinprot != 0.f); - float alphaC = (1024.f + 15.f * cpMul * cpChrom / 50.f) / 1024.f ; + + float mea[10]; + float effect = cp.sigmacol; + float betaab; + float offs = 1.f; + + calceffect(level, meanab, sigmaab, mea, effect, offs); for (int i = 0; i < W_ab * H_ab; i++) { + float WavCab = std::fabs(WavCoeffs_ab[dir][i]); + + if (WavCab < mea[0]) { + betaab = 0.05f; + } else if (WavCab < mea[1]) { + betaab = 0.2f; + } else if (WavCab < mea[2]) { + betaab = 0.7f; + } else if (WavCab < mea[3]) { + betaab = 1.f; //standard + } else if (WavCab < mea[4]) { + betaab = 1.f; + } else if (WavCab < mea[5]) { + betaab = 0.8f; //+sigma + } else if (WavCab < mea[6]) { + betaab = 0.6f; + } else if (WavCab < mea[7]) { + betaab = 0.4f; + } else if (WavCab < mea[8]) { + betaab = 0.2f; // + 2 sigma + } else if (WavCab < mea[9]) { + betaab = 0.1f; + } else { + betaab = 0.0f; + } + + float scale = 1.f; + if (useSkinControl) { int ii = i / W_ab; int jj = i - ii * W_ab; @@ -3853,7 +3829,6 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f float modhue = varhue[ii][jj]; float modchro = varchrom[ii * 2][jj * 2]; // hue chroma skin with initial lab data - float scale = 1.f; if (skinprot > 0.f) { Color::SkinSatCbdl2(LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand @@ -3862,9 +3837,10 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f scale = (scale == 1.f) ? factorHard : 1.f; } - alphaC = (1024.f + 15.f * cpMul * cpChrom * scale / 50.f) / 1024.f ; } + const float alphaC = (1024.f + 15.f * cpMul * cpChrom * betaab * scale / 50.f) / 1024.f ; + WavCoeffs_ab[dir][i] *= alphaC; } } @@ -3873,14 +3849,48 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f float cpMulC = cp.mulC[level]; - // if( (cp.curv || cp.CHSLmet==1) && cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip + // if ( (cp.curv || cp.CHSLmet==1) && cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip if (cp.CHmet != 2 && level < 9 && cpMulC != 0.f && cp.chromena) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip const float skinprot = params->wavelet.skinprotect; const float skinprotneg = -skinprot; const float factorHard = (1.f - skinprotneg / 100.f); bool useSkinControl = (skinprot != 0.f); + + float mea[10]; + float effect = cp.sigmacol; + float betaab; + float offs = 1.f; + + calceffect(level, meanab, sigmaab, mea, effect, offs); + for (int i = 0; i < W_ab * H_ab; i++) { + float WavCab = std::fabs(WavCoeffs_ab[dir][i]); + + if (WavCab < mea[0]) { + betaab = 0.05f; + } else if (WavCab < mea[1]) { + betaab = 0.2f; + } else if (WavCab < mea[2]) { + betaab = 0.7f; + } else if (WavCab < mea[3]) { + betaab = 1.f; //standard + } else if (WavCab < mea[4]) { + betaab = 1.f; + } else if (WavCab < mea[5]) { + betaab = 0.8f; //+sigma + } else if (WavCab < mea[6]) { + betaab = 0.6f; + } else if (WavCab < mea[7]) { + betaab = 0.4f; + } else if (WavCab < mea[8]) { + betaab = 0.2f; // + 2 sigma + } else if (WavCab < mea[9]) { + betaab = 0.1f; + } else { + betaab = 0.0f; + } + int ii = i / W_ab; int jj = i - ii * W_ab; //WL and W_ab are identical @@ -3900,7 +3910,7 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f } } - float beta = (1024.f + 20.f * cpMulC * scale) / 1024.f ; + float beta = (1024.f + 20.f * cpMulC * scale * betaab) / 1024.f ; if (beta < 0.02f) { beta = 0.02f; @@ -3966,15 +3976,112 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f } if ((useOpacity && level < 9 && mulOpacity != 0.f) && cp.toningena) { //toning + float mea[10]; + float effect = cp.sigmaton; + float betaab; + float offs = 1.f; + float protec = 0.01f * (100.f - cp.protab); + float aref1 = cp.a_high; + float bref1 = cp.b_high; + float aref2 = cp.a_low; + float bref2 = cp.b_low; - float beta = (1024.f + 20.f * mulOpacity) / 1024.f ; + float kk = 100.f; + float arefplus1 = aref1 + cp.rangeab * kk; + float arefmoins1 = aref1 - cp.rangeab * kk; + float brefplus1 = bref1 + cp.rangeab * kk; + float brefmoins1 = bref1 - cp.rangeab * kk; - //float beta = (1000.f * mulOpacity); - for (int i = 0; i < W_ab * H_ab; i++) { - WavCoeffs_ab[dir][i] *= beta; + float arefplus2 = aref2 + cp.rangeab * kk; + float arefmoins2 = aref2 - cp.rangeab * kk; + float brefplus2 = bref2 + cp.rangeab * kk; + float brefmoins2 = bref2 - cp.rangeab * kk; + + calceffect(level, meanab, sigmaab, mea, effect, offs); + + for (int co = 0; co < W_ab * H_ab; co++) { + float WavCab = std::fabs(WavCoeffs_ab[dir][co]); + + if (WavCab < mea[0]) { + betaab = 0.05f; + } else if (WavCab < mea[1]) { + betaab = 0.2f; + } else if (WavCab < mea[2]) { + betaab = 0.7f; + } else if (WavCab < mea[3]) { + betaab = 1.f; //standard + } else if (WavCab < mea[4]) { + betaab = 1.f; + } else if (WavCab < mea[5]) { + betaab = 0.8f; //+sigma + } else if (WavCab < mea[6]) { + betaab = 0.6f; + } else if (WavCab < mea[7]) { + betaab = 0.4f; + } else if (WavCab < mea[8]) { + betaab = 0.2f; // + 2 sigma + } else if (WavCab < mea[9]) { + betaab = 0.1f; + } else { + betaab = 0.0f; + } + + float kreduc1 = 1.f; + float kreduc2 = 1.f; + int ii = co / W_ab; + int jj = co - ii * W_ab; + + // cp.protab = 0.f;// always disabled provisory... + if (cp.protab > 0.f) { + if (useChannelA) { + if ((labco->a[ii * 2][jj * 2] > arefmoins1) && (labco->a[ii * 2][jj * 2] < arefplus1)) { + kreduc1 = 0.5f * protec; + + if ((labco->a[ii * 2][jj * 2] > 0.8f * arefmoins1) && (labco->a[ii * 2][jj * 2] < 0.8f * arefplus1)) { + kreduc1 = protec; + } + } + + } else { + if ((labco->b[ii * 2][jj * 2] > brefmoins1) && (labco->b[ii * 2][jj * 2] < brefplus1)) { + kreduc1 = 0.5f * protec; + + if ((labco->b[ii * 2][jj * 2] > 0.8f * brefmoins1) && (labco->b[ii * 2][jj * 2] < 0.8f * brefplus1)) { + kreduc1 = protec; + } + } + } + + if (useChannelA) { + if ((labco->a[ii * 2][jj * 2] > arefmoins2) && (labco->a[ii * 2][jj * 2] < arefplus2)) { + kreduc2 = 0.5f * protec; + + if ((labco->a[ii * 2][jj * 2] > 0.8f * arefmoins2) && (labco->a[ii * 2][jj * 2] < 0.8f * arefplus2)) { + kreduc2 = protec; + } + + } + } else { + if ((labco->b[ii * 2][jj * 2] > brefmoins2) && (labco->b[ii * 2][jj * 2] < brefplus2)) { + kreduc2 = 0.5f * protec; + + if ((labco->b[ii * 2][jj * 2] > brefmoins2) && (labco->b[ii * 2][jj * 2] < brefplus2)) { + kreduc2 = protec; + } + } + } + + } + + + // printf("pa1=%f pa2=%f\n", kreduc1, kredu2); + + + float beta = (1024.f + 50.f * mulOpacity * betaab * kreduc1 * kreduc2) / 1024.f ; + + WavCoeffs_ab[dir][co] *= beta; } - // WavCoeffs_ab[dir][i] += beta; } if (waOpacityCurveW) { @@ -3993,7 +4100,7 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f it = itmoins; } else if (level == med) { it = 7; - } else { /*if(level > med)*/ + } else { /*if (level > med)*/ it = itplus; } @@ -4001,8 +4108,8 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f //float bal = cp.balan;//-100 +100 float kba = 1.f; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; + // if (dir <3) kba= 1.f + bal/600.f; + // if (dir==3) kba = 1.f - bal/300.f; for (int i = 0; i < W_ab * H_ab; i++) { int ii = i / W_ab; int jj = i - ii * W_ab; @@ -4034,7 +4141,7 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f it = itmoins; } else if (level == med) { it = 7; - } else { /*if(level > med)*/ + } else { /*if (level > med)*/ it = itplus; } @@ -4042,8 +4149,8 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f float bal = cp.balan;//-100 +100 float kba = 1.f; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; + // if (dir <3) kba= 1.f + bal/600.f; + // if (dir==3) kba = 1.f - bal/300.f; for (int i = 0; i < W_ab * H_ab; i++) { int ii = i / W_ab; int jj = i - ii * W_ab; @@ -4187,191 +4294,4 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f } } -void ImProcFunctions::softproc2(const LabImage* bufcolorig, const LabImage* bufcolfin, float rad, int bfh, int bfw, double epsilmax, double epsilmin, float thres, int sk, bool multiThread, int flag) -{ - if (flag == 0) { - if (rad > 0.f) { - array2D ble(bfw, bfh); - array2D guid(bfw, bfh); - Imagefloat *tmpImage = nullptr; - tmpImage = new Imagefloat(bfw, bfh); - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int ir = 0; ir < bfh; ir++) - for (int jr = 0; jr < bfw; jr++) { - - float X, Y, Z; - float L = bufcolorig->L[ir][jr]; - float a = bufcolorig->a[ir][jr]; - float b = bufcolorig->b[ir][jr]; - Color::Lab2XYZ(L, a, b, X, Y, Z); - - guid[ir][jr] = Y / 32768.f; - float La = bufcolfin->L[ir][jr]; - float aa = bufcolfin->a[ir][jr]; - float ba = bufcolfin->b[ir][jr]; - Color::Lab2XYZ(La, aa, ba, X, Y, Z); - tmpImage->r(ir, jr) = X; - tmpImage->g(ir, jr) = Y; - tmpImage->b(ir, jr) = Z; - - ble[ir][jr] = Y / 32768.f; - } - - double aepsil = (epsilmax - epsilmin) / 90.f; - double bepsil = epsilmax - 100.f * aepsil; - double epsil = aepsil * 0.1 * rad + bepsil; - - float blur = 10.f / sk * (thres + 0.8f * rad); - rtengine::guidedFilter(guid, ble, ble, blur, epsil, multiThread, 4); - - - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int ir = 0; ir < bfh; ir++) - for (int jr = 0; jr < bfw; jr++) { - float X = tmpImage->r(ir, jr); - float Y = 32768.f * ble[ir][jr]; - float Z = tmpImage->b(ir, jr); - float L, a, b; - Color::XYZ2Lab(X, Y, Z, L, a, b); - bufcolfin->L[ir][jr] = L; - } - - delete tmpImage; - } - } else if (flag == 1) { - if (rad > 0.f) { - array2D ble(bfw, bfh); - array2D blechro(bfw, bfh); - array2D hue(bfw, bfh); - array2D guid(bfw, bfh); - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int ir = 0; ir < bfh; ir++) - for (int jr = 0; jr < bfw; jr++) { -// hue[ir][jr] = xatan2f(bufcolfin->b[ir][jr], bufcolfin->a[ir][jr]); -// float chromah = sqrt(SQR(bufcolfin->b[ir][jr]) + SQR(bufcolfin->a[ir][jr])); - - ble[ir][jr] = (bufcolfin->L[ir][jr]) / 32768.f; -// blechro[ir][jr] = chromah / 32768.f; - guid[ir][jr] = bufcolorig->L[ir][jr] / 32768.f; - } - - double aepsil = (epsilmax - epsilmin) / 90.f; - double bepsil = epsilmax - 100.f * aepsil; - double epsil = aepsil * 0.1 * rad + bepsil; - - if (rad != 0.f) { - float blur = rad; - blur = blur < 0.f ? -1.f / blur : 1.f + blur; - // int r1 = max(int(4 / sk * blur + 0.5), 1); - int r2 = max(int(25 / sk * blur + 0.5), 1); - - if (rad < 0.f) { - epsil = 0.0001; - } - - rtengine::guidedFilter(guid, ble, ble, r2, epsil, multiThread); -// rtengine::guidedFilter(guid, blechro, blechro, r1, 0.5 * epsil, multiThread); - } - - - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int ir = 0; ir < bfh; ir++) - for (int jr = 0; jr < bfw; jr++) { - // float2 sincosval = xsincosf(hue[ir][jr]); - - bufcolfin->L[ir][jr] = 32768.f * ble[ir][jr]; - // bufcolfin->a[ir][jr] = 32768.f * sincosval.y * blechro[ir][jr]; - // bufcolfin->b[ir][jr] = 32768.f * sincosval.x * blechro[ir][jr]; - } - } - - } -} - - -void ImProcFunctions::Compresslevels2(float **Source, int W_L, int H_L, float compression, float detailattenuator, float thres, float mean, float maxp, float meanN, float maxN, float madL) -{ - //J.Desmis 12-2019 - - float exponent; - - if (detailattenuator > 0.f && detailattenuator < 0.05f) { - float betemp = expf(-(2.f - detailattenuator + 0.693147f)) - 1.f; //0.69315 = log(2) - exponent = 1.2f * xlogf(-betemp); - exponent /= 20.f; - } else if (detailattenuator >= 0.05f && detailattenuator < 0.25f) { - float betemp = expf(-(2.f - detailattenuator + 0.693147f)) - 1.f; - exponent = 1.2f * xlogf(-betemp); - exponent /= (-75.f * detailattenuator + 23.75f); - } else if (detailattenuator >= 0.25f) { - float betemp = expf(-(2.f - detailattenuator + 0.693147f)) - 1.f; - exponent = 1.2f * xlogf(-betemp); - exponent /= (-2.f * detailattenuator + 5.5f); - } else { - exponent = (compression - 1.0f) / 20.f; - } - - exponent += 1.f; - - - float ap = (thres - 1.f) / (maxp - mean); - float bp = 1.f - ap * mean; - - float a0 = (1.33f * thres - 1.f) / (1.f - mean); - float b0 = 1.f - a0 * mean; - - float apn = (thres - 1.f) / (maxN - meanN); - float bpn = 1.f - apn * meanN; - - float a0n = (1.33f * thres - 1.f) / (1.f - meanN); - float b0n = 1.f - a0n * meanN; - - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int y = 0; y < H_L; y++) { - for (int x = 0; x < W_L; x++) { - float expone = 1.f; - - if (Source[y][x] >= 0.f) { - - if (Source[y][x] > mean) { - expone = 1.f + (exponent - 1.f) * (ap * Source[y][x] + bp); - } else { - expone = 1.f + (exponent - 1.f) * (a0 * Source[y][x] + b0); - } - - Source[y][x] = xexpf(xlogf(Source[y][x] + 0.05f * madL) * expone); - } else if (Source[y][x] < 0.f) { - if (-Source[y][x] > mean) { - expone = 1.f + (exponent - 1.f) * (apn * -Source[y][x] + bpn); - } else { - expone = 1.f + (exponent - 1.f) * (a0n * -Source[y][x] + b0n); - } - - Source[y][x] = -xexpf(xlogf(-Source[y][x] + 0.05f * madL) * expone); - } - } - } - -} - } diff --git a/rtengine/labimage.cc b/rtengine/labimage.cc index 153af4c75..319103d64 100644 --- a/rtengine/labimage.cc +++ b/rtengine/labimage.cc @@ -24,9 +24,12 @@ namespace rtengine { -LabImage::LabImage (int w, int h) : W(w), H(h) +LabImage::LabImage (int w, int h, bool initZero, bool multiThread) : W(w), H(h) { allocLab(w, h); + if (initZero) { + clear(multiThread); + } } LabImage::~LabImage () @@ -34,9 +37,21 @@ LabImage::~LabImage () deleteLab(); } -void LabImage::CopyFrom(LabImage *Img) +void LabImage::CopyFrom(LabImage *Img, bool multiThread) { - memcpy(data, Img->data, W * H * 3 * sizeof(float)); +#ifdef _OPENMP + #pragma omp parallel sections if(multiThread) + { + #pragma omp section + memcpy(L[0], Img->L[0], static_cast(W) * H * sizeof(float)); + #pragma omp section + memcpy(a[0], Img->a[0], static_cast(W) * H * sizeof(float)); + #pragma omp section + memcpy(b[0], Img->b[0], static_cast(W) * H * sizeof(float)); + } +#else + memcpy(data, Img->data, static_cast(W) * H * 3 * sizeof(float)); +#endif } void LabImage::getPipetteData (float &v1, float &v2, float &v3, int posX, int posY, int squareSize) @@ -102,4 +117,12 @@ void LabImage::reallocLab() allocLab(W, H); } +void LabImage::clear(bool multiThread) { +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for(size_t i = 0; i < static_cast(H) * W * 3; ++i) { + data[i] = 0.f; + } + } } diff --git a/rtengine/labimage.h b/rtengine/labimage.h index 7140d9de0..b4b974c29 100644 --- a/rtengine/labimage.h +++ b/rtengine/labimage.h @@ -35,14 +35,15 @@ public: float** a; float** b; - LabImage (int w, int h); + LabImage (int w, int h, bool initZero = false, bool multiThread = true); ~LabImage (); //Copies image data in Img into this instance. - void CopyFrom(LabImage *Img); + void CopyFrom(LabImage *Img, bool multiThread = true); void getPipetteData (float &L, float &a, float &b, int posX, int posY, int squareSize); void deleteLab(); void reallocLab(); + void clear(bool multiThread = false); }; } diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 1826101e7..8e90a3549 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -990,16 +990,16 @@ bool rtengine::LCPMapper::isCACorrectionAvailable() const return enableCA; } -void rtengine::LCPMapper::correctDistortion(double &x, double &y, int cx, int cy, double scale) const +void rtengine::LCPMapper::correctDistortion(double &x, double &y, int cx, int cy) const { x += cx; y += cy; if (isFisheye) { - const double u = x * scale; - const double v = y * scale; - const double u0 = static_cast(mc.x0) * scale; - const double v0 = static_cast(mc.y0) * scale; + const double u = x; + const double v = y; + const double u0 = static_cast(mc.x0); + const double v0 = static_cast(mc.y0); const double du = (u - u0); const double dv = (v - v0); const double fx = mc.fx; @@ -1007,7 +1007,7 @@ void rtengine::LCPMapper::correctDistortion(double &x, double &y, int cx, int cy const double k1 = mc.param[0]; const double k2 = mc.param[1]; const double r = sqrt(du * du + dv * dv); - const double f = sqrt(fx*fy / (scale * scale)); + const double f = sqrt(fx*fy); const double th = atan2(r, f); const double th2 = th * th; const double cfact = (((k2 * th2 + k1) * th2 + 1) * th) / r; @@ -1017,10 +1017,8 @@ void rtengine::LCPMapper::correctDistortion(double &x, double &y, int cx, int cy x = ud; y = vd; } else { - x *= scale; - y *= scale; - const double x0 = static_cast(mc.x0) * scale; - const double y0 = static_cast(mc.y0) * scale; + const double x0 = static_cast(mc.x0); + const double y0 = static_cast(mc.y0); const double xd = (x - x0) / static_cast(mc.fx), yd = (y - y0) / static_cast(mc.fy); const auto& aDist = mc.param; @@ -1037,8 +1035,8 @@ void rtengine::LCPMapper::correctDistortion(double &x, double &y, int cx, int cy y = ynew * static_cast(mc.fy) + y0; } - x -= cx * scale; - y -= cy * scale; + x -= cx; + y -= cy; } void rtengine::LCPMapper::correctCA(double& x, double& y, int cx, int cy, int channel) const diff --git a/rtengine/lcp.h b/rtengine/lcp.h index 4c1e09865..b59cc84c6 100644 --- a/rtengine/lcp.h +++ b/rtengine/lcp.h @@ -166,7 +166,7 @@ private: class LensCorrection { public: virtual ~LensCorrection() {} - virtual void correctDistortion(double &x, double &y, int cx, int cy, double scale) const = 0; + virtual void correctDistortion(double &x, double &y, int cx, int cy) const = 0; virtual bool isCACorrectionAvailable() const = 0; virtual void correctCA(double &x, double &y, int cx, int cy, int channel) const = 0; virtual void processVignette(int width, int height, float** rawData) const = 0; @@ -194,7 +194,7 @@ public: ); - void correctDistortion(double &x, double &y, int cx, int cy, double scale) const override; // MUST be the first stage + void correctDistortion(double &x, double &y, int cx, int cy) const override; bool isCACorrectionAvailable() const override; void correctCA(double& x, double& y, int cx, int cy, int channel) const override; void processVignette(int width, int height, float** rawData) const override; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 1b00d4218..e3243938f 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -518,29 +518,481 @@ enum ProcEventCode { EvLEnabled = 492, EvPdShrEnabled = 493, EvPdShrMaskToggled = 494, + EvLocallabSpotDeleted = 495, + EvLocallabSpotSelected = 496, + EvLocallabSpotName = 497, + EvLocallabSpotVisibility = 498, + EvLocallabSpotShape = 499, + EvLocallabSpotSpotMethod = 500, + EvLocallabSpotShapeMethod = 501, + EvLocallabSpotLocX = 502, + EvLocallabSpotLocXL = 503, + EvLocallabSpotLocY = 504, + EvLocallabSpotLocYT = 505, + EvLocallabSpotCenter = 506, + EvLocallabSpotCircrad = 507, + EvLocallabSpotQualityMethod = 508, + EvLocallabSpotTransit = 509, + EvLocallabSpotThresh = 510, + EvLocallabSpotIter = 511, + EvLocallabSpotSensiexclu = 512, + EvLocallabSpotStruc = 513, + EvlocallabEnabled = 514, + EvLocenacolor = 515, + Evlocallabcurvactiv = 516, + Evlocallablightness = 517, + Evlocallabcontrast = 518, + Evlocallabchroma = 519, + Evlocallabsensi = 520, + EvlocallabqualitycurveMethod = 521, + Evlocallabllshape = 522, + Evlocallabccshape = 523, + EvlocallabLHshape = 524, + EvlocallabHHshape = 525, + Evlocallabinvers = 526, + EvLocenaexpose = 527, + Evlocallabexpcomp = 528, + Evlocallabhlcompr = 529, + Evlocallabhlcomprthresh = 530, + Evlocallabblack = 531, + Evlocallabshcompr = 532, + Evlocallabwarm = 533, + Evlocallabsensiex = 534, + Evlocallabshapeexpos = 535, + EvLocenavibrance = 536, + EvlocallabSaturated = 537, + EvlocallabPastels = 538, + EvlocallabPastSatThreshold = 539, + EvlocallabProtectSkins = 540, + EvlocallabAvoidColorShift = 541, + EvlocallabPastSatTog = 542, + Evlocallabsensiv = 543, + EvlocallabSkinTonesCurve = 544, + EvLocenablur = 545, + Evlocallabradius = 546, + Evlocallabstrength = 547, + Evlocallabsensibn = 548, + EvlocallabblurMethod = 549, + Evlocallabactivlum = 550, + EvLocenatonemap = 551, + Evlocallabstren = 552, + Evlocallabgamma = 553, + Evlocallabestop = 554, + Evlocallabscaltm = 555, + Evlocallabrewei = 556, + Evlocallabsensitm = 557, + EvLocenareti = 558, + EvlocallabretinexMethod = 559, + Evlocallabstr = 560, + Evlocallabchrrt = 561, + Evlocallabneigh = 562, + Evlocallabvart = 563, + Evlocallabsensih = 564, + EvlocallabCTgainCurve = 565, + Evlocallabinversret = 566, + EvLocenasharp = 567, + Evlocallabsharradius = 568, + Evlocallabsharamount = 569, + Evlocallabshardamping = 570, + Evlocallabshariter = 571, + Evlocallabsensis = 572, + Evlocallabinverssha = 573, + EvLocenacbdl = 574, + EvlocallabEqualizer = 575, + Evlocallabchromacbdl = 576, + EvlocallabThresho = 577, + Evlocallabsensicb = 578, + // EvLocenadenoi = 579, + Evlocallabnoiselumf = 580, + Evlocallabnoiselumc = 581, + Evlocallabnoiselumdetail = 582, + Evlocallabnoiselequal = 583, + Evlocallabnoisechrof = 584, + Evlocallabnoisechroc = 585, + Evlocallabnoisechrodetail = 586, + Evlocallabadjblur = 587, + Evlocallabbilateral = 588, + Evlocallabsensiden = 589, + Evlocallabavoid = 590, + Evlocallabsharcontrast = 591, + EvLocenacontrast = 592, + Evlocallablcradius = 593, + Evlocallablcamount = 594, + Evlocallablcdarkness = 595, + Evlocallablclightness = 596, + Evlocallabsensilc = 597, + Evlocallabdehaz = 598, + EvLocenasoft = 599, + Evlocallabstreng = 600, + Evlocallabsensisf = 601, + Evlocallabsharblur = 602, + EvLocenalabregion = 603, + EvlocallabshowmaskMethod = 604, + EvLocallabSpotSelectedWithMask = 605, + EvlocallabCCmaskshape = 606, + EvlocallabLLmaskshape = 607, + EvlocallabCCmaskexpshape = 608, + EvlocallabLLmaskexpshape = 609, + EvlocallabHHmaskshape = 610, + Evlocallabstructcol = 611, + Evlocallabstructexp = 612, + EvlocallabHHmaskexpshape = 613, + Evlocallabblendmaskcol = 614, + Evlocallabblendmaskexp = 615, + Evlocallabblurexpde = 616, + EvLocallabEnaColorMask = 617, + EvLocallabEnaExpMask = 618, + Evlocallabblurcolde = 619, + Evlocallabinversex = 620, + Evlocallabstructexlu = 621, + Evlocallabexpchroma = 622, + EvLocallabLabGridValue = 623, + EvLocallabLabstrengthgrid = 624, + EvLocallabgridMethod = 625, + EvLocenashadhigh = 626, + Evlocallabhighlights = 627, + Evlocallabh_tonalwidth = 628, + Evlocallabshadows = 629, + Evlocallabs_tonalwidth = 630, + Evlocallabsh_radius = 631, + Evlocallabsensihs = 632, + Evlocallabradmaskcol = 633, + Evlocallabradmaskexp = 634, + EvlocallabToolAdded = 635, + EvlocallabCCmaskSHshape = 636, + EvlocallabLLmaskSHshape = 637, + EvlocallabHHmaskSHshape = 638, + EvlocallabblendmaskSH = 639, + EvLocallabEnaSHMask = 640, + EvlocallabradmaskSH = 641, + EvlocallabblurSHde = 642, + Evlocallabinverssh = 643, + EvLocallabSpotbalan = 644, + Evlocallabchromaskexp = 645, + Evlocallabgammaskexp = 646, + Evlocallabslomaskexp = 647, + Evlocallabsoftradiusexp = 648, + Evlocallabchromaskcol = 649, + Evlocallabgammaskcol = 650, + Evlocallabslomaskcol = 651, + EvlocallabchromaskSH = 652, + EvlocallabgammaskSH = 653, + EvlocallabslomaskSH = 654, + Evlocallabsoftradiuscol = 655, + Evlocallabsoftradiusret = 656, + Evlocallabsoftradiuscb = 657, + EvLocallabSpotTransitweak = 658, + EvLocallabclarityml = 659, + EvLocallabcontresid = 660, + Evlocallabnoiselumf0 = 661, + Evlocallabnoiselumf2 = 662, + EvLocallabblurcbdl = 663, + Evlocallabblendmaskcb = 664, + Evlocallabradmaskcb = 665, + Evlocallabchromaskcb = 666, + Evlocallabgammaskcb = 667, + Evlocallabslomaskcb = 668, + EvlocallabCCmaskcbshape = 669, + EvlocallabLLmaskcbshape = 670, + EvlocallabHHmaskcbshape = 671, + EvLocallabEnacbMask = 672, + EvlocallabToolRemovedWithoutRefresh = 673, + Evlocallabsoftradiustm = 674, + EvLocallabSpotTransitgrad = 675, + Evlocallabamount = 676, + Evlocallabsatur = 677, + EvlocallabCCmaskretishape = 678, + EvlocallabLLmaskretishape = 679, + EvlocallabHHmaskretishape = 680, + EvLocallabEnaretiMask = 681, + Evlocallabblendmaskreti = 682, + Evlocallabradmaskreti = 683, + Evlocallabchromaskreti = 684, + Evlocallabgammaskreti = 685, + Evlocallabslomaskreti = 686, + EvlocallabToolRemovedWithRefresh = 687, + EvLocallabEnaretiMasktmap = 688, + Evlocallabscalereti = 689, + Evlocallabdarkness = 690, + Evlocallablightnessreti = 691, + Evlocallablimd = 692, + Evlocallablaplace = 693, + EvlocallabsoftMethod = 694, + Evlocallabequilret = 695, + Evlocallabequiltm = 696, + Evlocallabfftwlc = 697, + Evlocallabfftwreti = 698, + // EvlocallabshowmasksoftMethod = 699, + Evlocallabshadex = 700, + EvlocallabexpMethod = 701, + Evlocallablaplacexp = 702, + Evlocallabbalanexp = 703, + Evlocallablinear = 704, + EvlocallabCCmasktmshape = 705, + EvlocallabLLmasktmshape = 706, + EvlocallabHHmasktmshape = 707, + EvLocallabEnatmMask = 708, + Evlocallabblendmasktm = 709, + Evlocallabradmasktm = 710, + Evlocallabchromasktm = 711, + Evlocallabgammasktm = 712, + Evlocallabslomasktm = 713, + // EvlocallabshowmasktmMethod = 714, + EvlocallablocalcontMethod = 715, + EvlocallabwavCurve = 716, + Evlocallablevelwav = 717, + Evlocallabresidcont = 718, + EvlocallabCCmaskblshape = 719, + EvlocallabLLmaskblshape = 720, + EvlocallabHHmaskblshape = 721, + EvLocallabEnablMask = 722, + // EvlocallabshowmaskblMethod = 723, + Evlocallabblendmaskbl = 724, + Evlocallabradmaskbl = 725, + Evlocallabchromaskbl = 726, + Evlocallabgammaskbl = 727, + Evlocallabslomaskbl = 728, + EvlocallabblMethod = 729, + EvlocallabmedMethod = 730, + Evlocallabitera = 731, + Evlocallabguidbl = 732, + Evlocallabepsbl = 733, + // EvlocallabshowmaskcolMethodinv = 734, + // EvlocallabshowmaskexpMethodinv = 735, + // EvlocallabshowmaskSHMethodinv = 736, + Evlocallabclarilres = 737, + Evlocallabclarisoft = 738, + Evlocallabclaricres = 739, + Evlocallabresidchro = 740, + Evlocallabgamm = 741, + Evlocallabfatamount = 742, + Evlocallabfatdetail = 743, + Evlocallabfatanchor = 744, + Evlocallabfatlevel = 745, + EvLocallabSpotCreated = 746, + EvlocallabexnoiseMethod = 747, + Evlocallabdepth = 748, + Evlocallabloglin = 749, + Evlocallablumonly = 750, + Evlocallaboffs = 751, + EvlocallabCTtransCurve = 752, + Evlocallabcliptm = 753, + EvLocallabEnatmMaskaft = 754, + EvLocallabEnaExpMaskaft = 755, + Evlocallablapmasktm = 756, + Evlocallablapmaskreti = 757, + Evlocallablapmaskexp = 758, + Evlocallablapmaskcol = 759, + EvlocallablapmaskSH = 760, + Evlocallablapmaskcb = 761, + Evlocallablapmaskbl = 762, + Evlocallablaplac = 763, + Evlocallabdetailthr = 764, + Evlocallabfftwbl = 765, + Evlocallabisogr = 766, + Evlocallabstrengr = 767, + Evlocallabscalegr = 768, + EvlocallabLmaskshape = 769, + EvlocallabLmaskexpshape = 770, + EvlocallabLmaskSHshape = 771, + EvlocallabLmasktmshape = 772, + EvlocallabLmaskretishape = 773, + EvlocallabLmaskcbshape = 774, + EvlocallabLmaskblshape = 775, + EvlocallabLLmaskblshapewav = 776, + Evlocallabshadmaskbl = 777, + EvlocallabLLmaskcolshapewav = 778, + Evlocallabshadmaskcol = 779, + EvlocallabcsThreshold = 780, + EvlocallabcsThresholdblur = 781, + EvlocallabcsThresholdcol = 782, + Evlocallabdeltae = 783, + EvLocallabSpotscopemask = 784, + EvlocallabshMethod = 785, + EvlocallabEqualizersh = 786, + EvlocallabdetailSH = 787, + EvlocallabfatamountSH = 788, + EvlocallabfatanchorSH = 789, + Evlocallabshortc = 790, + EvLocallabSpotlumask = 791, + EvlocallabgamSH = 792, + EvlocallabsloSH = 793, + Evlocallabsavrest = 794, + Evlocallabrecurs = 795, + EvLocallabmergecolMethod = 796, + Evlocallabopacol = 797, + Evlocallabrgbshape = 798, + EvLocallabtoneMethod = 799, + EvLocallabspecial = 800, + Evlocallabconthrcol = 801, + EvLocallabmerMethod = 802, + Evlocallabstrumaskcol = 803, + Evlocallabstrumaskbl = 804, + EvLocallabtoolcol = 805, + Evlocallabtoolbl = 806, + EvlocallabHHhmaskshape = 807, + EvlocallabCCmaskvibshape = 808, + EvlocallabLLmaskvibshape = 809, + EvlocallabHHmaskvibshape = 810, + // EvlocallabshowmaskvibMethod = 811, + EvLocallabEnavibMask = 812, + Evlocallabblendmaskvi = 813, + Evlocallabradmaskvib = 814, + Evlocallabchromaskvib = 815, + Evlocallabgammaskvib = 816, + Evlocallabslomaskvib = 817, + Evlocallablapmaskvib = 818, + EvlocallabLmaskvibshape = 819, + EvLocallabLabGridmergValue = 820, + Evlocallabmercol = 821, + Evlocallabmerlucol = 822, + Evlocallabstrmaskexp = 823, + Evlocallabangmaskexp = 824, + Evlocallabstrexp = 825, + Evlocallabangexp = 826, + EvlocallabstrSH = 827, + EvlocallabangSH = 828, + Evlocallabstrcol = 829, + Evlocallabangcol = 830, + Evlocallabstrcolab = 831, + EvLocallabSpotfeather = 832, + Evlocallabstrcolh = 833, + Evlocallabstrvib = 834, + Evlocallabangvib = 835, + Evlocallabstrvibab = 836, + Evlocallabstrvibh = 837, + EvLocallabSpotcomplexMethod = 838, + Evlocallabclshape = 839, + Evlocallablcshape = 840, + Evlocallabblurcol = 841, + Evlocallabcontcol = 842, + EvLocallabfftColorMask = 843, + EvLocenalog = 844, + EvLocallabAuto = 845, + EvlocallabsourceGray = 846, + EvlocallabsourceGrayAuto = 847, + EvlocallabAutogray = 848, + EvlocallabblackEv = 849, + EvlocallabwhiteEv = 850, + EvlocallabtargetGray = 851, + Evlocallabdetail = 852, + Evlocallabsensilog = 853, + Evlocallabfullimage = 854, + Evlocallabbaselog = 855, + Evlocallabresidblur = 856, + Evlocallabblurlc = 857, + Evlocallablevelblur = 858, + EvlocallabwavCurvelev = 859, + EvlocallabwavCurvecon = 860, + Evlocallabsigma = 861, + Evlocallaboriglc = 862, + Evlocallabsigmadc = 863, + Evlocallabdeltad = 864, + EvlocallabwavCurvecomp = 865, + Evlocallabfatres = 866, + EvLocallabSpotbalanh = 867, + EvlocallabwavCurveden = 868, + EvlocallabHHmasklcshape = 869, + EvlocallabCCmasklcshape = 870, + EvlocallabLLmasklcshape = 871, + EvLocallabEnalcMask = 872, + // EvlocallabshowmasklcMethod = 873, + Evlocallabblendmasklc = 874, + Evlocallabradmasklc = 875, + Evlocallabchromasklc = 876, + EvlocallabLmasklcshape = 877, + Evlocallabchromalev = 878, + Evlocallabchromablu = 879, + Evlocallaboffset = 880, + Evlocallabwavblur = 881, + Evlocallabwavcont = 882, + Evlocallabwavcomp = 883, + Evlocallabwavcompre = 884, + EvlocallabwavCurvecompre = 885, + Evlocallabresidcomp = 886, + Evlocallabthreswav = 887, + Evlocallabstrwav = 888, + Evlocallabangwav = 889, + Evlocallabwavgradl = 890, + Evlocallabstrlog = 891, + Evlocallabanglog = 892, + EvLocallabSpotcolorde = 893, + // EvlocallabshowmasksharMethod = 894, + Evlocallabshowreset = 895, + Evlocallabstrengthw = 896, + Evlocallabradiusw = 897, + Evlocallabdetailw = 898, + Evlocallabgradw = 899, + Evlocallabtloww = 900, + Evlocallabthigw = 901, + EvlocallabwavCurveedg = 902, + EvlocallablocaledgMethod = 903, + Evlocallabwavedg = 904, + Evlocallabedgw = 905, + Evlocallabbasew = 906, + EvlocallablocalneiMethod = 907, + Evlocallabwaveshow = 908, + EvLocallabSpotwavMethod = 909, + EvlocallabchroMethod = 910, + Evlocallabstrbl = 911, + Evlocallabsigmadr = 912, + Evlocallabsigmabl = 913, + Evlocallabsigmaed = 914, + Evlocallabresidsha = 915, + Evlocallabresidshathr = 916, + Evlocallabresidhi = 917, + Evlocallabresidhithr = 918, + Evlocallabsigmalc = 919, + Evlocallabsigmalc2 = 920, + Evlocallabblwh = 921, + EvlocallabcomplexityWithRefresh = 922, + EvlocallabcomplexityWithoutRefresh = 923, + EvLocallabSpotcolorscope = 924, + EvlocallabshowmasktypMethod = 925, + Evlocallabshadmaskblsha = 926, NUMOFEVENTS - }; - -class ProcEvent { +class ProcEvent +{ public: ProcEvent(): code_(0) {} ProcEvent(ProcEventCode code): code_(code) {} explicit ProcEvent(int code): code_(code) {} - operator int() const { return code_; } + operator int() const + { + return code_; + } private: int code_; }; -inline bool operator ==(ProcEvent a, ProcEvent b) { return int(a) == int(b); } -inline bool operator ==(ProcEvent a, ProcEventCode b) { return int(a) == int(b); } -inline bool operator ==(ProcEventCode a, ProcEvent b) { return int(a) == int(b); } -inline bool operator !=(ProcEvent a, ProcEvent b) { return int(a) != int(b); } -inline bool operator !=(ProcEvent a, ProcEventCode b) { return int(a) != int(b); } -inline bool operator !=(ProcEventCode a, ProcEvent b) { return int(a) != int(b); } +inline bool operator ==(ProcEvent a, ProcEvent b) +{ + return int(a) == int(b); +} +inline bool operator ==(ProcEvent a, ProcEventCode b) +{ + return int(a) == int(b); +} +inline bool operator ==(ProcEventCode a, ProcEvent b) +{ + return int(a) == int(b); +} +inline bool operator !=(ProcEvent a, ProcEvent b) +{ + return int(a) != int(b); +} +inline bool operator !=(ProcEvent a, ProcEventCode b) +{ + return int(a) != int(b); +} +inline bool operator !=(ProcEventCode a, ProcEvent b) +{ + return int(a) != int(b); +} } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e00e50186..def39a5cd 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -132,6 +132,16 @@ void getFromKeyfile( value = keyfile.get_string(group_name, key); } +void getFromKeyfile( + const Glib::KeyFile& keyfile, + const Glib::ustring& group_name, + const Glib::ustring& key, + std::vector& value +) +{ + value = keyfile.get_integer_list(group_name, key); +} + void getFromKeyfile( const Glib::KeyFile& keyfile, const Glib::ustring& group_name, @@ -604,7 +614,6 @@ bool RGBCurvesParams::operator !=(const RGBCurvesParams& other) const return !(*this == other); } - LocalContrastParams::LocalContrastParams(): enabled(false), radius(80), @@ -614,7 +623,6 @@ LocalContrastParams::LocalContrastParams(): { } - bool LocalContrastParams::operator==(const LocalContrastParams &other) const { return @@ -625,13 +633,11 @@ bool LocalContrastParams::operator==(const LocalContrastParams &other) const && lightness == other.lightness; } - bool LocalContrastParams::operator!=(const LocalContrastParams &other) const { return !(*this == other); } - const double ColorToningParams::LABGRID_CORR_MAX = 12000.f; const double ColorToningParams::LABGRID_CORR_SCALE = 3.f; @@ -644,46 +650,46 @@ ColorToningParams::LabCorrectionRegion::LabCorrectionRegion(): power(1), hueMask{ FCT_MinMaxCPoints, - 0.166666667, - 1., - 0.35, - 0.35, - 0.8287775246, - 1., - 0.35, - 0.35 + 0.166666667, + 1., + 0.35, + 0.35, + 0.8287775246, + 1., + 0.35, + 0.35 }, chromaticityMask{ FCT_MinMaxCPoints, - 0., - 1., - 0.35, - 0.35, - 1., - 1., - 0.35, - 0.35 - }, + 0., + 1., + 0.35, + 0.35, + 1., + 1., + 0.35, + 0.35 + }, lightnessMask{ FCT_MinMaxCPoints, - 0., - 1., - 0.35, - 0.35, - 1., - 1., - 0.35, - 0.35 - }, + 0., + 1., + 0.35, + 0.35, + 1., + 1., + 0.35, + 0.35 + }, maskBlur(0), channel(ColorToningParams::LabCorrectionRegion::CHAN_ALL) { } - bool ColorToningParams::LabCorrectionRegion::operator==(const LabCorrectionRegion &other) const { - return a == other.a + return + a == other.a && b == other.b && saturation == other.saturation && slope == other.slope @@ -696,13 +702,11 @@ bool ColorToningParams::LabCorrectionRegion::operator==(const LabCorrectionRegio && channel == other.channel; } - bool ColorToningParams::LabCorrectionRegion::operator!=(const LabCorrectionRegion &other) const { return !(*this == other); } - ColorToningParams::ColorToningParams() : enabled(false), autosat(true), @@ -741,7 +745,7 @@ ColorToningParams::ColorToningParams() : strength(50), balance(0), hlColSat(60, 80, false), - shadowsColSat (80, 208, false), + shadowsColSat(80, 208, false), clcurve{ DCT_NURBS, 0.00, @@ -844,7 +848,7 @@ void ColorToningParams::mixerToCurve(std::vector& colorCurve, std::vecto float highSat = 0.f; float minTmp, maxTmp; -// Fill the shadow mixer values of the Color TOning tool + // Fill the shadow mixer values of the Color TOning tool low[0] = float (redlow) / 100.f; // [-1. ; +1.] low[1] = float (greenlow) / 100.f; // [-1. ; +1.] low[2] = float (bluelow) / 100.f; // [-1. ; +1.] @@ -886,7 +890,7 @@ void ColorToningParams::mixerToCurve(std::vector& colorCurve, std::vecto low[0] = low[1] = low[2] = 1.f; } -// Fill the mid-tones mixer values of the Color TOning tool + // Fill the mid-tones mixer values of the Color TOning tool med[0] = float (redmed) / 100.f; // [-1. ; +1.] med[1] = float (greenmed) / 100.f; // [-1. ; +1.] med[2] = float (bluemed) / 100.f; // [-1. ; +1.] @@ -1274,17 +1278,23 @@ WBParams::WBParams() : bool WBParams::isPanningRelatedChange(const WBParams& other) const { - return ! - (enabled == other.enabled - && ((method == "Camera" && other.method == "Camera") - || - (method == other.method - && temperature == other.temperature - && green == other.green - && equal == other.equal - && tempBias == other.tempBias) + return + !( + enabled == other.enabled + && ( + ( + method == "Camera" + && other.method == "Camera" + ) + || ( + method == other.method + && temperature == other.temperature + && green == other.green + && equal == other.equal + && tempBias == other.tempBias + ) ) - ); + ); } bool WBParams::operator ==(const WBParams& other) const @@ -1305,8 +1315,6 @@ bool WBParams::operator !=(const WBParams& other) const const std::vector& WBParams::getWbEntries() { - - static const std::vector wb_entries = { {"Camera", WBEntry::Type::CAMERA, M("TP_WBALANCE_CAMERA"), 0, 1.f, 1.f, 0.f}, {"autitcgreen", WBEntry::Type::AUTO, M("TP_WBALANCE_AUTOITCGREEN"), 0, 1.f, 1.f, 0.f}, @@ -2176,6 +2184,10 @@ bool ColorManagementParams::operator !=(const ColorManagementParams& other) cons return !(*this == other); } +const double WaveletParams::LABGRID_CORR_MAX = 12800.f; +const double WaveletParams::LABGRID_CORR_SCALE = 3.276f; +const double WaveletParams::LABGRIDL_DIRECT_SCALE = 41950.; + WaveletParams::WaveletParams() : ccwcurve{ static_cast(FCT_MinMaxCPoints), @@ -2194,15 +2206,27 @@ WaveletParams::WaveletParams() : }, blcurve{ static_cast(FCT_MinMaxCPoints), -0.0, 0.0, 0.0, 0.35, 0.5, 0., 0.35, 0.35, 1.0, 0.0, 0.35, 0.35 -/* 0.0, - 0.75, + 0.0, + 0.0, + 0.0, + 0.35, + 0.5, + 0., 0.35, 0.35, 1.0, - 0.75, + 0.0, 0.35, - 0.35*/ + 0.35 +/* + 0.0, + 0.35, + 0.35, + 1.0, + 0.0, + 0.35, + 0.35 +*/ }, opacityCurveRG{ static_cast(FCT_MinMaxCPoints), @@ -2215,6 +2239,62 @@ WaveletParams::WaveletParams() : 0.35, 0.35 }, + opacityCurveSH{ + static_cast(FCT_MinMaxCPoints), + 0., + 1., + 0.35, + 0.35, + 0.15, + 0.9, + 0.35, + 0.35, + 0.4, + 0.8, + 0.35, + 0.35, + 0.4, + 0.5, + 0.35, + 0.35, + 0.5, + 0.5, + 0.35, + 0.35, + 0.5, + 0.2, + 0.35, + 0.35, + 0.8, + 0.1, + 0.35, + 0.35, + 1.0, + 0., + 0.35, + 0.35 + }, +/* + opacityCurveSH{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1., + 0.35, + 0.35, + 0.4, + 0.5, + 0.35, + 0.35, + 0.5, + 0.5, + 0.35, + 0.35, + 1., + 0., + 0.35, + 0.35 + }, +*/ opacityCurveBY{ static_cast(FCT_MinMaxCPoints), 0.0, @@ -2268,7 +2348,7 @@ WaveletParams::WaveletParams() : enabled(false), median(false), medianlev(false), - linkedg(true), + linkedg(false), cbenab(false), greenlow(0), bluelow(0), @@ -2280,7 +2360,7 @@ WaveletParams::WaveletParams() : balchrom(0.), chromfi(0.), chromco(0.), - mergeL(40.), + mergeL(20.), mergeC(20.), softrad(0.), softradend(0.), @@ -2291,6 +2371,12 @@ WaveletParams::WaveletParams() : tmr(false), strength(100), balance(0), + sigmafin(1.0), + sigmaton(1.0), + sigmacol(1.0), + sigmadir(1.0), + rangeab(20.0), + protab(0.0), iter(0), expcontrast(false), expchroma(false), @@ -2303,6 +2389,10 @@ WaveletParams::WaveletParams() : exptoning(false), expnoise(false), expclari(false), + labgridALow(0.0), + labgridBLow(0.0), + labgridAHigh(0.0), + labgridBHigh(0.0), Lmethod(4), CLmethod("all"), Backmethod("grey"), @@ -2335,8 +2425,8 @@ WaveletParams::WaveletParams() : thres(7), chroma(5), chro(0), - threshold(5), - threshold2(4), + threshold(4), + threshold2(5), edgedetect(90), edgedetectthr(20), edgedetectthr2(0), @@ -2373,6 +2463,7 @@ bool WaveletParams::operator ==(const WaveletParams& other) const ccwcurve == other.ccwcurve && blcurve == other.blcurve && opacityCurveRG == other.opacityCurveRG + && opacityCurveSH == other.opacityCurveSH && opacityCurveBY == other.opacityCurveBY && opacityCurveW == other.opacityCurveW && opacityCurveWL == other.opacityCurveWL @@ -2405,7 +2496,17 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && tmr == other.tmr && strength == other.strength && balance == other.balance + && sigmafin == other.sigmafin + && sigmaton == other.sigmaton + && sigmacol == other.sigmacol + && sigmadir == other.sigmadir + && rangeab == other.rangeab + && protab == other.protab && iter == other.iter + && labgridALow == other.labgridALow + && labgridBLow == other.labgridBLow + && labgridAHigh == other.labgridAHigh + && labgridBHigh == other.labgridBHigh && expcontrast == other.expcontrast && expchroma == other.expchroma && [this, &other]() -> bool @@ -2496,6 +2597,7 @@ void WaveletParams::getCurves( WavCurve& cCurve, Wavblcurve& tCurve, WavOpacityCurveRG& opacityCurveLUTRG, + WavOpacityCurveSH& opacityCurveLUTSH, WavOpacityCurveBY& opacityCurveLUTBY, WavOpacityCurveW& opacityCurveLUTW, WavOpacityCurveWL& opacityCurveLUTWL @@ -2504,12 +2606,1636 @@ void WaveletParams::getCurves( cCurve.Set(this->ccwcurve); tCurve.Set(this->blcurve); opacityCurveLUTRG.Set(this->opacityCurveRG); + opacityCurveLUTSH.Set(this->opacityCurveSH); opacityCurveLUTBY.Set(this->opacityCurveBY); opacityCurveLUTW.Set(this->opacityCurveW); opacityCurveLUTWL.Set(this->opacityCurveWL); } +LocallabParams::LocallabSpot::LocallabSpot() : + // Control spot settings + name(""), + isvisible(true), + shape("ELI"), + spotMethod("norm"), + wavMethod("D4"), + sensiexclu(12), + structexclu(0), + struc(4.0), + shapeMethod("IND"), + loc{150, 150, 150, 150}, + centerX(0), + centerY(0), + circrad(18), + qualityMethod("enh"), + complexMethod("mod"), + transit(60.), + feather(25.), + thresh(2.0), + iter(2.0), + balan(1.0), + balanh(1.0), + colorde(5.0), + colorscope(30.0), + transitweak(1.0), + transitgrad(0.0), + avoid(false), + blwh(false), + recurs(false), + laplac(true), + deltae(true), + shortc(false), + savrest(false), + scopemask(60), + lumask(10), + // Color & Light + visicolor(false), + expcolor(false), + complexcolor(0), + curvactiv(false), + lightness(0), + contrast(0), + chroma(0), + labgridALow(0.0), + labgridBLow(0.0), + labgridAHigh(0.0), + labgridBHigh(0.0), + labgridALowmerg(0.0), + labgridBLowmerg(0.0), + labgridAHighmerg(-3500.0), + labgridBHighmerg(-4600.0), + strengthgrid(30), + sensi(15), + structcol(0), + strcol(0.), + strcolab(0.), + strcolh(0.), + angcol(0.), + blurcolde(5), + blurcol(0.2), + contcol(0.), + blendmaskcol(0), + radmaskcol(0.0), + chromaskcol(0.0), + gammaskcol(1.0), + slomaskcol(0.0), + shadmaskcol(0), + strumaskcol(0.), + lapmaskcol(0.0), + qualitycurveMethod("none"), + gridMethod("one"), + merMethod("mone"), + toneMethod("fou"), + mergecolMethod("one"), + llcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + lccurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + cccurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + clcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + rgbcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + LHcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.50, + 0.35, + 0.35, + 0.166, + 0.50, + 0.35, + 0.35, + 0.333, + 0.50, + 0.35, + 0.35, + 0.50, + 0.50, + 0.35, + 0.35, + 0.666, + 0.50, + 0.35, + 0.35, + 0.833, + 0.50, + 0.35, + 0.35 + }, + HHcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.50, + 0.35, + 0.35, + 0.166, + 0.50, + 0.35, + 0.35, + 0.333, + 0.50, + 0.35, + 0.35, + 0.50, + 0.50, + 0.35, + 0.35, + 0.666, + 0.50, + 0.35, + 0.35, + 0.833, + 0.50, + 0.35, + 0.35 + }, + invers(false), + special(false), + toolcol(true), + enaColorMask(false), + fftColorMask(true), + CCmaskcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.00, + 1.0, + 0.35, + 0.35 + }, + LLmaskcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.00, + 1.0, + 0.35, + 0.35 + }, + HHmaskcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.00, + 1.0, + 0.35, + 0.35 + }, + HHhmaskcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.5, + 0.35, + 0.35, + 0.50, + 0.5, + 0.35, + 0.35, + 1.00, + 0.5, + 0.35, + 0.35 + }, + softradiuscol(0.0), + opacol(60.0), + mercol(18.0), + merlucol(32.0), + conthrcol(0.0), + Lmaskcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + LLmaskcolcurvewav{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.5, + 0.35, + 0.35, + 1., + 0.5, + 0.35, + 0.35 + }, + csthresholdcol(0, 0, 6, 5, false), + // Exposure + visiexpose(false), + expexpose(false), + complexexpose(0), + expcomp(0.0), + hlcompr(0), + hlcomprthresh(0), + black(0), + shadex(0), + shcompr(50), + expchroma(5), + sensiex(60), + structexp(0), + blurexpde(5), + strexp(0.), + angexp(0.), + excurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + inversex(false), + enaExpMask(false), + enaExpMaskaft(false), + CCmaskexpcurve{ + static_cast(FCT_MinMaxCPoints),0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmaskexpcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmaskexpcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + blendmaskexp(0), + radmaskexp(0.0), + chromaskexp(0.0), + gammaskexp(1.0), + slomaskexp(0.0), + lapmaskexp(0.0), + strmaskexp(0.0), + angmaskexp(0.0), + softradiusexp(0.0), + Lmaskexpcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + expMethod("std"), + exnoiseMethod("none"), + laplacexp(0.0), + balanexp(1.0), + linear(0.05), + gamm(0.4), + fatamount(1.0), + fatdetail(40.0), + fatanchor(1.0), + fatlevel(1.), + // Shadow highlight + visishadhigh(false), + expshadhigh(false), + complexshadhigh(0), + shMethod("std"), + multsh{0, 0, 0, 0, 0}, + highlights(0), + h_tonalwidth(70), + shadows(0), + s_tonalwidth(30), + sh_radius(40), + sensihs(15), + enaSHMask(false), + CCmaskSHcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmaskSHcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmaskSHcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + blendmaskSH(0), + radmaskSH(0.0), + blurSHde(5), + strSH(0.), + angSH(0.), + inverssh(false), + chromaskSH(0.0), + gammaskSH(1.0), + slomaskSH(0.0), + lapmaskSH(0.0), + detailSH(0), + LmaskSHcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + fatamountSH(1.0), + fatanchorSH(50.0), + gamSH(2.4), + sloSH(12.92), + // Vibrance + visivibrance(false), + expvibrance(false), + complexvibrance(0), + saturated(0), + pastels(0), + warm(0), + psthreshold({0, 75, false}), + protectskins(false), + avoidcolorshift(true), + pastsattog(true), + sensiv(15), + skintonescurve{ + static_cast(DCT_Linear) + }, + CCmaskvibcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmaskvibcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmaskvibcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + enavibMask(false), + blendmaskvib(0), + radmaskvib(0.0), + chromaskvib(0.0), + gammaskvib(1.0), + slomaskvib(0.0), + lapmaskvib(0.0), + strvib(0.0), + strvibab(0.0), + strvibh(0.0), + angvib(0.0), + Lmaskvibcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + // Soft Light + visisoft(false), + expsoft(false), + complexsoft(0), + streng(0), + sensisf(30), + laplace(25.), + softMethod("soft"), + // Blur & Noise + visiblur(false), + expblur(false), + complexblur(0), + radius(1.5), + strength(0), + sensibn(40), + itera(1), + guidbl(0), + strbl(50), + isogr(400), + strengr(0), + scalegr(100), + epsbl(0), + blMethod("blur"), + chroMethod("lum"), + blurMethod("norm"), + medMethod("33"), + activlum(true), + noiselumf(0.), + noiselumf0(0.), + noiselumf2(0.), + noiselumc(0.), + noiselumdetail(0.), + noiselequal(7), + noisechrof(0.), + noisechroc(0.), + noisechrodetail(0.), + adjblur(0), + bilateral(0), + sensiden(60), + detailthr(0), + locwavcurveden{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.0, + 0.0, + 0.35, + 0.5, + 0., + 0.35, + 0.35, + 1.0, + 0.0, + 0.35, + 0.35 + }, + showmaskblMethodtyp("blur"), + CCmaskblcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmaskblcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmaskblcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + enablMask(false), + fftwbl(false), + toolbl(false), + blendmaskbl(0), + radmaskbl(0.0), + chromaskbl(0.0), + gammaskbl(1.0), + slomaskbl(0.0), + lapmaskbl(0.0), + shadmaskbl(0), + shadmaskblsha(0), + strumaskbl(0.), + Lmaskblcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + LLmaskblcurvewav{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.5, + 0.35, + 0.35, + 1., + 0.5, + 0.35, + 0.35 + }, + csthresholdblur(0, 0, 6, 5, false), + // Tone Mapping + visitonemap(false), + exptonemap(false), + complextonemap(0), + stren(0.5), + gamma(1.0), + estop(1.4), + scaltm(1.0), + rewei(0), + satur(0.), + sensitm(30), + softradiustm(0.0), + amount(95.), + equiltm(true), + CCmasktmcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmasktmcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmasktmcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + enatmMask(false), + enatmMaskaft(false), + blendmasktm(0), + radmasktm(0.0), + chromasktm(0.0), + gammasktm(1.0), + slomasktm(0.0), + lapmasktm(0.0), + Lmasktmcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + // Retinex + visireti(false), + expreti(false), + complexreti(0), + retinexMethod("high"), + str(0.), + chrrt(0.0), + neigh(50.0), + vart(150.0), + offs(0.0), + dehaz(0), + depth(25), + sensih(60), + localTgaincurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.12, + 0.35, + 0.35, + 0.70, + 0.50, + 0.35, + 0.35, + 1.00, + 0.12, + 0.35, + 0.35 + }, + localTtranscurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.50, + 0.35, + 0.35, + 0.5, + 0.5, + 0.35, + 0.35, + 1.00, + 0.50, + 0.35, + 0.35 + }, + inversret(false), + equilret(true), + loglin(false), + lumonly(false), + softradiusret(40.0), + CCmaskreticurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmaskreticurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmaskreticurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + enaretiMask(false), + enaretiMasktmap(true), + blendmaskreti(0), + radmaskreti(0.0), + chromaskreti(0.0), + gammaskreti(1.0), + slomaskreti(0.0), + lapmaskreti(0.0), + scalereti(2.0), + darkness(2.0), + lightnessreti(1.0), + limd(8.0), + cliptm(1.0), + fftwreti(false), + Lmaskreticurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + // Sharpening + visisharp(false), + expsharp(false), + complexsharp(0), + sharcontrast(20), + sharradius(0.75), + sharamount(100), + shardamping(0), + shariter(30), + sharblur(0.2), + sensisha(40), + inverssha(false), + // Local Contrast + visicontrast(false), + expcontrast(false), + complexcontrast(0), + lcradius(80), + lcamount(0.0), + lcdarkness(1.0), + lclightness(1.0), + sigmalc(1.0), + levelwav(4), + residcont(0.0), + residsha(0.0), + residshathr(30.0), + residhi(0.0), + residhithr(70.0), + residblur(0.0), + levelblur(0.0), + sigmabl(1.0), + residchro(0.0), + residcomp(0.0), + sigma(1.0), + offset(1.0), + sigmadr(1.0), + threswav(1.4), + chromalev(1.0), + chromablu(0.0), + sigmadc(1.0), + deltad(0.0), + fatres(0.0), + clarilres(0.0), + claricres(0.0), + clarisoft(1.0), + sigmalc2(1.0), + strwav(0.0), + angwav(0.0), + strengthw(0.0), + sigmaed(1.0), + radiusw(15.0), + detailw(10.0), + gradw(90.0), + tloww(20.0), + thigw(0.0), + edgw(60.0), + basew(10.0), + sensilc(60), + fftwlc(false), + blurlc(true), + wavblur(false), + wavedg(false), + waveshow(false), + wavcont(false), + wavcomp(false), + wavgradl(false), + wavcompre(false), + origlc(false), + localcontMethod("loc"), + localedgMethod("thr"), + localneiMethod("low"), + locwavcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.5, + 0.35, + 0.35, + 1., + 0.5, + 0.35, + 0.35 + }, + csthreshold(0, 0, 6, 6, false), + loclevwavcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.0, + 0.0, + 0.35, + 0.5, + 0., + 0.35, + 0.35, + 1.0, + 0.0, + 0.35, + 0.35 + }, + locconwavcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.5, + 0.35, + 0.35, + 1., + 0.5, + 0.35, + 0.35 + }, + loccompwavcurve{ + static_cast(FCT_MinMaxCPoints), + 0.00, + 0.35, + 0.35, + 0.00, + 0.35, + 0.75, + 0.35, + 0.35, + 0.60, + 0.75, + 0.35, + 0.35, + 1.00, + 0.35, + 0.00, + 0.00 + }, + loccomprewavcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.75, + 0.35, + 0.35, + 1., + 0.75, + 0.35, + 0.35 + }, + locedgwavcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.25, + 0.35, + 0.35, + 0.50, + 0.75, + 0.35, + 0.35, + 0.90, + 0.0, + 0.35, + 0.35 + }, + CCmasklccurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmasklccurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmasklccurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + enalcMask(false), + blendmasklc(0), + radmasklc(0.0), + chromasklc(0.0), + Lmasklccurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + // Contrast by detail levels + visicbdl(false), + expcbdl(false), + complexcbdl(0), + mult{1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, + chromacbdl(0.), + threshold(0.2), + sensicb(60), + clarityml(0.1), + contresid(0), + blurcbdl(0.), + softradiuscb(0.0), + enacbMask(false), + CCmaskcbcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + LLmaskcbcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + HHmaskcbcurve{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 1.0, + 0.35, + 0.35, + 0.50, + 1.0, + 0.35, + 0.35, + 1.0, + 1.0, + 0.35, + 0.35 + }, + blendmaskcb(0), + radmaskcb(0.0), + chromaskcb(0.0), + gammaskcb(1.0), + slomaskcb(0.0), + lapmaskcb(0.0), + Lmaskcbcurve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + // Log encoding + visilog(false), + explog(false), + autocompute(false), + sourceGray(10.), + targetGray(18.), + Autogray(true), + fullimage(true), + blackEv(-5.0), + whiteEv(10.0), + detail(0.6), + sensilog(60), + baselog(2.), + strlog(0.0), + anglog(0.0) +{ +} + +bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const +{ + return + // Control spot settings + name == other.name + && isvisible == other.isvisible + && shape == other.shape + && spotMethod == other.spotMethod + && wavMethod == other.wavMethod + && sensiexclu == other.sensiexclu + && structexclu == other.structexclu + && struc == other.struc + && shapeMethod == other.shapeMethod + && loc == other.loc + && centerX == other.centerX + && centerY == other.centerY + && circrad == other.circrad + && qualityMethod == other.qualityMethod + && complexMethod == other.complexMethod + && transit == other.transit + && feather == other.feather + && thresh == other.thresh + && iter == other.iter + && balan == other.balan + && balanh == other.balanh + && colorde == other.colorde + && colorscope == other.colorscope + && transitweak == other.transitweak + && transitgrad == other.transitgrad + && avoid == other.avoid + && blwh == other.blwh + && recurs == other.recurs + && laplac == other.laplac + && deltae == other.deltae + && shortc == other.shortc + && savrest == other.savrest + && scopemask == other.scopemask + && lumask == other.lumask + // Color & Light + && visicolor == other.visicolor + && expcolor == other.expcolor + && complexcolor == other.complexcolor + && curvactiv == other.curvactiv + && lightness == other.lightness + && contrast == other.contrast + && chroma == other.chroma + && labgridALow == other.labgridALow + && labgridBLow == other.labgridBLow + && labgridAHigh == other.labgridAHigh + && labgridBHigh == other.labgridBHigh + && labgridALowmerg == other.labgridALowmerg + && labgridBLowmerg == other.labgridBLowmerg + && labgridAHighmerg == other.labgridAHighmerg + && labgridBHighmerg == other.labgridBHighmerg + && strengthgrid == other.strengthgrid + && sensi == other.sensi + && structcol == other.structcol + && strcol == other.strcol + && strcolab == other.strcolab + && strcolh == other.strcolh + && angcol == other.angcol + && blurcolde == other.blurcolde + && blurcol == other.blurcol + && contcol == other.contcol + && blendmaskcol == other.blendmaskcol + && radmaskcol == other.radmaskcol + && chromaskcol == other.chromaskcol + && gammaskcol == other.gammaskcol + && slomaskcol == other.slomaskcol + && shadmaskcol == other.shadmaskcol + && strumaskcol == other.strumaskcol + && lapmaskcol == other.lapmaskcol + && qualitycurveMethod == other.qualitycurveMethod + && gridMethod == other.gridMethod + && merMethod == other.merMethod + && toneMethod == other.toneMethod + && mergecolMethod == other.mergecolMethod + && llcurve == other.llcurve + && lccurve == other.lccurve + && cccurve == other.cccurve + && clcurve == other.clcurve + && rgbcurve == other.rgbcurve + && LHcurve == other.LHcurve + && HHcurve == other.HHcurve + && invers == other.invers + && special == other.special + && toolcol == other.toolcol + && enaColorMask == other.enaColorMask + && fftColorMask == other.fftColorMask + && CCmaskcurve == other.CCmaskcurve + && LLmaskcurve == other.LLmaskcurve + && HHmaskcurve == other.HHmaskcurve + && HHhmaskcurve == other.HHhmaskcurve + && softradiuscol == other.softradiuscol + && opacol == other.opacol + && mercol == other.mercol + && merlucol == other.merlucol + && conthrcol == other.conthrcol + && Lmaskcurve == other.Lmaskcurve + && LLmaskcolcurvewav == other.LLmaskcolcurvewav + && csthresholdcol == other.csthresholdcol + // Exposure + && visiexpose == other.visiexpose + && expexpose == other.expexpose + && complexexpose == other.complexexpose + && expcomp == other.expcomp + && hlcompr == other.hlcompr + && hlcomprthresh == other.hlcomprthresh + && black == other.black + && shadex == other.shadex + && shcompr == other.shcompr + && expchroma == other.expchroma + && sensiex == other.sensiex + && structexp == other.structexp + && blurexpde == other.blurexpde + && strexp == other.strexp + && angexp == other.angexp + && excurve == other.excurve + && inversex == other.inversex + && enaExpMask == other.enaExpMask + && enaExpMaskaft == other.enaExpMaskaft + && CCmaskexpcurve == other.CCmaskexpcurve + && LLmaskexpcurve == other.LLmaskexpcurve + && HHmaskexpcurve == other.HHmaskexpcurve + && blendmaskexp == other.blendmaskexp + && radmaskexp == other.radmaskexp + && chromaskexp == other.chromaskexp + && gammaskexp == other.gammaskexp + && slomaskexp == other.slomaskexp + && lapmaskexp == other.lapmaskexp + && strmaskexp == other.strmaskexp + && angmaskexp == other.angmaskexp + && softradiusexp == other.softradiusexp + && Lmaskexpcurve == other.Lmaskexpcurve + && expMethod == other.expMethod + && exnoiseMethod == other.exnoiseMethod + && laplacexp == other.laplacexp + && balanexp == other.balanexp + && linear == other.linear + && gamm == other.gamm + && fatamount == other.fatamount + && fatdetail == other.fatdetail + && fatanchor == other.fatanchor + && fatlevel == other.fatlevel + // Shadow highlight + && visishadhigh == other.visishadhigh + && expshadhigh == other.expshadhigh + && complexshadhigh == other.complexshadhigh + && shMethod == other.shMethod + && [this, &other]() -> bool + { + for (int i = 0; i < 5; ++i) { + if (multsh[i] != other.multsh[i]) { + return false; + } + } + return true; + }() + && highlights == other.highlights + && h_tonalwidth == other.h_tonalwidth + && shadows == other.shadows + && s_tonalwidth == other.s_tonalwidth + && sh_radius == other.sh_radius + && sensihs == other.sensihs + && enaSHMask == other.enaSHMask + && CCmaskSHcurve == other.CCmaskSHcurve + && LLmaskSHcurve == other.LLmaskSHcurve + && HHmaskSHcurve == other.HHmaskSHcurve + && blendmaskSH == other.blendmaskSH + && radmaskSH == other.radmaskSH + && blurSHde == other.blurSHde + && strSH == other.strSH + && angSH == other.angSH + && inverssh == other.inverssh + && chromaskSH == other.chromaskSH + && gammaskSH == other.gammaskSH + && slomaskSH == other.slomaskSH + && lapmaskSH == other.lapmaskSH + && detailSH == other.detailSH + && LmaskSHcurve == other.LmaskSHcurve + && fatamountSH == other.fatamountSH + && fatanchorSH == other.fatanchorSH + && gamSH == other.gamSH + && sloSH == other.sloSH + // Vibrance + && visivibrance == other.visivibrance + && expvibrance == other.expvibrance + && complexvibrance == other.complexvibrance + && saturated == other.saturated + && pastels == other.pastels + && warm == other.warm + && psthreshold == other.psthreshold + && protectskins == other.protectskins + && avoidcolorshift == other.avoidcolorshift + && pastsattog == other.pastsattog + && sensiv == other.sensiv + && skintonescurve == other.skintonescurve + && CCmaskvibcurve == other.CCmaskvibcurve + && LLmaskvibcurve == other.LLmaskvibcurve + && HHmaskvibcurve == other.HHmaskvibcurve + && enavibMask == other.enavibMask + && blendmaskvib == other.blendmaskvib + && radmaskvib == other.radmaskvib + && chromaskvib == other.chromaskvib + && gammaskvib == other.gammaskvib + && slomaskvib == other.slomaskvib + && lapmaskvib == other.lapmaskvib + && strvib == other.strvib + && strvibab == other.strvibab + && strvibh == other.strvibh + && angvib == other.angvib + && Lmaskvibcurve == other.Lmaskvibcurve + // Soft Light + && visisoft == other.visisoft + && expsoft == other.expsoft + && complexsoft == other.complexsoft + && streng == other.streng + && sensisf == other.sensisf + && laplace == other.laplace + && softMethod == other.softMethod + // Blur & Noise + && visiblur == other.visiblur + && expblur == other.expblur + && complexblur == other.complexblur + && radius == other.radius + && strength == other.strength + && sensibn == other.sensibn + && itera == other.itera + && guidbl == other.guidbl + && strbl == other.strbl + && isogr == other.isogr + && strengr == other.strengr + && scalegr == other.scalegr + && epsbl == other.epsbl + && blMethod == other.blMethod + && chroMethod == other.chroMethod + && blurMethod == other.blurMethod + && medMethod == other.medMethod + && activlum == other.activlum + && noiselumf == other.noiselumf + && noiselumf0 == other.noiselumf0 + && noiselumf2 == other.noiselumf2 + && noiselumc == other.noiselumc + && noiselumdetail == other.noiselumdetail + && noiselequal == other.noiselequal + && noisechrof == other.noisechrof + && noisechroc == other.noisechroc + && noisechrodetail == other.noisechrodetail + && adjblur == other.adjblur + && bilateral == other.bilateral + && sensiden == other.sensiden + && detailthr == other.detailthr + && locwavcurveden == other.locwavcurveden + && showmaskblMethodtyp == other.showmaskblMethodtyp + && CCmaskblcurve == other.CCmaskblcurve + && LLmaskblcurve == other.LLmaskblcurve + && HHmaskblcurve == other.HHmaskblcurve + && enablMask == other.enablMask + && fftwbl == other.fftwbl + && toolbl == other.toolbl + && blendmaskbl == other.blendmaskbl + && radmaskbl == other.radmaskbl + && chromaskbl == other.chromaskbl + && gammaskbl == other.gammaskbl + && slomaskbl == other.slomaskbl + && lapmaskbl == other.lapmaskbl + && shadmaskbl == other.shadmaskbl + && shadmaskblsha == other.shadmaskblsha + && strumaskbl == other.strumaskbl + && Lmaskblcurve == other.Lmaskblcurve + && LLmaskblcurvewav == other.LLmaskblcurvewav + && csthresholdblur == other.csthresholdblur + // Tone Mapping + && visitonemap == other.visitonemap + && exptonemap == other.exptonemap + && complextonemap == other.complextonemap + && stren == other.stren + && gamma == other.gamma + && estop == other.estop + && scaltm == other.scaltm + && rewei == other.rewei + && satur == other.satur + && sensitm == other.sensitm + && softradiustm == other.softradiustm + && amount == other.amount + && equiltm == other.equiltm + && CCmasktmcurve == other.CCmasktmcurve + && LLmasktmcurve == other.LLmasktmcurve + && HHmasktmcurve == other.HHmasktmcurve + && enatmMask == other.enatmMask + && enatmMaskaft == other.enatmMaskaft + && blendmasktm == other.blendmasktm + && radmasktm == other.radmasktm + && chromasktm == other.chromasktm + && gammasktm == other.gammasktm + && slomasktm == other.slomasktm + && lapmasktm == other.lapmasktm + && Lmasktmcurve == other.Lmasktmcurve + // Retinex + && visireti == other.visireti + && expreti == other.expreti + && complexreti == other.complexreti + && retinexMethod == other.retinexMethod + && str == other.str + && chrrt == other.chrrt + && neigh == other.neigh + && vart == other.vart + && offs == other.offs + && dehaz == other.dehaz + && depth == other.depth + && sensih == other.sensih + && localTgaincurve == other.localTgaincurve + && localTtranscurve == other.localTtranscurve + && inversret == other.inversret + && equilret == other.equilret + && loglin == other.loglin + && lumonly == other.lumonly + && softradiusret == other.softradiusret + && CCmaskreticurve == other.CCmaskreticurve + && LLmaskreticurve == other.LLmaskreticurve + && HHmaskreticurve == other.HHmaskreticurve + && enaretiMask == other.enaretiMask + && enaretiMasktmap == other.enaretiMasktmap + && blendmaskreti == other.blendmaskreti + && radmaskreti == other.radmaskreti + && chromaskreti == other.chromaskreti + && gammaskreti == other.gammaskreti + && slomaskreti == other.slomaskreti + && lapmaskreti == other.lapmaskreti + && scalereti == other.scalereti + && darkness == other.darkness + && lightnessreti == other.lightnessreti + && limd == other.limd + && cliptm == other.cliptm + && fftwreti == other.fftwreti + && Lmaskreticurve == other.Lmaskreticurve + // Sharpening + && visisharp == other.visisharp + && expsharp == other.expsharp + && complexsharp == other.complexsharp + && sharcontrast == other.sharcontrast + && sharradius == other.sharradius + && sharamount == other.sharamount + && shardamping == other.shardamping + && shariter == other.shariter + && sharblur == other.sharblur + && sensisha == other.sensisha + && inverssha == other.inverssha + // Local contrast + && visicontrast == other.visicontrast + && expcontrast == other.expcontrast + && complexcontrast == other.complexcontrast + && lcradius == other.lcradius + && lcamount == other.lcamount + && lcdarkness == other.lcdarkness + && lclightness == other.lclightness + && sigmalc == other.sigmalc + && levelwav == other.levelwav + && residcont == other.residcont + && residsha == other.residsha + && residshathr == other.residshathr + && residhi == other.residhi + && residhithr == other.residhithr + && residblur == other.residblur + && levelblur == other.levelblur + && sigmabl == other.sigmabl + && residchro == other.residchro + && residcomp == other.residcomp + && sigma == other.sigma + && offset == other.offset + && sigmadr == other.sigmadr + && threswav == other.threswav + && chromalev == other.chromalev + && chromablu == other.chromablu + && sigmadc == other.sigmadc + && deltad == other.deltad + && fatres == other.fatres + && clarilres == other.clarilres + && claricres == other.claricres + && clarisoft == other.clarisoft + && sigmalc2 == other.sigmalc2 + && strwav == other.strwav + && angwav == other.angwav + && strengthw == other.strengthw + && sigmaed == other.sigmaed + && radiusw == other.radiusw + && detailw == other.detailw + && gradw == other.gradw + && tloww == other.tloww + && thigw == other.thigw + && edgw == other.edgw + && basew == other.basew + && sensilc == other.sensilc + && fftwlc == other.fftwlc + && blurlc == other.blurlc + && wavblur == other.wavblur + && wavedg == other.wavedg + && waveshow == other.waveshow + && wavcont == other.wavcont + && wavcomp == other.wavcomp + && wavgradl == other.wavgradl + && wavcompre == other.wavcompre + && origlc == other.origlc + && localcontMethod == other.localcontMethod + && localedgMethod == other.localedgMethod + && localneiMethod == other.localneiMethod + && locwavcurve == other.locwavcurve + && csthreshold == other.csthreshold + && loclevwavcurve == other.loclevwavcurve + && locconwavcurve == other.locconwavcurve + && loccompwavcurve == other.loccompwavcurve + && loccomprewavcurve == other.loccomprewavcurve + && locedgwavcurve == other.locedgwavcurve + && CCmasklccurve == other.CCmasklccurve + && LLmasklccurve == other.LLmasklccurve + && HHmasklccurve == other.HHmasklccurve + && enalcMask == other.enalcMask + && blendmasklc == other.blendmasklc + && radmasklc == other.radmasklc + && chromasklc == other.chromasklc + && Lmasklccurve == other.Lmasklccurve + // Contrast by detail levels + && visicbdl == other.visicbdl + && expcbdl == other.expcbdl + && complexcbdl == other.complexcbdl + && [this, &other]() -> bool + { + for (int i = 0; i < 6; ++i) { + if (mult[i] != other.mult[i]) { + return false; + } + } + return true; + }() + && chromacbdl == other.chromacbdl + && threshold == other.threshold + && sensicb == other.sensicb + && clarityml == other.clarityml + && contresid == other.contresid + && blurcbdl == other.blurcbdl + && softradiuscb == other.softradiuscb + && enacbMask == other.enacbMask + && CCmaskcbcurve == other.CCmaskcbcurve + && LLmaskcbcurve == other.LLmaskcbcurve + && HHmaskcbcurve == other.HHmaskcbcurve + && blendmaskcb == other.blendmaskcb + && radmaskcb == other.radmaskcb + && chromaskcb == other.chromaskcb + && gammaskcb == other.gammaskcb + && slomaskcb == other.slomaskcb + && lapmaskcb == other.lapmaskcb + && Lmaskcbcurve == other.Lmaskcbcurve + // Log encoding + && visilog == other.visilog + && explog == other.explog + && autocompute == other.autocompute + && sourceGray == other.sourceGray + && targetGray == other.targetGray + && Autogray == other.Autogray + && fullimage == other.fullimage + && blackEv == other.blackEv + && whiteEv == other.whiteEv + && detail == other.detail + && sensilog == other.sensilog + && baselog == other.baselog + && strlog == other.strlog + && anglog == other.anglog; +} + +bool LocallabParams::LocallabSpot::operator !=(const LocallabSpot& other) const +{ + return !(*this == other); +} + +const double LocallabParams::LABGRIDL_CORR_MAX = 12800.; +const double LocallabParams::LABGRIDL_CORR_SCALE = 3.276; +const double LocallabParams::LABGRIDL_DIRECT_SCALE = 41950.; + +LocallabParams::LocallabParams() : + enabled(false), + selspot(0), + spots() +{ +} + +bool LocallabParams::operator ==(const LocallabParams& other) const +{ + return + enabled == other.enabled + && selspot == other.selspot + && spots == other.spots; +} + +bool LocallabParams::operator !=(const LocallabParams& other) const +{ + return !(*this == other); +} + DirPyrEqualizerParams::DirPyrEqualizerParams() : enabled(false), gamutlab(false), @@ -2523,7 +4249,7 @@ DirPyrEqualizerParams::DirPyrEqualizerParams() : }, threshold(0.2), skinprotect(0.0), - hueskin (-5, 25, 170, 120, false), + hueskin(-5, 25, 170, 120, false), cbdlMethod("bef") { } @@ -2783,8 +4509,6 @@ Glib::ustring RAWParams::BayerSensor::getPSDemosaicMethodString(PSDemosaicMethod return getPSDemosaicMethodStrings()[toUnderlying(method)]; } - - RAWParams::XTransSensor::XTransSensor() : method(getMethodString(Method::THREE_PASS)), dualDemosaicAutoContrast(true), @@ -2834,6 +4558,23 @@ Glib::ustring RAWParams::XTransSensor::getMethodString(Method method) return getMethodStrings()[toUnderlying(method)]; } + +RAWParams::PreprocessWB::PreprocessWB() : + mode(Mode::AUTO) +{ +} + +bool RAWParams::PreprocessWB::operator ==(const PreprocessWB& other) const +{ + return mode == other.mode; +} + +bool RAWParams::PreprocessWB::operator !=(const PreprocessWB& other) const +{ + return !(*this == other); +} + + RAWParams::RAWParams() : df_autoselect(false), ff_AutoSelect(false), @@ -2872,6 +4613,7 @@ bool RAWParams::operator ==(const RAWParams& other) const && cared == other.cared && cablue == other.cablue && expos == other.expos + && preprocessWB == other.preprocessWB && hotPixelFilter == other.hotPixelFilter && deadPixelFilter == other.deadPixelFilter && hotdeadpix_thresh == other.hotdeadpix_thresh; @@ -3013,6 +4755,8 @@ void ProcParams::setDefaults() vignetting = {}; + locallab = {}; + chmixer = {}; blackwhite = {}; @@ -3333,7 +5077,6 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo {ColorAppearanceParams::CtcMode::CHROMA, "Chroma"}, {ColorAppearanceParams::CtcMode::SATUR, "Saturation"}, {ColorAppearanceParams::CtcMode::COLORF, "Colorfullness"} - }, colorappearance.curveMode3, keyFile @@ -3476,6 +5219,488 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->gradient.centerX, "Gradient", "CenterX", gradient.centerX, keyFile); saveToKeyfile(!pedited || pedited->gradient.centerY, "Gradient", "CenterY", gradient.centerY, keyFile); +// Locallab + saveToKeyfile(!pedited || pedited->locallab.enabled, "Locallab", "Enabled", locallab.enabled, keyFile); + saveToKeyfile(!pedited || pedited->locallab.selspot, "Locallab", "Selspot", locallab.selspot, keyFile); + + for (size_t i = 0; i < locallab.spots.size(); ++i) { + if (!pedited || i < pedited->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = locallab.spots.at(i); + const LocallabParamsEdited::LocallabSpotEdited* const spot_edited = + pedited + ? &pedited->locallab.spots.at(i) + : nullptr; + const std::string index_str = std::to_string(i); + // Control spot settings + saveToKeyfile(!pedited || spot_edited->name, "Locallab", "Name_" + index_str, spot.name, keyFile); + saveToKeyfile(!pedited || spot_edited->isvisible, "Locallab", "Isvisible_" + index_str, spot.isvisible, keyFile); + saveToKeyfile(!pedited || spot_edited->shape, "Locallab", "Shape_" + index_str, spot.shape, keyFile); + saveToKeyfile(!pedited || spot_edited->spotMethod, "Locallab", "SpotMethod_" + index_str, spot.spotMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->wavMethod, "Locallab", "WavMethod_" + index_str, spot.wavMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->sensiexclu, "Locallab", "SensiExclu_" + index_str, spot.sensiexclu, keyFile); + saveToKeyfile(!pedited || spot_edited->structexclu, "Locallab", "StructExclu_" + index_str, spot.structexclu, keyFile); + saveToKeyfile(!pedited || spot_edited->struc, "Locallab", "Struc_" + index_str, spot.struc, keyFile); + saveToKeyfile(!pedited || spot_edited->shapeMethod, "Locallab", "ShapeMethod_" + index_str, spot.shapeMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->loc, "Locallab", "Loc_" + index_str, spot.loc, keyFile); + saveToKeyfile(!pedited || spot_edited->centerX, "Locallab", "CenterX_" + index_str, spot.centerX, keyFile); + saveToKeyfile(!pedited || spot_edited->centerY, "Locallab", "CenterY_" + index_str, spot.centerY, keyFile); + saveToKeyfile(!pedited || spot_edited->circrad, "Locallab", "Circrad_" + index_str, spot.circrad, keyFile); + saveToKeyfile(!pedited || spot_edited->qualityMethod, "Locallab", "QualityMethod_" + index_str, spot.qualityMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->complexMethod, "Locallab", "ComplexMethod_" + index_str, spot.complexMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->transit, "Locallab", "Transit_" + index_str, spot.transit, keyFile); + saveToKeyfile(!pedited || spot_edited->feather, "Locallab", "Feather_" + index_str, spot.feather, keyFile); + saveToKeyfile(!pedited || spot_edited->thresh, "Locallab", "Thresh_" + index_str, spot.thresh, keyFile); + saveToKeyfile(!pedited || spot_edited->iter, "Locallab", "Iter_" + index_str, spot.iter, keyFile); + saveToKeyfile(!pedited || spot_edited->balan, "Locallab", "Balan_" + index_str, spot.balan, keyFile); + saveToKeyfile(!pedited || spot_edited->balanh, "Locallab", "Balanh_" + index_str, spot.balanh, keyFile); + saveToKeyfile(!pedited || spot_edited->colorde, "Locallab", "Colorde_" + index_str, spot.colorde, keyFile); + saveToKeyfile(!pedited || spot_edited->colorscope, "Locallab", "Colorscope_" + index_str, spot.colorscope, keyFile); + saveToKeyfile(!pedited || spot_edited->transitweak, "Locallab", "Transitweak_" + index_str, spot.transitweak, keyFile); + saveToKeyfile(!pedited || spot_edited->transitgrad, "Locallab", "Transitgrad_" + index_str, spot.transitgrad, keyFile); + saveToKeyfile(!pedited || spot_edited->avoid, "Locallab", "Avoid_" + index_str, spot.avoid, keyFile); + saveToKeyfile(!pedited || spot_edited->blwh, "Locallab", "Blwh_" + index_str, spot.blwh, keyFile); + saveToKeyfile(!pedited || spot_edited->recurs, "Locallab", "Recurs_" + index_str, spot.recurs, keyFile); + saveToKeyfile(!pedited || spot_edited->laplac, "Locallab", "Laplac_" + index_str, spot.laplac, keyFile); + saveToKeyfile(!pedited || spot_edited->deltae, "Locallab", "Deltae_" + index_str, spot.deltae, keyFile); + saveToKeyfile(!pedited || spot_edited->shortc, "Locallab", "Shortc_" + index_str, spot.shortc, keyFile); + saveToKeyfile(!pedited || spot_edited->savrest, "Locallab", "Savrest_" + index_str, spot.savrest, keyFile); + saveToKeyfile(!pedited || spot_edited->scopemask, "Locallab", "Scopemask_" + index_str, spot.scopemask, keyFile); + saveToKeyfile(!pedited || spot_edited->lumask, "Locallab", "Lumask_" + index_str, spot.lumask, keyFile); + // Color & Light + if ((!pedited || spot_edited->visicolor) && spot.visicolor) { + saveToKeyfile(!pedited || spot_edited->expcolor, "Locallab", "Expcolor_" + index_str, spot.expcolor, keyFile); + saveToKeyfile(!pedited || spot_edited->complexcolor, "Locallab", "Complexcolor_" + index_str, spot.complexcolor, keyFile); + saveToKeyfile(!pedited || spot_edited->curvactiv, "Locallab", "Curvactiv_" + index_str, spot.curvactiv, keyFile); + saveToKeyfile(!pedited || spot_edited->lightness, "Locallab", "Lightness_" + index_str, spot.lightness, keyFile); + saveToKeyfile(!pedited || spot_edited->contrast, "Locallab", "Contrast_" + index_str, spot.contrast, keyFile); + saveToKeyfile(!pedited || spot_edited->chroma, "Locallab", "Chroma_" + index_str, spot.chroma, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridALow, "Locallab", "labgridALow_" + index_str, spot.labgridALow, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridBLow, "Locallab", "labgridBLow_" + index_str, spot.labgridBLow, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridAHigh, "Locallab", "labgridAHigh_" + index_str, spot.labgridAHigh, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridBHigh, "Locallab", "labgridBHigh_" + index_str, spot.labgridBHigh, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridALowmerg, "Locallab", "labgridALowmerg_" + index_str, spot.labgridALowmerg, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridBLowmerg, "Locallab", "labgridBLowmerg_" + index_str, spot.labgridBLowmerg, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridAHighmerg, "Locallab", "labgridAHighmerg_" + index_str, spot.labgridAHighmerg, keyFile); + saveToKeyfile(!pedited || spot_edited->labgridBHighmerg, "Locallab", "labgridBHighmerg_" + index_str, spot.labgridBHighmerg, keyFile); + saveToKeyfile(!pedited || spot_edited->strengthgrid, "Locallab", "Strengthgrid_" + index_str, spot.strengthgrid, keyFile); + saveToKeyfile(!pedited || spot_edited->sensi, "Locallab", "Sensi_" + index_str, spot.sensi, keyFile); + saveToKeyfile(!pedited || spot_edited->structcol, "Locallab", "Structcol_" + index_str, spot.structcol, keyFile); + saveToKeyfile(!pedited || spot_edited->strcol, "Locallab", "Strcol_" + index_str, spot.strcol, keyFile); + saveToKeyfile(!pedited || spot_edited->strcolab, "Locallab", "Strcolab_" + index_str, spot.strcolab, keyFile); + saveToKeyfile(!pedited || spot_edited->strcolh, "Locallab", "Strcolh_" + index_str, spot.strcolh, keyFile); + saveToKeyfile(!pedited || spot_edited->angcol, "Locallab", "Angcol_" + index_str, spot.angcol, keyFile); + saveToKeyfile(!pedited || spot_edited->blurcolde, "Locallab", "Blurcolde_" + index_str, spot.blurcolde, keyFile); + saveToKeyfile(!pedited || spot_edited->blurcol, "Locallab", "Blurcol_" + index_str, spot.blurcol, keyFile); + saveToKeyfile(!pedited || spot_edited->contcol, "Locallab", "Contcol_" + index_str, spot.contcol, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskcol, "Locallab", "Blendmaskcol_" + index_str, spot.blendmaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskcol, "Locallab", "Radmaskcol_" + index_str, spot.radmaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskcol, "Locallab", "Chromaskcol_" + index_str, spot.chromaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskcol, "Locallab", "Gammaskcol_" + index_str, spot.gammaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskcol, "Locallab", "Slomaskcol_" + index_str, spot.slomaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->shadmaskcol, "Locallab", "shadmaskcol_" + index_str, spot.shadmaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->strumaskcol, "Locallab", "strumaskcol_" + index_str, spot.strumaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmaskcol, "Locallab", "Lapmaskcol_" + index_str, spot.lapmaskcol, keyFile); + saveToKeyfile(!pedited || spot_edited->qualitycurveMethod, "Locallab", "QualityCurveMethod_" + index_str, spot.qualitycurveMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->gridMethod, "Locallab", "gridMethod_" + index_str, spot.gridMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->merMethod, "Locallab", "Merg_Method_" + index_str, spot.merMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->toneMethod, "Locallab", "ToneMethod_" + index_str, spot.toneMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->mergecolMethod, "Locallab", "mergecolMethod_" + index_str, spot.mergecolMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->llcurve, "Locallab", "LLCurve_" + index_str, spot.llcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->lccurve, "Locallab", "LCCurve_" + index_str, spot.lccurve, keyFile); + saveToKeyfile(!pedited || spot_edited->cccurve, "Locallab", "CCCurve_" + index_str, spot.cccurve, keyFile); + saveToKeyfile(!pedited || spot_edited->clcurve, "Locallab", "CLCurve_" + index_str, spot.clcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->rgbcurve, "Locallab", "RGBCurve_" + index_str, spot.rgbcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LHcurve, "Locallab", "LHCurve_" + index_str, spot.LHcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHcurve, "Locallab", "HHCurve_" + index_str, spot.HHcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->invers, "Locallab", "Invers_" + index_str, spot.invers, keyFile); + saveToKeyfile(!pedited || spot_edited->special, "Locallab", "Special_" + index_str, spot.special, keyFile); + saveToKeyfile(!pedited || spot_edited->toolcol, "Locallab", "Toolcol_" + index_str, spot.toolcol, keyFile); + saveToKeyfile(!pedited || spot_edited->enaColorMask, "Locallab", "EnaColorMask_" + index_str, spot.enaColorMask, keyFile); + saveToKeyfile(!pedited || spot_edited->fftColorMask, "Locallab", "FftColorMask_" + index_str, spot.fftColorMask, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskcurve, "Locallab", "CCmaskCurve_" + index_str, spot.CCmaskcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskcurve, "Locallab", "LLmaskCurve_" + index_str, spot.LLmaskcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskcurve, "Locallab", "HHmaskCurve_" + index_str, spot.HHmaskcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHhmaskcurve, "Locallab", "HHhmaskCurve_" + index_str, spot.HHhmaskcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->softradiuscol, "Locallab", "Softradiuscol_" + index_str, spot.softradiuscol, keyFile); + saveToKeyfile(!pedited || spot_edited->opacol, "Locallab", "Opacol_" + index_str, spot.opacol, keyFile); + saveToKeyfile(!pedited || spot_edited->mercol, "Locallab", "Mercol_" + index_str, spot.mercol, keyFile); + saveToKeyfile(!pedited || spot_edited->merlucol, "Locallab", "Merlucol_" + index_str, spot.merlucol, keyFile); + saveToKeyfile(!pedited || spot_edited->conthrcol, "Locallab", "Conthrcol_" + index_str, spot.conthrcol, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmaskcurve, "Locallab", "LmaskCurve_" + index_str, spot.Lmaskcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskcolcurvewav, "Locallab", "LLmaskcolCurvewav_" + index_str, spot.LLmaskcolcurvewav, keyFile); + saveToKeyfile(!pedited || spot_edited->csthresholdcol, "Locallab", "CSThresholdcol_" + index_str, spot.csthresholdcol.toVector(), keyFile); + } + // Exposure + if ((!pedited || spot_edited->visiexpose) && spot.visiexpose) { + saveToKeyfile(!pedited || spot_edited->expexpose, "Locallab", "Expexpose_" + index_str, spot.expexpose, keyFile); + saveToKeyfile(!pedited || spot_edited->complexexpose, "Locallab", "Complexexpose_" + index_str, spot.complexexpose, keyFile); + saveToKeyfile(!pedited || spot_edited->expcomp, "Locallab", "Expcomp_" + index_str, spot.expcomp, keyFile); + saveToKeyfile(!pedited || spot_edited->hlcompr, "Locallab", "Hlcompr_" + index_str, spot.hlcompr, keyFile); + saveToKeyfile(!pedited || spot_edited->hlcomprthresh, "Locallab", "Hlcomprthresh_" + index_str, spot.hlcomprthresh, keyFile); + saveToKeyfile(!pedited || spot_edited->black, "Locallab", "Black_" + index_str, spot.black, keyFile); + saveToKeyfile(!pedited || spot_edited->shadex, "Locallab", "Shadex_" + index_str, spot.shadex, keyFile); + saveToKeyfile(!pedited || spot_edited->shcompr, "Locallab", "Shcompr_" + index_str, spot.shcompr, keyFile); + saveToKeyfile(!pedited || spot_edited->expchroma, "Locallab", "Expchroma_" + index_str, spot.expchroma, keyFile); + saveToKeyfile(!pedited || spot_edited->sensiex, "Locallab", "Sensiex_" + index_str, spot.sensiex, keyFile); + saveToKeyfile(!pedited || spot_edited->structexp, "Locallab", "Structexp_" + index_str, spot.structexp, keyFile); + saveToKeyfile(!pedited || spot_edited->blurexpde, "Locallab", "Blurexpde_" + index_str, spot.blurexpde, keyFile); + saveToKeyfile(!pedited || spot_edited->strexp, "Locallab", "Strexp_" + index_str, spot.strexp, keyFile); + saveToKeyfile(!pedited || spot_edited->angexp, "Locallab", "Angexp_" + index_str, spot.angexp, keyFile); + saveToKeyfile(!pedited || spot_edited->excurve, "Locallab", "ExCurve_" + index_str, spot.excurve, keyFile); + saveToKeyfile(!pedited || spot_edited->inversex, "Locallab", "Inversex_" + index_str, spot.inversex, keyFile); + saveToKeyfile(!pedited || spot_edited->enaExpMask, "Locallab", "EnaExpMask_" + index_str, spot.enaExpMask, keyFile); + saveToKeyfile(!pedited || spot_edited->enaExpMaskaft, "Locallab", "EnaExpMaskaft_" + index_str, spot.enaExpMaskaft, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskexpcurve, "Locallab", "CCmaskexpCurve_" + index_str, spot.CCmaskexpcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskexpcurve, "Locallab", "LLmaskexpCurve_" + index_str, spot.LLmaskexpcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskexpcurve, "Locallab", "HHmaskexpCurve_" + index_str, spot.HHmaskexpcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskexp, "Locallab", "Blendmaskexp_" + index_str, spot.blendmaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskexp, "Locallab", "Radmaskexp_" + index_str, spot.radmaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskexp, "Locallab", "Chromaskexp_" + index_str, spot.chromaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskexp, "Locallab", "Gammaskexp_" + index_str, spot.gammaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskexp, "Locallab", "Slomaskexp_" + index_str, spot.slomaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmaskexp, "Locallab", "Lapmaskexp_" + index_str, spot.lapmaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->strmaskexp, "Locallab", "Strmaskexp_" + index_str, spot.strmaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->angmaskexp, "Locallab", "Angmaskexp_" + index_str, spot.angmaskexp, keyFile); + saveToKeyfile(!pedited || spot_edited->softradiusexp, "Locallab", "Softradiusexp_" + index_str, spot.softradiusexp, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmaskexpcurve, "Locallab", "LmaskexpCurve_" + index_str, spot.Lmaskexpcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->expMethod, "Locallab", "ExpMethod_" + index_str, spot.expMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->exnoiseMethod, "Locallab", "ExnoiseMethod_" + index_str, spot.exnoiseMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->laplacexp, "Locallab", "Laplacexp_" + index_str, spot.laplacexp, keyFile); + saveToKeyfile(!pedited || spot_edited->balanexp, "Locallab", "Balanexp_" + index_str, spot.balanexp, keyFile); + saveToKeyfile(!pedited || spot_edited->linear, "Locallab", "Linearexp_" + index_str, spot.linear, keyFile); + saveToKeyfile(!pedited || spot_edited->gamm, "Locallab", "Gamm_" + index_str, spot.gamm, keyFile); + saveToKeyfile(!pedited || spot_edited->fatamount, "Locallab", "Fatamount_" + index_str, spot.fatamount, keyFile); + saveToKeyfile(!pedited || spot_edited->fatdetail, "Locallab", "Fatdetail_" + index_str, spot.fatdetail, keyFile); + saveToKeyfile(!pedited || spot_edited->fatanchor, "Locallab", "Fatanchor_" + index_str, spot.fatanchor, keyFile); + saveToKeyfile(!pedited || spot_edited->fatlevel, "Locallab", "Fatlevel_" + index_str, spot.fatlevel, keyFile); + } + // Shadow highlight + if ((!pedited || spot_edited->visishadhigh) && spot.visishadhigh) { + saveToKeyfile(!pedited || spot_edited->expshadhigh, "Locallab", "Expshadhigh_" + index_str, spot.expshadhigh, keyFile); + saveToKeyfile(!pedited || spot_edited->complexshadhigh, "Locallab", "Complexshadhigh_" + index_str, spot.complexshadhigh, keyFile); + saveToKeyfile(!pedited || spot_edited->shMethod, "Locallab", "ShMethod_" + index_str, spot.shMethod, keyFile); + + for (int j = 0; j < 5; j++) { + saveToKeyfile(!pedited || spot_edited->multsh[j], "Locallab", "Multsh" + std::to_string(j) + "_" + index_str, spot.multsh[j], keyFile); + } + + saveToKeyfile(!pedited || spot_edited->highlights, "Locallab", "highlights_" + index_str, spot.highlights, keyFile); + saveToKeyfile(!pedited || spot_edited->h_tonalwidth, "Locallab", "h_tonalwidth_" + index_str, spot.h_tonalwidth, keyFile); + saveToKeyfile(!pedited || spot_edited->shadows, "Locallab", "shadows_" + index_str, spot.shadows, keyFile); + saveToKeyfile(!pedited || spot_edited->s_tonalwidth, "Locallab", "s_tonalwidth_" + index_str, spot.s_tonalwidth, keyFile); + saveToKeyfile(!pedited || spot_edited->sh_radius, "Locallab", "sh_radius_" + index_str, spot.sh_radius, keyFile); + saveToKeyfile(!pedited || spot_edited->sensihs, "Locallab", "sensihs_" + index_str, spot.sensihs, keyFile); + saveToKeyfile(!pedited || spot_edited->enaSHMask, "Locallab", "EnaSHMask_" + index_str, spot.enaSHMask, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskSHcurve, "Locallab", "CCmaskSHCurve_" + index_str, spot.CCmaskSHcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskSHcurve, "Locallab", "LLmaskSHCurve_" + index_str, spot.LLmaskSHcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskSHcurve, "Locallab", "HHmaskSHCurve_" + index_str, spot.HHmaskSHcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskSH, "Locallab", "BlendmaskSH_" + index_str, spot.blendmaskSH, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskSH, "Locallab", "RadmaskSH_" + index_str, spot.radmaskSH, keyFile); + saveToKeyfile(!pedited || spot_edited->blurSHde, "Locallab", "BlurSHde_" + index_str, spot.blurSHde, keyFile); + saveToKeyfile(!pedited || spot_edited->strSH, "Locallab", "StrSH_" + index_str, spot.strSH, keyFile); + saveToKeyfile(!pedited || spot_edited->angSH, "Locallab", "AngSH_" + index_str, spot.angSH, keyFile); + saveToKeyfile(!pedited || spot_edited->inverssh, "Locallab", "Inverssh_" + index_str, spot.inverssh, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskSH, "Locallab", "ChromaskSH_" + index_str, spot.chromaskSH, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskSH, "Locallab", "GammaskSH_" + index_str, spot.gammaskSH, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskSH, "Locallab", "SlomaskSH_" + index_str, spot.slomaskSH, keyFile); + saveToKeyfile(!pedited || spot_edited->detailSH, "Locallab", "DetailSH_" + index_str, spot.detailSH, keyFile); + saveToKeyfile(!pedited || spot_edited->LmaskSHcurve, "Locallab", "LmaskSHCurve_" + index_str, spot.LmaskSHcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->fatamountSH, "Locallab", "FatamountSH_" + index_str, spot.fatamountSH, keyFile); + saveToKeyfile(!pedited || spot_edited->fatanchorSH, "Locallab", "FatanchorSH_" + index_str, spot.fatanchorSH, keyFile); + saveToKeyfile(!pedited || spot_edited->gamSH, "Locallab", "GamSH_" + index_str, spot.gamSH, keyFile); + saveToKeyfile(!pedited || spot_edited->sloSH, "Locallab", "SloSH_" + index_str, spot.sloSH, keyFile); + } + // Vibrance + if ((!pedited || spot_edited->visivibrance) && spot.visivibrance) { + saveToKeyfile(!pedited || spot_edited->expvibrance, "Locallab", "Expvibrance_" + index_str, spot.expvibrance, keyFile); + saveToKeyfile(!pedited || spot_edited->complexvibrance, "Locallab", "Complexvibrance_" + index_str, spot.complexvibrance, keyFile); + saveToKeyfile(!pedited || spot_edited->saturated, "Locallab", "Saturated_" + index_str, spot.saturated, keyFile); + saveToKeyfile(!pedited || spot_edited->pastels, "Locallab", "Pastels_" + index_str, spot.pastels, keyFile); + saveToKeyfile(!pedited || spot_edited->warm, "Locallab", "Warm_" + index_str, spot.warm, keyFile); + saveToKeyfile(!pedited || spot_edited->psthreshold, "Locallab", "PSThreshold_" + index_str, spot.psthreshold.toVector(), keyFile); + saveToKeyfile(!pedited || spot_edited->protectskins, "Locallab", "ProtectSkins_" + index_str, spot.protectskins, keyFile); + saveToKeyfile(!pedited || spot_edited->avoidcolorshift, "Locallab", "AvoidColorShift_" + index_str, spot.avoidcolorshift, keyFile); + saveToKeyfile(!pedited || spot_edited->pastsattog, "Locallab", "PastSatTog_" + index_str, spot.pastsattog, keyFile); + saveToKeyfile(!pedited || spot_edited->sensiv, "Locallab", "Sensiv_" + index_str, spot.sensiv, keyFile); + saveToKeyfile(!pedited || spot_edited->skintonescurve, "Locallab", "SkinTonesCurve_" + index_str, spot.skintonescurve, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskvibcurve, "Locallab", "CCmaskvibCurve_" + index_str, spot.CCmaskvibcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskvibcurve, "Locallab", "LLmaskvibCurve_" + index_str, spot.LLmaskvibcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskvibcurve, "Locallab", "HHmaskvibCurve_" + index_str, spot.HHmaskvibcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->enavibMask, "Locallab", "EnavibMask_" + index_str, spot.enavibMask, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskvib, "Locallab", "Blendmaskvib_" + index_str, spot.blendmaskvib, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskvib, "Locallab", "Radmaskvib_" + index_str, spot.radmaskvib, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskvib, "Locallab", "Chromaskvib_" + index_str, spot.chromaskvib, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskvib, "Locallab", "Gammaskvib_" + index_str, spot.gammaskvib, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskvib, "Locallab", "Slomaskvib_" + index_str, spot.slomaskvib, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmaskvib, "Locallab", "Lapmaskvib_" + index_str, spot.lapmaskvib, keyFile); + saveToKeyfile(!pedited || spot_edited->strvib, "Locallab", "Strvib_" + index_str, spot.strvib, keyFile); + saveToKeyfile(!pedited || spot_edited->strvibab, "Locallab", "Strvibab_" + index_str, spot.strvibab, keyFile); + saveToKeyfile(!pedited || spot_edited->strvibh, "Locallab", "Strvibh_" + index_str, spot.strvibh, keyFile); + saveToKeyfile(!pedited || spot_edited->angvib, "Locallab", "Angvib_" + index_str, spot.angvib, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmaskvibcurve, "Locallab", "LmaskvibCurve_" + index_str, spot.Lmaskvibcurve, keyFile); + } + // Soft Light + if ((!pedited || spot_edited->visisoft) && spot.visisoft) { + saveToKeyfile(!pedited || spot_edited->expsoft, "Locallab", "Expsoft_" + index_str, spot.expsoft, keyFile); + saveToKeyfile(!pedited || spot_edited->complexsoft, "Locallab", "Complexsoft_" + index_str, spot.complexsoft, keyFile); + saveToKeyfile(!pedited || spot_edited->streng, "Locallab", "Streng_" + index_str, spot.streng, keyFile); + saveToKeyfile(!pedited || spot_edited->sensisf, "Locallab", "Sensisf_" + index_str, spot.sensisf, keyFile); + saveToKeyfile(!pedited || spot_edited->laplace, "Locallab", "Laplace_" + index_str, spot.laplace, keyFile); + saveToKeyfile(!pedited || spot_edited->softMethod, "Locallab", "SoftMethod_" + index_str, spot.softMethod, keyFile); + } + // Blur & Noise + if ((!pedited || spot_edited->visiblur) && spot.visiblur) { + saveToKeyfile(!pedited || spot_edited->expblur, "Locallab", "Expblur_" + index_str, spot.expblur, keyFile); + saveToKeyfile(!pedited || spot_edited->complexblur, "Locallab", "Complexblur_" + index_str, spot.complexblur, keyFile); + saveToKeyfile(!pedited || spot_edited->radius, "Locallab", "Radius_" + index_str, spot.radius, keyFile); + saveToKeyfile(!pedited || spot_edited->strength, "Locallab", "Strength_" + index_str, spot.strength, keyFile); + saveToKeyfile(!pedited || spot_edited->sensibn, "Locallab", "Sensibn_" + index_str, spot.sensibn, keyFile); + saveToKeyfile(!pedited || spot_edited->itera, "Locallab", "Iteramed_" + index_str, spot.itera, keyFile); + saveToKeyfile(!pedited || spot_edited->guidbl, "Locallab", "Guidbl_" + index_str, spot.guidbl, keyFile); + saveToKeyfile(!pedited || spot_edited->strbl, "Locallab", "Strbl_" + index_str, spot.strbl, keyFile); + saveToKeyfile(!pedited || spot_edited->isogr, "Locallab", "Isogr_" + index_str, spot.isogr, keyFile); + saveToKeyfile(!pedited || spot_edited->strengr, "Locallab", "Strengr_" + index_str, spot.strengr, keyFile); + saveToKeyfile(!pedited || spot_edited->scalegr, "Locallab", "Scalegr_" + index_str, spot.scalegr, keyFile); + saveToKeyfile(!pedited || spot_edited->epsbl, "Locallab", "Epsbl_" + index_str, spot.epsbl, keyFile); + saveToKeyfile(!pedited || spot_edited->blMethod, "Locallab", "BlMethod_" + index_str, spot.blMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->chroMethod, "Locallab", "ChroMethod_" + index_str, spot.chroMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->blurMethod, "Locallab", "BlurMethod_" + index_str, spot.blurMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->medMethod, "Locallab", "MedMethod_" + index_str, spot.medMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->activlum, "Locallab", "activlum_" + index_str, spot.activlum, keyFile); + saveToKeyfile(!pedited || spot_edited->noiselumf, "Locallab", "noiselumf_" + index_str, spot.noiselumf, keyFile); + saveToKeyfile(!pedited || spot_edited->noiselumf0, "Locallab", "noiselumf0_" + index_str, spot.noiselumf0, keyFile); + saveToKeyfile(!pedited || spot_edited->noiselumf2, "Locallab", "noiselumf2_" + index_str, spot.noiselumf2, keyFile); + saveToKeyfile(!pedited || spot_edited->noiselumc, "Locallab", "noiselumc_" + index_str, spot.noiselumc, keyFile); + saveToKeyfile(!pedited || spot_edited->noiselumdetail, "Locallab", "noiselumdetail_" + index_str, spot.noiselumdetail, keyFile); + saveToKeyfile(!pedited || spot_edited->noiselequal, "Locallab", "noiselequal_" + index_str, spot.noiselequal, keyFile); + saveToKeyfile(!pedited || spot_edited->noisechrof, "Locallab", "noisechrof_" + index_str, spot.noisechrof, keyFile); + saveToKeyfile(!pedited || spot_edited->noisechroc, "Locallab", "noisechroc_" + index_str, spot.noisechroc, keyFile); + saveToKeyfile(!pedited || spot_edited->noisechrodetail, "Locallab", "noisechrodetail_" + index_str, spot.noisechrodetail, keyFile); + saveToKeyfile(!pedited || spot_edited->adjblur, "Locallab", "Adjblur_" + index_str, spot.adjblur, keyFile); + saveToKeyfile(!pedited || spot_edited->bilateral, "Locallab", "Bilateral_" + index_str, spot.bilateral, keyFile); + saveToKeyfile(!pedited || spot_edited->sensiden, "Locallab", "Sensiden_" + index_str, spot.sensiden, keyFile); + saveToKeyfile(!pedited || spot_edited->detailthr, "Locallab", "Detailthr_" + index_str, spot.detailthr, keyFile); + saveToKeyfile(!pedited || spot_edited->locwavcurveden, "Locallab", "LocwavCurveden_" + index_str, spot.locwavcurveden, keyFile); + saveToKeyfile(!pedited || spot_edited->showmaskblMethodtyp, "Locallab", "Showmasktyp_" + index_str, spot.showmaskblMethodtyp, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskblcurve, "Locallab", "CCmaskblCurve_" + index_str, spot.CCmaskblcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskblcurve, "Locallab", "LLmaskblCurve_" + index_str, spot.LLmaskblcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskblcurve, "Locallab", "HHmaskblCurve_" + index_str, spot.HHmaskblcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->enablMask, "Locallab", "EnablMask_" + index_str, spot.enablMask, keyFile); + saveToKeyfile(!pedited || spot_edited->fftwbl, "Locallab", "Fftwbl_" + index_str, spot.fftwbl, keyFile); + saveToKeyfile(!pedited || spot_edited->toolbl, "Locallab", "Toolbl_" + index_str, spot.toolbl, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskbl, "Locallab", "Blendmaskbl_" + index_str, spot.blendmaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskbl, "Locallab", "Radmaskbl_" + index_str, spot.radmaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskbl, "Locallab", "Chromaskbl_" + index_str, spot.chromaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskbl, "Locallab", "Gammaskbl_" + index_str, spot.gammaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskbl, "Locallab", "Slomaskbl_" + index_str, spot.slomaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmaskbl, "Locallab", "Lapmaskbl_" + index_str, spot.lapmaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->shadmaskbl, "Locallab", "shadmaskbl_" + index_str, spot.shadmaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->shadmaskblsha, "Locallab", "shadmaskblsha_" + index_str, spot.shadmaskblsha, keyFile); + saveToKeyfile(!pedited || spot_edited->strumaskbl, "Locallab", "strumaskbl_" + index_str, spot.strumaskbl, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmaskblcurve, "Locallab", "LmaskblCurve_" + index_str, spot.Lmaskblcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskblcurvewav, "Locallab", "LLmaskblCurvewav_" + index_str, spot.LLmaskblcurvewav, keyFile); + saveToKeyfile(!pedited || spot_edited->csthresholdblur, "Locallab", "CSThresholdblur_" + index_str, spot.csthresholdblur.toVector(), keyFile); + } + // Tone Mapping + if ((!pedited || spot_edited->visitonemap) && spot.visitonemap) { + saveToKeyfile(!pedited || spot_edited->exptonemap, "Locallab", "Exptonemap_" + index_str, spot.exptonemap, keyFile); + saveToKeyfile(!pedited || spot_edited->complextonemap, "Locallab", "Complextonemap_" + index_str, spot.complextonemap, keyFile); + saveToKeyfile(!pedited || spot_edited->stren, "Locallab", "Stren_" + index_str, spot.stren, keyFile); + saveToKeyfile(!pedited || spot_edited->gamma, "Locallab", "Gamma_" + index_str, spot.gamma, keyFile); + saveToKeyfile(!pedited || spot_edited->estop, "Locallab", "Estop_" + index_str, spot.estop, keyFile); + saveToKeyfile(!pedited || spot_edited->scaltm, "Locallab", "Scaltm_" + index_str, spot.scaltm, keyFile); + saveToKeyfile(!pedited || spot_edited->rewei, "Locallab", "Rewei_" + index_str, spot.rewei, keyFile); + saveToKeyfile(!pedited || spot_edited->satur, "Locallab", "Satur_" + index_str, spot.satur, keyFile); + saveToKeyfile(!pedited || spot_edited->sensitm, "Locallab", "Sensitm_" + index_str, spot.sensitm, keyFile); + saveToKeyfile(!pedited || spot_edited->softradiustm, "Locallab", "Softradiustm_" + index_str, spot.softradiustm, keyFile); + saveToKeyfile(!pedited || spot_edited->amount, "Locallab", "Amount_" + index_str, spot.amount, keyFile); + saveToKeyfile(!pedited || spot_edited->equiltm, "Locallab", "Equiltm_" + index_str, spot.equiltm, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmasktmcurve, "Locallab", "CCmasktmCurve_" + index_str, spot.CCmasktmcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmasktmcurve, "Locallab", "LLmasktmCurve_" + index_str, spot.LLmasktmcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmasktmcurve, "Locallab", "HHmasktmCurve_" + index_str, spot.HHmasktmcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->enatmMask, "Locallab", "EnatmMask_" + index_str, spot.enatmMask, keyFile); + saveToKeyfile(!pedited || spot_edited->enatmMaskaft, "Locallab", "EnatmMaskaft_" + index_str, spot.enatmMaskaft, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmasktm, "Locallab", "Blendmasktm_" + index_str, spot.blendmasktm, keyFile); + saveToKeyfile(!pedited || spot_edited->radmasktm, "Locallab", "Radmasktm_" + index_str, spot.radmasktm, keyFile); + saveToKeyfile(!pedited || spot_edited->chromasktm, "Locallab", "Chromasktm_" + index_str, spot.chromasktm, keyFile); + saveToKeyfile(!pedited || spot_edited->gammasktm, "Locallab", "Gammasktm_" + index_str, spot.gammasktm, keyFile); + saveToKeyfile(!pedited || spot_edited->slomasktm, "Locallab", "Slomasktm_" + index_str, spot.slomasktm, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmasktm, "Locallab", "Lapmasktm_" + index_str, spot.lapmasktm, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmasktmcurve, "Locallab", "LmasktmCurve_" + index_str, spot.Lmasktmcurve, keyFile); + } + // Retinex + if ((!pedited || spot_edited->visireti) && spot.visireti) { + saveToKeyfile(!pedited || spot_edited->expreti, "Locallab", "Expreti_" + index_str, spot.expreti, keyFile); + saveToKeyfile(!pedited || spot_edited->complexreti, "Locallab", "Complexreti_" + index_str, spot.complexreti, keyFile); + saveToKeyfile(!pedited || spot_edited->retinexMethod, "Locallab", "retinexMethod_" + index_str, spot.retinexMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->str, "Locallab", "Str_" + index_str, spot.str, keyFile); + saveToKeyfile(!pedited || spot_edited->chrrt, "Locallab", "Chrrt_" + index_str, spot.chrrt, keyFile); + saveToKeyfile(!pedited || spot_edited->neigh, "Locallab", "Neigh_" + index_str, spot.neigh, keyFile); + saveToKeyfile(!pedited || spot_edited->vart, "Locallab", "Vart_" + index_str, spot.vart, keyFile); + saveToKeyfile(!pedited || spot_edited->offs, "Locallab", "Offs_" + index_str, spot.offs, keyFile); + saveToKeyfile(!pedited || spot_edited->dehaz, "Locallab", "Dehaz_" + index_str, spot.dehaz, keyFile); + saveToKeyfile(!pedited || spot_edited->depth, "Locallab", "Depth_" + index_str, spot.depth, keyFile); + saveToKeyfile(!pedited || spot_edited->sensih, "Locallab", "Sensih_" + index_str, spot.sensih, keyFile); + saveToKeyfile(!pedited || spot_edited->localTgaincurve, "Locallab", "TgainCurve_" + index_str, spot.localTgaincurve, keyFile); + saveToKeyfile(!pedited || spot_edited->localTtranscurve, "Locallab", "TtransCurve_" + index_str, spot.localTtranscurve, keyFile); + saveToKeyfile(!pedited || spot_edited->inversret, "Locallab", "Inversret_" + index_str, spot.inversret, keyFile); + saveToKeyfile(!pedited || spot_edited->equilret, "Locallab", "Equilret_" + index_str, spot.equilret, keyFile); + saveToKeyfile(!pedited || spot_edited->loglin, "Locallab", "Loglin_" + index_str, spot.loglin, keyFile); + saveToKeyfile(!pedited || spot_edited->lumonly, "Locallab", "Lumonly_" + index_str, spot.lumonly, keyFile); + saveToKeyfile(!pedited || spot_edited->softradiusret, "Locallab", "Softradiusret_" + index_str, spot.softradiusret, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskreticurve, "Locallab", "CCmaskretiCurve_" + index_str, spot.CCmaskreticurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskreticurve, "Locallab", "LLmaskretiCurve_" + index_str, spot.LLmaskreticurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskreticurve, "Locallab", "HHmaskretiCurve_" + index_str, spot.HHmaskreticurve, keyFile); + saveToKeyfile(!pedited || spot_edited->enaretiMask, "Locallab", "EnaretiMask_" + index_str, spot.enaretiMask, keyFile); + saveToKeyfile(!pedited || spot_edited->enaretiMasktmap, "Locallab", "EnaretiMasktmap_" + index_str, spot.enaretiMasktmap, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskreti, "Locallab", "Blendmaskreti_" + index_str, spot.blendmaskreti, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskreti, "Locallab", "Radmaskreti_" + index_str, spot.radmaskreti, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskreti, "Locallab", "Chromaskreti_" + index_str, spot.chromaskreti, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskreti, "Locallab", "Gammaskreti_" + index_str, spot.gammaskreti, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskreti, "Locallab", "Slomaskreti_" + index_str, spot.slomaskreti, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmaskreti, "Locallab", "Lapmaskreti_" + index_str, spot.lapmaskreti, keyFile); + saveToKeyfile(!pedited || spot_edited->scalereti, "Locallab", "Scalereti_" + index_str, spot.scalereti, keyFile); + saveToKeyfile(!pedited || spot_edited->darkness, "Locallab", "Darkness_" + index_str, spot.darkness, keyFile); + saveToKeyfile(!pedited || spot_edited->lightnessreti, "Locallab", "Lightnessreti_" + index_str, spot.lightnessreti, keyFile); + saveToKeyfile(!pedited || spot_edited->limd, "Locallab", "Limd_" + index_str, spot.limd, keyFile); + saveToKeyfile(!pedited || spot_edited->cliptm, "Locallab", "Cliptm_" + index_str, spot.cliptm, keyFile); + saveToKeyfile(!pedited || spot_edited->fftwreti, "Locallab", "Fftwreti_" + index_str, spot.fftwreti, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmaskreticurve, "Locallab", "LmaskretiCurve_" + index_str, spot.Lmaskreticurve, keyFile); + } + // Sharpening + if ((!pedited || spot_edited->visisharp) && spot.visisharp) { + saveToKeyfile(!pedited || spot_edited->expsharp, "Locallab", "Expsharp_" + index_str, spot.expsharp, keyFile); + saveToKeyfile(!pedited || spot_edited->complexsharp, "Locallab", "Complexsharp_" + index_str, spot.complexsharp, keyFile); + saveToKeyfile(!pedited || spot_edited->sharcontrast, "Locallab", "Sharcontrast_" + index_str, spot.sharcontrast, keyFile); + saveToKeyfile(!pedited || spot_edited->sharradius, "Locallab", "Sharradius_" + index_str, spot.sharradius, keyFile); + saveToKeyfile(!pedited || spot_edited->sharamount, "Locallab", "Sharamount_" + index_str, spot.sharamount, keyFile); + saveToKeyfile(!pedited || spot_edited->shardamping, "Locallab", "Shardamping_" + index_str, spot.shardamping, keyFile); + saveToKeyfile(!pedited || spot_edited->shariter, "Locallab", "Shariter_" + index_str, spot.shariter, keyFile); + saveToKeyfile(!pedited || spot_edited->sharblur, "Locallab", "Sharblur_" + index_str, spot.sharblur, keyFile); + saveToKeyfile(!pedited || spot_edited->sensisha, "Locallab", "Sensisha_" + index_str, spot.sensisha, keyFile); + saveToKeyfile(!pedited || spot_edited->inverssha, "Locallab", "Inverssha_" + index_str, spot.inverssha, keyFile); + } + // Local Contrast + if ((!pedited || spot_edited->visicontrast) && spot.visicontrast) { + saveToKeyfile(!pedited || spot_edited->expcontrast, "Locallab", "Expcontrast_" + index_str, spot.expcontrast, keyFile); + saveToKeyfile(!pedited || spot_edited->complexcontrast, "Locallab", "Complexcontrast_" + index_str, spot.complexcontrast, keyFile); + saveToKeyfile(!pedited || spot_edited->lcradius, "Locallab", "Lcradius_" + index_str, spot.lcradius, keyFile); + saveToKeyfile(!pedited || spot_edited->lcamount, "Locallab", "Lcamount_" + index_str, spot.lcamount, keyFile); + saveToKeyfile(!pedited || spot_edited->lcdarkness, "Locallab", "Lcdarkness_" + index_str, spot.lcdarkness, keyFile); + saveToKeyfile(!pedited || spot_edited->lclightness, "Locallab", "Lclightness_" + index_str, spot.lclightness, keyFile); + saveToKeyfile(!pedited || spot_edited->sigmalc, "Locallab", "Sigmalc_" + index_str, spot.sigmalc, keyFile); + saveToKeyfile(!pedited || spot_edited->levelwav, "Locallab", "Levelwav_" + index_str, spot.levelwav, keyFile); + saveToKeyfile(!pedited || spot_edited->residcont, "Locallab", "Residcont_" + index_str, spot.residcont, keyFile); + saveToKeyfile(!pedited || spot_edited->residsha, "Locallab", "Residsha_" + index_str, spot.residsha, keyFile); + saveToKeyfile(!pedited || spot_edited->residshathr, "Locallab", "Residshathr_" + index_str, spot.residshathr, keyFile); + saveToKeyfile(!pedited || spot_edited->residhi, "Locallab", "Residhi_" + index_str, spot.residhi, keyFile); + saveToKeyfile(!pedited || spot_edited->residhithr, "Locallab", "Residhithr_" + index_str, spot.residhithr, keyFile); + saveToKeyfile(!pedited || spot_edited->residblur, "Locallab", "Residblur_" + index_str, spot.residblur, keyFile); + saveToKeyfile(!pedited || spot_edited->levelblur, "Locallab", "Levelblur_" + index_str, spot.levelblur, keyFile); + saveToKeyfile(!pedited || spot_edited->sigmabl, "Locallab", "Sigmabl_" + index_str, spot.sigmabl, keyFile); + saveToKeyfile(!pedited || spot_edited->residchro, "Locallab", "Residchro_" + index_str, spot.residchro, keyFile); + saveToKeyfile(!pedited || spot_edited->residcomp, "Locallab", "Residcomp_" + index_str, spot.residcomp, keyFile); + saveToKeyfile(!pedited || spot_edited->sigma, "Locallab", "Sigma_" + index_str, spot.sigma, keyFile); + saveToKeyfile(!pedited || spot_edited->offset, "Locallab", "Offset_" + index_str, spot.offset, keyFile); + saveToKeyfile(!pedited || spot_edited->sigmadr, "Locallab", "Sigmadr_" + index_str, spot.sigmadr, keyFile); + saveToKeyfile(!pedited || spot_edited->threswav, "Locallab", "Threswav_" + index_str, spot.threswav, keyFile); + saveToKeyfile(!pedited || spot_edited->chromalev, "Locallab", "Chromalev_" + index_str, spot.chromalev, keyFile); + saveToKeyfile(!pedited || spot_edited->chromablu, "Locallab", "Chromablu_" + index_str, spot.chromablu, keyFile); + saveToKeyfile(!pedited || spot_edited->sigmadc, "Locallab", "sigmadc_" + index_str, spot.sigmadc, keyFile); + saveToKeyfile(!pedited || spot_edited->deltad, "Locallab", "deltad_" + index_str, spot.deltad, keyFile); + saveToKeyfile(!pedited || spot_edited->fatres, "Locallab", "Fatres_" + index_str, spot.fatres, keyFile); + saveToKeyfile(!pedited || spot_edited->clarilres, "Locallab", "ClariLres_" + index_str, spot.clarilres, keyFile); + saveToKeyfile(!pedited || spot_edited->claricres, "Locallab", "ClariCres_" + index_str, spot.claricres, keyFile); + saveToKeyfile(!pedited || spot_edited->clarisoft, "Locallab", "Clarisoft_" + index_str, spot.clarisoft, keyFile); + saveToKeyfile(!pedited || spot_edited->sigmalc2, "Locallab", "Sigmalc2_" + index_str, spot.sigmalc2, keyFile); + saveToKeyfile(!pedited || spot_edited->strwav, "Locallab", "Strwav_" + index_str, spot.strwav, keyFile); + saveToKeyfile(!pedited || spot_edited->angwav, "Locallab", "Angwav_" + index_str, spot.angwav, keyFile); + saveToKeyfile(!pedited || spot_edited->strengthw, "Locallab", "Strengthw_" + index_str, spot.strengthw, keyFile); + saveToKeyfile(!pedited || spot_edited->sigmaed, "Locallab", "Sigmaed_" + index_str, spot.sigmaed, keyFile); + saveToKeyfile(!pedited || spot_edited->radiusw, "Locallab", "Radiusw_" + index_str, spot.radiusw, keyFile); + saveToKeyfile(!pedited || spot_edited->detailw, "Locallab", "Detailw_" + index_str, spot.detailw, keyFile); + saveToKeyfile(!pedited || spot_edited->gradw, "Locallab", "Gradw_" + index_str, spot.gradw, keyFile); + saveToKeyfile(!pedited || spot_edited->tloww, "Locallab", "Tloww_" + index_str, spot.tloww, keyFile); + saveToKeyfile(!pedited || spot_edited->thigw, "Locallab", "Thigw_" + index_str, spot.thigw, keyFile); + saveToKeyfile(!pedited || spot_edited->edgw, "Locallab", "Edgw_" + index_str, spot.edgw, keyFile); + saveToKeyfile(!pedited || spot_edited->basew, "Locallab", "Basew_" + index_str, spot.basew, keyFile); + saveToKeyfile(!pedited || spot_edited->sensilc, "Locallab", "Sensilc_" + index_str, spot.sensilc, keyFile); + saveToKeyfile(!pedited || spot_edited->fftwlc, "Locallab", "Fftwlc_" + index_str, spot.fftwlc, keyFile); + saveToKeyfile(!pedited || spot_edited->blurlc, "Locallab", "Blurlc_" + index_str, spot.blurlc, keyFile); + saveToKeyfile(!pedited || spot_edited->wavblur, "Locallab", "Wavblur_" + index_str, spot.wavblur, keyFile); + saveToKeyfile(!pedited || spot_edited->wavedg, "Locallab", "Wavedg_" + index_str, spot.wavedg, keyFile); + saveToKeyfile(!pedited || spot_edited->waveshow, "Locallab", "Waveshow_" + index_str, spot.waveshow, keyFile); + saveToKeyfile(!pedited || spot_edited->wavcont, "Locallab", "Wavcont_" + index_str, spot.wavcont, keyFile); + saveToKeyfile(!pedited || spot_edited->wavcomp, "Locallab", "Wavcomp_" + index_str, spot.wavcomp, keyFile); + saveToKeyfile(!pedited || spot_edited->wavgradl, "Locallab", "Wavgradl_" + index_str, spot.wavgradl, keyFile); + saveToKeyfile(!pedited || spot_edited->wavcompre, "Locallab", "Wavcompre_" + index_str, spot.wavcompre, keyFile); + saveToKeyfile(!pedited || spot_edited->origlc, "Locallab", "Origlc_" + index_str, spot.origlc, keyFile); + saveToKeyfile(!pedited || spot_edited->localcontMethod, "Locallab", "localcontMethod_" + index_str, spot.localcontMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->localedgMethod, "Locallab", "localedgMethod_" + index_str, spot.localedgMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->localneiMethod, "Locallab", "localneiMethod_" + index_str, spot.localneiMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->locwavcurve, "Locallab", "LocwavCurve_" + index_str, spot.locwavcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->csthreshold, "Locallab", "CSThreshold_" + index_str, spot.csthreshold.toVector(), keyFile); + saveToKeyfile(!pedited || spot_edited->loclevwavcurve, "Locallab", "LoclevwavCurve_" + index_str, spot.loclevwavcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->locconwavcurve, "Locallab", "LocconwavCurve_" + index_str, spot.locconwavcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->loccompwavcurve, "Locallab", "LoccompwavCurve_" + index_str, spot.loccompwavcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->loccomprewavcurve, "Locallab", "LoccomprewavCurve_" + index_str, spot.loccomprewavcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->locedgwavcurve, "Locallab", "LocedgwavCurve_" + index_str, spot.locedgwavcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmasklccurve, "Locallab", "CCmasklcCurve_" + index_str, spot.CCmasklccurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmasklccurve, "Locallab", "LLmasklcCurve_" + index_str, spot.LLmasklccurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmasklccurve, "Locallab", "HHmasklcCurve_" + index_str, spot.HHmasklccurve, keyFile); + saveToKeyfile(!pedited || spot_edited->enalcMask, "Locallab", "EnalcMask_" + index_str, spot.enalcMask, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmasklc, "Locallab", "Blendmasklc_" + index_str, spot.blendmasklc, keyFile); + saveToKeyfile(!pedited || spot_edited->radmasklc, "Locallab", "Radmasklc_" + index_str, spot.radmasklc, keyFile); + saveToKeyfile(!pedited || spot_edited->chromasklc, "Locallab", "Chromasklc_" + index_str, spot.chromasklc, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmasklccurve, "Locallab", "LmasklcCurve_" + index_str, spot.Lmasklccurve, keyFile); + } + // Contrast by detail levels + if ((!pedited || spot_edited->visicbdl) && spot.visicbdl) { + saveToKeyfile(!pedited || spot_edited->expcbdl, "Locallab", "Expcbdl_" + index_str, spot.expcbdl, keyFile); + saveToKeyfile(!pedited || spot_edited->complexcbdl, "Locallab", "Complexcbdl_" + index_str, spot.complexcbdl, keyFile); + + for (int j = 0; j < 6; j++) { + saveToKeyfile(!pedited || spot_edited->mult[j], "Locallab", "Mult" + std::to_string(j) + "_" + index_str, spot.mult[j], keyFile); + } + + saveToKeyfile(!pedited || spot_edited->chromacbdl, "Locallab", "Chromacbdl_" + index_str, spot.chromacbdl, keyFile); + saveToKeyfile(!pedited || spot_edited->threshold, "Locallab", "Threshold_" + index_str, spot.threshold, keyFile); + saveToKeyfile(!pedited || spot_edited->sensicb, "Locallab", "Sensicb_" + index_str, spot.sensicb, keyFile); + saveToKeyfile(!pedited || spot_edited->clarityml, "Locallab", "Clarityml_" + index_str, spot.clarityml, keyFile); + saveToKeyfile(!pedited || spot_edited->contresid, "Locallab", "Contresid_" + index_str, spot.contresid, keyFile); + saveToKeyfile(!pedited || spot_edited->blurcbdl, "Locallab", "Blurcbdl_" + index_str, spot.blurcbdl, keyFile); + saveToKeyfile(!pedited || spot_edited->softradiuscb, "Locallab", "Softradiuscb_" + index_str, spot.softradiuscb, keyFile); + saveToKeyfile(!pedited || spot_edited->enacbMask, "Locallab", "EnacbMask_" + index_str, spot.enacbMask, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmaskcbcurve, "Locallab", "CCmaskcbCurve_" + index_str, spot.CCmaskcbcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskcbcurve, "Locallab", "LLmaskcbCurve_" + index_str, spot.LLmaskcbcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskcbcurve, "Locallab", "HHmaskcbCurve_" + index_str, spot.HHmaskcbcurve, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskcb, "Locallab", "Blendmaskcb_" + index_str, spot.blendmaskcb, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskcb, "Locallab", "Radmaskcb_" + index_str, spot.radmaskcb, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskcb, "Locallab", "Chromaskcb_" + index_str, spot.chromaskcb, keyFile); + saveToKeyfile(!pedited || spot_edited->gammaskcb, "Locallab", "Gammaskcb_" + index_str, spot.gammaskcb, keyFile); + saveToKeyfile(!pedited || spot_edited->slomaskcb, "Locallab", "Slomaskcb_" + index_str, spot.slomaskcb, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmaskcb, "Locallab", "Lapmaskcb_" + index_str, spot.lapmaskcb, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmaskcbcurve, "Locallab", "LmaskcbCurve_" + index_str, spot.Lmaskcbcurve, keyFile); + } + // Log encoding + if ((!pedited || spot_edited->visilog) && spot.visilog) { + saveToKeyfile(!pedited || spot_edited->explog, "Locallab", "Explog_" + index_str, spot.explog, keyFile); + saveToKeyfile(!pedited || spot_edited->autocompute, "Locallab", "Autocompute_" + index_str, spot.autocompute, keyFile); + saveToKeyfile(!pedited || spot_edited->sourceGray, "Locallab", "SourceGray_" + index_str, spot.sourceGray, keyFile); + saveToKeyfile(!pedited || spot_edited->targetGray, "Locallab", "TargetGray_" + index_str, spot.targetGray, keyFile); + saveToKeyfile(!pedited || spot_edited->Autogray, "Locallab", "Autogray_" + index_str, spot.Autogray, keyFile); + saveToKeyfile(!pedited || spot_edited->fullimage, "Locallab", "Fullimage_" + index_str, spot.fullimage, keyFile); + saveToKeyfile(!pedited || spot_edited->blackEv, "Locallab", "BlackEv_" + index_str, spot.blackEv, keyFile); + saveToKeyfile(!pedited || spot_edited->whiteEv, "Locallab", "WhiteEv_" + index_str, spot.whiteEv, keyFile); + saveToKeyfile(!pedited || spot_edited->detail, "Locallab", "Detail_" + index_str, spot.detail, keyFile); + saveToKeyfile(!pedited || spot_edited->sensilog, "Locallab", "Sensilog_" + index_str, spot.sensilog, keyFile); + saveToKeyfile(!pedited || spot_edited->baselog, "Locallab", "Baselog_" + index_str, spot.baselog, keyFile); + saveToKeyfile(!pedited || spot_edited->strlog, "Locallab", "Strlog_" + index_str, spot.strlog, keyFile); + saveToKeyfile(!pedited || spot_edited->anglog, "Locallab", "Anglog_" + index_str, spot.anglog, keyFile); + } + } + } + // Post-crop vignette saveToKeyfile(!pedited || pedited->pcvignette.enabled, "PCVignette", "Enabled", pcvignette.enabled, keyFile); saveToKeyfile(!pedited || pedited->pcvignette.strength, "PCVignette", "Strength", pcvignette.strength, keyFile); @@ -3562,6 +5787,12 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.enabled, "Wavelet", "Enabled", wavelet.enabled, keyFile); saveToKeyfile(!pedited || pedited->wavelet.strength, "Wavelet", "Strength", wavelet.strength, keyFile); saveToKeyfile(!pedited || pedited->wavelet.balance, "Wavelet", "Balance", wavelet.balance, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.sigmafin, "Wavelet", "Sigmafin", wavelet.sigmafin, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.sigmaton, "Wavelet", "Sigmaton", wavelet.sigmaton, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.sigmacol, "Wavelet", "Sigmacol", wavelet.sigmacol, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.sigmadir, "Wavelet", "Sigmadir", wavelet.sigmadir, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.rangeab, "Wavelet", "Rangeab", wavelet.rangeab, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.protab, "Wavelet", "Protab", wavelet.protab, keyFile); saveToKeyfile(!pedited || pedited->wavelet.iter, "Wavelet", "Iter", wavelet.iter, keyFile); saveToKeyfile(!pedited || pedited->wavelet.thres, "Wavelet", "MaxLev", wavelet.thres, keyFile); saveToKeyfile(!pedited || pedited->wavelet.Tilesmethod, "Wavelet", "TilesMethod", wavelet.Tilesmethod, keyFile); @@ -3593,6 +5824,10 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.exptoning, "Wavelet", "Exptoning", wavelet.exptoning, keyFile); saveToKeyfile(!pedited || pedited->wavelet.expnoise, "Wavelet", "Expnoise", wavelet.expnoise, keyFile); saveToKeyfile(!pedited || pedited->wavelet.expclari, "Wavelet", "Expclari", wavelet.expclari, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.labgridALow, "Wavelet", "LabGridALow", wavelet.labgridALow, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.labgridBLow, "Wavelet", "LabGridBLow", wavelet.labgridBLow, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.labgridAHigh, "Wavelet", "LabGridAHigh", wavelet.labgridAHigh, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.labgridBHigh, "Wavelet", "LabGridBHigh", wavelet.labgridBHigh, keyFile); for (int i = 0; i < 9; i++) { std::stringstream ss; @@ -3639,6 +5874,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.pastlev, "Wavelet", "Pastlev", wavelet.pastlev.toVector(), keyFile); saveToKeyfile(!pedited || pedited->wavelet.satlev, "Wavelet", "Satlev", wavelet.satlev.toVector(), keyFile); saveToKeyfile(!pedited || pedited->wavelet.opacityCurveRG, "Wavelet", "OpacityCurveRG", wavelet.opacityCurveRG, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.opacityCurveSH, "Wavelet", "Levalshc", wavelet.opacityCurveSH, keyFile); saveToKeyfile(!pedited || pedited->wavelet.opacityCurveBY, "Wavelet", "OpacityCurveBY", wavelet.opacityCurveBY, keyFile); saveToKeyfile(!pedited || pedited->wavelet.opacityCurveW, "Wavelet", "OpacityCurveW", wavelet.opacityCurveW, keyFile); saveToKeyfile(!pedited || pedited->wavelet.opacityCurveWL, "Wavelet", "OpacityCurveWL", wavelet.opacityCurveWL, keyFile); @@ -3841,6 +6077,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->filmNegative.baseValues, "Film Negative", "GreenBase", filmNegative.greenBase, keyFile); saveToKeyfile(!pedited || pedited->filmNegative.baseValues, "Film Negative", "BlueBase", filmNegative.blueBase, keyFile); +// Preprocess WB + saveToKeyfile(!pedited || pedited->raw.preprocessWB.mode, "RAW Preprocess WB", "Mode", toUnderlying(raw.preprocessWB.mode), keyFile); + // EXIF change list if (!pedited || pedited->exif) { for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); ++i) { @@ -4177,14 +6416,17 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Sharpening")) { assignFromKeyfile(keyFile, "Sharpening", "Enabled", pedited, sharpening.enabled, pedited->sharpening.enabled); + if (ppVersion >= 334) { assignFromKeyfile(keyFile, "Sharpening", "Contrast", pedited, sharpening.contrast, pedited->sharpening.contrast); } else { sharpening.contrast = 0; + if (pedited) { pedited->sharpening.contrast = true; } } + assignFromKeyfile(keyFile, "Sharpening", "Radius", pedited, sharpening.radius, pedited->sharpening.radius); assignFromKeyfile(keyFile, "Sharpening", "BlurRadius", pedited, sharpening.blurradius, pedited->sharpening.blurradius); assignFromKeyfile(keyFile, "Sharpening", "Amount", pedited, sharpening.amount, pedited->sharpening.amount); @@ -4229,10 +6471,12 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "SharpenMicro", "Enabled", pedited, sharpenMicro.enabled, pedited->sharpenMicro.enabled); assignFromKeyfile(keyFile, "SharpenMicro", "Matrix", pedited, sharpenMicro.matrix, pedited->sharpenMicro.matrix); assignFromKeyfile(keyFile, "SharpenMicro", "Strength", pedited, sharpenMicro.amount, pedited->sharpenMicro.amount); + if (ppVersion >= 334) { assignFromKeyfile(keyFile, "SharpenMicro", "Contrast", pedited, sharpenMicro.contrast, pedited->sharpenMicro.contrast); } else { sharpenMicro.contrast = 0; + if (pedited) { pedited->sharpenMicro.contrast = true; } @@ -4429,7 +6673,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "FattalToneMapping", "Anchor", pedited, fattal.anchor, pedited->fattal.anchor); } - if (keyFile.has_group ("Shadows & Highlights") && ppVersion >= 333) { + if (keyFile.has_group("Shadows & Highlights") && ppVersion >= 333) { assignFromKeyfile(keyFile, "Shadows & Highlights", "Enabled", pedited, sh.enabled, pedited->sh.enabled); assignFromKeyfile(keyFile, "Shadows & Highlights", "Highlights", pedited, sh.highlights, pedited->sh.highlights); assignFromKeyfile(keyFile, "Shadows & Highlights", "HighlightTonalWidth", pedited, sh.htonalwidth, pedited->sh.htonalwidth); @@ -4606,6 +6850,580 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Gradient", "CenterY", pedited, gradient.centerY, pedited->gradient.centerY); } + if (keyFile.has_group("Locallab")) { + assignFromKeyfile(keyFile, "Locallab", "Enabled", pedited, locallab.enabled, pedited->locallab.enabled); + assignFromKeyfile(keyFile, "Locallab", "Selspot", pedited, locallab.selspot, pedited->locallab.selspot); + + Glib::ustring ppName; + bool peName; + int i = 0; + + while (assignFromKeyfile(keyFile, "Locallab", "Name_" + std::to_string(i), pedited, ppName, peName)) { + const std::string index_str = std::to_string(i); + + // Create new LocallabSpot and LocallabParamsEdited + LocallabParams::LocallabSpot spot; + spot.name = ppName; + LocallabParamsEdited::LocallabSpotEdited spotEdited(false); + spotEdited.name = peName; + + // Control spot settings + assignFromKeyfile(keyFile, "Locallab", "Isvisible_" + index_str, pedited, spot.isvisible, spotEdited.isvisible); + assignFromKeyfile(keyFile, "Locallab", "Shape_" + index_str, pedited, spot.shape, spotEdited.shape); + assignFromKeyfile(keyFile, "Locallab", "SpotMethod_" + index_str, pedited, spot.spotMethod, spotEdited.spotMethod); + assignFromKeyfile(keyFile, "Locallab", "wavMethod_" + index_str, pedited, spot.wavMethod, spotEdited.wavMethod); + assignFromKeyfile(keyFile, "Locallab", "SensiExclu_" + index_str, pedited, spot.sensiexclu, spotEdited.sensiexclu); + assignFromKeyfile(keyFile, "Locallab", "StructExclu_" + index_str, pedited, spot.structexclu, spotEdited.structexclu); + assignFromKeyfile(keyFile, "Locallab", "Struc_" + index_str, pedited, spot.struc, spotEdited.struc); + assignFromKeyfile(keyFile, "Locallab", "ShapeMethod_" + index_str, pedited, spot.shapeMethod, spotEdited.shapeMethod); + assignFromKeyfile(keyFile, "Locallab", "Loc_" + index_str, pedited, spot.loc, spotEdited.loc); + assignFromKeyfile(keyFile, "Locallab", "CenterX_" + index_str, pedited, spot.centerX, spotEdited.centerX); + assignFromKeyfile(keyFile, "Locallab", "CenterY_" + index_str, pedited, spot.centerY, spotEdited.centerY); + assignFromKeyfile(keyFile, "Locallab", "Circrad_" + index_str, pedited, spot.circrad, spotEdited.circrad); + assignFromKeyfile(keyFile, "Locallab", "QualityMethod_" + index_str, pedited, spot.qualityMethod, spotEdited.qualityMethod); + assignFromKeyfile(keyFile, "Locallab", "ComplexMethod_" + index_str, pedited, spot.complexMethod, spotEdited.complexMethod); + assignFromKeyfile(keyFile, "Locallab", "Transit_" + index_str, pedited, spot.transit, spotEdited.transit); + assignFromKeyfile(keyFile, "Locallab", "Feather_" + index_str, pedited, spot.feather, spotEdited.feather); + assignFromKeyfile(keyFile, "Locallab", "Thresh_" + index_str, pedited, spot.thresh, spotEdited.thresh); + assignFromKeyfile(keyFile, "Locallab", "Iter_" + index_str, pedited, spot.iter, spotEdited.iter); + assignFromKeyfile(keyFile, "Locallab", "Balan_" + index_str, pedited, spot.balan, spotEdited.balan); + assignFromKeyfile(keyFile, "Locallab", "Balanh_" + index_str, pedited, spot.balanh, spotEdited.balanh); + assignFromKeyfile(keyFile, "Locallab", "Colorde_" + index_str, pedited, spot.colorde, spotEdited.colorde); + assignFromKeyfile(keyFile, "Locallab", "Colorscope_" + index_str, pedited, spot.colorscope, spotEdited.colorscope); + assignFromKeyfile(keyFile, "Locallab", "Transitweak_" + index_str, pedited, spot.transitweak, spotEdited.transitweak); + assignFromKeyfile(keyFile, "Locallab", "Transitgrad_" + index_str, pedited, spot.transitgrad, spotEdited.transitgrad); + assignFromKeyfile(keyFile, "Locallab", "Avoid_" + index_str, pedited, spot.avoid, spotEdited.avoid); + assignFromKeyfile(keyFile, "Locallab", "Blwh_" + index_str, pedited, spot.blwh, spotEdited.blwh); + assignFromKeyfile(keyFile, "Locallab", "Recurs_" + index_str, pedited, spot.recurs, spotEdited.recurs); + assignFromKeyfile(keyFile, "Locallab", "Laplac_" + index_str, pedited, spot.laplac, spotEdited.laplac); + assignFromKeyfile(keyFile, "Locallab", "Deltae_" + index_str, pedited, spot.deltae, spotEdited.deltae); + assignFromKeyfile(keyFile, "Locallab", "Shortc_" + index_str, pedited, spot.shortc, spotEdited.shortc); + assignFromKeyfile(keyFile, "Locallab", "Savrest_" + index_str, pedited, spot.savrest, spotEdited.savrest); + assignFromKeyfile(keyFile, "Locallab", "Scopemask_" + index_str, pedited, spot.scopemask, spotEdited.scopemask); + assignFromKeyfile(keyFile, "Locallab", "Lumask_" + index_str, pedited, spot.lumask, spotEdited.lumask); + // Color & Light + spot.visicolor = assignFromKeyfile(keyFile, "Locallab", "Expcolor_" + index_str, pedited, spot.expcolor, spotEdited.expcolor); + + if (spot.visicolor) { + spotEdited.visicolor = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexcolor_" + index_str, pedited, spot.complexcolor, spotEdited.complexcolor); + assignFromKeyfile(keyFile, "Locallab", "Curvactiv_" + index_str, pedited, spot.curvactiv, spotEdited.curvactiv); + assignFromKeyfile(keyFile, "Locallab", "Lightness_" + index_str, pedited, spot.lightness, spotEdited.lightness); + assignFromKeyfile(keyFile, "Locallab", "Contrast_" + index_str, pedited, spot.contrast, spotEdited.contrast); + assignFromKeyfile(keyFile, "Locallab", "Chroma_" + index_str, pedited, spot.chroma, spotEdited.chroma); + assignFromKeyfile(keyFile, "Locallab", "labgridALow_" + index_str, pedited, spot.labgridALow, spotEdited.labgridALow); + assignFromKeyfile(keyFile, "Locallab", "labgridBLow_" + index_str, pedited, spot.labgridBLow, spotEdited.labgridBLow); + assignFromKeyfile(keyFile, "Locallab", "labgridAHigh_" + index_str, pedited, spot.labgridAHigh, spotEdited.labgridAHigh); + assignFromKeyfile(keyFile, "Locallab", "labgridBHigh_" + index_str, pedited, spot.labgridBHigh, spotEdited.labgridBHigh); + assignFromKeyfile(keyFile, "Locallab", "labgridALowmerg_" + index_str, pedited, spot.labgridALowmerg, spotEdited.labgridALowmerg); + assignFromKeyfile(keyFile, "Locallab", "labgridBLowmerg_" + index_str, pedited, spot.labgridBLowmerg, spotEdited.labgridBLowmerg); + assignFromKeyfile(keyFile, "Locallab", "labgridAHighmerg_" + index_str, pedited, spot.labgridAHighmerg, spotEdited.labgridAHighmerg); + assignFromKeyfile(keyFile, "Locallab", "labgridBHighmerg_" + index_str, pedited, spot.labgridBHighmerg, spotEdited.labgridBHighmerg); + assignFromKeyfile(keyFile, "Locallab", "Strengthgrid_" + index_str, pedited, spot.strengthgrid, spotEdited.strengthgrid); + assignFromKeyfile(keyFile, "Locallab", "Sensi_" + index_str, pedited, spot.sensi, spotEdited.sensi); + assignFromKeyfile(keyFile, "Locallab", "Structcol_" + index_str, pedited, spot.structcol, spotEdited.structcol); + assignFromKeyfile(keyFile, "Locallab", "Strcol_" + index_str, pedited, spot.strcol, spotEdited.strcol); + assignFromKeyfile(keyFile, "Locallab", "Strcolab_" + index_str, pedited, spot.strcolab, spotEdited.strcolab); + assignFromKeyfile(keyFile, "Locallab", "Strcolh_" + index_str, pedited, spot.strcolh, spotEdited.strcolh); + assignFromKeyfile(keyFile, "Locallab", "Angcol_" + index_str, pedited, spot.angcol, spotEdited.angcol); + assignFromKeyfile(keyFile, "Locallab", "Blurcolde_" + index_str, pedited, spot.blurcolde, spotEdited.blurcolde); + assignFromKeyfile(keyFile, "Locallab", "Blurcol_" + index_str, pedited, spot.blurcol, spotEdited.blurcol); + assignFromKeyfile(keyFile, "Locallab", "Contcol_" + index_str, pedited, spot.contcol, spotEdited.contcol); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskcol_" + index_str, pedited, spot.blendmaskcol, spotEdited.blendmaskcol); + assignFromKeyfile(keyFile, "Locallab", "Radmaskcol_" + index_str, pedited, spot.radmaskcol, spotEdited.radmaskcol); + assignFromKeyfile(keyFile, "Locallab", "Chromaskcol_" + index_str, pedited, spot.chromaskcol, spotEdited.chromaskcol); + assignFromKeyfile(keyFile, "Locallab", "Gammaskcol_" + index_str, pedited, spot.gammaskcol, spotEdited.gammaskcol); + assignFromKeyfile(keyFile, "Locallab", "Slomaskcol_" + index_str, pedited, spot.slomaskcol, spotEdited.slomaskcol); + assignFromKeyfile(keyFile, "Locallab", "shadmaskcol_" + index_str, pedited, spot.shadmaskcol, spotEdited.shadmaskcol); + assignFromKeyfile(keyFile, "Locallab", "strumaskcol_" + index_str, pedited, spot.strumaskcol, spotEdited.strumaskcol); + assignFromKeyfile(keyFile, "Locallab", "Lapmaskcol_" + index_str, pedited, spot.lapmaskcol, spotEdited.lapmaskcol); + assignFromKeyfile(keyFile, "Locallab", "QualityCurveMethod_" + index_str, pedited, spot.qualitycurveMethod, spotEdited.qualitycurveMethod); + assignFromKeyfile(keyFile, "Locallab", "gridMethod_" + index_str, pedited, spot.gridMethod, spotEdited.gridMethod); + assignFromKeyfile(keyFile, "Locallab", "Merg_Method_" + index_str, pedited, spot.merMethod, spotEdited.merMethod); + assignFromKeyfile(keyFile, "Locallab", "ToneMethod_" + index_str, pedited, spot.toneMethod, spotEdited.toneMethod); + assignFromKeyfile(keyFile, "Locallab", "mergecolMethod_" + index_str, pedited, spot.mergecolMethod, spotEdited.mergecolMethod); + assignFromKeyfile(keyFile, "Locallab", "LLCurve_" + index_str, pedited, spot.llcurve, spotEdited.llcurve); + assignFromKeyfile(keyFile, "Locallab", "LCCurve_" + index_str, pedited, spot.lccurve, spotEdited.lccurve); + assignFromKeyfile(keyFile, "Locallab", "CCCurve_" + index_str, pedited, spot.cccurve, spotEdited.cccurve); + assignFromKeyfile(keyFile, "Locallab", "CLCurve_" + index_str, pedited, spot.clcurve, spotEdited.clcurve); + assignFromKeyfile(keyFile, "Locallab", "RGBCurve_" + index_str, pedited, spot.rgbcurve, spotEdited.rgbcurve); + assignFromKeyfile(keyFile, "Locallab", "LHCurve_" + index_str, pedited, spot.LHcurve, spotEdited.LHcurve); + assignFromKeyfile(keyFile, "Locallab", "HHCurve_" + index_str, pedited, spot.HHcurve, spotEdited.HHcurve); + assignFromKeyfile(keyFile, "Locallab", "Invers_" + index_str, pedited, spot.invers, spotEdited.invers); + assignFromKeyfile(keyFile, "Locallab", "Special_" + index_str, pedited, spot.special, spotEdited.special); + assignFromKeyfile(keyFile, "Locallab", "Toolcol_" + index_str, pedited, spot.toolcol, spotEdited.toolcol); + assignFromKeyfile(keyFile, "Locallab", "EnaColorMask_" + index_str, pedited, spot.enaColorMask, spotEdited.enaColorMask); + assignFromKeyfile(keyFile, "Locallab", "FftColorMask_" + index_str, pedited, spot.fftColorMask, spotEdited.fftColorMask); + assignFromKeyfile(keyFile, "Locallab", "CCmaskCurve_" + index_str, pedited, spot.CCmaskcurve, spotEdited.CCmaskcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskCurve_" + index_str, pedited, spot.LLmaskcurve, spotEdited.LLmaskcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskCurve_" + index_str, pedited, spot.HHmaskcurve, spotEdited.HHmaskcurve); + assignFromKeyfile(keyFile, "Locallab", "HHhmaskCurve_" + index_str, pedited, spot.HHhmaskcurve, spotEdited.HHhmaskcurve); + assignFromKeyfile(keyFile, "Locallab", "Softradiuscol_" + index_str, pedited, spot.softradiuscol, spotEdited.softradiuscol); + assignFromKeyfile(keyFile, "Locallab", "Opacol_" + index_str, pedited, spot.opacol, spotEdited.opacol); + assignFromKeyfile(keyFile, "Locallab", "Mercol_" + index_str, pedited, spot.mercol, spotEdited.mercol); + assignFromKeyfile(keyFile, "Locallab", "Merlucol_" + index_str, pedited, spot.merlucol, spotEdited.merlucol); + assignFromKeyfile(keyFile, "Locallab", "Conthrcol_" + index_str, pedited, spot.conthrcol, spotEdited.conthrcol); + assignFromKeyfile(keyFile, "Locallab", "LmaskCurve_" + index_str, pedited, spot.Lmaskcurve, spotEdited.Lmaskcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskcolCurvewav_" + index_str, pedited, spot.LLmaskcolcurvewav, spotEdited.LLmaskcolcurvewav); + + if (keyFile.has_key("Locallab", "CSThresholdcol_" + index_str)) { + const std::vector thresh = keyFile.get_integer_list("Locallab", "CSThresholdcol_" + index_str); + + if (thresh.size() >= 4) { + spot.csthresholdcol.setValues(thresh[0], thresh[1], min(thresh[2], 10), min(thresh[3], 10)); + } + + spotEdited.csthresholdcol = true; + } + + // Exposure + spot.visiexpose = assignFromKeyfile(keyFile, "Locallab", "Expexpose_" + index_str, pedited, spot.expexpose, spotEdited.expexpose); + + if (spot.visiexpose) { + spotEdited.visiexpose = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexexpose_" + index_str, pedited, spot.complexexpose, spotEdited.complexexpose); + assignFromKeyfile(keyFile, "Locallab", "Expcomp_" + index_str, pedited, spot.expcomp, spotEdited.expcomp); + assignFromKeyfile(keyFile, "Locallab", "Hlcompr_" + index_str, pedited, spot.hlcompr, spotEdited.hlcompr); + assignFromKeyfile(keyFile, "Locallab", "Hlcomprthresh_" + index_str, pedited, spot.hlcomprthresh, spotEdited.hlcomprthresh); + assignFromKeyfile(keyFile, "Locallab", "Black_" + index_str, pedited, spot.black, spotEdited.black); + assignFromKeyfile(keyFile, "Locallab", "Shadex_" + index_str, pedited, spot.shadex, spotEdited.shadex); + assignFromKeyfile(keyFile, "Locallab", "Shcompr_" + index_str, pedited, spot.shcompr, spotEdited.shcompr); + assignFromKeyfile(keyFile, "Locallab", "Expchroma_" + index_str, pedited, spot.expchroma, spotEdited.expchroma); + assignFromKeyfile(keyFile, "Locallab", "Sensiex_" + index_str, pedited, spot.sensiex, spotEdited.sensiex); + assignFromKeyfile(keyFile, "Locallab", "Structexp_" + index_str, pedited, spot.structexp, spotEdited.structexp); + assignFromKeyfile(keyFile, "Locallab", "Blurexpde_" + index_str, pedited, spot.blurexpde, spotEdited.blurexpde); + assignFromKeyfile(keyFile, "Locallab", "Strexp_" + index_str, pedited, spot.strexp, spotEdited.strexp); + assignFromKeyfile(keyFile, "Locallab", "Angexp_" + index_str, pedited, spot.angexp, spotEdited.angexp); + assignFromKeyfile(keyFile, "Locallab", "ExCurve_" + index_str, pedited, spot.excurve, spotEdited.excurve); + assignFromKeyfile(keyFile, "Locallab", "Inversex_" + index_str, pedited, spot.inversex, spotEdited.inversex); + assignFromKeyfile(keyFile, "Locallab", "EnaExpMask_" + index_str, pedited, spot.enaExpMask, spotEdited.enaExpMask); + assignFromKeyfile(keyFile, "Locallab", "EnaExpMaskaft_" + index_str, pedited, spot.enaExpMaskaft, spotEdited.enaExpMaskaft); + assignFromKeyfile(keyFile, "Locallab", "CCmaskexpCurve_" + index_str, pedited, spot.CCmaskexpcurve, spotEdited.CCmaskexpcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskexpCurve_" + index_str, pedited, spot.LLmaskexpcurve, spotEdited.LLmaskexpcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskexpCurve_" + index_str, pedited, spot.HHmaskexpcurve, spotEdited.HHmaskexpcurve); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskexp_" + index_str, pedited, spot.blendmaskexp, spotEdited.blendmaskexp); + assignFromKeyfile(keyFile, "Locallab", "Radmaskexp_" + index_str, pedited, spot.radmaskexp, spotEdited.radmaskexp); + assignFromKeyfile(keyFile, "Locallab", "Chromaskexp_" + index_str, pedited, spot.chromaskexp, spotEdited.chromaskexp); + assignFromKeyfile(keyFile, "Locallab", "Gammaskexp_" + index_str, pedited, spot.gammaskexp, spotEdited.gammaskexp); + assignFromKeyfile(keyFile, "Locallab", "Slomaskexp_" + index_str, pedited, spot.slomaskexp, spotEdited.slomaskexp); + assignFromKeyfile(keyFile, "Locallab", "Lapmaskexp_" + index_str, pedited, spot.lapmaskexp, spotEdited.lapmaskexp); + assignFromKeyfile(keyFile, "Locallab", "Strmaskexp_" + index_str, pedited, spot.strmaskexp, spotEdited.strmaskexp); + assignFromKeyfile(keyFile, "Locallab", "Angmaskexp_" + index_str, pedited, spot.angmaskexp, spotEdited.angmaskexp); + assignFromKeyfile(keyFile, "Locallab", "Softradiusexp_" + index_str, pedited, spot.softradiusexp, spotEdited.softradiusexp); + assignFromKeyfile(keyFile, "Locallab", "LmaskexpCurve_" + index_str, pedited, spot.Lmaskexpcurve, spotEdited.Lmaskexpcurve); + assignFromKeyfile(keyFile, "Locallab", "ExpMethod_" + index_str, pedited, spot.expMethod, spotEdited.expMethod); + assignFromKeyfile(keyFile, "Locallab", "ExnoiseMethod_" + index_str, pedited, spot.exnoiseMethod, spotEdited.exnoiseMethod); + assignFromKeyfile(keyFile, "Locallab", "Laplacexp_" + index_str, pedited, spot.laplacexp, spotEdited.laplacexp); + assignFromKeyfile(keyFile, "Locallab", "Balanexp_" + index_str, pedited, spot.balanexp, spotEdited.balanexp); + assignFromKeyfile(keyFile, "Locallab", "Linearexp_" + index_str, pedited, spot.linear, spotEdited.linear); + assignFromKeyfile(keyFile, "Locallab", "Gamm_" + index_str, pedited, spot.gamm, spotEdited.gamm); + assignFromKeyfile(keyFile, "Locallab", "Fatamount_" + index_str, pedited, spot.fatamount, spotEdited.fatamount); + assignFromKeyfile(keyFile, "Locallab", "Fatdetail_" + index_str, pedited, spot.fatdetail, spotEdited.fatdetail); + assignFromKeyfile(keyFile, "Locallab", "Fatanchor_" + index_str, pedited, spot.fatanchor, spotEdited.fatanchor); + assignFromKeyfile(keyFile, "Locallab", "Fatlevel_" + index_str, pedited, spot.fatlevel, spotEdited.fatlevel); + // Shadow highlight + spot.visishadhigh = assignFromKeyfile(keyFile, "Locallab", "Expshadhigh_" + index_str, pedited, spot.expshadhigh, spotEdited.expshadhigh); + + if (spot.visishadhigh) { + spotEdited.visishadhigh = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexshadhigh_" + index_str, pedited, spot.complexshadhigh, spotEdited.complexshadhigh); + assignFromKeyfile(keyFile, "Locallab", "ShMethod_" + index_str, pedited, spot.shMethod, spotEdited.shMethod); + + for (int j = 0; j < 5; j ++) { + assignFromKeyfile(keyFile, "Locallab", "Multsh" + std::to_string(j) + "_" + index_str, pedited, spot.multsh[j], spotEdited.multsh[j]); + } + + assignFromKeyfile(keyFile, "Locallab", "Expshadhigh_" + index_str, pedited, spot.expshadhigh, spotEdited.expshadhigh); + assignFromKeyfile(keyFile, "Locallab", "highlights_" + index_str, pedited, spot.highlights, spotEdited.highlights); + assignFromKeyfile(keyFile, "Locallab", "h_tonalwidth_" + index_str, pedited, spot.h_tonalwidth, spotEdited.h_tonalwidth); + assignFromKeyfile(keyFile, "Locallab", "shadows_" + index_str, pedited, spot.shadows, spotEdited.shadows); + assignFromKeyfile(keyFile, "Locallab", "s_tonalwidth_" + index_str, pedited, spot.s_tonalwidth, spotEdited.s_tonalwidth); + assignFromKeyfile(keyFile, "Locallab", "sh_radius_" + index_str, pedited, spot.sh_radius, spotEdited.sh_radius); + assignFromKeyfile(keyFile, "Locallab", "sensihs_" + index_str, pedited, spot.sensihs, spotEdited.sensihs); + assignFromKeyfile(keyFile, "Locallab", "EnaSHMask_" + index_str, pedited, spot.enaSHMask, spotEdited.enaSHMask); + assignFromKeyfile(keyFile, "Locallab", "CCmaskSHCurve_" + index_str, pedited, spot.CCmaskSHcurve, spotEdited.CCmaskSHcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskSHCurve_" + index_str, pedited, spot.LLmaskSHcurve, spotEdited.LLmaskSHcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskSHCurve_" + index_str, pedited, spot.HHmaskSHcurve, spotEdited.HHmaskSHcurve); + assignFromKeyfile(keyFile, "Locallab", "BlendmaskSH_" + index_str, pedited, spot.blendmaskSH, spotEdited.blendmaskSH); + assignFromKeyfile(keyFile, "Locallab", "RadmaskSH_" + index_str, pedited, spot.radmaskSH, spotEdited.radmaskSH); + assignFromKeyfile(keyFile, "Locallab", "BlurSHde_" + index_str, pedited, spot.blurSHde, spotEdited.blurSHde); + assignFromKeyfile(keyFile, "Locallab", "StrSH_" + index_str, pedited, spot.strSH, spotEdited.strSH); + assignFromKeyfile(keyFile, "Locallab", "AngSH_" + index_str, pedited, spot.angSH, spotEdited.angSH); + assignFromKeyfile(keyFile, "Locallab", "Inverssh_" + index_str, pedited, spot.inverssh, spotEdited.inverssh); + assignFromKeyfile(keyFile, "Locallab", "ChromaskSH_" + index_str, pedited, spot.chromaskSH, spotEdited.chromaskSH); + assignFromKeyfile(keyFile, "Locallab", "GammaskSH_" + index_str, pedited, spot.gammaskSH, spotEdited.gammaskSH); + assignFromKeyfile(keyFile, "Locallab", "SlomaskSH_" + index_str, pedited, spot.slomaskSH, spotEdited.slomaskSH); + assignFromKeyfile(keyFile, "Locallab", "LapmaskSH_" + index_str, pedited, spot.lapmaskSH, spotEdited.lapmaskSH); + assignFromKeyfile(keyFile, "Locallab", "DetailSH_" + index_str, pedited, spot.detailSH, spotEdited.detailSH); + assignFromKeyfile(keyFile, "Locallab", "LmaskSHCurve_" + index_str, pedited, spot.LmaskSHcurve, spotEdited.LmaskSHcurve); + assignFromKeyfile(keyFile, "Locallab", "FatamountSH_" + index_str, pedited, spot.fatamountSH, spotEdited.fatamountSH); + assignFromKeyfile(keyFile, "Locallab", "FatanchorSH_" + index_str, pedited, spot.fatanchorSH, spotEdited.fatanchorSH); + assignFromKeyfile(keyFile, "Locallab", "GamSH_" + index_str, pedited, spot.gamSH, spotEdited.gamSH); + assignFromKeyfile(keyFile, "Locallab", "SloSH_" + index_str, pedited, spot.sloSH, spotEdited.sloSH); + // Vibrance + spot.visivibrance = assignFromKeyfile(keyFile, "Locallab", "Expvibrance_" + index_str, pedited, spot.expvibrance, spotEdited.expvibrance); + + if (spot.visivibrance) { + spotEdited.visivibrance = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexvibrance_" + index_str, pedited, spot.complexvibrance, spotEdited.complexvibrance); + assignFromKeyfile(keyFile, "Locallab", "Saturated_" + index_str, pedited, spot.saturated, spotEdited.saturated); + assignFromKeyfile(keyFile, "Locallab", "Pastels_" + index_str, pedited, spot.pastels, spotEdited.pastels); + assignFromKeyfile(keyFile, "Locallab", "Warm_" + index_str, pedited, spot.warm, spotEdited.warm); + + if (keyFile.has_key("Locallab", "PSThreshold_" + index_str)) { + const std::vector thresh = keyFile.get_integer_list("Locallab", "PSThreshold_" + index_str); + + if (thresh.size() >= 2) { + spot.psthreshold.setValues(thresh[0], thresh[1]); + } + + spotEdited.psthreshold = true; + } + + assignFromKeyfile(keyFile, "Locallab", "ProtectSkins_" + index_str, pedited, spot.protectskins, spotEdited.protectskins); + assignFromKeyfile(keyFile, "Locallab", "AvoidColorShift_" + index_str, pedited, spot.avoidcolorshift, spotEdited.avoidcolorshift); + assignFromKeyfile(keyFile, "Locallab", "PastSatTog_" + index_str, pedited, spot.pastsattog, spotEdited.pastsattog); + assignFromKeyfile(keyFile, "Locallab", "Sensiv_" + index_str, pedited, spot.sensiv, spotEdited.sensiv); + assignFromKeyfile(keyFile, "Locallab", "SkinTonesCurve_" + index_str, pedited, spot.skintonescurve, spotEdited.skintonescurve); + assignFromKeyfile(keyFile, "Locallab", "CCmaskvibCurve_" + index_str, pedited, spot.CCmaskvibcurve, spotEdited.CCmaskvibcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskvibCurve_" + index_str, pedited, spot.LLmaskvibcurve, spotEdited.LLmaskvibcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskvibCurve_" + index_str, pedited, spot.HHmaskvibcurve, spotEdited.HHmaskvibcurve); + assignFromKeyfile(keyFile, "Locallab", "EnavibMask_" + index_str, pedited, spot.enavibMask, spotEdited.enavibMask); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskvib_" + index_str, pedited, spot.blendmaskvib, spotEdited.blendmaskvib); + assignFromKeyfile(keyFile, "Locallab", "Radmaskvib_" + index_str, pedited, spot.radmaskvib, spotEdited.radmaskvib); + assignFromKeyfile(keyFile, "Locallab", "Chromaskvib_" + index_str, pedited, spot.chromaskvib, spotEdited.chromaskvib); + assignFromKeyfile(keyFile, "Locallab", "Gammaskvib_" + index_str, pedited, spot.gammaskvib, spotEdited.gammaskvib); + assignFromKeyfile(keyFile, "Locallab", "Slomaskvib_" + index_str, pedited, spot.slomaskvib, spotEdited.slomaskvib); + assignFromKeyfile(keyFile, "Locallab", "Lapmaskvib_" + index_str, pedited, spot.lapmaskvib, spotEdited.lapmaskvib); + assignFromKeyfile(keyFile, "Locallab", "Strvib_" + index_str, pedited, spot.strvib, spotEdited.strvib); + assignFromKeyfile(keyFile, "Locallab", "Strvibab_" + index_str, pedited, spot.strvibab, spotEdited.strvibab); + assignFromKeyfile(keyFile, "Locallab", "Strvibh_" + index_str, pedited, spot.strvibh, spotEdited.strvibh); + assignFromKeyfile(keyFile, "Locallab", "Angvib_" + index_str, pedited, spot.angvib, spotEdited.angvib); + assignFromKeyfile(keyFile, "Locallab", "LmaskvibCurve_" + index_str, pedited, spot.Lmaskvibcurve, spotEdited.Lmaskvibcurve); + // Soft Light + spot.visisoft = assignFromKeyfile(keyFile, "Locallab", "Expsoft_" + index_str, pedited, spot.expsoft, spotEdited.expsoft); + + if (spot.visisoft) { + spotEdited.visisoft = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexsoft_" + index_str, pedited, spot.complexsoft, spotEdited.complexsoft); + assignFromKeyfile(keyFile, "Locallab", "Streng_" + index_str, pedited, spot.streng, spotEdited.streng); + assignFromKeyfile(keyFile, "Locallab", "Sensisf_" + index_str, pedited, spot.sensisf, spotEdited.sensisf); + assignFromKeyfile(keyFile, "Locallab", "Laplace_" + index_str, pedited, spot.laplace, spotEdited.laplace); + assignFromKeyfile(keyFile, "Locallab", "SoftMethod_" + index_str, pedited, spot.softMethod, spotEdited.softMethod); + // Blur & Noise + spot.visiblur = assignFromKeyfile(keyFile, "Locallab", "Expblur_" + index_str, pedited, spot.expblur, spotEdited.expblur); + + if (spot.visiblur) { + spotEdited.visiblur = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexblur_" + index_str, pedited, spot.complexblur, spotEdited.complexblur); + assignFromKeyfile(keyFile, "Locallab", "Radius_" + index_str, pedited, spot.radius, spotEdited.radius); + assignFromKeyfile(keyFile, "Locallab", "Strength_" + index_str, pedited, spot.strength, spotEdited.strength); + assignFromKeyfile(keyFile, "Locallab", "Sensibn_" + index_str, pedited, spot.sensibn, spotEdited.sensibn); + assignFromKeyfile(keyFile, "Locallab", "Iteramed_" + index_str, pedited, spot.itera, spotEdited.itera); + assignFromKeyfile(keyFile, "Locallab", "Guidbl_" + index_str, pedited, spot.guidbl, spotEdited.guidbl); + assignFromKeyfile(keyFile, "Locallab", "Strbl_" + index_str, pedited, spot.strbl, spotEdited.strbl); + assignFromKeyfile(keyFile, "Locallab", "Isogr_" + index_str, pedited, spot.isogr, spotEdited.isogr); + assignFromKeyfile(keyFile, "Locallab", "Strengr_" + index_str, pedited, spot.strengr, spotEdited.strengr); + assignFromKeyfile(keyFile, "Locallab", "Scalegr_" + index_str, pedited, spot.scalegr, spotEdited.scalegr); + assignFromKeyfile(keyFile, "Locallab", "Epsbl_" + index_str, pedited, spot.epsbl, spotEdited.epsbl); + assignFromKeyfile(keyFile, "Locallab", "BlMethod_" + index_str, pedited, spot.blMethod, spotEdited.blMethod); + assignFromKeyfile(keyFile, "Locallab", "ChroMethod_" + index_str, pedited, spot.chroMethod, spotEdited.chroMethod); + assignFromKeyfile(keyFile, "Locallab", "BlurMethod_" + index_str, pedited, spot.blurMethod, spotEdited.blurMethod); + assignFromKeyfile(keyFile, "Locallab", "MedMethod_" + index_str, pedited, spot.medMethod, spotEdited.medMethod); + assignFromKeyfile(keyFile, "Locallab", "activlum_" + index_str, pedited, spot.activlum, spotEdited.activlum); + assignFromKeyfile(keyFile, "Locallab", "noiselumf_" + index_str, pedited, spot.noiselumf, spotEdited.noiselumf); + assignFromKeyfile(keyFile, "Locallab", "noiselumf0_" + index_str, pedited, spot.noiselumf0, spotEdited.noiselumf0); + assignFromKeyfile(keyFile, "Locallab", "noiselumf2_" + index_str, pedited, spot.noiselumf2, spotEdited.noiselumf2); + assignFromKeyfile(keyFile, "Locallab", "noiselumc_" + index_str, pedited, spot.noiselumc, spotEdited.noiselumc); + assignFromKeyfile(keyFile, "Locallab", "noiselumdetail_" + index_str, pedited, spot.noiselumdetail, spotEdited.noiselumdetail); + assignFromKeyfile(keyFile, "Locallab", "noiselequal_" + index_str, pedited, spot.noiselequal, spotEdited.noiselequal); + assignFromKeyfile(keyFile, "Locallab", "noisechrof_" + index_str, pedited, spot.noisechrof, spotEdited.noisechrof); + assignFromKeyfile(keyFile, "Locallab", "noisechroc_" + index_str, pedited, spot.noisechroc, spotEdited.noisechroc); + assignFromKeyfile(keyFile, "Locallab", "noisechrodetail_" + index_str, pedited, spot.noisechrodetail, spotEdited.noisechrodetail); + assignFromKeyfile(keyFile, "Locallab", "Adjblur_" + index_str, pedited, spot.adjblur, spotEdited.adjblur); + assignFromKeyfile(keyFile, "Locallab", "Bilateral_" + index_str, pedited, spot.bilateral, spotEdited.bilateral); + assignFromKeyfile(keyFile, "Locallab", "Sensiden_" + index_str, pedited, spot.sensiden, spotEdited.sensiden); + assignFromKeyfile(keyFile, "Locallab", "Detailthr_" + index_str, pedited, spot.detailthr, spotEdited.detailthr); + assignFromKeyfile(keyFile, "Locallab", "LocwavCurveden_" + index_str, pedited, spot.locwavcurveden, spotEdited.locwavcurveden); + assignFromKeyfile(keyFile, "Locallab", "Showmasktyp_" + index_str, pedited, spot.showmaskblMethodtyp, spotEdited.showmaskblMethodtyp); + assignFromKeyfile(keyFile, "Locallab", "CCmaskblCurve_" + index_str, pedited, spot.CCmaskblcurve, spotEdited.CCmaskblcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskblCurve_" + index_str, pedited, spot.LLmaskblcurve, spotEdited.LLmaskblcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskblCurve_" + index_str, pedited, spot.HHmaskblcurve, spotEdited.HHmaskblcurve); + assignFromKeyfile(keyFile, "Locallab", "EnablMask_" + index_str, pedited, spot.enablMask, spotEdited.enablMask); + assignFromKeyfile(keyFile, "Locallab", "Fftwbl_" + index_str, pedited, spot.fftwbl, spotEdited.fftwbl); + assignFromKeyfile(keyFile, "Locallab", "Toolbl_" + index_str, pedited, spot.toolbl, spotEdited.toolbl); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskbl_" + index_str, pedited, spot.blendmaskbl, spotEdited.blendmaskbl); + assignFromKeyfile(keyFile, "Locallab", "Radmaskbl_" + index_str, pedited, spot.radmaskbl, spotEdited.radmaskbl); + assignFromKeyfile(keyFile, "Locallab", "Chromaskbl_" + index_str, pedited, spot.chromaskbl, spotEdited.chromaskbl); + assignFromKeyfile(keyFile, "Locallab", "Gammaskbl_" + index_str, pedited, spot.gammaskbl, spotEdited.gammaskbl); + assignFromKeyfile(keyFile, "Locallab", "Slomaskbl_" + index_str, pedited, spot.slomaskbl, spotEdited.slomaskbl); + assignFromKeyfile(keyFile, "Locallab", "Lapmaskbl_" + index_str, pedited, spot.lapmaskbl, spotEdited.lapmaskbl); + assignFromKeyfile(keyFile, "Locallab", "shadmaskbl_" + index_str, pedited, spot.shadmaskbl, spotEdited.shadmaskbl); + assignFromKeyfile(keyFile, "Locallab", "shadmaskblsha_" + index_str, pedited, spot.shadmaskblsha, spotEdited.shadmaskblsha); + assignFromKeyfile(keyFile, "Locallab", "strumaskbl_" + index_str, pedited, spot.strumaskbl, spotEdited.strumaskbl); + assignFromKeyfile(keyFile, "Locallab", "LmaskblCurve_" + index_str, pedited, spot.Lmaskblcurve, spotEdited.Lmaskblcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskblCurvewav_" + index_str, pedited, spot.LLmaskblcurvewav, spotEdited.LLmaskblcurvewav); + + if (keyFile.has_key("Locallab", "CSThresholdblur_" + index_str)) { + const std::vector thresh = keyFile.get_integer_list("Locallab", "CSThresholdblur_" + index_str); + + if (thresh.size() >= 4) { + spot.csthresholdblur.setValues(thresh[0], thresh[1], min(thresh[2], 10), min(thresh[3], 10)); + } + + spotEdited.csthresholdblur = true; + } + // Tone Mapping + spot.visitonemap = assignFromKeyfile(keyFile, "Locallab", "Exptonemap_" + index_str, pedited, spot.exptonemap, spotEdited.exptonemap); + + if (spot.visitonemap) { + spotEdited.visitonemap = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complextonemap_" + index_str, pedited, spot.complextonemap, spotEdited.complextonemap); + assignFromKeyfile(keyFile, "Locallab", "Stren_" + index_str, pedited, spot.stren, spotEdited.stren); + assignFromKeyfile(keyFile, "Locallab", "Gamma_" + index_str, pedited, spot.gamma, spotEdited.gamma); + assignFromKeyfile(keyFile, "Locallab", "Estop_" + index_str, pedited, spot.estop, spotEdited.estop); + assignFromKeyfile(keyFile, "Locallab", "Scaltm_" + index_str, pedited, spot.scaltm, spotEdited.scaltm); + assignFromKeyfile(keyFile, "Locallab", "Rewei_" + index_str, pedited, spot.rewei, spotEdited.rewei); + assignFromKeyfile(keyFile, "Locallab", "Satur_" + index_str, pedited, spot.satur, spotEdited.satur); + assignFromKeyfile(keyFile, "Locallab", "Sensitm_" + index_str, pedited, spot.sensitm, spotEdited.sensitm); + assignFromKeyfile(keyFile, "Locallab", "Softradiustm_" + index_str, pedited, spot.softradiustm, spotEdited.softradiustm); + assignFromKeyfile(keyFile, "Locallab", "Amount_" + index_str, pedited, spot.amount, spotEdited.amount); + assignFromKeyfile(keyFile, "Locallab", "Equiltm_" + index_str, pedited, spot.equiltm, spotEdited.equiltm); + assignFromKeyfile(keyFile, "Locallab", "CCmasktmCurve_" + index_str, pedited, spot.CCmasktmcurve, spotEdited.CCmasktmcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmasktmCurve_" + index_str, pedited, spot.LLmasktmcurve, spotEdited.LLmasktmcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmasktmCurve_" + index_str, pedited, spot.HHmasktmcurve, spotEdited.HHmasktmcurve); + assignFromKeyfile(keyFile, "Locallab", "EnatmMask_" + index_str, pedited, spot.enatmMask, spotEdited.enatmMask); + assignFromKeyfile(keyFile, "Locallab", "EnatmMaskaft_" + index_str, pedited, spot.enatmMaskaft, spotEdited.enatmMaskaft); + assignFromKeyfile(keyFile, "Locallab", "Blendmasktm_" + index_str, pedited, spot.blendmasktm, spotEdited.blendmasktm); + assignFromKeyfile(keyFile, "Locallab", "Radmasktm_" + index_str, pedited, spot.radmasktm, spotEdited.radmasktm); + assignFromKeyfile(keyFile, "Locallab", "Chromasktm_" + index_str, pedited, spot.chromasktm, spotEdited.chromasktm); + assignFromKeyfile(keyFile, "Locallab", "Gammasktm_" + index_str, pedited, spot.gammasktm, spotEdited.gammasktm); + assignFromKeyfile(keyFile, "Locallab", "Slomasktm_" + index_str, pedited, spot.slomasktm, spotEdited.slomasktm); + assignFromKeyfile(keyFile, "Locallab", "Lapmasktm_" + index_str, pedited, spot.lapmasktm, spotEdited.lapmasktm); + assignFromKeyfile(keyFile, "Locallab", "LmasktmCurve_" + index_str, pedited, spot.Lmasktmcurve, spotEdited.Lmasktmcurve); + // Retinex + spot.visireti = assignFromKeyfile(keyFile, "Locallab", "Expreti_" + index_str, pedited, spot.expreti, spotEdited.expreti); + + if (spot.visireti) { + spotEdited.visireti = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexreti_" + index_str, pedited, spot.complexreti, spotEdited.complexreti); + assignFromKeyfile(keyFile, "Locallab", "retinexMethod_" + index_str, pedited, spot.retinexMethod, spotEdited.retinexMethod); + assignFromKeyfile(keyFile, "Locallab", "Str_" + index_str, pedited, spot.str, spotEdited.str); + assignFromKeyfile(keyFile, "Locallab", "Chrrt_" + index_str, pedited, spot.chrrt, spotEdited.chrrt); + assignFromKeyfile(keyFile, "Locallab", "Neigh_" + index_str, pedited, spot.neigh, spotEdited.neigh); + assignFromKeyfile(keyFile, "Locallab", "Vart_" + index_str, pedited, spot.vart, spotEdited.vart); + assignFromKeyfile(keyFile, "Locallab", "Offs_" + index_str, pedited, spot.offs, spotEdited.offs); + assignFromKeyfile(keyFile, "Locallab", "Dehaz_" + index_str, pedited, spot.dehaz, spotEdited.dehaz); + assignFromKeyfile(keyFile, "Locallab", "Depth_" + index_str, pedited, spot.depth, spotEdited.depth); + assignFromKeyfile(keyFile, "Locallab", "Sensih_" + index_str, pedited, spot.sensih, spotEdited.sensih); + assignFromKeyfile(keyFile, "Locallab", "TgainCurve_" + index_str, pedited, spot.localTgaincurve, spotEdited.localTgaincurve); + assignFromKeyfile(keyFile, "Locallab", "TtransCurve_" + index_str, pedited, spot.localTtranscurve, spotEdited.localTtranscurve); + assignFromKeyfile(keyFile, "Locallab", "Inversret_" + index_str, pedited, spot.inversret, spotEdited.inversret); + assignFromKeyfile(keyFile, "Locallab", "Equilret_" + index_str, pedited, spot.equilret, spotEdited.equilret); + assignFromKeyfile(keyFile, "Locallab", "Loglin_" + index_str, pedited, spot.loglin, spotEdited.loglin); + assignFromKeyfile(keyFile, "Locallab", "Lumonly_" + index_str, pedited, spot.lumonly, spotEdited.lumonly); + assignFromKeyfile(keyFile, "Locallab", "Softradiusret_" + index_str, pedited, spot.softradiusret, spotEdited.softradiusret); + assignFromKeyfile(keyFile, "Locallab", "CCmaskretiCurve_" + index_str, pedited, spot.CCmaskreticurve, spotEdited.CCmaskreticurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskretiCurve_" + index_str, pedited, spot.LLmaskreticurve, spotEdited.LLmaskreticurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskretiCurve_" + index_str, pedited, spot.HHmaskreticurve, spotEdited.HHmaskreticurve); + assignFromKeyfile(keyFile, "Locallab", "EnaretiMask_" + index_str, pedited, spot.enaretiMask, spotEdited.enaretiMask); + assignFromKeyfile(keyFile, "Locallab", "EnaretiMasktmap_" + index_str, pedited, spot.enaretiMasktmap, spotEdited.enaretiMasktmap); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskreti_" + index_str, pedited, spot.blendmaskreti, spotEdited.blendmaskreti); + assignFromKeyfile(keyFile, "Locallab", "Radmaskreti_" + index_str, pedited, spot.radmaskreti, spotEdited.radmaskreti); + assignFromKeyfile(keyFile, "Locallab", "Chromaskreti_" + index_str, pedited, spot.chromaskreti, spotEdited.chromaskreti); + assignFromKeyfile(keyFile, "Locallab", "Gammaskreti_" + index_str, pedited, spot.gammaskreti, spotEdited.gammaskreti); + assignFromKeyfile(keyFile, "Locallab", "Slomaskreti_" + index_str, pedited, spot.slomaskreti, spotEdited.slomaskreti); + assignFromKeyfile(keyFile, "Locallab", "Lapmaskreti_" + index_str, pedited, spot.lapmaskreti, spotEdited.lapmaskreti); + assignFromKeyfile(keyFile, "Locallab", "Scalereti_" + index_str, pedited, spot.scalereti, spotEdited.scalereti); + assignFromKeyfile(keyFile, "Locallab", "Darkness_" + index_str, pedited, spot.darkness, spotEdited.darkness); + assignFromKeyfile(keyFile, "Locallab", "Lightnessreti_" + index_str, pedited, spot.lightnessreti, spotEdited.lightnessreti); + assignFromKeyfile(keyFile, "Locallab", "Limd_" + index_str, pedited, spot.limd, spotEdited.limd); + assignFromKeyfile(keyFile, "Locallab", "Cliptm_" + index_str, pedited, spot.cliptm, spotEdited.cliptm); + assignFromKeyfile(keyFile, "Locallab", "Fftwreti_" + index_str, pedited, spot.fftwreti, spotEdited.fftwreti); + assignFromKeyfile(keyFile, "Locallab", "LmaskretiCurve_" + index_str, pedited, spot.Lmaskreticurve, spotEdited.Lmaskreticurve); + // Sharpening + spot.visisharp = assignFromKeyfile(keyFile, "Locallab", "Expsharp_" + index_str, pedited, spot.expsharp, spotEdited.expsharp); + + if (spot.visisharp) { + spotEdited.visisharp = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexsharp_" + index_str, pedited, spot.complexsharp, spotEdited.complexsharp); + assignFromKeyfile(keyFile, "Locallab", "Sharcontrast_" + index_str, pedited, spot.sharcontrast, spotEdited.sharcontrast); + assignFromKeyfile(keyFile, "Locallab", "Sharradius_" + index_str, pedited, spot.sharradius, spotEdited.sharradius); + assignFromKeyfile(keyFile, "Locallab", "Sharamount_" + index_str, pedited, spot.sharamount, spotEdited.sharamount); + assignFromKeyfile(keyFile, "Locallab", "Shardamping_" + index_str, pedited, spot.shardamping, spotEdited.shardamping); + assignFromKeyfile(keyFile, "Locallab", "Shariter_" + index_str, pedited, spot.shariter, spotEdited.shariter); + assignFromKeyfile(keyFile, "Locallab", "Sharblur_" + index_str, pedited, spot.sharblur, spotEdited.sharblur); + assignFromKeyfile(keyFile, "Locallab", "Sensisha_" + index_str, pedited, spot.sensisha, spotEdited.sensisha); + assignFromKeyfile(keyFile, "Locallab", "Inverssha_" + index_str, pedited, spot.inverssha, spotEdited.inverssha); + // Local Contrast + spot.visicontrast = assignFromKeyfile(keyFile, "Locallab", "Expcontrast_" + index_str, pedited, spot.expcontrast, spotEdited.expcontrast); + + if (spot.visicontrast) { + spotEdited.visicontrast = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexcontrast_" + index_str, pedited, spot.complexcontrast, spotEdited.complexcontrast); + assignFromKeyfile(keyFile, "Locallab", "Lcradius_" + index_str, pedited, spot.lcradius, spotEdited.lcradius); + assignFromKeyfile(keyFile, "Locallab", "Lcamount_" + index_str, pedited, spot.lcamount, spotEdited.lcamount); + assignFromKeyfile(keyFile, "Locallab", "Lcdarkness_" + index_str, pedited, spot.lcdarkness, spotEdited.lcdarkness); + assignFromKeyfile(keyFile, "Locallab", "Lclightness_" + index_str, pedited, spot.lclightness, spotEdited.lclightness); + assignFromKeyfile(keyFile, "Locallab", "Sigmalc_" + index_str, pedited, spot.sigmalc, spotEdited.sigmalc); + assignFromKeyfile(keyFile, "Locallab", "Levelwav_" + index_str, pedited, spot.levelwav, spotEdited.levelwav); + assignFromKeyfile(keyFile, "Locallab", "Residcont_" + index_str, pedited, spot.residcont, spotEdited.residcont); + assignFromKeyfile(keyFile, "Locallab", "Residsha_" + index_str, pedited, spot.residsha, spotEdited.residsha); + assignFromKeyfile(keyFile, "Locallab", "Residshathr_" + index_str, pedited, spot.residshathr, spotEdited.residshathr); + assignFromKeyfile(keyFile, "Locallab", "Residhi_" + index_str, pedited, spot.residhi, spotEdited.residhi); + assignFromKeyfile(keyFile, "Locallab", "Residhithr_" + index_str, pedited, spot.residhithr, spotEdited.residhithr); + assignFromKeyfile(keyFile, "Locallab", "Residblur_" + index_str, pedited, spot.residblur, spotEdited.residblur); + assignFromKeyfile(keyFile, "Locallab", "Levelblur_" + index_str, pedited, spot.levelblur, spotEdited.levelblur); + assignFromKeyfile(keyFile, "Locallab", "Sigmabl_" + index_str, pedited, spot.sigmabl, spotEdited.sigmabl); + assignFromKeyfile(keyFile, "Locallab", "Residchro_" + index_str, pedited, spot.residchro, spotEdited.residchro); + assignFromKeyfile(keyFile, "Locallab", "Residcomp_" + index_str, pedited, spot.residcomp, spotEdited.residcomp); + assignFromKeyfile(keyFile, "Locallab", "Sigma_" + index_str, pedited, spot.sigma, spotEdited.sigma); + assignFromKeyfile(keyFile, "Locallab", "Offset_" + index_str, pedited, spot.offset, spotEdited.offset); + assignFromKeyfile(keyFile, "Locallab", "Sigmadr_" + index_str, pedited, spot.sigmadr, spotEdited.sigmadr); + assignFromKeyfile(keyFile, "Locallab", "Threswav_" + index_str, pedited, spot.threswav, spotEdited.threswav); + assignFromKeyfile(keyFile, "Locallab", "Chromalev_" + index_str, pedited, spot.chromalev, spotEdited.chromalev); + assignFromKeyfile(keyFile, "Locallab", "Chromablu_" + index_str, pedited, spot.chromablu, spotEdited.chromablu); + assignFromKeyfile(keyFile, "Locallab", "sigmadc_" + index_str, pedited, spot.sigmadc, spotEdited.sigmadc); + assignFromKeyfile(keyFile, "Locallab", "deltad_" + index_str, pedited, spot.deltad, spotEdited.deltad); + assignFromKeyfile(keyFile, "Locallab", "Fatres_" + index_str, pedited, spot.fatres, spotEdited.fatres); + assignFromKeyfile(keyFile, "Locallab", "ClariLres_" + index_str, pedited, spot.clarilres, spotEdited.clarilres); + assignFromKeyfile(keyFile, "Locallab", "ClariCres_" + index_str, pedited, spot.claricres, spotEdited.claricres); + assignFromKeyfile(keyFile, "Locallab", "Clarisoft_" + index_str, pedited, spot.clarisoft, spotEdited.clarisoft); + assignFromKeyfile(keyFile, "Locallab", "Sigmalc2_" + index_str, pedited, spot.sigmalc2, spotEdited.sigmalc2); + assignFromKeyfile(keyFile, "Locallab", "Strwav_" + index_str, pedited, spot.strwav, spotEdited.strwav); + assignFromKeyfile(keyFile, "Locallab", "Angwav_" + index_str, pedited, spot.angwav, spotEdited.angwav); + assignFromKeyfile(keyFile, "Locallab", "Strengthw_" + index_str, pedited, spot.strengthw, spotEdited.strengthw); + assignFromKeyfile(keyFile, "Locallab", "Sigmaed_" + index_str, pedited, spot.sigmaed, spotEdited.sigmaed); + assignFromKeyfile(keyFile, "Locallab", "Radiusw_" + index_str, pedited, spot.radiusw, spotEdited.radiusw); + assignFromKeyfile(keyFile, "Locallab", "Detailw_" + index_str, pedited, spot.detailw, spotEdited.detailw); + assignFromKeyfile(keyFile, "Locallab", "Gradw_" + index_str, pedited, spot.gradw, spotEdited.gradw); + assignFromKeyfile(keyFile, "Locallab", "Tloww_" + index_str, pedited, spot.tloww, spotEdited.tloww); + assignFromKeyfile(keyFile, "Locallab", "Thigw_" + index_str, pedited, spot.thigw, spotEdited.thigw); + assignFromKeyfile(keyFile, "Locallab", "Edgw_" + index_str, pedited, spot.edgw, spotEdited.edgw); + assignFromKeyfile(keyFile, "Locallab", "Basew_" + index_str, pedited, spot.basew, spotEdited.basew); + assignFromKeyfile(keyFile, "Locallab", "Sensilc_" + index_str, pedited, spot.sensilc, spotEdited.sensilc); + assignFromKeyfile(keyFile, "Locallab", "Fftwlc_" + index_str, pedited, spot.fftwlc, spotEdited.fftwlc); + assignFromKeyfile(keyFile, "Locallab", "Blurlc_" + index_str, pedited, spot.blurlc, spotEdited.blurlc); + assignFromKeyfile(keyFile, "Locallab", "Wavblur_" + index_str, pedited, spot.wavblur, spotEdited.wavblur); + assignFromKeyfile(keyFile, "Locallab", "Wavedg_" + index_str, pedited, spot.wavedg, spotEdited.wavedg); + assignFromKeyfile(keyFile, "Locallab", "Waveshow_" + index_str, pedited, spot.waveshow, spotEdited.waveshow); + assignFromKeyfile(keyFile, "Locallab", "Wavcont_" + index_str, pedited, spot.wavcont, spotEdited.wavcont); + assignFromKeyfile(keyFile, "Locallab", "Wavcomp_" + index_str, pedited, spot.wavcomp, spotEdited.wavcomp); + assignFromKeyfile(keyFile, "Locallab", "Wavgradl_" + index_str, pedited, spot.wavgradl, spotEdited.wavgradl); + assignFromKeyfile(keyFile, "Locallab", "Wavcompre_" + index_str, pedited, spot.wavcompre, spotEdited.wavcompre); + assignFromKeyfile(keyFile, "Locallab", "Origlc_" + index_str, pedited, spot.origlc, spotEdited.origlc); + assignFromKeyfile(keyFile, "Locallab", "localcontMethod_" + index_str, pedited, spot.localcontMethod, spotEdited.localcontMethod); + assignFromKeyfile(keyFile, "Locallab", "localedgMethod_" + index_str, pedited, spot.localedgMethod, spotEdited.localedgMethod); + assignFromKeyfile(keyFile, "Locallab", "localneiMethod_" + index_str, pedited, spot.localneiMethod, spotEdited.localneiMethod); + assignFromKeyfile(keyFile, "Locallab", "LocwavCurve_" + index_str, pedited, spot.locwavcurve, spotEdited.locwavcurve); + assignFromKeyfile(keyFile, "Locallab", "LoclevwavCurve_" + index_str, pedited, spot.loclevwavcurve, spotEdited.loclevwavcurve); + assignFromKeyfile(keyFile, "Locallab", "LocconwavCurve_" + index_str, pedited, spot.locconwavcurve, spotEdited.locconwavcurve); + assignFromKeyfile(keyFile, "Locallab", "LoccompwavCurve_" + index_str, pedited, spot.loccompwavcurve, spotEdited.loccompwavcurve); + assignFromKeyfile(keyFile, "Locallab", "LoccomprewavCurve_" + index_str, pedited, spot.loccomprewavcurve, spotEdited.loccomprewavcurve); + assignFromKeyfile(keyFile, "Locallab", "LocedgwavCurve_" + index_str, pedited, spot.locedgwavcurve, spotEdited.locedgwavcurve); + + if (keyFile.has_key("Locallab", "CSThreshold_" + index_str)) { + + const std::vector thresh = keyFile.get_integer_list("Locallab", "CSThreshold_" + index_str); + + if (thresh.size() >= 4) { + spot.csthreshold.setValues(thresh[0], thresh[1], min(thresh[2], 10), min(thresh[3], 10)); + } + + spotEdited.csthreshold = true; + } + + assignFromKeyfile(keyFile, "Locallab", "CCmasklcCurve_" + index_str, pedited, spot.CCmasklccurve, spotEdited.CCmasklccurve); + assignFromKeyfile(keyFile, "Locallab", "LLmasklcCurve_" + index_str, pedited, spot.LLmasklccurve, spotEdited.LLmasklccurve); + assignFromKeyfile(keyFile, "Locallab", "HHmasklcCurve_" + index_str, pedited, spot.HHmasklccurve, spotEdited.HHmasklccurve); + assignFromKeyfile(keyFile, "Locallab", "EnalcMask_" + index_str, pedited, spot.enalcMask, spotEdited.enalcMask); + assignFromKeyfile(keyFile, "Locallab", "Blendmasklc_" + index_str, pedited, spot.blendmasklc, spotEdited.blendmasklc); + assignFromKeyfile(keyFile, "Locallab", "Radmasklc_" + index_str, pedited, spot.radmasklc, spotEdited.radmasklc); + assignFromKeyfile(keyFile, "Locallab", "Chromasklc_" + index_str, pedited, spot.chromasklc, spotEdited.chromasklc); + assignFromKeyfile(keyFile, "Locallab", "LmasklcCurve_" + index_str, pedited, spot.Lmasklccurve, spotEdited.Lmasklccurve); + // Contrast by detail levels + spot.visicbdl = assignFromKeyfile(keyFile, "Locallab", "Expcbdl_" + index_str, pedited, spot.expcbdl, spotEdited.expcbdl); + + if (spot.visicbdl) { + spotEdited.visicbdl = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Complexcbdl_" + index_str, pedited, spot.complexcbdl, spotEdited.complexcbdl); + + for (int j = 0; j < 6; j ++) { + assignFromKeyfile(keyFile, "Locallab", "Mult" + std::to_string(j) + "_" + index_str, pedited, spot.mult[j], spotEdited.mult[j]); + } + + assignFromKeyfile(keyFile, "Locallab", "Chromacbdl_" + index_str, pedited, spot.chromacbdl, spotEdited.chromacbdl); + assignFromKeyfile(keyFile, "Locallab", "Threshold_" + index_str, pedited, spot.threshold, spotEdited.threshold); + assignFromKeyfile(keyFile, "Locallab", "Sensicb_" + index_str, pedited, spot.sensicb, spotEdited.sensicb); + assignFromKeyfile(keyFile, "Locallab", "Clarityml_" + index_str, pedited, spot.clarityml, spotEdited.clarityml); + assignFromKeyfile(keyFile, "Locallab", "Contresid_" + index_str, pedited, spot.contresid, spotEdited.contresid); + assignFromKeyfile(keyFile, "Locallab", "Blurcbdl_" + index_str, pedited, spot.blurcbdl, spotEdited.blurcbdl); + assignFromKeyfile(keyFile, "Locallab", "Softradiuscb_" + index_str, pedited, spot.softradiuscb, spotEdited.softradiuscb); + assignFromKeyfile(keyFile, "Locallab", "EnacbMask_" + index_str, pedited, spot.enacbMask, spotEdited.enacbMask); + assignFromKeyfile(keyFile, "Locallab", "CCmaskcbCurve_" + index_str, pedited, spot.CCmaskcbcurve, spotEdited.CCmaskcbcurve); + assignFromKeyfile(keyFile, "Locallab", "LLmaskcbCurve_" + index_str, pedited, spot.LLmaskcbcurve, spotEdited.LLmaskcbcurve); + assignFromKeyfile(keyFile, "Locallab", "HHmaskcbCurve_" + index_str, pedited, spot.HHmaskcbcurve, spotEdited.HHmaskcbcurve); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskcb_" + index_str, pedited, spot.blendmaskcb, spotEdited.blendmaskcb); + assignFromKeyfile(keyFile, "Locallab", "Radmaskcb_" + index_str, pedited, spot.radmaskcb, spotEdited.radmaskcb); + assignFromKeyfile(keyFile, "Locallab", "Chromaskcb_" + index_str, pedited, spot.chromaskcb, spotEdited.chromaskcb); + assignFromKeyfile(keyFile, "Locallab", "Gammaskcb_" + index_str, pedited, spot.gammaskcb, spotEdited.gammaskcb); + assignFromKeyfile(keyFile, "Locallab", "Slomaskcb_" + index_str, pedited, spot.slomaskcb, spotEdited.slomaskcb); + assignFromKeyfile(keyFile, "Locallab", "Lapmaskcb_" + index_str, pedited, spot.lapmaskcb, spotEdited.lapmaskcb); + assignFromKeyfile(keyFile, "Locallab", "LmaskcbCurve_" + index_str, pedited, spot.Lmaskcbcurve, spotEdited.Lmaskcbcurve); + // Log encoding + spot.visilog = assignFromKeyfile(keyFile, "Locallab", "Explog_" + index_str, pedited, spot.explog, spotEdited.explog); + + if (spot.visilog) { + spotEdited.visilog = true; + } + + assignFromKeyfile(keyFile, "Locallab", "Autocompute_" + index_str, pedited, spot.autocompute, spotEdited.autocompute); + assignFromKeyfile(keyFile, "Locallab", "SourceGray_" + index_str, pedited, spot.sourceGray, spotEdited.sourceGray); + assignFromKeyfile(keyFile, "Locallab", "TargetGray_" + index_str, pedited, spot.targetGray, spotEdited.targetGray); + assignFromKeyfile(keyFile, "Locallab", "AutoGray_" + index_str, pedited, spot.Autogray, spotEdited.Autogray); + assignFromKeyfile(keyFile, "Locallab", "Fullimage_" + index_str, pedited, spot.fullimage, spotEdited.fullimage); + assignFromKeyfile(keyFile, "Locallab", "BlackEv_" + index_str, pedited, spot.blackEv, spotEdited.blackEv); + assignFromKeyfile(keyFile, "Locallab", "WhiteEv_" + index_str, pedited, spot.whiteEv, spotEdited.whiteEv); + assignFromKeyfile(keyFile, "Locallab", "Detail_" + index_str, pedited, spot.detail, spotEdited.detail); + assignFromKeyfile(keyFile, "Locallab", "Sensilog_" + index_str, pedited, spot.sensilog, spotEdited.sensilog); + assignFromKeyfile(keyFile, "Locallab", "Baselog_" + index_str, pedited, spot.baselog, spotEdited.baselog); + assignFromKeyfile(keyFile, "Locallab", "Strlog_" + index_str, pedited, spot.strlog, spotEdited.strlog); + assignFromKeyfile(keyFile, "Locallab", "Anglog_" + index_str, pedited, spot.anglog, spotEdited.anglog); + + // Append LocallabSpot and LocallabParamsEdited + locallab.spots.push_back(spot); + + if (pedited) { + pedited->locallab.spots.push_back(spotEdited); + } + + // Update increment + ++i; + } + } + if (keyFile.has_group("PCVignette")) { assignFromKeyfile(keyFile, "PCVignette", "Enabled", pedited, pcvignette.enabled, pedited->pcvignette.enabled); assignFromKeyfile(keyFile, "PCVignette", "Strength", pedited, pcvignette.strength, pedited->pcvignette.strength); @@ -4755,6 +7573,12 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "Enabled", pedited, wavelet.enabled, pedited->wavelet.enabled); assignFromKeyfile(keyFile, "Wavelet", "Strength", pedited, wavelet.strength, pedited->wavelet.strength); assignFromKeyfile(keyFile, "Wavelet", "Balance", pedited, wavelet.balance, pedited->wavelet.balance); + assignFromKeyfile(keyFile, "Wavelet", "Sigmafin", pedited, wavelet.sigmafin, pedited->wavelet.sigmafin); + assignFromKeyfile(keyFile, "Wavelet", "Sigmaton", pedited, wavelet.sigmaton, pedited->wavelet.sigmaton); + assignFromKeyfile(keyFile, "Wavelet", "Sigmacol", pedited, wavelet.sigmacol, pedited->wavelet.sigmacol); + assignFromKeyfile(keyFile, "Wavelet", "Sigmadir", pedited, wavelet.sigmadir, pedited->wavelet.sigmadir); + assignFromKeyfile(keyFile, "Wavelet", "Rangeab", pedited, wavelet.rangeab, pedited->wavelet.rangeab); + assignFromKeyfile(keyFile, "Wavelet", "Protab", pedited, wavelet.protab, pedited->wavelet.protab); assignFromKeyfile(keyFile, "Wavelet", "Iter", pedited, wavelet.iter, pedited->wavelet.iter); assignFromKeyfile(keyFile, "Wavelet", "Median", pedited, wavelet.median, pedited->wavelet.median); assignFromKeyfile(keyFile, "Wavelet", "Medianlev", pedited, wavelet.medianlev, pedited->wavelet.medianlev); @@ -4779,6 +7603,10 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "Showmask", pedited, wavelet.showmask, pedited->wavelet.showmask); assignFromKeyfile(keyFile, "Wavelet", "Oldsh", pedited, wavelet.oldsh, pedited->wavelet.oldsh); assignFromKeyfile(keyFile, "Wavelet", "TMr", pedited, wavelet.tmr, pedited->wavelet.tmr); + assignFromKeyfile(keyFile, "Wavelet", "LabGridALow", pedited, wavelet.labgridALow, pedited->wavelet.labgridALow); + assignFromKeyfile(keyFile, "Wavelet", "LabGridBLow", pedited, wavelet.labgridBLow, pedited->wavelet.labgridBLow); + assignFromKeyfile(keyFile, "Wavelet", "LabGridAHigh", pedited, wavelet.labgridAHigh, pedited->wavelet.labgridAHigh); + assignFromKeyfile(keyFile, "Wavelet", "LabGridBHigh", pedited, wavelet.labgridBHigh, pedited->wavelet.labgridBHigh); if (ppVersion < 331) { // wavelet.Lmethod was a string before version 331 Glib::ustring temp; @@ -4841,6 +7669,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "ContrastCurve", pedited, wavelet.ccwcurve, pedited->wavelet.ccwcurve); assignFromKeyfile(keyFile, "Wavelet", "blcurve", pedited, wavelet.blcurve, pedited->wavelet.blcurve); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveRG", pedited, wavelet.opacityCurveRG, pedited->wavelet.opacityCurveRG); + assignFromKeyfile(keyFile, "Wavelet", "Levalshc", pedited, wavelet.opacityCurveSH, pedited->wavelet.opacityCurveSH); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveBY", pedited, wavelet.opacityCurveBY, pedited->wavelet.opacityCurveBY); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveW", pedited, wavelet.opacityCurveW, pedited->wavelet.opacityCurveW); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveWL", pedited, wavelet.opacityCurveWL, pedited->wavelet.opacityCurveWL); @@ -5394,9 +8223,11 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftEperIso", pedited, raw.bayersensor.pixelShiftEperIso, pedited->raw.bayersensor.pixelShiftEperIso); + if (ppVersion < 332) { raw.bayersensor.pixelShiftEperIso += 1.0; } + assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftSigma", pedited, raw.bayersensor.pixelShiftSigma, pedited->raw.bayersensor.pixelShiftSigma); assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftShowMotion", pedited, raw.bayersensor.pixelShiftShowMotion, pedited->raw.bayersensor.pixelShiftShowMotion); assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftShowMotionMaskOnly", pedited, raw.bayersensor.pixelShiftShowMotionMaskOnly, pedited->raw.bayersensor.pixelShiftShowMotionMaskOnly); @@ -5411,12 +8242,14 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (ppVersion < 336) { if (keyFile.has_key("RAW Bayer", "pixelShiftLmmse")) { - bool useLmmse = keyFile.get_boolean ("RAW Bayer", "pixelShiftLmmse"); + const bool useLmmse = keyFile.get_boolean("RAW Bayer", "pixelShiftLmmse"); + if (useLmmse) { raw.bayersensor.pixelShiftDemosaicMethod = raw.bayersensor.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::LMMSE); } else { raw.bayersensor.pixelShiftDemosaicMethod = raw.bayersensor.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZE); } + if (pedited) { pedited->raw.bayersensor.pixelShiftDemosaicMethod = true; } @@ -5470,6 +8303,16 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } + if (keyFile.has_group("RAW Preprocess WB")) { + if (keyFile.has_key("RAW Preprocess WB", "Mode")) { + raw.preprocessWB.mode = RAWParams::PreprocessWB::Mode(keyFile.get_integer("RAW Preprocess WB", "Mode")); + + if (pedited) { + pedited->raw.preprocessWB.mode = true; + } + } + } + if (keyFile.has_group("MetaData")) { int mode = int(MetaDataParams::TUNNEL); assignFromKeyfile(keyFile, "MetaData", "Mode", pedited, mode, pedited->metadata.mode); @@ -5574,6 +8417,7 @@ bool ProcParams::operator ==(const ProcParams& other) const && lensProf == other.lensProf && perspective == other.perspective && gradient == other.gradient + && locallab == other.locallab && pcvignette == other.pcvignette && cacorrection == other.cacorrection && vignetting == other.vignetting diff --git a/rtengine/procparams.h b/rtengine/procparams.h index b6d2b9c3a..ae46174a2 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -42,9 +42,20 @@ class RetinextransmissionCurve; class WavCurve; class Wavblcurve; class WavOpacityCurveBY; +class WavOpacityCurveSH; class WavOpacityCurveRG; class WavOpacityCurveW; class WavOpacityCurveWL; +class LocretigainCurve; +class LocretigainCurverab; +class LocLHCurve; +class LocHHCurve; +class LocLLmaskCurve; +class LocCCmaskCurve; +class LocHHmaskCurve; +class LocLLmaskexpCurve; +class LocCCmaskexpCurve; +class LocHHmaskexpCurve; enum RenderingIntent : int { RI_PERCEPTUAL = INTENT_PERCEPTUAL, @@ -103,6 +114,12 @@ public: } } + template + typename std::enable_if::value, bool>::type operator !=(const Threshold& rhs) const + { + return !(*this == rhs); + } + T getBottom() const { return bottom_left; @@ -402,7 +419,6 @@ struct RGBCurvesParams { /** * Parameters of the Color Toning */ - struct ColorToningParams { bool enabled; bool autosat; @@ -490,6 +506,7 @@ struct ColorToningParams { void getCurves(ColorGradientCurve& colorCurveLUT, OpacityCurve& opacityCurveLUT, const double xyz_rgb[3][3], bool& opautili) const; }; + /** * Parameters of the sharpening */ @@ -529,8 +546,10 @@ struct SharpenEdgeParams { bool operator ==(const SharpenEdgeParams& other) const; bool operator !=(const SharpenEdgeParams& other) const; + }; + struct SharpenMicroParams { bool enabled; bool matrix; @@ -950,6 +969,480 @@ struct GradientParams { bool operator !=(const GradientParams& other) const; }; +/** + * Parameters of the Local Lab + */ +struct LocallabParams { + struct LocallabSpot { + // Control spot settings + Glib::ustring name; + bool isvisible; + Glib::ustring shape; // ELI, RECT + Glib::ustring spotMethod; // norm, exc + Glib::ustring wavMethod; // D2, D4, D6, D10, D14 + int sensiexclu; + int structexclu; + double struc; + Glib::ustring shapeMethod; // IND, SYM, INDSL, SYMSL + std::vector loc; // For ellipse/rectangle: {locX, locXL, locY, locYT} + int centerX; + int centerY; + int circrad; + Glib::ustring qualityMethod; // none, std, enh, enhsup, contr, sob2 + Glib::ustring complexMethod; // sim, mod, all + double transit; + double feather; + double thresh; + double iter; + double balan; + double balanh; + double colorde; + double colorscope; + double transitweak; + double transitgrad; + bool avoid; + bool blwh; + bool recurs; + bool laplac; + bool deltae; + bool shortc; + bool savrest; + int scopemask; + int lumask; + // Color & Light + bool visicolor; + bool expcolor; + int complexcolor; + bool curvactiv; + int lightness; + int contrast; + int chroma; + double labgridALow; + double labgridBLow; + double labgridAHigh; + double labgridBHigh; + double labgridALowmerg; + double labgridBLowmerg; + double labgridAHighmerg; + double labgridBHighmerg; + int strengthgrid; + int sensi; + int structcol; + double strcol; + double strcolab; + double strcolh; + double angcol; + int blurcolde; + double blurcol; + double contcol; + int blendmaskcol; + double radmaskcol; + double chromaskcol; + double gammaskcol; + double slomaskcol; + int shadmaskcol; + double strumaskcol; + double lapmaskcol; + Glib::ustring qualitycurveMethod; // none, std + Glib::ustring gridMethod; // one, two + Glib::ustring merMethod; // mone, mtwo, mthr, mfou, mfiv + Glib::ustring toneMethod; // one, two, thr, fou + Glib::ustring mergecolMethod; // one, two, thr, fou, fiv, six, sev, sev0, sev1, sev2, hei, nin, ten, ele, twe, thi, for, hue, sat, col, lum + std::vector llcurve; + std::vector lccurve; + std::vector cccurve; + std::vector clcurve; + std::vector rgbcurve; + std::vector LHcurve; + std::vector HHcurve; + bool invers; + bool special; + bool toolcol; + bool enaColorMask; + bool fftColorMask; + std::vector CCmaskcurve; + std::vector LLmaskcurve; + std::vector HHmaskcurve; + std::vector HHhmaskcurve; + double softradiuscol; + double opacol; + double mercol; + double merlucol; + double conthrcol; + std::vector Lmaskcurve; + std::vector LLmaskcolcurvewav; + Threshold csthresholdcol; + // Exposure + bool visiexpose; + bool expexpose; + int complexexpose; + double expcomp; + int hlcompr; + int hlcomprthresh; + int black; + int shadex; + int shcompr; + int expchroma; + int sensiex; + int structexp; + int blurexpde; + double strexp; + double angexp; + std::vector excurve; + bool inversex; + bool enaExpMask; + bool enaExpMaskaft; + std::vector CCmaskexpcurve; + std::vector LLmaskexpcurve; + std::vector HHmaskexpcurve; + int blendmaskexp; + double radmaskexp; + double chromaskexp; + double gammaskexp; + double slomaskexp; + double lapmaskexp; + double strmaskexp; + double angmaskexp; + double softradiusexp; + std::vector Lmaskexpcurve; + Glib::ustring expMethod; // std, pde + Glib::ustring exnoiseMethod; // none, med, medhi + double laplacexp; + double balanexp; + double linear; + double gamm; + double fatamount; + double fatdetail; + double fatanchor; + double fatlevel; + // Shadow highlight + bool visishadhigh; + bool expshadhigh; + int complexshadhigh; + Glib::ustring shMethod; // std, tone + int multsh[5]; + int highlights; + int h_tonalwidth; + int shadows; + int s_tonalwidth; + int sh_radius; + int sensihs; + bool enaSHMask; + std::vector CCmaskSHcurve; + std::vector LLmaskSHcurve; + std::vector HHmaskSHcurve; + int blendmaskSH; + double radmaskSH; + int blurSHde; + double strSH; + double angSH; + bool inverssh; + double chromaskSH; + double gammaskSH; + double slomaskSH; + double lapmaskSH; + int detailSH; + std::vector LmaskSHcurve; + double fatamountSH; + double fatanchorSH; + double gamSH; + double sloSH; + // Vibrance + bool visivibrance; + bool expvibrance; + int complexvibrance; + int saturated; + int pastels; + int warm; + Threshold psthreshold; + bool protectskins; + bool avoidcolorshift; + bool pastsattog; + int sensiv; + std::vector skintonescurve; + std::vector CCmaskvibcurve; + std::vector LLmaskvibcurve; + std::vector HHmaskvibcurve; + bool enavibMask; + int blendmaskvib; + double radmaskvib; + double chromaskvib; + double gammaskvib; + double slomaskvib; + double lapmaskvib; + double strvib; + double strvibab; + double strvibh; + double angvib; + std::vector Lmaskvibcurve; + // Soft Light + bool visisoft; + bool expsoft; + int complexsoft; + int streng; + int sensisf; + double laplace; + Glib::ustring softMethod; // soft, reti + // Blur & Noise + bool visiblur; + bool expblur; + int complexblur; + double radius; + int strength; + int sensibn; + int itera; + int guidbl; + int strbl; + int isogr; + int strengr; + int scalegr; + int epsbl; + Glib::ustring blMethod; // blur, med, guid + Glib::ustring chroMethod; // lum, chr, all + Glib::ustring blurMethod; // norm, inv + Glib::ustring medMethod; // none, 33, 55, 77, 99 + bool activlum; + double noiselumf; + double noiselumf0; + double noiselumf2; + double noiselumc; + double noiselumdetail; + int noiselequal; + double noisechrof; + double noisechroc; + double noisechrodetail; + int adjblur; + int bilateral; + int sensiden; + int detailthr; + std::vector locwavcurveden; + Glib::ustring showmaskblMethodtyp; + std::vector CCmaskblcurve; + std::vector LLmaskblcurve; + std::vector HHmaskblcurve; + bool enablMask; + bool fftwbl; + bool toolbl; + int blendmaskbl; + double radmaskbl; + double chromaskbl; + double gammaskbl; + double slomaskbl; + double lapmaskbl; + int shadmaskbl; + int shadmaskblsha; + double strumaskbl; + std::vector Lmaskblcurve; + std::vector LLmaskblcurvewav; + Threshold csthresholdblur; + // Tone Mapping + bool visitonemap; + bool exptonemap; + int complextonemap; + double stren; + double gamma; + double estop; + double scaltm; + int rewei; + double satur; + int sensitm; + double softradiustm; + double amount; + bool equiltm; + std::vector CCmasktmcurve; + std::vector LLmasktmcurve; + std::vector HHmasktmcurve; + bool enatmMask; + bool enatmMaskaft; + int blendmasktm; + double radmasktm; + double chromasktm; + double gammasktm; + double slomasktm; + double lapmasktm; + std::vector Lmasktmcurve; + // Retinex + bool visireti; + bool expreti; + int complexreti; + Glib::ustring retinexMethod; // low, uni, high + double str; + double chrrt; + double neigh; + double vart; + double offs; + int dehaz; + int depth; + int sensih; + std::vector localTgaincurve; + std::vector localTtranscurve; + bool inversret; + bool equilret; + bool loglin; + bool lumonly; + double softradiusret; + std::vector CCmaskreticurve; + std::vector LLmaskreticurve; + std::vector HHmaskreticurve; + bool enaretiMask; + bool enaretiMasktmap; + int blendmaskreti; + double radmaskreti; + double chromaskreti; + double gammaskreti; + double slomaskreti; + double lapmaskreti; + double scalereti; + double darkness; + double lightnessreti; + double limd; + double cliptm; + bool fftwreti; + std::vector Lmaskreticurve; + // Sharpening + bool visisharp; + bool expsharp; + int complexsharp; + int sharcontrast; + double sharradius; + int sharamount; + int shardamping; + int shariter; + double sharblur; + int sensisha; + bool inverssha; + // Local Contrast + bool visicontrast; + bool expcontrast; + int complexcontrast; + int lcradius; + double lcamount; + double lcdarkness; + double lclightness; + double sigmalc; + int levelwav; + double residcont; + double residsha; + double residshathr; + double residhi; + double residhithr; + double residblur; + double levelblur; + double sigmabl; + double residchro; + double residcomp; + double sigma; + double offset; + double sigmadr; + double threswav; + double chromalev; + double chromablu; + double sigmadc; + double deltad; + double fatres; + double clarilres; + double claricres; + double clarisoft; + double sigmalc2; + double strwav; + double angwav; + double strengthw; + double sigmaed; + double radiusw; + double detailw; + double gradw; + double tloww; + double thigw; + double edgw; + double basew; + int sensilc; + bool fftwlc; + bool blurlc; + bool wavblur; + bool wavedg; + bool waveshow; + bool wavcont; + bool wavcomp; + bool wavgradl; + bool wavcompre; + bool origlc; + Glib::ustring localcontMethod; // loc, wav + Glib::ustring localedgMethod; // fir, sec, thr + Glib::ustring localneiMethod; // none, low, high + std::vector locwavcurve; + Threshold csthreshold; + std::vector loclevwavcurve; + std::vector locconwavcurve; + std::vector loccompwavcurve; + std::vector loccomprewavcurve; + std::vector locedgwavcurve; + std::vector CCmasklccurve; + std::vector LLmasklccurve; + std::vector HHmasklccurve; + bool enalcMask; + int blendmasklc; + double radmasklc; + double chromasklc; + std::vector Lmasklccurve; + // Contrast by detail levels + bool visicbdl; + bool expcbdl; + int complexcbdl; + double mult[6]; + double chromacbdl; + double threshold; + int sensicb; + double clarityml; + int contresid; + double blurcbdl; + double softradiuscb; + bool enacbMask; + std::vector CCmaskcbcurve; + std::vector LLmaskcbcurve; + std::vector HHmaskcbcurve; + int blendmaskcb; + double radmaskcb; + double chromaskcb; + double gammaskcb; + double slomaskcb; + double lapmaskcb; + std::vector Lmaskcbcurve; + // Log encoding + bool visilog; + bool explog; + bool autocompute; + double sourceGray; + double targetGray; + bool Autogray; + bool fullimage; + double blackEv; + double whiteEv; + double detail; + int sensilog; + double baselog; + double strlog; + double anglog; + + LocallabSpot(); + + bool operator ==(const LocallabSpot& other) const; + bool operator !=(const LocallabSpot& other) const; + }; + + static const double LABGRIDL_CORR_MAX; + static const double LABGRIDL_CORR_SCALE; + static const double LABGRIDL_DIRECT_SCALE; + + bool enabled; + int selspot; + std::vector spots; + + LocallabParams(); + + bool operator ==(const LocallabParams& other) const; + bool operator !=(const LocallabParams& other) const; +}; + /** * Parameters of the post-crop vignette filter */ @@ -1201,7 +1694,9 @@ private: struct WaveletParams { std::vector ccwcurve; std::vector blcurve; + std::vector levelshc; std::vector opacityCurveRG; + std::vector opacityCurveSH; std::vector opacityCurveBY; std::vector opacityCurveW; std::vector opacityCurveWL; @@ -1235,6 +1730,12 @@ struct WaveletParams { bool tmr; int strength; int balance; + double sigmafin; + double sigmaton; + double sigmacol; + double sigmadir; + double rangeab; + double protab; int iter; bool expcontrast; bool expchroma; @@ -1247,7 +1748,13 @@ struct WaveletParams { bool exptoning; bool expnoise; bool expclari; - + double labgridALow; + double labgridBLow; + double labgridAHigh; + double labgridBHigh; + static const double LABGRID_CORR_MAX; + static const double LABGRID_CORR_SCALE; + static const double LABGRIDL_DIRECT_SCALE; int Lmethod; Glib::ustring CLmethod; Glib::ustring Backmethod; @@ -1318,8 +1825,8 @@ struct WaveletParams { void getCurves( WavCurve& cCurve, Wavblcurve& tCurve, - WavOpacityCurveRG& - opacityCurveLUTRG, + WavOpacityCurveRG& opacityCurveLUTRG, + WavOpacityCurveSH& opacityCurveLUTSH, WavOpacityCurveBY& opacityCurveLUTBY, WavOpacityCurveW& opacityCurveLUTW, WavOpacityCurveWL& opacityCurveLUTWL @@ -1551,6 +2058,22 @@ struct RAWParams { // exposure before interpolation double expos; + struct PreprocessWB { + enum class Mode { + CAMERA = 0, + AUTO + }; + + Mode mode; + + PreprocessWB(); + + bool operator ==(const PreprocessWB& other) const; + bool operator !=(const PreprocessWB& other) const; + }; + + PreprocessWB preprocessWB; + bool hotPixelFilter; bool deadPixelFilter; int hotdeadpix_thresh; @@ -1618,6 +2141,7 @@ public: LensProfParams lensProf; ///< Lens correction profile parameters PerspectiveParams perspective; ///< Perspective correction parameters GradientParams gradient; ///< Gradient filter parameters + LocallabParams locallab; ///< Local lab parameters PCVignetteParams pcvignette; ///< Post-crop vignette filter parameters CACorrParams cacorrection; ///< Lens c/a correction parameters VignettingParams vignetting; ///< Lens vignetting correction parameters diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index c2df70468..e3a747048 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -20,7 +20,7 @@ namespace rtengine { -RawImage::RawImage( const Glib::ustring &name ) +RawImage::RawImage(const Glib::ustring &name) : data(nullptr) , prefilters(0) , filename(name) @@ -36,31 +36,31 @@ RawImage::RawImage( const Glib::ustring &name ) RawImage::~RawImage() { - if(ifp) { + if (ifp) { fclose(ifp); ifp = nullptr; } - if( image ) { + if (image) { free(image); } - if(allocation) { + if (allocation) { delete [] allocation; allocation = nullptr; } - if(float_raw_image) { + if (float_raw_image) { delete [] float_raw_image; float_raw_image = nullptr; } - if(data) { + if (data) { delete [] data; data = nullptr; } - if(profile_data) { + if (profile_data) { delete [] profile_data; profile_data = nullptr; } @@ -82,15 +82,38 @@ eSensorType RawImage::getSensorType() const /* Similar to dcraw scale_colors for coeff. calculation, but without actual pixels scaling. * need pixels in data[][] available */ -void RawImage::get_colorsCoeff( float *pre_mul_, float *scale_mul_, float *cblack_, bool forceAutoWB) +void RawImage::get_colorsCoeff(float *pre_mul_, float *scale_mul_, float *cblack_, bool forceAutoWB) { + if (!pre_mul_ && !scale_mul_ && !forceAutoWB) { + // only black levels + if (isXtrans()) { + // for xtrans files dcraw stores black levels in cblack[6] .. cblack[41], but all are equal, so we just use cblack[6] + for (int c = 0; c < 4; c++) { + cblack_[c] = (float) this->get_cblack(6); + } + } else if ((this->get_cblack(4) + 1) / 2 == 1 && (this->get_cblack(5) + 1) / 2 == 1) { + for (int c = 0; c < 4; c++) { + cblack_[c] = this->get_cblack(c); + } + + for (int c = 0; c < 4; c++) { + cblack_[FC(c / 2, c % 2)] = this->get_cblack(6 + c / 2 % this->get_cblack(4) * this->get_cblack(5) + c % 2 % this->get_cblack(5)); + } + } else { + for (int c = 0; c < 4; c++) { + cblack_[c] = (float) this->get_cblack(c); + } + } + return; + } + unsigned sum[8], c; unsigned W = this->get_width(); unsigned H = this->get_height(); float val; double dsum[8], dmin, dmax; - if(isXtrans()) { + if (isXtrans()) { // for xtrans files dcraw stores black levels in cblack[6] .. cblack[41], but all are equal, so we just use cblack[6] for (int c = 0; c < 4; c++) { cblack_[c] = (float) this->get_cblack(6); @@ -100,6 +123,7 @@ void RawImage::get_colorsCoeff( float *pre_mul_, float *scale_mul_, float *cblac for (int c = 0; c < 4; c++) { cblack_[c] = this->get_cblack(c); } + for (int c = 0; c < 4; c++) { cblack_[FC(c / 2, c % 2)] = this->get_cblack(6 + c / 2 % this->get_cblack(4) * this->get_cblack(5) + c % 2 % this->get_cblack(5)); pre_mul_[c] = this->get_pre_mul(c); @@ -112,9 +136,10 @@ void RawImage::get_colorsCoeff( float *pre_mul_, float *scale_mul_, float *cblac } if (this->get_cam_mul(0) == -1 || forceAutoWB) { - if(!data) { // this happens only for thumbnail creation when get_cam_mul(0) == -1 + if (!data) { // this happens only for thumbnail creation when get_cam_mul(0) == -1 compress_image(0, false); } + memset(dsum, 0, sizeof dsum); constexpr float blackThreshold = 8.f; @@ -194,11 +219,11 @@ skip_block2: } } - for(int c = 0; c < 4; c++) { + for (int c = 0; c < 4; c++) { dsum[c] -= static_cast(cblack_[c]) * dsum[c + 4]; } - } else if(isXtrans()) { + } else if (isXtrans()) { #ifdef _OPENMP #pragma omp parallel #endif @@ -313,8 +338,7 @@ skip_block: if (sum[0] && sum[1] && sum[2] && sum[3]) for (int c = 0; c < 4; c++) { pre_mul_[c] = (float) sum[c + 4] / sum[c]; - } - else if (this->get_cam_mul(0) && this->get_cam_mul(2)) { + } else if (this->get_cam_mul(0) && this->get_cam_mul(2)) { pre_mul_[0] = this->get_cam_mul(0); pre_mul_[1] = this->get_cam_mul(1); pre_mul_[2] = this->get_cam_mul(2); @@ -412,17 +436,17 @@ skip_block: } } -int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, ProgressListener *plistener, double progressRange) +int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, ProgressListener *plistener, double progressRange) { ifname = filename.c_str(); image = nullptr; verbose = settings->verbose; oprof = nullptr; - if(!ifp) { - ifp = gfopen (ifname); // Maps to either file map or direct fopen + if (!ifp) { + ifp = gfopen(ifname); // Maps to either file map or direct fopen } else { - fseek (ifp, 0, SEEK_SET); + fseek(ifp, 0, SEEK_SET); } if (!ifp) { @@ -458,7 +482,7 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro return 2; } - if(!strcmp(make,"Fujifilm") && raw_height * raw_width * 2u != raw_size) { + if (!strcmp(make, "Fujifilm") && raw_height * raw_width * 2u != raw_size) { if (raw_width * raw_height * 7u / 4u == raw_size) { load_raw = &RawImage::fuji_14bit_load_raw; } else { @@ -478,13 +502,13 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro this->rotate_deg = 0; } - if( loadData ) { + if (loadData) { use_camera_wb = 1; shrink = 0; if (settings->verbose) { - printf ("Loading %s %s image from %s...\n", make, model, filename.c_str()); + printf("Loading %s %s image from %s...\n", make, model, filename.c_str()); } iheight = height; @@ -492,16 +516,15 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro if (filters || colors == 1) { raw_image = (ushort *) calloc ((static_cast(raw_height) + 7u) * static_cast(raw_width), 2); - merror (raw_image, "main()"); + merror(raw_image, "main()"); } // dcraw needs this global variable to hold pixel data image = (dcrawImage_t)calloc (static_cast(height) * static_cast(width) * sizeof * image + meta_length, 1); - meta_data = (char *) (image + static_cast(height) * static_cast(width)); - if(!image) { return 200; } + meta_data = (char *) (image + static_cast(height) * static_cast(width)); /* Issue 2467 if (setjmp (failure)) { @@ -512,7 +535,7 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro } */ // Load raw pixels data - fseek (ifp, data_offset, SEEK_SET); + fseek(ifp, data_offset, SEEK_SET); (this->*load_raw)(); if (!float_raw_image) { // apply baseline exposure only for float DNGs @@ -530,13 +553,15 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro if (cc && cc->has_rawCrop()) { int lm, tm, w, h; cc->get_rawCrop(lm, tm, w, h); - if(isXtrans()) { - shiftXtransMatrix(6 - ((top_margin - tm)%6), 6 - ((left_margin - lm)%6)); + + if (isXtrans()) { + shiftXtransMatrix(6 - ((top_margin - tm) % 6), 6 - ((left_margin - lm) % 6)); } else { - if(((int)top_margin - tm) & 1) { // we have an odd border difference + if (((int)top_margin - tm) & 1) { // we have an odd border difference filters = (filters << 4) | (filters >> 28); // left rotate filters by 4 bits } } + left_margin = lm; top_margin = tm; @@ -566,7 +591,7 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro } crop_masked_pixels(); - free (raw_image); + free(raw_image); raw_image = nullptr; } else { if (get_maker() == "Sigma" && cc && cc->has_rawCrop()) { // foveon images @@ -594,8 +619,8 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro // Load embedded profile if (profile_length) { profile_data = new char[profile_length]; - fseek ( ifp, profile_offset, SEEK_SET); - fread ( profile_data, 1, profile_length, ifp); + fseek(ifp, profile_offset, SEEK_SET); + fread(profile_data, 1, profile_length, ifp); } /* @@ -625,10 +650,10 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro if (RT_whitelevel_from_constant == ThreeValBool::T) { maximum_c4[i] = cc->get_WhiteLevel(i, iso_speed, aperture); - if(tiff_bps > 0 && maximum_c4[i] > 0 && !isFoveon()) { + if (tiff_bps > 0 && maximum_c4[i] > 0 && !isFoveon()) { unsigned compare = ((uint64_t)1 << tiff_bps) - 1; // use uint64_t to avoid overflow if tiff_bps == 32 - while(static_cast(maximum_c4[i]) > compare) { + while (static_cast(maximum_c4[i]) > compare) { maximum_c4[i] >>= 1; } } @@ -637,11 +662,10 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro } if (black_c4[0] == -1) { - if(isXtrans()) + if (isXtrans()) for (int c = 0; c < 4; c++) { black_c4[c] = cblack[6]; - } - else + } else // RT constants not set, bring in the DCRAW single channel black constant for (int c = 0; c < 4; c++) { @@ -677,7 +701,7 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro } } - if ( closeFile ) { + if (closeFile) { fclose(ifp); ifp = nullptr; } @@ -691,7 +715,7 @@ int RawImage::loadRaw (bool loadData, unsigned int imageNum, bool closeFile, Pro float** RawImage::compress_image(unsigned int frameNum, bool freeImage) { - if( !image ) { + if (!image) { return nullptr; } @@ -727,7 +751,7 @@ float** RawImage::compress_image(unsigned int frameNum, bool freeImage) } // copy pixel raw data: the compressed format earns space - if( float_raw_image ) { + if (float_raw_image) { #ifdef _OPENMP #pragma omp parallel for #endif @@ -783,50 +807,51 @@ float** RawImage::compress_image(unsigned int frameNum, bool freeImage) } } - if(freeImage) { + if (freeImage) { free(image); // we don't need this anymore image = nullptr; } + return data; } bool RawImage::is_supportedThumb() const { - return ( (thumb_width * thumb_height) > 0 && - ( write_thumb == &rtengine::RawImage::jpeg_thumb || - write_thumb == &rtengine::RawImage::ppm_thumb) && - !thumb_load_raw ); + return ((thumb_width * thumb_height) > 0 && + (write_thumb == &rtengine::RawImage::jpeg_thumb || + write_thumb == &rtengine::RawImage::ppm_thumb) && + !thumb_load_raw); } bool RawImage::is_jpegThumb() const { - return ( (thumb_width * thumb_height) > 0 && - write_thumb == &rtengine::RawImage::jpeg_thumb && - !thumb_load_raw ); + return ((thumb_width * thumb_height) > 0 && + write_thumb == &rtengine::RawImage::jpeg_thumb && + !thumb_load_raw); } bool RawImage::is_ppmThumb() const { - return ( (thumb_width * thumb_height) > 0 && - write_thumb == &rtengine::RawImage::ppm_thumb && - !thumb_load_raw ); + return ((thumb_width * thumb_height) > 0 && + write_thumb == &rtengine::RawImage::ppm_thumb && + !thumb_load_raw); } -void RawImage::getXtransMatrix( int XtransMatrix[6][6]) +void RawImage::getXtransMatrix(int XtransMatrix[6][6]) { - for(int row = 0; row < 6; row++) - for(int col = 0; col < 6; col++) { + for (int row = 0; row < 6; row++) + for (int col = 0; col < 6; col++) { XtransMatrix[row][col] = xtrans[row][col]; } } -void RawImage::getRgbCam (float rgbcam[3][4]) +void RawImage::getRgbCam(float rgbcam[3][4]) { - for(int row = 0; row < 3; row++) - for(int col = 0; col < 4; col++) { + for (int row = 0; row < 3; row++) + for (int col = 0; col < 4; col++) { rgbcam[row][col] = rgb_cam[row][col]; } diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 09aaed7ad..871267dac 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -33,11 +33,11 @@ class RawImage: public DCraw { public: - explicit RawImage( const Glib::ustring &name ); + explicit RawImage(const Glib::ustring &name); ~RawImage(); - int loadRaw (bool loadData, unsigned int imageNum = 0, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); - void get_colorsCoeff( float* pre_mul_, float* scale_mul_, float* cblack_, bool forceAutoWB ); + int loadRaw(bool loadData, unsigned int imageNum = 0, bool closeFile = true, ProgressListener *plistener = nullptr, double progressRange = 1.0); + void get_colorsCoeff(float* pre_mul_, float* scale_mul_, float* cblack_, bool forceAutoWB); void set_prefilters() { if (isBayer() && get_colors() == 3) { @@ -55,6 +55,7 @@ public: unsigned int getFrameCount() const { return is_raw; } double getBaselineExposure() const { return RT_baseline_exposure; } + protected: Glib::ustring filename; // complete filename int rotate_deg; // 0,90,180,270 degree of rotation: info taken by dcraw from exif @@ -115,8 +116,8 @@ public: eSensorType getSensorType() const; - void getRgbCam (float rgbcam[3][4]); - void getXtransMatrix ( int xtransMatrix[6][6]); + void getRgbCam(float rgbcam[3][4]); + void getXtransMatrix(int xtransMatrix[6][6]); unsigned get_filters() const { return filters; @@ -137,7 +138,7 @@ public: return maximum; } } - unsigned short get_whiteSample( int r, int c ) const + unsigned short get_whiteSample(int r, int c) const { return white[r][c]; } @@ -171,13 +172,13 @@ public: return std::string(model); } - float get_cam_mul(int c )const + float get_cam_mul(int c)const { return cam_mul[c]; } - float get_pre_mul(int c )const + float get_pre_mul(int c)const { - if(std::isfinite(pre_mul[c])) { + if (std::isfinite(pre_mul[c])) { return pre_mul[c]; } else { std::cout << "Failure decoding '" << filename << "', please file a bug report including the raw file and the line below:" << std::endl; @@ -185,7 +186,7 @@ public: return 1.f; } } - float get_rgb_cam( int r, int c) const + float get_rgb_cam(int r, int c) const { return rgb_cam[r][c]; } @@ -258,6 +259,10 @@ public: { return float_raw_image; } + void set_filters(unsigned f) + { + filters = f; + } public: // dcraw functions @@ -267,7 +272,7 @@ public: } public: - bool ISRED (unsigned row, unsigned col) const + bool ISRED(unsigned row, unsigned col) const { return ((filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) == 0); } @@ -275,15 +280,15 @@ public: { return ((filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) == 1); } - bool ISBLUE (unsigned row, unsigned col) const + bool ISBLUE(unsigned row, unsigned col) const { return ((filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) == 2); } - unsigned FC (unsigned row, unsigned col) const + unsigned FC(unsigned row, unsigned col) const { return (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3); } - bool ISXTRANSRED (unsigned row, unsigned col) const + bool ISXTRANSRED(unsigned row, unsigned col) const { return ((xtrans[(row) % 6][(col) % 6]) == 0); } @@ -291,16 +296,16 @@ public: { return ((xtrans[(row) % 6][(col) % 6]) == 1); } - bool ISXTRANSBLUE (unsigned row, unsigned col) const + bool ISXTRANSBLUE(unsigned row, unsigned col) const { return ((xtrans[(row) % 6][(col) % 6]) == 2); } - unsigned XTRANSFC (unsigned row, unsigned col) const + unsigned XTRANSFC(unsigned row, unsigned col) const { return (xtrans[(row) % 6][(col) % 6]); } - unsigned DNGVERSION ( ) const + unsigned DNGVERSION() const { return dng_version; } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 75088a07c..2022f7516 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1161,25 +1161,8 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) double cam_b = imatrices.rgb_cam[2][0] * camwb_red + imatrices.rgb_cam[2][1] * camwb_green + imatrices.rgb_cam[2][2] * camwb_blue; camera_wb = ColorTemp (cam_r, cam_g, cam_b, 1.); // as shot WB - ColorTemp ReferenceWB; - double ref_r, ref_g, ref_b; - { - // ...then we re-get the constants but now with auto which gives us better demosaicing and CA auto-correct - // performance for strange white balance settings (such as UniWB) - ri->get_colorsCoeff(ref_pre_mul, scale_mul, c_black, true); - refwb_red = ri->get_pre_mul(0) / ref_pre_mul[0]; - refwb_green = ri->get_pre_mul(1) / ref_pre_mul[1]; - refwb_blue = ri->get_pre_mul(2) / ref_pre_mul[2]; - initialGain = max(scale_mul[0], scale_mul[1], scale_mul[2], scale_mul[3]) / min(scale_mul[0], scale_mul[1], scale_mul[2], scale_mul[3]); - ref_r = imatrices.rgb_cam[0][0] * refwb_red + imatrices.rgb_cam[0][1] * refwb_green + imatrices.rgb_cam[0][2] * refwb_blue; - ref_g = imatrices.rgb_cam[1][0] * refwb_red + imatrices.rgb_cam[1][1] * refwb_green + imatrices.rgb_cam[1][2] * refwb_blue; - ref_b = imatrices.rgb_cam[2][0] * refwb_red + imatrices.rgb_cam[2][1] * refwb_green + imatrices.rgb_cam[2][2] * refwb_blue; - ReferenceWB = ColorTemp (ref_r, ref_g, ref_b, 1.); - } - if (settings->verbose) { printf("Raw As Shot White balance: temp %f, tint %f\n", camera_wb.getTemp(), camera_wb.getGreen()); - printf("Raw Reference (auto) white balance: temp %f, tint %f, multipliers [%f %f %f | %f %f %f]\n", ReferenceWB.getTemp(), ReferenceWB.getGreen(), ref_r, ref_g, ref_b, refwb_red, refwb_blue, refwb_green); } /*{ @@ -1249,6 +1232,28 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le MyTime t1, t2; t1.set(); + { + // Recalculate the scaling coefficients, using auto WB if selected in the Preprocess WB param. + // Auto WB gives us better demosaicing and CA auto-correct performance for strange white balance settings (such as UniWB) + float dummy_cblk[4] = { 0.f }; // Avoid overwriting c_black, see issue #5676 + ri->get_colorsCoeff( ref_pre_mul, scale_mul, dummy_cblk, raw.preprocessWB.mode == RAWParams::PreprocessWB::Mode::AUTO); + + refwb_red = ri->get_pre_mul(0) / ref_pre_mul[0]; + refwb_green = ri->get_pre_mul(1) / ref_pre_mul[1]; + refwb_blue = ri->get_pre_mul(2) / ref_pre_mul[2]; + initialGain = max(scale_mul[0], scale_mul[1], scale_mul[2], scale_mul[3]) / min(scale_mul[0], scale_mul[1], scale_mul[2], scale_mul[3]); + + const double ref_r = imatrices.rgb_cam[0][0] * refwb_red + imatrices.rgb_cam[0][1] * refwb_green + imatrices.rgb_cam[0][2] * refwb_blue; + const double ref_g = imatrices.rgb_cam[1][0] * refwb_red + imatrices.rgb_cam[1][1] * refwb_green + imatrices.rgb_cam[1][2] * refwb_blue; + const double ref_b = imatrices.rgb_cam[2][0] * refwb_red + imatrices.rgb_cam[2][1] * refwb_green + imatrices.rgb_cam[2][2] * refwb_blue; + const ColorTemp ReferenceWB = ColorTemp (ref_r, ref_g, ref_b, 1.); + + if (settings->verbose) { + printf("Raw Reference white balance: temp %f, tint %f, multipliers [%f %f %f | %f %f %f]\n", ReferenceWB.getTemp(), ReferenceWB.getGreen(), ref_r, ref_g, ref_b, refwb_red, refwb_blue, refwb_green); + } + } + + Glib::ustring newDF = raw.dark_frame; RawImage *rid = nullptr; @@ -2253,15 +2258,8 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara } float R, G, B; -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else //gamut control : Lab values are in gamut Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); -#endif @@ -2402,10 +2400,11 @@ void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp) */ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile, array2D &rawData) { - const float black[4] = { - static_cast(ri->get_cblack(0)), static_cast(ri->get_cblack(1)), - static_cast(ri->get_cblack(2)), static_cast(ri->get_cblack(3)) - }; + const auto tmpfilters = ri->get_filters(); + ri->set_filters(ri->prefilters); // we need 4 blacks for bayer processing + float black[4]; + ri->get_colorsCoeff(nullptr, nullptr, black, false); + ri->set_filters(tmpfilters); if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) { if (!rawData) { @@ -4425,17 +4424,17 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double 1) for the current raw file we create a table for each temp of RGB multipliers 2) then, I choose the "camera temp" to initialize calculation (why not) - 3) for this temp, I calculated XYZ values for the 201 spectral datas + 3) for this temp, I calculated XYZ values for the 201 spectral data 4) then I create for the image an "histogram", but for xyY (CIE 1931 color space or CIE 1964 (default)) - 5) for each pixel (in fact to accelerate only 1/5 for and 1/5 for y), I determine for each couple xy, the number of occurences, can be change by Itcwb_precis to 3 or 9 + 5) for each pixel (in fact to accelerate only 1/5 for and 1/5 for y), I determine for each couple xy, the number of occurrences, can be change by Itcwb_precis to 3 or 9 6) I sort this result in ascending order 7) in option we can sort in another manner to take into account chroma : chromax = x - white point x, chromay = y - white point y - 8) then I compare this result, with spectral datas found above in 3) with deltaE (limited to chroma) - 9) at this point we have xyY values that match Camera temp, and spectral datas associated + 8) then I compare this result, with spectral data found above in 3) with deltaE (limited to chroma) + 9) at this point we have xyY values that match Camera temp, and spectral data associated 10) then I recalculate RGB values from xyY histogram 11) after, I vary temp, between 2000K to 12000K 12) RGB values are recalculated from 10) with RGB multipliers, and then xyY are calculated for each temp - 13) spectral datas choose are recalculated with temp between 2000K to 12000K with matrix spectral calculation, that leads to xyY values + 13) spectral data choose are recalculated with temp between 2000K to 12000K with matrix spectral calculation, that leads to xyY values 14) I calculated for each couple xy, Student correlation (without Snedecor test) 15) the good result, is the best correlation 16) we have found the best temperature where color image and color references are correlate @@ -4992,7 +4991,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double chrom wbchro[sizcu4]; const float swpr = Txyz[repref].XX + Txyz[repref].ZZ + 1.f; - const float xwpr = Txyz[repref].XX / swpr;//white point for tt in xy coordiantes + const float xwpr = Txyz[repref].XX / swpr;//white point for tt in xy coordinates const float ywpr = 1.f / swpr; for (int i = 0; i < sizcu4; ++i) { //take the max values @@ -5023,7 +5022,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double std::sort(wbchro, wbchro + sizcu4, wbchro[0]); } - const int maxval = rtengine::LIM(settings->itcwb_thres, 10, 55);//max values of color to find correllation + const int maxval = rtengine::LIM(settings->itcwb_thres, 10, 55);//max values of color to find correlation sizcurr2ref = rtengine::min(sizcurr2ref, maxval); //keep about the biggest values, @@ -5037,7 +5036,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } } - //calculate deltaE xx to find best values of spectrals datas - limited to chroma values + //calculate deltaE xx to find best values of spectrals data - limited to chroma values int maxnb = rtengine::LIM(settings->itcwb_sizereference, 1, 5); if (settings->itcwb_thres > 55) { @@ -5205,8 +5204,8 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double reff_spect_xxyy[2 * kkg + 1][tt] = reff_spect_xxyy_prov[2 * i + 1][tt]; } } - //now we have good spectral datas - //claculate student correlation + //now we have good spectral data + //calculate student correlation const float abstudgr = std::fabs(studentXY(xxyycurr_reduc, reff_spect_xxyy, 2 * w, 2 * kkg, tt)); if (abstudgr < minstudgr) { // find the minimum Student diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 770c18ae3..3c19efd67 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -46,7 +46,7 @@ private: static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); static void colorSpaceConversion_ (Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); - int defTransform (int tran); + int defTransform (int tran); protected: MyMutex getImageMutex; // locks getImage @@ -107,10 +107,10 @@ protected: std::vector histMatchingCache; const std::unique_ptr histMatchingParams; - void processFalseColorCorrectionThread (Imagefloat* im, array2D &rbconv_Y, array2D &rbconv_I, array2D &rbconv_Q, array2D &rbout_I, array2D &rbout_Q, const int row_from, const int row_to); - void hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax); - void transformRect (const PreviewProps &pp, int tran, int &sx1, int &sy1, int &width, int &height, int &fw); - void transformPosition (int x, int y, int tran, int& tx, int& ty); + void processFalseColorCorrectionThread(Imagefloat* im, array2D &rbconv_Y, array2D &rbconv_I, array2D &rbconv_Q, array2D &rbout_I, array2D &rbout_Q, const int row_from, const int row_to); + void hlRecovery(const std::string &method, float* red, float* green, float* blue, int width, float* hlmax); + void transformRect(const PreviewProps &pp, int tran, int &sx1, int &sy1, int &width, int &height, int &fw); + void transformPosition(int x, int y, int tran, int& tx, int& ty); void ItcWB(bool extra, double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::WBParams & wbpar); unsigned FC(int row, int col) const; @@ -190,11 +190,11 @@ public: void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); - static void colorSpaceConversion (Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName) + static void colorSpaceConversion(Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName) { - colorSpaceConversion_ (im, cmp, wb, pre_mul, embedded, camprofile, cam, camName); + colorSpaceConversion_(im, cmp, wb, pre_mul, embedded, camprofile, cam, camName); } - static void inverse33 (const double (*coeff)[3], double (*icoeff)[3]); + static void inverse33(const double (*coeff)[3], double (*icoeff)[3]); void MSR(float** luminance, float **originalLuminance, float **exLuminance, const LUTf& mapcurve, bool mapcontlutili, int width, int height, const procparams::RetinexParams &deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); void HLRecovery_inpaint (float** red, float** green, float** blue) override; @@ -232,10 +232,10 @@ public: protected: typedef unsigned short ushort; - void processFalseColorCorrection (Imagefloat* i, const int steps); - inline void convert_row_to_YIQ (const float* const r, const float* const g, const float* const b, float* Y, float* I, float* Q, const int W); - inline void convert_row_to_RGB (float* r, float* g, float* b, const float* const Y, const float* const I, const float* const Q, const int W); - inline void convert_to_RGB (float &r, float &g, float &b, const float Y, const float I, const float Q); + void processFalseColorCorrection(Imagefloat* i, const int steps); + inline void convert_row_to_YIQ(const float* const r, const float* const g, const float* const b, float* Y, float* I, float* Q, const int W); + inline void convert_row_to_RGB(float* r, float* g, float* b, const float* const Y, const float* const I, const float* const Q, const int W); + inline void convert_to_RGB(float &r, float &g, float &b, const float Y, const float I, const float Q); inline void interpolate_row_g (float* agh, float* agv, int i); inline void interpolate_row_rb (float* ar, float* ab, float* pg, float* cg, float* ng, int i); @@ -265,7 +265,7 @@ protected: int findZeroPixels(PixelsMap &bpMap) const; void cfa_linedn (float linenoiselevel, bool horizontal, bool vertical, const CFALineDenoiseRowBlender &rowblender);//Emil's line denoise - void green_equilibrate_global (array2D &rawData); + void green_equilibrate_global(array2D &rawData); void green_equilibrate (const GreenEqulibrateThreshold &greenthresh, array2D &rawData);//Emil's green equilibration void nodemosaic(bool bw); @@ -282,8 +282,8 @@ protected: void rcd_demosaic(size_t chunkSize = 1, bool measure = false); void border_interpolate(int winw, int winh, int lborders, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border); - void fill_raw( float (*cache )[3], int x0, int y0, float** rawData); - void fill_border( float (*cache )[3], int border, int x0, int y0); + void fill_raw(float (*cache)[3], int x0, int y0, float** rawData); + void fill_border(float (*cache)[3], int border, int x0, int y0); void copy_to_buffer(float (*image2)[2], float (*image)[3]); void dcb_hid(float (*image)[3], int x0, int y0); void dcb_color(float (*image)[3], int x0, int y0); @@ -295,7 +295,7 @@ protected: void restore_from_buffer(float (*image)[3], float (*image2)[2]); void dcb_refinement(float (*image)[3], uint8_t *map, int x0, int y0); void dcb_color_full(float (*image)[3], int x0, int y0, float (*chroma)[2]); - void cielab (const float (*rgb)[3], float* l, float* a, float *b, const int width, const int height, const int labWidth, const float xyz_cam[3][3]); + void cielab(const float (*rgb)[3], float* l, float* a, float *b, const int width, const int height, const int labWidth, const float xyz_cam[3][3]); void xtransborder_interpolate (int border, array2D &red, array2D &green, array2D &blue); void xtrans_interpolate (const int passes, const bool useCieLab, size_t chunkSize = 1, bool measure = false); void fast_xtrans_interpolate (const array2D &rawData, array2D &red, array2D &green, array2D &blue); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index b77eac29c..773ec8b68 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -74,7 +74,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { 0, // EvLDNEdgeTolerance: obsolete, 0, // EvCDNEnabled:obsolete, 0, // free entry - RGBCURVE|M_AUTOEXP, // EvDCPToneCurve, + RGBCURVE | M_AUTOEXP, // EvDCPToneCurve, ALLNORAW, // EvDCPIlluminant, RETINEX, // EvSHEnabled, RGBCURVE, // EvSHHighlights, @@ -419,8 +419,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DIRPYREQUALIZER, // EvWavgreenlow DIRPYREQUALIZER, // EvWavbluelow DIRPYREQUALIZER, // EvWavNeutral - RGBCURVE|M_AUTOEXP, // EvDCPApplyLookTable, - RGBCURVE|M_AUTOEXP, // EvDCPApplyBaselineExposureOffset, + RGBCURVE | M_AUTOEXP, // EvDCPApplyLookTable, + RGBCURVE | M_AUTOEXP, // EvDCPApplyBaselineExposureOffset, ALLNORAW, // EvDCPApplyHueSatMap DIRPYREQUALIZER, // EvWavenacont DIRPYREQUALIZER, // EvWavenachrom @@ -470,7 +470,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvRetinexgaintransmission RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens - ALLNORAW, // EvWBtempBias + ALLNORAW, // EvWBtempBias DARKFRAME, // EvRawImageNum 0, // unused 0, // unused @@ -521,7 +521,439 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RGBCURVE, // EvRGBEnabled LUMINANCECURVE, // EvLEnabled DEMOSAIC, // EvPdShrEnabled - CAPTURESHARPEN // EvPdShrMaskToggled + CAPTURESHARPEN, // EvPdShrMaskToggled + LUMINANCECURVE, // EvLocallabSpotDeleted + M_VOID, // EvLocallabSpotSelected + M_VOID, // EvLocallabSpotName + M_VOID, // EvLocallabSpotVisibility + LUMINANCECURVE, // EvLocallabSpotShape + LUMINANCECURVE, // EvLocallabSpotSpotMethod + LUMINANCECURVE, // EvLocallabSpotShapeMethod + LUMINANCECURVE, // EvLocallabSpotLocX + LUMINANCECURVE, // EvLocallabSpotLocXL + LUMINANCECURVE, // EvLocallabSpotLocY + LUMINANCECURVE, // EvLocallabSpotLocYT + LUMINANCECURVE, // EvLocallabSpotCenter + LUMINANCECURVE, // EvLocallabSpotCircrad + LUMINANCECURVE, // EvLocallabSpotQualityMethod + LUMINANCECURVE, // EvLocallabSpotTransit + LUMINANCECURVE, // EvLocallabSpotThresh + LUMINANCECURVE, // EvLocallabSpotIter + LUMINANCECURVE, // EvLocallabSpotSensiexclu + LUMINANCECURVE, // EvLocallabSpotStruc + LUMINANCECURVE, // EvlocallabEnabled + LUMINANCECURVE, // EvLocenacolor + LUMINANCECURVE, // Evlocallabcurvactiv + LUMINANCECURVE, // Evlocallablightness + LUMINANCECURVE, // Evlocallabcontrast + LUMINANCECURVE, // Evlocallabchroma + LUMINANCECURVE, // Evlocallabsensi + LUMINANCECURVE, // EvlocallabqualitycurveMethod + LUMINANCECURVE, // Evlocallabllshape + LUMINANCECURVE, // Evlocallabccshape + LUMINANCECURVE, // EvlocallabLHshape + LUMINANCECURVE, // EvlocallabHHshape + LUMINANCECURVE, // Evlocallabinvers + LUMINANCECURVE, // EvLocenaexpose + LUMINANCECURVE, // Evlocallabexpcomp + LUMINANCECURVE, // Evlocallabhlcompr + LUMINANCECURVE, // Evlocallabhlcomprthresh + LUMINANCECURVE, // Evlocallabblack + LUMINANCECURVE, // Evlocallabshcompr + LUMINANCECURVE, // Evlocallabwarm + LUMINANCECURVE, // Evlocallabsensiex + LUMINANCECURVE, // Evlocallabshapeexpos + LUMINANCECURVE, // EvLocenavibrance + LUMINANCECURVE, // EvlocallabSaturated + LUMINANCECURVE, // EvlocallabPastels + LUMINANCECURVE, // EvlocallabPastSatThreshold + LUMINANCECURVE, // EvlocallabProtectSkins + LUMINANCECURVE, // EvlocallabAvoidColorShift + LUMINANCECURVE, // EvlocallabPastSatTog + LUMINANCECURVE, // Evlocallabsensiv + LUMINANCECURVE, // EvlocallabSkinTonesCurve + LUMINANCECURVE, // EvLocenablur + LUMINANCECURVE, // Evlocallabradius + LUMINANCECURVE, // Evlocallabstrength + LUMINANCECURVE, // Evlocallabsensibn + LUMINANCECURVE, // EvlocallabblurMethod + LUMINANCECURVE, // Evlocallabactivlum + LUMINANCECURVE, // EvLocenatonemap + LUMINANCECURVE, // Evlocallabstren + LUMINANCECURVE, // Evlocallabgamma + LUMINANCECURVE, // Evlocallabestop + LUMINANCECURVE, // Evlocallabscaltm + LUMINANCECURVE, // Evlocallabrewei + LUMINANCECURVE, // Evlocallabsensitm + LUMINANCECURVE, // EvLocenareti + LUMINANCECURVE, // EvlocallabretinexMethod + LUMINANCECURVE, // Evlocallabstr + LUMINANCECURVE, // Evlocallabchrrt + LUMINANCECURVE, // Evlocallabneigh + LUMINANCECURVE, // Evlocallabvart + LUMINANCECURVE, // Evlocallabsensih + LUMINANCECURVE, // EvlocallabCTgainCurve + LUMINANCECURVE, // Evlocallabinversret + LUMINANCECURVE, // EvLocenasharp + LUMINANCECURVE, // Evlocallabsharradius + LUMINANCECURVE, // Evlocallabsharamount + LUMINANCECURVE, // Evlocallabshardamping + LUMINANCECURVE, // Evlocallabshariter + LUMINANCECURVE, // Evlocallabsensis + LUMINANCECURVE, // Evlocallabinverssha + LUMINANCECURVE, // EvLocenacbdl + LUMINANCECURVE, // EvlocallabEqualizer + LUMINANCECURVE, // Evlocallabchromacbdl + LUMINANCECURVE, // EvlocallabThresho + LUMINANCECURVE, // Evlocallabsensicb + LUMINANCECURVE, // EvLocenadenoi + LUMINANCECURVE, // Evlocallabnoiselumf + LUMINANCECURVE, // Evlocallabnoiselumc + LUMINANCECURVE, // Evlocallabnoiselumdetail + LUMINANCECURVE, // Evlocallabnoiselequal + LUMINANCECURVE, // Evlocallabnoisechrof + LUMINANCECURVE, // Evlocallabnoisechroc + LUMINANCECURVE, // Evlocallabnoisechrodetail + LUMINANCECURVE, // Evlocallabadjblur + LUMINANCECURVE, // Evlocallabbilateral + LUMINANCECURVE, // Evlocallabsensiden + LUMINANCECURVE, // Evlocallabavoid + LUMINANCECURVE, // Evlocallabsharcontrast + LUMINANCECURVE, // EvLocenacontrast + LUMINANCECURVE, // Evlocallablcradius + LUMINANCECURVE, // Evlocallablcamount + LUMINANCECURVE, // Evlocallablcdarkness + LUMINANCECURVE, // Evlocallablclightness + LUMINANCECURVE, // Evlocallabsensilc + LUMINANCECURVE, // Evlocallabdehaz + LUMINANCECURVE, // EvLocenasoft + LUMINANCECURVE, // EvLocallabstreng + LUMINANCECURVE, // EvLocallabsensisf + LUMINANCECURVE, // Evlocallabsharblur + LUMINANCECURVE, // EvLocenalabregion + LUMINANCECURVE, // EvlocallabshowmaskMethod + LUMINANCECURVE, // EvLocallabSpotSelectedWithMask + LUMINANCECURVE, // EvlocallabCCmaskshape + LUMINANCECURVE, // EvlocallabLLmaskshape + LUMINANCECURVE, // EvlocallabCCmaskexpshape + LUMINANCECURVE, // EvlocallabLLmaskexpshape + LUMINANCECURVE, // EvlocallabHHmaskshape + LUMINANCECURVE, // Evlocallabstructcol + LUMINANCECURVE, // Evlocallabstructexp + LUMINANCECURVE, // EvlocallabHHmaskexpshape + LUMINANCECURVE, // Evlocallabblendmaskcol + LUMINANCECURVE, // Evlocallabblendmaskexp + LUMINANCECURVE, // Evlocallabblurexpde + LUMINANCECURVE, // EvLocallabEnaColorMask + LUMINANCECURVE, // EvLocallabEnaExpMask + LUMINANCECURVE, // Evlocallabblurcolde + LUMINANCECURVE, // Evlocallabinversex + LUMINANCECURVE, // Evlocallabstructexclu + LUMINANCECURVE, // Evlocallabexpchroma + LUMINANCECURVE, // EvLocallabLabGridValue + LUMINANCECURVE, // EvLocallabLabstrengthgrid + LUMINANCECURVE, // EvLocallabgridMethod + LUMINANCECURVE, // EvLocenashadhigh + LUMINANCECURVE, // EvLocallabhighlights + LUMINANCECURVE, // EvLocallabh_tonalwidth + LUMINANCECURVE, // EvLocallabshadows + LUMINANCECURVE, // EvLocallabs_tonalwidth + LUMINANCECURVE, // EvLocallabsh_radius + LUMINANCECURVE, // EvLocallabsensihs + LUMINANCECURVE, // Evlocallabradmaskcol + LUMINANCECURVE, // Evlocallabradmaskexp + LUMINANCECURVE, // EvlocallabToolAdded + LUMINANCECURVE, // EvlocallabCCmaskSHshape + LUMINANCECURVE, // EvlocallabLLmaskSHshape + LUMINANCECURVE, // EvlocallabHHmaskSHshape + LUMINANCECURVE, // EvlocallabblendmaskSH + LUMINANCECURVE, // EvLocallabEnaSHMask + LUMINANCECURVE, // EvlocallabradmaskSH + LUMINANCECURVE, // EvlocallabblurSHde + LUMINANCECURVE, // Evlocallabinverssh + LUMINANCECURVE, // EvLocallabSpotbalan + LUMINANCECURVE, // EvLocallabchromaskexp + LUMINANCECURVE, // EvLocallabgammaskexp + LUMINANCECURVE, // EvLocallabslomaskexp + LUMINANCECURVE, // EvLocallabsoftradiusexp + LUMINANCECURVE, // EvLocallabchromaskcol + LUMINANCECURVE, // EvLocallabgammaskcol + LUMINANCECURVE, // EvLocallabslomaskcol + LUMINANCECURVE, // EvLocallabchromaskSH + LUMINANCECURVE, // EvLocallabgammaskSH + LUMINANCECURVE, // EvLocallabslomaskSH + LUMINANCECURVE, // EvLocallabsoftradiuscol + LUMINANCECURVE, // EvLocallabsoftradiusret + LUMINANCECURVE, // EvLocallabsoftradiuscb + LUMINANCECURVE, // EvLocallabSpotTransitweak + LUMINANCECURVE, // EvLocallabclarityml + LUMINANCECURVE, // EvLocallabcontresid + LUMINANCECURVE, // Evlocallabnoiselumf0 + LUMINANCECURVE, // Evlocallabnoiselumf2 + LUMINANCECURVE, // Evlocallabblurcbdl + LUMINANCECURVE, // Evlocallabblendmaskcb + LUMINANCECURVE, // Evlocallabradmaskcb + LUMINANCECURVE, // Evlocallabchromaskcb + LUMINANCECURVE, // Evlocallabgammaskcb + LUMINANCECURVE, // Evlocallabslomaskcb + LUMINANCECURVE, // EvlocallabCCmaskcbshape + LUMINANCECURVE, // EvlocallabLLmaskcbshape + LUMINANCECURVE, // EvlocallabHHmaskcbshape + LUMINANCECURVE, // EvLocallabEnacbMask + M_VOID, // EvlocallabToolRemovedWithoutRefresh + LUMINANCECURVE, // Evlocallabsoftradiustm + LUMINANCECURVE, // EvLocallabSpotTransitgrad + LUMINANCECURVE, // Evlocallabamount + LUMINANCECURVE, // Evlocallabsatur + LUMINANCECURVE, // EvlocallabCCmaskretishape + LUMINANCECURVE, // EvlocallabLLmaskretishape + LUMINANCECURVE, // EvlocallabHHmaskretishape + LUMINANCECURVE, // EvLocallabEnaretiMask + LUMINANCECURVE, // Evlocallabblendmaskreti + LUMINANCECURVE, // Evlocallabradmaskreti + LUMINANCECURVE, // Evlocallabchromaskreti + LUMINANCECURVE, // Evlocallabgammaskreti + LUMINANCECURVE, // Evlocallabslomaskreti + LUMINANCECURVE, // EvlocallabToolRemovedWithRefresh + LUMINANCECURVE, // EvLocallabEnaretiMasktmap + LUMINANCECURVE, // Evlocallabscalereti + LUMINANCECURVE, // Evlocallabdarkness + LUMINANCECURVE, // Evlocallablightnessreti + LUMINANCECURVE, // Evlocallablimd + LUMINANCECURVE, // Evlocallablaplace + LUMINANCECURVE, // EvlocallabsoftMethod + LUMINANCECURVE, // Evlocallabequilret + LUMINANCECURVE, // Evlocallabequiltm + LUMINANCECURVE, // Evlocallabfftwlc + LUMINANCECURVE, // Evlocallabfftwreti + LUMINANCECURVE, // EvlocallabshowmasksoftMethod + LUMINANCECURVE, // Evlocallabshadex + LUMINANCECURVE, // EvlocallabexpMethod + LUMINANCECURVE, // EvLocallablaplacexp + LUMINANCECURVE, // EvLocallabbalanexp + LUMINANCECURVE, // EvLocallablinear + LUMINANCECURVE, // EvlocallabCCmasktmshape + LUMINANCECURVE, // EvlocallabLLmasktmshape + LUMINANCECURVE, // EvlocallabHHmasktmshape + LUMINANCECURVE, // EvLocallabEnatmMask + LUMINANCECURVE, // Evlocallabblendmasktm + LUMINANCECURVE, // Evlocallabradmasktm + LUMINANCECURVE, // Evlocallabchromasktm + LUMINANCECURVE, // Evlocallabgammasktm + LUMINANCECURVE, // Evlocallabslomasktm + LUMINANCECURVE, // EvlocallabshowmasktmMethod + LUMINANCECURVE, // EvlocallablocalcontMethod + LUMINANCECURVE, // Evlocallabwavcurve + LUMINANCECURVE, // Evlocallablevelwav + LUMINANCECURVE, // Evlocallabresidcont + LUMINANCECURVE, // EvlocallabCCmaskblshape + LUMINANCECURVE, // EvlocallabLLmaskblshape + LUMINANCECURVE, // EvlocallabHHmaskblshape + LUMINANCECURVE, // EvLocallabEnablMask + LUMINANCECURVE, // EvlocallabshowmaskblMethod + LUMINANCECURVE, // Evlocallabblendmaskbl + LUMINANCECURVE, // Evlocallabradmaskbl + LUMINANCECURVE, // Evlocallabchromaskbl + LUMINANCECURVE, // Evlocallabgammaskbl + LUMINANCECURVE, // Evlocallabslomaskbl + LUMINANCECURVE, // EvlocallabblMethod + LUMINANCECURVE, // EvlocallabmedMethod + LUMINANCECURVE, // Evlocallabitera + LUMINANCECURVE, // Evlocallabguidbl + LUMINANCECURVE, // Evlocallabepsbl + LUMINANCECURVE, // EvlocallabshowmaskcolMethodinv + LUMINANCECURVE, // EvlocallabshowmaskexpMethodinv + LUMINANCECURVE, // EvlocallabshowmaskSHMethodinv + LUMINANCECURVE, // Evlocallabclarilres + LUMINANCECURVE, // Evlocallabclarisoft + LUMINANCECURVE, // Evlocallabclaricres + LUMINANCECURVE, // Evlocallabresidchro + LUMINANCECURVE, // Evlocallabgamm + LUMINANCECURVE, // Evlocallabfatamount + LUMINANCECURVE, // Evlocallabfatdetail + LUMINANCECURVE, // Evlocallabfatanchor + LUMINANCECURVE, // Evlocallabfatlevel + LUMINANCECURVE, // EvlocallabSpotCreated + LUMINANCECURVE, // EvlocallabexnoiseMethod + LUMINANCECURVE, // Evlocallabdepth + LUMINANCECURVE, // Evlocallabloglin + LUMINANCECURVE, // Evlocallablumonly + LUMINANCECURVE, // Evlocallaboffs + LUMINANCECURVE, // EvlocallabCTtransCurve + LUMINANCECURVE, // Evlocallabcliptm + LUMINANCECURVE, // Evlocallabenatmmaskaft + LUMINANCECURVE, // EvlocallabenaExpmaskaft + LUMINANCECURVE, // Evlocallablapmasktm + LUMINANCECURVE, // Evlocallablapmaskreti + LUMINANCECURVE, // Evlocallablapmaskexp + LUMINANCECURVE, // Evlocallablapmaskcol + LUMINANCECURVE, // EvlocallablapmaskSH + LUMINANCECURVE, // Evlocallablapmaskcb + LUMINANCECURVE, // Evlocallablapmaskbl + LUMINANCECURVE, // Evlocallablaplac + LUMINANCECURVE, // Evlocallabdetailthr + LUMINANCECURVE, // Evlocallabfftwbl + LUMINANCECURVE, // Evlocallabisogr + LUMINANCECURVE, // Evlocallabstrengr + LUMINANCECURVE, // Evlocallabscalegr + LUMINANCECURVE, // EvlocallabLmaskshape + LUMINANCECURVE, // EvlocallabLmaskexpshape + LUMINANCECURVE, // EvlocallabLmaskSHshape + LUMINANCECURVE, // EvlocallabLmasktmshape + LUMINANCECURVE, // EvlocallabLmaskretishape + LUMINANCECURVE, // EvlocallabLmaskcbshape + LUMINANCECURVE, // EvlocallabLmaskblshape + LUMINANCECURVE, // EvlocallabLLmaskblshapewav + LUMINANCECURVE, // Evlocallabshadmaskbl + LUMINANCECURVE, // EvlocallabLLmaskcolshapewav + LUMINANCECURVE, // Evlocallabshadmaskcol + LUMINANCECURVE, // EvlocallabcsThreshold + LUMINANCECURVE, // EvlocallabcsThresholdblur + LUMINANCECURVE, // EvlocallabcsThresholdcol + LUMINANCECURVE, // Evlocallabdeltae + LUMINANCECURVE, // EvLocallabSpotscopemask + LUMINANCECURVE, // EvlocallabshMethod + LUMINANCECURVE, // EvlocallabEqualizersh + LUMINANCECURVE, // EvlocallabdetailSH + LUMINANCECURVE, // EvlocallabfatamountSH + LUMINANCECURVE, // EvlocallabfatanchorSH + LUMINANCECURVE, // Evlocallabshortc + LUMINANCECURVE, // EvLocallabSpotlumask + LUMINANCECURVE, // EvlocallabgamSH + LUMINANCECURVE, // EvlocallabsloSH + LUMINANCECURVE, // Evlocallabsavrest + LUMINANCECURVE, // Evlocallabrecurs + LUMINANCECURVE, // EvLocallabmergecolMethod + LUMINANCECURVE, // EvLocallabopacol + LUMINANCECURVE, // Evlocallabrgbshape + LUMINANCECURVE, // EvLocallabtoneMethod + LUMINANCECURVE, // EvLocallabspecial + LUMINANCECURVE, // EvLocallabconthrcol + LUMINANCECURVE, // EvLocallabmerMethod + LUMINANCECURVE, // EvLocallabstrumaskcol + LUMINANCECURVE, // EvLocallabstrumaskbl + LUMINANCECURVE, // EvLocallabtoolcol + LUMINANCECURVE, // Evlocallabtoolbl + LUMINANCECURVE, // EvlocallabHHhmaskshape + LUMINANCECURVE, // EvlocallabCCmaskvibshape + LUMINANCECURVE, // EvlocallabLLmaskvibshape + LUMINANCECURVE, // EvlocallabHHmaskvibshape + LUMINANCECURVE, // EvlocallabshowmaskvibMethod + LUMINANCECURVE, // EvLocallabEnavibMask + LUMINANCECURVE, // Evlocallabblendmaskvi + LUMINANCECURVE, // Evlocallabradmaskvib + LUMINANCECURVE, // Evlocallabchromaskvib + LUMINANCECURVE, // Evlocallabgammaskvib + LUMINANCECURVE, // Evlocallabslomaskvib + LUMINANCECURVE, // Evlocallablapmaskvib + LUMINANCECURVE, // EvlocallabLmaskvibshape + LUMINANCECURVE, // EvLocallabLabGridmergValue + LUMINANCECURVE, // EvLocallabmercol + LUMINANCECURVE, // EvLocallabmerlucol + LUMINANCECURVE, // Evlocallabstrmaskexp + LUMINANCECURVE, // Evlocallabangmaskexp + LUMINANCECURVE, // Evlocallabstrexp + LUMINANCECURVE, // Evlocallabangexp + LUMINANCECURVE, // EvlocallabstrSH + LUMINANCECURVE, // EvlocallabangSH + LUMINANCECURVE, // Evlocallabstrcol + LUMINANCECURVE, // Evlocallabangcol + LUMINANCECURVE, // Evlocallabstrcolab + LUMINANCECURVE, // EvLocallabSpotfeather + LUMINANCECURVE, // Evlocallabstrcolh + LUMINANCECURVE, // Evlocallabstrvib + LUMINANCECURVE, // Evlocallabangvib + LUMINANCECURVE, // Evlocallabstrvibab + LUMINANCECURVE, // Evlocallabstrvibh + LUMINANCECURVE, // EvLocallabSpotcomplexMethod + LUMINANCECURVE, // Evlocallabclshape + LUMINANCECURVE, // Evlocallablcshape + LUMINANCECURVE, // Evlocallabblurcol + LUMINANCECURVE, // Evlocallabcontcol + LUMINANCECURVE, // EvLocallabfftColorMask + RGBCURVE | M_AUTOEXP, // EvLocenalog + AUTOEXP, // EvLocallabAuto + LUMINANCECURVE, // EvlocallabsourceGray + AUTOEXP, // EvlocallabsourceGrayAuto + AUTOEXP, // EvlocallabAutoGray + LUMINANCECURVE, // EvlocallabblackEv + LUMINANCECURVE, // EvlocallabwhiteEv + LUMINANCECURVE, // EvlocallabtargetGray + LUMINANCECURVE, // Evlocallabdetail + LUMINANCECURVE, // Evlocallabsensilog + AUTOEXP, // Evlocallabfullimage + LUMINANCECURVE, // Evlocallabbaselog + LUMINANCECURVE, // Evlocallabresidblur + LUMINANCECURVE, // Evlocallabblurlc + LUMINANCECURVE, // Evlocallablevelblur + LUMINANCECURVE, // EvlocallabwavCurvelev + LUMINANCECURVE, // EvlocallabwavCurvecon + LUMINANCECURVE, // Evlocallabsigma + LUMINANCECURVE, // Evlocallaboriglc + LUMINANCECURVE, // Evlocallabsigmadc + LUMINANCECURVE, // Evlocallabdeltad + LUMINANCECURVE, // EvlocallabwavCurvecomp + LUMINANCECURVE, // Evlocallabfatres + LUMINANCECURVE, // EvLocallabSpotbalanh + LUMINANCECURVE, // EvlocallabwavCurveden + LUMINANCECURVE, // EvlocallabHHmasklcshape + LUMINANCECURVE, // EvlocallabCCmasklcshape + LUMINANCECURVE, // EvlocallabLLmasklcshape + LUMINANCECURVE, // EvlocallabEnalcMask + LUMINANCECURVE, // EvlocallabshowmasklcMethod + LUMINANCECURVE, // Evlocallabblendmasklc + LUMINANCECURVE, // Evlocallabradmasklc + LUMINANCECURVE, // Evlocallabchromasklc + LUMINANCECURVE, // EvlocallabLmasklcshape + LUMINANCECURVE, // Evlocallabchromalev + LUMINANCECURVE, // Evlocallabchromablu + LUMINANCECURVE, // Evlocallaboffset + LUMINANCECURVE, // Evlocallabwavblur + LUMINANCECURVE, // Evlocallabwavcont + LUMINANCECURVE, // Evlocallabwavcomp + LUMINANCECURVE, // Evlocallabwavcompre + LUMINANCECURVE, // EvlocallabwavCurvecompre + LUMINANCECURVE, // Evlocallabresidcomp + LUMINANCECURVE, // Evlocallabthreswav + LUMINANCECURVE, // Evlocallabstrwav + LUMINANCECURVE, // Evlocallabangwav + LUMINANCECURVE, // Evlocallabwavgradl + LUMINANCECURVE, // Evlocallabstrlog + LUMINANCECURVE, // Evlocallabanglog + LUMINANCECURVE, // EvLocallabSpotcolorde + LUMINANCECURVE, // EvlocallabshowmasksharMethod + LUMINANCECURVE, // Evlocallabshowreset + LUMINANCECURVE, // Evlocallabstrengthw + LUMINANCECURVE, // Evlocallabradiusw + LUMINANCECURVE, // Evlocallabdetailw + LUMINANCECURVE, // Evlocallabgradw + LUMINANCECURVE, // Evlocallabtloww + LUMINANCECURVE, // Evlocallabthigw + LUMINANCECURVE, // EvlocallabwavCurveedg + LUMINANCECURVE, // EvlocallablocaledgMethod + LUMINANCECURVE, // Evlocallabwavedg + LUMINANCECURVE, // Evlocallabedgw + LUMINANCECURVE, // Evlocallabbasew + LUMINANCECURVE, // EvlocallablocalneiMethod + LUMINANCECURVE, // Evlocallabwaveshow + LUMINANCECURVE, // EvLocallabSpotwavMethod + LUMINANCECURVE, // EvlocallabchroMethod + LUMINANCECURVE, // Evlocallabstrbl + LUMINANCECURVE, // Evlocallabsigmadr + LUMINANCECURVE, // Evlocallabsigmabl + LUMINANCECURVE, // Evlocallabsigmaed + LUMINANCECURVE, // Evlocallabresidsha + LUMINANCECURVE, // Evlocallabresidshathr + LUMINANCECURVE, // Evlocallabresidhi + LUMINANCECURVE, // Evlocallabresidhithr + LUMINANCECURVE, // Evlocallabsigmalc + LUMINANCECURVE, // Evlocallabsigmalc2 + LUMINANCECURVE, // Evlocallabblwh + LUMINANCECURVE, // EvlocallabcomplexityWithRefresh + M_VOID, // EvlocallabcomplexityWithoutRefresh + LUMINANCECURVE, // EvLocallabSpotcolorscope + LUMINANCECURVE, //EvlocallabshowmasktypMethod + LUMINANCECURVE // Evlocallabshadmaskblsha }; @@ -553,6 +985,7 @@ void RefreshMapper::mapEvent(ProcEvent event, int action) int RefreshMapper::getAction(ProcEvent event) const { auto it = actions_.find(event); + if (it == actions_.end()) { return 0; } else { diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h index 81147fd75..a72a7c56b 100644 --- a/rtengine/rt_algo.h +++ b/rtengine/rt_algo.h @@ -25,4 +25,8 @@ namespace rtengine { void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multiThread = true); void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, bool autoContrast = false, float ** clipmask = nullptr); +// implemented in tmo_fattal02 +void buildGradientsMask(int W, int H, float **luminance, float **out, + float amount, int nlevels, int detail_level, + float alfa, float beta, bool multithread); } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 028cedec9..7561d68aa 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -35,6 +35,7 @@ #include "../rtgui/threadutils.h" + /** * @file * This file contains the main functionality of the RawTherapee engine. @@ -375,6 +376,32 @@ public: virtual void minmaxChanged(double cdma, double cdmin, double mini, double maxi, double Tmean, double Tsigma, double Tmin, double Tmax) = 0; }; +class LocallabListener +{ +public: + struct locallabRef { + double huer; + double lumar; + double chromar; + }; + + struct locallabRetiMinMax { + double cdma; + double cdmin; + double mini; + double maxi; + double Tmean; + double Tsigma; + double Tmin; + double Tmax; + }; + + virtual ~LocallabListener() = default; + virtual void refChanged(const std::vector &ref, int selspot) = 0; + virtual void minmaxChanged(const std::vector &minmax, int selspot) = 0; + virtual void logencodChanged(const float blackev, const float whiteev, const float sourceg, const float targetg) = 0; +}; + class AutoColorTonListener { public: @@ -522,6 +549,8 @@ public: virtual void updateUnLock() = 0; + virtual void setLocallabMaskVisibility(bool previewDeltaE, int locallColorMask, int locallColorMaskinv, int locallExpMask, int locallExpMaskinv, int locallSHMask, int locallSHMaskinv, int locallvibMask, int locallsoftMask, int locallblMask, int localltmMask, int locallretiMask, int locallsharMask, int localllcMask, int locallcbMask) = 0; + /** Creates and returns a Crop instance that acts as a window on the image * @param editDataProvider pointer to the EditDataProvider that communicates with the EditSubscriber * @return a pointer to the Crop object that handles the image data trough its own pipeline */ @@ -557,6 +586,7 @@ public: virtual void setRetinexListener (RetinexListener* l) = 0; virtual void setWaveletListener (WaveletListener* l) = 0; virtual void setImageTypeListener (ImageTypeListener* l) = 0; + virtual void setLocallabListener (LocallabListener* l) = 0; virtual void setFilmNegListener (FilmNegListener* l) = 0; virtual void setMonitorProfile (const Glib::ustring& monitorProfile, RenderingIntent intent) = 0; diff --git a/rtengine/rtlensfun.cc b/rtengine/rtlensfun.cc index 7ffb9ad33..363819cf7 100644 --- a/rtengine/rtlensfun.cc +++ b/rtengine/rtlensfun.cc @@ -46,7 +46,7 @@ LFModifier::operator bool() const } -void LFModifier::correctDistortion(double &x, double &y, int cx, int cy, double scale) const +void LFModifier::correctDistortion(double &x, double &y, int cx, int cy) const { if (!data_) { return; @@ -67,8 +67,6 @@ void LFModifier::correctDistortion(double &x, double &y, int cx, int cy, double x -= cx; y -= cy; } - x *= scale; - y *= scale; } diff --git a/rtengine/rtlensfun.h b/rtengine/rtlensfun.h index 2f3e4677d..51212c9b9 100644 --- a/rtengine/rtlensfun.h +++ b/rtengine/rtlensfun.h @@ -53,7 +53,7 @@ public: explicit operator bool() const; - void correctDistortion(double &x, double &y, int cx, int cy, double scale) const override; + void correctDistortion(double &x, double &y, int cx, int cy) const override; bool isCACorrectionAvailable() const override; void correctCA(double &x, double &y, int cx, int cy, int channel) const override; void processVignette(int width, int height, float** rawData) const override; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index e8126be36..4ebb95842 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1245,8 +1245,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.firstAnalysis (baseImg, params, hist16); - ipf.dehaze(baseImg); - ipf.ToneMapFattal02(baseImg); + ipf.dehaze(baseImg, params.dehaze); + ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0, 0); // perform transform int origFW; @@ -1413,16 +1413,17 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 16); - ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); - ipf.vibrance (labView); + ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); + + ipf.vibrance (labView, params.vibrance, params.toneCurve.hrenabled, params.icm.workingProfile); ipf.labColorCorrectionRegions(labView); if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || !params.colorappearance.enabled) { ipf.EPDToneMap (labView, 5, 6); } - ipf.softLight(labView); + ipf.softLight(labView, params.softlight); if (params.colorappearance.enabled) { CurveFactory::curveLightBrightColor ( diff --git a/rtengine/settings.h b/rtengine/settings.h index 529336cbc..fde6fa132 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -63,7 +63,7 @@ public: bool gamutICC; // no longer used bool gamutLch; bool HistogramWorking; // true: histogram is display the value of the image computed in the Working profile - // false: histogram is display the value of the image computed in the Output profile + // false: histogram is display the value of the image computed in the Output profile int amchroma; int protectred; double protectredh; @@ -81,6 +81,15 @@ public: double level0_cbdl; double level123_cbdl; Glib::ustring lensfunDbDirectory; // The directory containing the lensfun database. If empty, the system defaults will be used, as described in https://lensfun.github.io/manual/latest/dbsearch.html + int cropsleep; + double reduchigh; + double reduclow; + bool detectshape; + bool fftwsigma; + int previewselection; + double cbdlsensi; +// bool showtooltip; + int itcwb_thres; bool itcwb_sort; int itcwb_greenrange; diff --git a/rtengine/shmap.h b/rtengine/shmap.h index b1b1e5eff..8e8f73c0e 100644 --- a/rtengine/shmap.h +++ b/rtengine/shmap.h @@ -29,6 +29,7 @@ namespace rtengine { class Imagefloat; +class LabImage; class SHMap : public NonCopyable @@ -40,6 +41,7 @@ public: SHMap (int w, int h); ~SHMap (); + void updateLab (LabImage* img, double radius, bool hq, int skip); void update (Imagefloat* img, double radius, double lumi[3], bool hq, int skip); void updateL (float** L, double radius, bool hq, int skip); @@ -47,6 +49,7 @@ public: private: int W, H; + void fillLuminanceLab( LabImage * img, float **luminance); void dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, const LUTf& rangefn, int level, int scale); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 14a594ac2..3c0e0aee8 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -880,8 +880,8 @@ private: ipf.firstAnalysis(baseImg, params, hist16); - ipf.dehaze(baseImg); - ipf.ToneMapFattal02(baseImg); + ipf.dehaze(baseImg, params.dehaze); + ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0, 0); // perform transform (excepted resizing) if (ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData())) { @@ -971,6 +971,8 @@ private: } labView = new LabImage(fw, fh); + reservView = new LabImage(fw, fh); + lastorigView = new LabImage(fw, fh); if (params.blackwhite.enabled) { CurveFactory::curveBW(params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); @@ -1077,6 +1079,323 @@ private: CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1); + + // bool locallutili = false; + // bool localcutili = false; + reservView->CopyFrom(labView); + lastorigView->CopyFrom(labView); + + if (params.locallab.enabled) { + MyTime t1, t2; + t1.set(); + + LUTf huerefs(500, -10000.f); + LUTf sobelrefs(500, -10000.f); + LUTi centerx(500, -10000); + LUTi centery(500, -10000); + LocretigainCurve locRETgainCurve; + LocretitransCurve locRETtransCurve; + LocLHCurve loclhCurve; + LocHHCurve lochhCurve; + LocCCmaskCurve locccmasCurve; + LocLLmaskCurve locllmasCurve; + LocHHmaskCurve lochhmasCurve; + LocHHmaskCurve lochhhmasCurve; + LocCCmaskCurve locccmasexpCurve; + LocLLmaskCurve locllmasexpCurve; + LocHHmaskCurve lochhmasexpCurve; + LocCCmaskCurve locccmasSHCurve; + LocLLmaskCurve locllmasSHCurve; + LocHHmaskCurve lochhmasSHCurve; + LocCCmaskCurve locccmasvibCurve; + LocLLmaskCurve locllmasvibCurve; + LocHHmaskCurve lochhmasvibCurve; + LocCCmaskCurve locccmaslcCurve; + LocLLmaskCurve locllmaslcCurve; + LocHHmaskCurve lochhmaslcCurve; + LocCCmaskCurve locccmascbCurve; + LocLLmaskCurve locllmascbCurve; + LocHHmaskCurve lochhmascbCurve; + LocCCmaskCurve locccmasretiCurve; + LocLLmaskCurve locllmasretiCurve; + LocHHmaskCurve lochhmasretiCurve; + LocCCmaskCurve locccmastmCurve; + LocLLmaskCurve locllmastmCurve; + LocHHmaskCurve lochhmastmCurve; + LocCCmaskCurve locccmasblCurve; + LocLLmaskCurve locllmasblCurve; + LocHHmaskCurve lochhmasblCurve; + LocwavCurve loclmasCurveblwav; + LocwavCurve loclmasCurvecolwav; + LocwavCurve locwavCurve; + LocwavCurve loclevwavCurve; + LocwavCurve locconwavCurve; + LocwavCurve loccompwavCurve; + LocwavCurve loccomprewavCurve; + LocwavCurve locedgwavCurve; + LocwavCurve locwavCurveden; + LUTf lllocalcurve(65536, 0); + LUTf lclocalcurve(65536, 0); + LUTf cllocalcurve(65536, 0); + LUTf cclocalcurve(65536, 0); + LUTf rgblocalcurve(65536, 0); + LUTf hltonecurveloc(65536, 0); + LUTf shtonecurveloc(65536, 0); + LUTf tonecurveloc(65536, 0); + LUTf lightCurveloc(32770, 0); + LUTf exlocalcurve(65536, 0); + LUTf lmasklocalcurve(65536, 0); + LUTf lmaskexplocalcurve(65536, 0); + LUTf lmaskSHlocalcurve(65536, 0); + LUTf lmaskviblocalcurve(65536, 0); + LUTf lmasktmlocalcurve(65536, 0); + LUTf lmaskretilocalcurve(65536, 0); + LUTf lmaskcblocalcurve(65536, 0); + LUTf lmaskbllocalcurve(65536, 0); + LUTf lmasklclocalcurve(65536, 0); + + // int maxspot = 1; + float** shbuffer = nullptr; + + for (size_t sp = 0; sp < params.locallab.spots.size(); sp++) { + if (params.locallab.spots.at(sp).inverssha) { + shbuffer = new float*[fh]; + + for (int i = 0; i < fh; i++) { + shbuffer[i] = new float[fw]; + } + } + + // Set local curves of current spot to LUT + bool LHutili = false; + bool HHutili = false; + bool locallutili = false; + bool localclutili = false; + bool locallcutili = false; + bool localcutili = false; + bool localrgbutili = false; + bool localexutili = false; + bool llmasutili = false; + bool lhmasutili = false; + bool lhhmasutili = false; + bool lcmasutili = false; + bool localmaskutili = false; + bool localmaskexputili = false; + bool localmaskSHutili = false; + bool localmaskvibutili = false; + bool localmasktmutili = false; + bool localmaskretiutili = false; + bool localmaskcbutili = false; + bool localmaskblutili = false; + bool localmasklcutili = false; + bool lcmasexputili = false; + bool lhmasexputili = false; + bool llmasexputili = false; + bool lcmasSHutili = false; + bool lhmasSHutili = false; + bool llmasSHutili = false; + bool lcmasvibutili = false; + bool lhmasvibutili = false; + bool llmasvibutili = false; + bool lcmaslcutili = false; + bool lhmaslcutili = false; + bool llmaslcutili = false; + bool lcmascbutili = false; + bool lhmascbutili = false; + bool llmascbutili = false; + bool lcmasretiutili = false; + bool lhmasretiutili = false; + bool llmasretiutili = false; + bool lcmastmutili = false; + bool lhmastmutili = false; + bool llmastmutili = false; + bool lcmasblutili = false; + bool lhmasblutili = false; + bool llmasblutili = false; + bool locwavutili = false; + bool locwavdenutili = false; + bool loclevwavutili = false; + bool locconwavutili = false; + bool loccompwavutili = false; + bool loccomprewavutili = false; + bool locedgwavutili = false; + bool lmasutiliblwav = false; + bool lmasutilicolwav = false; + locRETgainCurve.Set(params.locallab.spots.at(sp).localTgaincurve); + locRETtransCurve.Set(params.locallab.spots.at(sp).localTtranscurve); + loclhCurve.Set(params.locallab.spots.at(sp).LHcurve, LHutili); + lochhCurve.Set(params.locallab.spots.at(sp).HHcurve, HHutili); + locccmasCurve.Set(params.locallab.spots.at(sp).CCmaskcurve, lcmasutili); + locllmasCurve.Set(params.locallab.spots.at(sp).LLmaskcurve, llmasutili); + lochhmasCurve.Set(params.locallab.spots.at(sp).HHmaskcurve, lhmasutili); + lochhhmasCurve.Set(params.locallab.spots.at(sp).HHhmaskcurve, lhhmasutili); + locccmasexpCurve.Set(params.locallab.spots.at(sp).CCmaskexpcurve, lcmasexputili); + locllmasexpCurve.Set(params.locallab.spots.at(sp).LLmaskexpcurve, llmasexputili); + lochhmasexpCurve.Set(params.locallab.spots.at(sp).HHmaskexpcurve, lhmasexputili); + locccmasSHCurve.Set(params.locallab.spots.at(sp).CCmaskSHcurve, lcmasSHutili); + locllmasSHCurve.Set(params.locallab.spots.at(sp).LLmaskSHcurve, llmasSHutili); + lochhmasSHCurve.Set(params.locallab.spots.at(sp).HHmaskSHcurve, lhmasSHutili); + locccmasvibCurve.Set(params.locallab.spots.at(sp).CCmaskvibcurve, lcmasvibutili); + locllmasvibCurve.Set(params.locallab.spots.at(sp).LLmaskvibcurve, llmasvibutili); + lochhmasvibCurve.Set(params.locallab.spots.at(sp).HHmaskvibcurve, lhmasvibutili); + locccmascbCurve.Set(params.locallab.spots.at(sp).CCmaskcbcurve, lcmascbutili); + locllmascbCurve.Set(params.locallab.spots.at(sp).LLmaskcbcurve, llmascbutili); + lochhmascbCurve.Set(params.locallab.spots.at(sp).HHmaskcbcurve, lhmascbutili); + locccmasretiCurve.Set(params.locallab.spots.at(sp).CCmaskreticurve, lcmasretiutili); + locllmasretiCurve.Set(params.locallab.spots.at(sp).LLmaskreticurve, llmasretiutili); + lochhmasretiCurve.Set(params.locallab.spots.at(sp).HHmaskreticurve, lhmasretiutili); + locccmastmCurve.Set(params.locallab.spots.at(sp).CCmasktmcurve, lcmastmutili); + locllmastmCurve.Set(params.locallab.spots.at(sp).LLmasktmcurve, llmastmutili); + lochhmastmCurve.Set(params.locallab.spots.at(sp).HHmasktmcurve, lhmastmutili); + locccmasblCurve.Set(params.locallab.spots.at(sp).CCmaskblcurve, lcmasblutili); + locllmasblCurve.Set(params.locallab.spots.at(sp).LLmaskblcurve, llmasblutili); + lochhmasblCurve.Set(params.locallab.spots.at(sp).HHmaskblcurve, lhmasblutili); + loclmasCurveblwav.Set(params.locallab.spots.at(sp).LLmaskblcurvewav, lmasutiliblwav); + loclmasCurvecolwav.Set(params.locallab.spots.at(sp).LLmaskcolcurvewav, lmasutilicolwav); + + locwavCurve.Set(params.locallab.spots.at(sp).locwavcurve, locwavutili); + locwavCurveden.Set(params.locallab.spots.at(sp).locwavcurveden, locwavdenutili); + loclevwavCurve.Set(params.locallab.spots.at(sp).loclevwavcurve, loclevwavutili); + locconwavCurve.Set(params.locallab.spots.at(sp).locconwavcurve, locconwavutili); + loccompwavCurve.Set(params.locallab.spots.at(sp).loccompwavcurve, loccompwavutili); + loccomprewavCurve.Set(params.locallab.spots.at(sp).loccomprewavcurve, loccomprewavutili); + locedgwavCurve.Set(params.locallab.spots.at(sp).locedgwavcurve, locedgwavutili); + CurveFactory::curveLocal(locallutili, params.locallab.spots.at(sp).llcurve, lllocalcurve, 1); + CurveFactory::curveLocal(localclutili, params.locallab.spots.at(sp).clcurve, cllocalcurve, 1); + CurveFactory::curveLocal(locallcutili, params.locallab.spots.at(sp).lccurve, lclocalcurve, 1); + CurveFactory::curveCCLocal(localcutili, params.locallab.spots.at(sp).cccurve, cclocalcurve, 1); + CurveFactory::curveLocal(localrgbutili, params.locallab.spots.at(sp).rgbcurve, rgblocalcurve, 1); + CurveFactory::curveexLocal(localexutili, params.locallab.spots.at(sp).excurve, exlocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskutili, params.locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskexputili, params.locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskSHutili, params.locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskvibutili, params.locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve, 1); + CurveFactory::curvemaskLocal(localmasktmutili, params.locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskretiutili, params.locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskcbutili, params.locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve, 1); + CurveFactory::curvemaskLocal(localmaskblutili, params.locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve, 1); + CurveFactory::curvemaskLocal(localmasklcutili, params.locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve, 1); + //provisory + double ecomp = params.locallab.spots.at(sp).expcomp; + double black = params.locallab.spots.at(sp).black; + double hlcompr = params.locallab.spots.at(sp).hlcompr; + double hlcomprthresh = params.locallab.spots.at(sp).hlcomprthresh; + double shcompr = params.locallab.spots.at(sp).shcompr; + double br = params.locallab.spots.at(sp).lightness; + double cont = params.locallab.spots.at(sp).contrast; + if(black < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) { + black *= 1.5; + } + + // Reference parameters computation + double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre; + int lastsav; + float avge; + if (params.locallab.spots.at(sp).spotMethod == "exc") { + ipf.calc_ref(sp, reservView, reservView, 0, 0, fw, fh, 1, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); + } else { + ipf.calc_ref(sp, labView, labView, 0, 0, fw, fh, 1, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); + } + CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumare, + hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, avge, + 1); + float minCD; + float maxCD; + float mini; + float maxi; + float Tmean; + float Tsigma; + float Tmin; + float Tmax; + + // No Locallab mask is shown in exported picture + ipf.Lab_Local(2, sp, (float**)shbuffer, labView, labView, reservView, lastorigView, 0, 0, fw, fh, 1, locRETgainCurve, locRETtransCurve, + lllocalcurve, locallutili, + cllocalcurve, localclutili, + lclocalcurve, locallcutili, + loclhCurve, lochhCurve, + lmasklocalcurve, localmaskutili, + lmaskexplocalcurve, localmaskexputili, + lmaskSHlocalcurve, localmaskSHutili, + lmaskviblocalcurve, localmaskvibutili, + lmasktmlocalcurve, localmasktmutili, + lmaskretilocalcurve, localmaskretiutili, + lmaskcblocalcurve, localmaskcbutili, + lmaskbllocalcurve, localmaskblutili, + lmasklclocalcurve, localmasklcutili, + locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, lochhhmasCurve, lhhmasutili, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, + locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, + locccmasvibCurve, lcmasvibutili, locllmasvibCurve, llmasvibutili, lochhmasvibCurve, lhmasvibutili, + locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili, + locccmasretiCurve, lcmasretiutili, locllmasretiCurve, llmasretiutili, lochhmasretiCurve, lhmasretiutili, + locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, + locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili, + locccmaslcCurve, lcmaslcutili, locllmaslcCurve, llmaslcutili, lochhmaslcCurve, lhmaslcutili, + loclmasCurveblwav,lmasutiliblwav, + loclmasCurvecolwav,lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + LHutili, HHutili, cclocalcurve, localcutili, rgblocalcurve, localrgbutili, localexutili, exlocalcurve, hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, + huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + + lastorigView->CopyFrom(labView); + + if (params.locallab.spots.at(sp).spotMethod == "exc") { + ipf.calc_ref(sp, reservView, reservView, 0, 0, fw, fh, 1, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); + } else { + ipf.calc_ref(sp, labView, labView, 0, 0, fw, fh, 1, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, avge, locwavCurveden, locwavdenutili); + } + + // Clear local curves + lllocalcurve.clear(); + lclocalcurve.clear(); + cllocalcurve.clear(); + cclocalcurve.clear(); + rgblocalcurve.clear(); + exlocalcurve.clear(); + hltonecurveloc.clear(); + lmasklocalcurve.clear(); + lmaskexplocalcurve.clear(); + lmaskSHlocalcurve.clear(); + lmaskviblocalcurve.clear(); + lmasktmlocalcurve.clear(); + lmaskretilocalcurve.clear(); + lmaskcblocalcurve.clear(); + lmaskbllocalcurve.clear(); + shtonecurveloc.clear(); + tonecurveloc.clear(); + lightCurveloc.clear(); + if (params.locallab.spots.at(sp).inverssha) { + + for (int i = 0; i < fh; i++) { + delete [] shbuffer[i]; + } + + delete [] shbuffer; + } + + + } + + t2.set(); + + if (settings->verbose) { + printf("Total local:- %d usec\n", t2.etime(t1)); + } + + } + + delete reservView; + reservView = nullptr; + delete lastorigView; + lastorigView = nullptr; + ipf.chromiLuminanceCurve(nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { @@ -1084,7 +1403,7 @@ private: } - ipf.vibrance(labView); + ipf.vibrance(labView, params.vibrance, params.toneCurve.hrenabled, params.icm.workingProfile); ipf.labColorCorrectionRegions(labView); // for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled @@ -1127,6 +1446,7 @@ private: WavCurve wavCLVCurve; Wavblcurve wavblcurve; WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveSH waOpacityCurveSH; WavOpacityCurveBY waOpacityCurveBY; WavOpacityCurveW waOpacityCurveW; WavOpacityCurveWL waOpacityCurveWL; @@ -1149,7 +1469,7 @@ private: provradius->CopyFrom(labView); } - params.wavelet.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); + params.wavelet.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1); @@ -1157,7 +1477,7 @@ private: unshar = new LabImage(fw, fh); provis = params.wavelet.CLmethod; params.wavelet.CLmethod = "all"; - ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); + ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); unshar->CopyFrom(labView); params.wavelet.CLmethod = provis; @@ -1169,7 +1489,7 @@ private: WaveParams.expnoise = false; } - ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); + ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { WaveParams.expcontrast = procont; @@ -1278,7 +1598,7 @@ private: wavCLVCurve.Reset(); } - ipf.softLight(labView); + ipf.softLight(labView, params.softlight); //Colorappearance and tone-mapping associated @@ -1422,6 +1742,8 @@ private: delete labView; labView = nullptr; +// delete reservView; +// reservView = nullptr; if (bwonly) { //force BW r=g=b @@ -1698,6 +2020,8 @@ private: ColorTemp currWB; Imagefloat *baseImg; LabImage* labView; + LabImage* reservView; + LabImage* lastorigView; LUTu hist16; diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc index cee57c851..60fbc7b4c 100644 --- a/rtengine/tmo_fattal02.cc +++ b/rtengine/tmo_fattal02.cc @@ -97,60 +97,62 @@ class Array2Df: public array2D typedef array2D Super; public: Array2Df(): Super() {} - Array2Df (int w, int h): Super (w, h) {} + Array2Df(int w, int h): Super(w, h) {} + Array2Df(int w, int h, float **data): + Super(w, h, data, ARRAY2D_BYREFERENCE) {} - float &operator() (int w, int h) + float &operator()(int w, int h) { return (*this)[h][w]; } - const float &operator() (int w, int h) const + const float &operator()(int w, int h) const { return (*this)[h][w]; } - float &operator() (int i) + float &operator()(int i) { - return static_cast (*this)[i]; + return static_cast(*this)[i]; } - const float &operator() (int i) const + const float &operator()(int i) const { - return const_cast (*this).operator() (i); + return const_cast(*this).operator()(i); } int getRows() const { - return const_cast (*this).height(); + return const_cast(*this).height(); } int getCols() const { - return const_cast (*this).width(); + return const_cast(*this).width(); } float *data() { - return static_cast (*this); + return static_cast(*this); } const float *data() const { - return const_cast (*this).data(); + return const_cast(*this).data(); } }; // upper bound on image dimension used in tmo_fattal02 -- see the comment there const int RT_dimension_cap = 1920; -void rescale_bilinear (const Array2Df &src, Array2Df &dst, bool multithread); +void rescale_bilinear(const Array2Df &src, Array2Df &dst, bool multithread); /****************************************************************************** * Luminance HDR code (modifications are marked with an RT comment) ******************************************************************************/ -void downSample (const Array2Df& A, Array2Df& B) +void downSample(const Array2Df& A, Array2Df& B) { const int width = B.getCols(); const int height = B.getRows(); @@ -160,18 +162,18 @@ void downSample (const Array2Df& A, Array2Df& B) // speed improvements. The main issue is the pde solver and in case of the // fft solver uses optimised threaded fftw routines. //#pragma omp parallel for - for ( int y = 0 ; y < height ; y++ ) { - for ( int x = 0 ; x < width ; x++ ) { - float p = A (2 * x, 2 * y); - p += A (2 * x + 1, 2 * y); - p += A (2 * x, 2 * y + 1); - p += A (2 * x + 1, 2 * y + 1); - B (x, y) = p * 0.25f; // p / 4.0f; + for (int y = 0 ; y < height ; y++) { + for (int x = 0 ; x < width ; x++) { + float p = A(2 * x, 2 * y); + p += A(2 * x + 1, 2 * y); + p += A(2 * x, 2 * y + 1); + p += A(2 * x + 1, 2 * y + 1); + B(x, y) = p * 0.25f; // p / 4.0f; } } } -void gaussianBlur (const Array2Df& I, Array2Df& L, bool multithread) +void gaussianBlur(const Array2Df& I, Array2Df& L, bool multithread) { const int width = I.getCols(); const int height = I.getRows(); @@ -179,30 +181,30 @@ void gaussianBlur (const Array2Df& I, Array2Df& L, bool multithread) if (width < 3 || height < 3) { if (&I != &L) { for (int i = 0, n = width * height; i < n; ++i) { - L (i) = I (i); + L(i) = I(i); } } return; } - Array2Df T (width, height); + Array2Df T(width, height); //--- X blur #ifdef _OPENMP #pragma omp parallel for shared(I, T) if(multithread) #endif - for ( int y = 0 ; y < height ; y++ ) { - for ( int x = 1 ; x < width - 1 ; x++ ) { - float t = 2.f * I (x, y); - t += I (x - 1, y); - t += I (x + 1, y); - T (x, y) = t * 0.25f; // t / 4.f; + for (int y = 0 ; y < height ; y++) { + for (int x = 1 ; x < width - 1 ; x++) { + float t = 2.f * I(x, y); + t += I(x - 1, y); + t += I(x + 1, y); + T(x, y) = t * 0.25f; // t / 4.f; } - T (0, y) = ( 3.f * I (0, y) + I (1, y) ) * 0.25f; // / 4.f; - T (width - 1, y) = ( 3.f * I (width - 1, y) + I (width - 2, y) ) * 0.25f; // / 4.f; + T(0, y) = (3.f * I(0, y) + I(1, y)) * 0.25f; // / 4.f; + T(width - 1, y) = (3.f * I(width - 1, y) + I(width - 2, y)) * 0.25f; // / 4.f; } //--- Y blur @@ -210,66 +212,66 @@ void gaussianBlur (const Array2Df& I, Array2Df& L, bool multithread) #pragma omp parallel for if(multithread) #endif - for ( int x = 0 ; x < width - 7 ; x += 8 ) { - for ( int y = 1 ; y < height - 1 ; y++ ) { + for (int x = 0 ; x < width - 7 ; x += 8) { + for (int y = 1 ; y < height - 1 ; y++) { for (int xx = 0; xx < 8; ++xx) { - float t = 2.f * T (x + xx, y); - t += T (x + xx, y - 1); - t += T (x + xx, y + 1); - L (x + xx, y) = t * 0.25f; // t/4.0f; + float t = 2.f * T(x + xx, y); + t += T(x + xx, y - 1); + t += T(x + xx, y + 1); + L(x + xx, y) = t * 0.25f; // t/4.0f; } } for (int xx = 0; xx < 8; ++xx) { - L (x + xx, 0) = ( 3.f * T (x + xx, 0) + T (x + xx, 1) ) * 0.25f; // / 4.0f; - L (x + xx, height - 1) = ( 3.f * T (x + xx, height - 1) + T (x + xx, height - 2) ) * 0.25f; // / 4.0f; + L(x + xx, 0) = (3.f * T(x + xx, 0) + T(x + xx, 1)) * 0.25f; // / 4.0f; + L(x + xx, height - 1) = (3.f * T(x + xx, height - 1) + T(x + xx, height - 2)) * 0.25f; // / 4.0f; } } - for ( int x = width - (width % 8) ; x < width ; x++ ) { - for ( int y = 1 ; y < height - 1 ; y++ ) { - float t = 2.f * T (x, y); - t += T (x, y - 1); - t += T (x, y + 1); - L (x, y) = t * 0.25f; // t/4.0f; + for (int x = width - (width % 8) ; x < width ; x++) { + for (int y = 1 ; y < height - 1 ; y++) { + float t = 2.f * T(x, y); + t += T(x, y - 1); + t += T(x, y + 1); + L(x, y) = t * 0.25f; // t/4.0f; } - L (x, 0) = ( 3.f * T (x, 0) + T (x, 1) ) * 0.25f; // / 4.0f; - L (x, height - 1) = ( 3.f * T (x, height - 1) + T (x, height - 2) ) * 0.25f; // / 4.0f; + L(x, 0) = (3.f * T(x, 0) + T(x, 1)) * 0.25f; // / 4.0f; + L(x, height - 1) = (3.f * T(x, height - 1) + T(x, height - 2)) * 0.25f; // / 4.0f; } } -void createGaussianPyramids (Array2Df** pyramids, int nlevels, bool multithread) +void createGaussianPyramids(Array2Df** pyramids, int nlevels, bool multithread) { // pyramids[0] is already set int width = pyramids[0]->getCols(); int height = pyramids[0]->getRows(); - Array2Df* L = new Array2Df (width, height); - gaussianBlur ( *pyramids[0], *L, multithread ); + Array2Df* L = new Array2Df(width, height); + gaussianBlur(*pyramids[0], *L, multithread); - for ( int k = 1 ; k < nlevels ; k++ ) { + for (int k = 1 ; k < nlevels ; k++) { if (width > 2 && height > 2) { width /= 2; height /= 2; - pyramids[k] = new Array2Df (width, height); - downSample (*L, *pyramids[k]); + pyramids[k] = new Array2Df(width, height); + downSample(*L, *pyramids[k]); } else { // RT - now nlevels is fixed in tmo_fattal02 (see the comment in // there), so it might happen that we have to add some padding to // the gaussian pyramids - pyramids[k] = new Array2Df (width, height); + pyramids[k] = new Array2Df(width, height); for (int j = 0, n = width * height; j < n; ++j) { - (*pyramids[k]) (j) = (*L) (j); + (*pyramids[k])(j) = (*L)(j); } } if (k < nlevels - 1) { delete L; - L = new Array2Df (width, height); - gaussianBlur ( *pyramids[k], *L, multithread ); + L = new Array2Df(width, height); + gaussianBlur(*pyramids[k], *L, multithread); } } @@ -278,36 +280,36 @@ void createGaussianPyramids (Array2Df** pyramids, int nlevels, bool multithread) //-------------------------------------------------------------------- -float calculateGradients (Array2Df* H, Array2Df* G, int k, bool multithread) +float calculateGradients(Array2Df* H, Array2Df* G, int k, bool multithread) { const int width = H->getCols(); const int height = H->getRows(); - const float divider = pow ( 2.0f, k + 1 ); + const float divider = pow(2.0f, k + 1); double avgGrad = 0.0; // use double precision for large summations #ifdef _OPENMP #pragma omp parallel for reduction(+:avgGrad) if(multithread) #endif - for ( int y = 0 ; y < height ; y++ ) { + for (int y = 0 ; y < height ; y++) { int n = (y == 0 ? 0 : y - 1); int s = (y + 1 == height ? y : y + 1); - for ( int x = 0 ; x < width ; x++ ) { + for (int x = 0 ; x < width ; x++) { float gx, gy; int w, e; w = (x == 0 ? 0 : x - 1); e = (x + 1 == width ? x : x + 1); - gx = ((*H) (w, y) - (*H) (e, y)); + gx = ((*H)(w, y) - (*H)(e, y)); - gy = ((*H) (x, s) - (*H) (x, n)); + gy = ((*H)(x, s) - (*H)(x, n)); // note this implicitly assumes that H(-1)=H(0) // for the fft-pde slover this would need adjustment as H(-1)=H(1) // is assumed, which means gx=0.0, gy=0.0 at the boundaries // however, the impact is not visible so we ignore this here - (*G) (x, y) = sqrt (gx * gx + gy * gy) / divider; + (*G)(x, y) = sqrt(gx * gx + gy * gy) / divider; avgGrad += static_cast((*G) (x, y)); } } @@ -317,7 +319,7 @@ float calculateGradients (Array2Df* H, Array2Df* G, int k, bool multithread) //-------------------------------------------------------------------- -void upSample (const Array2Df& A, Array2Df& B) +void upSample(const Array2Df& A, Array2Df& B) { const int width = B.getCols(); const int height = B.getRows(); @@ -325,14 +327,14 @@ void upSample (const Array2Df& A, Array2Df& B) const int aheight = A.getRows(); //#pragma omp parallel for shared(A, B) - for ( int y = 0 ; y < height ; y++ ) { - for ( int x = 0 ; x < width ; x++ ) { - int ax = static_cast (x * 0.5f); //x / 2.f; - int ay = static_cast (y * 0.5f); //y / 2.f; + for (int y = 0 ; y < height ; y++) { + for (int x = 0 ; x < width ; x++) { + int ax = static_cast(x * 0.5f); //x / 2.f; + int ay = static_cast(y * 0.5f); //y / 2.f; ax = (ax < awidth) ? ax : awidth - 1; ay = (ay < aheight) ? ay : aheight - 1; - B (x, y) = A (ax, ay); + B(x, y) = A(ax, ay); } } @@ -352,24 +354,25 @@ void upSample (const Array2Df& A, Array2Df& B) } -void calculateFiMatrix (Array2Df* FI, Array2Df* gradients[], - float avgGrad[], int nlevels, int detail_level, - float alfa, float beta, float noise, bool multithread) +void calculateFiMatrix(Array2Df* FI, Array2Df* gradients[], + float avgGrad[], int nlevels, int detail_level, + float alfa, float beta, float noise, bool multithread) { int width = gradients[nlevels - 1]->getCols(); int height = gradients[nlevels - 1]->getRows(); Array2Df** fi = new Array2Df*[nlevels]; - fi[nlevels - 1] = new Array2Df (width, height); + fi[nlevels - 1] = new Array2Df(width, height); #ifdef _OPENMP #pragma omp parallel for shared(fi) if(multithread) #endif - for ( int k = 0 ; k < width * height ; k++ ) { - (*fi[nlevels - 1]) (k) = 1.0f; + + for (int k = 0 ; k < width * height ; k++) { + (*fi[nlevels - 1])(k) = 1.0f; } - for ( int k = nlevels - 1; k >= 0 ; k-- ) { + for (int k = nlevels - 1; k >= 0 ; k--) { width = gradients[k]->getCols(); height = gradients[k]->getRows(); @@ -379,50 +382,51 @@ void calculateFiMatrix (Array2Df* FI, Array2Df* gradients[], #ifdef _OPENMP #pragma omp parallel for shared(fi,avgGrad) if(multithread) #endif - for ( int y = 0; y < height; y++ ) { - for ( int x = 0; x < width; x++ ) { + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { float grad = ((*gradients[k]) (x, y) < 1e-4f) ? 1e-4f : (*gradients[k]) (x, y); float a = alfa * avgGrad[k]; - float value = pow ((grad + noise) / a, beta - 1.0f); + float value = pow((grad + noise) / a, beta - 1.0f); - (*fi[k]) (x, y) *= value; + (*fi[k])(x, y) *= value; } } } // create next level - if ( k > 1 ) { + if (k > 1) { width = gradients[k - 1]->getCols(); height = gradients[k - 1]->getRows(); - fi[k - 1] = new Array2Df (width, height); + fi[k - 1] = new Array2Df(width, height); } else { fi[0] = FI; // highest level -> result } if (k > 0) { - upSample (*fi[k], *fi[k - 1]); // upsample to next level - gaussianBlur (*fi[k - 1], *fi[k - 1], multithread); + upSample(*fi[k], *fi[k - 1]); // upsample to next level + gaussianBlur(*fi[k - 1], *fi[k - 1], multithread); } } - for ( int k = 1 ; k < nlevels ; k++ ) { + for (int k = 1 ; k < nlevels ; k++) { delete fi[k]; } delete[] fi; } -void solve_pde_fft (Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread); +void solve_pde_fft(Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread, int algo); -void tmo_fattal02 (size_t width, - size_t height, - const Array2Df& Y, - Array2Df& L, - float alfa, - float beta, - float noise, - int detail_level, - bool multithread) +void tmo_fattal02(size_t width, + size_t height, + const Array2Df& Y, + Array2Df& L, + float alfa, + float beta, + float noise, + int detail_level, + bool multithread, int algo) { // #ifdef TIMER_PROFILING // msec_timer stop_watch; @@ -431,13 +435,14 @@ void tmo_fattal02 (size_t width, // static const float black_point = 0.1f; // static const float white_point = 0.5f; static const float gamma = 1.0f; // 0.8f; +//paramet // static const int detail_level = 3; - if ( detail_level < 0 ) { + if (detail_level < 0) { detail_level = 0; } - if ( detail_level > 3 ) { + if (detail_level > 3) { detail_level = 3; } @@ -462,21 +467,26 @@ void tmo_fattal02 (size_t width, int size = width * height; - +//paramet // find max value, normalize to range 0..100 and take logarithm // float minLum = Y (0, 0); - float maxLum = Y (0, 0); + float maxLum = Y(0, 0); #ifdef _OPENMP #pragma omp parallel for reduction(max:maxLum) if(multithread) #endif - for ( int i = 0 ; i < size ; i++ ) { - maxLum = std::max (maxLum, Y (i)); + for (int i = 0 ; i < size ; i++) { + maxLum = std::max(maxLum, Y(i)); } - Array2Df* H = new Array2Df (width, height); + Array2Df* H = new Array2Df(width, height); float temp = 100.f / maxLum; + + if (algo == 1) { + temp = 1.f; + } + #ifdef _OPENMP #pragma omp parallel if(multithread) #endif @@ -495,13 +505,13 @@ void tmo_fattal02 (size_t width, #ifdef __SSE2__ for (; j < width - 3; j += 4) { - STVFU ((*H)[i][j], xlogf (tempv * LVFU (Y[i][j]) + epsv)); + STVFU((*H)[i][j], xlogf(tempv * LVFU(Y[i][j]) + epsv)); } #endif for (; j < width; ++j) { - (*H)[i][j] = xlogf (temp * Y[i][j] + eps); + (*H)[i][j] = xlogf(temp * Y[i][j] + eps); } } } @@ -528,13 +538,13 @@ void tmo_fattal02 (size_t width, * improved */ int fullwidth = width; int fullheight = height; - int dim = std::max (width, height); + int dim = std::max(width, height); Array2Df *fullH = nullptr; if (dim > RT_dimension_cap) { float s = float (RT_dimension_cap) / float (dim); - Array2Df *HH = new Array2Df (width * s, height * s); - rescale_bilinear (*H, *HH, multithread); + Array2Df *HH = new Array2Df(width * s, height * s); + rescale_bilinear(*H, *HH, multithread); fullH = H; H = HH; width = H->getCols(); @@ -547,25 +557,27 @@ void tmo_fattal02 (size_t width, Array2Df* pyramids[nlevels]; pyramids[0] = H; - createGaussianPyramids (pyramids, nlevels, multithread); + createGaussianPyramids(pyramids, nlevels, multithread); // calculate gradients and its average values on pyramid levels Array2Df* gradients[nlevels]; float avgGrad[nlevels]; - for ( int k = 0 ; k < nlevels ; k++ ) { - gradients[k] = new Array2Df (pyramids[k]->getCols(), pyramids[k]->getRows()); - avgGrad[k] = calculateGradients (pyramids[k], gradients[k], k, multithread); - if(k != 0) // pyramids[0] is H. Will be deleted later + for (int k = 0 ; k < nlevels ; k++) { + gradients[k] = new Array2Df(pyramids[k]->getCols(), pyramids[k]->getRows()); + avgGrad[k] = calculateGradients(pyramids[k], gradients[k], k, multithread); + + if (k != 0) { // pyramids[0] is H. Will be deleted later delete pyramids[k]; + } } // calculate fi matrix - Array2Df* FI = new Array2Df (width, height); - calculateFiMatrix (FI, gradients, avgGrad, nlevels, detail_level, alfa, beta, noise, multithread); + Array2Df* FI = new Array2Df(width, height); + calculateFiMatrix(FI, gradients, avgGrad, nlevels, detail_level, alfa, beta, noise, multithread); - for ( int i = 0 ; i < nlevels ; i++ ) { + for (int i = 0 ; i < nlevels ; i++) { delete gradients[i]; } @@ -573,8 +585,8 @@ void tmo_fattal02 (size_t width, if (fullH) { delete H; H = fullH; - Array2Df *FI2 = new Array2Df (fullwidth, fullheight); - rescale_bilinear (*FI, *FI2, multithread); + Array2Df *FI2 = new Array2Df(fullwidth, fullheight); + rescale_bilinear(*FI, *FI2, multithread); delete FI; FI = FI2; width = fullwidth; @@ -584,7 +596,7 @@ void tmo_fattal02 (size_t width, /** RT */ // attenuate gradients - Array2Df* Gx = new Array2Df (width, height); + Array2Df* Gx = new Array2Df(width, height); Array2Df* Gy = &L; // use L as buffer for Gy // the fft solver solves the Poisson pde but with slightly different @@ -595,11 +607,11 @@ void tmo_fattal02 (size_t width, #pragma omp parallel for if(multithread) #endif - for ( size_t y = 0 ; y < height ; y++ ) { + for (size_t y = 0 ; y < height ; y++) { // sets index+1 based on the boundary assumption H(N+1)=H(N-1) unsigned int yp1 = (y + 1 >= height ? height - 2 : y + 1); - for ( size_t x = 0 ; x < width ; x++ ) { + for (size_t x = 0 ; x < width ; x++) { // sets index+1 based on the boundary assumption H(N+1)=H(N-1) unsigned int xp1 = (x + 1 >= width ? width - 2 : x + 1); // forward differences in H, so need to use between-points approx of FI @@ -615,24 +627,24 @@ void tmo_fattal02 (size_t width, #pragma omp parallel for if(multithread) #endif - for ( size_t y = 0; y < height; ++y ) { - for ( size_t x = 0; x < width; ++x ) { - (*FI) (x, y) = (*Gx) (x, y) + (*Gy) (x, y); + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + (*FI)(x, y) = (*Gx)(x, y) + (*Gy)(x, y); - if ( x > 0 ) { - (*FI) (x, y) -= (*Gx) (x - 1, y); + if (x > 0) { + (*FI)(x, y) -= (*Gx)(x - 1, y); } - if ( y > 0 ) { - (*FI) (x, y) -= (*Gy) (x, y - 1); + if (y > 0) { + (*FI)(x, y) -= (*Gy)(x, y - 1); } if (x == 0) { - (*FI) (x, y) += (*Gx) (x, y); + (*FI)(x, y) += (*Gx)(x, y); } if (y == 0) { - (*FI) (x, y) += (*Gy) (x, y); + (*FI)(x, y) += (*Gy)(x, y); } } @@ -642,8 +654,8 @@ void tmo_fattal02 (size_t width, // solve pde and exponentiate (ie recover compressed image) { - MyMutex::MyLock lock (*fftwMutex); - solve_pde_fft (FI, &L, Gx, multithread); + MyMutex::MyLock lock(*fftwMutex); + solve_pde_fft(FI, &L, Gx, multithread, algo); } delete Gx; delete FI; @@ -653,7 +665,7 @@ void tmo_fattal02 (size_t width, #endif { #ifdef __SSE2__ - vfloat gammav = F2V (gamma); + vfloat gammav = F2V(gamma); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) @@ -664,13 +676,13 @@ void tmo_fattal02 (size_t width, #ifdef __SSE2__ for (; j < width - 3; j += 4) { - STVFU (L[i][j], xexpf (gammav * LVFU (L[i][j]))); + STVFU(L[i][j], xexpf(gammav * LVFU(L[i][j]))); } #endif for (; j < width; j++) { - L[i][j] = xexpf ( gamma * L[i][j]); + L[i][j] = xexpf(gamma * L[i][j]); } } } @@ -724,11 +736,11 @@ void tmo_fattal02 (size_t width, // returns T = EVy A EVx^tr // note, modifies input data -void transform_ev2normal (Array2Df *A, Array2Df *T, bool multithread) +void transform_ev2normal(Array2Df *A, Array2Df *T, bool multithread) { int width = A->getCols(); int height = A->getRows(); - assert ((int)T->getCols() == width && (int)T->getRows() == height); + assert((int)T->getCols() == width && (int)T->getRows() == height); // the discrete cosine transform is not exactly the transform needed // need to scale input values to get the right transformation @@ -736,19 +748,19 @@ void transform_ev2normal (Array2Df *A, Array2Df *T, bool multithread) #pragma omp parallel for if(multithread) #endif - for (int y = 1 ; y < height - 1 ; y++ ) - for (int x = 1 ; x < width - 1 ; x++ ) { - (*A) (x, y) *= 0.25f; + for (int y = 1 ; y < height - 1 ; y++) + for (int x = 1 ; x < width - 1 ; x++) { + (*A)(x, y) *= 0.25f; } - for (int x = 1 ; x < width - 1 ; x++ ) { - (*A) (x, 0) *= 0.5f; - (*A) (x, height - 1) *= 0.5f; + for (int x = 1 ; x < width - 1 ; x++) { + (*A)(x, 0) *= 0.5f; + (*A)(x, height - 1) *= 0.5f; } - for (int y = 1 ; y < height - 1 ; y++ ) { + for (int y = 1 ; y < height - 1 ; y++) { (*A) (0, y) *= 0.5f; - (*A) (width - 1, y) *= 0.5f; + (*A)(width - 1, y) *= 0.5f; } // note, fftw provides its own memory allocation routines which @@ -762,26 +774,26 @@ void transform_ev2normal (Array2Df *A, Array2Df *T, bool multithread) // executes 2d discrete cosine transform fftwf_plan p; - p = fftwf_plan_r2r_2d (height, width, A->data(), T->data(), - FFTW_REDFT00, FFTW_REDFT00, FFTW_ESTIMATE); - fftwf_execute (p); - fftwf_destroy_plan (p); + p = fftwf_plan_r2r_2d(height, width, A->data(), T->data(), + FFTW_REDFT00, FFTW_REDFT00, FFTW_ESTIMATE); + fftwf_execute(p); + fftwf_destroy_plan(p); } // returns T = EVy^-1 * A * (EVx^-1)^tr -void transform_normal2ev (Array2Df *A, Array2Df *T, bool multithread) +void transform_normal2ev(Array2Df *A, Array2Df *T, bool multithread) { int width = A->getCols(); int height = A->getRows(); - assert ((int)T->getCols() == width && (int)T->getRows() == height); + assert((int)T->getCols() == width && (int)T->getRows() == height); // executes 2d discrete cosine transform fftwf_plan p; - p = fftwf_plan_r2r_2d (height, width, A->data(), T->data(), - FFTW_REDFT00, FFTW_REDFT00, FFTW_ESTIMATE); - fftwf_execute (p); - fftwf_destroy_plan (p); + p = fftwf_plan_r2r_2d(height, width, A->data(), T->data(), + FFTW_REDFT00, FFTW_REDFT00, FFTW_ESTIMATE); + fftwf_execute(p); + fftwf_destroy_plan(p); // need to scale the output matrix to get the right transform float factor = (1.0f / ((height - 1) * (width - 1))); @@ -789,30 +801,30 @@ void transform_normal2ev (Array2Df *A, Array2Df *T, bool multithread) #pragma omp parallel for if(multithread) #endif - for (int y = 0 ; y < height ; y++ ) - for (int x = 0 ; x < width ; x++ ) { - (*T) (x, y) *= factor; + for (int y = 0 ; y < height ; y++) + for (int x = 0 ; x < width ; x++) { + (*T)(x, y) *= factor; } - for (int x = 0 ; x < width ; x++ ) { - (*T) (x, 0) *= 0.5f; - (*T) (x, height - 1) *= 0.5f; + for (int x = 0 ; x < width ; x++) { + (*T)(x, 0) *= 0.5f; + (*T)(x, height - 1) *= 0.5f; } - for (int y = 0 ; y < height ; y++ ) { - (*T) (0, y) *= 0.5f; - (*T) (width - 1, y) *= 0.5f; + for (int y = 0 ; y < height ; y++) { + (*T)(0, y) *= 0.5f; + (*T)(width - 1, y) *= 0.5f; } } // returns the eigenvalues of the 1d laplace operator -std::vector get_lambda (int n) +std::vector get_lambda(int n) { - assert (n > 1); - std::vector v (n); + assert(n > 1); + std::vector v(n); for (int i = 0; i < n; i++) { - v[i] = -4.0 * SQR (sin ((double)i / (2 * (n - 1)) * RT_PI)); + v[i] = -4.0 * SQR(sin((double)i / (2 * (n - 1)) * RT_PI)); } return v; @@ -862,22 +874,22 @@ std::vector get_lambda (int n) // not modified and the equation might not have a solution but an // approximate solution with a minimum error is then calculated // double precision version -void solve_pde_fft (Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread)/*, pfs::Progress &ph, +void solve_pde_fft(Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread, int algo)/*, pfs::Progress &ph, bool adjust_bound)*/ { // ph.setValue(20); //DEBUG_STR << "solve_pde_fft: solving Laplace U = F ..." << std::endl; int width = F->getCols(); int height = F->getRows(); - assert ((int)U->getCols() == width && (int)U->getRows() == height); - assert (buf->getCols() == width && buf->getRows() == height); + assert((int)U->getCols() == width && (int)U->getRows() == height); + assert(buf->getCols() == width && buf->getRows() == height); // activate parallel execution of fft routines #ifdef RT_FFTW3F_OMP if (multithread) { fftwf_init_threads(); - fftwf_plan_with_nthreads ( omp_get_max_threads() ); + fftwf_plan_with_nthreads(omp_get_max_threads()); } // #else @@ -897,29 +909,29 @@ void solve_pde_fft (Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread)/* // transforms F into eigenvector space: Ftr = //DEBUG_STR << "solve_pde_fft: transform F to ev space (fft)" << std::endl; Array2Df* F_tr = buf; - transform_normal2ev (F, F_tr, multithread); + transform_normal2ev(F, F_tr, multithread); // TODO: F no longer needed so could release memory, but as it is an // input parameter we won't do that // in the eigenvector space the solution is very simple - std::vector l1 = get_lambda (height); - std::vector l2 = get_lambda (width); + std::vector l1 = get_lambda(height); + std::vector l2 = get_lambda(width); #ifdef _OPENMP #pragma omp parallel for if(multithread) #endif - for (int y = 0 ; y < height ; y++ ) { - for (int x = 0 ; x < width ; x++ ) { + for (int y = 0 ; y < height ; y++) { + for (int x = 0 ; x < width ; x++) { (*F_tr) (x, y) = static_cast((*F_tr) (x, y)) / (l1[y] + l2[x]); } } - (*F_tr) (0, 0) = 0.f; // any value ok, only adds a const to the solution + (*F_tr)(0, 0) = 0.f; // any value ok, only adds a const to the solution // transforms F_tr back to the normal space - transform_ev2normal (F_tr, U, multithread); + transform_ev2normal(F_tr, U, multithread); // the solution U as calculated will satisfy something like int U = 0 // since for any constant c, U-c is also a solution and we are mainly @@ -927,21 +939,23 @@ void solve_pde_fft (Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread)/* // a solution which has no positive values: U_new(x,y)=U(x,y)-max // (not really needed but good for numerics as we later take exp(U)) //DEBUG_STR << "solve_pde_fft: removing constant from solution" << std::endl; - float maxVal = 0.f; + if (algo == 0) { + float maxVal = 0.f; #ifdef _OPENMP - #pragma omp parallel for reduction(max:maxVal) if(multithread) + #pragma omp parallel for reduction(max:maxVal) if(multithread) #endif - for (int i = 0; i < width * height; i++) { - maxVal = std::max(maxVal, (*U)(i)); - } + for (int i = 0; i < width * height; i++) { + maxVal = std::max(maxVal, (*U)(i)); + } #ifdef _OPENMP - #pragma omp parallel for if(multithread) + #pragma omp parallel for if(multithread) #endif - for (int i = 0; i < width * height; i++) { - (*U) (i) -= maxVal; + for (int i = 0; i < width * height; i++) { + (*U)(i) -= maxVal; + } } } @@ -975,27 +989,27 @@ void solve_pde_fft (Array2Df *F, Array2Df *U, Array2Df *buf, bool multithread)/* * RT code from here on *****************************************************************************/ -inline void rescale_bilinear (const Array2Df &src, Array2Df &dst, bool multithread) +inline void rescale_bilinear(const Array2Df &src, Array2Df &dst, bool multithread) { rescaleBilinear(src, dst, multithread); } -inline void rescale_nearest (const Array2Df &src, Array2Df &dst, bool multithread) +inline void rescale_nearest(const Array2Df &src, Array2Df &dst, bool multithread) { rescaleNearest(src, dst, multithread); } -inline float luminance (float r, float g, float b, TMatrix ws) +inline float luminance(float r, float g, float b, TMatrix ws) { return Color::rgbLuminance(r, g, b, ws); } -inline int round_up_pow2 (int dim) +inline int round_up_pow2(int dim) { // from https://graphics.stanford.edu/~seander/bithacks.html - assert (dim > 0); + assert(dim > 0); unsigned int v = dim; v--; v |= v >> 1; @@ -1007,7 +1021,7 @@ inline int round_up_pow2 (int dim) return v; } -inline int find_fast_dim (int dim) +inline int find_fast_dim(int dim) { // as per the FFTW docs: // @@ -1019,7 +1033,7 @@ inline int find_fast_dim (int dim) // the above form. This is not exhaustive, but should be ok for pictures // up to 100MPix at least - int d1 = round_up_pow2 (dim); + int d1 = round_up_pow2(dim); std::vector d = { d1 / 128 * 65, d1 / 64 * 33, @@ -1041,72 +1055,93 @@ inline int find_fast_dim (int dim) } } - assert (false); + assert(false); return dim; } + + } // namespace -void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) +void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingParams &fatParams, int detail_level, int Lalone, float **Lum, int WW, int HH, int algo) +//algo allows to use ART algorithme algo = 0 RT, algo = 1 ART +//Lalone allows to use L without RGB values in RT mode { - if (!params->fattal.enabled) { + if (!fatParams.enabled) { return; } - + BENCHFUN - const int detail_level = 3; +// const int detail_level = 3; float alpha = 1.f; - if (params->fattal.threshold < 0) { - alpha += (params->fattal.threshold * 0.9f) / 100.f; - } else if (params->fattal.threshold > 0) { - alpha += params->fattal.threshold / 100.f; + if (fatParams.threshold < 0) { + alpha += (fatParams.threshold * 0.9f) / 100.f; + } else if (fatParams.threshold > 0) { + alpha += fatParams.threshold / 100.f; } - float beta = 1.f - (params->fattal.amount * 0.3f) / 100.f; + float beta = 1.f - (fatParams.amount * 0.3f) / 100.f; // sanity check if (alpha <= 0 || beta <= 0) { return; } - int w = rgb->getWidth(); - int h = rgb->getHeight(); + int w; + int h; - Array2Df Yr (w, h); + if (Lalone != 0) { + w = WW; + h = HH; + } else { + w = rgb->getWidth(); + h = rgb->getHeight(); + } + + Array2Df Yr(w, h); constexpr float epsilon = 1e-4f; constexpr float luminance_noise_floor = 65.535f; constexpr float min_luminance = 1.f; - TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix (params->icm.workingProfile); - + TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); #ifdef _OPENMP #pragma omp parallel for if(multiThread) #endif + for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { - Yr (x, y) = std::max (luminance (rgb->r (y, x), rgb->g (y, x), rgb->b (y, x), ws), min_luminance); // clip really black pixels + if (Lalone != 0) { + Yr(x, y) = std::max(2.f * Lum[y][x], min_luminance); // clip really black pixels + } else { + Yr(x, y) = std::max(luminance(rgb->r(y, x), rgb->g(y, x), rgb->b(y, x), ws), min_luminance); // clip really black pixels + } } } float oldMedian; - const float percentile = float(LIM(params->fattal.anchor, 1, 100)) / 100.f; - findMinMaxPercentile (Yr.data(), static_cast(Yr.getRows()) * Yr.getCols(), percentile, oldMedian, percentile, oldMedian, multiThread); + float percentile = 1.f; + + if (algo == 0) { + percentile = float(LIM(fatParams.anchor, 1, 100)) / 100.f; + findMinMaxPercentile(Yr.data(), static_cast(Yr.getRows()) * Yr.getCols(), percentile, oldMedian, percentile, oldMedian, multiThread); + } + // median filter on the deep shadows, to avoid boosting noise // because w2 >= w and h2 >= h, we can use the L buffer as temporary buffer for Median_Denoise() - int w2 = find_fast_dim (w) + 1; - int h2 = find_fast_dim (h) + 1; - Array2Df L (w2, h2); + int w2 = find_fast_dim(w) + 1; + int h2 = find_fast_dim(h) + 1; + Array2Df L(w2, h2); { #ifdef _OPENMP int num_threads = multiThread ? omp_get_max_threads() : 1; #else int num_threads = 1; #endif - float r = float (std::max (w, h)) / float (RT_dimension_cap); + float r = float (std::max(w, h)) / float (RT_dimension_cap); Median med; if (r >= 3) { @@ -1119,7 +1154,7 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) med = Median::TYPE_3X3_STRONG; } - Median_Denoise (Yr, Yr, luminance_noise_floor, w, h, med, 1, num_threads, L); + Median_Denoise(Yr, Yr, luminance_noise_floor, w, h, med, 1, num_threads, L); } float noise = alpha * 0.01f; @@ -1129,19 +1164,72 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) << ", detail_level = " << detail_level << std::endl; } - rescale_nearest (Yr, L, multiThread); - tmo_fattal02 (w2, h2, L, L, alpha, beta, noise, detail_level, multiThread); + rescale_nearest(Yr, L, multiThread); + + tmo_fattal02(w2, h2, L, L, alpha, beta, noise, detail_level, multiThread, 0); const float hr = float(h2) / float(h); const float wr = float(w2) / float(w); - float newMedian; - findMinMaxPercentile (L.data(), static_cast(L.getRows()) * L.getCols(), percentile, newMedian, percentile, newMedian, multiThread); - const float scale = (oldMedian == 0.f || newMedian == 0.f) ? 65535.f : (oldMedian / newMedian); // avoid Nan + float offset = 0.f; + float scale = 65535.f; + + if (algo == 0) { + float newMedian; + findMinMaxPercentile(L.data(), static_cast(L.getRows()) * L.getCols(), percentile, newMedian, percentile, newMedian, multiThread); + scale = (oldMedian == 0.f || newMedian == 0.f) ? 65535.f : (oldMedian / newMedian); // avoid Nan + } else { + + scale = 65535.f; + { + float ratio = 0.f; + int ww, hh; + + if (w >= h) { + ratio = 200.f / w; + ww = 200; + hh = ratio * h; + } else { + ratio = 200.f / h; + hh = 200; + ww = ratio * w; + } + + Array2Df tmp(ww, hh); + int sz = ww * hh; + int idx = sz / 2; + int oidx = LIM(int(sz * 0.05f + 0.5f), 1, sz - 1); + rescale_nearest(Yr, tmp, multiThread); + std::sort(tmp.data(), tmp.data() + sz); + float oldMedian = tmp(idx); + float old_min = 0.f; + + for (int i = 0; i <= oidx; ++i) { + old_min += tmp(i); + } + + old_min /= oidx; + rescale_nearest(L, tmp, multiThread); + std::sort(tmp.data(), tmp.data() + sz); + float newMedian = tmp(idx); + scale = (oldMedian == 0.f || newMedian == 0.f) ? 65535.f : (oldMedian / newMedian); // avoid Nan + float new_min = 0.f; + + for (int i = 0; i <= oidx; ++i) { + new_min += tmp(i); + } + + new_min /= oidx; + offset = old_min - new_min; + } + + + } #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if(multiThread) #endif + for (int y = 0; y < h; y++) { int yy = y * hr + 1; @@ -1150,16 +1238,106 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) float Y = std::max(Yr(x, y), epsilon); float l = std::max(L(xx, yy), epsilon) * (scale / Y); - rgb->r(y, x) *= l; - rgb->g(y, x) *= l; - rgb->b(y, x) *= l; - assert(std::isfinite(rgb->r(y, x))); - assert(std::isfinite(rgb->g(y, x))); - assert(std::isfinite(rgb->b(y, x))); + if (Lalone == 0) { + float &r = rgb->r(y, x); + float &g = rgb->g(y, x); + float &b = rgb->b(y, x); + if(l > 1.f) { + r = max(r * l - offset, r); + g = max(g * l - offset, g); + b = max(b * l - offset, b); + } else { + r *= l; + g *= l; + b *= l; + } + assert(std::isfinite(rgb->r(y, x))); + assert(std::isfinite(rgb->g(y, x))); + assert(std::isfinite(rgb->b(y, x))); + } else { + if (Lalone == 1) { + Lum[y][x] *= (0.5f * l - offset); + } else if (Lalone == -1) { + Lum[y][x] *= (-0.5f * l + offset); + } + } } } + } +void buildGradientsMask(int W, int H, float **luminance, float **out, + float amount, int nlevels, int detail_level, + float alfa, float beta, bool multithread) +{ + Array2Df Y(W, H, luminance); + const float noise = alfa * 0.01f; + + Array2Df *pyramids[nlevels]; + pyramids[0] = &Y; + createGaussianPyramids(pyramids, nlevels, multithread); + + // calculate gradients and its average values on pyramid levels + Array2Df *gradients[nlevels]; + float avgGrad[nlevels]; + + for (int k = 0 ; k < nlevels ; k++) { + gradients[k] = new Array2Df(pyramids[k]->getCols(), pyramids[k]->getRows()); + avgGrad[k] = calculateGradients(pyramids[k], gradients[k], k, multithread); + + if (k != 0) { // pyramids[0] is Y + delete pyramids[k]; + } + } + + + // calculate fi matrix + Array2Df FI(W, H, out); + calculateFiMatrix(&FI, gradients, avgGrad, nlevels, detail_level, alfa, beta, noise, multithread); + + for (int i = 0 ; i < nlevels ; i++) { + delete gradients[i]; + } + + // rescale the mask + float m = out[0][0]; +#ifdef _OPENMP + # pragma omp parallel for reduction(max:m) if (multithread) +#endif + + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float v = std::abs(out[y][x]); + out[y][x] = v; + m = std::max(v, m); + } + } + + if (m > 0.f) { + const float f = amount / m; +#ifdef _OPENMP + # pragma omp parallel for reduction(max:m) if (multithread) +#endif + + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + out[y][x] *= f; + } + } + } + + // { + // Imagefloat tmp(W, H); + // for (int y = 0; y < H; ++y) { + // for (int x = 0; x < W; ++x) { + // tmp.r(y, x) = tmp.g(y, x) = tmp.b(y, x) = out[y][x] * 65535.f; + // } + // } + // std::ostringstream name; + // name << "/tmp/FI-" << W << "x" << H << ".tif"; + // tmp.saveAsTIFF(name.str(), 16); + // } +} } // namespace rtengine diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index b01b0ac1c..5f5afa073 100644 --- a/rtengine/xtrans_demosaic.cc +++ b/rtengine/xtrans_demosaic.cc @@ -45,7 +45,9 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b if (!rgb) { static bool cbrtinit = false; if(!cbrtinit) { - #pragma omp parallel for +#ifdef _OPENMP + #pragma omp parallel for +#endif for (int i = 0; i < 0x14000; i++) { double r = i / 65535.0; cbrt[i] = r > Color::eps ? std::cbrt(r) : (Color::kappa * r + 16.0) / 116.0; diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index 06604ade5..c0038c067 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -1510,8 +1510,6 @@ int Tag::toInt (int ofs, TagType astype) const return attrib->interpreter->toInt (this, ofs, astype); } - int a; - if (astype == INVALID) { astype = type; } @@ -1537,10 +1535,15 @@ int Tag::toInt (int ofs, TagType astype) const case LONG: return (int)sget4 (value + ofs, getOrder()); - case SRATIONAL: - case RATIONAL: - a = (int)sget4 (value + ofs + 4, getOrder()); + case SRATIONAL: { + int a = (int)sget4 (value + ofs + 4, getOrder()); return a == 0 ? 0 : (int)sget4 (value + ofs, getOrder()) / a; + } + + case RATIONAL: { + uint32_t a = (uint32_t)sget4 (value + ofs + 4, getOrder()); + return a == 0 ? 0 : (uint32_t)sget4 (value + ofs, getOrder()) / a; + } case FLOAT: return (int)toDouble (ofs); @@ -1589,10 +1592,14 @@ double Tag::toDouble (int ofs) const return (double) ((int)sget4 (value + ofs, getOrder())); case SRATIONAL: - case RATIONAL: ud = (int)sget4 (value + ofs, getOrder()); dd = (int)sget4 (value + ofs + 4, getOrder()); - return dd == 0. ? 0. : (double)ud / (double)dd; + return dd == 0. ? 0. : ud / dd; + + case RATIONAL: + ud = (uint32_t)sget4 (value + ofs, getOrder()); + dd = (uint32_t)sget4 (value + ofs + 4, getOrder()); + return dd == 0. ? 0. : ud / dd; case FLOAT: conv.i = sget4 (value + ofs, getOrder()); @@ -1735,10 +1742,13 @@ void Tag::toString (char* buffer, int ofs) const break; case SRATIONAL: - case RATIONAL: sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder())); break; + case RATIONAL: + sprintf (b, "%u/%u", (uint32_t)sget4 (value + 8 * i + ofs, getOrder()), (uint32_t)sget4 (value + 8 * i + ofs + 4, getOrder())); + break; + case FLOAT: sprintf (b, "%g", toDouble (8 * i + ofs)); break; @@ -3049,19 +3059,14 @@ void ExifManager::parse (bool isRaw, bool skipIgnored, bool parseJpeg) bool frameRootDetected = false; - if(!frameRootDetected) { - std::vector risTagList = root->findTags("RawImageSegmentation"); - if (!risTagList.empty()) { - for (auto ris : risTagList) { - frames.push_back(ris->getParent()); - frameRootDetected = true; + for (auto ris : root->findTags("RawImageSegmentation")) { + frames.push_back(ris->getParent()); + frameRootDetected = true; - #if PRINT_METADATA_TREE - printf("\n--------------- FRAME (RAWIMAGESEGMENTATION) ---------------\n\n"); - ris->getParent()->printAll (); - #endif - } - } +#if PRINT_METADATA_TREE + printf("\n--------------- FRAME (RAWIMAGESEGMENTATION) ---------------\n\n"); + ris->getParent()->printAll (); +#endif } if(!frameRootDetected) { diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index 1a956a4a5..5084f70de 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -434,13 +434,18 @@ public: case LONG: return (double) ((int)sget4 (t->getValue() + ofs, t->getOrder())); - case SRATIONAL: - case RATIONAL: { + case SRATIONAL: { const double dividend = (int)sget4 (t->getValue() + ofs, t->getOrder()); const double divisor = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); return divisor == 0. ? 0. : dividend / divisor; } + case RATIONAL: { + const double dividend = (uint32_t)sget4 (t->getValue() + ofs, t->getOrder()); + const double divisor = (uint32_t)sget4 (t->getValue() + ofs + 4, t->getOrder()); + return divisor == 0. ? 0. : dividend / divisor; + } + case FLOAT: return double (sget4 (t->getValue() + ofs, t->getOrder())); @@ -454,8 +459,6 @@ public: // Get the value as an int virtual int toInt (const Tag* t, int ofs = 0, TagType astype = INVALID) { - int a; - if (astype == INVALID || astype == AUTO) { astype = t->getType(); } @@ -480,10 +483,15 @@ public: case LONG: return (int)sget4 (t->getValue() + ofs, t->getOrder()); - case SRATIONAL: - case RATIONAL: - a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); + case SRATIONAL: { + int a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); return a == 0 ? 0 : (int)sget4 (t->getValue() + ofs, t->getOrder()) / a; + } + + case RATIONAL: { + uint32_t a = (uint32_t)sget4 (t->getValue() + ofs + 4, t->getOrder()); + return a == 0 ? 0 : (uint32_t)sget4 (t->getValue() + ofs, t->getOrder()) / a; + } case FLOAT: return (int)toDouble (t, ofs); diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 828151338..cfadb7928 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -34,6 +34,7 @@ set(NONCLISOURCEFILES colorappearance.cc coloredbar.cc colortoning.cc + controlspotpanel.cc coordinateadjuster.cc crop.cc crophandler.cc @@ -90,6 +91,9 @@ set(NONCLISOURCEFILES lensgeom.cc lensprofile.cc localcontrast.cc + locallab.cc + locallabtools.cc + locallabtools2.cc lockablecolorpicker.cc lwbutton.cc lwbuttonset.cc @@ -113,6 +117,7 @@ set(NONCLISOURCEFILES popuptogglebutton.cc preferences.cc preprocess.cc + preprocesswb.cc previewhandler.cc previewloader.cc previewmodepanel.cc diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 4462401be..4d7a08b5f 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -62,7 +62,8 @@ void BatchToolPanelCoordinator::selectionChanged (const std::vector& void BatchToolPanelCoordinator::closeSession (bool save) { - pparamsEdited.set (false); + // Should remain commented for Locallab to work + // pparamsEdited.set (false); for (size_t i = 0; i < selected.size(); i++) { selected[i]->removeThumbnailListener (this); @@ -139,7 +140,7 @@ void BatchToolPanelCoordinator::initSession () if (selected.size() == 1) { for (size_t i = 0; i < toolPanels.size(); i++) { - toolPanels.at(i)->setMultiImage(false); + toolPanels.at (i)->setMultiImage (false); } toneCurve->setAdjusterBehavior (false, false, false, false, false, false, false, false); @@ -177,14 +178,14 @@ void BatchToolPanelCoordinator::initSession () xtransprocess->setAdjusterBehavior(false, false); bayerpreprocess->setAdjusterBehavior (false, false); rawcacorrection->setAdjusterBehavior (false); - flatfield->setAdjusterBehavior(false); + flatfield->setAdjusterBehavior (false); rawexposure->setAdjusterBehavior (false); bayerrawexposure->setAdjusterBehavior (false); xtransrawexposure->setAdjusterBehavior (false); } else { for (size_t i = 0; i < toolPanels.size(); i++) { - toolPanels.at(i)->setMultiImage(true); + toolPanels.at (i)->setMultiImage (true); } toneCurve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT], options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL], options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]); @@ -225,7 +226,7 @@ void BatchToolPanelCoordinator::initSession () xtransprocess->setAdjusterBehavior(options.baBehav[ADDSET_BAYER_FALSE_COLOR_SUPPRESSION], options.baBehav[ADDSET_BAYER_DUALDEMOZCONTRAST]); bayerpreprocess->setAdjusterBehavior (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE], options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]); rawcacorrection->setAdjusterBehavior (options.baBehav[ADDSET_RAWCACORR]); - flatfield->setAdjusterBehavior(options.baBehav[ADDSET_RAWFFCLIPCONTROL]); + flatfield->setAdjusterBehavior (options.baBehav[ADDSET_RAWFFCLIPCONTROL]); rawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_LINEAR]); bayerrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]); xtransrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]); @@ -398,9 +399,12 @@ void BatchToolPanelCoordinator::initSession () for (size_t i = 0; i < paramcListeners.size(); i++) // send this initial state to the History { - paramcListeners[i]->procParamsChanged (&pparams, rtengine::EvPhotoLoaded, M("BATCH_PROCESSING"), &pparamsEdited); + paramcListeners[i]->procParamsChanged (&pparams, rtengine::EvPhotoLoaded, M ("BATCH_PROCESSING"), &pparamsEdited); } } + + // ParamsEdited are set to false for initialization and is updated each time panel is changed (mandatory for Locallab) + pparamsEdited.set(false); } void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) @@ -411,7 +415,8 @@ void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, c somethingChanged = true; - pparamsEdited.set (false); + // Should remain commented for Locallab to work + // pparamsEdited.set (false); // read new values from the gui for (size_t i = 0; i < toolPanels.size(); i++) { @@ -423,7 +428,7 @@ void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, c if (selected.size() == 1) { // Compensate rotation on flip if (event == rtengine::EvCTHFlip || event == rtengine::EvCTVFlip) { - if (fabs(pparams.rotate.degree) > 0.001) { + if (fabs (pparams.rotate.degree) > 0.001) { pparams.rotate.degree *= -1; rotate->read (&pparams); } @@ -431,7 +436,7 @@ void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, c int w, h; selected[0]->getFinalSize (selected[0]->getProcParams (), w, h); - crop->setDimensions(w, h); + crop->setDimensions (w, h); // Some transformations change the crop and resize parameter for convenience. if (event == rtengine::EvCTHFlip) { @@ -453,7 +458,7 @@ void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, c // Compensate rotation on flip if (event == rtengine::EvCTHFlip || event == rtengine::EvCTVFlip) { for (size_t i = 0; i < selected.size(); i++) { - if (fabs(initialPP[i].rotate.degree) > 0.001) { + if (fabs (initialPP[i].rotate.degree) > 0.001) { initialPP[i].rotate.degree *= -1.0; pparamsEdited.rotate.degree = false; @@ -495,30 +500,30 @@ void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, c int rotation = (360 + newDeg - oldDeg) % 360; ProcParams pptemp = selected[i]->getProcParams(); // Get actual procparams - if((pptemp.coarse.hflip != pptemp.coarse.vflip) && ((rotation % 180) == 90)) { + if ((pptemp.coarse.hflip != pptemp.coarse.vflip) && ((rotation % 180) == 90)) { rotation = (rotation + 180) % 360; } switch (rotation) { - case 90: - std::swap(crop.x, crop.y); - std::swap(crop.w, crop.h); + case 90: + std::swap (crop.x, crop.y); + std::swap (crop.w, crop.h); - crop.x = h - crop.x - crop.w; - break; + crop.x = h - crop.x - crop.w; + break; - case 270: - std::swap(crop.x, crop.y); - std::swap(crop.w, crop.h); + case 270: + std::swap (crop.x, crop.y); + std::swap (crop.w, crop.h); - crop.y = w - crop.y - crop.h; - break; + crop.y = w - crop.y - crop.h; + break; - case 180: - crop.x = w - crop.x - crop.w; - crop.y = h - crop.y - crop.h; - break; + case 180: + crop.x = w - crop.x - crop.w; + crop.y = h - crop.y - crop.h; + break; } initialPP[i].coarse.rotate = newDeg; @@ -605,13 +610,13 @@ void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChange } } -void BatchToolPanelCoordinator::beginBatchPParamsChange(int numberOfEntries) +void BatchToolPanelCoordinator::beginBatchPParamsChange (int numberOfEntries) { blockedUpdate = true; if (numberOfEntries > 50) { // Arbitrary amount - parent->set_sensitive(false); + parent->set_sensitive (false); } } @@ -622,7 +627,7 @@ void BatchToolPanelCoordinator::endBatchPParamsChange() closeSession (false); initSession (); blockedUpdate = false; - parent->set_sensitive(true); + parent->set_sensitive (true); } /* @@ -644,7 +649,7 @@ void BatchToolPanelCoordinator::profileChange( return; } - pparams = *(nparams->pparams); + pparams = * (nparams->pparams); if (paramsEdited) { pparamsEdited = *paramsEdited; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 5b5cfe9c4..66053a338 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar) +BayerProcess::BayerProcess () : + FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar), + oldMethod(-1) { auto m = ProcEventMapper::getInstance(); diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 93dafc1ba..5e540b604 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -79,6 +79,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) // if it is open, return it const auto iterator = openEntries.find (fname); + if (iterator != openEntries.end ()) { auto cachedThumbnail = iterator->second; @@ -102,9 +103,11 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) CacheImageData imageData; const auto error = imageData.load (cacheName); + if (error == 0 && imageData.supported) { thumbnail.reset (new Thumbnail (this, fname, &imageData)); + if (!thumbnail->isSupported ()) { thumbnail.reset (); } @@ -115,6 +118,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) if (!thumbnail) { thumbnail.reset (new Thumbnail (this, fname, md5)); + if (!thumbnail->isSupported ()) { thumbnail.reset (); } @@ -126,6 +130,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) MyMutex::MyLock lock (mutex); const auto iterator = openEntries.find (fname); + if (iterator != openEntries.end ()) { auto cachedThumbnail = iterator->second; @@ -148,6 +153,7 @@ void CacheManager::deleteEntry (const Glib::ustring& fname) // check if it is opened auto iterator = openEntries.find (fname); + if (iterator == openEntries.end ()) { deleteFiles (fname, getMD5 (fname), true, true); return; @@ -195,6 +201,7 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin // check if it is opened // if it is open, update md5 const auto iterator = openEntries.find (oldfilename); + if (iterator == openEntries.end ()) { return; } @@ -246,8 +253,10 @@ void CacheManager::clearProfiles () const MyMutex::MyLock lock (mutex); deleteDir ("profiles"); + } + void CacheManager::deleteDir (const Glib::ustring& dirName) const { try { @@ -255,6 +264,7 @@ void CacheManager::deleteDir (const Glib::ustring& dirName) const Glib::Dir dir (Glib::build_filename (baseDir, dirName)); auto error = 0; + for (auto entry = dir.begin (); entry != dir.end (); ++entry) { error |= g_remove (Glib::build_filename (baseDir, dirName, *entry).c_str ()); } @@ -325,9 +335,9 @@ std::string CacheManager::getMD5 (const Glib::ustring& fname) } Glib::ustring CacheManager::getCacheFileName (const Glib::ustring& subDir, - const Glib::ustring& fname, - const Glib::ustring& fext, - const Glib::ustring& md5) const + const Glib::ustring& fname, + const Glib::ustring& fext, + const Glib::ustring& md5) const { const auto dirName = Glib::build_filename (baseDir, subDir); const auto baseName = Glib::path_get_basename (fname) + "." + md5; diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h index 56370e966..61602aeba 100644 --- a/rtgui/cachemanager.h +++ b/rtgui/cachemanager.h @@ -59,7 +59,6 @@ public: void clearImages () const; void clearProfiles () const; void clearFromCache (const Glib::ustring& fname, bool purge) const; - static std::string getMD5 (const Glib::ustring& fname); Glib::ustring getCacheFileName (const Glib::ustring& subDir, diff --git a/rtgui/config.h.in b/rtgui/config.h.in index 558c25f76..d3fc58cf7 100644 --- a/rtgui/config.h.in +++ b/rtgui/config.h.in @@ -22,8 +22,9 @@ #cmakedefine BUILD_BUNDLE #cmakedefine HAVE_UNALIGNED_MALLOC +#cmakedefine OSX_DEV_BUILD -#ifdef __APPLE__ +#if defined(__APPLE__) && !defined(OSX_DEV_BUILD) #define DATA_SEARCH_PATH "/Applications/RawTherapee.app/Contents/Resources/share" #define DOC_SEARCH_PATH "/Applications/RawTherapee.app/Contents/Resources" #define CREDITS_SEARCH_PATH "/Applications/RawTherapee.app/Contents/Resources" diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc new file mode 100644 index 000000000..83d62f572 --- /dev/null +++ b/rtgui/controlspotpanel.cc @@ -0,0 +1,2516 @@ +/* + * 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 . + * 2018 Pierre Cabrera + */ + +#include "../rtengine/rt_math.h" +#include "controlspotpanel.h" +#include "editwidgets.h" +#include "options.h" +#include "../rtengine/procparams.h" +#include "rtimage.h" + +using namespace rtengine; +using namespace procparams; + +extern Options options; + +//----------------------------------------------------------------------------- +// ControlSpotPanel +//----------------------------------------------------------------------------- + +ControlSpotPanel::ControlSpotPanel(): + EditSubscriber(ET_OBJECTS), + FoldableToolPanel(this, "controlspotpanel", M("TP_LOCALLAB_SETTINGS")), + + scrolledwindow_(Gtk::manage(new Gtk::ScrolledWindow())), + treeview_(Gtk::manage(new Gtk::TreeView())), + + button_add_(Gtk::manage(new Gtk::Button(M("TP_LOCALLAB_BUTTON_ADD")))), + button_delete_(Gtk::manage(new Gtk::Button(M("TP_LOCALLAB_BUTTON_DEL")))), + button_duplicate_(Gtk::manage(new Gtk::Button(M("TP_LOCALLAB_BUTTON_DUPL")))), + + button_rename_(Gtk::manage(new Gtk::Button(M("TP_LOCALLAB_BUTTON_REN")))), + button_visibility_(Gtk::manage(new Gtk::Button(M("TP_LOCALLAB_BUTTON_VIS")))), + + shape_(Gtk::manage(new MyComboBoxText())), + spotMethod_(Gtk::manage(new MyComboBoxText())), + shapeMethod_(Gtk::manage(new MyComboBoxText())), + qualityMethod_(Gtk::manage(new MyComboBoxText())), + complexMethod_(Gtk::manage(new MyComboBoxText())), + wavMethod_(Gtk::manage(new MyComboBoxText())), + + sensiexclu_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIEXCLU"), 0, 100, 1, 12))), + structexclu_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUCCOL"), 0, 100, 1, 0))), + locX_(Gtk::manage(new Adjuster(M("TP_LOCAL_WIDTH"), 2, 3000, 1, 150))), + locXL_(Gtk::manage(new Adjuster(M("TP_LOCAL_WIDTH_L"), 2, 3000, 1, 150))), + locY_(Gtk::manage(new Adjuster(M("TP_LOCAL_HEIGHT"), 2, 3000, 1, 150))), + locYT_(Gtk::manage(new Adjuster(M("TP_LOCAL_HEIGHT_T"), 2, 3000, 1, 150))), + centerX_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CENTER_X"), -1000, 1000, 1, 0))), + centerY_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CENTER_Y"), -1000, 1000, 1, 0))), + circrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CIRCRADIUS"), 2, 150, 1, 18))), + transit_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TRANSITVALUE"), 2., 100., 0.1, 60.))), + transitweak_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TRANSITWEAK"), 0.5, 25.0, 0.1, 1.0))), + transitgrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TRANSITGRAD"), -1.0, 1.0, 0.01, 0.0))), + feather_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FEATVALUE"), 10., 100., 0.1, 25.))), + struc_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_THRES"), 1.0, 12.0, 0.1, 4.0))), + thresh_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_THRESDELTAE"), 0.0, 10.0, 0.1, 2.0))), + iter_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_PROXI"), 0.2, 10.0, 0.1, 2.0))), + balan_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BALAN"), 0.2, 2.5, 0.1, 1.0, Gtk::manage(new RTImage("rawtherapee-logo-16.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + balanh_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BALANH"), 0.2, 2.5, 0.1, 1.0, Gtk::manage(new RTImage("rawtherapee-logo-16.png")), Gtk::manage(new RTImage("circle-red-green-small.png"))))), + colorde_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_COLORDE"), -15, 15, 2, 5, Gtk::manage(new RTImage("circle-blue-yellow-small.png")), Gtk::manage(new RTImage("circle-gray-green-small.png"))))), + colorscope_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_COLORSCOPE"), 0., 100.0, 1., 30.))), + scopemask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCOPEMASK"), 0, 100, 1, 60))), + lumask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LUMASK"), 0, 30, 1, 10))), + + avoid_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AVOID")))), + blwh_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_BLWH")))), + recurs_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_RECURS")))), + laplac_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_LAPLACC")))), + deltae_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_DELTAEC")))), + shortc_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_SHORTC")))), + savrest_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_SAVREST")))), + + expTransGrad_(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_TRANSIT")))), + expShapeDetect_(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_ARTIF")))), + expSpecCases_(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SPECCASE")))), + expMaskMerge_(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_MASFRAME")))), + + preview_(Gtk::manage(new Gtk::ToggleButton(M("TP_LOCALLAB_PREVIEW")))), + + controlPanelListener(nullptr), + lastObject_(-1), + nbSpotChanged_(false), + selSpotChanged_(false), + nameChanged_(false), + visibilityChanged_(false), + eventType(None), + excluFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_EXCLUF")))), + maskPrevActive(false) +{ + const bool showtooltip = options.showtooltip; + + Gtk::HBox* const hbox1_ = Gtk::manage(new Gtk::HBox(true, 4)); + buttonaddconn_ = button_add_->signal_clicked().connect( + sigc::mem_fun(*this, &ControlSpotPanel::on_button_add)); + buttondeleteconn_ = button_delete_->signal_clicked().connect( + sigc::mem_fun(*this, &ControlSpotPanel::on_button_delete)); + buttonduplicateconn_ = button_duplicate_->signal_clicked().connect( + sigc::mem_fun(*this, &ControlSpotPanel::on_button_duplicate)); + + hbox1_->pack_start(*button_add_); + hbox1_->pack_start(*button_delete_); + hbox1_->pack_start(*button_duplicate_); + pack_start(*hbox1_); + + Gtk::HBox* const hbox2_ = Gtk::manage(new Gtk::HBox(true, 4)); + buttonrenameconn_ = button_rename_->signal_clicked().connect( + sigc::mem_fun(*this, &ControlSpotPanel::on_button_rename)); + buttonvisibilityconn_ = button_visibility_->signal_button_release_event().connect( + sigc::mem_fun(*this, &ControlSpotPanel::on_button_visibility)); + + + if (showtooltip) { + button_visibility_->set_tooltip_markup(M("TP_LOCALLAB_VIS_TOOLTIP")); + } + + hbox2_->pack_start(*button_rename_); + hbox2_->pack_start(*button_visibility_); + pack_start(*hbox2_); + + treemodel_ = Gtk::ListStore::create(spots_); + treeview_->set_model(treemodel_); + treeviewconn_ = treeview_->get_selection()->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::controlspotChanged)); + treeview_->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_VERTICAL); + + // Disable search to prevent hijacking keyboard shortcuts #5265 + treeview_->set_enable_search(false); + treeview_->signal_key_press_event().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::blockTreeviewSearch), false); + + // Avoid situation where no spot is selected (Ctrl+click on treeview) + treeview_->signal_button_press_event().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::onSpotSelectionEvent), false); + + auto cell = Gtk::manage(new Gtk::CellRendererText()); + int cols_count = treeview_->append_column(M("TP_LOCALLAB_COL_NAME"), *cell); + auto col = treeview_->get_column(cols_count - 1); + + if (col) { + col->set_cell_data_func( + *cell, sigc::mem_fun( + *this, &ControlSpotPanel::render_name)); + } + + cell = Gtk::manage(new Gtk::CellRendererText()); + cols_count = treeview_->append_column(M("TP_LOCALLAB_COL_VIS"), *cell); + col = treeview_->get_column(cols_count - 1); + + if (col) { + col->set_cell_data_func( + *cell, sigc::mem_fun( + *this, &ControlSpotPanel::render_isvisible)); + } + + scrolledwindow_->add(*treeview_); + scrolledwindow_->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + scrolledwindow_->set_min_content_height(150); + pack_start(*scrolledwindow_); + + Gtk::HBox* const ctboxshape = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labelshape = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_SHAPETYPE") + ":")); + ctboxshape->pack_start(*labelshape, Gtk::PACK_SHRINK, 4); + shape_->append(M("TP_LOCALLAB_ELI")); + shape_->append(M("TP_LOCALLAB_RECT")); + shape_->set_active(0); + shapeconn_ = shape_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::shapeChanged)); + ctboxshape->pack_start(*shape_); + pack_start(*ctboxshape); + if (showtooltip) { + shape_->set_tooltip_text(M("TP_LOCALLAB_SHAPE_TOOLTIP")); + } + + Gtk::HBox* const ctboxspotmethod = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labelspotmethod = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_EXCLUTYPE") + ":")); + ctboxspotmethod->pack_start(*labelspotmethod, Gtk::PACK_SHRINK, 4); + + if (showtooltip) { + ctboxspotmethod->set_tooltip_markup(M("TP_LOCALLAB_EXCLUTYPE_TOOLTIP")); + } + + spotMethod_->append(M("TP_LOCALLAB_EXNORM")); + spotMethod_->append(M("TP_LOCALLAB_EXECLU")); + spotMethod_->set_active(0); + spotMethodconn_ = spotMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::spotMethodChanged)); + ctboxspotmethod->pack_start(*spotMethod_); + pack_start(*ctboxspotmethod); + + excluFrame->set_label_align(0.025, 0.5); + + if (showtooltip) { + excluFrame->set_tooltip_text(M("TP_LOCALLAB_EXCLUF_TOOLTIP")); + } + + ToolParamBlock* const excluBox = Gtk::manage(new ToolParamBlock()); + + if (showtooltip) { + sensiexclu_->set_tooltip_text(M("TP_LOCALLAB_SENSIEXCLU_TOOLTIP")); + } + + sensiexclu_->setAdjusterListener(this); + structexclu_->setAdjusterListener(this); + structexclu_->setLogScale(10, 0); + + excluBox->pack_start(*sensiexclu_); + excluBox->pack_start(*structexclu_); + excluFrame->add(*excluBox); + pack_start(*excluFrame); + + Gtk::HBox* const ctboxshapemethod = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labelshapemethod = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_STYPE") + ":")); + ctboxshapemethod->pack_start(*labelshapemethod, Gtk::PACK_SHRINK, 4); + + if (showtooltip) { + ctboxshapemethod->set_tooltip_markup(M("TP_LOCALLAB_STYPE_TOOLTIP")); + } + + shapeMethod_->append(M("TP_LOCALLAB_IND")); + shapeMethod_->append(M("TP_LOCALLAB_SYM")); + shapeMethod_->append(M("TP_LOCALLAB_INDSL")); + shapeMethod_->append(M("TP_LOCALLAB_SYMSL")); + shapeMethod_->set_active(0); + shapeMethodconn_ = shapeMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::shapeMethodChanged)); + ctboxshapemethod->pack_start(*shapeMethod_); +// pack_start(*ctboxshapemethod); + + pack_start(*locX_); + locX_->setAdjusterListener(this); + + pack_start(*locXL_); + locXL_->setAdjusterListener(this); + + pack_start(*locY_); + locY_->setAdjusterListener(this); + + pack_start(*locYT_); + locYT_->setAdjusterListener(this); + + pack_start(*centerX_); + centerX_->setAdjusterListener(this); + + pack_start(*centerY_); + centerY_->setAdjusterListener(this); + + pack_start(*circrad_); + circrad_->setAdjusterListener(this); + + if (showtooltip) { + circrad_->set_tooltip_text(M("TP_LOCALLAB_CIRCRAD_TOOLTIP")); + } + + Gtk::HBox* const ctboxqualitymethod = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labelqualitymethod = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_QUAL_METHOD") + ":")); + ctboxqualitymethod->pack_start(*labelqualitymethod, Gtk::PACK_SHRINK, 4); + + if (showtooltip) { + ctboxqualitymethod->set_tooltip_markup(M("TP_LOCALLAB_METHOD_TOOLTIP")); + } + + qualityMethod_->append(M("TP_LOCALLAB_ENH")); + qualityMethod_->append(M("TP_LOCALLAB_ENHDEN")); + qualityMethod_->set_active(1); + qualityMethodconn_ = qualityMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::qualityMethodChanged)); + ctboxqualitymethod->pack_start(*qualityMethod_); +// pack_start(*ctboxqualitymethod); + + if (showtooltip) { + expTransGrad_->set_tooltip_text(M("TP_LOCALLAB_TRANSIT_TOOLTIP")); + } + + ToolParamBlock* const transitBox = Gtk::manage(new ToolParamBlock()); + + if (showtooltip) { + transit_->set_tooltip_text(M("TP_LOCALLAB_TRANSIT_TOOLTIP")); + } + + if (showtooltip) { + transitweak_->set_tooltip_text(M("TP_LOCALLAB_TRANSITWEAK_TOOLTIP")); + } + + if (showtooltip) { + feather_->set_tooltip_text(M("TP_LOCALLAB_FEATH_TOOLTIP")); + } + + if (showtooltip) { + transitgrad_->set_tooltip_text(M("TP_LOCALLAB_TRANSITGRAD_TOOLTIP")); + } + + if (showtooltip) { + scopemask_->set_tooltip_text(M("TP_LOCALLAB_SCOPEMASK_TOOLTIP")); + } + + transit_->setAdjusterListener(this); + transitweak_->setAdjusterListener(this); + transitgrad_->setAdjusterListener(this); + feather_->setAdjusterListener(this); + scopemask_->setAdjusterListener(this); + transitBox->pack_start(*transit_); + transitBox->pack_start(*transitweak_); + transitBox->pack_start(*transitgrad_); + transitBox->pack_start(*feather_); + expTransGrad_->add(*transitBox, false); + pack_start(*expTransGrad_, false, false); + + if (showtooltip) { + expShapeDetect_->set_tooltip_text(M("TP_LOCALLAB_ARTIF_TOOLTIP")); + } + + ToolParamBlock* const artifBox = Gtk::manage(new ToolParamBlock()); + struc_->setAdjusterListener(this); + thresh_->setAdjusterListener(this); + iter_->setAdjusterListener(this); + balan_->setAdjusterListener(this); + balanh_->setAdjusterListener(this); + colorde_->setAdjusterListener(this); + colorscope_->setAdjusterListener(this); + + preview_->set_active(false); + previewConn_ = preview_->signal_clicked().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::previewChanged)); + + if (showtooltip) { + balan_->set_tooltip_text(M("TP_LOCALLAB_BALAN_TOOLTIP")); + balanh_->set_tooltip_text(M("TP_LOCALLAB_BALAN_TOOLTIP")); + colorde_->set_tooltip_text(M("TP_LOCALLAB_COLORDE_TOOLTIP")); + colorscope_->set_tooltip_text(M("TP_LOCALLAB_COLORSCOPE_TOOLTIP")); + preview_->set_tooltip_text(M("TP_LOCALLAB_COLORDEPREV_TOOLTIP")); + } + +// artifBox->pack_start(*struc_); + artifBox->pack_start(*thresh_); + artifBox->pack_start(*iter_); + artifBox->pack_start(*balan_); + artifBox->pack_start(*balanh_); + artifBox->pack_start(*colorde_); + artifBox->pack_start(*preview_); + artifBox->pack_start(*colorscope_); + expShapeDetect_->add(*artifBox, false); + pack_start(*expShapeDetect_, false, false); + + ToolParamBlock* const specCaseBox = Gtk::manage(new ToolParamBlock()); + + avoidConn_ = avoid_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::avoidChanged)); + specCaseBox->pack_start(*avoid_); + + blwhConn_ = blwh_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::blwhChanged)); + + if (showtooltip) { + blwh_->set_tooltip_text(M("TP_LOCALLAB_BLWH_TOOLTIP")); + } + + specCaseBox->pack_start(*blwh_); + + recursConn_ = recurs_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::recursChanged)); + + if (showtooltip) { + recurs_->set_tooltip_text(M("TP_LOCALLAB_RECURS_TOOLTIP")); + avoid_->set_tooltip_text(M("TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP")); + } + + specCaseBox->pack_start(*recurs_); + expSpecCases_->add(*specCaseBox, false); + pack_start(*expSpecCases_, false, false); + + if (showtooltip) { + expMaskMerge_->set_tooltip_text(M("TP_LOCALLAB_MASFRAME_TOOLTIP")); + } + + ToolParamBlock* const maskBox = Gtk::manage(new ToolParamBlock()); + laplacConn_ = laplac_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::laplacChanged)); + deltaeConn_ = deltae_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::deltaeChanged)); + shortcConn_ = shortc_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::shortcChanged)); + + if (showtooltip) { + shortc_->set_tooltip_text(M("TP_LOCALLAB_SHORTCMASK_TOOLTIP")); + } + + lumask_->setAdjusterListener(this); + savrestConn_ = savrest_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::savrestChanged)); + + if (showtooltip) { + savrest_->set_tooltip_text(M("TP_LOCALLAB_SAVREST_TOOLTIP")); + lumask_->set_tooltip_text(M("TP_LOCALLAB_LUMASK_TOOLTIP")); + laplac_->set_tooltip_text(M("TP_LOCALLAB_LAP_MASK_TOOLTIP")); + } + + maskBox->pack_start(*laplac_); + maskBox->pack_start(*deltae_); + maskBox->pack_start(*scopemask_); + // maskBox->pack_start(*shortc_); + maskBox->pack_start(*lumask_); + // maskBox->pack_start(*savrest_); + expMaskMerge_->add(*maskBox, false); + pack_start(*expMaskMerge_, false, false); + + Gtk::HSeparator *separatormet = Gtk::manage(new Gtk::HSeparator()); + pack_start(*separatormet, Gtk::PACK_SHRINK, 2); + + Gtk::HBox* const ctboxcomplexmethod = Gtk::manage(new Gtk::HBox()); + + if (showtooltip) { + ctboxcomplexmethod->set_tooltip_markup(M("TP_LOCALLAB_COMPLEXMETHOD_TOOLTIP")); + } + + Gtk::Label* const labelcomplexmethod = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_COMPLEX_METHOD") + ":")); + ctboxcomplexmethod->pack_start(*labelcomplexmethod, Gtk::PACK_SHRINK, 4); + + if (showtooltip) { + complexMethod_->set_tooltip_markup(M("TP_LOCALLAB_COMPLEX_TOOLTIP")); + } + + complexMethod_->append(M("TP_LOCALLAB_SIM")); + complexMethod_->append(M("TP_LOCALLAB_MED")); + complexMethod_->append(M("TP_LOCALLAB_ALL")); + complexMethod_->set_active(1); + complexMethodconn_ = complexMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::complexMethodChanged)); + ctboxcomplexmethod->pack_start(*complexMethod_); + // pack_start(*ctboxcomplexmethod); + + Gtk::HBox* const ctboxwavmethod = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labelwavmethod = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DAUBLOCAL") + ":")); + ctboxwavmethod->pack_start(*labelwavmethod, Gtk::PACK_SHRINK, 4); + + if (showtooltip) { + ctboxwavmethod->set_tooltip_markup(M("TP_WAVELET_DAUB_TOOLTIP")); + } + + wavMethod_->append(M("TP_WAVELET_DAUB2")); + wavMethod_->append(M("TP_WAVELET_DAUB4")); + wavMethod_->append(M("TP_WAVELET_DAUB6")); + wavMethod_->append(M("TP_WAVELET_DAUB10")); + wavMethod_->append(M("TP_WAVELET_DAUB14")); + wavMethod_->set_active(1); + wavMethodconn_ = wavMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::wavMethodChanged)); + ctboxwavmethod->pack_start(*wavMethod_); + pack_start(*ctboxwavmethod); + + show_all(); + + // Define row background color + // Mouseovered spot (opaque orange) + colorMouseover.set_red(1.); + colorMouseover.set_green(100. / 255.); + colorMouseover.set_blue(0.); + colorMouseover.set_alpha(1.); + + colorMouseovertext.set_red(0.6); + colorMouseovertext.set_green(100. / 255.); + colorMouseovertext.set_blue(0.); + colorMouseovertext.set_alpha(0.5); + + // Nominal spot (transparent black) + colorNominal.set_red(0.); + colorNominal.set_green(0.); + colorNominal.set_blue(0.); + colorNominal.set_alpha(0.); +} + +ControlSpotPanel::~ControlSpotPanel() +{ + // visibleGeometry + for (auto i = EditSubscriber::visibleGeometry.begin(); i != EditSubscriber::visibleGeometry.end(); ++i) { + delete *i; + } + + // mouseOverGeometry + for (auto i = EditSubscriber::mouseOverGeometry.begin(); i != EditSubscriber::mouseOverGeometry.end(); ++i) { + delete *i; + } +} + +void ControlSpotPanel::setEditProvider(EditDataProvider* provider) +{ + EditSubscriber::setEditProvider(provider); +} + +void ControlSpotPanel::render_name( + Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter) +{ + auto row = *iter; + Gtk::CellRendererText *ct = static_cast(cell); + + // Render cell text + ct->property_text() = row[spots_.name]; + + // Render cell background color + if (row[spots_.mouseover]) { + ct->property_background_rgba() = colorMouseovertext; + } else { + ct->property_background_rgba() = colorNominal; + } +} + +void ControlSpotPanel::render_isvisible( + Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter) +{ + auto row = *iter; + Gtk::CellRendererText *ct = static_cast(cell); + + // Render cell text + if (row[spots_.isvisible]) { + ct->property_text() = M("TP_LOCALLAB_ROW_VIS"); + } else { + ct->property_text() = M("TP_LOCALLAB_ROW_NVIS"); + } + + // Render cell background color + if (row[spots_.mouseover]) { + ct->property_background_rgba() = colorMouseovertext; + } else { + ct->property_background_rgba() = colorNominal; + } +} + +void ControlSpotPanel::on_button_add() +{ + // printf("on_button_add\n"); + + if (!listener) { + return; + } + + // Raise event + nbSpotChanged_ = true; + selSpotChanged_ = true; + eventType = SpotCreation; + listener->panelChanged(EvLocallabSpotCreated, "-"); +} + +void ControlSpotPanel::on_button_delete() +{ + // printf("on_button_delete\n"); + + if (!listener) { + return; + } + + // Raise event + const int selIndex = getSelectedSpot(); + + if (selIndex == -1) { // No selected spot to remove + return; + } + + nbSpotChanged_ = true; + selSpotChanged_ = true; + eventType = SpotDeletion; + SpotRow* const delSpotRow = getSpot(selIndex); + listener->panelChanged(EvLocallabSpotDeleted, delSpotRow->name); +} + +void ControlSpotPanel::on_button_duplicate() +{ + // printf("on_button_duplicate\n"); + + if (!listener) { + return; + } + + // Raise event + const int selIndex = getSelectedSpot(); + + if (selIndex == -1) { // No selected spot to duplicate + return; + } + + nbSpotChanged_ = true; + selSpotChanged_ = true; + eventType = SpotDuplication; + SpotRow* const duplSpotRow = getSpot(selIndex); + listener->panelChanged(EvLocallabSpotCreated, M("TP_LOCALLAB_EV_DUPL") + " " + + duplSpotRow->name); +} + +void ControlSpotPanel::on_button_rename() +{ + // printf("on_button_rename\n"); + + if (!listener) { + return; + } + + // Get actual control spot name + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + const Gtk::TreeModel::Row row = *iter; + const Glib::ustring actualname = row[spots_.name]; + + // Launch windows to update spot name + RenameDialog d(actualname, + static_cast(*get_toplevel())); + int status = d.run(); + + // Update actual name and raise event + if (status == RenameDialog::OkButton) { + const Glib::ustring newname = d.get_new_name(); + + if (newname != actualname) { // Event is only raised if name is updated + nameChanged_ = true; + row[spots_.name] = newname; + treeview_->columns_autosize(); + listener->panelChanged(EvLocallabSpotName, newname); + } + } +} + +bool ControlSpotPanel::on_button_visibility(GdkEventButton* event) +{ + // printf("on_button_visibility\n"); + + if (!listener) { + return true; + } + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return true; + } + + const auto iter = s->get_selected(); + const Gtk::TreeModel::Row row = *iter; + + const int ctrl = event->state & GDK_CONTROL_MASK; + + if (event->button == 1) { // Left click on button + if (ctrl) { // Ctrl+click case: all spots are shown/hidden + // Get visibility of selected spot + const bool selVisibility = row[spots_.isvisible]; + + // Update visibility of all spot + const Gtk::TreeModel::Children children = treemodel_->children(); + + for (auto i = children.begin(); i != children.end(); i++) { + Gtk::TreeModel::Row r = *i; + r[spots_.isvisible] = !selVisibility; + updateControlSpotCurve(r); + } + + // Raise event + visibilityChanged_ = true; + eventType = SpotAllVisibilityChanged; + + if (!selVisibility) { + listener->panelChanged(EvLocallabSpotVisibility, M("TP_LOCALLAB_EV_VIS_ALL")); + } else { + listener->panelChanged(EvLocallabSpotVisibility, M("TP_LOCALLAB_EV_NVIS_ALL")); + } + + return true; + } else { // Click case: only selected spot is shown/hidden + // Update visibility for selected spot only + row[spots_.isvisible] = !row[spots_.isvisible]; + updateControlSpotCurve(row); + + // Raise event + visibilityChanged_ = true; + SpotRow* const spotRow = getSpot(getSelectedSpot()); + + if (row[spots_.isvisible]) { + listener->panelChanged(EvLocallabSpotVisibility, M("TP_LOCALLAB_EV_VIS") + " (" + spotRow->name + ")"); + } else { + listener->panelChanged(EvLocallabSpotVisibility, M("TP_LOCALLAB_EV_NVIS") + " (" + spotRow->name + ")"); + } + + return true; + } + } + + return false; +} + +bool ControlSpotPanel::blockTreeviewSearch(GdkEventKey* event) +{ + // printf("blockTreeviewSearch\n"); + + if (event->state & Gdk::CONTROL_MASK) { // Ctrl + if (event->keyval == GDK_KEY_f || event->keyval == GDK_KEY_F) { + // No action is performed to avoid activating treeview search + return true; + } + } + + // Otherwise key action is transferred to treeview widget + return false; +} + +bool ControlSpotPanel::onSpotSelectionEvent(GdkEventButton* event) +{ + if (event->state & Gdk::CONTROL_MASK) { // Ctrl + // No action is performed to avoid a situation where no spot is selected + return true; + } + + // Otherwise selection action is transferred to treeview widget + return false; +} + +void ControlSpotPanel::load_ControlSpot_param() +{ + // printf("load_ControlSpot_param\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + const Gtk::TreeModel::Row row = *iter; + + // Load param in selected control spot + shape_->set_active(row[spots_.shape]); + spotMethod_->set_active(row[spots_.spotMethod]); + sensiexclu_->setValue((double)row[spots_.sensiexclu]); + structexclu_->setValue((double)row[spots_.structexclu]); + shapeMethod_->set_active(row[spots_.shapeMethod]); + locX_->setValue((double)row[spots_.locX]); + locXL_->setValue((double)row[spots_.locXL]); + locY_->setValue((double)row[spots_.locY]); + locYT_->setValue((double)row[spots_.locYT]); + centerX_->setValue((double)row[spots_.centerX]); + centerY_->setValue((double)row[spots_.centerY]); + circrad_->setValue((double)row[spots_.circrad]); + qualityMethod_->set_active(row[spots_.qualityMethod]); + transit_->setValue((double)row[spots_.transit]); + transitweak_->setValue((double)row[spots_.transitweak]); + transitgrad_->setValue((double)row[spots_.transitgrad]); + feather_->setValue((double)row[spots_.feather]); + struc_->setValue((double)row[spots_.struc]); + thresh_->setValue((double)row[spots_.thresh]); + iter_->setValue((double)row[spots_.iter]); + balan_->setValue((double)row[spots_.balan]); + balanh_->setValue((double)row[spots_.balanh]); + colorde_->setValue((double)row[spots_.colorde]); + colorscope_->setValue((double)row[spots_.colorscope]); + avoid_->set_active(row[spots_.avoid]); + blwh_->set_active(row[spots_.blwh]); + recurs_->set_active(row[spots_.recurs]); + laplac_->set_active(row[spots_.laplac]); + deltae_->set_active(row[spots_.deltae]); + scopemask_->setValue((double)row[spots_.scopemask]); + shortc_->set_active(row[spots_.shortc]); + lumask_->setValue((double)row[spots_.lumask]); + savrest_->set_active(row[spots_.savrest]); + complexMethod_->set_active(row[spots_.complexMethod]); + wavMethod_->set_active(row[spots_.wavMethod]); +} + +void ControlSpotPanel::controlspotChanged() +{ + // printf("controlspotChanged\n"); + + if (!listener) { + return; + } + + // Raise event + const int selIndex = getSelectedSpot(); + + if (selIndex == -1) { // No selected spot + return; + } + + selSpotChanged_ = true; + eventType = SpotSelection; + SpotRow* const spotRow = getSpot(selIndex); + + // Image area shall be regenerated if mask or deltaE preview was active when switching spot + if (maskPrevActive || preview_->get_active()) { + listener->panelChanged(EvLocallabSpotSelectedWithMask, spotRow->name); + } else { + listener->panelChanged(EvLocallabSpotSelected, spotRow->name); + } +} + +void ControlSpotPanel::shapeChanged() +{ + // printf("shapeChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.shape] = shape_->get_active_row_number(); + updateControlSpotCurve(row); + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabSpotShape, shape_->get_active_text()); + } +} + +void ControlSpotPanel::spotMethodChanged() +{ + // printf("spotMethodChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.spotMethod] = spotMethod_->get_active_row_number(); + + // Update Control Spot GUI according to spotMethod_ combobox state (to be compliant with updateParamVisibility function) + if (multiImage && spotMethod_->get_active_text() == M("GENERAL_UNCHANGED")) { + excluFrame->show(); + } else if (spotMethod_->get_active_row_number() == 0) { // Normal case + excluFrame->hide(); + } else { // Excluding case + excluFrame->show(); + } + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabSpotSpotMethod, spotMethod_->get_active_text()); + } +} + +void ControlSpotPanel::shapeMethodChanged() +{ + // printf("shapeMethodChanged\n"); + + const int method = shapeMethod_->get_active_row_number(); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + if (!batchMode && (method == 1 || method == 3)) { // Symmetrical cases + disableParamlistener(true); + locXL_->setValue(locX_->getValue()); + locYT_->setValue(locY_->getValue()); + disableParamlistener(false); + + row[spots_.shapeMethod] = shapeMethod_->get_active_row_number(); + row[spots_.locXL] = locX_->getIntValue(); + row[spots_.locYT] = locY_->getIntValue(); + + updateControlSpotCurve(row); + } else { // In batch mode, sliders are always independent + row[spots_.shapeMethod] = shapeMethod_->get_active_row_number(); + } + + // Update Control Spot GUI according to shapeMethod_ combobox state (to be compliant with updateParamVisibility function) + if (!batchMode) { + if (method == 1 || method == 3) { // Symmetrical cases + locXL_->hide(); + locYT_->hide(); + + if (method == 1) { // 1 = Symmetrical (mouse) + locX_->hide(); + locY_->hide(); + centerX_->hide(); + centerY_->hide(); + } else { // 3 = Symmetrical (mouse + sliders) + locX_->show(); + locY_->show(); + centerX_->show(); + centerY_->show(); + } + } else { // Independent cases + if (method == 0) { // 0 = Independent (mouse) + locX_->hide(); + locXL_->hide(); + locY_->hide(); + locYT_->hide(); + centerX_->hide(); + centerY_->hide(); + } else { // 2 = Independent (mouse + sliders) + locX_->show(); + locXL_->show(); + locY_->show(); + locYT_->show(); + centerX_->show(); + centerY_->show(); + } + } + } else { // In batch mode, sliders are necessary shown + locX_->show(); + locXL_->show(); + locY_->show(); + locYT_->show(); + centerX_->show(); + centerY_->show(); + } + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabSpotShapeMethod, shapeMethod_->get_active_text()); + } +} + +void ControlSpotPanel::qualityMethodChanged() +{ + // printf("qualityMethodChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.qualityMethod] = qualityMethod_->get_active_row_number(); + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabSpotQualityMethod, qualityMethod_->get_active_text()); + } +} + +void ControlSpotPanel::complexMethodChanged() +{ + // printf("qualityMethodChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.complexMethod] = complexMethod_->get_active_row_number(); + + if (multiImage && complexMethod_->get_active_text() == M("GENERAL_UNCHANGED")) { + // excluFrame->show(); + } else if (complexMethod_->get_active_row_number() == 0) { //sim + // excluFrame->hide(); + } else if (complexMethod_->get_active_row_number() == 1) { // mod + // excluFrame->show(); + } else if (complexMethod_->get_active_row_number() == 2) { // all + // excluFrame->show(); + } + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabSpotcomplexMethod, complexMethod_->get_active_text()); + } +} + +void ControlSpotPanel::wavMethodChanged() +{ + // printf("qualityMethodChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.wavMethod] = wavMethod_->get_active_row_number(); + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabSpotwavMethod, wavMethod_->get_active_text()); + } +} + +void ControlSpotPanel::updateParamVisibility() +{ + // printf("updateParamVisibility\n"); + + // Update Control Spot GUI according to shapeMethod_ combobox state (to be compliant with shapeMethodChanged function) + const int method = shapeMethod_->get_active_row_number(); + + if (!batchMode) { + if (method == 1 || method == 3) { // Symmetrical cases + locXL_->hide(); + locYT_->hide(); + + if (method == 1) { // 1 = Symmetrical (mouse) + locX_->hide(); + locY_->hide(); + centerX_->hide(); + centerY_->hide(); + } else { // 3 = Symmetrical (mouse + sliders) + locX_->show(); + locY_->show(); + centerX_->show(); + centerY_->show(); + } + } else { // Independent cases + if (method == 0) { // 0 = Independent (mouse) + locX_->hide(); + locXL_->hide(); + locY_->hide(); + locYT_->hide(); + centerX_->hide(); + centerY_->hide(); + } else { // 2 = Independent (mouse + sliders) + locX_->show(); + locXL_->show(); + locY_->show(); + locYT_->show(); + centerX_->show(); + centerY_->show(); + } + } + } else { // In batch mode, sliders are necessary shown + locX_->show(); + locXL_->show(); + locY_->show(); + locYT_->show(); + centerX_->show(); + centerY_->show(); + } + + // Update Control Spot GUI according to spotMethod_ combobox state (to be compliant with spotMethodChanged function) + if (multiImage && spotMethod_->get_active_text() == M("GENERAL_UNCHANGED")) { + excluFrame->show(); + } else if (spotMethod_->get_active_row_number() == 0) { // Normal case + excluFrame->hide(); + } else { // Excluding case + excluFrame->show(); + } +} + +void ControlSpotPanel::adjusterChanged(Adjuster* a, double newval) +{ + // printf("adjusterChanged\n"); + + const int method = shapeMethod_->get_active_row_number(); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + if (a == sensiexclu_) { + row[spots_.sensiexclu] = sensiexclu_->getIntValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotSensiexclu, sensiexclu_->getTextValue()); + } + } + + if (a == structexclu_) { + row[spots_.structexclu] = structexclu_->getIntValue(); + + if (listener) { + listener->panelChanged(Evlocallabstructexlu, structexclu_->getTextValue()); + } + } + + if (a == locX_) { + row[spots_.locX] = locX_->getIntValue(); + + if (!batchMode && (method == 1 || method == 3)) { // Symmetrical cases (in batch mode, sliders are always independent) + disableParamlistener(true); + locXL_->setValue(locX_->getValue()); + disableParamlistener(false); + row[spots_.locXL] = locXL_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocX, locX_->getTextValue()); + } + } + + if (a == locXL_) { + row[spots_.locXL] = locXL_->getIntValue(); + + if (!batchMode && (method == 1 || method == 3)) { // Symmetrical cases (in batch mode, sliders are always independent) + disableParamlistener(true); + locX_->setValue(locXL_->getValue()); + disableParamlistener(false); + row[spots_.locX] = locX_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocXL, locXL_->getTextValue()); + } + } + + if (a == locY_) { + row[spots_.locY] = locY_->getIntValue(); + + if (!batchMode && (method == 1 || method == 3)) { // Symmetrical cases (in batch mode, sliders are always independent) + disableParamlistener(true); + locYT_->setValue(locY_->getValue()); + disableParamlistener(false); + row[spots_.locYT] = locYT_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocY, locY_->getTextValue()); + } + } + + if (a == locYT_) { + row[spots_.locYT] = locYT_->getIntValue(); + + if (!batchMode && (method == 1 || method == 3)) { // Symmetrical cases (in batch mode, sliders are always independent) + disableParamlistener(true); + locY_->setValue(locYT_->getValue()); + disableParamlistener(false); + row[spots_.locY] = locY_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocYT, locYT_->getTextValue()); + } + } + + if (a == centerX_ || a == centerY_) { + row[spots_.centerX] = centerX_->getIntValue(); + row[spots_.centerY] = centerY_->getIntValue(); + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotCenter, "X=" + centerX_->getTextValue() + ", Y=" + centerY_->getTextValue()); + } + } + + if (a == circrad_) { + row[spots_.circrad] = circrad_->getIntValue(); + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotCircrad, circrad_->getTextValue()); + } + } + + if (a == transit_) { + row[spots_.transit] = transit_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotTransit, transit_->getTextValue()); + } + } + + if (a == transitweak_) { + row[spots_.transitweak] = transitweak_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotTransitweak, transitweak_->getTextValue()); + } + } + + if (a == transitgrad_) { + row[spots_.transitgrad] = transitgrad_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotTransitgrad, transitgrad_->getTextValue()); + } + } + + if (a == feather_) { + row[spots_.feather] = feather_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotfeather, feather_->getTextValue()); + } + } + + if (a == struc_) { + row[spots_.struc] = struc_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotStruc, struc_->getTextValue()); + } + } + + if (a == thresh_) { + row[spots_.thresh] = thresh_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotThresh, thresh_->getTextValue()); + } + } + + if (a == iter_) { + row[spots_.iter] = iter_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotIter, iter_->getTextValue()); + } + } + + if (a == balan_) { + row[spots_.balan] = balan_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotbalan, balan_->getTextValue()); + } + } + + if (a == balanh_) { + row[spots_.balanh] = balanh_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotbalanh, balanh_->getTextValue()); + } + } + + if (a == colorde_) { + row[spots_.colorde] = colorde_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotcolorde, colorde_->getTextValue()); + } + } + + if (a == colorscope_) { + row[spots_.colorscope] = colorscope_->getValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotcolorscope, colorscope_->getTextValue()); + } + } + + if (a == scopemask_) { + row[spots_.scopemask] = scopemask_->getIntValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotscopemask, scopemask_->getTextValue()); + } + } + + if (a == lumask_) { + row[spots_.lumask] = lumask_->getIntValue(); + + if (listener) { + listener->panelChanged(EvLocallabSpotlumask, lumask_->getTextValue()); + } + } +} + +void ControlSpotPanel::avoidChanged() +{ + // printf("avoidChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.avoid] = avoid_->get_active(); + + // Raise event + if (listener) { + if (avoid_->get_active()) { + listener->panelChanged(Evlocallabavoid, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabavoid, M("GENERAL_DISABLED")); + } + } +} + +void ControlSpotPanel::blwhChanged() +{ + // printf("blwhChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.blwh] = blwh_->get_active(); + + // Raise event + if (listener) { + if (blwh_->get_active()) { + listener->panelChanged(Evlocallabblwh, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabblwh, M("GENERAL_DISABLED")); + } + } +} + +void ControlSpotPanel::recursChanged() +{ + // printf("recursChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.recurs] = recurs_->get_active(); + + // Raise event + if (listener) { + if (recurs_->get_active()) { + listener->panelChanged(Evlocallabrecurs, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabrecurs, M("GENERAL_DISABLED")); + } + } +} + + +void ControlSpotPanel::laplacChanged() +{ + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.laplac] = laplac_->get_active(); + + // Raise event + if (listener) { + if (laplac_->get_active()) { + listener->panelChanged(Evlocallablaplac, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallablaplac, M("GENERAL_DISABLED")); + } + } +} + + +void ControlSpotPanel::deltaeChanged() +{ + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.deltae] = deltae_->get_active(); + + // Raise event + if (listener) { + if (deltae_->get_active()) { + listener->panelChanged(Evlocallabdeltae, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabdeltae, M("GENERAL_DISABLED")); + } + } +} + +void ControlSpotPanel::shortcChanged() +{ + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.shortc] = shortc_->get_active(); + + // Raise event + if (listener) { + if (shortc_->get_active()) { + listener->panelChanged(Evlocallabshortc, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabshortc, M("GENERAL_DISABLED")); + } + } +} + +void ControlSpotPanel::savrestChanged() +{ + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.savrest] = savrest_->get_active(); + + // Raise event + if (listener) { + if (savrest_->get_active()) { + listener->panelChanged(Evlocallabsavrest, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabsavrest, M("GENERAL_DISABLED")); + } + } +} + +void ControlSpotPanel::previewChanged() +{ + // If deltaE preview is activated, deactivate all other tool mask preview + if (controlPanelListener) { + controlPanelListener->resetToolMaskView(); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void ControlSpotPanel::disableParamlistener(bool cond) +{ + // printf("disableParamlistener: %d\n", cond); + + treeviewconn_.block(cond); + buttonaddconn_.block(cond); + buttondeleteconn_.block(cond); + buttonduplicateconn_.block(cond); + buttonrenameconn_.block(cond); + buttonvisibilityconn_.block(cond); + shapeconn_.block(cond); + spotMethodconn_.block(cond); + sensiexclu_->block(cond); + structexclu_->block(cond); + shapeMethodconn_.block(cond); + locX_->block(cond); + locXL_->block(cond); + locY_->block(cond); + locYT_->block(cond); + centerX_->block(cond); + centerY_->block(cond); + circrad_->block(cond); + qualityMethodconn_.block(cond); + transit_->block(cond); + transitweak_->block(cond); + transitgrad_->block(cond); + feather_->block(cond); + struc_->block(cond); + thresh_->block(cond); + iter_->block(cond); + balan_->block(cond); + balanh_->block(cond); + colorde_->block(cond); + colorscope_->block(cond); + avoidConn_.block(cond); + blwhConn_.block(cond); + recursConn_.block(cond); + laplacConn_.block(cond); + deltaeConn_.block(cond); + scopemask_->block(cond); + shortcConn_.block(cond); + lumask_->block(cond); + savrestConn_.block(cond); + complexMethodconn_.block(cond); + wavMethodconn_.block(cond); +} + +void ControlSpotPanel::setParamEditable(bool cond) +{ + // printf("setParamEditable: %d\n", cond); + + shape_->set_sensitive(cond); + spotMethod_->set_sensitive(cond); + sensiexclu_->set_sensitive(cond); + structexclu_->set_sensitive(cond); + shapeMethod_->set_sensitive(cond); + locX_->set_sensitive(cond); + locXL_->set_sensitive(cond); + locY_->set_sensitive(cond); + locYT_->set_sensitive(cond); + centerX_->set_sensitive(cond); + centerY_->set_sensitive(cond); + circrad_->set_sensitive(cond); + qualityMethod_->set_sensitive(cond); + transit_->set_sensitive(cond); + transitweak_->set_sensitive(cond); + transitgrad_->set_sensitive(cond); + feather_->set_sensitive(cond); + struc_->set_sensitive(cond); + thresh_->set_sensitive(cond); + iter_->set_sensitive(cond); + balan_->set_sensitive(cond); + balanh_->set_sensitive(cond); + colorde_->set_sensitive(cond); + colorscope_->set_sensitive(cond); + avoid_->set_sensitive(cond); + blwh_->set_sensitive(cond); + recurs_->set_sensitive(cond); + laplac_->set_sensitive(cond); + deltae_->set_sensitive(cond); + scopemask_->set_sensitive(cond); + shortc_->set_sensitive(cond); + lumask_->set_sensitive(cond); + savrest_->set_sensitive(cond); + complexMethod_->set_sensitive(cond); + wavMethod_->set_sensitive(cond); +} + +void ControlSpotPanel::setDefaultExpanderVisibility() +{ + expTransGrad_->set_expanded(false); + expShapeDetect_->set_expanded(false); + expSpecCases_->set_expanded(false); + expMaskMerge_->set_expanded(false); +} + +void ControlSpotPanel::addControlSpotCurve(Gtk::TreeModel::Row& row) +{ + // printf("addControlSpotCurve\n"); + + if (row[spots_.curveid] > 0) { // Row has already an associated curve + return; + } + + // Creation of visibleGeometry + Circle* cirX; + cirX = new Circle(); + cirX->radius = 4.; + cirX->filled = true; + cirX->datum = Geometry::IMAGE; + Circle* cirXL; + cirXL = new Circle(); + cirXL->radius = 4.; + cirXL->filled = true; + cirXL->datum = Geometry::IMAGE; + Circle* cirY; + cirY = new Circle(); + cirY->radius = 4.; + cirY->filled = true; + cirY->datum = Geometry::IMAGE; + Circle* cirYT; + cirYT = new Circle(); + cirYT->radius = 4.; + cirYT->filled = true; + cirYT->datum = Geometry::IMAGE; + Circle* centerCircle; + centerCircle = new Circle(); + centerCircle->datum = Geometry::IMAGE; + centerCircle->radiusInImageSpace = true; + Ellipse* shape_ellipse; + shape_ellipse = new Ellipse(); + shape_ellipse->datum = Geometry::IMAGE; + shape_ellipse->radiusInImageSpace = true; + Rectangle* shape_rectangle; + shape_rectangle = new Rectangle(); + shape_rectangle->datum = Geometry::IMAGE; + EditSubscriber::visibleGeometry.push_back(centerCircle); // (curveid - 1) * 7 + EditSubscriber::visibleGeometry.push_back(shape_ellipse); // (curveid - 1) * 7 + 1 + EditSubscriber::visibleGeometry.push_back(shape_rectangle); // (curveid - 1) * 7 + 2 + EditSubscriber::visibleGeometry.push_back(cirX); // (curveid - 1) * 7 + 3 + EditSubscriber::visibleGeometry.push_back(cirXL); // (curveid - 1) * 7 + 4 + EditSubscriber::visibleGeometry.push_back(cirY); // (curveid - 1) * 7 + 5 + EditSubscriber::visibleGeometry.push_back(cirYT); // (curveid - 1) * 7 + 6 + + // Creation of mouseOverGeometry + cirX = new Circle(); + cirX->radius = 4.; + cirX->filled = true; + cirX->datum = Geometry::IMAGE; + cirXL = new Circle(); + cirXL->radius = 4.; + cirXL->filled = true; + cirXL->datum = Geometry::IMAGE; + cirY = new Circle(); + cirY->radius = 4.; + cirY->filled = true; + cirY->datum = Geometry::IMAGE; + cirYT = new Circle(); + cirYT->radius = 4.; + cirYT->filled = true; + cirYT->datum = Geometry::IMAGE; + centerCircle = new Circle(); + centerCircle->filled = true; + centerCircle->datum = Geometry::IMAGE; + centerCircle->radiusInImageSpace = true; + shape_ellipse = new Ellipse(); + shape_ellipse->datum = Geometry::IMAGE; + shape_ellipse->radiusInImageSpace = true; + shape_rectangle = new Rectangle(); + shape_rectangle->datum = Geometry::IMAGE; + EditSubscriber::mouseOverGeometry.push_back(centerCircle); // (curveid - 1) * 7 + EditSubscriber::mouseOverGeometry.push_back(shape_ellipse); // (curveid - 1) * 7 + 1 + EditSubscriber::mouseOverGeometry.push_back(shape_rectangle); // (curveid - 1) * 7 + 2 + EditSubscriber::mouseOverGeometry.push_back(cirX); // (curveid - 1) * 7 + 3 + EditSubscriber::mouseOverGeometry.push_back(cirXL); // (curveid - 1) * 7 + 4 + EditSubscriber::mouseOverGeometry.push_back(cirY); // (curveid - 1) * 7 + 5 + EditSubscriber::mouseOverGeometry.push_back(cirYT); // (curveid - 1) * 7 + 6 + + row[spots_.curveid] = EditSubscriber::visibleGeometry.size() / 7; +} + +void ControlSpotPanel::updateControlSpotCurve(const Gtk::TreeModel::Row& row) +{ + const int curveid_ = row[spots_.curveid]; + EditDataProvider* const dataProvider = getEditProvider(); + + // printf("updateControlSpotCurve: %d\n", curveid_); + + if (curveid_ == 0 || !dataProvider) { // Row has no associated curve or there is no EditProvider + return; + } + + int imW = 0; + int imH = 0; + dataProvider->getImageSize(imW, imH); + + if (!imW || !imH) { // No image loaded + return; + } + + const int centerX_ = row[spots_.centerX]; + const int centerY_ = row[spots_.centerY]; + const int circrad_ = row[spots_.circrad]; + const int locX_ = row[spots_.locX]; + const int locXL_ = row[spots_.locXL]; + const int locY_ = row[spots_.locY]; + const int locYT_ = row[spots_.locYT]; + const int shape_ = row[spots_.shape]; + const bool isvisible_ = row[spots_.isvisible]; + + const int decayX = (double)locX_ * (double)imW / 2000.; + const int decayXL = (double)locXL_ * (double)imW / 2000.; + const int decayY = (double)locY_ * (double)imH / 2000.; + const int decayYT = (double)locYT_ * (double)imH / 2000.; + const rtengine::Coord origin((double)imW / 2. + (double)centerX_ * (double)imW / 2000., (double)imH / 2. + (double)centerY_ * (double)imH / 2000.); + + const auto updateSelectionCircle = [&](Geometry * geometry, const int offsetX, const int offsetY) { + const auto cir = static_cast(geometry); + cir->center.x = origin.x + offsetX; + cir->center.y = origin.y + offsetY; + }; + + const auto updateCenterCircle = [&](Geometry * geometry) { + const auto circle = static_cast(geometry); + circle->center = origin; + circle->radius = circrad_; + }; + + const auto updateEllipse = [&](Geometry * geometry) { + const auto ellipse = static_cast(geometry); + ellipse->center = origin; + ellipse->radX = decayX; + ellipse->radXL = decayXL; + ellipse->radY = decayY; + ellipse->radYT = decayYT; + }; + + const auto updateRectangle = [&](Geometry * geometry) { + const auto rectangle = static_cast(geometry); + rectangle->bottomRight.x = origin.x + decayX; + rectangle->bottomRight.y = origin.y + decayY; + rectangle->topLeft.x = origin.x - decayXL; + rectangle->topLeft.y = origin.y - decayYT; + }; + + updateCenterCircle(visibleGeometry.at((curveid_ - 1) * 7)); + updateCenterCircle(mouseOverGeometry.at((curveid_ - 1) * 7)); + + updateEllipse(visibleGeometry.at((curveid_ - 1) * 7 + 1)); + updateEllipse(mouseOverGeometry.at((curveid_ - 1) * 7 + 1)); + + updateRectangle(visibleGeometry.at((curveid_ - 1) * 7 + 2)); + updateRectangle(mouseOverGeometry.at((curveid_ - 1) * 7 + 2)); + + updateSelectionCircle(visibleGeometry.at((curveid_ - 1) * 7 + 3), decayX, 0.); + updateSelectionCircle(mouseOverGeometry.at((curveid_ - 1) * 7 + 3), decayX, 0.); + + updateSelectionCircle(visibleGeometry.at((curveid_ - 1) * 7 + 4), -decayXL, 0.); + updateSelectionCircle(mouseOverGeometry.at((curveid_ - 1) * 7 + 4), -decayXL, 0.); + + updateSelectionCircle(visibleGeometry.at((curveid_ - 1) * 7 + 5), 0., decayY); + updateSelectionCircle(mouseOverGeometry.at((curveid_ - 1) * 7 + 5), 0., decayY); + + updateSelectionCircle(visibleGeometry.at((curveid_ - 1) * 7 + 6), 0., -decayYT); + updateSelectionCircle(mouseOverGeometry.at((curveid_ - 1) * 7 + 6), 0., -decayYT); + + // Update Arcellipse/Rectangle visibility according to shape and visibility + if (isvisible_) { + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7)->setActive(true); // centerCircle + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 3)->setActive(true); // cirX + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 4)->setActive(true); // cirXL + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 5)->setActive(true); // cirY + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 6)->setActive(true); // cirYT + + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7)->setActive(true); // centerCircle + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 3)->setActive(true); // cirX + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 4)->setActive(true); // cirXL + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 5)->setActive(true); // cirY + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 6)->setActive(true); // cirYT + + if (shape_ == 0) { // 0 = Ellipse + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 1)->setActive(true); // shape_ellipse + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 2)->setActive(false); // shape_rectangle + + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 1)->setActive(true); // shape_ellipse + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 2)->setActive(false); // shape_rectangle + } else { // 1 = Rectangle + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 1)->setActive(false); // shape_ellipse + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 2)->setActive(true); // shape_rectangle + + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 1)->setActive(false); // shape_ellipse + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 2)->setActive(true); // shape_rectangle + } + } else { + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7)->setActive(false); // centerCircle + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 1)->setActive(false); // shape_ellipse + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 2)->setActive(false); // shape_rectangle + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 3)->setActive(false); // cirX + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 4)->setActive(false); // cirXL + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 5)->setActive(false); // cirY + EditSubscriber::visibleGeometry.at((curveid_ - 1) * 7 + 6)->setActive(false); // cirYT + + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7)->setActive(false); // centerCircle + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 1)->setActive(false); // shape_ellipse + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 2)->setActive(false); // shape_rectangle + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 3)->setActive(false); // cirX + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 4)->setActive(false); // cirXL + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 5)->setActive(false); // cirY + EditSubscriber::mouseOverGeometry.at((curveid_ - 1) * 7 + 6)->setActive(false); // cirYT + } +} + +void ControlSpotPanel::deleteControlSpotCurve(Gtk::TreeModel::Row& row) +{ + const int curveid_ = row[spots_.curveid]; + + // printf("deleteControlSpotCurve: %d\n", curveid_); + + if (curveid_ == 0) { // Row has no associated curve + return; + } + + // visibleGeometry + for (int i = 6; i >= 0; i--) { + delete *(EditSubscriber::visibleGeometry.begin() + (curveid_ - 1) * 7 + i); + EditSubscriber::visibleGeometry.erase(EditSubscriber::visibleGeometry.begin() + (curveid_ - 1) * 7 + i); + } + + // mouseOverGeometry + for (int i = 6; i >= 0; i--) { + delete *(EditSubscriber::mouseOverGeometry.begin() + (curveid_ - 1) * 7 + i); + EditSubscriber::mouseOverGeometry.erase(EditSubscriber::mouseOverGeometry.begin() + (curveid_ - 1) * 7 + i); + } + + row[spots_.curveid] = 0; // Reset associated curve id + + // Reordering curve id + const Gtk::TreeModel::Children children = treemodel_->children(); + + for (auto iter = children.begin(); iter != children.end(); iter++) { + Gtk::TreeModel::Row r = *iter; + + if (r[spots_.curveid] > curveid_) { + r[spots_.curveid] = r[spots_.curveid] - 1; + } + } +} + +void ControlSpotPanel::updateCurveOpacity(const Gtk::TreeModel::Row& selectedRow) +{ + const int curveid_ = selectedRow[spots_.curveid]; + + // printf("updateCurveOpacity: %d\n", curveid_); + + if (curveid_ == 0) { // Row has no associated curve + return; + } + + for (int it_ = 0; it_ < (int) EditSubscriber::visibleGeometry.size(); it_++) { + if ((it_ < ((curveid_ - 1) * 7)) || (it_ > ((curveid_ - 1) * 7) + 6)) { // it_ does not belong to selected curve + EditSubscriber::visibleGeometry.at(it_)->opacity = 25.; + } else { + EditSubscriber::visibleGeometry.at(it_)->opacity = 75.; + } + } +} + +CursorShape ControlSpotPanel::getCursor(int objectID) const +{ + // printf("Object ID: %d\n", objectID); + + // When there is no control spot (i.e. no selected row), objectID can unexpectedly be different from -1 and produced not desired behavior + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return CSHandOpen; + } + + const int rem_ = objectID % 7; + + switch (rem_) { + case (0): // centerCircle: (curveid_ - 1) * 7 + return CSMove2D; + + case (1): // shape_ellipse: (curveid_ - 1) * 7 + 1 + return CSMove2D; + + case (2): // shape_rectangle: (curveid_ - 1) * 7 + 2 + return CSMove2D; + + case (3): // cirX: (curveid_ - 1) * 7 + 3 + return CSMove1DH; + + case (4): // cirXL: (curveid_ - 1) * 7 + 4 + return CSMove1DH; + + case (5): // cirY: (curveid_ - 1) * 7 + 5 + return CSMove1DV; + + case (6): // cirYT: (curveid_ - 1) * 7 + 6 + return CSMove1DV; + + default: + return CSHandOpen; + } +} + +bool ControlSpotPanel::mouseOver(int modifierKey) +{ + EditDataProvider* editProvider_ = getEditProvider(); + const auto s = treeview_->get_selection(); + + if (!editProvider_ || !s->count_selected_rows()) { // When there is no control spot (i.e. no selected row), objectID can unexpectedly be different from -1 and produced not desired behavior + return false; + } + + // Get selected row + const auto selIter = s->get_selected(); + const Gtk::TreeModel::Row selRow = *selIter; + + const int object_ = editProvider_->object; + + if (object_ != lastObject_) { + if (object_ == -1) { + // Reset mouseOver preview for visibleGeometry + for (size_t it_ = 0; it_ < EditSubscriber::visibleGeometry.size(); it_++) { + EditSubscriber::visibleGeometry.at(it_)->state = Geometry::NORMAL; + } + + // Reset mouseOver preview for TreeView + const Gtk::TreeModel::Children children = treemodel_->children(); + + for (auto iter = children.begin(); iter != children.end(); iter++) { + Gtk::TreeModel::Row row = *iter; + row[spots_.mouseover] = false; + } + + // Actualize lastObject_ + lastObject_ = object_; + return false; + } + + const int curveId_ = object_ / 7 + 1; + const int rem = object_ % 7; + + // Manage mouseOver preview for TreeView + const Gtk::TreeModel::Children children = treemodel_->children(); + + for (auto iter = children.begin(); iter != children.end(); iter++) { + Gtk::TreeModel::Row row = *iter; + + if (row[spots_.curveid] == curveId_ && *row != *selRow) { + row[spots_.mouseover] = true; + } else { + row[spots_.mouseover] = false; + } + } + + for (int it_ = 0; it_ < (int) EditSubscriber::visibleGeometry.size(); it_++) { + if ((it_ < ((curveId_ - 1) * 7)) || (it_ > ((curveId_ - 1) * 7) + 6)) { // it_ does not belong to cursor pointed curve + EditSubscriber::visibleGeometry.at(it_)->state = Geometry::NORMAL; + } + } + + const int method = shapeMethod_->get_active_row_number(); + + // Circle, Arcellipses and Rectangle + if (rem >= 0 && rem < 3) { + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 1)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 2)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 3)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 4)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 5)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 6)->state = Geometry::PRELIGHT; + } else { + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 2)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 3)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 4)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 4)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 5)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 6)->state = Geometry::NORMAL; + } + + // cirX + if (rem == 3) { + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 3)->state = Geometry::PRELIGHT; + + if (method == 1 || method == 3) { // Symmetrical cases + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 4)->state = Geometry::PRELIGHT; + } + } + + // cirXL + if (rem == 4) { + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 4)->state = Geometry::PRELIGHT; + + if (method == 1 || method == 3) { // Symmetrical cases + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 3)->state = Geometry::PRELIGHT; + } + } + + // cirY + if (rem == 5) { + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 5)->state = Geometry::PRELIGHT; + + if (method == 1 || method == 3) { // Symmetrical cases + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 6)->state = Geometry::PRELIGHT; + } + } + + // cirYT + if (rem == 6) { + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 6)->state = Geometry::PRELIGHT; + + if (method == 1 || method == 3) { // Symmetrical cases + EditSubscriber::visibleGeometry.at((curveId_ - 1) * 7 + 5)->state = Geometry::PRELIGHT; + } + } + + lastObject_ = object_; + return true; + } + + return false; +} + +bool ControlSpotPanel::button1Pressed(int modifierKey) +{ + // printf("button1Pressed\n"); + + EditDataProvider *provider = getEditProvider(); + const auto s = treeview_->get_selection(); + + if (!provider || lastObject_ == -1 || !s->count_selected_rows()) { // When there is no control spot (i.e. no selected row), objectID can unexpectedly be different from -1 and produced not desired behavior + return false; + } + + // Select associated control spot + const int curveId_ = lastObject_ / 7 + 1; + Gtk::TreeModel::Children children = treemodel_->children(); + + for (auto iter = children.begin(); iter != children.end(); iter++) { + const Gtk::TreeModel::Row r = *iter; + + if (r[spots_.curveid] == curveId_) { + treeview_->set_cursor(treemodel_->get_path(r)); + break; + } + } + + lastCoord_.set(provider->posImage.x + provider->deltaImage.x, provider->posImage.y + provider->deltaImage.y); + EditSubscriber::action = EditSubscriber::Action::DRAGGING; + return true; +} + +bool ControlSpotPanel::button1Released() +{ + // printf("button1Released\n"); + EditSubscriber::action = EditSubscriber::Action::NONE; + return true; +} + +bool ControlSpotPanel::drag1(int modifierKey) +{ + // printf("drag1\n"); + + EditDataProvider *provider = getEditProvider(); + const auto s = treeview_->get_selection(); + + if (!provider || lastObject_ == -1 || !s->count_selected_rows()) { // When there is no control spot (i.e. no selected row), objectID can unexpectedly be different from -1 and produced not desired behavior + return false; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + int imW, imH; + provider->getImageSize(imW, imH); + const int rem = lastObject_ % 7; + const int method = shapeMethod_->get_active_row_number(); + Coord newCoord = Coord(provider->posImage.x + provider->deltaImage.x, provider->posImage.y + provider->deltaImage.y); + + // Circle, Ellipses and Rectangle + if (rem >= 0 && rem < 3) { + double deltaX = (double (newCoord.x) - double (lastCoord_.x)) * 2000. / double (imW); + double deltaY = (double (newCoord.y) - double (lastCoord_.y)) * 2000. / double (imH); + centerX_->setValue(centerX_->getValue() + deltaX); + centerY_->setValue(centerY_->getValue() + deltaY); + row[spots_.centerX] = centerX_->getIntValue(); + row[spots_.centerY] = centerY_->getIntValue(); + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotCenter, "X=" + centerX_->getTextValue() + ", Y=" + centerY_->getTextValue()); + } + } + + // cirX + if (rem == 3) { + double deltaX = (double (newCoord.x) - double (lastCoord_.x)) * 2000. / double (imW); + locX_->setValue(locX_->getValue() + deltaX); + row[spots_.locX] = locX_->getIntValue(); + + if (method == 1 || method == 3) { // Symmetrical cases + disableParamlistener(true); + locXL_->setValue(locX_->getValue()); + disableParamlistener(false); + row[spots_.locXL] = locXL_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocX, locX_->getTextValue()); + } + } + + // cirXL + if (rem == 4) { + double deltaXL = (double (lastCoord_.x) - double (newCoord.x)) * 2000. / double (imW); + locXL_->setValue(locXL_->getValue() + deltaXL); + row[spots_.locXL] = locXL_->getIntValue(); + + if (method == 1 || method == 3) { // Symmetrical cases + disableParamlistener(true); + locX_->setValue(locXL_->getValue()); + disableParamlistener(false); + row[spots_.locX] = locX_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocXL, locXL_->getTextValue()); + } + } + + // cirY + if (rem == 5) { + double deltaY = (double (newCoord.y) - double (lastCoord_.y)) * 2000. / double (imH); + locY_->setValue(locY_->getValue() + deltaY); + row[spots_.locY] = locY_->getIntValue(); + + if (method == 1 || method == 3) { // Symmetrical cases + disableParamlistener(true); + locYT_->setValue(locY_->getValue()); + disableParamlistener(false); + row[spots_.locYT] = locYT_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocY, locY_->getTextValue()); + } + } + + // cirYT + if (rem == 6) { + double deltaYT = (double (lastCoord_.y) - double (newCoord.y)) * 2000. / double (imH); + locYT_->setValue(locYT_->getValue() + deltaYT); + row[spots_.locYT] = locYT_->getIntValue(); + + if (method == 1 || method == 3) { // Symmetrical cases + disableParamlistener(true); + locY_->setValue(locYT_->getValue()); + disableParamlistener(false); + row[spots_.locY] = locY_->getIntValue(); + } + + updateControlSpotCurve(row); + + if (listener) { + listener->panelChanged(EvLocallabSpotLocYT, locYT_->getTextValue()); + } + } + + lastCoord_.set(newCoord.x, newCoord.y); + return true; +} + +int ControlSpotPanel::getEventType() +{ + const int tmp = eventType; + eventType = None; // Re-initialization at "None" if event type gotten + return tmp; +} + +ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(const int index) +{ + // printf("getSpot: %d\n", index); + + MyMutex::MyLock lock(mTreeview); + + SpotRow* r = new SpotRow(); + + int i = -1; + + for (auto &row : treemodel_->children()) { + i++; + + if (i == index) { + r->name = row[spots_.name]; + r->isvisible = row[spots_.isvisible]; + r->shape = row[spots_.shape]; + r->spotMethod = row[spots_.spotMethod]; +// r->mergeMethod = row[spots_.mergeMethod]; + r->sensiexclu = row[spots_.sensiexclu]; + r->structexclu = row[spots_.structexclu]; + r->struc = row[spots_.struc]; + r->shapeMethod = row[spots_.shapeMethod]; + r->locX = row[spots_.locX]; + r->locXL = row[spots_.locXL]; + r->locY = row[spots_.locY]; + r->locYT = row[spots_.locYT]; + r->centerX = row[spots_.centerX]; + r->centerY = row[spots_.centerY]; + r->circrad = row[spots_.circrad]; + r->qualityMethod = row[spots_.qualityMethod]; + r->complexMethod = row[spots_.complexMethod]; + r->transit = row[spots_.transit]; + r->feather = row[spots_.feather]; + r->thresh = row[spots_.thresh]; + r->iter = row[spots_.iter]; + r->balan = row[spots_.balan]; + r->balanh = row[spots_.balanh]; + r->colorde = row[spots_.colorde]; + r->colorscope = row[spots_.colorscope]; + r->transitweak = row[spots_.transitweak]; + r->transitgrad = row[spots_.transitgrad]; + r->scopemask = row[spots_.scopemask]; + r->lumask = row[spots_.lumask]; + r->avoid = row[spots_.avoid]; + r->blwh = row[spots_.blwh]; + r->recurs = row[spots_.recurs]; + r->laplac = row[spots_.laplac]; + r->deltae = row[spots_.deltae]; + r->shortc = row[spots_.shortc]; + r->savrest = row[spots_.savrest]; + r->wavMethod = row[spots_.wavMethod]; + + return r; + } + } + + return nullptr; +} + +int ControlSpotPanel::getSpotNumber() +{ + // printf("getSpotNumber\n"); + + return (int)treemodel_->children().size(); +} + +int ControlSpotPanel::getSelectedSpot() +{ + // printf("getSelectedSpot\n"); + + MyMutex::MyLock lock(mTreeview); + + const auto s = treeview_->get_selection(); + + // Check if treeview has row, otherwise return 0 + if (!s->count_selected_rows()) { + return -1; + } + + const auto selRow = s->get_selected(); + + // Get selected spot index + int index = -1; + + for (auto i : treemodel_->children()) { + index++; + + if (selRow == i) { + return index; + } + } + + return -1; +} + +bool ControlSpotPanel::setSelectedSpot(const int index) +{ + // printf("setSelectedSpot: %d\n", index); + + MyMutex::MyLock lock(mTreeview); + + int i = -1; + + for (auto &row : treemodel_->children()) { + i++; + + if (i == index) { + disableParamlistener(true); + + treeview_->set_cursor(treemodel_->get_path(row)); + load_ControlSpot_param(); + updateParamVisibility(); + updateCurveOpacity(row); + + disableParamlistener(false); + + return true; + } + } + + return false; +} + +bool ControlSpotPanel::isDeltaEPrevActive() +{ + return (preview_->get_active()); +} + +void ControlSpotPanel::resetDeltaEPreview() +{ + previewConn_.block(true); + preview_->set_active(false); + previewConn_.block(false); +} + +void ControlSpotPanel::addControlSpot(SpotRow* newSpot) +{ + // printf("addControlSpot: %d\n", newSpot->name); + + MyMutex::MyLock lock(mTreeview); + + disableParamlistener(true); + Gtk::TreeModel::Row row = *(treemodel_->append()); + row[spots_.mouseover] = false; + row[spots_.name] = newSpot->name; + row[spots_.isvisible] = newSpot->isvisible; + row[spots_.curveid] = 0; // No associated curve + row[spots_.shape] = newSpot->shape; + row[spots_.spotMethod] = newSpot->spotMethod; + row[spots_.sensiexclu] = newSpot->sensiexclu; + row[spots_.structexclu] = newSpot->structexclu; + row[spots_.shapeMethod] = newSpot->shapeMethod; + row[spots_.locX] = newSpot->locX; + row[spots_.locXL] = newSpot->locXL; + row[spots_.locY] = newSpot->locY; + row[spots_.locYT] = newSpot->locYT; + row[spots_.centerX] = newSpot->centerX; + row[spots_.centerY] = newSpot->centerY; + row[spots_.circrad] = newSpot->circrad; + row[spots_.qualityMethod] = newSpot->qualityMethod; + row[spots_.transit] = newSpot->transit; + row[spots_.transitweak] = newSpot->transitweak; + row[spots_.transitgrad] = newSpot->transitgrad; + row[spots_.feather] = newSpot->feather; + row[spots_.struc] = newSpot->struc; + row[spots_.thresh] = newSpot->thresh; + row[spots_.iter] = newSpot->iter; + row[spots_.balan] = newSpot->balan; + row[spots_.balanh] = newSpot->balanh; + row[spots_.colorde] = newSpot->colorde; + row[spots_.colorscope] = newSpot->colorscope; + row[spots_.avoid] = newSpot->avoid; + row[spots_.blwh] = newSpot->blwh; + row[spots_.recurs] = newSpot->recurs; + row[spots_.laplac] = newSpot->laplac; + row[spots_.deltae] = newSpot->deltae; + row[spots_.scopemask] = newSpot->scopemask; + row[spots_.shortc] = newSpot->shortc; + row[spots_.lumask] = newSpot->lumask; + row[spots_.savrest] = newSpot->savrest; + row[spots_.complexMethod] = newSpot->complexMethod; + row[spots_.wavMethod] = newSpot->wavMethod; + updateParamVisibility(); + disableParamlistener(false); + + // Add associated control spot curve + addControlSpotCurve(row); + updateControlSpotCurve(row); +} + +void ControlSpotPanel::deleteControlSpot(const int index) +{ + // printf("deleteControlSpot: %d\n", index); + + MyMutex::MyLock lock(mTreeview); + + disableParamlistener(true); + + int i = -1; + + for (auto iter : treemodel_->children()) { + i++; + + if (i == index) { + Gtk::TreeModel::Row row = *iter; + deleteControlSpotCurve(row); + treemodel_->erase(*row); + break; + } + } + + disableParamlistener(false); +} + +void ControlSpotPanel::setDefaults(const rtengine::procparams::ProcParams * defParams, const ParamsEdited * pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + sensiexclu_->setDefault((double)defSpot.sensiexclu); + structexclu_->setDefault((double)defSpot.structexclu); + locX_->setDefault((double)defSpot.loc.at(0)); + locXL_->setDefault((double)defSpot.loc.at(1)); + locY_->setDefault((double)defSpot.loc.at(2)); + locYT_->setDefault((double)defSpot.loc.at(3)); + centerX_->setDefault((double)defSpot.centerX); + centerY_->setDefault((double)defSpot.centerY); + circrad_->setDefault((double)defSpot.circrad); + transit_->setDefault(defSpot.transit); + transitweak_->setDefault(defSpot.transitweak); + transitgrad_->setDefault(defSpot.transitgrad); + feather_->setDefault(defSpot.feather); + struc_->setDefault(defSpot.struc); + thresh_->setDefault(defSpot.thresh); + iter_->setDefault(defSpot.iter); + balan_->setDefault(defSpot.balan); + balanh_->setDefault(defSpot.balanh); + colorde_->setDefault(defSpot.colorde); + colorscope_->setDefault(defSpot.colorscope); + scopemask_->setDefault((double)defSpot.scopemask); + lumask_->setDefault((double)defSpot.lumask); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +//----------------------------------------------------------------------------- +// ControlSpots +//----------------------------------------------------------------------------- + +ControlSpotPanel::ControlSpots::ControlSpots() +{ + add(mouseover); + add(name); + add(isvisible); + add(curveid); + add(shape); + add(spotMethod); + add(sensiexclu); + add(structexclu); + add(shapeMethod); + add(locX); + add(locXL); + add(locYT); + add(locY); + add(centerX); + add(centerY); + add(circrad); + add(qualityMethod); + add(transit); + add(transitweak); + add(transitgrad); + add(feather); + add(struc); + add(thresh); + add(iter); + add(balan); + add(balanh); + add(colorde); + add(colorscope); + add(avoid); + add(blwh); + add(recurs); + add(laplac); + add(deltae); + add(scopemask); + add(shortc); + add(lumask); + add(savrest); + add(complexMethod); + add(wavMethod); +} + +//----------------------------------------------------------------------------- +// RenameDialog +//----------------------------------------------------------------------------- + +ControlSpotPanel::RenameDialog::RenameDialog(const Glib::ustring &actualname, Gtk::Window &parent): + Gtk::Dialog(M("TP_LOCALLAB_REN_DIALOG_NAME"), parent), + + newname_(Gtk::manage(new Gtk::Entry())) +{ + // Entry widget + Gtk::HBox* const hb = Gtk::manage(new Gtk::HBox()); + hb->pack_start(*Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_REN_DIALOG_LAB"))), false, false, 4); + newname_->set_text(actualname); + hb->pack_start(*newname_); + get_content_area()->pack_start(*hb, Gtk::PACK_SHRINK, 4); + + // OK/CANCEL buttons + add_button(M("GENERAL_OK"), OkButton); + add_button(M("GENERAL_CANCEL"), CancelButton); + + // Set OK button as default one when pressing enter + newname_->set_activates_default(); + set_default_response(OkButton); + + show_all_children(); +} + +Glib::ustring ControlSpotPanel::RenameDialog::get_new_name() +{ + return newname_->get_text(); +} diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h new file mode 100644 index 000000000..f2bfa1fd0 --- /dev/null +++ b/rtgui/controlspotpanel.h @@ -0,0 +1,430 @@ +/* + * 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 . + * 2018 Pierre Cabrera + */ + +#ifndef _CONTROLSPOTPANEL_H_ +#define _CONTROLSPOTPANEL_H_ + +#include "../rtengine/coord.h" +#include "editcallbacks.h" +#include "threadutils.h" +#include "toolpanel.h" +#include "adjuster.h" + +class ControlPanelListener +{ +public: + ControlPanelListener() {}; + virtual ~ControlPanelListener() {}; + + virtual void resetToolMaskView() = 0; +}; + + +class ControlSpotPanel: + public ToolParamBlock, + public AdjusterListener, + public EditSubscriber, + public FoldableToolPanel +{ +public: + /** + * A SpotRow structure allows exchanges from and to ControlSpotClass + */ + struct SpotRow { + Glib::ustring name; + bool isvisible; + int shape; // 0 = Ellipse, 1 = Rectangle + int spotMethod; // 0 = Normal, 1 = Excluding + int sensiexclu; + int structexclu; + int shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders) + int locX; + int locXL; + int locY; + int locYT; + int centerX; + int centerY; + int circrad; + int qualityMethod; // 0 = Standard, 1 = Enhanced, 2 = Enhanced + chroma denoise + double transit; + double transitweak; + double transitgrad; + double feather; + double struc; + double thresh; + double iter; + double balan; + double balanh; + double colorde; + double colorscope; + bool avoid; + bool blwh; + bool recurs; + bool laplac; + bool deltae; + int scopemask; + bool shortc; + int lumask; + bool savrest; + int complexMethod; // 0 = Simple, 1 = Moderate, 2 = all + int wavMethod; // 0 = D2, 1 = D4, 2 = D6, 3 = D10, 4 = D14 + }; + + /** + * An event type enumeration allows exchanges of spot panel event type from and to ControlSpotClass + */ + enum eventType { + None = 0, + SpotCreation = 1, + SpotDeletion = 2, + SpotSelection = 3, + SpotDuplication = 4, + SpotAllVisibilityChanged = 5 + }; + + // Constructor and management functions + /** + * Default constructor of ControlSpotPanel class + */ + ControlSpotPanel(); + /** + * Destructor of ControlSpotPanel class + */ + ~ControlSpotPanel(); + /** + * Implementation of setEditProvider function of toolpanel.h + * + * @param provider The EditDataProvider to be linked to the panel to manage curves + */ + void setEditProvider(EditDataProvider* provider) override; + /** + * Setter for controlPanelListener + * + * @param cpl The ControlPanelListener to be linked to the panel + */ + void setControlPanelListener(ControlPanelListener* cpl) + { + controlPanelListener = cpl; + } + /** + * Getter of the event type raised by this panel + * + * @return The raised event type (refer to eventType enumeration) + */ + int getEventType(); + /** + * Getter of params of associated spot + * + * @param index The spot index to get params + * @return A SpotRow structure containing params of associated spot + */ + SpotRow* getSpot(const int index); + /** + * Getter of spots number + * + * @return The number of spots in panel + */ + int getSpotNumber(); + /** + * Getter of selected spot index + * + * @return The index of selected spot in treeview (return -1 if no selected spot) + */ + int getSelectedSpot(); + /** + * Setter of selected spot + * + * @param index The index of spot to be selected + * @return True if a spot corresponding to the index has been selected + */ + bool setSelectedSpot(const int index); + /** + * Setter for mask preview active indicator + * + * @param ind True is mask preview is active + */ + void setMaskPrevActive(bool ind) + { + maskPrevActive = ind; + } + /** + * Getter for deltaE preview active + * + * @return True if preview deltaE is active + */ + bool isDeltaEPrevActive(); + /** + * Reset deltaE preview active state + */ + void resetDeltaEPreview(); + + // Control spot creation functions + /** + * Add a new spot (and its associated curve) + * + * @param newSpot A SpotRow structure containing new spot params + */ + void addControlSpot(SpotRow* newSpot); + + // Control spot delete function + /** + * Delete a spot (and its associated curve) + * + * @param id The id of the spot to be deleted + */ + void deleteControlSpot(const int index); + + // Panel widgets management functions + /** + * Implementation of setDefaults function of toolpanel.h + * + * @param defParams ProcParams containing default values to set to the adjusters + * @param pedited ParamsEdited containing default state values to set to the adjusters (not used because batch mode is deactivated for Locallab) + */ + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + /** + * Enable or disable the interactions with panel widgets + * + * @param cond Condition to enable interactions + */ + void setParamEditable(bool cond); + /** + * Reset expander collapse state to default one + */ + void setDefaultExpanderVisibility(); + + // Batch mode management + // Note: Batch mode is deactivated for Locallab + +private: + // Cell renderer + void render_name(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); + void render_isvisible(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); + + void on_button_add(); + void on_button_delete(); + void on_button_duplicate(); + void on_button_rename(); + bool on_button_visibility(GdkEventButton* event); + + bool blockTreeviewSearch(GdkEventKey* event); + bool onSpotSelectionEvent(GdkEventButton* event); + + void load_ControlSpot_param(); + + void controlspotChanged(); + + void shapeChanged(); + void spotMethodChanged(); + void shapeMethodChanged(); + void qualityMethodChanged(); + void complexMethodChanged(); + void wavMethodChanged(); + + void updateParamVisibility(); + + void adjusterChanged(Adjuster* a, double newval) override; + + void avoidChanged(); + void blwhChanged(); + void recursChanged(); + void laplacChanged(); + void deltaeChanged(); + void shortcChanged(); + void savrestChanged(); + + void previewChanged(); + + void disableParamlistener(bool cond); + + void addControlSpotCurve(Gtk::TreeModel::Row& row); + void updateControlSpotCurve(const Gtk::TreeModel::Row& row); + void deleteControlSpotCurve(Gtk::TreeModel::Row& row); + void updateCurveOpacity(const Gtk::TreeModel::Row& selectedRow); + CursorShape getCursor(int objectID) const override; + bool mouseOver(int modifierKey) override; + bool button1Pressed(int modifierKey) override; + bool button1Released() override; + bool drag1(int modifierKey) override; + + using ToolPanel::setDefaults; + + class ControlSpots: + public Gtk::TreeModel::ColumnRecord + { + public: + ControlSpots(); + + Gtk::TreeModelColumn mouseover; // Used to manage spot enlightening when mouse over + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn isvisible; + Gtk::TreeModelColumn curveid; // Associated curve id + Gtk::TreeModelColumn shape; // 0 = Ellipse, 1 = Rectangle + Gtk::TreeModelColumn spotMethod; // 0 = Normal, 1 = Excluding + Gtk::TreeModelColumn sensiexclu; + Gtk::TreeModelColumn structexclu; + Gtk::TreeModelColumn shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders) + Gtk::TreeModelColumn locX; + Gtk::TreeModelColumn locXL; + Gtk::TreeModelColumn locY; + Gtk::TreeModelColumn locYT; + Gtk::TreeModelColumn centerX; + Gtk::TreeModelColumn centerY; + Gtk::TreeModelColumn circrad; + Gtk::TreeModelColumn qualityMethod; // 0 = Standard, 1 = Enhanced, 2 = Enhanced + chroma denoise + Gtk::TreeModelColumn transit; + Gtk::TreeModelColumn transitweak; + Gtk::TreeModelColumn transitgrad; + Gtk::TreeModelColumn feather; + Gtk::TreeModelColumn struc; + Gtk::TreeModelColumn thresh; + Gtk::TreeModelColumn iter; + Gtk::TreeModelColumn balan; + Gtk::TreeModelColumn balanh; + Gtk::TreeModelColumn colorde; + Gtk::TreeModelColumn colorscope; + Gtk::TreeModelColumn avoid; + Gtk::TreeModelColumn blwh; + Gtk::TreeModelColumn recurs; + Gtk::TreeModelColumn laplac; + Gtk::TreeModelColumn deltae; + Gtk::TreeModelColumn scopemask; + Gtk::TreeModelColumn shortc; + Gtk::TreeModelColumn lumask; + Gtk::TreeModelColumn savrest; + Gtk::TreeModelColumn complexMethod; // 0 = Simple, 1 = mod, 2 = all + Gtk::TreeModelColumn wavMethod; // 0 = D2, 1 = D4, 2 = D6, 3 = D10, 4 = D14 + }; + + class RenameDialog: + public Gtk::Dialog + { + public: + enum DialogButton { + OkButton = 1, + CancelButton = 2 + }; + + RenameDialog(const Glib::ustring &actualname, Gtk::Window &parent); + Glib::ustring get_new_name(); + + private: + Gtk::Entry* const newname_; + }; + + ControlSpots spots_; + + // Child widgets + Gtk::ScrolledWindow* const scrolledwindow_; + Gtk::TreeView* const treeview_; + sigc::connection treeviewconn_; + Glib::RefPtr treemodel_; + + Gtk::Button* const button_add_; + sigc::connection buttonaddconn_; + Gtk::Button* const button_delete_; + sigc::connection buttondeleteconn_; + Gtk::Button* const button_duplicate_; + sigc::connection buttonduplicateconn_; + + Gtk::Button* const button_rename_; + sigc::connection buttonrenameconn_; + Gtk::Button* const button_visibility_; + sigc::connection buttonvisibilityconn_; + + MyComboBoxText* const shape_; + sigc::connection shapeconn_; + MyComboBoxText* const spotMethod_; + sigc::connection spotMethodconn_; + MyComboBoxText* const shapeMethod_; + sigc::connection shapeMethodconn_; + MyComboBoxText* const qualityMethod_; + sigc::connection qualityMethodconn_; + MyComboBoxText* const complexMethod_; + sigc::connection complexMethodconn_; + MyComboBoxText* const wavMethod_; + sigc::connection wavMethodconn_; + + Adjuster* const sensiexclu_; + Adjuster* const structexclu_; + Adjuster* const locX_; + Adjuster* const locXL_; + Adjuster* const locY_; + Adjuster* const locYT_; + Adjuster* const centerX_; + Adjuster* const centerY_; + Adjuster* const circrad_; + Adjuster* const transit_; + Adjuster* const transitweak_; + Adjuster* const transitgrad_; + Adjuster* const feather_; + Adjuster* const struc_; + Adjuster* const thresh_; + Adjuster* const iter_; + Adjuster* const balan_; + Adjuster* const balanh_; + Adjuster* const colorde_; + Adjuster* const colorscope_; + Adjuster* const scopemask_; + Adjuster* const lumask_; + + Gtk::CheckButton* const avoid_; + sigc::connection avoidConn_; + Gtk::CheckButton* const blwh_; + sigc::connection blwhConn_; + Gtk::CheckButton* const recurs_; + sigc::connection recursConn_; + Gtk::CheckButton* const laplac_; + sigc::connection laplacConn_; + Gtk::CheckButton* const deltae_; + sigc::connection deltaeConn_; + Gtk::CheckButton* const shortc_; + sigc::connection shortcConn_; + Gtk::CheckButton* const savrest_; + sigc::connection savrestConn_; + + MyExpander* const expTransGrad_; + MyExpander* const expShapeDetect_; + MyExpander* const expSpecCases_; + MyExpander* const expMaskMerge_; + + Gtk::ToggleButton* const preview_; + sigc::connection previewConn_; + + // Internal variables + ControlPanelListener* controlPanelListener; + int lastObject_; + rtengine::Coord lastCoord_; + bool nbSpotChanged_; + bool selSpotChanged_; + bool nameChanged_; + bool visibilityChanged_; + int eventType; // 0 = No event, 1 = Spot creation event, 2 = Spot deletion event, 3 = Spot selection event, 4 = Spot duplication event + Gtk::Frame* const excluFrame; + bool maskPrevActive; + + // Row background color + Gdk::RGBA colorMouseover, colorNominal, colorMouseovertext; + + // Treeview mutex + MyMutex mTreeview; +}; + +#endif // _CONTROLSPOTPANEL_H_ diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 8dc88473e..e38f3a947 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -248,6 +248,7 @@ CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEd { bgHistValid = false; + locallabRef = 0.0; remoteDrag = false; selected = DCT_Linear; bottomBarCP = nullptr; @@ -322,6 +323,18 @@ void CurveEditor::updateBackgroundHistogram(const LUTu& hist) subGroup->updateBackgroundHistogram(this); } +/* + * Update Locallab reference value displayed in the background + */ +void CurveEditor::updateLocallabBackground(double ref) +{ + // Copy Locallab reference value in the curve editor cache + locallabRef = ref; + + // Then call the curve editor group to eventually update the histogram + subGroup->updateLocallabBackground(this); +} + // Open up the curve if it has modifications and it's not already opened // Returns: true if curve was non linear and opened bool CurveEditor::openIfNonlinear() diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index abc0cc10a..d5ec49559 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -59,7 +59,7 @@ protected: PopUpToggleButton* curveType; LUTu histogram; // histogram values bool bgHistValid; - + double locallabRef; // Locallab reference value bool remoteDrag; int selected; @@ -95,7 +95,7 @@ public: bool isUnChanged (); void setUnChanged (bool uc); void updateBackgroundHistogram(const LUTu& hist); - + void updateLocallabBackground(double ref); void setLeftBarColorProvider(ColorProvider* cp, int callerId); void setBottomBarColorProvider(ColorProvider* cp, int callerId); void setCurveColorProvider(ColorProvider* cp, int callerId); diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index cad49d331..5c120f7e4 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -274,6 +274,7 @@ void CurveEditorGroup::curveTypeToggled(CurveEditor* ce) if (ct < ce->subGroup->valUnchanged) { ce->subGroup->restoreDisplayedHistogram(); + ce->subGroup->restoreLocallabBackground(); } } else { // The button is now released, so we have to hide this CurveEditor diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h index 5ef13656b..0f7c01a32 100644 --- a/rtgui/curveeditorgroup.h +++ b/rtgui/curveeditorgroup.h @@ -137,6 +137,7 @@ public: } void updateEditButton(CurveEditor* curve, Gtk::ToggleButton *button, sigc::connection &connection); virtual void updateBackgroundHistogram (CurveEditor* ce) {} + virtual void updateLocallabBackground(CurveEditor* ce) {}; virtual void switchGUI() = 0; virtual void refresh(CurveEditor *curveToRefresh) = 0; virtual void editModeSwitchedOff() = 0; @@ -166,6 +167,7 @@ protected: virtual void storeCurveValues (CurveEditor* ce, const std::vector& p) = 0; virtual void storeDisplayedCurve () = 0; virtual void restoreDisplayedHistogram() {}; + virtual void restoreLocallabBackground() {}; virtual void removeEditor () = 0; virtual const std::vector getCurveFromGUI (int type) = 0; diff --git a/rtgui/editcallbacks.cc b/rtgui/editcallbacks.cc index 1538ef7ba..5404b0bc9 100644 --- a/rtgui/editcallbacks.cc +++ b/rtgui/editcallbacks.cc @@ -99,10 +99,11 @@ bool EditSubscriber::isPicking() const EditDataProvider::EditDataProvider() : currSubscriber(nullptr), - object(0), +// object(0), pipetteVal1(0.f), pipetteVal2(0.f), pipetteVal3(0.f), + object(0), posScreen(-1, -1), posImage(-1, -1), deltaScreen(0, 0), diff --git a/rtgui/editcallbacks.h b/rtgui/editcallbacks.h index c2efcf53e..d81e84806 100644 --- a/rtgui/editcallbacks.h +++ b/rtgui/editcallbacks.h @@ -160,12 +160,13 @@ class EditDataProvider private: EditSubscriber *currSubscriber; - int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise +// int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise float pipetteVal1; /// Current pipette values float pipetteVal2; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, will be set to 0 float pipetteVal3; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, will be set to 0 public: + int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise rtengine::Coord posScreen; /// Location of the mouse button press, in preview image space rtengine::Coord posImage; /// Location of the mouse button press, in the full image space @@ -192,4 +193,6 @@ public: int getPipetteRectSize () const; EditSubscriber* getCurrSubscriber() const; virtual void getImageSize (int &w, int&h) = 0; + virtual void getPreviewCenterPos(int &x, int &y) = 0; + virtual void getPreviewSize(int &w, int &h) = 0; }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 1a82c4a94..669dd491a 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -957,6 +957,13 @@ void EditorPanel::writeToolExpandedStatus (std::vector &tpOpen) } } +void EditorPanel::updateShowtooltipVisibility (bool showtooltip) +{ + if (tpc) { + tpc->updateShowtooltipVisibility (showtooltip); + } +} + void EditorPanel::showTopPanel (bool show) { if (tbTopPanel_1->get_active() != show) { @@ -1674,6 +1681,11 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) case GDK_KEY_F5: openThm->openDefaultViewer (3); return true; + + case GDK_KEY_f: + case GDK_KEY_F: + // No action is performed to avoid Gtk-CRITICAL due to Locallab treeview when treeview isn't focused + return true; } } //if (!ctrl) } //if (!alt) @@ -1735,6 +1747,7 @@ void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) PartialProfile pp (true); pp.set (true); * (pp.pparams) = openThm->getProcParams(); + pp.pedited->locallab.spots.resize(pp.pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); tpc->profileChange (&pp, rtengine::EvProfileChangeNotification, M ("PROGRESSDLG_PROFILECHANGEDINBROWSER")); pp.deleteInstance(); } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 8993fea07..826793507 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -79,6 +79,7 @@ public: void writeOptions(); void writeToolExpandedStatus (std::vector &tpOpen); + void updateShowtooltipVisibility (bool showtooltip); void showTopPanel (bool show); bool isRealized() diff --git a/rtgui/editwidgets.cc b/rtgui/editwidgets.cc index e67b664db..fccdb874a 100644 --- a/rtgui/editwidgets.cc +++ b/rtgui/editwidgets.cc @@ -76,7 +76,7 @@ void Circle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); cr->set_line_width( getOuterLineWidth() ); rtengine::Coord center_ = center; @@ -107,7 +107,7 @@ void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer color = innerLineColor; } - cr->set_source_rgb(color.getR(), color.getG(), color.getB()); + cr->set_source_rgba(color.getR(), color.getG(), color.getB(), opacity / 100.); } cr->set_line_width( innerLineWidth ); @@ -199,7 +199,7 @@ void Line::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer * color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.0); cr->set_line_width( getOuterLineWidth() ); rtengine::Coord begin_ = begin; @@ -234,7 +234,7 @@ void Line::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer * color = innerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); } cr->set_line_width(innerLineWidth); @@ -313,7 +313,7 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuff color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); cr->set_line_width( getOuterLineWidth() ); rtengine::Coord currPos; @@ -357,7 +357,7 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuff color = innerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); } cr->set_line_width( innerLineWidth ); @@ -506,7 +506,7 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuf color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); cr->set_line_width( getOuterLineWidth() ); rtengine::Coord tl, br; @@ -550,7 +550,7 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuf color = innerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); } cr->set_line_width( innerLineWidth ); @@ -646,6 +646,292 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned shor } } +void Ellipse::drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getOuterLineColor(); + } else { + color = outerLineColor; + } + + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); + cr->set_line_width ( getOuterLineWidth() ); + + rtengine::Coord center_ = center; + double radYT_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radYT)) : double (radYT); + double radY_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radY)) : double (radY); + double radXL_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radXL)) : double (radXL); + double radX_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radX)) : double (radX); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y); + } else if (datum == CLICKED_POINT) { + center_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (radYT_ > 0 && radY_ > 0 && radXL_ > 0 && radX_ > 0) { + // To have an ellipse with radius of (radX, radX), a circle of radius 1. shall be twisted with a scale + // of radX for x-axis, radY for y-axis + // Center of coordinates (x, y) in previous coordinates system becomes (X, Y) = (radX * x, radY * y) in new one + // To go back to previous location, center shall be translated to tx = -X * (1 - 1 / radX) in x-axis (x = tx + X) + // and ty = -Y * (1 - 1 / radY) in y-axis (y = ty + Y) + cr->save(); + + // Drawing bottom-right part + cr->scale (radX_, radY_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, 0.0, rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing bottom-left part + cr->scale (radXL_, radY_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI_2, rtengine::RT_PI); + cr->scale (radXL_, radY_); + + cr->restore (); + cr->save(); + + // Drawing top-left part + cr->scale (radXL_, radYT_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI, 3. * rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing top-right part + cr->scale (radX_, radYT_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, 3. * rtengine::RT_PI_2, 2. * rtengine::RT_PI); + + cr->restore (); + cr->stroke (); + } + } +} + +void Ellipse::drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_VISIBLE) { + if (state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getInnerLineColor(); + } else { + color = innerLineColor; + } + + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), opacity / 100.); + } + + cr->set_line_width ( innerLineWidth ); + + rtengine::Coord center_ = center; + double radYT_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radYT)) : double (radYT); + double radY_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radY)) : double (radY); + double radXL_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radXL)) : double (radXL); + double radX_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radX)) : double (radX); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y); + } else if (datum == CLICKED_POINT) { + center_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (filled && state != INSENSITIVE) { + if (radYT_ > 0 && radY_ > 0 && radXL_ > 0 && radX_ > 0) { + // To have an ellipse with radius of (radX, radX), a circle of radius 1. shall be twisted with a scale + // of radX for x-axis, radY for y-axis + // Center of coordinates (x, y) in previous coordinates system becomes (X, Y) = (radX * x, radY * y) in new one + // To go back to previous location, center shall be translated to tx = -X * (1 - 1 / radX) in x-axis (x = tx + X) + // and ty = -Y * (1 - 1 / radY) in y-axis (y = ty + Y) + cr->save(); + + // Drawing bottom-right part + cr->scale (radX_, radY_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, 0.0, rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing bottom-left part + cr->scale (radXL_, radY_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI_2, rtengine::RT_PI); + cr->scale (radXL_, radY_); + + cr->restore (); + cr->save(); + + // Drawing top-left part + cr->scale (radXL_, radYT_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI, 3. * rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing top-right part + cr->scale (radX_, radYT_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, 3. * rtengine::RT_PI_2, 2. * rtengine::RT_PI); + + cr->restore (); + cr->stroke (); + } + + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else if (innerLineWidth > 0.) { + if (radYT_ > 0 && radY_ > 0 && radXL_ > 0 && radX_ > 0) { + // To have an ellipse with radius of (radX, radX), a circle of radius 1. shall be twisted with a scale + // of radX for x-axis, radY for y-axis + // Center of coordinates (x, y) in previous coordinates system becomes (X, Y) = (radX * x, radY * y) in new one + // To go back to previous location, center shall be translated to tx = -X * (1 - 1 / radX) in x-axis (x = tx + X) + // and ty = -Y * (1 - 1 / radY) in y-axis (y = ty + Y) + cr->save(); + + // Drawing bottom-right part + cr->scale (radX_, radY_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, 0.0, rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing bottom-left part + cr->scale (radXL_, radY_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI_2, rtengine::RT_PI); + cr->scale (radXL_, radY_); + + cr->restore (); + cr->save(); + + // Drawing top-left part + cr->scale (radXL_, radYT_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI, 3. * rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing top-right part + cr->scale (radX_, radYT_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, 3. * rtengine::RT_PI_2, 2. * rtengine::RT_PI); + + cr->restore (); + cr->stroke (); + } + + if (state == INSENSITIVE) { + std::valarray ds (1); + ds[0] = 4; + cr->set_source_rgba (1.0, 1.0, 1.0, 0.618); + cr->stroke_preserve(); + cr->set_source_rgba (0.0, 0.0, 0.0, 0.618); + cr->set_dash (ds, 0); + cr->stroke(); + ds.resize (0); + cr->set_dash (ds, 0); + } else { + cr->stroke(); + } + } + } +} + +void Ellipse::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_HOVERABLE) { + cr->set_line_width ( getMouseOverLineWidth() ); + + rtengine::Coord center_ = center; + double radYT_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radYT)) : double (radYT); + double radY_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radY)) : double (radY); + double radXL_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radXL)) : double (radXL); + double radX_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas (double (radX)) : double (radX); + + if (datum == IMAGE) { + coordSystem.imageCoordToCropCanvas (center.x, center.y, center_.x, center_.y); + } else if (datum == CLICKED_POINT) { + center_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (radYT_ > 0 && radY_ > 0 && radXL_ > 0 && radX_ > 0) { + // To have an ellipse with radius of (radX, radX), a circle of radius 1. shall be twisted with a scale + // of radX for x-axis, radY for y-axis + // Center of coordinates (x, y) in previous coordinates system becomes (X, Y) = (radX * x, radY * y) in new one + // To go back to previous location, center shall be translated to tx = -X * (1 - 1 / radX) in x-axis (x = tx + X) + // and ty = -Y * (1 - 1 / radY) in y-axis (y = ty + Y) + cr->save(); + + // Drawing bottom-right part + cr->scale (radX_, radY_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, 0.0, rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing bottom-left part + cr->scale (radXL_, radY_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radY_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI_2, rtengine::RT_PI); + cr->scale (radXL_, radY_); + + cr->restore (); + cr->save(); + + // Drawing top-left part + cr->scale (radXL_, radYT_); + cr->translate(- center_.x * (1 - 1 / radXL_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, rtengine::RT_PI, 3. * rtengine::RT_PI_2); + + cr->restore (); + cr->save(); + + // Drawing top-right part + cr->scale (radX_, radYT_); + cr->translate(- center_.x * (1 - 1 / radX_), - center_.y * (1 - 1 / radYT_)); + cr->arc (center_.x, center_.y, 1.0, 3. * rtengine::RT_PI_2, 2. * rtengine::RT_PI); + + cr->restore (); + cr->stroke (); + } + + if (filled) { + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else { + cr->stroke(); + } + } +} + void OPIcon::drivenPointToRectangle(const rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H) { diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index 0fa7a91bf..c86949cb4 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -234,6 +234,7 @@ public: float innerLineWidth; // ...outerLineWidth = innerLineWidth+2 Datum datum; State state; // set by the Subscriber + float opacity; // Percentage of opacity Geometry (); virtual ~Geometry() {} @@ -324,6 +325,25 @@ public: void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; }; +class Ellipse : public Geometry +{ +public: + rtengine::Coord center; + int radYT; // Ellipse half-radius for top y-axis + int radY; // Ellipse half-radius for bottom y-axis + int radXL; // Ellipse half-radius for left x-axis + int radX; // Ellipse half-radius for right x-axis + bool filled; + bool radiusInImageSpace; /// If true, the radius depend on the image scale; if false, it is a fixed 'screen' size + + Ellipse (); + Ellipse (const rtengine::Coord& center, int radYT, int radY, int radXL, int radX, bool filled = false, bool radiusInImageSpace = false); + + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; +}; + class OPIcon : public Geometry // OP stands for "On Preview" { @@ -476,7 +496,7 @@ inline Geometry::Geometry () : innerLineColor (char (255), char (255), char (255)), outerLineColor ( char (0), char (0), char (0)), flags ( F_VISIBLE | F_HOVERABLE | F_AUTO_COLOR), innerLineWidth (1.5f), datum ( - IMAGE), state (NORMAL) { + IMAGE), state (NORMAL), opacity(100.) { } inline RGBAColor::RGBAColor () : @@ -520,6 +540,10 @@ inline Line::Line () : begin (10, 10), end (100, 100) { } +inline Ellipse::Ellipse () : + center (100, 100), radYT (5), radY (5), radXL (10), radX (10), filled (false), radiusInImageSpace (false) { +} + inline Circle::Circle (rtengine::Coord& center, int radius, bool filled, bool radiusInImageSpace) : center (center), radius (radius), filled (filled), radiusInImageSpace ( @@ -540,5 +564,10 @@ inline Line::Line (int beginX, int beginY, int endX, int endY) : begin (beginX, beginY), end (endX, endY) { } -#endif +inline Ellipse::Ellipse (const rtengine::Coord& center, int radYT, int radY, int radXL, int radX, + bool filled, bool radiusInImageSpace) : + center (center), radYT (radYT), radY (radY), radXL (radXL), radX (radX), filled (filled), + radiusInImageSpace (radiusInImageSpace) { +} +#endif diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index caa60ebbc..42aafd2e0 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -29,6 +29,7 @@ #include "clipboard.h" #include "multilangmgr.h" #include "options.h" +#include "paramsedited.h" #include "profilestorecombobox.h" #include "procparamchangers.h" #include "rtimage.h" @@ -1066,6 +1067,8 @@ void FileBrowser::partPasteProfile () auto toplevel = static_cast (get_toplevel ()); PartialPasteDlg partialPasteDlg (M("PARTIALPASTE_DIALOGLABEL"), toplevel); + partialPasteDlg.updateSpotWidget(clipboard.getPartialProfile().pparams); + int i = partialPasteDlg.run (); if (i == Gtk::RESPONSE_OK) { @@ -1392,6 +1395,8 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label) auto toplevel = static_cast (get_toplevel ()); PartialPasteDlg partialPasteDlg (M("PARTIALPASTE_DIALOGLABEL"), toplevel); + partialPasteDlg.updateSpotWidget(srcProfiles->pparams); + if (partialPasteDlg.run() == Gtk::RESPONSE_OK) { MYREADERLOCK(l, entryRW); @@ -1406,6 +1411,7 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label) rtengine::procparams::PartialProfile dstProfile(true); *dstProfile.pparams = (static_cast(selected[i]))->thumbnail->getProcParams (); dstProfile.set(true); + dstProfile.pedited->locallab.spots.resize(dstProfile.pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); partialPasteDlg.applyPaste (dstProfile.pparams, dstProfile.pedited, srcProfiles->pparams, srcProfiles->pedited); (static_cast(selected[i]))->thumbnail->setProcParams (*dstProfile.pparams, dstProfile.pedited, FILEBROWSER); dstProfile.deleteInstance(); diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 102c17daf..42a2263e2 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2446,6 +2446,8 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) case GDK_KEY_underscore: zoomOut(); return true; + default: // do nothing, avoids a cppcheck false positive + break; } } diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index 4e0591ac3..1cc3f5c14 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -556,6 +556,13 @@ void FlatCurveEditorSubGroup::restoreDisplayedHistogram() } +void FlatCurveEditorSubGroup::restoreLocallabBackground() +{ + if (parent->displayedCurve) { + CPointsCurve->updateLocallabBackground(parent->displayedCurve->locallabRef); + } +} + void FlatCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { if (!p.empty()) { @@ -629,6 +636,13 @@ bool FlatCurveEditorSubGroup::curveReset(CurveEditor *ce) return true; } +void FlatCurveEditorSubGroup::updateLocallabBackground(CurveEditor* ce) +{ + if (ce == parent->displayedCurve) { + CPointsCurve->updateLocallabBackground(ce->locallabRef); + } +} + /*void FlatCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) { CurveEditor* fce = (CurveEditor*)ce; if (fce==displayedCurve) { diff --git a/rtgui/flatcurveeditorsubgroup.h b/rtgui/flatcurveeditorsubgroup.h index 865a0ef83..79dd5e7d0 100644 --- a/rtgui/flatcurveeditorsubgroup.h +++ b/rtgui/flatcurveeditorsubgroup.h @@ -55,6 +55,7 @@ public: FlatCurveEditor* addCurve(Glib::ustring curveLabel = "", bool periodic = true); //virtual void updateBackgroundHistogram (CurveEditor* ce); + void updateLocallabBackground(CurveEditor* ce) override; void switchGUI() override; void refresh(CurveEditor *curveToRefresh) override; void editModeSwitchedOff() override; @@ -71,6 +72,7 @@ protected: void storeCurveValues (CurveEditor* ce, const std::vector& p) override; void storeDisplayedCurve () override; void restoreDisplayedHistogram () override; + void restoreLocallabBackground() override; void savePressed (); void loadPressed (); void copyPressed (); diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index b46f8e1ca..8229e883a 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -151,6 +151,8 @@ void Gradient::updateGeometry(const int centerX, const int centerY, const double int imW=0; int imH=0; + + if (fullWidth != -1 && fullHeight != -1) { imW = fullWidth; imH = fullHeight; diff --git a/rtgui/history.cc b/rtgui/history.cc index 5305c258b..1a9cc1258 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -29,16 +29,22 @@ using namespace rtengine; using namespace rtengine::procparams; -History::History (bool bookmarkSupport) : historyVPaned(nullptr), blistener(nullptr), tpc (nullptr), bmnum (1) +History::History (bool bookmarkSupport) : historyVPaned (nullptr), blistener (nullptr), tpc (nullptr), bmnum (1) { blistenerLock = false; // sets default that the Before preview will not be locked + /* + // fill history event message array + for (int i = 0; i < NUMOFEVENTS; i++) { + eventDescrArray[i] = M (Glib::ustring::compose ("HISTORY_MSG_%1", i + 1)); + } + */ // History List // ~~~~~~~~~~~~ Gtk::ScrolledWindow* hscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); hscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - Gtk::Frame* histFrame = Gtk::manage (new Gtk::Frame (M("HISTORY_LABEL"))); + Gtk::Frame* histFrame = Gtk::manage (new Gtk::Frame (M ("HISTORY_LABEL"))); histFrame->set_name ("HistoryPanel"); histFrame->add (*hscrollw); @@ -48,9 +54,9 @@ History::History (bool bookmarkSupport) : historyVPaned(nullptr), blistener(null historyModel = Gtk::ListStore::create (historyColumns); hTreeView->set_model (historyModel); hTreeView->set_headers_visible (false); - hTreeView->set_hscroll_policy(Gtk::SCROLL_MINIMUM); - hTreeView->set_vscroll_policy(Gtk::SCROLL_NATURAL); - hTreeView->set_size_request(80, -1); + hTreeView->set_hscroll_policy (Gtk::SCROLL_MINIMUM); + hTreeView->set_vscroll_policy (Gtk::SCROLL_NATURAL); + hTreeView->set_size_request (80, -1); Gtk::CellRendererText *changecrt = Gtk::manage (new Gtk::CellRendererText()); changecrt->property_ellipsize() = Pango::ELLIPSIZE_END; @@ -59,46 +65,46 @@ History::History (bool bookmarkSupport) : historyVPaned(nullptr), blistener(null Gtk::TreeView::Column *hviewcol = Gtk::manage (new Gtk::TreeView::Column ("")); hviewcol->pack_start (*changecrt, true); hviewcol->add_attribute (changecrt->property_markup (), historyColumns.text); - hviewcol->set_expand(true); + hviewcol->set_expand (true); hviewcol->set_resizable (true); - hviewcol->set_fixed_width(35); - hviewcol->set_min_width(35); - hviewcol->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + hviewcol->set_fixed_width (35); + hviewcol->set_min_width (35); + hviewcol->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); Gtk::TreeView::Column *hviewcol2 = Gtk::manage (new Gtk::TreeView::Column ("")); hviewcol2->pack_start (*valuecrt, true); hviewcol2->add_attribute (valuecrt->property_markup (), historyColumns.value); - hviewcol2->set_expand(true); - hviewcol2->set_resizable(true); - hviewcol2->set_fixed_width(35); - hviewcol2->set_min_width(35); - hviewcol2->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); - valuecrt->set_alignment(1.f, 0.f); + hviewcol2->set_expand (true); + hviewcol2->set_resizable (true); + hviewcol2->set_fixed_width (35); + hviewcol2->set_min_width (35); + hviewcol2->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + valuecrt->set_alignment (1.f, 0.f); - hTreeView->set_has_tooltip(true); - hTreeView->signal_query_tooltip().connect( sigc::mem_fun(*this, &History::on_query_tooltip) ); + hTreeView->set_has_tooltip (true); + hTreeView->signal_query_tooltip().connect ( sigc::mem_fun (*this, &History::on_query_tooltip) ); hTreeView->append_column (*hviewcol); hTreeView->append_column (*hviewcol2); - selchangehist = hTreeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &History::historySelectionChanged)); + selchangehist = hTreeView->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &History::historySelectionChanged)); // Bookmark List // ~~~~~~~~~~~~~ Gtk::HBox* ahbox = Gtk::manage (new Gtk::HBox ()); addBookmark = Gtk::manage (new Gtk::Button ()); // M("HISTORY_NEWSNAPSHOT") - setExpandAlignProperties(addBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties (addBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); //addBookmark->get_style_context()->set_junction_sides(Gtk::JUNCTION_RIGHT); - addBookmark->get_style_context()->add_class("Left"); - addBookmark->set_tooltip_markup (M("HISTORY_NEWSNAPSHOT_TOOLTIP")); + addBookmark->get_style_context()->add_class ("Left"); + addBookmark->set_tooltip_markup (M ("HISTORY_NEWSNAPSHOT_TOOLTIP")); Gtk::Image* addimg = Gtk::manage (new RTImage ("add-small.png")); addBookmark->set_image (*addimg); ahbox->pack_start (*addBookmark); delBookmark = Gtk::manage (new Gtk::Button ()); // M("HISTORY_DELSNAPSHOT") - setExpandAlignProperties(delBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties (delBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); //delBookmark->get_style_context()->set_junction_sides(Gtk::JUNCTION_LEFT); - delBookmark->get_style_context()->add_class("Right"); + delBookmark->get_style_context()->add_class ("Right"); Gtk::Image* delimg = Gtk::manage (new RTImage ("remove-small.png")); delBookmark->set_image (*delimg); ahbox->pack_start (*delBookmark); @@ -108,19 +114,19 @@ History::History (bool bookmarkSupport) : historyVPaned(nullptr), blistener(null bscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); bscrollw->set_size_request (-1, 45); - Gtk::Frame* bmFrame = Gtk::manage (new Gtk::Frame (M("HISTORY_SNAPSHOTS"))); - bmFrame->set_name("Snapshots"); + Gtk::Frame* bmFrame = Gtk::manage (new Gtk::Frame (M ("HISTORY_SNAPSHOTS"))); + bmFrame->set_name ("Snapshots"); Gtk::VBox* bmBox = Gtk::manage (new Gtk::VBox ()); bmFrame->add (*bmBox); bmBox->pack_start (*bscrollw, Gtk::PACK_EXPAND_WIDGET, 4); bmBox->pack_end (*ahbox, Gtk::PACK_SHRINK, 4); - bmBox->set_size_request(-1,60); + bmBox->set_size_request (-1, 60); if (bookmarkSupport) { historyVPaned = Gtk::manage ( new Gtk::VPaned () ); historyVPaned->pack1 (*histFrame, true, true); historyVPaned->pack2 (*bmFrame, false, false); - pack_start(*historyVPaned); + pack_start (*historyVPaned); } else { pack_start (*histFrame); } @@ -132,19 +138,19 @@ History::History (bool bookmarkSupport) : historyVPaned(nullptr), blistener(null bookmarkModel = Gtk::ListStore::create (bookmarkColumns); bTreeView->set_model (bookmarkModel); bTreeView->set_headers_visible (false); - bTreeView->append_column_editable (M("HISTORY_SNAPSHOTS"), bookmarkColumns.text); + bTreeView->append_column_editable (M ("HISTORY_SNAPSHOTS"), bookmarkColumns.text); - selchangebm = bTreeView->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &History::bookmarkSelectionChanged)); + selchangebm = bTreeView->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &History::bookmarkSelectionChanged)); - addBookmark->signal_clicked().connect( sigc::mem_fun(*this, &History::addBookmarkPressed) ); - delBookmark->signal_clicked().connect( sigc::mem_fun(*this, &History::delBookmarkPressed) ); + addBookmark->signal_clicked().connect ( sigc::mem_fun (*this, &History::addBookmarkPressed) ); + delBookmark->signal_clicked().connect ( sigc::mem_fun (*this, &History::delBookmarkPressed) ); //hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_HORIZONTAL); hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_BOTH); //hTreeView->signal_size_allocate().connect( sigc::mem_fun(*this, &History::resized) ); - hTreeView->set_enable_search(false); - bTreeView->set_enable_search(false); + hTreeView->set_enable_search (false); + bTreeView->set_enable_search (false); show_all_children (); } @@ -152,7 +158,7 @@ History::History (bool bookmarkSupport) : historyVPaned(nullptr), blistener(null void History::initHistory () { - ConnectionBlocker selBlocker(selchangehist); + ConnectionBlocker selBlocker (selchangehist); historyModel->clear (); bookmarkModel->clear (); } @@ -172,9 +178,11 @@ void History::historySelectionChanged () if (row && tpc) { ProcParams pparams = row[historyColumns.params]; - ParamsEdited pe(true); - PartialProfile pp(&pparams, &pe); + ParamsEdited pe (true); + pe.locallab.spots.resize(pparams.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; + tpc->profileChange (&pp, EvHistoryBrowsed, row[historyColumns.text], ¶msEdited); } @@ -205,8 +213,9 @@ void History::bookmarkSelectionChanged () if (row && tpc) { ProcParams pparams = row[bookmarkColumns.params]; - ParamsEdited pe(true); - PartialProfile pp(&pparams, &pe); + ParamsEdited pe (true); + pe.locallab.spots.resize(pparams.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[bookmarkColumns.paramsEdited]; tpc->profileChange (&pp, EvBookmarkSelected, row[bookmarkColumns.text], ¶msEdited); } @@ -221,7 +230,7 @@ void History::procParamsChanged( ) { // to prevent recursion, we filter out the events triggered by the history and events that should not be registered - if (ev == EvHistoryBrowsed || ev == EvMonitorTransform) { + if (ev == EvHistoryBrowsed || ev == EvMonitorTransform || descr == "") { return; } @@ -255,10 +264,11 @@ void History::procParamsChanged( } // if there is no last item or its chev!=ev, create a new one - if (size == 0 || !row || row[historyColumns.chev] != ev || ev == EvProfileChanged) { - Gtk::TreeModel::Row newrow = *(historyModel->append()); + if (size == 0 || !row || row[historyColumns.chev] != ev || ev == EvProfileChanged + || ev == EvLocallabSpotCreated || ev == EvLocallabSpotDeleted) { // Special cases: If Locallab spot is created , deleted or duplicated several times in a row, a new history row is used + Gtk::TreeModel::Row newrow = * (historyModel->append()); newrow[historyColumns.text] = ProcEventMapper::getInstance()->getHistoryMsg(ev); - newrow[historyColumns.value] = g_markup_escape_text(descr.c_str(), -1); + newrow[historyColumns.value] = g_markup_escape_text (descr.c_str(), -1); newrow[historyColumns.chev] = ev; newrow[historyColumns.params] = *params; newrow[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; @@ -314,7 +324,7 @@ void History::addBookmarkWithText (Glib::ustring text) } // append new row to bookmarks - Gtk::TreeModel::Row newrow = *(bookmarkModel->append()); + Gtk::TreeModel::Row newrow = * (bookmarkModel->append()); newrow[bookmarkColumns.text] = text; ProcParams params = row[historyColumns.params]; newrow[bookmarkColumns.params] = params; @@ -326,7 +336,7 @@ void History::addBookmarkPressed () { if (hTreeView->get_selection()->get_selected()) { - addBookmarkWithText (Glib::ustring::compose ("%1 %2", M("HISTORY_SNAPSHOT"), bmnum++)); + addBookmarkWithText (Glib::ustring::compose ("%1 %2", M ("HISTORY_SNAPSHOT"), bmnum++)); } } @@ -361,7 +371,7 @@ void History::undo () int size = historyModel->children().size (); if (size > 1) { - selection->select (historyModel->children().operator [](size - 2)); + selection->select (historyModel->children().operator [] (size - 2)); } } } @@ -382,7 +392,7 @@ void History::redo () int size = historyModel->children().size (); if (size > 1) { - selection->select (historyModel->children().operator [](size - 2)); + selection->select (historyModel->children().operator [] (size - 2)); } } } @@ -408,22 +418,27 @@ bool History::getBeforeLineParams (rtengine::procparams::ProcParams& params) return true; } -bool History::on_query_tooltip(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { +bool History::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) +{ bool displayTooltip = false; Gtk::TreeModel::Path path; int x2 = -1; int y2 = -1; - hTreeView->convert_widget_to_bin_window_coords(x, y, x2, y2); - bool hasPath = hTreeView->get_path_at_pos(x2, y2, path); + hTreeView->convert_widget_to_bin_window_coords (x, y, x2, y2); + bool hasPath = hTreeView->get_path_at_pos (x2, y2, path); if (hasPath) { if (path && !path.empty()) { - Gtk::TreeModel::iterator iter = historyModel->get_iter(path); + Gtk::TreeModel::iterator iter = historyModel->get_iter (path); + if (iter) { +// Glib::ustring param, val; +// iter->get_value (1, param); +// iter->get_value (2, val); Glib::ustring text, val; - iter->get_value(0, text); - iter->get_value(1, val); + iter->get_value (0, text); + iter->get_value (1, val); /* * @@ -442,10 +457,12 @@ bool History::on_query_tooltip(int x, int y, bool keyboard_tooltip, const Glib:: tooltip->set_custom(*hbox); */ - tooltip->set_text(text + " : " + val); +// tooltip->set_text (param + " : " + val); + tooltip->set_text (text + " : " + val); displayTooltip = true; } } } + return displayTooltip; } diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index 0be6982f9..22e140e7d 100644 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -409,6 +409,34 @@ void ImageArea::getImageSize (int &w, int&h) } } +void ImageArea::getPreviewCenterPos(int &x, int &y) +{ + if (mainCropWindow) { + // Getting crop window size + int cW, cH; + mainCropWindow->getSize(cW, cH); + + // Converting center coord of crop window to image coord + const int cX = cW / 2; + const int cY = cH / 2; + mainCropWindow->screenCoordToImage(cX, cY, x, y); + } else { + x = y = 0; + } +} + +void ImageArea::getPreviewSize(int &w, int &h) +{ + if (mainCropWindow) { + int tmpW, tmpH; + mainCropWindow->getSize(tmpW, tmpH); + w = mainCropWindow->scaleValueToImage(tmpW); + h = mainCropWindow->scaleValueToImage(tmpH); + } else { + w = h = 0; + } +} + void ImageArea::grabFocus (CropWindow* cw) { diff --git a/rtgui/imagearea.h b/rtgui/imagearea.h index 586bba7a7..ad6fd305f 100644 --- a/rtgui/imagearea.h +++ b/rtgui/imagearea.h @@ -148,6 +148,8 @@ public: void subscribe(EditSubscriber *subscriber) override; void unsubscribe() override; void getImageSize (int &w, int&h) override; + void getPreviewCenterPos(int &x, int &y) override; + void getPreviewSize(int &w, int &h) override; // CropWindowListener interface void cropPositionChanged (CropWindow* cw) override; diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc new file mode 100644 index 000000000..a4351c710 --- /dev/null +++ b/rtgui/locallab.cc @@ -0,0 +1,1189 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as publishfed 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 . + * 2017 Jacques Desmis + * 2019 Pierre Cabrera + */ +#include "locallab.h" + +#include "options.h" +#include "../rtengine/procparams.h" + +using namespace rtengine; +using namespace procparams; + +extern Options options; + +/* ==== LocallabToolList ==== */ +LocallabToolList::LocallabToolList(): + // Tool list GUI elements + list(Gtk::manage(new MyComboBox())), + listTreeModel(Gtk::ListStore::create(toolRow)), + + // Tool list listener + listListener(nullptr) +{ + list->set_model(listTreeModel); + list->pack_start(toolRow.name); + listConn = list->signal_changed().connect(sigc::mem_fun(*this, &LocallabToolList::toolRowSelected)); + list->set_tooltip_text(M("TP_LOCALLAB_LIST_TOOLTIP")); + // Append title row to list + // Important: Title row shall always be the first one + const auto titleRow = *(listTreeModel->append()); + titleRow[toolRow.id] = 0; + titleRow[toolRow.name] = M("TP_LOCALLAB_LIST_NAME"); + listConn.block(true); + list->set_active(titleRow); + listConn.block(false); + + // Add ComboBox to LocallabToolList widget + add(*list); +} + +void LocallabToolList::addToolRow(const Glib::ustring &toolname, const int id) +{ + // Disable event management + listConn.block(true); + + // Add tool name according to id + Gtk::TreeIter insertAfter; + + for (auto &r : listTreeModel->children()) { + if (r[toolRow.id] < id) { + insertAfter = *r; // Tool name shall be added at least after this row + } else { + break; // Tool name shall be added before this row + } + } + + // Note: There is always at list one row (i.e. title one) + + const auto newRow = *(listTreeModel->insert_after(insertAfter)); + newRow[toolRow.id] = id; + newRow[toolRow.name] = toolname; + + // Select title row (i.e. always first row) + list->set_active(0); + + // Enable event management + listConn.block(false); +} + +void LocallabToolList::removeToolRow(const Glib::ustring &toolname) +{ + // Disable event management + listConn.block(true); + + // Remove tool name row + for (auto &r : listTreeModel->children()) { + if (r[toolRow.name] == toolname) { + listTreeModel->erase(*r); + break; + } + } + + // Select title row (i.e. always first row) + list->set_active(0); + + // Enable event management + listConn.block(false); +} + +void LocallabToolList::removeAllTool() +{ + // Disable event management + listConn.block(true); + + // Remove all tools + listTreeModel->clear(); + + // Add title row again + const auto titleRow = *(listTreeModel->append()); + titleRow[toolRow.id] = 0; + titleRow[toolRow.name] = M("TP_LOCALLAB_LIST_NAME"); + + // Select title row (i.e. always first row) + list->set_active(0); + + // Enable event management + listConn.block(false); +} + +void LocallabToolList::toolRowSelected() +{ + // Get selected tool name + const auto selRow = *(list->get_active()); + const Glib::ustring toolname = selRow[toolRow.name]; + + // Remove selected tool name for ComboBox + removeToolRow(toolname); + + // Warm tool list listener + if (listListener) { + listListener->locallabToolToAdd(toolname); + } +} + +/* ==== Locallab ==== */ +Locallab::Locallab(): + FoldableToolPanel(this, "locallab", M("TP_LOCALLAB_LABEL"), false, true), + + // Spot control panel widget + expsettings(Gtk::manage(new ControlSpotPanel())), + + // Tool list widget + toollist(Gtk::manage(new LocallabToolList())), + + // Create Locallab tools + expcolor(Gtk::manage(new LocallabColor())), + expexpose(Gtk::manage(new LocallabExposure())), + expshadhigh(Gtk::manage(new LocallabShadow())), + expvibrance(Gtk::manage(new LocallabVibrance())), + expsoft(Gtk::manage(new LocallabSoft())), + expblur(Gtk::manage(new LocallabBlur())), + exptonemap(Gtk::manage(new LocallabTone())), + expreti(Gtk::manage(new LocallabRetinex())), + expsharp(Gtk::manage(new LocallabSharp())), + expcontrast(Gtk::manage(new LocallabContrast())), + expcbdl(Gtk::manage(new LocallabCBDL())), + explog(Gtk::manage(new LocallabLog())), + + // Other widgets + resetshowButton(Gtk::manage(new Gtk::Button(M("TP_LOCALLAB_RESETSHOW")))) +{ + // Create panel widget to receive Locallab GUI elements + ToolVBox* const panel = Gtk::manage(new ToolVBox()); + panel->set_spacing(2); + + // Add spot control panel to panel widget + expsettings->setControlPanelListener(this); + expsettings->setLevel(2); + panel->pack_start(*expsettings->getExpander(), false, false); + + // Add separator + Gtk::HSeparator* const separator = Gtk::manage(new Gtk::HSeparator()); + panel->pack_start(*separator, false, false); + + // Add tool list widget + toollist->setLocallabToolListListener(this); + panel->pack_start(*toollist, false, false); + + // Add Locallab tools to panel widget + ToolVBox* const toolpanel = Gtk::manage(new ToolVBox()); + toolpanel->set_name("LocallabToolPanel"); + addTool(toolpanel, expcolor); + addTool(toolpanel, expexpose); + addTool(toolpanel, expshadhigh); + addTool(toolpanel, expvibrance); + addTool(toolpanel, expsoft); + addTool(toolpanel, expblur); + addTool(toolpanel, exptonemap); + addTool(toolpanel, expreti); + addTool(toolpanel, expsharp); + addTool(toolpanel, expcontrast); + addTool(toolpanel, expcbdl); + addTool(toolpanel, explog); + panel->pack_start(*toolpanel, false, false); + + // Add separator + // Gtk::HSeparator* const separator2 = Gtk::manage(new Gtk::HSeparator()); + // panel->pack_start(*separator2, false, false); + + // Add mask reset button to panel widget + resetshowButton->signal_pressed().connect(sigc::mem_fun(*this, &Locallab::resetshowPressed)); + // panel->pack_start(*resetshowButton); + + // Add panel widget to Locallab GUI + pack_start(*panel); + + // Show all widgets + show_all(); + + // Update Locallab tools advice tooltips visibility based on saved option + for (auto tool : locallabTools) { + tool->updateAdviceTooltips(options.showtooltip); + } + + // By default, if no photo is loaded, all Locallab tools are removed and it's not possible to add them + // (to be necessary called after "show_all" function) + setParamEditable(false); +} + +void Locallab::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update Locallab activation state + setEnabled(pp->locallab.enabled); + + // Transmit Locallab activation state to Locallab tools + for (auto tool : locallabTools) { + tool->isLocallabActivated(exp->getEnabled()); + } + + // TODO Manage it with read function in controlspotpanel.cc + // Delete all existent spots + const int spotNb = expsettings->getSpotNumber(); + + for (int i = spotNb - 1; i >= 0; i--) { + expsettings->deleteControlSpot(i); + } + + // TODO Manage it with read function in controlspotpanel.cc + // Add existent spots based on pp + ControlSpotPanel::SpotRow* const r = new ControlSpotPanel::SpotRow(); + + for (int i = 0; i < (int)pp->locallab.spots.size(); i++) { + r->name = pp->locallab.spots.at(i).name; + r->isvisible = pp->locallab.spots.at(i).isvisible; + + if (pp->locallab.spots.at(i).shape == "ELI") { + r->shape = 0; + } else { + r->shape = 1; + } + + if (pp->locallab.spots.at(i).spotMethod == "norm") { + r->spotMethod = 0; + } else { + r->spotMethod = 1; + } + + r->sensiexclu = pp->locallab.spots.at(i).sensiexclu; + r->structexclu = pp->locallab.spots.at(i).structexclu; + + if (pp->locallab.spots.at(i).shapeMethod == "IND") { + r->shapeMethod = 0; + } else if (pp->locallab.spots.at(i).shapeMethod == "SYM") { + r->shapeMethod = 1; + } else if (pp->locallab.spots.at(i).shapeMethod == "INDSL") { + r->shapeMethod = 2; + } else { + r->shapeMethod = 3; + } + + r->locX = pp->locallab.spots.at(i).loc.at(0); + r->locXL = pp->locallab.spots.at(i).loc.at(1); + r->locY = pp->locallab.spots.at(i).loc.at(2); + r->locYT = pp->locallab.spots.at(i).loc.at(3); + r->centerX = pp->locallab.spots.at(i).centerX; + r->centerY = pp->locallab.spots.at(i).centerY; + r->circrad = pp->locallab.spots.at(i).circrad; + + if (pp->locallab.spots.at(i).qualityMethod == "enh") { + r->qualityMethod = 0; + } else { + r->qualityMethod = 1; + } + + r->transit = pp->locallab.spots.at(i).transit; + r->transitweak = pp->locallab.spots.at(i).transitweak; + r->transitgrad = pp->locallab.spots.at(i).transitgrad; + r->feather = pp->locallab.spots.at(i).feather; + r->struc = pp->locallab.spots.at(i).struc; + r->thresh = pp->locallab.spots.at(i).thresh; + r->iter = pp->locallab.spots.at(i).iter; + r->balan = pp->locallab.spots.at(i).balan; + r->balanh = pp->locallab.spots.at(i).balanh; + r->colorde = pp->locallab.spots.at(i).colorde; + r->colorscope = pp->locallab.spots.at(i).colorscope; + r->avoid = pp->locallab.spots.at(i).avoid; + r->blwh = pp->locallab.spots.at(i).blwh; + r->recurs = pp->locallab.spots.at(i).recurs; + r->laplac = pp->locallab.spots.at(i).laplac; + r->deltae = pp->locallab.spots.at(i).deltae; + r->scopemask = pp->locallab.spots.at(i).scopemask; + r->shortc = pp->locallab.spots.at(i).shortc; + r->lumask = pp->locallab.spots.at(i).lumask; + r->savrest = pp->locallab.spots.at(i).savrest; + + if (pp->locallab.spots.at(i).complexMethod == "sim") { + r->complexMethod = 0; + } else if (pp->locallab.spots.at(i).complexMethod == "mod") { + r->complexMethod = 1; + } else if (pp->locallab.spots.at(i).complexMethod == "all") { + r->complexMethod = 2; + } + + if (pp->locallab.spots.at(i).wavMethod == "D2") { + r->wavMethod = 0; + } else if (pp->locallab.spots.at(i).wavMethod == "D4") { + r->wavMethod = 1; + } else if (pp->locallab.spots.at(i).wavMethod == "D6") { + r->wavMethod = 2; + } else if (pp->locallab.spots.at(i).wavMethod == "D10") { + r->wavMethod = 3; + } else if (pp->locallab.spots.at(i).wavMethod == "D14") { + r->wavMethod = 4; + } + + expsettings->addControlSpot(r); + } + + // Select active spot + if (pp->locallab.spots.size() > 0) { + expsettings->setSelectedSpot(pp->locallab.selspot); + } + + // Update each Locallab tools GUI + for (auto tool : locallabTools) { + tool->read(pp, pedited); + } + + // Update tool list widget + int toolNb = 0; + toollist->removeAllTool(); // Reset Locallab list firstly + + for (auto tool : locallabTools) { + toolNb++; + + if (!tool->isLocallabToolAdded()) { + toollist->addToolRow(tool->getToolName(), toolNb); + } + } + + // Specific case: if there is no spot, GUI isn't anymore editable (i.e. Locallab tool cannot be managed) + if (pp->locallab.spots.size() > 0) { + setParamEditable(true); + } else { + setParamEditable(false); + } + + // Enable all listeners + enableListener(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + // Update Locallab activation state + pp->locallab.enabled = getEnabled(); + + // Transmit Locallab activation state to Locallab tools (in case of updated) + for (auto tool : locallabTools) { + tool->isLocallabActivated(exp->getEnabled()); + } + + const int spotPanelEvent = expsettings->getEventType(); + int spotIndex; + ControlSpotPanel::SpotRow* r; + rtengine::procparams::LocallabParams::LocallabSpot* newSpot; + + int imW, imH; // Size of image + int prW, prH; // Size of preview area + int prX, prY; // Coord of preview area center + EditDataProvider* const provider = expsettings->getEditProvider(); + + int toolNb; + + switch (spotPanelEvent) { + case (ControlSpotPanel::SpotCreation): // Spot creation event + // Spot creation (default initialization) + newSpot = new LocallabParams::LocallabSpot(); + r = new ControlSpotPanel::SpotRow(); + r->name = newSpot->name = M("TP_LOCALLAB_SPOTNAME"); + r->isvisible = newSpot->isvisible; + + if (newSpot->shape == "ELI") { + r->shape = 0; + } else { + r->shape = 1; + } + + if (newSpot->spotMethod == "norm") { + r->spotMethod = 0; + } else { + r->spotMethod = 1; + } + + r->sensiexclu = newSpot->sensiexclu; + r->structexclu = newSpot->structexclu; + + if (newSpot->shapeMethod == "IND") { + r->shapeMethod = 0; + } else if (newSpot->shapeMethod == "SYM") { + r->shapeMethod = 1; + } else if (newSpot->shapeMethod == "INDSL") { + r->shapeMethod = 2; + } else { + r->shapeMethod = 3; + } + + // Calculate spot size and center position according to preview area + if (provider && !batchMode) { + provider->getImageSize(imW, imH); + provider->getPreviewCenterPos(prX, prY); + provider->getPreviewSize(prW, prH); + + if (imW && imH) { // Image loaded + // Spot center position computation + newSpot->centerX = rtengine::LIM(int(int((double)prX - (double)imW / 2.) * 2000. / (double)imW), -1000, 1000); + newSpot->centerY = rtengine::LIM(int(int((double)prY - (double)imH / 2.) * 2000. / (double)imH), -1000, 1000); + // Ellipse/rectangle size computation + newSpot->loc.at(0) = rtengine::LIM(int(((double)prW / 2. - 5.) * 2000. / (double)imW), 2, newSpot->loc.at(0)); + newSpot->loc.at(1) = rtengine::LIM(int(((double)prW / 2. - 5.) * 2000. / (double)imW), 2, newSpot->loc.at(1)); + newSpot->loc.at(2) = rtengine::LIM(int(((double)prH / 2. - 5.) * 2000. / (double)imH), 2, newSpot->loc.at(2)); + newSpot->loc.at(3) = rtengine::LIM(int(((double)prH / 2. - 5.) * 2000. / (double)imH), 2, newSpot->loc.at(3)); + } + } + + r->locX = newSpot->loc.at(0); + r->locXL = newSpot->loc.at(1); + r->locY = newSpot->loc.at(2); + r->locYT = newSpot->loc.at(3); + r->centerX = newSpot->centerX; + r->centerY = newSpot->centerY; + + r->circrad = newSpot->circrad; + + if (newSpot->qualityMethod == "enh") { + r->qualityMethod = 0; + } else { + r->qualityMethod = 1; + } + + r->transit = newSpot->transit; + r->transitweak = newSpot->transitweak; + r->transitgrad = newSpot->transitgrad; + r->feather = newSpot->feather; + r->struc = newSpot->struc; + r->thresh = newSpot->thresh; + r->iter = newSpot->iter; + r->balan = newSpot->balan; + r->balanh = newSpot->balanh; + r->colorde = newSpot->colorde; + r->colorscope = newSpot->colorscope; + r->avoid = newSpot->avoid; + r->blwh = newSpot->blwh; + r->recurs = newSpot->recurs; + r->laplac = newSpot->laplac; + r->deltae = newSpot->deltae; + r->scopemask = newSpot->scopemask; + r->shortc = newSpot->shortc; + r->lumask = newSpot->lumask; + r->savrest = newSpot->savrest; + + if (newSpot->complexMethod == "sim") { + r->complexMethod = 0; + } else if (newSpot->complexMethod == "mod") { + r->complexMethod = 1; + } else if (newSpot->complexMethod == "all") { + r->complexMethod = 2; + } + + if (newSpot->wavMethod == "D2") { + r->wavMethod = 0; + } else if (newSpot->wavMethod == "D4") { + r->wavMethod = 1; + } else if (newSpot->wavMethod == "D6") { + r->wavMethod = 2; + } else if (newSpot->wavMethod == "D10") { + r->wavMethod = 3; + } else if (newSpot->wavMethod == "D14") { + r->wavMethod = 4; + } + + expsettings->addControlSpot(r); + + // ProcParams update + pp->locallab.spots.push_back(*newSpot); + pp->locallab.selspot = pp->locallab.spots.size() - 1; + + // New created spot selection + expsettings->setSelectedSpot(pp->locallab.selspot); + + // Update Locallab tools GUI with new created spot + disableListener(); + + for (auto tool : locallabTools) { + tool->read(pp, pedited); + } + + enableListener(); + + // Update tool list widget + toolNb = 0; + toollist->removeAllTool(); // Reset Locallab list firstly + + for (auto tool : locallabTools) { + toolNb++; + + if (!tool->isLocallabToolAdded()) { + toollist->addToolRow(tool->getToolName(), toolNb); + } + } + + if (pp->locallab.spots.size() == 1) { + setParamEditable(true); + } + + // Update default values according to selected spot + setDefaults(pp, pedited); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab + + break; + + case (ControlSpotPanel::SpotDeletion): // Spot deletion event + // Get deleted spot index in ProcParams and update it + spotIndex = expsettings->getSelectedSpot(); + + for (int i = 0; i < (int)pp->locallab.spots.size(); i++) { + if (i == spotIndex) { + // ProcParams update + pp->locallab.spots.erase(pp->locallab.spots.begin() + i); + expsettings->deleteControlSpot(spotIndex); + + // Select the first remaining spot before deleted one + if (pp->locallab.spots.size() > 0) { + for (int j = i - 1; j >= 0; j--) { + if (expsettings->setSelectedSpot(j)) { // True if an existing spot has been selected on controlspotpanel + pp->locallab.selspot = j; + + break; + } + } + } else { + // Reset selspot + pp->locallab.selspot = 0; + } + + // Update Locallab tools GUI with selected spot + disableListener(); + + for (auto tool : locallabTools) { + tool->read(pp, pedited); + } + + enableListener(); + + // Update tool list widget + toolNb = 0; + toollist->removeAllTool(); // Reset Locallab list firstly + + for (auto tool : locallabTools) { + toolNb++; + + if (!tool->isLocallabToolAdded()) { + toollist->addToolRow(tool->getToolName(), toolNb); + } + } + + if (pp->locallab.spots.size() == 0) { + setParamEditable(false); + } + + // Update default values according to selected spot + setDefaults(pp, pedited); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab + + break; + } + } + + break; + + case (ControlSpotPanel::SpotSelection): // Spot selection event + pp->locallab.selspot = expsettings->getSelectedSpot(); + + // Update control spots and Locallab tools GUI with selected spot + expsettings->setSelectedSpot(pp->locallab.selspot); + disableListener(); + + for (auto tool : locallabTools) { + tool->read(pp, pedited); + } + + enableListener(); + + // Update tool list widget + toolNb = 0; + toollist->removeAllTool(); // Reset Locallab list firstly + + for (auto tool : locallabTools) { + toolNb++; + + if (!tool->isLocallabToolAdded()) { + toollist->addToolRow(tool->getToolName(), toolNb); + } + } + + // Update locallab tools mask background + if (pp->locallab.selspot < (int)maskBackRef.size()) { + const double huer = maskBackRef.at(pp->locallab.selspot).huer; + const double lumar = maskBackRef.at(pp->locallab.selspot).lumar; + const double chromar = maskBackRef.at(pp->locallab.selspot).chromar; + + for (auto tool : locallabTools) { + tool->refChanged(huer, lumar, chromar); + } + } + + // Update Locallab Retinex tool min/max + if (pp->locallab.selspot < (int)retiMinMax.size()) { + const double cdma = retiMinMax.at(pp->locallab.selspot).cdma; + const double cdmin = retiMinMax.at(pp->locallab.selspot).cdmin; + const double mini = retiMinMax.at(pp->locallab.selspot).mini; + const double maxi = retiMinMax.at(pp->locallab.selspot).maxi; + const double Tmean = retiMinMax.at(pp->locallab.selspot).Tmean; + const double Tsigma = retiMinMax.at(pp->locallab.selspot).Tsigma; + const double Tmin = retiMinMax.at(pp->locallab.selspot).Tmin; + const double Tmax = retiMinMax.at(pp->locallab.selspot).Tmax; + + expreti->updateMinMax(cdma, cdmin, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } + + // Update default values according to selected spot + setDefaults(pp, pedited); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab + + break; + + case (ControlSpotPanel::SpotDuplication): // Spot duplication event + newSpot = nullptr; + spotIndex = expsettings->getSelectedSpot(); + + for (int i = 0; i < (int)pp->locallab.spots.size(); i++) { + if (i == spotIndex) { + newSpot = new LocallabParams::LocallabSpot(pp->locallab.spots.at(i)); + break; + } + } + + if (!newSpot) { + break; + } + + // Spot creation (initialization at currently selected spot) + r = new ControlSpotPanel::SpotRow(); + r->name = newSpot->name = newSpot->name + " - " + M("TP_LOCALLAB_DUPLSPOTNAME"); + r->isvisible = newSpot->isvisible; + + if (newSpot->shape == "ELI") { + r->shape = 0; + } else { + r->shape = 1; + } + + if (newSpot->spotMethod == "norm") { + r->spotMethod = 0; + } else { + r->spotMethod = 1; + } + + r->sensiexclu = newSpot->sensiexclu; + r->structexclu = newSpot->structexclu; + + if (newSpot->shapeMethod == "IND") { + r->shapeMethod = 0; + } else if (newSpot->shapeMethod == "SYM") { + r->shapeMethod = 1; + } else if (newSpot->shapeMethod == "INDSL") { + r->shapeMethod = 2; + } else { + r->shapeMethod = 3; + } + + // Calculate spot size and center position according to preview area + if (provider && !batchMode) { + provider->getImageSize(imW, imH); + provider->getPreviewCenterPos(prX, prY); + provider->getPreviewSize(prW, prH); + + if (imW && imH) { // Image loaded + // Spot center position computation + newSpot->centerX = rtengine::LIM(int(int((double)prX - (double)imW / 2.) * 2000. / (double)imW), -1000, 1000); + newSpot->centerY = rtengine::LIM(int(int((double)prY - (double)imH / 2.) * 2000. / (double)imH), -1000, 1000); + // Ellipse/rectangle size computation + newSpot->loc.at(0) = rtengine::LIM(int(((double)prW / 2. - 5.) * 2000. / (double)imW), 2, newSpot->loc.at(0)); + newSpot->loc.at(1) = rtengine::LIM(int(((double)prW / 2. - 5.) * 2000. / (double)imW), 2, newSpot->loc.at(1)); + newSpot->loc.at(2) = rtengine::LIM(int(((double)prH / 2. - 5.) * 2000. / (double)imH), 2, newSpot->loc.at(2)); + newSpot->loc.at(3) = rtengine::LIM(int(((double)prH / 2. - 5.) * 2000. / (double)imH), 2, newSpot->loc.at(3)); + } + } + + r->locX = newSpot->loc.at(0); + r->locXL = newSpot->loc.at(1); + r->locY = newSpot->loc.at(2); + r->locYT = newSpot->loc.at(3); + r->centerX = newSpot->centerX; + r->centerY = newSpot->centerY; + + r->circrad = newSpot->circrad; + + if (newSpot->qualityMethod == "enh") { + r->qualityMethod = 0; + } else { + r->qualityMethod = 1; + } + + r->transit = newSpot->transit; + r->transitweak = newSpot->transitweak; + r->transitgrad = newSpot->transitgrad; + r->feather = newSpot->feather; + r->struc = newSpot->struc; + r->thresh = newSpot->thresh; + r->iter = newSpot->iter; + r->balan = newSpot->balan; + r->balanh = newSpot->balanh; + r->colorde = newSpot->colorde; + r->colorscope = newSpot->colorscope; + r->avoid = newSpot->avoid; + r->blwh = newSpot->blwh; + r->recurs = newSpot->recurs; + r->laplac = newSpot->laplac; + r->deltae = newSpot->deltae; + r->scopemask = newSpot->scopemask; + r->shortc = newSpot->shortc; + r->lumask = newSpot->lumask; + r->savrest = newSpot->savrest; + + if (newSpot->complexMethod == "sim") { + r->complexMethod = 0; + } else if (newSpot->complexMethod == "mod") { + r->complexMethod = 1; + } else if (newSpot->complexMethod == "all") { + r->complexMethod = 2; + } + + if (newSpot->wavMethod == "D2") { + r->wavMethod = 0; + } else if (newSpot->wavMethod == "D4") { + r->wavMethod = 1; + } else if (newSpot->wavMethod == "D6") { + r->wavMethod = 2; + } else if (newSpot->wavMethod == "D10") { + r->wavMethod = 3; + } else if (newSpot->wavMethod == "D14") { + r->wavMethod = 4; + } + + expsettings->addControlSpot(r); + + // ProcParams update + pp->locallab.spots.push_back(*newSpot); + pp->locallab.selspot = pp->locallab.spots.size() - 1; + + + // New created spot selection + expsettings->setSelectedSpot(pp->locallab.selspot); + + // Update Locallab tools GUI with new created spot + disableListener(); + + for (auto tool : locallabTools) { + tool->read(pp, pedited); + } + + enableListener(); + + // Update tool list widget + toolNb = 0; + toollist->removeAllTool(); // Reset Locallab list firstly + + for (auto tool : locallabTools) { + toolNb++; + + if (!tool->isLocallabToolAdded()) { + toollist->addToolRow(tool->getToolName(), toolNb); + } + } + + // Update default values according to selected spot + setDefaults(pp, pedited); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab + + break; + + case (ControlSpotPanel::SpotAllVisibilityChanged): // Event when updating visibility of all spots + r = expsettings->getSpot(expsettings->getSelectedSpot()); + + // ProcParams update + for (size_t i = 0; i < pp->locallab.spots.size(); i++) { + pp->locallab.spots.at(i).isvisible = r->isvisible; + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab + + break; + + default: // Spot or locallab GUI updated + if (pp->locallab.spots.size() > 0) { + r = expsettings->getSpot(expsettings->getSelectedSpot()); + + // ProcParams update + if (pp->locallab.selspot < (int)pp->locallab.spots.size()) { + // Control spot settings + pp->locallab.spots.at(pp->locallab.selspot).name = r->name; + pp->locallab.spots.at(pp->locallab.selspot).isvisible = r->isvisible; + + if (r->shape == 0) { + pp->locallab.spots.at(pp->locallab.selspot).shape = "ELI"; + } else { + pp->locallab.spots.at(pp->locallab.selspot).shape = "RECT"; + } + + if (r->spotMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).spotMethod = "norm"; + } else { + pp->locallab.spots.at(pp->locallab.selspot).spotMethod = "exc"; + } + + pp->locallab.spots.at(pp->locallab.selspot).sensiexclu = r->sensiexclu; + pp->locallab.spots.at(pp->locallab.selspot).structexclu = r->structexclu; + + if (r->shapeMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).shapeMethod = "IND"; + } else if (r->shapeMethod == 1) { + pp->locallab.spots.at(pp->locallab.selspot).shapeMethod = "SYM"; + } else if (r->shapeMethod == 2) { + pp->locallab.spots.at(pp->locallab.selspot).shapeMethod = "INDSL"; + } else { + pp->locallab.spots.at(pp->locallab.selspot).shapeMethod = "SYMSL"; + } + + pp->locallab.spots.at(pp->locallab.selspot).loc.at(0) = r->locX; + pp->locallab.spots.at(pp->locallab.selspot).loc.at(1) = r->locXL; + pp->locallab.spots.at(pp->locallab.selspot).loc.at(2) = r->locY; + pp->locallab.spots.at(pp->locallab.selspot).loc.at(3) = r->locYT; + pp->locallab.spots.at(pp->locallab.selspot).centerX = r->centerX; + pp->locallab.spots.at(pp->locallab.selspot).centerY = r->centerY; + pp->locallab.spots.at(pp->locallab.selspot).circrad = r->circrad; + + if (r->qualityMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).qualityMethod = "enh"; + } else { + pp->locallab.spots.at(pp->locallab.selspot).qualityMethod = "enhden"; + } + + pp->locallab.spots.at(pp->locallab.selspot).transit = r->transit; + pp->locallab.spots.at(pp->locallab.selspot).transitweak = r->transitweak; + pp->locallab.spots.at(pp->locallab.selspot).transitgrad = r->transitgrad; + pp->locallab.spots.at(pp->locallab.selspot).feather = r->feather; + pp->locallab.spots.at(pp->locallab.selspot).struc = r->struc; + pp->locallab.spots.at(pp->locallab.selspot).thresh = r->thresh; + pp->locallab.spots.at(pp->locallab.selspot).iter = r->iter; + pp->locallab.spots.at(pp->locallab.selspot).balan = r->balan; + pp->locallab.spots.at(pp->locallab.selspot).balanh = r->balanh; + pp->locallab.spots.at(pp->locallab.selspot).colorde = r->colorde; + pp->locallab.spots.at(pp->locallab.selspot).colorscope = r->colorscope; + pp->locallab.spots.at(pp->locallab.selspot).avoid = r->avoid; + pp->locallab.spots.at(pp->locallab.selspot).blwh = r->blwh; + pp->locallab.spots.at(pp->locallab.selspot).recurs = r->recurs; + pp->locallab.spots.at(pp->locallab.selspot).laplac = r->laplac; + pp->locallab.spots.at(pp->locallab.selspot).deltae = r->deltae; + pp->locallab.spots.at(pp->locallab.selspot).scopemask = r->scopemask; + pp->locallab.spots.at(pp->locallab.selspot).shortc = r->shortc; + pp->locallab.spots.at(pp->locallab.selspot).lumask = r->lumask; + pp->locallab.spots.at(pp->locallab.selspot).savrest = r->savrest; + + if (r->complexMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).complexMethod = "sim"; + } else if (r->complexMethod == 1) { + pp->locallab.spots.at(pp->locallab.selspot).complexMethod = "mod"; + } else if (r->complexMethod == 2) { + pp->locallab.spots.at(pp->locallab.selspot).complexMethod = "all"; + } + + if (r->wavMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).wavMethod = "D2"; + } else if (r->wavMethod == 1) { + pp->locallab.spots.at(pp->locallab.selspot).wavMethod = "D4"; + } else if (r->wavMethod == 2) { + pp->locallab.spots.at(pp->locallab.selspot).wavMethod = "D6"; + } else if (r->wavMethod == 3) { + pp->locallab.spots.at(pp->locallab.selspot).wavMethod = "D10"; + } else if (r->wavMethod == 4) { + pp->locallab.spots.at(pp->locallab.selspot).wavMethod = "D14"; + } + } + + for (auto tool : locallabTools) { + tool->write(pp, pedited); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab + } + } +} + +/* + * Note: + * By default, this function is called when a new image/profile is loaded (after read function). In this case, + * if there is at least one spot, default values are set to selected spot ones. + * To keep having default values according to selected spot, this function shall also be called in the following + * situations (after having called write function for controlspotpanel): + * - After spot creation + * - After spot deletion + * - After spot selection + * - After spot duplication + */ +void Locallab::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + // Set default values in spot panel control + expsettings->setDefaults(defParams, pedited); + + // Set default values in Locallab tools + for (auto tool : locallabTools) { + tool->setDefaults(defParams, pedited); + } +} + +void Locallab::setListener(ToolPanelListener* tpl) +{ + this->listener = tpl; + + // Set listener for spot control panel + expsettings->setListener(tpl); + + // Set listener for locallab tools + for (auto tool : locallabTools) { + tool->setListener(tpl); + } +} + +void Locallab::minmaxChanged(const std::vector &minmax, int selspot) +{ + // Saving transmitted min/max data + retiMinMax = minmax; + + // Update Locallab Retinex tool min/max + if (selspot < (int)retiMinMax.size()) { + const double cdma = retiMinMax.at(selspot).cdma; + const double cdmin = retiMinMax.at(selspot).cdmin; + const double mini = retiMinMax.at(selspot).mini; + const double maxi = retiMinMax.at(selspot).maxi; + const double Tmean = retiMinMax.at(selspot).Tmean; + const double Tsigma = retiMinMax.at(selspot).Tsigma; + const double Tmin = retiMinMax.at(selspot).Tmin; + const double Tmax = retiMinMax.at(selspot).Tmax; + + expreti->updateMinMax(cdma, cdmin, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } +} + +void Locallab::logencodChanged(const float blackev, const float whiteev, const float sourceg, const float targetg) +{ + // Update Locallab Log Encoding accordingly + explog->updateAutocompute(blackev, whiteev, sourceg, targetg); +} + +void Locallab::refChanged(const std::vector &ref, int selspot) +{ + // Saving transmitted mask background data + maskBackRef = ref; + + // Update locallab tools mask background + if (selspot < (int)maskBackRef.size()) { + const double huer = maskBackRef.at(selspot).huer; + const double lumar = maskBackRef.at(selspot).lumar; + const double chromar = maskBackRef.at(selspot).chromar; + + for (auto tool : locallabTools) { + tool->refChanged(huer, lumar, chromar); + } + } +} + +void Locallab::resetMaskVisibility() +{ + // Indicate to spot control panel that no more mask preview is active + expsettings->setMaskPrevActive(false); + + // Reset deltaE preview + expsettings->resetDeltaEPreview(); + + // Reset mask preview for all Locallab tools + for (auto tool : locallabTools) { + tool->resetMaskView(); + } +} + +Locallab::llMaskVisibility Locallab::getMaskVisibility() const +{ + // Get deltaE preview state + const bool prevDeltaE = expsettings->isDeltaEPrevActive(); + + // Get mask preview from Locallab tools + int colorMask, colorMaskinv, expMask, expMaskinv, shMask, shMaskinv, vibMask, softMask, blMask, tmMask, retiMask, sharMask, lcMask, cbMask; + + for (auto tool : locallabTools) { + tool->getMaskView(colorMask, colorMaskinv, expMask, expMaskinv, shMask, shMaskinv, vibMask, softMask, blMask, tmMask, retiMask, sharMask, lcMask, cbMask); + } + + // Indicate to spot control panel if one mask preview is active + const bool isMaskActive = (colorMask == 0) || (colorMaskinv == 0) || (expMask == 0) || (expMaskinv == 0) || + (shMask == 0) || (shMaskinv == 0) || (vibMask == 0) || (softMask == 0) || + (blMask == 0) || (tmMask == 0) || (retiMask == 0) || (sharMask == 0) || + (lcMask == 0) || (cbMask == 0); + expsettings->setMaskPrevActive(isMaskActive); + + return {prevDeltaE, colorMask, colorMaskinv, expMask, expMaskinv, shMask, shMaskinv, vibMask, softMask, blMask, tmMask, retiMask, sharMask, lcMask, cbMask}; +} + +void Locallab::resetshowPressed() +{ + // Raise event to reset mask + if (listener) { + listener->panelChanged(Evlocallabshowreset, ""); + } +} + +void Locallab::setEditProvider(EditDataProvider * provider) +{ + expsettings->setEditProvider(provider); +} + +void Locallab::subscribe() +{ + expsettings->subscribe(); +} + +void Locallab::unsubscribe() +{ + expsettings->unsubscribe(); +} + +void Locallab::enabledChanged() +{ + if (listener) { + if (getEnabled()) { + listener->panelChanged(EvlocallabEnabled, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvlocallabEnabled, M("GENERAL_DISABLED")); + } + } +} + +void Locallab::autoOpenCurve() +{ + // TODO Actually autoOpenCurve only considers linearity state of selected spot curve +} + +void Locallab::foldAllButOne(LocallabTool* except) +{ + for (auto tool : locallabTools) { + if (tool != except) { + // All other tool expanders are fold + tool->setExpanded(false); + } else { + // If fold, selected tool expander is unfold + if (!tool->getExpanded()) { + tool->setExpanded(true); + } + } + } +} + +void Locallab::openAllTools() +{ + // Set default visibility for settings panel sub-expanders + expsettings->setDefaultExpanderVisibility(); + + for (auto tool : locallabTools) { + tool->setExpanded(true); + + // Set default visibility for tool sub-expanders + tool->setDefaultExpanderVisibility(); + } +} + +void Locallab::updateShowtooltipVisibility(bool showtooltip) +{ + for (auto tool : locallabTools) { + tool->updateAdviceTooltips(showtooltip); + } +} + +void Locallab::addTool(Gtk::Box* where, LocallabTool* tool) +{ + tool->getExpander()->setLevel(3); + where->pack_start(*tool->getExpander(), false, false); + locallabTools.push_back(tool); + tool->setLocallabToolListener(this); +} + +void Locallab::setParamEditable(bool cond) +{ + // Update params editable state for controlspotpanel + expsettings->setParamEditable(cond); // TODO Move this code to controlspotpanel.cc when there is zero spot + + // Enable/disable possibility to add Locallab tool + toollist->set_sensitive(cond); + + // Remove all Locallab tool (without raising event) only if cond is false + if (!cond) { + for (auto tool : locallabTools) { + tool->removeLocallabTool(false); + } + } +} + +void Locallab::resetToolMaskView() +{ + // Reset mask view GUI for all other Locallab tools + for (auto tool : locallabTools) { + tool->resetMaskView(); + } +} + +void Locallab::resetOtherMaskView(LocallabTool* current) +{ + // Reset deltaE preview + expsettings->resetDeltaEPreview(); + + // Reset mask view GUI for all other Locallab tools except current + for (auto tool : locallabTools) { + if (tool != current) { + tool->resetMaskView(); + } + } +} + +void Locallab::toolRemoved(LocallabTool* current) +{ + // Update tool list widget according to removed tool + int toolNb = 0; + + for (auto tool : locallabTools) { + toolNb++; + + if (tool == current) { + toollist->addToolRow(tool->getToolName(), toolNb); + } + } +} + +void Locallab::locallabToolToAdd(const Glib::ustring &toolname) +{ + for (auto tool : locallabTools) { + if (tool->getToolName() == toolname) { + // Set expanders visibility default state when adding tool + tool->setExpanded(true); + tool->setDefaultExpanderVisibility(); + + // Add tool + tool->addLocallabTool(true); + } + } +} diff --git a/rtgui/locallab.h b/rtgui/locallab.h new file mode 100644 index 000000000..8d68576f4 --- /dev/null +++ b/rtgui/locallab.h @@ -0,0 +1,209 @@ +/* + * 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 . + * 2017 Jacques Desmis + * 2019 Pierre Cabrera + */ +#ifndef _LOCALLAB_H_ +#define _LOCALLAB_H_ + +#pragma once + +#include "controlspotpanel.h" +#include "locallabtools.h" + +/* ==== LocallabToolListListener ==== */ +class LocallabToolList; +class LocallabToolListListener +{ +public: + LocallabToolListListener() {}; + virtual ~LocallabToolListListener() {}; + + virtual void locallabToolToAdd(const Glib::ustring &toolname) = 0; +}; + +/* ==== LocallabToolList ==== */ +class LocallabToolList: + public Gtk::VBox +{ +private: + // Tree model to manage ComboBox rows + class ToolRow: + public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn id; + Gtk::TreeModelColumn name; + + ToolRow() + { + add(id); + add(name); + } + }; + + // Tool list GUI widgets + MyComboBox* const list; + sigc::connection listConn; + ToolRow toolRow; + Glib::RefPtr listTreeModel; + + // Tool list listener + LocallabToolListListener* listListener; + +public: + LocallabToolList(); + + // Setter for tool list listener + void setLocallabToolListListener(LocallabToolListListener* ltll) + { + listListener = ltll; + } + + // Tool list management function + void addToolRow(const Glib::ustring &toolname, const int id); + void removeToolRow(const Glib::ustring &toolname); + void removeAllTool(); + +private: + // Tool list event management function + void toolRowSelected(); +}; + +/* ==== Locallab ==== */ +class Locallab : + public ToolParamBlock, + public FoldableToolPanel, + public rtengine::LocallabListener, + public ControlPanelListener, + public LocallabToolListener, + public LocallabToolListListener +{ +private: + // Spot control panel widget + ControlSpotPanel* const expsettings; + + // Tool list widget + LocallabToolList* const toollist; + + // Locallab tool widgets + LocallabColor* const expcolor; + LocallabExposure* const expexpose; + LocallabShadow* const expshadhigh; + LocallabVibrance* const expvibrance; + LocallabSoft* const expsoft; + LocallabBlur* const expblur; + LocallabTone* const exptonemap; + LocallabRetinex* const expreti; + LocallabSharp* const expsharp; + LocallabContrast* const expcontrast; + LocallabCBDL* const expcbdl; + LocallabLog* const explog; + + std::vector locallabTools; + + // Locallab tools mask background management data + std::vector retiMinMax; + + // Locallab tools mask background management data + std::vector maskBackRef; + + // Other widgets + Gtk::Button* const resetshowButton; + +public: + Locallab(); + + // FoldableToolPanel management functions + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void setListener(ToolPanelListener* tpl) override; + + // Locallab Retinex tool min/man management function + void minmaxChanged(const std::vector &minmax, int selspot) override; + + // Locallab Log Encoding autocompute function + void logencodChanged(const float blackev, const float whiteev, const float sourceg, const float targetg) override; + + // Locallab tools mask background management function + void refChanged(const std::vector &ref, int selspot) override; + + // Mask visibility management functions + struct llMaskVisibility { + bool previewDeltaE; + int colorMask; + int colorMaskinv; + int expMask; + int expMaskinv; + int SHMask; + int SHMaskinv; + int vibMask; + int softMask; + int blMask; + int tmMask; + int retiMask; + int sharMask; + int lcMask; + int cbMask; + }; + + void resetMaskVisibility(); + llMaskVisibility getMaskVisibility() const; + + // Other widgets event functions + void resetshowPressed(); + + // EditProvider management function + void setEditProvider(EditDataProvider* provider) override; + void subscribe(); + void unsubscribe(); + + // FoldableToolPanel event function + void enabledChanged() override; + + // Curve management function + void autoOpenCurve() override; + + // Locallab tools expanders management functions + void foldAllButOne(LocallabTool* except); + void openAllTools(); + + // Locallab tools advice tooltips management function + void updateShowtooltipVisibility(bool showtooltip); + +private: + // Locallab tools management functions + void addTool(Gtk::Box* where, LocallabTool* tool); + + // Locallab GUI management function + void setParamEditable(bool cond); + + // ControlSpotListener function + void resetToolMaskView() override; + + // LocallabToolListener function + void resetOtherMaskView(LocallabTool* current) override; + void toolRemoved(LocallabTool* current) override; + + // LocallabToolListListener function + void locallabToolToAdd(const Glib::ustring &toolname) override; +}; + +#endif diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc new file mode 100644 index 000000000..78dfacbbe --- /dev/null +++ b/rtgui/locallabtools.cc @@ -0,0 +1,6393 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath frame + * + * + * 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 . + * 2019 Pierre Cabrera + */ +#include "locallabtools.h" + +#include "options.h" +#include "../rtengine/procparams.h" +#include "locallab.h" +#include "thresholdadjuster.h" +#include "rtimage.h" +#include "../rtengine/color.h" + +#define MINRAD 1.5 +#define MAXRAD 10000 +#define CENTERRAD 100 +#define MINCHRO 0. +#define MAXCHRO 150. +#define MAXCHROCC 100. +#define MINEXP -1.5 +#define MAXEXP 1.5 + +using namespace rtengine; +using namespace procparams; + +extern Options options; +static double blurSlider2radius(double sval) +{ + // Slider range: 0 - 1000 + double radius; + + if (sval <= 100) { + // Linear below center-temp + radius = MINRAD + (sval / 100.0) * (CENTERRAD - MINRAD); + } else { + const double slope = (double)(CENTERRAD - MINRAD) / (MAXRAD - CENTERRAD); + double x = (sval - 100) / 100; // x range: 0 - 1 + double y = x * slope + (1.0 - slope) * pow(x, 4.0); + radius = CENTERRAD + y * (MAXRAD - CENTERRAD); + } + + if (radius < MINRAD) { + radius = MINRAD; + } + + if (radius > MAXRAD) { + radius = MAXRAD; + } + + return radius; +} + +static double blurRadius2Slider(double radius) +{ + double sval; + + if (radius <= CENTERRAD) { + sval = ((radius - MINRAD) / (CENTERRAD - MINRAD)) * 100.0; + } else { + const double slope = (double)(CENTERRAD - MINRAD) / (MAXRAD - CENTERRAD); + const double y = (radius - CENTERRAD) / (MAXRAD - CENTERRAD); + double x = pow(y, 0.25); // Rough guess of x, will be a little lower + double k = 0.1; + bool add = true; + + // The y=f(x) function is a mess to invert, therefore we have this trial-refinement loop instead. + // From tests, worst case is about 20 iterations, i.e. no problem + for (;;) { + double y1 = x * slope + (1.0 - slope) * pow(x, 4.0); + + if (100. * fabs(y1 - y) < 0.1) { + break; + } + + if (y1 < y) { + if (!add) { + k /= 2; + } + + x += k; + add = true; + } else { + if (add) { + k /= 2; + } + + x -= k; + add = false; + } + } + + sval = 100.0 + x * 100.0; + } + + if (sval < 0.) { + sval = 0.; + } + + if (sval > 10000.) { + sval = 10000.; + } + + return sval; +} + +/* ==== LocallabTool ==== */ +LocallabTool::LocallabTool(Gtk::Box* content, Glib::ustring toolName, Glib::ustring UILabel, bool need11, bool needMode): + ToolPanel(toolName, need11), + + // LocallabTool parameters + needMode(needMode), + isLocActivated(false), + locToolListener(nullptr), + + // LocallabTool generic widgets + complexity(Gtk::manage(new MyComboBoxText())) +{ + // Create expander title bar + Gtk::HBox* const titleBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const titleLabel = Gtk::manage(new Gtk::Label()); + titleLabel->set_markup(Glib::ustring("") + escapeHtmlChars(UILabel) + Glib::ustring("")); + titleLabel->set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + titleBox->pack_start(*titleLabel, Gtk::PACK_EXPAND_WIDGET, 0); + + Gtk::EventBox* const removeEvBox = Gtk::manage(new Gtk::EventBox()); // Glue to manage mouse clicking event on remove image + removeEvBox->set_can_focus(false); + removeEvBox->set_above_child(false); // To have priority over expander title bar when mouse clicking on remove image + removeEvBox->signal_button_release_event().connect(sigc::mem_fun(this, &LocallabTool::on_remove_change)); + RTImage* const removeImage = Gtk::manage(new RTImage("cancel-small.png")); + removeEvBox->add(*removeImage); + titleBox->pack_end(*removeEvBox, Gtk::PACK_SHRINK, 4); + + if (needMode) { + complexity->append(M("TP_LOCALLAB_MODE_EXPERT")); + complexity->append(M("TP_LOCALLAB_MODE_NORMAL")); + complexity->set_active(0); + complexity->setPreferredWidth(100, -1); + complexityConn = complexity->signal_changed().connect(sigc::mem_fun(*this, &LocallabTool::complexityModeChanged)); + titleBox->pack_end(*complexity, Gtk::PACK_SHRINK, 2); + } + + Gtk::VSeparator* const separator = Gtk::manage(new Gtk::VSeparator()); + titleBox->pack_end(*separator, Gtk::PACK_SHRINK, 0); + + if (need100Percent) { + RTImage* const titleImage = Gtk::manage(new RTImage("one-to-one-small.png")); + titleImage->set_tooltip_text(M("TP_GENERAL_11SCALE_TOOLTIP")); + titleBox->pack_end(*titleImage, Gtk::PACK_SHRINK, 0); + } + + exp = Gtk::manage(new MyExpander(true, titleBox)); + exp->signal_button_release_event().connect_notify(sigc::mem_fun(this, &LocallabTool::foldThemAll)); + enaExpConn = exp->signal_enabled_toggled().connect(sigc::mem_fun(*this, &LocallabTool::enabledChanged)); + + ToolParamBlock* const totalBox = Gtk::manage(new ToolParamBlock()); + + // Create panel for specific widget tools + totalBox->pack_start(*content, Gtk::PACK_SHRINK, 0); + exp->add(*totalBox, false); +} + +LocallabTool::~LocallabTool() +{ + idle_register.destroy(); +} + +void LocallabTool::addLocallabTool(bool raiseEvent) +{ + exp->set_visible(true); + + // Raise event if required + if (raiseEvent) { // Note: Event is only raised when a tool is added by user + // By default, activate newly added tool + enaExpConn.block(true); + exp->setEnabled(true); + enaExpConn.block(false); + + if (needMode) { + // Set complexity mode according to chosen default one + complexityConn.block(true); + complexity->set_active(options.complexity); + complexityConn.block(false); + + // Update GUI accordingly + if (complexity->get_active_row_number() == Normal) { + convertParamToNormal(); + updateGUIToMode(Normal); + } else { + updateGUIToMode(Expert); + } + } + + if (listener) { + listener->panelChanged(EvlocallabToolAdded, + toolName + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabTool::removeLocallabTool(bool raiseEvent) +{ + exp->set_visible(false); + + // Inform LocallabToolListener to update Locallab tools list + if (locToolListener) { + locToolListener->toolRemoved(this); + } + + if (exp->getEnabled() || isMaskViewActive()) { + // Disable tool while removing it + disableListener(); + exp->setEnabled(false); + enableListener(); + // Note: Mask views are all reset when removing tool (in toolpanelcoord.cc) + + // Raise event if required refreshing image + if (raiseEvent && listener) { + listener->panelChanged(EvlocallabToolRemovedWithRefresh, + toolName + " (" + escapeHtmlChars(spotName) + ")"); + } + } else { + // Raise event if required without refreshing image + if (raiseEvent && listener) { + listener->panelChanged(EvlocallabToolRemovedWithoutRefresh, + toolName + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +bool LocallabTool::isLocallabToolAdded() +{ + return exp->get_visible(); +} + +void LocallabTool::refChanged(const double huer, const double lumar, const double chromar) +{ + // Hue reference normalization (between 0 and 1) + double normHuer = huer; + float h = Color::huelab_to_huehsv2(normHuer); + h += 1.f / 6.f; + + if (h > 1.f) { + h -= 1.f; + } + + normHuer = h; + + // Luma reference normalization (between 0 and 1) + const double normLumar = lumar / 100.f; + + // Chroma reference normalization (between 0 and 1) + const double normChromar = chromar / 137.4f; + + // Update mask curve backgrounds + updateMaskBackground(normChromar, normLumar, normHuer); +} + +void LocallabTool::colorForValue(double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) +{ + float R = 0.f; + float G = 0.f; + float B = 0.f; + float x; + + if (elemType == ColorCaller::CCET_VERTICAL_BAR) { + valY = 0.5; + } + + switch (callerId) { + case 1: // Mask CC shape (bottom bar) + Color CC/LC shape (left bar) + Color::hsv2rgb01(float(valY), float(valX), 0.5f, R, G, B); + + break; + + case 2: // Mask HH shape (main curve and bottom bar) + x = valX - 1.f / 6.f; + + if (x < 0.f) { + x += 1.f; + } + + x = log2lin(x, 3.f); + Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); + + break; + + case 3: // Color LH/HH shape (main curve) + Color::hsv2rgb01(float (valX), float (valY), 0.5f, R, G, B); + + break; + + case 4: // Color CC/LC shape (bottom bar) + const float value = (1.f - 0.7f) * float (valX) + 0.7f; + // Whole hue range + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(float (valY), float (valX), value, R, G, B); + } + + caller->ccRed = double (R); + caller->ccGreen = double (G); + caller->ccBlue = double (B); +} + +void LocallabTool::disableListener() +{ + ToolPanel::disableListener(); + + enaExpConn.block(true); + + if (needMode) { + complexityConn.block(true); + } +} +void LocallabTool::enableListener() +{ + ToolPanel::enableListener(); + + enaExpConn.block(false); + + if (needMode) { + complexityConn.block(false); + } +} + +bool LocallabTool::on_remove_change(GdkEventButton* event) +{ + if (event->button == GDK_BUTTON_PRIMARY) { + // Remove Locallab tool raising an event + removeLocallabTool(true); + } + + return true; // No event propagation further (to avoid closing expander when mouse clicking on remove image) +} + +void LocallabTool::foldThemAll(GdkEventButton* event) +{ + if (event->button == GDK_BUTTON_SECONDARY) { + if (locToolListener) { + (static_cast(locToolListener))->foldAllButOne(this); + } + } +} + +void LocallabTool::complexityModeChanged() +{ + if (complexity->get_active_row_number() == Normal) { // New selected mode is Normal one + // Convert tool widget parameters + convertParamToNormal(); + + // Update GUI based on new mode + updateGUIToMode(Normal); + + // Raise event with refreshing + if (listener) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_NORMAL") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else { // New selected mode is Expert one + // Update GUI based on new mode + updateGUIToMode(Expert); + + // Raise event without refreshing + if (listener) { + listener->panelChanged(EvlocallabcomplexityWithoutRefresh, + M("TP_LOCALLAB_MODE_EXPERT") + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +/* ==== LocallabColor ==== */ +LocallabColor::LocallabColor(): + LocallabTool(this, M("TP_LOCALLAB_COLOR_TOOLNAME"), M("TP_LOCALLAB_COFR"), false), + + // Color & Light specific widgets + curvactiv(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_CURV")))), + lightness(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LIGHTNESS"), -100, 500, 1, 0))), + contrast(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CONTRAST"), -100, 100, 1, 0))), + chroma(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMA"), -100, 150, 1, 0))), + gridFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABGRID")))), + labgrid(Gtk::manage(new LabGrid(EvLocallabLabGridValue, M("TP_LOCALLAB_LABGRID_VALUES")))), + gridMethod(Gtk::manage(new MyComboBoxText())), + strengthgrid(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRGRID"), 0, 100, 1, 30))), + sensi(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 15))), + structcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUCCOL1"), 0, 100, 1, 0))), + blurcolde(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURDE"), 2, 100, 1, 5))), + softradiuscol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 1000.0, 0.5, 0.))), + invers(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVERS")))), + expgradcol(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPGRAD")))), + strcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTRLUM"), -4., 4., 0.05, 0.))), + strcolab(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTRCHRO"), -6., 6., 0.05, 0.))), + strcolh(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTRHUE"), -6., 6., 0.05, 0.))), + angcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180, 180, 0.1, 0.))), + expcurvcol(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPCURV")))), + labqualcurv(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_QUALCURV_METHOD") + ":"))), + qualitycurveMethod(Gtk::manage(new MyComboBoxText())), + llCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_LUM"))), + llshape(static_cast(llCurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + ccshape(static_cast(llCurveEditorG->addCurve(CT_Diagonal, "C(C)"))), + clCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_CH"))), + clshape(static_cast(clCurveEditorG->addCurve(CT_Diagonal, "C(L)"))), + lcshape(static_cast(clCurveEditorG->addCurve(CT_Diagonal, "L(C)"))), + HCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_HLH"))), + LHshape(static_cast(HCurveEditorG->addCurve(CT_Flat, "L(H)", nullptr, false, true))), + H2CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_HLH"))), + HHshape(static_cast(H2CurveEditorG->addCurve(CT_Flat, "H(H)", nullptr, false, true))), + rgbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_RGB"))), + toneMethod(Gtk::manage(new MyComboBoxText())), + rgbshape(static_cast(rgbCurveEditorG->addCurve(CT_Diagonal, "", toneMethod))), + special(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_SPECIAL")))), + expmaskcol1(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWC1")))), + merMethod(Gtk::manage(new MyComboBoxText())), + mask7(Gtk::manage(new ToolParamBlock())), + mergecolMethod(Gtk::manage(new MyComboBoxText())), + mercol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MERDCOL"), 0.0, 100.0, 0.5, 18.))), + opacol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_OPACOL"), 0.0, 100.0, 0.5, 60.))), + conthrcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CONTTHR"), 0.0, 100.0, 0.5, 0.))), + gridmerFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABGRIDMERG")))), + labgridmerg(Gtk::manage(new LabGrid(EvLocallabLabGridmergValue, M("TP_LOCALLAB_LABGRID_VALUES"), false))), + merlucol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MERLUCOL"), 0.0, 100.0, 0.5, 32., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + expmaskcol(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWC")))), + showmaskcolMethod(Gtk::manage(new MyComboBoxText())), + showmaskcolMethodinv(Gtk::manage(new MyComboBoxText())), + enaColorMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + maskCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), + CCmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + struFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABSTRUM")))), + strumaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUMASKCOL"), 0., 200., 0.1, 0.))), + toolcol(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TOOLCOL")))), + blurFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABBLURM")))), + fftColorMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FFTCOL_MASK")))), + contcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CONTCOL"), 0., 200., 0.5, 0.))), + blurcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURCOL"), 0.2, 100., 0.5, 0.2))), + blendmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + lapmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), + slomaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + shadmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHAMASKCOL"), 0, 100, 1, 0))), + maskHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKH"))), + HHhmaskshape(static_cast(maskHCurveEditorG->addCurve(CT_Flat, "H(H)", nullptr, false, true))), + mask2CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmaskshape(static_cast(mask2CurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + mask2CurveEditorGwav(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVMASK"))), + LLmaskcolshapewav(static_cast(mask2CurveEditorGwav->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + csThresholdcol(Gtk::manage(new ThresholdAdjuster(M("TP_LOCALLAB_CSTHRESHOLDBLUR"), 0, 9, 0, 0, 6, 5, 0, false))) +{ + float R, G, B; + + std::vector six_shape; + + for (int i = 0; i < 6; i++) { + const float x = static_cast(i) * (1.f / 6.f); + Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); + six_shape.emplace_back(x, R, G, B); + } + + const LocallabParams::LocallabSpot defSpot; + + // Parameter Color & Light specific widgets + curvactivConn = curvactiv->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::curvactivChanged)); + + lightness->setAdjusterListener(this); + + contrast->setAdjusterListener(this); + + chroma->setAdjusterListener(this); + + gridFrame->set_label_align(0.025, 0.5); + + gridMethod->append(M("TP_LOCALLAB_GRIDONE")); + gridMethod->append(M("TP_LOCALLAB_GRIDTWO")); + gridMethod->set_active(0); + gridMethodConn = gridMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::gridMethodChanged)); + + strengthgrid->setAdjusterListener(this); + + sensi->setAdjusterListener(this); + + structcol->setAdjusterListener(this); + + blurcolde->setAdjusterListener(this); + + softradiuscol->setLogScale(10, 0); + softradiuscol->setAdjusterListener(this); + + inversConn = invers->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::inversChanged)); + invers->set_tooltip_text(M("TP_LOCALLAB_INVERS_TOOLTIP")); + + setExpandAlignProperties(expgradcol, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + strcol->setAdjusterListener(this); + + strcolab->setAdjusterListener(this); + strcolab->set_tooltip_text(M("TP_LOCALLAB_GRADSTRAB_TOOLTIP")); + + strcolh->setAdjusterListener(this); + strcolh->set_tooltip_text(M("TP_LOCALLAB_GRADSTRHUE_TOOLTIP")); + + angcol->setAdjusterListener(this); + + setExpandAlignProperties(expcurvcol, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + qualitycurveMethod->append(M("TP_LOCALLAB_CURVNONE")); + qualitycurveMethod->append(M("TP_LOCALLAB_CURVCURR")); + qualitycurveMethod->set_active(0); + qualitycurveMethodConn = qualitycurveMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::qualitycurveMethodChanged)); + + llCurveEditorG->setCurveListener(this); + + llshape->setResetCurve(DiagonalCurveType(defSpot.llcurve.at(0)), defSpot.llcurve); + llshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + llshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + llshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + ccshape->setResetCurve(DiagonalCurveType(defSpot.cccurve.at(0)), defSpot.cccurve); + ccshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + ccshape->setBottomBarColorProvider(this, 4); + ccshape->setLeftBarColorProvider(this, 1); + + llCurveEditorG->curveListComplete(); + + clCurveEditorG->setCurveListener(this); + + clshape->setResetCurve(DiagonalCurveType(defSpot.clcurve.at(0)), defSpot.clcurve); + clshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + clshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + clshape->setLeftBarColorProvider(this, 1); + + lcshape->setResetCurve(DiagonalCurveType(defSpot.lccurve.at(0)), defSpot.lccurve); + lcshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + lcshape->setBottomBarColorProvider(this, 4); + lcshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + clCurveEditorG->curveListComplete(); + + HCurveEditorG->setCurveListener(this); + + LHshape->setIdentityValue(0.); + LHshape->setResetCurve(FlatCurveType(defSpot.LHcurve.at(0)), defSpot.LHcurve); + LHshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + LHshape->setCurveColorProvider(this, 3); + LHshape->setBottomBarBgGradient(six_shape); + + HCurveEditorG->curveListComplete(); + + H2CurveEditorG->setCurveListener(this); + + HHshape->setIdentityValue(0.); + HHshape->setResetCurve(FlatCurveType(defSpot.HHcurve.at(0)), defSpot.HHcurve); + HHshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + HHshape->setCurveColorProvider(this, 3); + HHshape->setBottomBarBgGradient(six_shape); + + H2CurveEditorG->curveListComplete(); + + rgbCurveEditorG->setCurveListener(this); + + toneMethod->append(M("TP_EXPOSURE_TCMODE_STANDARD")); + toneMethod->append(M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); + toneMethod->append(M("TP_EXPOSURE_TCMODE_LUMINANCE")); + toneMethod->append(M("TP_EXPOSURE_TCMODE_FILMLIKE")); + toneMethod->set_active(0); + toneMethodConn = toneMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::toneMethodChanged)); + + rgbshape->setResetCurve(DiagonalCurveType(defSpot.rgbcurve.at(0)), defSpot.rgbcurve); + rgbshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + rgbshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + rgbshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + rgbCurveEditorG->curveListComplete(); + + specialConn = special->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::specialChanged)); + + setExpandAlignProperties(expmaskcol1, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + merMethod->append(M("TP_LOCALLAB_MRONE")); +// merMethod->append(M("TP_LOCALLAB_MRTWO")); + merMethod->append(M("TP_LOCALLAB_MRTHR")); + merMethod->append(M("TP_LOCALLAB_MRFOU")); + merMethod->append(M("TP_LOCALLAB_MRFIV")); + merMethod->set_active(0); + merMethodConn = merMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::merMethodChanged)); + + mergecolMethod->append(M("TP_LOCALLAB_MERONE")); + mergecolMethod->append(M("TP_LOCALLAB_MERTWO")); + mergecolMethod->append(M("TP_LOCALLAB_MERTHR")); + mergecolMethod->append(M("TP_LOCALLAB_MERFOU")); + mergecolMethod->append(M("TP_LOCALLAB_MERFIV")); + mergecolMethod->append(M("TP_LOCALLAB_MERSIX")); + mergecolMethod->append(M("TP_LOCALLAB_MERSEV")); + mergecolMethod->append(M("TP_LOCALLAB_MERSEV0")); + mergecolMethod->append(M("TP_LOCALLAB_MERSEV1")); + mergecolMethod->append(M("TP_LOCALLAB_MERSEV2")); + mergecolMethod->append(M("TP_LOCALLAB_MERHEI")); + mergecolMethod->append(M("TP_LOCALLAB_MERNIN")); + mergecolMethod->append(M("TP_LOCALLAB_MERTEN")); + mergecolMethod->append(M("TP_LOCALLAB_MERELE")); + mergecolMethod->append(M("TP_LOCALLAB_MERTWE")); + mergecolMethod->append(M("TP_LOCALLAB_MERTHI")); + mergecolMethod->append(M("TP_LOCALLAB_MERFOR")); + mergecolMethod->append(M("TP_LOCALLAB_MERHUE")); + mergecolMethod->append(M("TP_LOCALLAB_MERSAT")); + mergecolMethod->append(M("TP_LOCALLAB_MERCOL")); + mergecolMethod->append(M("TP_LOCALLAB_MERLUM")); + mergecolMethod->set_active(0); + mergecolMethodConn = mergecolMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::mergecolMethodChanged)); + + mercol->setAdjusterListener(this); + + opacol->setAdjusterListener(this); + + conthrcol->setAdjusterListener(this); + + merlucol->setAdjusterListener(this); + + setExpandAlignProperties(expmaskcol, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskcolMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskcolMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskcolMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskcolMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskcolMethod->append(M("TP_LOCALLAB_SHOWSTRUC")); + showmaskcolMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskcolMethod->set_active(0); + showmaskcolMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskcolMethodConn = showmaskcolMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::showmaskcolMethodChanged)); + + showmaskcolMethodinv->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskcolMethodinv->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskcolMethodinv->set_active(0); + showmaskcolMethodinv->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskcolMethodConninv = showmaskcolMethodinv->signal_changed().connect(sigc::mem_fun(*this, &LocallabColor::showmaskcolMethodChangedinv)); + + enaColorMaskConn = enaColorMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::enaColorMaskChanged)); + + maskCurveEditorG->setCurveListener(this); + + CCmaskshape->setIdentityValue(0.); + CCmaskshape->setResetCurve(FlatCurveType(defSpot.CCmaskcurve.at(0)), defSpot.CCmaskcurve); + CCmaskshape->setBottomBarColorProvider(this, 1); + + LLmaskshape->setIdentityValue(0.); + LLmaskshape->setResetCurve(FlatCurveType(defSpot.LLmaskcurve.at(0)), defSpot.LLmaskcurve); + LLmaskshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskshape->setIdentityValue(0.); + HHmaskshape->setResetCurve(FlatCurveType(defSpot.HHmaskcurve.at(0)), defSpot.HHmaskcurve); + HHmaskshape->setCurveColorProvider(this, 2); + HHmaskshape->setBottomBarColorProvider(this, 2); + + maskCurveEditorG->curveListComplete(); + + struFrame->set_label_align(0.025, 0.5); + + strumaskcol->setAdjusterListener(this); + + toolcolConn = toolcol->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::toolcolChanged)); + + blurFrame->set_label_align(0.025, 0.5); + + fftColorMaskConn = fftColorMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::fftColorMaskChanged)); + + contcol->setAdjusterListener(this); + + blurcol->setAdjusterListener(this); + + blendmaskcol->setAdjusterListener(this); + + radmaskcol->setLogScale(10, -10); + radmaskcol->setAdjusterListener(this); + + lapmaskcol->setAdjusterListener(this); + + chromaskcol->setAdjusterListener(this); + + gammaskcol->setAdjusterListener(this); + + slomaskcol->setAdjusterListener(this); + + shadmaskcol->setAdjusterListener(this); + + maskHCurveEditorG->setCurveListener(this); + + HHhmaskshape->setIdentityValue(0.); + HHhmaskshape->setResetCurve(FlatCurveType(defSpot.HHhmaskcurve.at(0)), defSpot.HHhmaskcurve); +// HHhmaskshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + HHhmaskshape->setCurveColorProvider(this, 2); + HHhmaskshape->setBottomBarColorProvider(this, 2); + + maskHCurveEditorG->curveListComplete(); + + mask2CurveEditorG->setCurveListener(this); + + Lmaskshape->setResetCurve(DiagonalCurveType(defSpot.Lmaskcurve.at(0)), defSpot.Lmaskcurve); + Lmaskshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmaskshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2CurveEditorG->curveListComplete(); + + mask2CurveEditorGwav->setCurveListener(this); + + LLmaskcolshapewav->setIdentityValue(0.); + LLmaskcolshapewav->setResetCurve(FlatCurveType(defSpot.LLmaskcolcurvewav.at(0)), defSpot.LLmaskcolcurvewav); + LLmaskcolshapewav->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2CurveEditorGwav->curveListComplete(); + + csThresholdcol->setAdjusterListener(this); + + // Add Color & Light specific widgets to GUI + Gtk::Frame* const superFrame = Gtk::manage(new Gtk::Frame()); + superFrame->set_label_align(0.025, 0.5); + // superFrame->set_label_widget(*curvactiv); + ToolParamBlock* const superBox = Gtk::manage(new ToolParamBlock()); + superBox->pack_start(*lightness); + superBox->pack_start(*contrast); + superBox->pack_start(*chroma); + ToolParamBlock* const gridBox = Gtk::manage(new ToolParamBlock()); + gridBox->pack_start(*labgrid); + gridBox->pack_start(*gridMethod); + gridBox->pack_start(*strengthgrid); + gridFrame->add(*gridBox); + superBox->pack_start(*gridFrame); + superFrame->add(*superBox); + pack_start(*superFrame); +// pack_start(*sensi); + pack_start(*structcol); + pack_start(*blurcolde); + pack_start(*softradiuscol); + pack_start(*invers); + ToolParamBlock* const gradcolBox = Gtk::manage(new ToolParamBlock()); + gradcolBox->pack_start(*strcol); + gradcolBox->pack_start(*strcolab); + gradcolBox->pack_start(*strcolh); + gradcolBox->pack_start(*angcol); + expgradcol->add(*gradcolBox, false); + pack_start(*expgradcol, false, false); + ToolParamBlock* const curvBox = Gtk::manage(new ToolParamBlock()); + Gtk::HBox* const qualcurvbox = Gtk::manage(new Gtk::HBox()); + qualcurvbox->pack_start(*labqualcurv, Gtk::PACK_SHRINK, 4); + qualcurvbox->pack_start(*qualitycurveMethod); + curvBox->pack_start(*qualcurvbox); + curvBox->pack_start(*llCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + curvBox->pack_start(*clCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + curvBox->pack_start(*HCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + curvBox->pack_start(*H2CurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + curvBox->pack_start(*rgbCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + curvBox->pack_start(*special); + expcurvcol->add(*curvBox, false); + pack_start(*expcurvcol, false, false); + ToolParamBlock* const mask7Box = Gtk::manage(new ToolParamBlock()); + mask7Box->pack_start(*merMethod); + Gtk::Frame* const merge1colFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_MERGE1COLFRA"))); + merge1colFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const mergecolBox = Gtk::manage(new ToolParamBlock()); + Gtk::HSeparator* const separatormer = Gtk::manage(new Gtk::HSeparator()); + mergecolBox->pack_start(*separatormer, Gtk::PACK_SHRINK, 2); + mergecolBox->pack_start(*mergecolMethod); + mergecolBox->pack_start(*mercol); + mergecolBox->pack_start(*opacol); + mergecolBox->pack_start(*conthrcol); + ToolParamBlock* const gridmerBox = Gtk::manage(new ToolParamBlock()); + gridmerFrame->set_label_align(0.025, 0.5); + gridmerBox->pack_start(*labgridmerg); + gridmerBox->pack_start(*merlucol); + gridmerFrame->add(*gridmerBox); + mergecolBox->pack_start(*gridmerFrame); + merge1colFrame->add(*mergecolBox); + mask7->pack_start(*merge1colFrame); + mask7Box->pack_start(*mask7); + expmaskcol1->add(*mask7Box, false); + pack_start(*expmaskcol1, false, false); + Gtk::Frame* const mergecolFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_MERGECOLFRA"))); + mergecolFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const maskcolBox = Gtk::manage(new ToolParamBlock()); + maskcolBox->pack_start(*showmaskcolMethod, Gtk::PACK_SHRINK, 4); + maskcolBox->pack_start(*showmaskcolMethodinv, Gtk::PACK_SHRINK, 4); + maskcolBox->pack_start(*enaColorMask, Gtk::PACK_SHRINK, 0); + maskcolBox->pack_start(*maskCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + ToolParamBlock* const strumBox = Gtk::manage(new ToolParamBlock()); + strumBox->pack_start(*strumaskcol); + strumBox->pack_start(*toolcol); + struFrame->add(*strumBox); + maskcolBox->pack_start(*struFrame, Gtk::PACK_SHRINK, 0); + ToolParamBlock* const blurmBox = Gtk::manage(new ToolParamBlock()); + blurmBox->pack_start(*fftColorMask, Gtk::PACK_SHRINK, 0); + blurmBox->pack_start(*contcol); + blurmBox->pack_start(*blurcol); + blurFrame->add(*blurmBox); + maskcolBox->pack_start(*blurFrame, Gtk::PACK_SHRINK, 0); + maskcolBox->pack_start(*blendmaskcol, Gtk::PACK_SHRINK, 0); + Gtk::Frame* const toolcolFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK"))); + toolcolFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const toolcolBox = Gtk::manage(new ToolParamBlock()); + toolcolBox->pack_start(*radmaskcol, Gtk::PACK_SHRINK, 0); + toolcolBox->pack_start(*lapmaskcol, Gtk::PACK_SHRINK, 0); + toolcolBox->pack_start(*chromaskcol, Gtk::PACK_SHRINK, 0); + toolcolBox->pack_start(*gammaskcol, Gtk::PACK_SHRINK, 0); + toolcolBox->pack_start(*slomaskcol, Gtk::PACK_SHRINK, 0); + toolcolBox->pack_start(*shadmaskcol, Gtk::PACK_SHRINK, 0); + toolcolBox->pack_start(*maskHCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolcolBox->pack_start(*mask2CurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolcolBox->pack_start(*mask2CurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolcolBox->pack_start(*csThresholdcol, Gtk::PACK_SHRINK, 0); + toolcolFrame->add(*toolcolBox); + maskcolBox->pack_start(*toolcolFrame); + mergecolFrame->add(*maskcolBox); + expmaskcol->add(*mergecolFrame, false); + pack_start(*expmaskcol, false, false); +} + +LocallabColor::~LocallabColor() +{ + delete llCurveEditorG; + delete clCurveEditorG; + delete HCurveEditorG; + delete H2CurveEditorG; + delete rgbCurveEditorG; + delete maskCurveEditorG; + delete maskHCurveEditorG; + delete mask2CurveEditorG; + delete mask2CurveEditorGwav; +} + +void LocallabColor::setListener(ToolPanelListener* tpl) +{ + LocallabTool::setListener(tpl); + + labgrid->setListener(tpl); + labgridmerg->setListener(tpl); +} + +bool LocallabColor::isMaskViewActive() +{ + return ((showmaskcolMethod->get_active_row_number() != 0) || (showmaskcolMethodinv->get_active_row_number() != 0)); +} + +void LocallabColor::resetMaskView() +{ + showmaskcolMethodConn.block(true); + showmaskcolMethodConninv.block(true); + + showmaskcolMethod->set_active(0); + showmaskcolMethodinv->set_active(0); + + showmaskcolMethodConn.block(false); + showmaskcolMethodConninv.block(false); +} + +void LocallabColor::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + colorMask = showmaskcolMethod->get_active_row_number(); + colorMaskinv = showmaskcolMethodinv->get_active_row_number(); +} + +void LocallabColor::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_EXPCOLOR_TOOLTIP")); + lightness->set_tooltip_text(M("TP_LOCALLAB_LIGHTN_TOOLTIP")); + structcol->set_tooltip_text(M("TP_LOCALLAB_STRUCT_TOOLTIP")); + sensi->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + strcol->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + angcol->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + qualitycurveMethod->set_tooltip_markup(M("TP_LOCALLAB_CURVEMETHOD_TOOLTIP")); + mercol->set_tooltip_text(M("TP_LOCALLAB_MERGEMER_TOOLTIP")); + opacol->set_tooltip_text(M("TP_LOCALLAB_MERGEOPA_TOOLTIP")); + conthrcol->set_tooltip_text(M("TP_LOCALLAB_MERGEOPA_TOOLTIP")); + gridmerFrame->set_tooltip_text(M("TP_LOCALLAB_GRIDFRAME_TOOLTIP")); + expmaskcol->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + radmaskcol->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskcol->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + Lmaskshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + LLmaskcolshapewav->setTooltip(M("TP_LOCALLAB_LMASK_LEVEL_TOOLTIP")); + expmaskcol1->set_tooltip_text(M("TP_LOCALLAB_EXPMERGEFILE_TOOLTIP")); + blendmaskcol->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + struFrame->set_tooltip_text(M("TP_LOCALLAB_STRUMASK_TOOLTIP")); + blurFrame->set_tooltip_text(M("TP_LOCALLAB_BLURMASK_TOOLTIP")); + maskHCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_HHMASK_TOOLTIP")); + mask2CurveEditorGwav->set_tooltip_text(M("TP_LOCALLAB_WAVMASK_TOOLTIP")); + mask2CurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + special->set_tooltip_text(M("TP_LOCALLAB_SPECIAL_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + lightness->set_tooltip_text(""); + structcol->set_tooltip_text(""); + sensi->set_tooltip_text(""); + angcol->set_tooltip_text(M("")); + strcol->set_tooltip_text(""); + qualitycurveMethod->set_tooltip_text(""); + mercol->set_tooltip_text(""); + opacol->set_tooltip_text(""); + conthrcol->set_tooltip_text(""); + gridmerFrame->set_tooltip_text(""); + expmaskcol->set_tooltip_text(""); + CCmaskshape->setTooltip(""); + LLmaskshape->setTooltip(""); + HHmaskshape->setTooltip(""); + radmaskcol->set_tooltip_text(""); + lapmaskcol->set_tooltip_text(""); + Lmaskshape->setTooltip(""); + LLmaskcolshapewav->setTooltip(""); + expmaskcol1->set_tooltip_text(M("")); + blendmaskcol->set_tooltip_text(M("")); + struFrame->set_tooltip_text(M("")); + blurFrame->set_tooltip_text(M("")); + maskHCurveEditorG->set_tooltip_text(M("")); + mask2CurveEditorGwav->set_tooltip_text(M("")); + mask2CurveEditorG->set_tooltip_text(M("")); + special->set_tooltip_text(M("")); + } +} + +void LocallabColor::setDefaultExpanderVisibility() +{ + expgradcol->set_expanded(false); + expcurvcol->set_expanded(false); + expmaskcol1->set_expanded(false); + expmaskcol->set_expanded(false); +} + +void LocallabColor::disableListener() +{ + LocallabTool::disableListener(); + + curvactivConn.block(true); + gridMethodConn.block(true); + inversConn.block(true); + qualitycurveMethodConn.block(true); + toneMethodConn.block(true); + specialConn.block(true); + merMethodConn.block(true); + mergecolMethodConn.block(true); + showmaskcolMethodConn.block(true); + showmaskcolMethodConninv.block(true); + enaColorMaskConn.block(true); + toolcolConn.block(true); + fftColorMaskConn.block(true); +} + +void LocallabColor::enableListener() +{ + LocallabTool::enableListener(); + + curvactivConn.block(false); + gridMethodConn.block(false); + inversConn.block(false); + qualitycurveMethodConn.block(false); + toneMethodConn.block(false); + specialConn.block(false); + merMethodConn.block(false); + mergecolMethodConn.block(false); + showmaskcolMethodConn.block(false); + showmaskcolMethodConninv.block(false); + enaColorMaskConn.block(false); + toolcolConn.block(false); + fftColorMaskConn.block(false); +} + +void LocallabColor::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visicolor); + exp->setEnabled(spot.expcolor); + complexity->set_active(spot.complexcolor); + + curvactiv->set_active(spot.curvactiv); + lightness->setValue(spot.lightness); + contrast->setValue(spot.contrast); + chroma->setValue(spot.chroma); + labgrid->setParams(spot.labgridALow / LocallabParams::LABGRIDL_CORR_MAX, + spot.labgridBLow / LocallabParams::LABGRIDL_CORR_MAX, + spot.labgridAHigh / LocallabParams::LABGRIDL_CORR_MAX, + spot.labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX, + false); + + if (spot.gridMethod == "one") { + gridMethod->set_active(0); + } else if (spot.gridMethod == "two") { + gridMethod->set_active(1); + } + + strengthgrid->setValue(spot.strengthgrid); + sensi->setValue(spot.sensi); + structcol->setValue(spot.structcol); + blurcolde->setValue(spot.blurcolde); + softradiuscol->setValue(spot.softradiuscol); + invers->set_active(spot.invers); + strcol->setValue(spot.strcol); + strcolab->setValue(spot.strcolab); + strcolh->setValue(spot.strcolh); + angcol->setValue(spot.angcol); + + if (spot.qualitycurveMethod == "none") { + qualitycurveMethod->set_active(0); + } else if (spot.qualitycurveMethod == "std") { + qualitycurveMethod->set_active(1); + } + + llshape->setCurve(spot.llcurve); + ccshape->setCurve(spot.cccurve); + clshape->setCurve(spot.clcurve); + lcshape->setCurve(spot.lccurve); + LHshape->setCurve(spot.LHcurve); + HHshape->setCurve(spot.HHcurve); + + if (spot.toneMethod == "one") { + toneMethod->set_active(0); + } else if (spot.toneMethod == "two") { + toneMethod->set_active(1); + } else if (spot.toneMethod == "thr") { + toneMethod->set_active(2); + } else if (spot.toneMethod == "fou") { + toneMethod->set_active(3); + } + + rgbshape->setCurve(spot.rgbcurve); + special->set_active(spot.special); + + if (spot.merMethod == "mone") { + merMethod->set_active(0); +// } else if (spot.merMethod == "mtwo") { +// merMethod->set_active(1); + } else if (spot.merMethod == "mthr") { + merMethod->set_active(1); + } else if (spot.merMethod == "mfou") { + merMethod->set_active(2); + } else if (spot.merMethod == "mfiv") { + merMethod->set_active(3); + } + + if (spot.mergecolMethod == "one") { + mergecolMethod->set_active(0); + } else if (spot.mergecolMethod == "two") { + mergecolMethod->set_active(1); + } else if (spot.mergecolMethod == "thr") { + mergecolMethod->set_active(2); + } else if (spot.mergecolMethod == "fou") { + mergecolMethod->set_active(3); + } else if (spot.mergecolMethod == "fiv") { + mergecolMethod->set_active(4); + } else if (spot.mergecolMethod == "six") { + mergecolMethod->set_active(5); + } else if (spot.mergecolMethod == "sev") { + mergecolMethod->set_active(6); + } else if (spot.mergecolMethod == "sev0") { + mergecolMethod->set_active(7); + } else if (spot.mergecolMethod == "sev1") { + mergecolMethod->set_active(8); + } else if (spot.mergecolMethod == "sev2") { + mergecolMethod->set_active(9); + } else if (spot.mergecolMethod == "hei") { + mergecolMethod->set_active(10); + } else if (spot.mergecolMethod == "nin") { + mergecolMethod->set_active(11); + } else if (spot.mergecolMethod == "ten") { + mergecolMethod->set_active(12); + } else if (spot.mergecolMethod == "ele") { + mergecolMethod->set_active(13); + } else if (spot.mergecolMethod == "twe") { + mergecolMethod->set_active(14); + } else if (spot.mergecolMethod == "thi") { + mergecolMethod->set_active(15); + } else if (spot.mergecolMethod == "for") { + mergecolMethod->set_active(16); + } else if (spot.mergecolMethod == "hue") { + mergecolMethod->set_active(17); + } else if (spot.mergecolMethod == "sat") { + mergecolMethod->set_active(18); + } else if (spot.mergecolMethod == "col") { + mergecolMethod->set_active(19); + } else if (spot.mergecolMethod == "lum") { + mergecolMethod->set_active(20); + } + + mercol->setValue(spot.mercol); + opacol->setValue(spot.opacol); + conthrcol->setValue(spot.conthrcol); + labgridmerg->setParams(0, 0, + spot.labgridAHighmerg / LocallabParams::LABGRIDL_CORR_MAX, + spot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX, + false); + merlucol->setValue(spot.merlucol); + enaColorMask->set_active(spot.enaColorMask); + CCmaskshape->setCurve(spot.CCmaskcurve); + LLmaskshape->setCurve(spot.LLmaskcurve); + HHmaskshape->setCurve(spot.HHmaskcurve); + strumaskcol->setValue(spot.strumaskcol); + toolcol->set_active(spot.toolcol); + fftColorMask->set_active(spot.fftColorMask); + contcol->setValue(spot.contcol); + // Update GUI according to fftColorMash button state + // Note: Contrary to the others, shall be called before setting 'blurcol' value + updateColorGUI3(); + blurcol->setValue(spot.blurcol); + blendmaskcol->setValue(spot.blendmaskcol); + radmaskcol->setValue(spot.radmaskcol); + lapmaskcol->setValue(spot.lapmaskcol); + chromaskcol->setValue(spot.chromaskcol); + gammaskcol->setValue(spot.gammaskcol); + slomaskcol->setValue(spot.slomaskcol); + shadmaskcol->setValue(spot.shadmaskcol); + HHhmaskshape->setCurve(spot.HHhmaskcurve); + Lmaskshape->setCurve(spot.Lmaskcurve); + LLmaskcolshapewav->setCurve(spot.LLmaskcolcurvewav); + csThresholdcol->setValue(spot.csthresholdcol); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update GUI according to invers button state + updateColorGUI1(); + + // Update GUI according to merMethod combobox state + updateColorGUI2(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabColor::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expcolor = exp->getEnabled(); + spot.visicolor = exp->get_visible(); + spot.complexcolor = complexity->get_active_row_number(); + + spot.curvactiv = curvactiv->get_active(); + spot.lightness = lightness->getIntValue(); + spot.contrast = contrast->getIntValue(); + spot.chroma = chroma->getIntValue(); + labgrid->getParams(spot.labgridALow, + spot.labgridBLow, + spot.labgridAHigh, + spot.labgridBHigh); + spot.labgridALow *= LocallabParams::LABGRIDL_CORR_MAX; + spot.labgridAHigh *= LocallabParams::LABGRIDL_CORR_MAX; + spot.labgridBLow *= LocallabParams::LABGRIDL_CORR_MAX; + spot.labgridBHigh *= LocallabParams::LABGRIDL_CORR_MAX; + + if (gridMethod->get_active_row_number() == 0) { + spot.gridMethod = "one"; + } else if (gridMethod->get_active_row_number() == 1) { + spot.gridMethod = "two"; + } + + spot.strengthgrid = strengthgrid->getIntValue(); + spot.sensi = sensi->getIntValue(); + spot.structcol = structcol->getIntValue(); + spot.blurcolde = blurcolde->getIntValue(); + spot.softradiuscol = softradiuscol->getValue(); + spot.invers = invers->get_active(); + spot.strcol = strcol->getValue(); + spot.strcolab = strcolab->getValue(); + spot.strcolh = strcolh->getValue(); + spot.angcol = angcol->getValue(); + + if (qualitycurveMethod->get_active_row_number() == 0) { + spot.qualitycurveMethod = "none"; + } else if (qualitycurveMethod->get_active_row_number() == 1) { + spot.qualitycurveMethod = "std"; + } + + spot.llcurve = llshape->getCurve(); + spot.cccurve = ccshape->getCurve(); + spot.clcurve = clshape->getCurve(); + spot.lccurve = lcshape->getCurve(); + spot.LHcurve = LHshape->getCurve(); + spot.HHcurve = HHshape->getCurve(); + + if (toneMethod->get_active_row_number() == 0) { + spot.toneMethod = "one"; + } else if (toneMethod->get_active_row_number() == 1) { + spot.toneMethod = "two"; + } else if (toneMethod->get_active_row_number() == 2) { + spot.toneMethod = "thr"; + } else if (toneMethod->get_active_row_number() == 3) { + spot.toneMethod = "fou"; + } + + spot.rgbcurve = rgbshape->getCurve(); + spot.special = special->get_active(); + + if (merMethod->get_active_row_number() == 0) { + spot.merMethod = "mone"; +// } else if (merMethod->get_active_row_number() == 1) { +// spot.merMethod = "mtwo"; + } else if (merMethod->get_active_row_number() == 1) { + spot.merMethod = "mthr"; + } else if (merMethod->get_active_row_number() == 2) { + spot.merMethod = "mfou"; + } else if (merMethod->get_active_row_number() == 3) { + spot.merMethod = "mfiv"; + } + + if (mergecolMethod->get_active_row_number() == 0) { + spot.mergecolMethod = "one"; + } else if (mergecolMethod->get_active_row_number() == 1) { + spot.mergecolMethod = "two"; + } else if (mergecolMethod->get_active_row_number() == 2) { + spot.mergecolMethod = "thr"; + } else if (mergecolMethod->get_active_row_number() == 3) { + spot.mergecolMethod = "fou"; + } else if (mergecolMethod->get_active_row_number() == 4) { + spot.mergecolMethod = "fiv"; + } else if (mergecolMethod->get_active_row_number() == 5) { + spot.mergecolMethod = "six"; + } else if (mergecolMethod->get_active_row_number() == 6) { + spot.mergecolMethod = "sev"; + } else if (mergecolMethod->get_active_row_number() == 7) { + spot.mergecolMethod = "sev0"; + } else if (mergecolMethod->get_active_row_number() == 8) { + spot.mergecolMethod = "sev1"; + } else if (mergecolMethod->get_active_row_number() == 9) { + spot.mergecolMethod = "sev2"; + } else if (mergecolMethod->get_active_row_number() == 10) { + spot.mergecolMethod = "hei"; + } else if (mergecolMethod->get_active_row_number() == 11) { + spot.mergecolMethod = "nin"; + } else if (mergecolMethod->get_active_row_number() == 12) { + spot.mergecolMethod = "ten"; + } else if (mergecolMethod->get_active_row_number() == 13) { + spot.mergecolMethod = "ele"; + } else if (mergecolMethod->get_active_row_number() == 14) { + spot.mergecolMethod = "twe"; + } else if (mergecolMethod->get_active_row_number() == 15) { + spot.mergecolMethod = "thi"; + } else if (mergecolMethod->get_active_row_number() == 16) { + spot.mergecolMethod = "for"; + } else if (mergecolMethod->get_active_row_number() == 17) { + spot.mergecolMethod = "hue"; + } else if (mergecolMethod->get_active_row_number() == 18) { + spot.mergecolMethod = "sat"; + } else if (mergecolMethod->get_active_row_number() == 19) { + spot.mergecolMethod = "col"; + } else if (mergecolMethod->get_active_row_number() == 20) { + spot.mergecolMethod = "lum"; + } + + spot.mercol = mercol->getValue(); + spot.opacol = opacol->getValue(); + spot.conthrcol = conthrcol->getValue(); + labgridmerg->getParams(spot.labgridALowmerg, + spot.labgridBLowmerg, + spot.labgridAHighmerg, + spot.labgridBHighmerg); + spot.labgridALowmerg *= LocallabParams::LABGRIDL_CORR_MAX; + spot.labgridAHighmerg *= LocallabParams::LABGRIDL_CORR_MAX; + spot.labgridBLowmerg *= LocallabParams::LABGRIDL_CORR_MAX; + spot.labgridBHighmerg *= LocallabParams::LABGRIDL_CORR_MAX; + spot.merlucol = merlucol->getValue(); + spot.enaColorMask = enaColorMask->get_active(); + spot.CCmaskcurve = CCmaskshape->getCurve(); + spot.LLmaskcurve = LLmaskshape->getCurve(); + spot.HHmaskcurve = HHmaskshape->getCurve(); + spot.strumaskcol = strumaskcol->getValue(); + spot.toolcol = toolcol->get_active(); + spot.fftColorMask = fftColorMask->get_active(); + spot.contcol = contcol->getValue(); + spot.blurcol = blurcol->getValue(); + spot.blendmaskcol = blendmaskcol->getIntValue(); + spot.radmaskcol = radmaskcol->getValue(); + spot.lapmaskcol = lapmaskcol->getValue(); + spot.chromaskcol = chromaskcol->getValue(); + spot.gammaskcol = gammaskcol->getValue(); + spot.slomaskcol = slomaskcol->getValue(); + spot.shadmaskcol = shadmaskcol->getIntValue(); + spot.HHhmaskcurve = HHhmaskshape->getCurve(); + spot.Lmaskcurve = Lmaskshape->getCurve(); + spot.LLmaskcolcurvewav = LLmaskcolshapewav->getCurve(); + spot.csthresholdcol = csThresholdcol->getValue(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabColor::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default value for adjuster, labgrid and threshold adjuster widgets + lightness->setDefault((double)defSpot.lightness); + contrast->setDefault((double)defSpot.contrast); + chroma->setDefault((double)defSpot.chroma); + labgrid->setDefault(defSpot.labgridALow / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridBLow / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridAHigh / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX); + strengthgrid->setDefault((double) defSpot.strengthgrid); + sensi->setDefault((double)defSpot.sensi); + structcol->setDefault((double)defSpot.structcol); + blurcolde->setDefault((double)defSpot.blurcolde); + softradiuscol->setDefault(defSpot.softradiuscol); + strcol->setDefault(defSpot.strcol); + strcolab->setDefault(defSpot.strcolab); + strcolh->setDefault(defSpot.strcolh); + angcol->setDefault(defSpot.angcol); + mercol->setDefault(defSpot.mercol); + opacol->setDefault(defSpot.opacol); + conthrcol->setDefault(defSpot.conthrcol); + labgridmerg->setDefault(defSpot.labgridALowmerg / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridBLowmerg / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridAHighmerg / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX); + merlucol->setDefault(defSpot.merlucol); + strumaskcol->setDefault(defSpot.strumaskcol); + contcol->setDefault(defSpot.contcol); + blurcol->setDefault(defSpot.blurcol); + blendmaskcol->setDefault((double)defSpot.blendmaskcol); + radmaskcol->setDefault(defSpot.radmaskcol); + lapmaskcol->setDefault(defSpot.lapmaskcol); + chromaskcol->setDefault(defSpot.chromaskcol); + gammaskcol->setDefault(defSpot.gammaskcol); + slomaskcol->setDefault(defSpot.slomaskcol); + shadmaskcol->setDefault((double)defSpot.shadmaskcol); + csThresholdcol->setDefault(defSpot.csthresholdcol); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabColor::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == lightness) { + if (listener) { + listener->panelChanged(Evlocallablightness, + lightness->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == contrast) { + if (listener) { + listener->panelChanged(Evlocallabcontrast, + contrast->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chroma) { + if (listener) { + listener->panelChanged(Evlocallabchroma, + chroma->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strengthgrid) { + if (listener) { + listener->panelChanged(EvLocallabLabstrengthgrid, + strengthgrid->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensi) { + if (listener) { + listener->panelChanged(Evlocallabsensi, + sensi->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == structcol) { + if (listener) { + listener->panelChanged(Evlocallabstructcol, + structcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blurcolde) { + if (listener) { + listener->panelChanged(Evlocallabblurcolde, + blurcolde->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == softradiuscol) { + if (listener) { + listener->panelChanged(Evlocallabsoftradiuscol, + softradiuscol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strcol) { + if (listener) { + listener->panelChanged(Evlocallabstrcol, + strcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strcolab) { + if (listener) { + listener->panelChanged(Evlocallabstrcolab, + strcolab->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strcolh) { + if (listener) { + listener->panelChanged(Evlocallabstrcolh, + strcolh->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == angcol) { + if (listener) { + listener->panelChanged(Evlocallabangcol, + angcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == mercol) { + if (listener) { + listener->panelChanged(Evlocallabmercol, + mercol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == opacol) { + if (listener) { + listener->panelChanged(Evlocallabopacol, + opacol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == conthrcol) { + if (listener) { + listener->panelChanged(Evlocallabconthrcol, + conthrcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == merlucol) { + if (listener) { + listener->panelChanged(Evlocallabmerlucol, + merlucol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strumaskcol) { + if (listener) { + listener->panelChanged(Evlocallabstrumaskcol, + strumaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == contcol) { + if (listener) { + listener->panelChanged(Evlocallabcontcol, + contcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blurcol) { + if (listener) { + listener->panelChanged(Evlocallabblurcol, + blurcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskcol) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskcol, + blendmaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskcol) { + if (listener) { + listener->panelChanged(Evlocallabradmaskcol, + radmaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskcol) { + if (listener) { + listener->panelChanged(Evlocallablapmaskcol, + lapmaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskcol) { + if (listener) { + listener->panelChanged(Evlocallabchromaskcol, + chromaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskcol) { + if (listener) { + listener->panelChanged(Evlocallabgammaskcol, + gammaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskcol) { + if (listener) { + listener->panelChanged(Evlocallabslomaskcol, + slomaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shadmaskcol) { + if (listener) { + listener->panelChanged(Evlocallabshadmaskcol, + shadmaskcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == csThresholdcol) { + if (listener) { + listener->panelChanged(EvlocallabcsThresholdcol, + csThresholdcol->getHistoryString() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == llshape) { + if (listener) { + listener->panelChanged(Evlocallabllshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == ccshape) { + if (listener) { + listener->panelChanged(Evlocallabccshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == clshape) { + if (listener) { + listener->panelChanged(Evlocallabclshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == lcshape) { + if (listener) { + listener->panelChanged(Evlocallablcshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LHshape) { + if (listener) { + listener->panelChanged(EvlocallabLHshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHshape) { + if (listener) { + listener->panelChanged(EvlocallabHHshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == rgbshape) { + if (listener) { + listener->panelChanged(Evlocallabrgbshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmaskshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHhmaskshape) { + if (listener) { + listener->panelChanged(EvlocallabHHhmaskshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmaskshape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskcolshapewav) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskcolshapewav, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenacolor, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenacolor, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + blurcolde->setValue((double)defSpot.blurcolde); + // softradiuscol->setValue(defSpot.softradiuscol); + strcolab->setValue(defSpot.strcolab); + strcolh->setValue(defSpot.strcolh); + clshape->setCurve(defSpot.clcurve); + lcshape->setCurve(defSpot.lccurve); + LHshape->setCurve(defSpot.LHcurve); + HHshape->setCurve(defSpot.HHcurve); + + if (defSpot.toneMethod == "one") { + toneMethod->set_active(0); + } else if (defSpot.toneMethod == "two") { + toneMethod->set_active(1); + } else if (defSpot.toneMethod == "thr") { + toneMethod->set_active(2); + } else if (defSpot.toneMethod == "fou") { + toneMethod->set_active(3); + } + + rgbshape->setCurve(defSpot.rgbcurve); + special->set_active(defSpot.special); + + if (defSpot.merMethod == "mone") { + merMethod->set_active(0); +// } else if (defSpot.merMethod == "mtwo") { +// merMethod->set_active(1); + } else if (defSpot.merMethod == "mthr") { + merMethod->set_active(1); + } else if (defSpot.merMethod == "mfou") { + merMethod->set_active(2); + } else if (defSpot.merMethod == "mfiv") { + merMethod->set_active(3); + } + + if (defSpot.mergecolMethod == "one") { + mergecolMethod->set_active(0); + } else if (defSpot.mergecolMethod == "two") { + mergecolMethod->set_active(1); + } else if (defSpot.mergecolMethod == "thr") { + mergecolMethod->set_active(2); + } else if (defSpot.mergecolMethod == "fou") { + mergecolMethod->set_active(3); + } else if (defSpot.mergecolMethod == "fiv") { + mergecolMethod->set_active(4); + } else if (defSpot.mergecolMethod == "six") { + mergecolMethod->set_active(5); + } else if (defSpot.mergecolMethod == "sev") { + mergecolMethod->set_active(6); + } else if (defSpot.mergecolMethod == "sev0") { + mergecolMethod->set_active(7); + } else if (defSpot.mergecolMethod == "sev1") { + mergecolMethod->set_active(8); + } else if (defSpot.mergecolMethod == "sev2") { + mergecolMethod->set_active(9); + } else if (defSpot.mergecolMethod == "hei") { + mergecolMethod->set_active(10); + } else if (defSpot.mergecolMethod == "nin") { + mergecolMethod->set_active(11); + } else if (defSpot.mergecolMethod == "ten") { + mergecolMethod->set_active(12); + } else if (defSpot.mergecolMethod == "ele") { + mergecolMethod->set_active(13); + } else if (defSpot.mergecolMethod == "twe") { + mergecolMethod->set_active(14); + } else if (defSpot.mergecolMethod == "thi") { + mergecolMethod->set_active(15); + } else if (defSpot.mergecolMethod == "for") { + mergecolMethod->set_active(16); + } else if (defSpot.mergecolMethod == "hue") { + mergecolMethod->set_active(17); + } else if (defSpot.mergecolMethod == "sat") { + mergecolMethod->set_active(18); + } else if (defSpot.mergecolMethod == "col") { + mergecolMethod->set_active(19); + } else if (defSpot.mergecolMethod == "lum") { + mergecolMethod->set_active(20); + } + + mercol->setValue(defSpot.mercol); + opacol->setValue(defSpot.opacol); + conthrcol->setValue(defSpot.conthrcol); + labgridmerg->setParams(0, 0, + defSpot.labgridAHighmerg / LocallabParams::LABGRIDL_CORR_MAX, + defSpot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX, + false); + merlucol->setValue(defSpot.merlucol); + strumaskcol->setValue(defSpot.strumaskcol); + toolcol->set_active(defSpot.toolcol); + fftColorMask->set_active(defSpot.fftColorMask); + contcol->setValue(defSpot.contcol); + lapmaskcol->setValue(defSpot.lapmaskcol); + gammaskcol->setValue(defSpot.gammaskcol); + slomaskcol->setValue(defSpot.slomaskcol); + shadmaskcol->setValue((double)defSpot.shadmaskcol); + HHhmaskshape->setCurve(defSpot.HHhmaskcurve); + LLmaskcolshapewav->setCurve(defSpot.LLmaskcolcurvewav); + csThresholdcol->setValue(defSpot.csthresholdcol); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update GUI according to merMethod combobox state + updateColorGUI2(); + // - Update GUI according to fftColorMash button state + updateColorGUI3(); +} + +void LocallabColor::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + blurcolde->hide(); + softradiuscol->show(); + strcolab->hide(); + strcolh->hide(); + clCurveEditorG->hide(); + HCurveEditorG->hide(); + H2CurveEditorG->hide(); + rgbCurveEditorG->hide(); + special->hide(); + expmaskcol1->hide(); + struFrame->hide(); + blurFrame->hide(); + lapmaskcol->hide(); + gammaskcol->hide(); + slomaskcol->hide(); + shadmaskcol->hide(); + maskHCurveEditorG->hide(); + mask2CurveEditorGwav->hide(); + csThresholdcol->hide(); + } else { + // Advanced widgets are shown in Expert mode + blurcolde->show(); + + if (!invers->get_active()) { // Keep widget hidden when invers is toggled + softradiuscol->show(); + } + + strcolab->show(); + strcolh->show(); + + if (!invers->get_active()) { // Keep widgets hidden when invers is toggled + clCurveEditorG->show(); + HCurveEditorG->show(); + } + + H2CurveEditorG->show(); + rgbCurveEditorG->show(); + special->show(); + + if (!invers->get_active()) { // Keep widget hidden when invers is toggled + expmaskcol1->show(); + } + + struFrame->show(); + blurFrame->show(); + lapmaskcol->show(); + gammaskcol->show(); + slomaskcol->show(); + shadmaskcol->show(); + maskHCurveEditorG->show(); + mask2CurveEditorGwav->show(); + csThresholdcol->show(); + } +} + +void LocallabColor::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskshape->updateLocallabBackground(normChromar); + LLmaskshape->updateLocallabBackground(normLumar); + HHmaskshape->updateLocallabBackground(normHuer); + HHhmaskshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabColor::curvactivChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (curvactiv->get_active()) { + listener->panelChanged(Evlocallabcurvactiv, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabcurvactiv, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::gridMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvLocallabgridMethod, + gridMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabColor::inversChanged() +{ + updateColorGUI1(); // Update GUI according to invers button state + + // This event is called to transmit potentially reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (invers->get_active()) { + listener->panelChanged(Evlocallabinvers, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabinvers, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::qualitycurveMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabqualitycurveMethod, + qualitycurveMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabColor::toneMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvLocallabtoneMethod, + toneMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabColor::specialChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (special->get_active()) { + listener->panelChanged(EvLocallabspecial, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabspecial, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::merMethodChanged() +{ + updateColorGUI2(); // Update GUI according to merMethod combobox state + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvLocallabmerMethod, + merMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabColor::mergecolMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvLocallabmergecolMethod, + mergecolMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabColor::showmaskcolMethodChanged() +{ + // If mask preview is activated, deactivate other Color & Light mask preview + showmaskcolMethodConninv.block(true); + showmaskcolMethodinv->set_active(0); + showmaskcolMethodConninv.block(false); + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabColor::showmaskcolMethodChangedinv() +{ + // If mask preview is activated, deactivate other Color & Light mask preview + showmaskcolMethodConn.block(true); + showmaskcolMethod->set_active(0); + showmaskcolMethodConn.block(false); + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabColor::enaColorMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaColorMask->get_active()) { + listener->panelChanged(EvLocallabEnaColorMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaColorMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::toolcolChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (toolcol->get_active()) { + listener->panelChanged(EvLocallabtoolcol, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabtoolcol, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::fftColorMaskChanged() +{ + updateColorGUI3(); // Update GUI according to fftColorMash button state + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (fftColorMask->get_active()) { + listener->panelChanged(EvLocallabfftColorMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabfftColorMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabColor::updateColorGUI1() +{ + const int mode = complexity->get_active_row_number(); + + if (invers->get_active()) { + gridFrame->hide(); + structcol->hide(); + softradiuscol->hide(); + expgradcol->hide(); + labqualcurv->hide(); + qualitycurveMethod->hide(); + clCurveEditorG->hide(); + HCurveEditorG->hide(); + expmaskcol1->hide(); + showmaskcolMethod->hide(); + // Reset hidden mask combobox + showmaskcolMethodConn.block(true); + showmaskcolMethod->set_active(0); + showmaskcolMethodConn.block(false); + showmaskcolMethodinv->show(); + contcol->hide(); + blurcol->hide(); + } else { + gridFrame->show(); + structcol->show(); + + if (mode == Normal) { // Keep widget hidden in Normal mode + softradiuscol->show(); + } + + expgradcol->show(); + labqualcurv->show(); + qualitycurveMethod->show(); + + if (mode == Normal) { // Keep widgets hidden in Normal mode + clCurveEditorG->show(); + HCurveEditorG->show(); + expmaskcol1->show(); + } + + showmaskcolMethod->show(); + showmaskcolMethodinv->hide(); + // Reset hidden mask combobox + showmaskcolMethodConninv.block(true); + showmaskcolMethodinv->set_active(0); + showmaskcolMethodConninv.block(false); + contcol->show(); + blurcol->show(); + } +} + +void LocallabColor::updateColorGUI2() +{ + // Note: When a merMethod is selected, invers button is set insensitive to avoid the combobox to disappear + switch (merMethod->get_active_row_number()) { + case 0: + invers->set_sensitive(true); + H2CurveEditorG->set_sensitive(true); + rgbCurveEditorG->set_sensitive(true); + special->set_sensitive(true); + mask7->hide(); + conthrcol->hide(); + gridmerFrame->hide(); + break; +/* + case 1: + invers->set_sensitive(false); + H2CurveEditorG->set_sensitive(true); + rgbCurveEditorG->set_sensitive(true); + special->set_sensitive(true); + mask7->hide(); + conthrcol->hide(); + gridmerFrame->hide(); + break; +*/ + case 1: + invers->set_sensitive(false); + H2CurveEditorG->set_sensitive(true); + rgbCurveEditorG->set_sensitive(false); + special->set_sensitive(false); + mask7->show(); + conthrcol->show(); + gridmerFrame->hide(); + break; + + case 2: + invers->set_sensitive(false); + H2CurveEditorG->set_sensitive(true); + rgbCurveEditorG->set_sensitive(false); + special->set_sensitive(false); + mask7->show(); + conthrcol->show(); + gridmerFrame->hide(); + break; + + case 3: + invers->set_sensitive(false); + H2CurveEditorG->set_sensitive(true); + rgbCurveEditorG->set_sensitive(false); + special->set_sensitive(false); + mask7->show(); + conthrcol->hide(); + gridmerFrame->show(); + } +} + +void LocallabColor::updateColorGUI3() +{ + const double temp = blurcol->getValue(); + + if (fftColorMask->get_active()) { + blurcol->setLimits(0.2, 1000., 0.5, 0.2); + } else { + blurcol->setLimits(0.2, 100., 0.5, 0.2); + } + + blurcol->setValue(temp); +} + +/* ==== LocallabExposure ==== */ +LocallabExposure::LocallabExposure(): + LocallabTool(this, M("TP_LOCALLAB_EXP_TOOLNAME"), M("TP_LOCALLAB_EXPOSE"), false), + + // Exposure specific widgets + expMethod(Gtk::manage(new MyComboBoxText())), + pdeFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_PDEFRA")))), + laplacexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPLACEXP"), 0.0, 100.0, 0.1, 0.))), + linear(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LINEAR"), 0., 1., 0.01, 0.05))), + balanexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BALANEXP"), 0.5, 1.5, 0.01, 1.0))), + gamm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMM"), 0.2, 1.3, 0.01, 0.4))), + exnoiseMethod(Gtk::manage(new MyComboBoxText())), + fatFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_FATFRA")))), + fatamount(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATAMOUNT"), 1., 100., 1., 1.))), + fatdetail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATDETAIL"), -100., 300., 1., 0.))), + fatlevel(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATLEVEL"), 0.25, 2.5, 0.05, 1.))), + fatanchor(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATANCHORA"), 0.1, 3.0, 0.05, 1.))), + sensiex(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))), + structexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUCCOL"), 0, 100, 1, 0))), + blurexpde(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURDE"), 2, 100, 1, 5))), + exptoolexp(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPTOOL")))), + expcomp(Gtk::manage(new Adjuster(M("TP_EXPOSURE_EXPCOMP"), MINEXP, MAXEXP, 0.02, 0.))), + black(Gtk::manage(new Adjuster(M("TP_EXPOSURE_BLACKLEVEL"), -16384, 32768, 10, 0))), + hlcompr(Gtk::manage(new Adjuster(M("TP_EXPOSURE_COMPRHIGHLIGHTS"), 0, 500, 1, 0))), + hlcomprthresh(Gtk::manage(new Adjuster(M("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), 0, 100, 1, 0))), + shadex(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHADEX"), 0, 100, 1, 0))), + shcompr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHADEXCOMP"), 0, 100, 1, 50))), + expchroma(Gtk::manage(new Adjuster(M("TP_LOCALLAB_EXPCHROMA"), -50, 100, 1, 5))), + curveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_CURVEEDITOR_TONES_LABEL"))), + shapeexpos(static_cast(curveEditorG->addCurve(CT_Diagonal, ""))), + expgradexp(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPGRAD")))), + strexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -4., 4., 0.05, 0.))), + angexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180, 180, 0.1, 0.))), + softradiusexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 1000.0, 0.5, 0.))), + inversex(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVERS")))), + expmaskexp(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWE")))), + showmaskexpMethod(Gtk::manage(new MyComboBoxText())), + showmaskexpMethodinv(Gtk::manage(new MyComboBoxText())), + enaExpMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + enaExpMaskaft(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASKAFT")))), + maskexpCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + lapmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), + slomaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + gradFramemask(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRADFRA")))), + strmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -2., 2., 0.05, 0.))), + angmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180., 180., 0.1, 0.))), + mask2expCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmaskexpshape(static_cast(mask2expCurveEditorG->addCurve(CT_Diagonal, "L(L)"))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Exposure specific widgets + expMethod->append(M("TP_LOCALLAB_STD")); + expMethod->append(M("TP_LOCALLAB_PDE")); + expMethod->set_active(0); + expMethodConn = expMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabExposure::expMethodChanged)); + + pdeFrame->set_label_align(0.025, 0.5); + + laplacexp->setAdjusterListener(this); + + linear->setAdjusterListener(this); + + balanexp->setAdjusterListener(this); + + gamm->setAdjusterListener(this); + + exnoiseMethod->append(M("TP_LOCALLAB_NONENOISE")); + exnoiseMethod->append(M("TP_LOCALLAB_MEDIAN")); + exnoiseMethod->append(M("TP_LOCALLAB_WEDIANHI")); + exnoiseMethod->set_active(0); + exnoiseMethodConn = exnoiseMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabExposure::exnoiseMethodChanged)); + + fatFrame->set_label_align(0.025, 0.5); + + fatamount->setAdjusterListener(this); + + fatdetail->setAdjusterListener(this); + + fatlevel->setAdjusterListener(this); + + fatanchor->setAdjusterListener(this); + + sensiex->setAdjusterListener(this); + + structexp->setAdjusterListener(this); + + blurexpde->setAdjusterListener(this); + + setExpandAlignProperties(exptoolexp, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + expcomp->setAdjusterListener(this); + + black->setAdjusterListener(this); + + hlcompr->setAdjusterListener(this); + + hlcomprthresh->setAdjusterListener(this); + + shadex->setAdjusterListener(this); + + shcompr->setAdjusterListener(this); + + expchroma->setAdjusterListener(this); + + curveEditorG->setCurveListener(this); + + shapeexpos->setResetCurve(DiagonalCurveType(defSpot.excurve.at(0)), defSpot.excurve); + shapeexpos->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1}}); + shapeexpos->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1}}); + + curveEditorG->curveListComplete(); + + setExpandAlignProperties(expgradexp, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + strexp->setAdjusterListener(this); + + angexp->setAdjusterListener(this); + angexp->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + + softradiusexp->setLogScale(10, 0); + softradiusexp->setAdjusterListener(this); + + inversexConn = inversex->signal_toggled().connect(sigc::mem_fun(*this, &LocallabExposure::inversexChanged)); + inversex->set_tooltip_text(M("TP_LOCALLAB_INVERS_TOOLTIP")); + + setExpandAlignProperties(expmaskexp, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskexpMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskexpMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskexpMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskexpMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskexpMethod->append(M("TP_LOCALLAB_SHOWSTRUCEX")); + showmaskexpMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskexpMethod->set_active(0); + showmaskexpMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskexpMethodConn = showmaskexpMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabExposure::showmaskexpMethodChanged)); + + showmaskexpMethodinv->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskexpMethodinv->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskexpMethodinv->set_active(0); + showmaskexpMethodinv->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskexpMethodConninv = showmaskexpMethodinv->signal_changed().connect(sigc::mem_fun(*this, &LocallabExposure::showmaskexpMethodChangedinv)); + + enaExpMaskConn = enaExpMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabExposure::enaExpMaskChanged)); + + enaExpMaskaftConn = enaExpMaskaft->signal_toggled().connect(sigc::mem_fun(*this, &LocallabExposure::enaExpMaskaftChanged)); + + maskexpCurveEditorG->setCurveListener(this); + + CCmaskexpshape->setIdentityValue(0.); + CCmaskexpshape->setResetCurve(FlatCurveType(defSpot.CCmaskexpcurve.at(0)), defSpot.CCmaskexpcurve); + CCmaskexpshape->setBottomBarColorProvider(this, 1); + + LLmaskexpshape->setIdentityValue(0.); + LLmaskexpshape->setResetCurve(FlatCurveType(defSpot.LLmaskexpcurve.at(0)), defSpot.LLmaskexpcurve); + LLmaskexpshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1}}); + + HHmaskexpshape->setIdentityValue(0.); + HHmaskexpshape->setResetCurve(FlatCurveType(defSpot.HHmaskexpcurve.at(0)), defSpot.HHmaskexpcurve); + HHmaskexpshape->setCurveColorProvider(this, 2); + HHmaskexpshape->setBottomBarColorProvider(this, 2); + + maskexpCurveEditorG->curveListComplete(); + + blendmaskexp->setAdjusterListener(this); + + radmaskexp->setLogScale(10, -10); + radmaskexp->setAdjusterListener(this); + + lapmaskexp->setAdjusterListener(this); + + chromaskexp->setAdjusterListener(this); + + gammaskexp->setAdjusterListener(this); + + slomaskexp->setAdjusterListener(this); + + gradFramemask->set_label_align(0.025, 0.5); + + strmaskexp->setAdjusterListener(this); + + angmaskexp->setAdjusterListener(this); + angmaskexp->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + + mask2expCurveEditorG->setCurveListener(this); + + Lmaskexpshape->setResetCurve(DiagonalCurveType(defSpot.Lmaskexpcurve.at(0)), defSpot.Lmaskexpcurve); + Lmaskexpshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1}}); + Lmaskexpshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1}}); + + mask2expCurveEditorG->curveListComplete(); + + // Add Color & Light specific widgets to GUI + pack_start(*expMethod); + ToolParamBlock* const pdeBox = Gtk::manage(new ToolParamBlock()); + pdeBox->pack_start(*laplacexp); + pdeBox->pack_start(*linear); + pdeBox->pack_start(*balanexp); + pdeBox->pack_start(*gamm); + Gtk::HBox* const ctboxexpmethod = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labelexpmethod = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_NOISEMETH") + ":")); + ctboxexpmethod->pack_start(*labelexpmethod, Gtk::PACK_SHRINK, 4); + ctboxexpmethod->pack_start(*exnoiseMethod); + pdeBox->pack_start(*ctboxexpmethod); + pdeFrame->add(*pdeBox); + pack_start(*pdeFrame); + ToolParamBlock* const fatBox = Gtk::manage(new ToolParamBlock()); + fatBox->pack_start(*fatamount); + fatBox->pack_start(*fatdetail); + fatBox->pack_start(*fatlevel); + fatBox->pack_start(*fatanchor); + fatFrame->add(*fatBox); + pack_start(*fatFrame); + pack_start(*expcomp); + pack_start(*sensiex); + pack_start(*structexp); + pack_start(*blurexpde); + ToolParamBlock* const toolBox = Gtk::manage(new ToolParamBlock()); +// toolBox->pack_start(*expcomp); + toolBox->pack_start(*black); + toolBox->pack_start(*hlcompr); + toolBox->pack_start(*hlcomprthresh); + toolBox->pack_start(*shadex); + toolBox->pack_start(*shcompr); + toolBox->pack_start(*expchroma); + toolBox->pack_start(*curveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + exptoolexp->add(*toolBox, false); + pack_start(*exptoolexp); + ToolParamBlock* const gradBox = Gtk::manage(new ToolParamBlock()); + gradBox->pack_start(*strexp); + gradBox->pack_start(*angexp); + expgradexp->add(*gradBox, false); + pack_start(*expgradexp); + pack_start(*softradiusexp); + pack_start(*inversex); + ToolParamBlock* const maskexpBox = Gtk::manage(new ToolParamBlock()); + maskexpBox->pack_start(*showmaskexpMethod, Gtk::PACK_SHRINK, 4); + maskexpBox->pack_start(*showmaskexpMethodinv, Gtk::PACK_SHRINK, 4); + maskexpBox->pack_start(*enaExpMask, Gtk::PACK_SHRINK, 0); + // maskexpBox->pack_start(*enaExpMaskaft, Gtk::PACK_SHRINK, 0); + maskexpBox->pack_start(*maskexpCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + maskexpBox->pack_start(*blendmaskexp, Gtk::PACK_SHRINK, 0); + maskexpBox->pack_start(*radmaskexp, Gtk::PACK_SHRINK, 0); + maskexpBox->pack_start(*lapmaskexp, Gtk::PACK_SHRINK, 0); + maskexpBox->pack_start(*chromaskexp, Gtk::PACK_SHRINK, 0); + maskexpBox->pack_start(*gammaskexp, Gtk::PACK_SHRINK, 0); + maskexpBox->pack_start(*slomaskexp, Gtk::PACK_SHRINK, 0); + ToolParamBlock* const gradmaskBox = Gtk::manage(new ToolParamBlock()); + gradmaskBox->pack_start(*strmaskexp); + gradmaskBox->pack_start(*angmaskexp); + gradFramemask->add(*gradmaskBox); + maskexpBox->pack_start(*gradFramemask); + maskexpBox->pack_start(*mask2expCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + expmaskexp->add(*maskexpBox, false); + pack_start(*expmaskexp, false, false); +} + +LocallabExposure::~LocallabExposure() +{ + delete curveEditorG; + delete maskexpCurveEditorG; + delete mask2expCurveEditorG; +} + +bool LocallabExposure::isMaskViewActive() +{ + return ((showmaskexpMethod->get_active_row_number() != 0) || (showmaskexpMethodinv->get_active_row_number() != 0)); +} + +void LocallabExposure::resetMaskView() +{ + showmaskexpMethodConn.block(true); + showmaskexpMethodConninv.block(true); + + showmaskexpMethod->set_active(0); + showmaskexpMethodinv->set_active(0); + + showmaskexpMethodConn.block(false); + showmaskexpMethodConninv.block(false); +} + +void LocallabExposure::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + expMask = showmaskexpMethod->get_active_row_number(); + expMaskinv = showmaskexpMethodinv->get_active_row_number(); +} + +void LocallabExposure::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_EXPOSURE_TOOLTIP")); + expMethod->set_tooltip_text(M("TP_LOCALLAB_EXPMETHOD_TOOLTIP")); + structexp->set_tooltip_text(M("TP_LOCALLAB_STRUCT_TOOLTIP")); + pdeFrame->set_tooltip_text(M("TP_LOCALLAB_PDEFRAME_TOOLTIP")); + laplacexp->set_tooltip_text(M("TP_LOCALLAB_EXPLAP_TOOLTIP")); + balanexp->set_tooltip_text(M("TP_LOCALLAB_EXPLAPBAL_TOOLTIP")); + gamm->set_tooltip_text(M("TP_LOCALLAB_EXPLAPGAMM_TOOLTIP")); + linear->set_tooltip_text(M("TP_LOCALLAB_EXPLAPLIN_TOOLTIP")); + exnoiseMethod->set_tooltip_text(M("TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP")); + fatFrame->set_tooltip_text(M("TP_LOCALLAB_FATFRAME_TOOLTIP")); + sensiex->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + shapeexpos->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_TONES_TOOLTIP")); + strexp->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + expmaskexp->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskexpshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskexpshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskexpshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + radmaskexp->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskexp->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + strmaskexp->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + Lmaskexpshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + blendmaskexp->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2expCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + expchroma->set_tooltip_text(M("TP_LOCALLAB_EXPCHROMA_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + expMethod->set_tooltip_text(""); + structexp->set_tooltip_text(""); + pdeFrame->set_tooltip_text(""); + exnoiseMethod->set_tooltip_text(""); + laplacexp->set_tooltip_text(M("")); + balanexp->set_tooltip_text(M("")); + gamm->set_tooltip_text(M("")); + linear->set_tooltip_text(M("")); + fatFrame->set_tooltip_text(""); + sensiex->set_tooltip_text(""); + shapeexpos->setTooltip(""); + strexp->set_tooltip_text(""); + expmaskexp->set_tooltip_text(""); + CCmaskexpshape->setTooltip(""); + LLmaskexpshape->setTooltip(""); + HHmaskexpshape->setTooltip(""); + radmaskexp->set_tooltip_text(""); + lapmaskexp->set_tooltip_text(""); + strmaskexp->set_tooltip_text(""); + Lmaskexpshape->setTooltip(""); + blendmaskexp->set_tooltip_text(M("")); + mask2expCurveEditorG->set_tooltip_text(M("")); + expchroma->set_tooltip_text(M("")); + } +} + +void LocallabExposure::setDefaultExpanderVisibility() +{ + exptoolexp->set_expanded(false); + expgradexp->set_expanded(false); + expmaskexp->set_expanded(false); +} + +void LocallabExposure::disableListener() +{ + LocallabTool::disableListener(); + + expMethodConn.block(true); + exnoiseMethodConn.block(true); + inversexConn.block(true); + showmaskexpMethodConn.block(true); + showmaskexpMethodConninv.block(true); + enaExpMaskConn.block(true); + enaExpMaskaftConn.block(true); +} + +void LocallabExposure::enableListener() +{ + LocallabTool::enableListener(); + + expMethodConn.block(false); + exnoiseMethodConn.block(false); + inversexConn.block(false); + showmaskexpMethodConn.block(false); + showmaskexpMethodConninv.block(false); + enaExpMaskConn.block(false); + enaExpMaskaftConn.block(false); +} + +void LocallabExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visiexpose); + exp->setEnabled(spot.expexpose); + complexity->set_active(spot.complexexpose); + + if (spot.expMethod == "std") { + expMethod->set_active(0); + } else if (spot.expMethod == "pde") { + expMethod->set_active(1); + } + + laplacexp->setValue(spot.laplacexp); + linear->setValue(spot.linear); + balanexp->setValue(spot.balanexp); + gamm->setValue(spot.gamm); + + if (spot.exnoiseMethod == "one") { + exnoiseMethod->set_active(0); + } else if (spot.exnoiseMethod == "med") { + exnoiseMethod->set_active(1); + } else if (spot.exnoiseMethod == "medhi") { + exnoiseMethod->set_active(2); + } + + fatamount->setValue(spot.fatamount); + fatdetail->setValue(spot.fatdetail); + fatlevel->setValue(spot.fatlevel); + fatanchor->setValue(spot.fatanchor); + sensiex->setValue(spot.sensiex); + structexp->setValue(spot.structexp); + blurexpde->setValue(spot.blurexpde); + expcomp->setValue(spot.expcomp); + black->setValue(spot.black); + hlcompr->setValue(spot.hlcompr); + hlcomprthresh->setValue(spot.hlcomprthresh); + shadex->setValue(spot.shadex); + shcompr->setValue(spot.shcompr); + expchroma->setValue(spot.expchroma); + shapeexpos->setCurve(spot.excurve); + strexp->setValue(spot.strexp); + angexp->setValue(spot.angexp); + softradiusexp->setValue(spot.softradiusexp); + inversex->set_active(spot.inversex); + enaExpMask->set_active(spot.enaExpMask); + enaExpMaskaft->set_active(spot.enaExpMaskaft); + CCmaskexpshape->setCurve(spot.CCmaskexpcurve); + LLmaskexpshape->setCurve(spot.LLmaskexpcurve); + HHmaskexpshape->setCurve(spot.HHmaskexpcurve); + blendmaskexp->setValue(spot.blendmaskexp); + radmaskexp->setValue(spot.radmaskexp); + lapmaskexp->setValue(spot.lapmaskexp); + chromaskexp->setValue(spot.chromaskexp); + gammaskexp->setValue(spot.gammaskexp); + slomaskexp->setValue(spot.slomaskexp); + strmaskexp->setValue(spot.strmaskexp); + angmaskexp->setValue(spot.angmaskexp); + Lmaskexpshape->setCurve(spot.Lmaskexpcurve); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update shcompr sensitivity according to black and shadex value + updateExposureGUI1(); + + // Update exposure GUI according to expMethod value + updateExposureGUI2(); + + // Update exposure GUI according to inversex button state + updateExposureGUI3(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabExposure::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expexpose = exp->getEnabled(); + spot.visiexpose = exp->get_visible(); + spot.complexexpose = complexity->get_active_row_number(); + + if (expMethod->get_active_row_number() == 0) { + spot.expMethod = "std"; + } else if (expMethod->get_active_row_number() == 1) { + spot.expMethod = "pde"; + } + + spot.laplacexp = laplacexp->getValue(); + spot.linear = linear->getValue(); + spot.balanexp = balanexp->getValue(); + spot.gamm = gamm->getValue(); + + if (exnoiseMethod->get_active_row_number() == 0) { + spot.exnoiseMethod = "none"; + } else if (exnoiseMethod->get_active_row_number() == 1) { + spot.exnoiseMethod = "med"; + } else if (exnoiseMethod->get_active_row_number() == 2) { + spot.exnoiseMethod = "medhi"; + } + + spot.fatamount = fatamount->getValue(); + spot.fatdetail = fatdetail->getValue(); + spot.fatlevel = fatlevel->getValue(); + spot.fatanchor = fatanchor->getValue(); + spot.sensiex = sensiex->getIntValue(); + spot.structexp = structexp->getIntValue(); + spot.blurexpde = blurexpde->getIntValue(); + spot.expcomp = expcomp->getValue(); + spot.black = black->getIntValue(); + spot.hlcompr = hlcompr->getIntValue(); + spot.hlcomprthresh = hlcomprthresh->getIntValue(); + spot.shadex = shadex->getIntValue(); + spot.shcompr = shcompr->getIntValue(); + spot.expchroma = expchroma->getIntValue(); + spot.excurve = shapeexpos->getCurve(); + spot.strexp = strexp->getValue(); + spot.angexp = angexp->getValue(); + spot.softradiusexp = softradiusexp->getValue(); + spot.inversex = inversex->get_active(); + spot.enaExpMask = enaExpMask->get_active(); + spot.enaExpMaskaft = enaExpMaskaft->get_active(); + spot.CCmaskexpcurve = CCmaskexpshape->getCurve(); + spot.LLmaskexpcurve = LLmaskexpshape->getCurve(); + spot.HHmaskexpcurve = HHmaskexpshape->getCurve(); + spot.blendmaskexp = blendmaskexp->getIntValue(); + spot.radmaskexp = radmaskexp->getValue(); + spot.lapmaskexp = lapmaskexp->getValue(); + spot.chromaskexp = chromaskexp->getValue(); + spot.gammaskexp = gammaskexp->getValue(); + spot.slomaskexp = slomaskexp->getValue(); + spot.strmaskexp = strmaskexp->getValue(); + spot.angmaskexp = angmaskexp->getValue(); + spot.Lmaskexpcurve = Lmaskexpshape->getCurve(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + laplacexp->setDefault(defSpot.laplacexp); + linear->setDefault(defSpot.linear); + balanexp->setDefault(defSpot.balanexp); + gamm->setDefault(defSpot.gamm); + fatamount->setDefault(defSpot.fatamount); + fatdetail->setDefault(defSpot.fatdetail); + fatlevel->setDefault(defSpot.fatlevel); + fatanchor->setDefault(defSpot.fatanchor); + sensiex->setDefault((double)defSpot.sensiex); + structexp->setDefault((double)defSpot.structexp); + blurexpde->setDefault((double)defSpot.blurexpde); + expcomp->setDefault(defSpot.expcomp); + black->setDefault((double)defSpot.black); + hlcompr->setDefault((double)defSpot.hlcompr); + hlcomprthresh->setDefault((double)defSpot.hlcomprthresh); + shadex->setDefault((double)defSpot.shadex); + shcompr->setDefault((double)defSpot.shcompr); + expchroma->setDefault((double)defSpot.expchroma); + strexp->setDefault(defSpot.strexp); + angexp->setDefault(defSpot.angexp); + softradiusexp->setDefault(defSpot.softradiusexp); + blendmaskexp->setDefault((double)defSpot.blendmaskexp); + radmaskexp->setDefault(defSpot.radmaskexp); + lapmaskexp->setDefault(defSpot.lapmaskexp); + chromaskexp->setDefault(defSpot.chromaskexp); + gammaskexp->setDefault(defSpot.gammaskexp); + slomaskexp->setDefault(defSpot.slomaskexp); + strmaskexp->setDefault(defSpot.strmaskexp); + angmaskexp->setDefault(defSpot.angmaskexp); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabExposure::adjusterChanged(Adjuster* a, double newval) +{ + // Update shcompr sensitivity according to black and shadex value + if (a == black || a == shadex) { + updateExposureGUI1(); + } + + if (isLocActivated && exp->getEnabled()) { + if (a == laplacexp) { + if (listener) { + listener->panelChanged(Evlocallablaplacexp, + laplacexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == linear) { + if (listener) { + listener->panelChanged(Evlocallablinear, + linear->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == balanexp) { + if (listener) { + listener->panelChanged(Evlocallabbalanexp, + balanexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gamm) { + if (listener) { + listener->panelChanged(Evlocallabgamm, + gamm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == fatamount) { + if (listener) { + listener->panelChanged(Evlocallabfatamount, + fatamount->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == fatdetail) { + if (listener) { + listener->panelChanged(Evlocallabfatdetail, + fatdetail->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == fatlevel) { + if (listener) { + listener->panelChanged(Evlocallabfatlevel, + fatlevel->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == fatanchor) { + if (listener) { + listener->panelChanged(Evlocallabfatanchor, + fatanchor->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensiex) { + if (listener) { + listener->panelChanged(Evlocallabsensiex, + sensiex->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == structexp) { + if (listener) { + listener->panelChanged(Evlocallabstructexp, + structexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blurexpde) { + if (listener) { + listener->panelChanged(Evlocallabblurexpde, + blurexpde->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == expcomp) { + if (listener) { + listener->panelChanged(Evlocallabexpcomp, + expcomp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == black) { + if (listener) { + listener->panelChanged(Evlocallabblack, + black->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == hlcompr) { + if (listener) { + listener->panelChanged(Evlocallabhlcompr, + hlcompr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == hlcomprthresh) { + if (listener) { + listener->panelChanged(Evlocallabhlcomprthresh, + hlcomprthresh->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shadex) { + if (listener) { + listener->panelChanged(Evlocallabshadex, + shadex->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shcompr) { + if (listener) { + listener->panelChanged(Evlocallabshcompr, + shcompr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == expchroma) { + if (listener) { + listener->panelChanged(Evlocallabexpchroma, + expchroma->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strexp) { + if (listener) { + listener->panelChanged(Evlocallabstrexp, + strexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == angexp) { + if (listener) { + listener->panelChanged(Evlocallabangexp, + angexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == softradiusexp) { + if (listener) { + listener->panelChanged(Evlocallabsoftradiusexp, + softradiusexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskexp) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskexp, + blendmaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskexp) { + if (listener) { + listener->panelChanged(Evlocallabradmaskexp, + radmaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskexp) { + if (listener) { + listener->panelChanged(Evlocallablapmaskexp, + lapmaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskexp) { + if (listener) { + listener->panelChanged(Evlocallabchromaskexp, + chromaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskexp) { + if (listener) { + listener->panelChanged(Evlocallabgammaskexp, + gammaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskexp) { + if (listener) { + listener->panelChanged(Evlocallabslomaskexp, + slomaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strmaskexp) { + if (listener) { + listener->panelChanged(Evlocallabstrmaskexp, + strmaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == angmaskexp) { + if (listener) { + listener->panelChanged(Evlocallabangmaskexp, + angmaskexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabExposure::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == shapeexpos) { + if (listener) { + listener->panelChanged(Evlocallabshapeexpos, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmaskexpshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskexpshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskexpshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskexpshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskexpshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskexpshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmaskexpshape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskexpshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabExposure::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenaexpose, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenaexpose, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabExposure::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + blurexpde->setValue((double)defSpot.blurexpde); + lapmaskexp->setValue(defSpot.lapmaskexp); + gammaskexp->setValue(defSpot.gammaskexp); + slomaskexp->setValue(defSpot.slomaskexp); + strmaskexp->setValue(defSpot.strmaskexp); + angmaskexp->setValue(defSpot.angmaskexp); + // laplacexp->setValue(defSpot.laplacexp); + // linear->setValue(defSpot.linear); + // balanexp->setValue(defSpot.balanexp); + // gamm->setValue(defSpot.gamm); + + // Enable all listeners + enableListener(); +} + +void LocallabExposure::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + lapmaskexp->hide(); + gammaskexp->hide(); + slomaskexp->hide(); + gradFramemask->hide(); + blurexpde->hide(); + // pdeFrame->hide(); + } else { + // Advanced widgets are shown in Expert mode + lapmaskexp->show(); + gammaskexp->show(); + slomaskexp->show(); + gradFramemask->show(); + blurexpde->show(); + // pdeFrame->show(); + } +} + +void LocallabExposure::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskexpshape->updateLocallabBackground(normChromar); + LLmaskexpshape->updateLocallabBackground(normLumar); + HHmaskexpshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabExposure::expMethodChanged() +{ + // Update exposure GUI according to expMethod value + updateExposureGUI2(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabexpMethod, + expMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabExposure::exnoiseMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabexnoiseMethod, + exnoiseMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabExposure::inversexChanged() +{ + // Update exposure GUI according to inversex button state + updateExposureGUI3(); + + // This event is called to transmit potentially reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (inversex->get_active()) { + listener->panelChanged(Evlocallabinversex, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabinversex, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabExposure::showmaskexpMethodChanged() +{ + // If mask preview is activated, deactivate other Exposure mask preview + showmaskexpMethodConninv.block(true); + showmaskexpMethodinv->set_active(0); + showmaskexpMethodConninv.block(false); + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabExposure::showmaskexpMethodChangedinv() +{ + // If mask preview is activated, deactivate other Exposure mask preview + showmaskexpMethodConn.block(true); + showmaskexpMethod->set_active(0); + showmaskexpMethodConn.block(false); + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabExposure::enaExpMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaExpMask->get_active()) { + listener->panelChanged(EvLocallabEnaExpMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaExpMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabExposure::enaExpMaskaftChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaExpMaskaft->get_active()) { + listener->panelChanged(EvLocallabEnaExpMaskaft, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaExpMaskaft, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabExposure::updateExposureGUI1() +{ + // Update shcompr sensitivity according to black and shadex value + if (black->getIntValue() == 0 && shadex->getIntValue() == 0) { + shcompr->set_sensitive(false); + } else { + shcompr->set_sensitive(true); + } +} + +void LocallabExposure::updateExposureGUI2() +{ + // Update exposure GUI according to expMethod value + if (expMethod->get_active_row_number() == 0) { + pdeFrame->hide(); + fatFrame->hide(); + softradiusexp->set_sensitive(true); + sensiex->set_sensitive(false); + } else if (expMethod->get_active_row_number() == 1) { + pdeFrame->show(); + fatFrame->show(); + softradiusexp->set_sensitive(false); + sensiex->set_sensitive(true); + } +} + +void LocallabExposure::updateExposureGUI3() +{ + // Update exposure GUI according to inversex button state + if (inversex->get_active()) { + expMethod->hide(); + + // Manage specific case where expMethod is different from 0 + if (expMethod->get_active_row_number() > 0) { + expMethodConn.block(true); + expMethod->set_active(0); + expMethodConn.block(false); + + // Update GUI accordingly + updateExposureGUI2(); + } + + structexp->hide(); + shadex->hide(); + softradiusexp->hide(); + expgradexp->hide(); + showmaskexpMethod->hide(); + // Reset hidden mask combobox + showmaskexpMethodConn.block(true); + showmaskexpMethod->set_active(0); + showmaskexpMethodConn.block(false); + showmaskexpMethodinv->show(); + } else { + expMethod->show(); + structexp->show(); + shadex->show(); + softradiusexp->show(); + expgradexp->show(); + showmaskexpMethodinv->hide(); + // Reset hidden mask combobox + showmaskexpMethodConninv.block(true); + showmaskexpMethodinv->set_active(0); + showmaskexpMethodConninv.block(false); + showmaskexpMethod->show(); + } +} + +/* ==== LocallabShadow ==== */ +LocallabShadow::LocallabShadow(): + LocallabTool(this, M("TP_LOCALLAB_SH_TOOLNAME"), M("TP_LOCALLAB_SHADHIGH"), false), + + // Shadow highlight specific widgets + shMethod(Gtk::manage(new MyComboBoxText())), + multipliersh([]() -> std::array + { + std::array res = {}; + + for (unsigned int i = 0; i < res.size(); ++i) { + Glib::ustring ss = Glib::ustring::format(i); + + if (i == 0) { + ss += Glib::ustring::compose(" (%1)", M("TP_LOCALLAB_LUMADARKEST")); + } else if (i == 4) { + ss += Glib::ustring::compose(" (%1)", M("TP_LOCALLAB_LUMAWHITESEST")); + } + + res[i] = Gtk::manage(new Adjuster(std::move(ss), -100, 100, 1, 0)); + } + + return res; + } + ()), + detailSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAILSH"), -5, 5, 1, 0))), + highlights(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), 0, 100, 1, 0))), + h_tonalwidth(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_HLTONALW"), 10, 100, 1, 70))), + shadows(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_SHADOWS"), 0, 100, 1, 0))), + s_tonalwidth(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_SHTONALW"), 10, 100, 1, 30))), + sh_radius(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_RADIUS"), 0, 100, 1, 40))), + sensihs(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 15))), + blurSHde(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURDE"), 2, 100, 1, 5))), + gamFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GAMFRA")))), + gamSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMSH"), 0.25, 15.0, 0.01, 2.4))), + sloSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOSH"), 0.0, 150.0, 0.01, 12.92))), + expgradsh(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPGRAD")))), + strSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -4., 4., 0.05, 0.))), + angSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180, 180, 0.1, 0.))), + inverssh(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVERS")))), + expmasksh(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWS")))), + showmaskSHMethod(Gtk::manage(new MyComboBoxText())), + showmaskSHMethodinv(Gtk::manage(new MyComboBoxText())), + enaSHMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + maskSHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + lapmaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), + slomaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + mask2SHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + LmaskSHshape(static_cast(mask2SHCurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + fatSHFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_FATSHFRA")))), + fatamountSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATAMOUNT"), 1., 100., 1., 1.))), + fatanchorSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATANCHOR"), 1., 100., 1., 50., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Shadow highlight specific widgets + shMethod->append(M("TP_LOCALLAB_SH1")); + shMethod->append(M("TP_LOCALLAB_SH2")); + shMethod->set_active(0); + shMethodConn = shMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabShadow::shMethodChanged)); + + for (unsigned int i = 0; i < multipliersh.size(); i++) { + multipliersh[i]->setAdjusterListener(this); + } + + detailSH->setAdjusterListener(this); + + highlights->setAdjusterListener(this); + + h_tonalwidth->setAdjusterListener(this); + + shadows->setAdjusterListener(this); + + s_tonalwidth->setAdjusterListener(this); + + sh_radius->setAdjusterListener(this); + + sensihs->setAdjusterListener(this); + + blurSHde->setAdjusterListener(this); + + gamSH->setAdjusterListener(this); + + sloSH->setAdjusterListener(this); + + setExpandAlignProperties(expgradsh, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + strSH->setAdjusterListener(this); + + angSH->setAdjusterListener(this); + angSH->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + + inversshConn = inverssh->signal_toggled().connect(sigc::mem_fun(*this, &LocallabShadow::inversshChanged)); + inverssh->set_tooltip_text(M("TP_LOCALLAB_INVERS_TOOLTIP")); + + setExpandAlignProperties(expmasksh, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskSHMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskSHMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskSHMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskSHMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskSHMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskSHMethod->set_active(0); + showmaskSHMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskSHMethodConn = showmaskSHMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabShadow::showmaskSHMethodChanged)); + + showmaskSHMethodinv->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskSHMethodinv->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskSHMethodinv->set_active(0); + showmaskSHMethodinv->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskSHMethodConninv = showmaskSHMethodinv->signal_changed().connect(sigc::mem_fun(*this, &LocallabShadow::showmaskSHMethodChangedinv)); + + enaSHMaskConn = enaSHMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabShadow::enaSHMaskChanged)); + + maskSHCurveEditorG->setCurveListener(this); + + CCmaskSHshape->setIdentityValue(0.); + CCmaskSHshape->setResetCurve(FlatCurveType(defSpot.CCmaskSHcurve.at(0)), defSpot.CCmaskSHcurve); + CCmaskSHshape->setBottomBarColorProvider(this, 1); + + LLmaskSHshape->setIdentityValue(0.); + LLmaskSHshape->setResetCurve(FlatCurveType(defSpot.LLmaskSHcurve.at(0)), defSpot.LLmaskSHcurve); + LLmaskSHshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskSHshape->setIdentityValue(0.); + HHmaskSHshape->setResetCurve(FlatCurveType(defSpot.HHmaskSHcurve.at(0)), defSpot.HHmaskSHcurve); + HHmaskSHshape->setCurveColorProvider(this, 2); + HHmaskSHshape->setBottomBarColorProvider(this, 2); + + maskSHCurveEditorG->curveListComplete(); + + blendmaskSH->setAdjusterListener(this); + + radmaskSH->setLogScale(10, -10); + radmaskSH->setAdjusterListener(this); + + lapmaskSH->setAdjusterListener(this); + + chromaskSH->setAdjusterListener(this); + + gammaskSH->setAdjusterListener(this); + + slomaskSH->setAdjusterListener(this); + + mask2SHCurveEditorG->setCurveListener(this); + + LmaskSHshape->setResetCurve(DiagonalCurveType(defSpot.LmaskSHcurve.at(0)), defSpot.LmaskSHcurve); + LmaskSHshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + LmaskSHshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2SHCurveEditorG->curveListComplete(); + + fatSHFrame->set_label_align(0.025, 0.5); + + fatamountSH->setAdjusterListener(this); + + fatanchorSH->setAdjusterListener(this); + + // Add Shadow highlight specific widgets to GUI + pack_start(*shMethod); + + for (int i = 0; i < 5; ++i) { + pack_start(*multipliersh[i]); + } + + pack_start(*detailSH); + pack_start(*highlights); + pack_start(*h_tonalwidth); + pack_start(*shadows); + pack_start(*s_tonalwidth); + pack_start(*sh_radius); +// pack_start(*sensihs); + pack_start(*blurSHde); +// Gtk::Frame* const gamFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GAMFRA"))); + gamFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const gammBox = Gtk::manage(new ToolParamBlock()); + gammBox->pack_start(*gamSH); + gammBox->pack_start(*sloSH); + gamFrame->add(*gammBox); + pack_start(*gamFrame); + ToolParamBlock* const gradSHBox = Gtk::manage(new ToolParamBlock()); + gradSHBox->pack_start(*strSH); + gradSHBox->pack_start(*angSH); + expgradsh->add(*gradSHBox, false); + pack_start(*expgradsh); + pack_start(*inverssh); + ToolParamBlock* const maskSHBox = Gtk::manage(new ToolParamBlock()); + maskSHBox->pack_start(*showmaskSHMethod, Gtk::PACK_SHRINK, 4); + maskSHBox->pack_start(*showmaskSHMethodinv, Gtk::PACK_SHRINK, 4); + maskSHBox->pack_start(*enaSHMask, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*maskSHCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + maskSHBox->pack_start(*blendmaskSH, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*radmaskSH, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*lapmaskSH, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*chromaskSH, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*gammaskSH, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*slomaskSH, Gtk::PACK_SHRINK, 0); + maskSHBox->pack_start(*mask2SHCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + ToolParamBlock* const fatSHBox = Gtk::manage(new ToolParamBlock()); + fatSHBox->pack_start(*fatamountSH); + fatSHBox->pack_start(*fatanchorSH); + fatSHFrame->add(*fatSHBox); +// maskSHBox->pack_start(*fatSHFrame); + expmasksh->add(*maskSHBox, false); + pack_start(*expmasksh, false, false); +} + +LocallabShadow::~LocallabShadow() +{ + delete maskSHCurveEditorG; + delete mask2SHCurveEditorG; +} + +bool LocallabShadow::isMaskViewActive() +{ + return ((showmaskSHMethod->get_active_row_number() != 0) || (showmaskSHMethodinv->get_active_row_number() != 0)); +} + +void LocallabShadow::resetMaskView() +{ + showmaskSHMethodConn.block(true); + showmaskSHMethodConninv.block(true); + + showmaskSHMethod->set_active(0); + showmaskSHMethodinv->set_active(0); + + showmaskSHMethodConn.block(false); + showmaskSHMethodConninv.block(false); +} + +void LocallabShadow::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + shMask = showmaskSHMethod->get_active_row_number(); + shMaskinv = showmaskSHMethodinv->get_active_row_number(); +} + +void LocallabShadow::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP")); + strSH->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + expmasksh->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskSHshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskSHshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskSHshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + radmaskSH->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskSH->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + LmaskSHshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + for (unsigned int i = 0; i < multipliersh.size(); i++) { + multipliersh[i]->set_tooltip_text(M("TP_LOCALLAB_MULTIPL_TOOLTIP")); + } + gamSH->set_tooltip_text(M("TP_LOCALLAB_SHTRC_TOOLTIP")); + sloSH->set_tooltip_text(M("TP_LOCALLAB_SHTRC_TOOLTIP")); + blendmaskSH->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2SHCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + strSH->set_tooltip_text(""); + expmasksh->set_tooltip_text(""); + CCmaskSHshape->setTooltip(""); + LLmaskSHshape->setTooltip(""); + HHmaskSHshape->setTooltip(""); + radmaskSH->set_tooltip_text(""); + lapmaskSH->set_tooltip_text(""); + LmaskSHshape->setTooltip(""); + for (unsigned int i = 0; i < multipliersh.size(); i++) { + multipliersh[i]->set_tooltip_text(M("")); + } + gamSH->set_tooltip_text(M("")); + sloSH->set_tooltip_text(M("")); + blendmaskSH->set_tooltip_text(M("")); + mask2SHCurveEditorG->set_tooltip_text(M("")); + } +} + +void LocallabShadow::setDefaultExpanderVisibility() +{ + expgradsh->set_expanded(false); + expmasksh->set_expanded(false); +} + +void LocallabShadow::disableListener() +{ + LocallabTool::disableListener(); + + shMethodConn.block(true); + inversshConn.block(true); + showmaskSHMethodConn.block(true); + showmaskSHMethodConninv.block(true); + enaSHMaskConn.block(true); +} + +void LocallabShadow::enableListener() +{ + LocallabTool::enableListener(); + + shMethodConn.block(false); + inversshConn.block(false); + showmaskSHMethodConn.block(false); + showmaskSHMethodConninv.block(false); + enaSHMaskConn.block(false); +} + +void LocallabShadow::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visishadhigh); + exp->setEnabled(spot.expshadhigh); + complexity->set_active(spot.complexshadhigh); + + if (spot.shMethod == "std") { + shMethod->set_active(0); + } else if (spot.shMethod == "tone") { + shMethod->set_active(1); + } + + for (int i = 0; i < 5; i++) { + multipliersh[i]->setValue((double)spot.multsh[i]); + } + + detailSH->setValue((double)spot.detailSH); + highlights->setValue((double)spot.highlights); + h_tonalwidth->setValue((double)spot.h_tonalwidth); + shadows->setValue(spot.shadows); + s_tonalwidth->setValue((double)spot.s_tonalwidth); + sh_radius->setValue((double)spot.sh_radius); + sensihs->setValue((double)spot.sensihs); + blurSHde->setValue((double)spot.blurSHde); + gamSH->setValue(spot.gamSH); + sloSH->setValue(spot.sloSH); + strSH->setValue(spot.strSH); + angSH->setValue(spot.angSH); + inverssh->set_active(spot.inverssh); + enaSHMask->set_active(spot.enaSHMask); + CCmaskSHshape->setCurve(spot.CCmaskSHcurve); + LLmaskSHshape->setCurve(spot.LLmaskSHcurve); + HHmaskSHshape->setCurve(spot.HHmaskSHcurve); + blendmaskSH->setValue((double)spot.blendmaskSH); + radmaskSH->setValue(spot.radmaskSH); + lapmaskSH->setValue(spot.lapmaskSH); + chromaskSH->setValue(spot.chromaskSH); + gammaskSH->setValue(spot.gammaskSH); + slomaskSH->setValue(spot.slomaskSH); + LmaskSHshape->setCurve(spot.LmaskSHcurve); + fatamountSH->setValue(spot.fatamountSH); + fatanchorSH->setValue(spot.fatanchorSH); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update shadow highlight GUI according to inverssh button state + updateShadowGUI1(); + + // Update shadow highlight GUI according to shMethod combobox state + updateShadowGUI2(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabShadow::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expshadhigh = exp->getEnabled(); + spot.visishadhigh = exp->get_visible(); + spot.complexshadhigh = complexity->get_active_row_number(); + + if (shMethod->get_active_row_number() == 0) { + spot.shMethod = "std"; + } else if (shMethod->get_active_row_number() == 1) { + spot.shMethod = "tone"; + } + + for (int i = 0; i < 5; i++) { + spot.multsh[i] = multipliersh[i]->getIntValue(); + } + + spot.detailSH = detailSH->getIntValue(); + spot.highlights = highlights->getIntValue(); + spot.h_tonalwidth = h_tonalwidth->getIntValue(); + spot.shadows = shadows->getIntValue(); + spot.s_tonalwidth = s_tonalwidth->getIntValue(); + spot.sh_radius = sh_radius->getIntValue(); + spot.sensihs = sensihs->getIntValue(); + spot.blurSHde = blurSHde->getIntValue(); + spot.gamSH = gamSH->getValue(); + spot.sloSH = sloSH->getValue(); + spot.strSH = strSH->getValue(); + spot.angSH = angSH->getValue(); + spot.inverssh = inverssh->get_active(); + spot.enaSHMask = enaSHMask->get_active(); + spot.LLmaskSHcurve = LLmaskSHshape->getCurve(); + spot.CCmaskSHcurve = CCmaskSHshape->getCurve(); + spot.HHmaskSHcurve = HHmaskSHshape->getCurve(); + spot.blendmaskSH = blendmaskSH->getIntValue(); + spot.radmaskSH = radmaskSH->getValue(); + spot.lapmaskSH = lapmaskSH->getValue(); + spot.chromaskSH = chromaskSH->getValue(); + spot.gammaskSH = gammaskSH->getValue(); + spot.slomaskSH = slomaskSH->getValue(); + spot.LmaskSHcurve = LmaskSHshape->getCurve(); + spot.fatamountSH = fatamountSH->getValue(); + spot.fatanchorSH = fatanchorSH->getValue(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabShadow::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + for (int i = 0; i < 5; i++) { + multipliersh[i]->setDefault(defSpot.multsh[i]); + } + + detailSH->setDefault((double)defSpot.detailSH); + highlights->setDefault((double)defSpot.highlights); + h_tonalwidth->setDefault((double)defSpot.h_tonalwidth); + shadows->setDefault((double)defSpot.shadows); + s_tonalwidth->setDefault((double)defSpot.s_tonalwidth); + sh_radius->setDefault((double)defSpot.sh_radius); + sensihs->setDefault((double)defSpot.sensihs); + blurSHde->setDefault((double)defSpot.blurSHde); + gamSH->setDefault(defSpot.gamSH); + sloSH->setDefault(defSpot.sloSH); + strSH->setDefault(defSpot.strSH); + angSH->setDefault(defSpot.angSH); + blendmaskSH->setDefault((double)defSpot.blendmaskSH); + radmaskSH->setDefault(defSpot.radmaskSH); + lapmaskSH->setDefault(defSpot.lapmaskSH); + chromaskSH->setDefault(defSpot.chromaskSH); + gammaskSH->setDefault(defSpot.gammaskSH); + slomaskSH->setDefault(defSpot.slomaskSH); + fatamountSH->setDefault(defSpot.fatamountSH); + fatanchorSH->setDefault(defSpot.fatanchorSH); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabShadow::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == multipliersh[0] || a == multipliersh[1] || a == multipliersh[2] || a == multipliersh[3] || a == multipliersh[4]) { + if (listener) { + listener->panelChanged(EvlocallabEqualizersh, + Glib::ustring::compose("%1, %2, %3, %4, %5", + Glib::ustring::format(std::fixed, std::setprecision(2), multipliersh[0]->getIntValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multipliersh[1]->getIntValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multipliersh[2]->getIntValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multipliersh[3]->getIntValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multipliersh[4]->getIntValue())) + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == detailSH) { + if (listener) { + listener->panelChanged(EvlocallabdetailSH, + detailSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == highlights) { + if (listener) { + listener->panelChanged(Evlocallabhighlights, + highlights->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == h_tonalwidth) { + if (listener) { + listener->panelChanged(Evlocallabh_tonalwidth, + h_tonalwidth->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shadows) { + if (listener) { + listener->panelChanged(Evlocallabshadows, + shadows->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == s_tonalwidth) { + if (listener) { + listener->panelChanged(Evlocallabs_tonalwidth, + s_tonalwidth->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sh_radius) { + if (listener) { + listener->panelChanged(Evlocallabsh_radius, + sh_radius->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensihs) { + if (listener) { + listener->panelChanged(Evlocallabsensihs, + sensihs->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blurSHde) { + if (listener) { + listener->panelChanged(EvlocallabblurSHde, + blurSHde->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gamSH) { + if (listener) { + listener->panelChanged(EvlocallabgamSH, + gamSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sloSH) { + if (listener) { + listener->panelChanged(EvlocallabsloSH, + sloSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strSH) { + if (listener) { + listener->panelChanged(EvlocallabstrSH, + strSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == angSH) { + if (listener) { + listener->panelChanged(EvlocallabangSH, + angSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskSH) { + if (listener) { + listener->panelChanged(EvlocallabblendmaskSH, + blendmaskSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskSH) { + if (listener) { + listener->panelChanged(EvlocallabradmaskSH, + radmaskSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskSH) { + if (listener) { + listener->panelChanged(EvlocallablapmaskSH, + lapmaskSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskSH) { + if (listener) { + listener->panelChanged(EvlocallabchromaskSH, + chromaskSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskSH) { + if (listener) { + listener->panelChanged(EvlocallabgammaskSH, + gammaskSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskSH) { + if (listener) { + listener->panelChanged(EvlocallabslomaskSH, + slomaskSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == fatamountSH) { + if (listener) { + listener->panelChanged(EvlocallabfatamountSH, + fatamountSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + + if (a == fatanchorSH) { + if (listener) { + listener->panelChanged(EvlocallabfatanchorSH, + fatanchorSH->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabShadow::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == CCmaskSHshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskSHshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskSHshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskSHshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskSHshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskSHshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LmaskSHshape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskSHshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabShadow::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenashadhigh, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenashadhigh, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabShadow::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + blurSHde->setValue((double)defSpot.blurSHde); + lapmaskSH->setValue(defSpot.lapmaskSH); + gammaskSH->setValue(defSpot.gammaskSH); + slomaskSH->setValue(defSpot.slomaskSH); + fatamountSH->setValue(defSpot.fatamountSH); + fatanchorSH->setValue(defSpot.fatanchorSH); + + // Enable all listeners + enableListener(); +} + +void LocallabShadow::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + blurSHde->hide(); + lapmaskSH->hide(); + gammaskSH->hide(); + slomaskSH->hide(); + fatSHFrame->hide(); + } else { + // Advanced widgets are shown in Expert mode + blurSHde->show(); + lapmaskSH->show(); + gammaskSH->show(); + slomaskSH->show(); + fatSHFrame->show(); + } +} + +void LocallabShadow::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskSHshape->updateLocallabBackground(normChromar); + LLmaskSHshape->updateLocallabBackground(normLumar); + HHmaskSHshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabShadow::shMethodChanged() +{ + + // Update shadow highlight GUI according to shMethod combobox state + updateShadowGUI2(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshMethod, + shMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabShadow::inversshChanged() +{ + // Update shadow highlight GUI according to inverssh button state + updateShadowGUI1(); + + // This event is called to transmit potentially reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (inverssh->get_active()) { + listener->panelChanged(Evlocallabinverssh, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabinverssh, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabShadow::showmaskSHMethodChanged() +{ + // If mask preview is activated, deactivate other Shadow highlight mask preview + showmaskSHMethodConninv.block(true); + showmaskSHMethodinv->set_active(0); + showmaskSHMethodConninv.block(false); + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabShadow::showmaskSHMethodChangedinv() +{ + // If mask preview is activated, deactivate other Shadow highlight mask preview + showmaskSHMethodConn.block(true); + showmaskSHMethod->set_active(0); + showmaskSHMethodConn.block(false); + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabShadow::enaSHMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaSHMask->get_active()) { + listener->panelChanged(EvLocallabEnaSHMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaSHMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabShadow::updateShadowGUI1() +{ + // Update shadow highlight GUI according to inverssh button state + if (inverssh->get_active()) { + expgradsh->hide(); + showmaskSHMethod->hide(); + // Reset hidden mask combobox + showmaskSHMethodConn.block(true); + showmaskSHMethod->set_active(0); + showmaskSHMethodConn.block(false); + showmaskSHMethodinv->show(); + } else { + expgradsh->show(); + showmaskSHMethod->show(); + showmaskSHMethodinv->hide(); + // Reset hidden mask combobox + showmaskSHMethodConninv.block(true); + showmaskSHMethodinv->set_active(0); + showmaskSHMethodConninv.block(false); + } +} + +void LocallabShadow::updateShadowGUI2() +{ + // Update shadow highlight GUI according to shMethod combobox state + if (shMethod->get_active_row_number() == 0) { + for (int i = 0; i < 5; i++) { + multipliersh[i]->hide(); + } + gamFrame->hide(); + detailSH->hide(); + highlights->show(); + h_tonalwidth->show(); + shadows->show(); + s_tonalwidth->show(); + sh_radius->show(); + } else if (shMethod->get_active_row_number() == 1) { + for (int i = 0; i < 5; i++) { + multipliersh[i]->show(); + } + gamFrame->show(); + + detailSH->show(); + highlights->hide(); + h_tonalwidth->hide(); + shadows->hide(); + s_tonalwidth->hide(); + sh_radius->hide(); + } +} + +/* ==== LocallabVibrance ==== */ +LocallabVibrance::LocallabVibrance(): + LocallabTool(this, M("TP_LOCALLAB_VIB_TOOLNAME"), M("TP_LOCALLAB_VIBRANCE"), false), + + // Vibrance specific widgets + saturated(Gtk::manage(new Adjuster(M("TP_VIBRANCE_SATURATED"), -100., 100., 1., 0.))), + pastels(Gtk::manage(new Adjuster(M("TP_VIBRANCE_PASTELS"), -100., 100., 1., 0.))), + warm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_WARM"), -100., 100., 1., 0., Gtk::manage(new RTImage("circle-blue-small.png")), Gtk::manage(new RTImage("circle-orange-small.png"))))), + psThreshold(Gtk::manage(new ThresholdAdjuster(M("TP_VIBRANCE_PSTHRESHOLD"), -100., 100., 0., M("TP_VIBRANCE_PSTHRESHOLD_WEIGTHING"), 0, 0., 100., 75., M("TP_VIBRANCE_PSTHRESHOLD_SATTHRESH"), 0, this, false))), + protectSkins(Gtk::manage(new Gtk::CheckButton(M("TP_VIBRANCE_PROTECTSKINS")))), + avoidColorShift(Gtk::manage(new Gtk::CheckButton(M("TP_VIBRANCE_AVOIDCOLORSHIFT")))), + pastSatTog(Gtk::manage(new Gtk::CheckButton(M("TP_VIBRANCE_PASTSATTOG")))), + sensiv(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 15))), + curveEditorGG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL"))), + skinTonesCurve(static_cast(curveEditorGG->addCurve(CT_Diagonal, M("TP_VIBRANCE_CURVEEDITOR_SKINTONES")))), + expgradvib(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPGRAD")))), + strvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -4., 4., 0.05, 0.))), + strvibab(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTRCHRO"), -4., 4., 0.05, 0.))), + strvibh(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTRHUE2"), -6., 6., 0.05, 0.))), + angvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180, 180, 0.1, 0.))), + expmaskvib(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWVI")))), + showmaskvibMethod(Gtk::manage(new MyComboBoxText())), + enavibMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + maskvibCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + lapmaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), + slomaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + mask2vibCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmaskvibshape(static_cast(mask2vibCurveEditorG->addCurve(CT_Diagonal, "L(L)"))) +{ + float R, G, B; + + const LocallabParams::LocallabSpot defSpot; + + // Parameter Vibrance specific widgets + saturated->setAdjusterListener(this); + + pastels->setAdjusterListener(this); + + warm->setAdjusterListener(this); + + psThreshold->set_tooltip_markup(M("TP_VIBRANCE_PSTHRESHOLD_TOOLTIP")); + psThreshold->setAdjusterListener(this); + + pskinsConn = protectSkins->signal_toggled().connect(sigc::mem_fun(*this, &LocallabVibrance::protectskins_toggled)); + + ashiftConn = avoidColorShift->signal_toggled().connect(sigc::mem_fun(*this, &LocallabVibrance::avoidcolorshift_toggled)); + + pastsattogConn = pastSatTog->signal_toggled().connect(sigc::mem_fun(*this, &LocallabVibrance::pastsattog_toggled)); + + sensiv->setAdjusterListener(this); + + curveEditorGG->setCurveListener(this); + + skinTonesCurve->setTooltip(M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_TOOLTIP")); + std::vector mskinTonesCurve; + // -0.1 rad < Hue < 1.6 rad + Color::hsv2rgb01(0.92f, 0.45f, 0.6f, R, G, B); + mskinTonesCurve.emplace_back(0.0, R, G, B); + Color::hsv2rgb01(0.14056f, 0.45f, 0.6f, R, G, B); + mskinTonesCurve.emplace_back(0.0, R, G, B); + skinTonesCurve->setBottomBarBgGradient(mskinTonesCurve); + skinTonesCurve->setLeftBarBgGradient(mskinTonesCurve); + skinTonesCurve->setRangeLabels( + M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE1"), M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE2"), + M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE3"), M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE4") + ); + skinTonesCurve->setRangeDefaultMilestones(0.1, 0.4, 0.85); + + curveEditorGG->curveListComplete(); + + setExpandAlignProperties(expgradvib, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + strvib->setAdjusterListener(this); + + strvibab->set_tooltip_text(M("TP_LOCALLAB_GRADSTRAB_TOOLTIP")); + strvibab->setAdjusterListener(this); + + strvibh->set_tooltip_text(M("TP_LOCALLAB_GRADSTRHUE_TOOLTIP")); + strvibh->setAdjusterListener(this); + + angvib->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + angvib->setAdjusterListener(this); + + setExpandAlignProperties(expmaskvib, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskvibMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskvibMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskvibMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskvibMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskvibMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskvibMethod->set_active(0); + showmaskvibMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskvibMethodConn = showmaskvibMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabVibrance::showmaskvibMethodChanged)); + + enavibMaskConn = enavibMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabVibrance::enavibMaskChanged)); + + maskvibCurveEditorG->setCurveListener(this); + + CCmaskvibshape->setIdentityValue(0.); + CCmaskvibshape->setResetCurve(FlatCurveType(defSpot.CCmaskvibcurve.at(0)), defSpot.CCmaskvibcurve); + CCmaskvibshape->setBottomBarColorProvider(this, 1); + + LLmaskvibshape->setIdentityValue(0.); + LLmaskvibshape->setResetCurve(FlatCurveType(defSpot.LLmaskvibcurve.at(0)), defSpot.LLmaskvibcurve); + LLmaskvibshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskvibshape->setIdentityValue(0.); + HHmaskvibshape->setResetCurve(FlatCurveType(defSpot.HHmaskvibcurve.at(0)), defSpot.HHmaskvibcurve); + HHmaskvibshape->setCurveColorProvider(this, 2); + HHmaskvibshape->setBottomBarColorProvider(this, 2); + + maskvibCurveEditorG->curveListComplete(); + + blendmaskvib->setAdjusterListener(this); + + radmaskvib->setLogScale(10, -10); + radmaskvib->setAdjusterListener(this); + + lapmaskvib->setAdjusterListener(this); + + chromaskvib->setAdjusterListener(this); + + gammaskvib->setAdjusterListener(this); + + slomaskvib->setAdjusterListener(this); + + mask2vibCurveEditorG->setCurveListener(this); + + Lmaskvibshape->setResetCurve(DiagonalCurveType(defSpot.Lmaskvibcurve.at(0)), defSpot.Lmaskvibcurve); + Lmaskvibshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmaskvibshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2vibCurveEditorG->curveListComplete(); + + // Add Vibrance specific widgets to GUI + pack_start(*saturated, Gtk::PACK_SHRINK, 0); + pack_start(*pastels, Gtk::PACK_SHRINK, 0); + pack_start(*warm, Gtk::PACK_SHRINK, 0); + pack_start(*psThreshold, Gtk::PACK_SHRINK, 0); + pack_start(*protectSkins, Gtk::PACK_SHRINK, 0); + pack_start(*avoidColorShift, Gtk::PACK_SHRINK, 0); + pack_start(*pastSatTog, Gtk::PACK_SHRINK, 0); +// pack_start(*sensiv, Gtk::PACK_SHRINK, 0); + pack_start(*curveEditorGG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + ToolParamBlock* const gradvibBox = Gtk::manage(new ToolParamBlock()); + gradvibBox->pack_start(*strvib); + gradvibBox->pack_start(*strvibab); + gradvibBox->pack_start(*strvibh); + gradvibBox->pack_start(*angvib); + expgradvib->add(*gradvibBox, false); + pack_start(*expgradvib); + ToolParamBlock* const maskvibBox = Gtk::manage(new ToolParamBlock()); + maskvibBox->pack_start(*showmaskvibMethod, Gtk::PACK_SHRINK, 4); + maskvibBox->pack_start(*enavibMask, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*maskvibCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + maskvibBox->pack_start(*blendmaskvib, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*radmaskvib, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*lapmaskvib, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*chromaskvib, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*gammaskvib, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*slomaskvib, Gtk::PACK_SHRINK, 0); + maskvibBox->pack_start(*mask2vibCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + expmaskvib->add(*maskvibBox, false); + pack_start(*expmaskvib, false, false); +} + +LocallabVibrance::~LocallabVibrance() +{ + delete curveEditorGG; + delete maskvibCurveEditorG; + delete mask2vibCurveEditorG; +} + +bool LocallabVibrance::isMaskViewActive() +{ + return (showmaskvibMethod->get_active_row_number() != 0); +} + +void LocallabVibrance::resetMaskView() +{ + showmaskvibMethodConn.block(true); + showmaskvibMethod->set_active(0); + showmaskvibMethodConn.block(false); +} + +void LocallabVibrance::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + vibMask = showmaskvibMethod->get_active_row_number(); +} + +void LocallabVibrance::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + warm->set_tooltip_text(M("TP_LOCALLAB_WARM_TOOLTIP")); + strvib->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + expmaskvib->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskvibshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskvibshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskvibshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + Lmaskvibshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + blendmaskvib->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2vibCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + } else { + warm->set_tooltip_text(""); + strvib->set_tooltip_text(""); + expmaskvib->set_tooltip_text(""); + CCmaskvibshape->setTooltip(""); + LLmaskvibshape->setTooltip(""); + HHmaskvibshape->setTooltip(""); + Lmaskvibshape->setTooltip(""); + blendmaskvib->set_tooltip_text(M("")); + mask2vibCurveEditorG->set_tooltip_text(M("")); + } +} + +void LocallabVibrance::setDefaultExpanderVisibility() +{ + expgradvib->set_expanded(false); + expmaskvib->set_expanded(false); +} + +void LocallabVibrance::disableListener() +{ + LocallabTool::disableListener(); + + pskinsConn.block(true); + ashiftConn.block(true); + pastsattogConn.block(true); + showmaskvibMethodConn.block(true); + enavibMaskConn.block(true); +} + +void LocallabVibrance::enableListener() +{ + LocallabTool::enableListener(); + + pskinsConn.block(false); + ashiftConn.block(false); + pastsattogConn.block(false); + showmaskvibMethodConn.block(false); + enavibMaskConn.block(false); +} + +void LocallabVibrance::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visivibrance); + exp->setEnabled(spot.expvibrance); + complexity->set_active(spot.complexvibrance); + + saturated->setValue(spot.saturated); + pastels->setValue(spot.pastels); + warm->setValue(spot.warm); + psThreshold->setValue(spot.psthreshold); + protectSkins->set_active(spot.protectskins); + avoidColorShift->set_active(spot.avoidcolorshift); + pastSatTog->set_active(spot.pastsattog); + sensiv->setValue(spot.sensiv); + skinTonesCurve->setCurve(spot.skintonescurve); + strvib->setValue(spot.strvib); + strvibab->setValue(spot.strvibab); + strvibh->setValue(spot.strvibh); + angvib->setValue(spot.angvib); + enavibMask->set_active(spot.enavibMask); + CCmaskvibshape->setCurve(spot.CCmaskvibcurve); + LLmaskvibshape->setCurve(spot.LLmaskvibcurve); + HHmaskvibshape->setCurve(spot.HHmaskvibcurve); + blendmaskvib->setValue(spot.blendmaskvib); + radmaskvib->setValue(spot.radmaskvib); + lapmaskvib->setValue(spot.lapmaskvib); + chromaskvib->setValue(spot.chromaskvib); + gammaskvib->setValue(spot.gammaskvib); + slomaskvib->setValue(spot.slomaskvib); + Lmaskvibshape->setCurve(spot.Lmaskvibcurve); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update vibrance GUI according to pastsattog button state + updateVibranceGUI(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabVibrance::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expvibrance = exp->getEnabled(); + spot.visivibrance = exp->get_visible(); + spot.complexvibrance = complexity->get_active_row_number(); + + spot.saturated = saturated->getIntValue(); + spot.pastels = pastels->getIntValue(); + spot.warm = warm->getIntValue(); + spot.psthreshold = psThreshold->getValue(); + spot.protectskins = protectSkins->get_active(); + spot.avoidcolorshift = avoidColorShift->get_active(); + spot.pastsattog = pastSatTog->get_active(); + spot.sensiv = sensiv->getIntValue(); + spot.skintonescurve = skinTonesCurve->getCurve(); + spot.strvib = strvib->getValue(); + spot.strvibab = strvibab->getValue(); + spot.strvibh = strvibh->getValue(); + spot.angvib = angvib->getValue(); + spot.enavibMask = enavibMask->get_active(); + spot.CCmaskvibcurve = CCmaskvibshape->getCurve(); + spot.LLmaskvibcurve = LLmaskvibshape->getCurve(); + spot.HHmaskvibcurve = HHmaskvibshape->getCurve(); + spot.blendmaskvib = blendmaskvib->getIntValue(); + spot.radmaskvib = radmaskvib->getValue(); + spot.lapmaskvib = lapmaskvib->getValue(); + spot.chromaskvib = chromaskvib->getValue(); + spot.gammaskvib = gammaskvib->getValue(); + spot.slomaskvib = slomaskvib->getValue(); + spot.Lmaskvibcurve = Lmaskvibshape->getCurve(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabVibrance::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster and threshold adjuster widgets + saturated->setDefault((double)defSpot.saturated); + pastels->setDefault((double)defSpot.pastels); + warm->setDefault((double)defSpot.warm); + psThreshold->setDefault(defSpot.psthreshold); + sensiv->setDefault((double)defSpot.sensiv); + strvib->setDefault(defSpot.strvib); + strvibab->setDefault(defSpot.strvibab); + strvibh->setDefault(defSpot.strvibh); + angvib->setDefault(defSpot.angvib); + blendmaskvib->setDefault((double)defSpot.blendmaskvib); + radmaskvib->setDefault(defSpot.radmaskvib); + lapmaskvib->setDefault(defSpot.lapmaskvib); + chromaskvib->setDefault(defSpot.chromaskvib); + gammaskvib->setDefault(defSpot.gammaskvib); + slomaskvib->setDefault(defSpot.slomaskvib); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabVibrance::adjusterChanged(Adjuster* a, double newval) +{ + // Copy pastels adjuster value to saturated one according to pastSatTog button state + if (a == pastels && pastSatTog->get_active()) { + saturated->setValue(newval); + } + + if (isLocActivated && exp->getEnabled()) { + if (a == saturated && !pastSatTog->get_active()) { + if (listener) { + listener->panelChanged(EvlocallabSaturated, + saturated->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == pastels) { + if (listener) { + listener->panelChanged(EvlocallabPastels, + pastels->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == warm) { + if (listener) { + listener->panelChanged(Evlocallabwarm, + warm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensiv) { + if (listener) { + listener->panelChanged(Evlocallabsensiv, + sensiv->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strvib) { + if (listener) { + listener->panelChanged(Evlocallabstrvib, + strvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strvibab) { + if (listener) { + listener->panelChanged(Evlocallabstrvibab, + strvibab->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strvibh) { + if (listener) { + listener->panelChanged(Evlocallabstrvibh, + strvibh->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == angvib) { + if (listener) { + listener->panelChanged(Evlocallabangvib, + angvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskvib) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskvi, + blendmaskvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskvib) { + if (listener) { + listener->panelChanged(Evlocallabradmaskvib, + radmaskvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskvib) { + if (listener) { + listener->panelChanged(Evlocallablapmaskvib, + lapmaskvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskvib) { + if (listener) { + listener->panelChanged(Evlocallabchromaskvib, + chromaskvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskvib) { + if (listener) { + listener->panelChanged(Evlocallabgammaskvib, + gammaskvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskvib) { + if (listener) { + listener->panelChanged(Evlocallabslomaskvib, + slomaskvib->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::adjusterChanged(ThresholdAdjuster* a, int newBottom, int newTop) +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabPastSatThreshold, + psThreshold->getHistoryString() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +std::vector LocallabVibrance::getCurvePoints(ThresholdSelector* tAdjuster) const +{ + std::vector points; + double threshold, transitionWeighting; + tAdjuster->getPositions(transitionWeighting, threshold); // ( range -100;+100, range 0;+100 ) + transitionWeighting /= 100.; // range -1., +1. + threshold /= 100.; // range 0., +1. + + // Initial point + points.push_back(0.); + points.push_back(0.); + + double p2 = 3.0 * threshold / 4.0; // same one than in ipvibrance.cc + double s0 = threshold + (1.0 - threshold) / 4.0; // same one than in ipvibrance.cc + + // point at the beginning of the first linear transition + points.push_back(p2); + points.push_back(0.); + + // Y value of the chroma mean point, calculated to get a straight line between p2 and s0 + double chromaMean = (threshold / 4.0) / (s0 - p2); + + // move chromaMean up or down depending on transitionWeighting + if (transitionWeighting > 0.0) { + // positive values -> give more weight to Saturated + chromaMean = (1.0 - chromaMean) * transitionWeighting + chromaMean; + } else if (transitionWeighting < 0.0) { + // negative values -> give more weight to Pastels + chromaMean = chromaMean * transitionWeighting + chromaMean; + } + + // point at the location of the Top cursor, at the end of the first linear transition and the beginning of the second one + points.push_back(threshold); + points.push_back(chromaMean); + + if (threshold < 1.0) { + // point at the end of the second linear transition + points.push_back(s0); + points.push_back(1.0); + + // end point + points.push_back(1.0); + points.push_back(1.0); + } + + return points; +} + +void LocallabVibrance::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == skinTonesCurve) { + if (listener) { + listener->panelChanged(EvlocallabSkinTonesCurve, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmaskvibshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskvibshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskvibshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskvibshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskvibshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskvibshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmaskvibshape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskvibshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenavibrance, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenashadhigh, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + saturated->setValue((double)defSpot.saturated); + psThreshold->setValue(defSpot.psthreshold); + protectSkins->set_active(defSpot.protectskins); + avoidColorShift->set_active(defSpot.avoidcolorshift); + pastSatTog->set_active(defSpot.pastsattog); + skinTonesCurve->setCurve(defSpot.skintonescurve); + strvibab->setValue(defSpot.strvibab); + strvibh->setValue(defSpot.strvibh); + lapmaskvib->setValue(defSpot.lapmaskvib); + gammaskvib->setValue(defSpot.gammaskvib); + slomaskvib->setValue(defSpot.slomaskvib); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update vibrance GUI according to pastsattog button state + updateVibranceGUI(); +} + +void LocallabVibrance::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + saturated->hide(); + pastels->setLabel(M("TP_LOCALLAB_PASTELS2")); + psThreshold->hide(); + protectSkins->hide(); + avoidColorShift->hide(); + pastSatTog->hide(); + curveEditorGG->hide(); + strvibab->hide(); + strvibh->hide(); + lapmaskvib->hide(); + gammaskvib->hide(); + slomaskvib->hide(); + } else { + // Advanced widgets are shown in Expert mode + saturated->show(); + pastels->setLabel(M("TP_VIBRANCE_PASTELS")); + psThreshold->show(); + protectSkins->show(); + avoidColorShift->show(); + pastSatTog->show(); + curveEditorGG->show(); + strvibab->show(); + strvibh->show(); + lapmaskvib->show(); + gammaskvib->show(); + slomaskvib->show(); + } +} + +void LocallabVibrance::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskvibshape->updateLocallabBackground(normChromar); + LLmaskvibshape->updateLocallabBackground(normLumar); + HHmaskvibshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabVibrance::protectskins_toggled() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (protectSkins->get_active()) { + listener->panelChanged(EvlocallabProtectSkins, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvlocallabProtectSkins, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::avoidcolorshift_toggled() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (avoidColorShift->get_active()) { + listener->panelChanged(EvlocallabAvoidColorShift, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvlocallabAvoidColorShift, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::pastsattog_toggled() +{ + // Update vibrance GUI according to pastsattog button state + updateVibranceGUI(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (pastSatTog->get_active()) { + listener->panelChanged(EvlocallabPastSatTog, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvlocallabPastSatTog, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::showmaskvibMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabVibrance::enavibMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enavibMask->get_active()) { + listener->panelChanged(EvLocallabEnavibMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnavibMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabVibrance::updateVibranceGUI() +{ + // Update vibrance GUI according to pastsattog button state + if (pastSatTog->get_active()) { + // Link both slider, so we set saturated and psThresholds unsensitive + psThreshold->set_sensitive(false); + saturated->set_sensitive(false); + saturated->setValue(pastels->getValue()); // Pastels and Saturated are linked + } else { + // Separate sliders, so we set saturated and psThresholds sensitive again + psThreshold->set_sensitive(true); + saturated->set_sensitive(true); + } +} + +/* ==== LocallabSoft ==== */ +LocallabSoft::LocallabSoft(): + LocallabTool(this, M("TP_LOCALLAB_SOFT_TOOLNAME"), M("TP_LOCALLAB_SOFT"), false), + + // Soft light specific widgets + softMethod(Gtk::manage(new MyComboBoxText())), + ctboxsoftmethod(Gtk::manage(new Gtk::HBox())), + showmasksoftMethod(Gtk::manage(new MyComboBoxText())), + streng(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRENG"), 1, 100, 1, 1))), + laplace(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPLACE"), 0., 100., 0.5, 25.))), + sensisf(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 1, 100, 1, 30))) +{ + // Parameter Soft light specific widgets + softMethod->append(M("TP_LOCALLAB_SOFTM")); + softMethod->append(M("TP_LOCALLAB_RETIM")); + softMethod->set_active(0); + softMethodConn = softMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabSoft::softMethodChanged)); + + showmasksoftMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmasksoftMethod->append(M("TP_LOCALLAB_SHOWLAPLACE")); + showmasksoftMethod->append(M("TP_LOCALLAB_SHOWFOURIER")); + showmasksoftMethod->append(M("TP_LOCALLAB_SHOWPOISSON")); + showmasksoftMethod->append(M("TP_LOCALLAB_SHOWNORMAL")); + showmasksoftMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmasksoftMethod->set_active(0); +// showmasksoftMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP")); + showmasksoftMethodConn = showmasksoftMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabSoft::showmasksoftMethodChanged)); + + streng->setAdjusterListener(this); + + laplace->setAdjusterListener(this); + + sensisf->setAdjusterListener(this); + + // Add Soft light specific widgets to GUI + pack_start(*softMethod); + Gtk::Label* const labelsoftmethod = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_SHOWDCT") + ":")); + ctboxsoftmethod->pack_start(*labelsoftmethod, Gtk::PACK_SHRINK, 4); + ctboxsoftmethod->pack_start(*showmasksoftMethod); + pack_start(*ctboxsoftmethod); + pack_start(*streng); + pack_start(*laplace); + pack_start(*sensisf); +} + +bool LocallabSoft::isMaskViewActive() +{ + return (showmasksoftMethod->get_active_row_number() != 0); +} + +void LocallabSoft::resetMaskView() +{ + showmasksoftMethodConn.block(true); + showmasksoftMethod->set_active(0); + showmasksoftMethodConn.block(false); +} + +void LocallabSoft::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + softMask = showmasksoftMethod->get_active_row_number(); +} + +void LocallabSoft::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + softMethod->set_tooltip_markup(M("TP_LOCALLAB_SOFTMETHOD_TOOLTIP")); + // ctboxsoftmethod->set_tooltip_markup(M("TP_LOCALLAB_ORRETISTEP_TOOLTIP")); + showmasksoftMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP")); + streng->set_tooltip_text(M("TP_LOCALLAB_ORRETISTREN_TOOLTIP")); + laplace->set_tooltip_text(M("TP_LOCALLAB_ORRETILAP_TOOLTIP")); + } else { + softMethod->set_tooltip_markup(M("")); + // ctboxsoftmethod->set_tooltip_markup(M("")); + showmasksoftMethod->set_tooltip_markup(M("")); + streng->set_tooltip_text(M("")); + laplace->set_tooltip_text(M("")); + } +} + +void LocallabSoft::disableListener() +{ + LocallabTool::disableListener(); + + softMethodConn.block(true); + showmasksoftMethodConn.block(true); +} + +void LocallabSoft::enableListener() +{ + LocallabTool::enableListener(); + + softMethodConn.block(false); + showmasksoftMethodConn.block(false); +} + +void LocallabSoft::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visisoft); + exp->setEnabled(spot.expsoft); + complexity->set_active(spot.complexsoft); + + if (spot.softMethod == "soft") { + softMethod->set_active(0); + } else if (spot.softMethod == "reti") { + softMethod->set_active(1); + } + + streng->setValue((double)spot.streng); + sensisf->setValue((double)spot.sensisf); + laplace->setValue(spot.laplace); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update soft light GUI according to softMethod combobox + updateSoftGUI(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabSoft::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expsoft = exp->getEnabled(); + spot.visisoft = exp->get_visible(); + spot.complexsoft = complexity->get_active_row_number(); + + if (softMethod->get_active_row_number() == 0) { + spot.softMethod = "soft"; + } else if (softMethod->get_active_row_number() == 1) { + spot.softMethod = "reti"; + } + + spot.streng = streng->getIntValue(); + spot.sensisf = sensisf->getIntValue(); + spot.laplace = laplace->getValue(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabSoft::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default value for adjuster widgets + streng->setDefault((double)defSpot.streng); + laplace->setDefault(defSpot.laplace); + sensisf->setDefault((double)defSpot.sensisf); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabSoft::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == streng) { + if (listener) { + listener->panelChanged(Evlocallabstreng, + streng->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensisf) { + if (listener) { + listener->panelChanged(Evlocallabsensisf, + sensisf->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == laplace) { + if (listener) { + listener->panelChanged(Evlocallablaplace, + laplace->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabSoft::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenasoft, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenasoft, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabSoft::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + if (defSpot.softMethod == "soft") { + softMethod->set_active(0); + } else if (defSpot.softMethod == "reti") { + softMethod->set_active(1); + } + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update soft light GUI according to softMethod combobox + updateSoftGUI(); +} + +void LocallabSoft::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + softMethod->hide(); + } else { + // Advanced widgets are shown in Expert mode + softMethod->show(); + } +} + +void LocallabSoft::softMethodChanged() +{ + // Update soft light GUI according to softMethod combobox + updateSoftGUI(); + + // This event is called to transmit potentially reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabsoftMethod, + softMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabSoft::showmasksoftMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabSoft::updateSoftGUI() +{ + // Update soft light GUI according to softMethod combobox + if (softMethod->get_active_row_number() == 0) { + ctboxsoftmethod->hide(); + // Reset hidden mask combobox + showmasksoftMethodConn.block(true); + showmasksoftMethod->set_active(0); + showmasksoftMethodConn.block(false); + laplace->hide(); + } else { + ctboxsoftmethod->show(); + laplace->show(); + } +} + +/* ==== LocallabBlur ==== */ +LocallabBlur::LocallabBlur(): + LocallabTool(this, M("TP_LOCALLAB_BLUR_TOOLNAME"), M("TP_LOCALLAB_BLUFR"), true), + + // Blur, Noise & Denoise specific widgets + expblnoise(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_BLNOI_EXP")))), + blMethod(Gtk::manage(new MyComboBoxText())), + fftwbl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FFTWBLUR")))), + radius(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADIUS"), MINRAD, MAXRAD, 0.1, 1.5, nullptr, nullptr, &blurSlider2radius, &blurRadius2Slider))), + strength(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRENGTH"), 0, 100, 1, 0))), + grainFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRAINFRA")))), + isogr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_ISOGR"), 20, 6400, 1, 0))), + strengr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRENGR"), 0, 100, 1, 0))), + scalegr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCALEGR"), 0, 100, 1, 100))), + medMethod(Gtk::manage(new MyComboBoxText())), + itera(Gtk::manage(new Adjuster(M("TP_DIRPYRDENOISE_MEDIAN_PASSES"), 1, 4, 1, 1))), + guidbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GUIDBL"), 0, 1000, 1, 0))), + strbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRBL"), 0, 100, 1, 50))), + epsbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_EPSBL"), -10, 10, 1, 0))), + sensibn(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIBN"), 0, 100, 1, 40))), + blurMethod(Gtk::manage(new MyComboBoxText())), + chroMethod(Gtk::manage(new MyComboBoxText())), + activlum(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ACTIV")))), + expdenoise(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOI_EXP")))), + LocalcurveEditorwavden(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVDEN"))), + wavshapeden(static_cast(LocalcurveEditorwavden->addCurve(CT_Flat, "", nullptr, false, false))), + noiselumf0(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINEZERO"), MINCHRO, MAXCHRO, 0.01, 0.))), + noiselumf(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINE"), MINCHRO, MAXCHRO, 0.01, 0.))), + noiselumf2(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINETWO"), MINCHRO, MAXCHRO, 0.01, 0.))), + noiselumc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMCOARSE"), MINCHRO, MAXCHROCC, 0.01, 0.))), + noiselumdetail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMDETAIL"), 0., 100., 0.01, 0.))), + noiselequal(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELEQUAL"), -2, 10, 1, 7, Gtk::manage(new RTImage("circle-white-small.png")), Gtk::manage(new RTImage("circle-black-small.png"))))), + noisechrof(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHROFINE"), MINCHRO, MAXCHRO, 0.01, 0.))), + noisechroc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHROCOARSE"), MINCHRO, MAXCHROCC, 0.01, 0.))), + noisechrodetail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHRODETAIL"), 0., 100., 0.01, 0.))), + detailthr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAILTHR"), 0, 100, 1, 0))), + adjblur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_ADJ"), -100., 100., 1., 0., Gtk::manage(new RTImage("circle-blue-yellow-small.png")), Gtk::manage(new RTImage("circle-red-green-small.png"))))), + bilateral(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BILATERAL"), 0, 100, 1, 0))), + sensiden(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIDEN"), 0, 100, 1, 60))), + expmaskbl(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWPLUS")))), + showmaskblMethod(Gtk::manage(new MyComboBoxText())), + showmaskblMethodtyp(Gtk::manage(new MyComboBoxText())), + enablMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + maskblCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + strumaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUMASKCOL"), 0., 200., 0.1, 0.))), + toolbl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TOOLCOL")))), + blendmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + lapmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.05, 5.0, 0.01, 1.))), + slomaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + shadmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_HIGHMASKCOL"), 0, 100, 1, 0))), + shadmaskblsha(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHAMASKCOL"), 0, 100, 1, 0))), + mask2blCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + Lmaskblshape(static_cast(mask2blCurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + mask2blCurveEditorGwav(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVMASK"))), + LLmaskblshapewav(static_cast(mask2blCurveEditorGwav->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + csThresholdblur(Gtk::manage(new ThresholdAdjuster(M("TP_LOCALLAB_CSTHRESHOLDBLUR"), 0, 9, 0, 0, 6, 5, 0, false))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Blur, Noise & Denoise specific widgets + setExpandAlignProperties(expblnoise, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + blMethod->append(M("TP_LOCALLAB_BLUR")); + blMethod->append(M("TP_LOCALLAB_BLMED")); + blMethod->append(M("TP_LOCALLAB_BLGUID")); + blMethod->set_active(0); + blMethodConn = blMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::blMethodChanged)); + + fftwblConn = fftwbl->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::fftwblChanged)); + + radius->setAdjusterListener(this); + + strength->setAdjusterListener(this); + + grainFrame->set_label_align(0.025, 0.5); + + isogr->setAdjusterListener(this); + + strengr->setAdjusterListener(this); + + scalegr->setAdjusterListener(this); + + medMethod->append(M("TP_LOCALLAB_MEDNONE")); + medMethod->append(M("TP_DIRPYRDENOISE_TYPE_3X3")); + medMethod->append(M("TP_DIRPYRDENOISE_TYPE_5X5")); + medMethod->append(M("TP_DIRPYRDENOISE_TYPE_7X7")); + medMethod->append(M("TP_DIRPYRDENOISE_TYPE_9X9")); + medMethod->set_active(0); + medMethodConn = medMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::medMethodChanged)); + + itera->setAdjusterListener(this); + + guidbl->setLogScale(100, 0); + guidbl->setAdjusterListener(this); + + strbl->setAdjusterListener(this); + + epsbl->setAdjusterListener(this); + + sensibn->setAdjusterListener(this); + + blurMethod->append(M("TP_LOCALLAB_BLNORM")); + blurMethod->append(M("TP_LOCALLAB_BLINV")); + blurMethod->set_active(0); + blurMethodConn = blurMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::blurMethodChanged)); + + chroMethod->append(M("TP_LOCALLAB_BLLO")); + chroMethod->append(M("TP_LOCALLAB_BLCO")); + chroMethod->append(M("TP_LOCALLAB_BLLC")); + chroMethod->set_active(0); + chroMethodConn = chroMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::chroMethodChanged)); + + activlumConn = activlum->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::activlumChanged)); + + setExpandAlignProperties(expdenoise, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + LocalcurveEditorwavden->setCurveListener(this); + + wavshapeden->setIdentityValue(0.); + wavshapeden->setResetCurve(FlatCurveType(defSpot.locwavcurveden.at(0)), defSpot.locwavcurveden); + + LocalcurveEditorwavden->curveListComplete(); + + noiselumf0->setAdjusterListener(this); + + noiselumf->setAdjusterListener(this); + + noiselumf2->setAdjusterListener(this); + + noiselumc->setAdjusterListener(this); + + noiselumdetail->setAdjusterListener(this); + + noiselequal->setAdjusterListener(this); + + noisechrof->setAdjusterListener(this); + + noisechroc->set_tooltip_text(M("TP_LOCALLAB_NOISECHROC_TOOLTIP")); + noisechroc->setAdjusterListener(this); + + noisechrodetail->setAdjusterListener(this); + + detailthr->setAdjusterListener(this); + + adjblur->setAdjusterListener(this); + + bilateral->setAdjusterListener(this); + + sensiden->setAdjusterListener(this); + + setExpandAlignProperties(expmaskbl, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskblMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskblMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskblMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskblMethod->append(M("TP_LOCALLAB_SHOWMASK")); +// showmaskblMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskblMethod->set_active(0); + showmaskblMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskblMethodConn = showmaskblMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::showmaskblMethodChanged)); + + showmaskblMethodtyp->append(M("TP_LOCALLAB_SHOWMASKTYP1")); + showmaskblMethodtyp->append(M("TP_LOCALLAB_SHOWMASKTYP2")); + showmaskblMethodtyp->append(M("TP_LOCALLAB_SHOWMASKTYP3")); + showmaskblMethodtyp->set_active(0); + showmaskblMethodtypConn = showmaskblMethodtyp->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::showmaskblMethodtypChanged)); + + enablMaskConn = enablMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::enablMaskChanged)); + + maskblCurveEditorG->setCurveListener(this); + + CCmaskblshape->setIdentityValue(0.); + CCmaskblshape->setResetCurve(FlatCurveType(defSpot.CCmaskblcurve.at(0)), defSpot.CCmaskblcurve); + CCmaskblshape->setBottomBarColorProvider(this, 1); + + LLmaskblshape->setIdentityValue(0.); + LLmaskblshape->setResetCurve(FlatCurveType(defSpot.LLmaskblcurve.at(0)), defSpot.LLmaskblcurve); + LLmaskblshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskblshape->setIdentityValue(0.); + HHmaskblshape->setResetCurve(FlatCurveType(defSpot.HHmaskblcurve.at(0)), defSpot.HHmaskblcurve); + HHmaskblshape->setCurveColorProvider(this, 2); + HHmaskblshape->setBottomBarColorProvider(this, 2); + + maskblCurveEditorG->curveListComplete(); + + strumaskbl->setAdjusterListener(this); + + toolblConn = toolbl->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::toolblChanged)); + + blendmaskbl->setAdjusterListener(this); + + radmaskbl->setAdjusterListener(this); + + lapmaskbl->setAdjusterListener(this); + + chromaskbl->setAdjusterListener(this); + + gammaskbl->setAdjusterListener(this); + + slomaskbl->setAdjusterListener(this); + + shadmaskbl->setAdjusterListener(this); + + shadmaskblsha->setAdjusterListener(this); + + mask2blCurveEditorG->setCurveListener(this); + + Lmaskblshape->setResetCurve(DiagonalCurveType(defSpot.Lmaskblcurve.at(0)), defSpot.Lmaskblcurve); + Lmaskblshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmaskblshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + mask2blCurveEditorG->curveListComplete(); + + mask2blCurveEditorGwav->setCurveListener(this); + + LLmaskblshapewav->setIdentityValue(0.); + LLmaskblshapewav->setResetCurve(FlatCurveType(defSpot.LLmaskblcurvewav.at(0)), defSpot.LLmaskblcurvewav); + LLmaskblshapewav->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2blCurveEditorGwav->curveListComplete(); + + csThresholdblur->setAdjusterListener(this); + + // Add Blur, Noise & Denoise specific widgets to GUI + ToolParamBlock* const blnoisebox = Gtk::manage(new ToolParamBlock()); + blnoisebox->pack_start(*blMethod); + blnoisebox->pack_start(*fftwbl, Gtk::PACK_SHRINK, 0); + blnoisebox->pack_start(*radius); + blnoisebox->pack_start(*strength); + ToolParamBlock* const grainBox = Gtk::manage(new ToolParamBlock()); + grainBox->pack_start(*isogr); + grainBox->pack_start(*strengr); + grainBox->pack_start(*scalegr); + grainFrame->add(*grainBox); + blnoisebox->pack_start(*grainFrame); + blnoisebox->pack_start(*medMethod); + blnoisebox->pack_start(*itera); + blnoisebox->pack_start(*guidbl); + blnoisebox->pack_start(*strbl); + blnoisebox->pack_start(*epsbl); + blnoisebox->pack_start(*sensibn); + blnoisebox->pack_start(*blurMethod); + blnoisebox->pack_start(*chroMethod); + // blnoisebox->pack_start(*activlum); + expblnoise->add(*blnoisebox, false); + pack_start(*expblnoise); + ToolParamBlock* const denoisebox = Gtk::manage(new ToolParamBlock()); + Gtk::Frame* const wavFrame = Gtk::manage(new Gtk::Frame()); + ToolParamBlock* const wavBox = Gtk::manage(new ToolParamBlock()); + wavBox->pack_start(*LocalcurveEditorwavden, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + // wavBox->pack_start(*noiselumf0); + // wavBox->pack_start(*noiselumf); + // wavBox->pack_start(*noiselumf2); + // wavBox->pack_start(*noiselumc); + wavBox->pack_start(*noiselumdetail); + wavBox->pack_start(*noiselequal); + wavBox->pack_start(*noisechrof); + wavBox->pack_start(*noisechroc); + wavBox->pack_start(*noisechrodetail); + wavBox->pack_start(*detailthr); + wavBox->pack_start(*adjblur); + wavFrame->add(*wavBox); + denoisebox->pack_start(*wavFrame); + denoisebox->pack_start(*bilateral); + denoisebox->pack_start(*sensiden); + expdenoise->add(*denoisebox, false); + pack_start(*expdenoise); + ToolParamBlock* const maskblBox = Gtk::manage(new ToolParamBlock()); + maskblBox->pack_start(*showmaskblMethod, Gtk::PACK_SHRINK, 4); + maskblBox->pack_start(*showmaskblMethodtyp, Gtk::PACK_SHRINK, 4); + maskblBox->pack_start(*enablMask, Gtk::PACK_SHRINK, 0); + maskblBox->pack_start(*maskblCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + maskblBox->pack_start(*strumaskbl, Gtk::PACK_SHRINK, 0); + maskblBox->pack_start(*toolbl, Gtk::PACK_SHRINK, 0); + Gtk::HSeparator* const separatorstrubl = Gtk::manage(new Gtk::HSeparator()); + maskblBox->pack_start(*separatorstrubl, Gtk::PACK_SHRINK, 2); + maskblBox->pack_start(*blendmaskbl, Gtk::PACK_SHRINK, 0); + Gtk::Frame* const toolblFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK"))); + toolblFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const toolblBox = Gtk::manage(new ToolParamBlock()); + toolblBox->pack_start(*radmaskbl, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*lapmaskbl, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*chromaskbl, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*gammaskbl, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*slomaskbl, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*shadmaskblsha, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*shadmaskbl, Gtk::PACK_SHRINK, 0); + toolblBox->pack_start(*mask2blCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolblBox->pack_start(*mask2blCurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolblBox->pack_start(*csThresholdblur, Gtk::PACK_SHRINK, 0); + toolblFrame->add(*toolblBox); + maskblBox->pack_start(*toolblFrame); + expmaskbl->add(*maskblBox, false); + pack_start(*expmaskbl); +} + +LocallabBlur::~LocallabBlur() +{ + delete maskblCurveEditorG; + delete mask2blCurveEditorG; + delete mask2blCurveEditorGwav; + delete LocalcurveEditorwavden; +} + +bool LocallabBlur::isMaskViewActive() +{ + return (showmaskblMethod->get_active_row_number() != 0); +} + +void LocallabBlur::resetMaskView() +{ + showmaskblMethodConn.block(true); + showmaskblMethod->set_active(0); + showmaskblMethodConn.block(false); +} + +void LocallabBlur::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + blMask = showmaskblMethod->get_active_row_number(); +} + +void LocallabBlur::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + expblnoise->set_tooltip_markup(M("TP_LOCALLAB_BLUMETHOD_TOOLTIP")); + radius->set_tooltip_text(M("TP_LOCALLAB_RADIUS_TOOLTIP")); + sensibn->set_tooltip_text(M("TP_LOCALLAB_SENSIH_TOOLTIP")); + blurMethod->set_tooltip_markup(M("TP_LOCALLAB_BLMETHOD_TOOLTIP")); + expdenoise->set_tooltip_markup(M("TP_LOCALLAB_DENOI_TOOLTIP")); + wavshapeden->setTooltip(M("TP_LOCALLAB_WASDEN_TOOLTIP")); + noiselumc->set_tooltip_text(M("TP_LOCALLAB_NOISECHROC_TOOLTIP")); + expmaskbl->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskblshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskblshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskblshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + radmaskbl->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskbl->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + Lmaskblshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + LLmaskblshapewav->setTooltip(M("TP_LOCALLAB_LMASK_LEVEL_TOOLTIP")); + blendmaskbl->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + showmaskblMethodtyp->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKTYP_TOOLTIP")); + } else { + expblnoise->set_tooltip_text(""); + radius->set_tooltip_text(""); + sensibn->set_tooltip_text(""); + blurMethod->set_tooltip_text(""); + expdenoise->set_tooltip_text(""); + wavshapeden->setTooltip(""); + noiselumc->set_tooltip_text(""); + expmaskbl->set_tooltip_text(""); + CCmaskblshape->setTooltip(""); + LLmaskblshape->setTooltip(""); + HHmaskblshape->setTooltip(""); + radmaskbl->set_tooltip_text(""); + lapmaskbl->set_tooltip_text(""); + Lmaskblshape->setTooltip(""); + LLmaskblshapewav->setTooltip(""); + blendmaskbl->set_tooltip_text(M("")); + showmaskblMethodtyp->set_tooltip_markup(M("")); + } +} + +void LocallabBlur::setDefaultExpanderVisibility() +{ + expblnoise->set_expanded(false); + expdenoise->set_expanded(false); + expmaskbl->set_expanded(false); +} + +void LocallabBlur::disableListener() +{ + LocallabTool::disableListener(); + + blMethodConn.block(true); + fftwblConn.block(true); + medMethodConn.block(true); + blurMethodConn.block(true); + chroMethodConn.block(true); + activlumConn.block(true); + showmaskblMethodConn.block(true); + showmaskblMethodtypConn.block(true); + enablMaskConn.block(true); + toolblConn.block(true); +} + +void LocallabBlur::enableListener() +{ + LocallabTool::enableListener(); + + blMethodConn.block(false); + fftwblConn.block(false); + medMethodConn.block(false); + blurMethodConn.block(false); + chroMethodConn.block(false); + activlumConn.block(false); + showmaskblMethodConn.block(false); + showmaskblMethodtypConn.block(false); + enablMaskConn.block(false); + toolblConn.block(false); +} + +void LocallabBlur::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visiblur); + exp->setEnabled(spot.expblur); + complexity->set_active(spot.complexblur); + + if (spot.blMethod == "blur") { + blMethod->set_active(0); + } else if (spot.blMethod == "med") { + blMethod->set_active(1); + } else if (spot.blMethod == "guid") { + blMethod->set_active(2); + } + + fftwbl->set_active(spot.fftwbl); + radius->setValue(spot.radius); + strength->setValue(spot.strength); + isogr->setValue((double)spot.isogr); + strengr->setValue((double)spot.strengr); + scalegr->setValue((double)spot.scalegr); + + if (spot.medMethod == "none") { + medMethod->set_active(0); + } else if (spot.medMethod == "33") { + medMethod->set_active(1); + } else if (spot.medMethod == "55") { + medMethod->set_active(2); + } else if (spot.medMethod == "77") { + medMethod->set_active(3); + } else if (spot.medMethod == "99") { + medMethod->set_active(4); + } + + itera->setValue((double)spot.itera); + guidbl->setValue((double)spot.guidbl); + strbl->setValue((double)spot.strbl); + epsbl->setValue((double)spot.epsbl); + sensibn->setValue((double)spot.sensibn); + + if (spot.blurMethod == "norm") { + blurMethod->set_active(0); + } else if (spot.blurMethod == "inv") { + blurMethod->set_active(1); + } + + if (spot.chroMethod == "lum") { + chroMethod->set_active(0); + } else if (spot.chroMethod == "chr") { + chroMethod->set_active(1); + } else if (spot.chroMethod == "all") { + chroMethod->set_active(2); + } + + + if (spot.showmaskblMethodtyp == "blur") { + showmaskblMethodtyp ->set_active(0); + } else if (spot.showmaskblMethodtyp == "nois") { + showmaskblMethodtyp->set_active(1); + } else if (spot.showmaskblMethodtyp == "all") { + showmaskblMethodtyp->set_active(2); + } + + activlum->set_active(spot.activlum); + wavshapeden->setCurve(spot.locwavcurveden); + noiselumf0->setValue(spot.noiselumf0); + noiselumf->setValue(spot.noiselumf); + noiselumf2->setValue(spot.noiselumf2); + noiselumc->setValue(spot.noiselumc); + noiselumdetail->setValue(spot.noiselumdetail); + noiselequal->setValue((double)spot.noiselequal); + noisechrof->setValue(spot.noisechrof); + noisechroc->setValue(spot.noisechroc); + noisechrodetail->setValue(spot.noisechrodetail); + detailthr->setValue((double)spot.detailthr); + adjblur->setValue((double)spot.adjblur); + bilateral->setValue((double)spot.bilateral); + sensiden->setValue((double)spot.sensiden); + enablMask->set_active(spot.enablMask); + CCmaskblshape->setCurve(spot.CCmaskblcurve); + LLmaskblshape->setCurve(spot.LLmaskblcurve); + HHmaskblshape->setCurve(spot.HHmaskblcurve); + strumaskbl->setValue(spot.strumaskbl); + toolbl->set_active(spot.toolbl); + blendmaskbl->setValue((double)spot.blendmaskbl); + radmaskbl->setValue(spot.radmaskbl); + lapmaskbl->setValue(spot.lapmaskbl); + chromaskbl->setValue(spot.chromaskbl); + gammaskbl->setValue(spot.gammaskbl); + slomaskbl->setValue(spot.slomaskbl); + shadmaskbl->setValue((double)spot.shadmaskbl); + shadmaskblsha->setValue((double)spot.shadmaskblsha); + Lmaskblshape->setCurve(spot.Lmaskblcurve); + LLmaskblshapewav->setCurve(spot.LLmaskblcurvewav); + csThresholdblur->setValue(spot.csthresholdblur); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update Blur & Noise GUI according to blMethod combobox state + updateBlurGUI(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabBlur::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expblur = exp->getEnabled(); + spot.visiblur = exp->get_visible(); + spot.complexblur = complexity->get_active_row_number(); + + if (blMethod->get_active_row_number() == 0) { + spot.blMethod = "blur"; + } else if (blMethod->get_active_row_number() == 1) { + spot.blMethod = "med"; + } else if (blMethod->get_active_row_number() == 2) { + spot.blMethod = "guid"; + } + + spot.fftwbl = fftwbl->get_active(); + spot.radius = radius->getValue(); + spot.strength = strength->getIntValue(); + spot.isogr = isogr->getIntValue(); + spot.strengr = strengr->getIntValue(); + spot.scalegr = scalegr->getIntValue(); + + if (medMethod->get_active_row_number() == 0) { + spot.medMethod = "none"; + } else if (medMethod->get_active_row_number() == 1) { + spot.medMethod = "33"; + } else if (medMethod->get_active_row_number() == 2) { + spot.medMethod = "55"; + } else if (medMethod->get_active_row_number() == 3) { + spot.medMethod = "77"; + } else if (medMethod->get_active_row_number() == 4) { + spot.medMethod = "99"; + } + + spot.itera = itera->getIntValue(); + spot.guidbl = guidbl->getIntValue(); + spot.strbl = strbl->getIntValue(); + spot.epsbl = epsbl->getIntValue(); + spot.sensibn = sensibn->getIntValue(); + + if (blurMethod->get_active_row_number() == 0) { + spot.blurMethod = "norm"; + } else if (blurMethod->get_active_row_number() == 1) { + spot.blurMethod = "inv"; + } + + if (chroMethod->get_active_row_number() == 0) { + spot.chroMethod = "lum"; + } else if (chroMethod->get_active_row_number() == 1) { + spot.chroMethod = "chr"; + } else if (chroMethod->get_active_row_number() == 2) { + spot.chroMethod = "all"; + } + + + if (showmaskblMethodtyp->get_active_row_number() == 0) { + spot.showmaskblMethodtyp = "blur"; + } else if (showmaskblMethodtyp->get_active_row_number() == 1) { + spot.showmaskblMethodtyp = "nois"; + } else if (showmaskblMethodtyp->get_active_row_number() == 2) { + spot.showmaskblMethodtyp = "all"; + } + + spot.activlum = activlum->get_active(); + spot.locwavcurveden = wavshapeden->getCurve(); + spot.noiselumf0 = noiselumf0->getValue(); + spot.noiselumf = noiselumf->getValue(); + spot.noiselumf2 = noiselumf2->getValue(); + spot.noiselumc = noiselumc->getValue(); + spot.noiselumdetail = noiselumdetail->getValue(); + spot.noiselequal = noiselequal->getIntValue(); + spot.noisechrof = noisechrof->getValue(); + spot.noisechroc = noisechroc->getValue(); + spot.noisechrodetail = noisechrodetail->getValue(); + spot.detailthr = detailthr->getIntValue(); + spot.adjblur = adjblur->getIntValue(); + spot.bilateral = bilateral->getIntValue(); + spot.sensiden = sensiden->getIntValue(); + spot.enablMask = enablMask->get_active(); + spot.LLmaskblcurve = LLmaskblshape->getCurve(); + spot.CCmaskblcurve = CCmaskblshape->getCurve(); + spot.HHmaskblcurve = HHmaskblshape->getCurve(); + spot.strumaskbl = strumaskbl->getValue(); + spot.toolbl = toolbl->get_active(); + spot.blendmaskbl = blendmaskbl->getIntValue(); + spot.radmaskbl = radmaskbl->getValue(); + spot.lapmaskbl = lapmaskbl->getValue(); + spot.chromaskbl = chromaskbl->getValue(); + spot.gammaskbl = gammaskbl->getValue(); + spot.slomaskbl = slomaskbl->getValue(); + spot.shadmaskbl = shadmaskbl->getIntValue(); + spot.shadmaskblsha = shadmaskblsha->getIntValue(); + spot.Lmaskblcurve = Lmaskblshape->getCurve(); + spot.LLmaskblcurvewav = LLmaskblshapewav->getCurve(); + spot.csthresholdblur = csThresholdblur->getValue(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabBlur::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default value for adjuster and threshold adjuster widgets + radius->setDefault(defSpot.radius); + strength->setDefault((double)defSpot.strength); + isogr->setDefault((double)defSpot.isogr); + strengr->setDefault((double)defSpot.strengr); + scalegr->setDefault((double)defSpot.scalegr); + itera->setDefault((double)defSpot.itera); + guidbl->setDefault((double)defSpot.guidbl); + strbl->setDefault((double)defSpot.strbl); + epsbl->setDefault((double)defSpot.epsbl); + sensibn->setDefault((double)defSpot.sensibn); + noiselumf0->setDefault(defSpot.noiselumf0); + noiselumf->setDefault(defSpot.noiselumf); + noiselumf2->setDefault(defSpot.noiselumf2); + noiselumc->setDefault(defSpot.noiselumc); + noiselumdetail->setDefault(defSpot.noiselumdetail); + noiselequal->setDefault((double)defSpot.noiselequal); + noisechrof->setDefault(defSpot.noisechrof); + noisechroc->setDefault(defSpot.noisechroc); + noisechrodetail->setDefault(defSpot.noisechrodetail); + detailthr->setDefault((double)defSpot.detailthr); + adjblur->setDefault((double)defSpot.adjblur); + bilateral->setDefault((double)defSpot.bilateral); + sensiden->setDefault((double)defSpot.sensiden); + strumaskbl->setDefault(defSpot.strumaskbl); + blendmaskbl->setDefault((double)defSpot.blendmaskbl); + radmaskbl->setDefault(defSpot.radmaskbl); + lapmaskbl->setDefault(defSpot.lapmaskbl); + chromaskbl->setDefault(defSpot.chromaskbl); + gammaskbl->setDefault(defSpot.gammaskbl); + slomaskbl->setDefault(defSpot.slomaskbl); + shadmaskbl->setDefault(defSpot.shadmaskbl); + shadmaskblsha->setDefault(defSpot.shadmaskblsha); + csThresholdblur->setDefault(defSpot.csthresholdblur); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabBlur::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == radius) { + if (listener) { + listener->panelChanged(Evlocallabradius, + radius->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strength) { + if (listener) { + listener->panelChanged(Evlocallabstrength, + strength->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == isogr) { + if (listener) { + listener->panelChanged(Evlocallabisogr, + isogr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strengr) { + if (listener) { + listener->panelChanged(Evlocallabstrengr, + strengr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == scalegr) { + if (listener) { + listener->panelChanged(Evlocallabscalegr, + scalegr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == itera) { + if (listener) { + listener->panelChanged(Evlocallabitera, + itera->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == guidbl) { + if (listener) { + listener->panelChanged(Evlocallabguidbl, + guidbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strbl) { + if (listener) { + listener->panelChanged(Evlocallabstrbl, + strbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == epsbl) { + if (listener) { + listener->panelChanged(Evlocallabepsbl, + epsbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensibn) { + if (listener) { + listener->panelChanged(Evlocallabsensibn, + sensibn->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noiselumf0) { + if (listener) { + listener->panelChanged(Evlocallabnoiselumf0, + noiselumf0->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noiselumf) { + if (listener) { + listener->panelChanged(Evlocallabnoiselumf, + noiselumf->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noiselumf2) { + if (listener) { + listener->panelChanged(Evlocallabnoiselumf2, + noiselumf2->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noiselumc) { + if (listener) { + listener->panelChanged(Evlocallabnoiselumc, + noiselumc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noiselumdetail) { + if (listener) { + listener->panelChanged(Evlocallabnoiselumdetail, + noiselumdetail->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noiselequal) { + if (listener) { + listener->panelChanged(Evlocallabnoiselequal, + noiselequal->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noisechrof) { + if (listener) { + listener->panelChanged(Evlocallabnoisechrof, + noisechrof->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noisechroc) { + if (listener) { + listener->panelChanged(Evlocallabnoisechroc, + noisechroc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == noisechrodetail) { + if (listener) { + listener->panelChanged(Evlocallabnoisechrodetail, + noisechrodetail->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == detailthr) { + if (listener) { + listener->panelChanged(Evlocallabdetailthr, + detailthr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == adjblur) { + if (listener) { + listener->panelChanged(Evlocallabadjblur, + adjblur->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == bilateral) { + if (listener) { + listener->panelChanged(Evlocallabbilateral, + bilateral->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensiden) { + if (listener) { + listener->panelChanged(Evlocallabsensiden, + sensiden->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strumaskbl) { + if (listener) { + listener->panelChanged(Evlocallabstrumaskbl, + strumaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskbl) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskbl, + blendmaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskbl) { + if (listener) { + listener->panelChanged(Evlocallabradmaskbl, + radmaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskbl) { + if (listener) { + listener->panelChanged(Evlocallablapmaskbl, + lapmaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskbl) { + if (listener) { + listener->panelChanged(Evlocallabchromaskbl, + chromaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskbl) { + if (listener) { + listener->panelChanged(Evlocallabgammaskbl, + gammaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskbl) { + if (listener) { + listener->panelChanged(Evlocallabslomaskbl, + slomaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shadmaskbl) { + if (listener) { + listener->panelChanged(Evlocallabshadmaskbl, + shadmaskbl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shadmaskblsha) { + if (listener) { + listener->panelChanged(Evlocallabshadmaskblsha, + shadmaskblsha->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + } +} + +void LocallabBlur::adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabcsThresholdblur, + csThresholdblur->getHistoryString() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabBlur::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == wavshapeden) { + if (listener) { + listener->panelChanged(EvlocallabwavCurveden, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmaskblshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskblshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskblshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskblshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskblshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskblshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmaskblshape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskblshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskblshapewav) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskblshapewav, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabBlur::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenablur, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenablur, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabBlur::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + fftwbl->set_active(defSpot.fftwbl); + strumaskbl->setValue(defSpot.strumaskbl); + toolbl->set_active(defSpot.toolbl); + lapmaskbl->setValue(defSpot.lapmaskbl); +// gammaskbl->setValue(defSpot.gammaskbl); +// slomaskbl->setValue(defSpot.slomaskbl); + shadmaskbl->setValue((double)defSpot.shadmaskbl); + shadmaskblsha->setValue((double)defSpot.shadmaskblsha); + LLmaskblshapewav->setCurve(defSpot.LLmaskblcurvewav); + csThresholdblur->setValue(defSpot.csthresholdblur); + + // Enable all listeners + enableListener(); +} + +void LocallabBlur::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + fftwbl->hide(); + strumaskbl->hide(); + toolbl->hide(); + lapmaskbl->hide(); + gammaskbl->show(); + slomaskbl->show(); + shadmaskbl->hide(); + shadmaskblsha->hide(); + mask2blCurveEditorGwav->hide(); + csThresholdblur->hide(); + } else { + // Advanced widgets are shown in Expert mode + if (blMethod->get_active_row_number() == 0) { // Keep widget hidden when blMethod is > 0 + fftwbl->show(); + } + + strumaskbl->show(); + toolbl->show(); + lapmaskbl->show(); + gammaskbl->show(); + slomaskbl->show(); + shadmaskbl->show(); + shadmaskblsha->show(); + mask2blCurveEditorGwav->show(); + csThresholdblur->show(); + } +} + +void LocallabBlur::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskblshape->updateLocallabBackground(normChromar); + LLmaskblshape->updateLocallabBackground(normLumar); + HHmaskblshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabBlur::blMethodChanged() +{ + // Update Blur & Noise GUI according to blMethod combobox state + updateBlurGUI(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabblMethod, + blMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabBlur::fftwblChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (fftwbl->get_active()) { + listener->panelChanged(Evlocallabfftwbl, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabfftwbl, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabBlur::medMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabmedMethod, + medMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabBlur::blurMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabblurMethod, + blurMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabBlur::chroMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabchroMethod, + chroMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabBlur::activlumChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (activlum->get_active()) { + listener->panelChanged(Evlocallabactivlum, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabactivlum, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabBlur::showmaskblMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabBlur::showmaskblMethodtypChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmasktypMethod, + showmaskblMethodtyp->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } +} + +void LocallabBlur::enablMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enablMask->get_active()) { + listener->panelChanged(EvLocallabEnablMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnablMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabBlur::toolblChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (toolbl->get_active()) { + listener->panelChanged(Evlocallabtoolbl, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabtoolbl, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabBlur::updateBlurGUI() +{ + if (blMethod->get_active_row_number() == 0) { + fftwbl->show(); + radius->show(); + strength->show(); + grainFrame->show(); + medMethod->hide(); + itera->hide(); + guidbl->hide(); + strbl->hide(); + epsbl->hide(); + activlum->show(); + } else if (blMethod->get_active_row_number() == 1) { + fftwbl->hide(); + radius->hide(); + strength->hide(); + grainFrame->hide(); + medMethod->show(); + itera->show(); + guidbl->hide(); + strbl->hide(); + epsbl->hide(); + activlum->show(); + } else if (blMethod->get_active_row_number() == 2) { + fftwbl->hide(); + radius->hide(); + strength->hide(); + grainFrame->hide(); + medMethod->hide(); + itera->hide(); + guidbl->show(); + strbl->show(); + epsbl->show(); + activlum->hide(); + } +} diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h new file mode 100644 index 000000000..4e6b30f00 --- /dev/null +++ b/rtgui/locallabtools.h @@ -0,0 +1,1199 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath frame + * + * + * 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 . + * 2019 Pierre Cabrera + */ +#ifndef _LOCALLABTOOLS_H_ +#define _LOCALLABTOOLS_H_ + +#include "curveeditorgroup.h" +#include "curveeditor.h" +#include "labgrid.h" +#include "thresholdadjuster.h" +#include "toolpanel.h" +#include "adjuster.h" + +/* ==== LocallabToolListener ==== */ +class LocallabTool; +class LocallabToolListener +{ +public: + LocallabToolListener() {}; + virtual ~LocallabToolListener() {}; + + virtual void resetOtherMaskView(LocallabTool* current) = 0; + virtual void toolRemoved(LocallabTool* current) = 0; +}; + + +/* ==== LocallabTool ==== */ +class LocallabTool: + public ToolPanel, + public CurveListener, + public ColorProvider, + public AdjusterListener +{ +protected: + // LocallabTool mode enumeration + enum modeType { + Expert = 0, + Normal = 1 + }; + + // LocallabTool parameters + bool needMode; + bool isLocActivated; + Glib::ustring spotName; + LocallabToolListener* locToolListener; + + // LocallabTool generic widgets + MyExpander* exp; + MyComboBoxText* const complexity; + + sigc::connection enaExpConn, complexityConn; + + IdleRegister idle_register; + +public: + // Locallab tool constructor/destructor + LocallabTool(Gtk::Box* content, Glib::ustring toolName, Glib::ustring UILabel, bool need11 = false, bool needMode = true); + virtual ~LocallabTool(); + + // Getter for Locallab tool expander + MyExpander* getExpander() override + { + return exp; + } + + // Getter/setter for Locallab tool expanded status + void setExpanded(bool expanded) override + { + exp->set_expanded(expanded); + } + + bool getExpanded() override + { + return exp->get_expanded(); + } + + // Setter for Locallab activation indicator + void isLocallabActivated(bool cond) + { + isLocActivated = cond; + } + + // Setter for spot name + void setSpotName(const Glib::ustring &spotname) + { + spotName = spotname; + } + + // Setter for Locallab tool listener + void setLocallabToolListener(LocallabToolListener* ltl) + { + locToolListener = ltl; + } + + // Management functions to add/remove Locallab tool + void addLocallabTool(bool raiseEvent); + void removeLocallabTool(bool raiseEvent); + bool isLocallabToolAdded(); + + // Mask background management function + void refChanged(const double huer, const double lumar, const double chromar); + + // Mask preview functions + virtual bool isMaskViewActive() + { + return false; + }; + virtual void resetMaskView() {}; + virtual void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) {}; + + // Advice tooltips management function + virtual void updateAdviceTooltips(const bool showTooltips) {}; + + /* Notes: + - callerId #1: Mask CC shape (bottom bar) + Color CC/LC shape (left bar) + - callerId #2: Mask HH shape (main curve and bottom bar) + - callerId #3: Color LH/HH shape (main curve) + - callerId #4: Color CC/LC shape (bottom bar) + */ + void colorForValue(double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) override; + + // To be implemented + virtual void setDefaultExpanderVisibility() {}; + virtual void disableListener(); + virtual void enableListener(); + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override {}; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override {}; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override {}; + void adjusterChanged(Adjuster* a, double newval) override {}; + void curveChanged(CurveEditor* ce) override {}; + +protected: + // To be implemented + virtual void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) {}; // Only necessary when using mask + +private: + // Remove button event function + bool on_remove_change(GdkEventButton* event); + + // Tool expander event function + void foldThemAll(GdkEventButton* event); + + // Complexity mode event function + void complexityModeChanged(); + + // To be implemented + virtual void enabledChanged() {}; + virtual void convertParamToNormal() {}; // Only necessary when using mode + virtual void updateGUIToMode(const modeType new_type) {}; // Only necessary when using mode +}; + +/* ==== LocallabColor ==== */ +class LocallabColor: + public Gtk::VBox, + public LocallabTool, + public ThresholdAdjusterListener +{ +private: + // Color & Light specific widgets + Gtk::CheckButton* const curvactiv; + Adjuster* const lightness; + Adjuster* const contrast; + Adjuster* const chroma; + Gtk::Frame* const gridFrame; + LabGrid* const labgrid; + MyComboBoxText* const gridMethod; + Adjuster* const strengthgrid; + Adjuster* const sensi; + Adjuster* const structcol; + Adjuster* const blurcolde; + Adjuster* const softradiuscol; + Gtk::CheckButton* const invers; + MyExpander* const expgradcol; + Adjuster* const strcol; + Adjuster* const strcolab; + Adjuster* const strcolh; + Adjuster* const angcol; + MyExpander* const expcurvcol; + Gtk::Label* const labqualcurv; + MyComboBoxText* const qualitycurveMethod; + CurveEditorGroup* const llCurveEditorG; + DiagonalCurveEditor* const llshape; + DiagonalCurveEditor* const ccshape; + CurveEditorGroup* const clCurveEditorG; + DiagonalCurveEditor* const clshape; + DiagonalCurveEditor* const lcshape; + CurveEditorGroup* const HCurveEditorG; + FlatCurveEditor* const LHshape; + CurveEditorGroup* const H2CurveEditorG; + FlatCurveEditor* const HHshape; + CurveEditorGroup* const rgbCurveEditorG; + MyComboBoxText* const toneMethod; + DiagonalCurveEditor* const rgbshape; + Gtk::CheckButton* const special; + MyExpander* const expmaskcol1; + MyComboBoxText* const merMethod; + ToolParamBlock* const mask7; + MyComboBoxText* const mergecolMethod; + Adjuster* const mercol; + Adjuster* const opacol; + Adjuster* const conthrcol; + Gtk::Frame* const gridmerFrame; + LabGrid* const labgridmerg; + Adjuster* const merlucol; + MyExpander* const expmaskcol; + MyComboBoxText* const showmaskcolMethod; + MyComboBoxText* const showmaskcolMethodinv; + Gtk::CheckButton* const enaColorMask; + CurveEditorGroup* const maskCurveEditorG; + FlatCurveEditor* const CCmaskshape; + FlatCurveEditor* const LLmaskshape; + FlatCurveEditor* const HHmaskshape; + Gtk::Frame* const struFrame; + Adjuster* const strumaskcol; + Gtk::CheckButton* const toolcol; + Gtk::Frame* const blurFrame; + Gtk::CheckButton* const fftColorMask; + Adjuster* const contcol; + Adjuster* const blurcol; + Adjuster* const blendmaskcol; + Adjuster* const radmaskcol; + Adjuster* const lapmaskcol; + Adjuster* const chromaskcol; + Adjuster* const gammaskcol; + Adjuster* const slomaskcol; + Adjuster* const shadmaskcol; + CurveEditorGroup* const maskHCurveEditorG; + FlatCurveEditor* const HHhmaskshape; + CurveEditorGroup* const mask2CurveEditorG; + DiagonalCurveEditor* const Lmaskshape; + CurveEditorGroup* const mask2CurveEditorGwav; + FlatCurveEditor* const LLmaskcolshapewav; + ThresholdAdjuster* const csThresholdcol; + + sigc::connection curvactivConn, gridMethodConn, inversConn, qualitycurveMethodConn, toneMethodConn, specialConn, merMethodConn, mergecolMethodConn, showmaskcolMethodConn, showmaskcolMethodConninv, enaColorMaskConn, toolcolConn, fftColorMaskConn; + +public: + LocallabColor(); + ~LocallabColor(); + + void setListener(ToolPanelListener* tpl) override; + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void adjusterChanged(ThresholdAdjuster* a, double newBottom, double newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, double newBottomLeft, double newTopLeft, double newBottomRight, double newTopRight) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottom, int newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) override {}; // Not used + void adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void curvactivChanged(); + void gridMethodChanged(); + void inversChanged(); + void qualitycurveMethodChanged(); + void toneMethodChanged(); + void specialChanged(); + void merMethodChanged(); + void mergecolMethodChanged(); + void showmaskcolMethodChanged(); + void showmaskcolMethodChangedinv(); + void enaColorMaskChanged(); + void toolcolChanged(); + void fftColorMaskChanged(); + + void updateColorGUI1(); + void updateColorGUI2(); + void updateColorGUI3(); +}; + +/* ==== LocallabExposure ==== */ +class LocallabExposure: + public Gtk::VBox, + public LocallabTool +{ +private: + // Exposure specific widgets + MyComboBoxText* const expMethod; + Gtk::Frame* const pdeFrame; + Adjuster* const laplacexp; + Adjuster* const linear; + Adjuster* const balanexp; + Adjuster* const gamm; + MyComboBoxText* const exnoiseMethod; + Gtk::Frame* const fatFrame; + Adjuster* const fatamount; + Adjuster* const fatdetail; + Adjuster* const fatlevel; + Adjuster* const fatanchor; + Adjuster* const sensiex; + Adjuster* const structexp; + Adjuster* const blurexpde; + MyExpander* const exptoolexp; + Adjuster* const expcomp; + Adjuster* const black; + Adjuster* const hlcompr; + Adjuster* const hlcomprthresh; + Adjuster* const shadex; + Adjuster* const shcompr; + Adjuster* const expchroma; + CurveEditorGroup* const curveEditorG; + DiagonalCurveEditor* shapeexpos; + MyExpander* const expgradexp; + Adjuster* const strexp; + Adjuster* const angexp; + Adjuster* const softradiusexp; + Gtk::CheckButton* const inversex; + MyExpander* const expmaskexp; + MyComboBoxText* const showmaskexpMethod; + MyComboBoxText* const showmaskexpMethodinv; + Gtk::CheckButton* const enaExpMask; + Gtk::CheckButton* const enaExpMaskaft; + CurveEditorGroup* const maskexpCurveEditorG; + FlatCurveEditor* const CCmaskexpshape; + FlatCurveEditor* const LLmaskexpshape; + FlatCurveEditor* const HHmaskexpshape; + Adjuster* const blendmaskexp; + Adjuster* const radmaskexp; + Adjuster* const lapmaskexp; + Adjuster* const chromaskexp; + Adjuster* const gammaskexp; + Adjuster* const slomaskexp; + Gtk::Frame* const gradFramemask; + Adjuster* const strmaskexp; + Adjuster* const angmaskexp; + CurveEditorGroup* const mask2expCurveEditorG; + DiagonalCurveEditor* const Lmaskexpshape; + + sigc::connection expMethodConn, exnoiseMethodConn, inversexConn, showmaskexpMethodConn, showmaskexpMethodConninv, enaExpMaskConn, enaExpMaskaftConn; + +public: + LocallabExposure(); + ~LocallabExposure(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void expMethodChanged(); + void exnoiseMethodChanged(); + void inversexChanged(); + void showmaskexpMethodChanged(); + void showmaskexpMethodChangedinv(); + void enaExpMaskChanged(); + void enaExpMaskaftChanged(); + + void updateExposureGUI1(); + void updateExposureGUI2(); + void updateExposureGUI3(); +}; + +/* ==== LocallabShadow ==== */ +class LocallabShadow: + public Gtk::VBox, + public LocallabTool +{ +private: + // Shadow highlight specific widgets + MyComboBoxText* const shMethod; + const std::array multipliersh; + Adjuster* const detailSH; + Adjuster* const highlights; + Adjuster* const h_tonalwidth; + Adjuster* const shadows; + Adjuster* const s_tonalwidth; + Adjuster* const sh_radius; + Adjuster* const sensihs; + Adjuster* const blurSHde; + Gtk::Frame* const gamFrame; + Adjuster* const gamSH; + Adjuster* const sloSH; + MyExpander* const expgradsh; + Adjuster* const strSH; + Adjuster* const angSH; + Gtk::CheckButton* const inverssh; + MyExpander* const expmasksh; + MyComboBoxText* const showmaskSHMethod; + MyComboBoxText* const showmaskSHMethodinv; + Gtk::CheckButton* const enaSHMask; + CurveEditorGroup* const maskSHCurveEditorG; + FlatCurveEditor* const CCmaskSHshape; + FlatCurveEditor* const LLmaskSHshape; + FlatCurveEditor* const HHmaskSHshape; + Adjuster* const blendmaskSH; + Adjuster* const radmaskSH; + Adjuster* const lapmaskSH; + Adjuster* const chromaskSH; + Adjuster* const gammaskSH; + Adjuster* const slomaskSH; + CurveEditorGroup* const mask2SHCurveEditorG; + DiagonalCurveEditor* const LmaskSHshape; + Gtk::Frame* const fatSHFrame; + Adjuster* const fatamountSH; + Adjuster* const fatanchorSH; + + sigc::connection shMethodConn, inversshConn, showmaskSHMethodConn, showmaskSHMethodConninv, enaSHMaskConn; + +public: + LocallabShadow(); + ~LocallabShadow(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void shMethodChanged(); + void inversshChanged(); + void showmaskSHMethodChanged(); + void showmaskSHMethodChangedinv(); + void enaSHMaskChanged(); + + void updateShadowGUI1(); + void updateShadowGUI2(); +}; + +/* ==== LocallabVibrance ==== */ +class LocallabVibrance: + public Gtk::VBox, + public LocallabTool, + public ThresholdAdjusterListener, + public ThresholdCurveProvider +{ +private: + // Vibrance specific widgets + Adjuster* const saturated; + Adjuster* const pastels; + Adjuster* const warm; + ThresholdAdjuster* const psThreshold; + Gtk::CheckButton* const protectSkins; + Gtk::CheckButton* const avoidColorShift; + Gtk::CheckButton* const pastSatTog; + Adjuster* const sensiv; + CurveEditorGroup* const curveEditorGG; + DiagonalCurveEditor* const skinTonesCurve; + MyExpander* const expgradvib; + Adjuster* const strvib; + Adjuster* const strvibab; + Adjuster* const strvibh; + Adjuster* const angvib; + MyExpander* const expmaskvib; + MyComboBoxText* const showmaskvibMethod; + Gtk::CheckButton* const enavibMask; + CurveEditorGroup* const maskvibCurveEditorG; + FlatCurveEditor* const CCmaskvibshape; + FlatCurveEditor* const LLmaskvibshape; + FlatCurveEditor* const HHmaskvibshape; + Adjuster* const blendmaskvib; + Adjuster* const radmaskvib; + Adjuster* const lapmaskvib; + Adjuster* const chromaskvib; + Adjuster* const gammaskvib; + Adjuster* const slomaskvib; + CurveEditorGroup* const mask2vibCurveEditorG; + DiagonalCurveEditor* const Lmaskvibshape; + + sigc::connection pskinsConn, ashiftConn, pastsattogConn, showmaskvibMethodConn, enavibMaskConn; + +public: + LocallabVibrance(); + ~LocallabVibrance(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void adjusterChanged(ThresholdAdjuster* a, double newBottom, double newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, double newBottomLeft, double newTopLeft, double newBottomRight, double newTopRight) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottom, int newTop) override; + void adjusterChanged(ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) override {}; // Not used + void adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) override {}; // Not used + std::vector getCurvePoints(ThresholdSelector* tAdjuster) const override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void protectskins_toggled(); + void avoidcolorshift_toggled(); + void pastsattog_toggled(); + void showmaskvibMethodChanged(); + void enavibMaskChanged(); + + void updateVibranceGUI(); +}; + +/* ==== LocallabSoft ==== */ +class LocallabSoft: + public Gtk::VBox, + public LocallabTool +{ +private: + // Soft light specific widgets + MyComboBoxText* const softMethod; + Gtk::HBox* const ctboxsoftmethod; + MyComboBoxText* const showmasksoftMethod; + Adjuster* const streng; + Adjuster* const laplace; + Adjuster* const sensisf; + + sigc::connection softMethodConn, showmasksoftMethodConn; + +public: + LocallabSoft(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void softMethodChanged(); + void showmasksoftMethodChanged(); + + void updateSoftGUI(); +}; + +/* ==== LocallabBlur ==== */ +class LocallabBlur: + public Gtk::VBox, + public LocallabTool, + public ThresholdAdjusterListener +{ +private: + // Blur & Noise specific widgets + MyExpander* const expblnoise; + MyComboBoxText* const blMethod; + Gtk::CheckButton* const fftwbl; + Adjuster* const radius; + Adjuster* const strength; + Gtk::Frame* const grainFrame; + Adjuster* const isogr; + Adjuster* const strengr; + Adjuster* const scalegr; + MyComboBoxText* const medMethod; + Adjuster* const itera; + Adjuster* const guidbl; + Adjuster* const strbl; + Adjuster* const epsbl; + Adjuster* const sensibn; + MyComboBoxText* const blurMethod; + MyComboBoxText* const chroMethod; + Gtk::CheckButton* const activlum; + MyExpander* const expdenoise; + CurveEditorGroup* const LocalcurveEditorwavden; + FlatCurveEditor* const wavshapeden; + Adjuster* const noiselumf0; + Adjuster* const noiselumf; + Adjuster* const noiselumf2; + Adjuster* const noiselumc; + Adjuster* const noiselumdetail; + Adjuster* const noiselequal; + Adjuster* const noisechrof; + Adjuster* const noisechroc; + Adjuster* const noisechrodetail; + Adjuster* const detailthr; + Adjuster* const adjblur; + Adjuster* const bilateral; + Adjuster* const sensiden; + MyExpander* const expmaskbl; + MyComboBoxText* const showmaskblMethod; + MyComboBoxText* const showmaskblMethodtyp; + Gtk::CheckButton* const enablMask; + CurveEditorGroup* const maskblCurveEditorG; + FlatCurveEditor* const CCmaskblshape; + FlatCurveEditor* const LLmaskblshape; + FlatCurveEditor* const HHmaskblshape; + Adjuster* const strumaskbl; + Gtk::CheckButton* const toolbl; + Adjuster* const blendmaskbl; + Adjuster* const radmaskbl; + Adjuster* const lapmaskbl; + Adjuster* const chromaskbl; + Adjuster* const gammaskbl; + Adjuster* const slomaskbl; + Adjuster* const shadmaskbl; + Adjuster* const shadmaskblsha; + CurveEditorGroup* const mask2blCurveEditorG; + DiagonalCurveEditor* const Lmaskblshape; + CurveEditorGroup* const mask2blCurveEditorGwav; + FlatCurveEditor* const LLmaskblshapewav; + ThresholdAdjuster* const csThresholdblur; + + sigc::connection blMethodConn, fftwblConn, medMethodConn, blurMethodConn, chroMethodConn, activlumConn, showmaskblMethodConn, showmaskblMethodtypConn, enablMaskConn, toolblConn; + +public: + LocallabBlur(); + ~LocallabBlur(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void adjusterChanged(ThresholdAdjuster* a, double newBottom, double newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, double newBottomLeft, double newTopLeft, double newBottomRight, double newTopRight) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottom, int newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) override {}; // Not used + void adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void blMethodChanged(); + void fftwblChanged(); + void medMethodChanged(); + void blurMethodChanged(); + void chroMethodChanged(); + void activlumChanged(); + void showmaskblMethodChanged(); + void showmaskblMethodtypChanged(); + void enablMaskChanged(); + void toolblChanged(); + + void updateBlurGUI(); +}; + +/* ==== LocallabTone ==== */ +class LocallabTone: + public Gtk::VBox, + public LocallabTool +{ +private: + // Tone Mapping specific widgets + Adjuster* const amount; + Adjuster* const stren; + Gtk::CheckButton* const equiltm; + Adjuster* const gamma; + Adjuster* const satur; + Adjuster* const estop; + Adjuster* const scaltm; + Adjuster* const rewei; + Adjuster* const softradiustm; + Adjuster* const sensitm; + MyExpander* const expmasktm; + MyComboBoxText* const showmasktmMethod; + Gtk::CheckButton* const enatmMask; + Gtk::CheckButton* const enatmMaskaft; + CurveEditorGroup* const masktmCurveEditorG; + FlatCurveEditor* const CCmasktmshape; + FlatCurveEditor* const LLmasktmshape; + FlatCurveEditor* const HHmasktmshape; + Adjuster* const blendmasktm; + Adjuster* const lapmasktm; + Adjuster* const radmasktm; + Adjuster* const chromasktm; + Adjuster* const gammasktm; + Adjuster* const slomasktm; + CurveEditorGroup* const mask2tmCurveEditorG; + DiagonalCurveEditor* const Lmasktmshape; + + sigc::connection equiltmConn, showmasktmMethodConn, enatmMaskConn, enatmMaskaftConn; + +public: + LocallabTone(); + ~LocallabTone(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void equiltmChanged(); + void showmasktmMethodChanged(); + void enatmMaskChanged(); + void enatmMaskaftChanged(); +}; + +/* ==== LocallabRetinex ==== */ +class LocallabRetinex: + public Gtk::VBox, + public LocallabTool +{ +private: + // Retinex specific widgets + Adjuster* const dehaz; + Adjuster* const depth; + Gtk::CheckButton* const lumonly; + Gtk::Frame* const retiFrame; + Adjuster* const str; + Gtk::CheckButton* const loglin; + Adjuster* const sensih; + Gtk::Frame* const retitoolFrame; + MyComboBoxText* const retinexMethod; + Gtk::CheckButton* const fftwreti; + Gtk::CheckButton* const equilret; + Adjuster* const neigh; + Adjuster* const vart; + Adjuster* const scalereti; + Adjuster* const limd; + Adjuster* const offs; + MyExpander* const expretitools; + Adjuster* const chrrt; + Adjuster* const darkness; + Adjuster* const lightnessreti; + Adjuster* const cliptm; + Adjuster* const softradiusret; + CurveEditorGroup* const LocalcurveEditortransT; + FlatCurveEditor* const cTtransshape; + Gtk::Label* const mMLabels; + Gtk::Label* const transLabels; + Gtk::Label* const transLabels2; + CurveEditorGroup* const LocalcurveEditorgainT; + FlatCurveEditor* const cTgainshape; + MyExpander* const expmaskreti; + MyComboBoxText* const showmaskretiMethod; + Gtk::CheckButton* const enaretiMask; + Gtk::CheckButton* const enaretiMasktmap; + CurveEditorGroup* const maskretiCurveEditorG; + FlatCurveEditor* const CCmaskretishape; + FlatCurveEditor* const LLmaskretishape; + FlatCurveEditor* const HHmaskretishape; + Adjuster* const blendmaskreti; + Adjuster* const radmaskreti; + Adjuster* const lapmaskreti; + Adjuster* const chromaskreti; + Adjuster* const gammaskreti; + Adjuster* const slomaskreti; + CurveEditorGroup* const mask2retiCurveEditorG; + DiagonalCurveEditor* const Lmaskretishape; + Gtk::CheckButton* const inversret; + + sigc::connection lumonlyConn, loglinConn, retinexMethodConn, fftwretiConn, equilretConn, showmaskretiMethodConn, enaretiMaskConn, enaretiMasktmapConn, inversretConn; + +public: + LocallabRetinex(); + ~LocallabRetinex(); + + void updateMinMax(const double cdma, const double cdmin, const double mini, const double maxi, const double Tmean, const double Tsigma, const double Tmin, const double Tmax); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void lumonlyChanged(); + void loglinChanged(); + void retinexMethodChanged(); + void fftwretiChanged(); + void equilretChanged(); + void showmaskretiMethodChanged(); + void enaretiMaskChanged(); + void enaretiMasktmapChanged(); + void inversretChanged(); + + void updateRetinexGUI1(); + void updateRetinexGUI2(); + void updateRetinexGUI3(); +}; + +/* ==== LocallabSharp ==== */ +class LocallabSharp: + public Gtk::VBox, + public LocallabTool +{ +private: + Adjuster* const sharcontrast; + Adjuster* const sharblur; + Adjuster* const sharamount; + Adjuster* const shardamping; + Adjuster* const shariter; + Adjuster* const sharradius; + Adjuster* const sensisha; + Gtk::CheckButton* const inverssha; + MyComboBoxText* const showmasksharMethod; + + sigc::connection inversshaConn, showmasksharMethodConn; + +public: + LocallabSharp(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void inversshaChanged(); + void showmasksharMethodChanged(); +}; + +/* ==== LocallabContrast ==== */ +class LocallabContrast: + public Gtk::VBox, + public LocallabTool, + public ThresholdAdjusterListener +{ +private: + MyComboBoxText* const localcontMethod; + Adjuster* const lcradius; + Adjuster* const lcamount; + Adjuster* const lcdarkness; + Adjuster* const lclightness; + Adjuster* const sigmalc; + CurveEditorGroup* const LocalcurveEditorwav; + FlatCurveEditor* const wavshape; + Adjuster* const levelwav; + ThresholdAdjuster* const csThreshold; + MyExpander* const expresidpyr; + Adjuster* const residcont; + Adjuster* const residchro; + Adjuster* const residsha; + Adjuster* const residshathr; + Adjuster* const residhi; + Adjuster* const residhithr; + Adjuster* const sensilc; + Gtk::Frame* const clariFrame; + Adjuster* const clarilres; + Adjuster* const claricres; + Adjuster* const clarisoft; + Gtk::CheckButton* const origlc; + MyExpander* const expcontrastpyr; + Gtk::CheckButton* const wavgradl; + Adjuster* const sigmalc2; + Adjuster* const strwav; + Adjuster* const angwav; + Gtk::CheckButton* const wavedg; + Adjuster* const strengthw; + Adjuster* const sigmaed; + CurveEditorGroup* const LocalcurveEditorwavedg; + FlatCurveEditor* const wavshapeedg; + Adjuster* const gradw; + Gtk::CheckButton* const waveshow; + ToolParamBlock* const edgsBoxshow; + Adjuster* const radiusw; + Adjuster* const detailw; + MyComboBoxText* const localedgMethod; + Adjuster* const tloww; + Adjuster* const thigw; + Adjuster* const edgw; + Adjuster* const basew; + MyComboBoxText* const localneiMethod; + Gtk::CheckButton* const wavblur; + Adjuster* const levelblur; + Adjuster* const sigmabl; + Adjuster* const chromablu; + CurveEditorGroup* const LocalcurveEditorwavlev; + FlatCurveEditor* const wavshapelev; + Adjuster* const residblur; + Gtk::CheckButton* const blurlc; + MyExpander* const expcontrastpyr2; + Gtk::CheckButton* const wavcont; + Adjuster* const sigma; + Adjuster* const offset; + Adjuster* const chromalev; + CurveEditorGroup* const LocalcurveEditorwavcon; + FlatCurveEditor* const wavshapecon; + Gtk::CheckButton* const wavcompre; + CurveEditorGroup* const LocalcurveEditorwavcompre; + FlatCurveEditor* const wavshapecompre; + Adjuster* const sigmadr; + Adjuster* const threswav; + Adjuster* const residcomp; + Gtk::CheckButton* const wavcomp; + Adjuster* const sigmadc; + Adjuster* const deltad; + CurveEditorGroup* const LocalcurveEditorwavcomp; + FlatCurveEditor* const wavshapecomp; + Adjuster* const fatres; + Gtk::CheckButton* const fftwlc; + MyExpander* const expmasklc; + MyComboBoxText* const showmasklcMethod; + Gtk::CheckButton* const enalcMask; + CurveEditorGroup* const masklcCurveEditorG; + FlatCurveEditor* const CCmasklcshape; + FlatCurveEditor* const LLmasklcshape; + FlatCurveEditor* const HHmasklcshape; + Adjuster* const blendmasklc; + Adjuster* const radmasklc; + Adjuster* const chromasklc; + CurveEditorGroup* const mask2lcCurveEditorG; + DiagonalCurveEditor* const Lmasklcshape; + + sigc::connection localcontMethodConn, origlcConn, wavgradlConn, wavedgConn, localedgMethodConn, waveshowConn, localneiMethodConn, wavblurConn, blurlcConn, wavcontConn, wavcompreConn, wavcompConn, fftwlcConn, showmasklcMethodConn, enalcMaskConn; + +public: + LocallabContrast(); + ~LocallabContrast(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void adjusterChanged(ThresholdAdjuster* a, double newBottom, double newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, double newBottomLeft, double newTopLeft, double newBottomRight, double newTopRight) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottom, int newTop) override {}; // Not used + void adjusterChanged(ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) override {}; // Not used + void adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void localcontMethodChanged(); + void origlcChanged(); + void wavgradlChanged(); + void wavedgChanged(); + void localedgMethodChanged(); + void waveshowChanged(); + void localneiMethodChanged(); + void wavblurChanged(); + void blurlcChanged(); + void wavcontChanged(); + void wavcompreChanged(); + void wavcompChanged(); + void fftwlcChanged(); + void showmasklcMethodChanged(); + void enalcMaskChanged(); + + void updateContrastGUI1(); + void updateContrastGUI2(); + void updateContrastGUI3(); +}; + +/* ==== LocallabCBDL ==== */ +class LocallabCBDL: + public Gtk::VBox, + public LocallabTool +{ +private: + const std::array multiplier; + Adjuster* const chromacbdl; + Adjuster* const threshold; + Adjuster* const blurcbdl; + Adjuster* const clarityml; + Adjuster* const contresid; + Adjuster* const softradiuscb; + Adjuster* const sensicb; + MyExpander* const expmaskcb; + MyComboBoxText* const showmaskcbMethod; + Gtk::CheckButton* const enacbMask; + CurveEditorGroup* const maskcbCurveEditorG; + FlatCurveEditor* const CCmaskcbshape; + FlatCurveEditor* const LLmaskcbshape; + FlatCurveEditor* const HHmaskcbshape; + Adjuster* const blendmaskcb; + Adjuster* const radmaskcb; + Adjuster* const lapmaskcb; + Adjuster* const chromaskcb; + Adjuster* const gammaskcb; + Adjuster* const slomaskcb; + CurveEditorGroup* const mask2cbCurveEditorG; + DiagonalCurveEditor* const Lmaskcbshape; + + sigc::connection showmaskcbMethodConn, enacbMaskConn; + + Gtk::Button* const lumacontrastMinusButton; + Gtk::Button* const lumaneutralButton; + Gtk::Button* const lumacontrastPlusButton; + + sigc::connection lumacontrastMinusPressedConn, lumaneutralPressedConn, lumacontrastPlusPressedConn; + +public: + LocallabCBDL(); + ~LocallabCBDL(); + + bool isMaskViewActive() override; + void resetMaskView() override; + void getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + + void setDefaultExpanderVisibility() override; + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + void curveChanged(CurveEditor* ce) override; + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void showmaskcbMethodChanged(); + void enacbMaskChanged(); + + void lumacontrastMinusPressed(); + void lumaneutralPressed(); + void lumacontrastPlusPressed(); +}; + +/* ==== LocallabLog ==== */ +class LocallabLog: + public Gtk::VBox, + public LocallabTool +{ +private: + Gtk::ToggleButton* const autocompute; + Gtk::Frame* const logPFrame; + Adjuster* const blackEv; + Adjuster* const whiteEv; + Gtk::CheckButton* const fullimage; + Gtk::CheckButton* const Autogray; + Adjuster* const sourceGray; + Adjuster* const targetGray; + Adjuster* const detail; + Adjuster* const baselog; + Adjuster* const sensilog; + Adjuster* const strlog; + Adjuster* const anglog; + + sigc::connection autoconn, fullimageConn, AutograyConn; + +public: + LocallabLog(); + void updateAdviceTooltips(const bool showTooltips) override; + + void disableListener() override; + void enableListener() override; + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster* a, double newval) override; + + void updateAutocompute(const float blackev, const float whiteev, const float sourceg, const float targetg); + +private: + void enabledChanged() override; + + void autocomputeToggled(); + void fullimageChanged(); + void AutograyChanged(); + + void updateLogGUI(); +}; + +#endif diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc new file mode 100644 index 000000000..816bfcd30 --- /dev/null +++ b/rtgui/locallabtools2.cc @@ -0,0 +1,4725 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath frame + * + * + * 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 . + * 2019 Pierre Cabrera + */ +#include "locallabtools.h" + +#include "options.h" +#include "../rtengine/procparams.h" +#include "locallab.h" +#include "rtimage.h" + +#define MINNEIGH 0.1 +#define MAXNEIGH 1500 +#define CENTERNEIGH 200 + +using namespace rtengine; +using namespace procparams; + +extern Options options; + +static double retiSlider2neigh(double sval) +{ + // Slider range: 0 - 5000 + double neigh; + + if (sval <= 200) { + // Linear below center-temp + neigh = MINNEIGH + (sval / 200.0) * (CENTERNEIGH - MINNEIGH); + } else { + const double slope = (double)(CENTERNEIGH - MINNEIGH) / (MAXNEIGH - CENTERNEIGH); + const double x = (sval - 200) / 200; // x range: 0 - 1 + const double y = x * slope + (1.0 - slope) * pow(x, 4.0); + neigh = CENTERNEIGH + y * (MAXNEIGH - CENTERNEIGH); + } + + if (neigh < MINNEIGH) { + neigh = MINNEIGH; + } + + if (neigh > MAXNEIGH) { + neigh = MAXNEIGH; + } + + return neigh; +} + +static double retiNeigh2Slider(double neigh) +{ + double sval; + + if (neigh <= CENTERNEIGH) { + sval = ((neigh - MINNEIGH) / (CENTERNEIGH - MINNEIGH)) * 200.0; + } else { + const double slope = (double)(CENTERNEIGH - MINNEIGH) / (MAXNEIGH - CENTERNEIGH); + const double y = (neigh - CENTERNEIGH) / (MAXNEIGH - CENTERNEIGH); + double x = pow(y, 0.25); // Rough guess of x, will be a little lower + double k = 0.1; + bool add = true; + + // The y=f(x) function is a mess to invert, therefore we have this trial-refinement loop instead. + // From tests, worst case is about 20 iterations, i.e. no problem + for (;;) { + double y1 = x * slope + (1.0 - slope) * pow(x, 4.0); + + if (200 * fabs(y1 - y) < 0.1) { + break; + } + + if (y1 < y) { + if (!add) { + k /= 2; + } + + x += k; + add = true; + } else { + if (add) { + k /= 2; + } + + x -= k; + add = false; + } + } + + sval = 200.0 + x * 200.0; + } + + if (sval < 0.) { + sval = 0.; + } + + if (sval > 1500.) { + sval = 1500.; + } + + return sval; +} + +/* ==== LocallabTone ==== */ +LocallabTone::LocallabTone(): + LocallabTool(this, M("TP_LOCALLAB_TONE_TOOLNAME"), M("TP_LOCALLAB_TM"), true), + + // Tone mapping specific widgets + amount(Gtk::manage(new Adjuster(M("TP_LOCALLAB_AMOUNT"), 50., 100.0, 0.5, 95.))), + stren(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STREN"), -0.5, 2.0, 0.01, 0.5))), + equiltm(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EQUIL")))), + gamma(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAM"), 0.4, 4.0, 0.11, 1.0))), + satur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SATUR"), -100., 100., 0.1, 0.))), // By default satur = 0 ==> use Mantiuk value + estop(Gtk::manage(new Adjuster(M("TP_LOCALLAB_ESTOP"), 0.1, 4., 0.01, 1.4))), + scaltm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCALTM"), 0.1, 10.0, 0.01, 1.0))), + rewei(Gtk::manage(new Adjuster(M("TP_LOCALLAB_REWEI"), 0, 3, 1, 0))), + softradiustm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 1000.0, 0.1, 0.))), + sensitm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 30))), + expmasktm(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWT")))), + showmasktmMethod(Gtk::manage(new MyComboBoxText())), + enatmMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + enatmMaskaft(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_AFTER_MASK")))), + masktmCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + lapmasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + radmasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + chromasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.05, 5.0, 0.01, 1.))), + slomasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + mask2tmCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmasktmshape(static_cast(mask2tmCurveEditorG->addCurve(CT_Diagonal, "L(L)"))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Tone Mapping specific widgets + amount->setAdjusterListener(this); + + stren->setAdjusterListener(this); + + equiltmConn = equiltm->signal_toggled().connect(sigc::mem_fun(*this, &LocallabTone::equiltmChanged)); + + gamma->setAdjusterListener(this); + + satur->setAdjusterListener(this); + + estop->setAdjusterListener(this); + + scaltm->setAdjusterListener(this); + + rewei->setAdjusterListener(this); + + softradiustm->setLogScale(10, 0); + softradiustm->setAdjusterListener(this); + + sensitm->setAdjusterListener(this); + + setExpandAlignProperties(expmasktm, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmasktmMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmasktmMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmasktmMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmasktmMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmasktmMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmasktmMethod->set_active(0); + showmasktmMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmasktmMethodConn = showmasktmMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabTone::showmasktmMethodChanged)); + + enatmMaskConn = enatmMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabTone::enatmMaskChanged)); + + enatmMaskaftConn = enatmMaskaft->signal_toggled().connect(sigc::mem_fun(*this, &LocallabTone::enatmMaskaftChanged)); + + masktmCurveEditorG->setCurveListener(this); + + CCmasktmshape->setIdentityValue(0.); + CCmasktmshape->setResetCurve(FlatCurveType(defSpot.CCmasktmcurve.at(0)), defSpot.CCmasktmcurve); + CCmasktmshape->setBottomBarColorProvider(this, 1); + + LLmasktmshape->setIdentityValue(0.); + LLmasktmshape->setResetCurve(FlatCurveType(defSpot.LLmasktmcurve.at(0)), defSpot.LLmasktmcurve); + LLmasktmshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmasktmshape->setIdentityValue(0.); + HHmasktmshape->setResetCurve(FlatCurveType(defSpot.HHmasktmcurve.at(0)), defSpot.HHmasktmcurve); + HHmasktmshape->setCurveColorProvider(this, 2); + HHmasktmshape->setBottomBarColorProvider(this, 2); + + masktmCurveEditorG->curveListComplete(); + + blendmasktm->setAdjusterListener(this); + + lapmasktm->setAdjusterListener(this); + + radmasktm->setLogScale(10, -10); + radmasktm->setAdjusterListener(this); + + chromasktm->setAdjusterListener(this); + + gammasktm->setAdjusterListener(this); + + slomasktm->setAdjusterListener(this); + + mask2tmCurveEditorG->setCurveListener(this); + Lmasktmshape->setResetCurve(DiagonalCurveType(defSpot.Lmasktmcurve.at(0)), defSpot.Lmasktmcurve); + Lmasktmshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmasktmshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2tmCurveEditorG->curveListComplete(); + + // Add Tone Mapping specific widgets to GUI + // pack_start(*amount); // To use if we change transit_shapedetect parameters + pack_start(*stren); + pack_start(*equiltm); + pack_start(*gamma); + pack_start(*satur); + pack_start(*estop); + pack_start(*scaltm); + pack_start(*rewei); + // pack_start(*softradiustm); // Always bad with TM ?? + pack_start(*sensitm); + ToolParamBlock* const masktmBox = Gtk::manage(new ToolParamBlock()); + masktmBox->pack_start(*showmasktmMethod, Gtk::PACK_SHRINK, 4); + masktmBox->pack_start(*enatmMask, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*enatmMaskaft, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*masktmCurveEditorG, Gtk::PACK_SHRINK, 4); + masktmBox->pack_start(*blendmasktm, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*lapmasktm, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*radmasktm, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*chromasktm, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*gammasktm, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*slomasktm, Gtk::PACK_SHRINK, 0); + masktmBox->pack_start(*mask2tmCurveEditorG, Gtk::PACK_SHRINK, 4); + expmasktm->add(*masktmBox, false); + pack_start(*expmasktm, false, false); +} + +LocallabTone::~LocallabTone() +{ + delete masktmCurveEditorG; + delete mask2tmCurveEditorG; +} + +bool LocallabTone::isMaskViewActive() +{ + return (showmasktmMethod->get_active_row_number() != 0); +} + +void LocallabTone::resetMaskView() +{ + showmasktmMethodConn.block(true); + showmasktmMethod->set_active(0); + showmasktmMethodConn.block(false); +} + +void LocallabTone::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + tmMask = showmasktmMethod->get_active_row_number(); +} + +void LocallabTone::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_TONEMAP_TOOLTIP")); + estop->set_tooltip_text(M("TP_LOCALLAB_TONEMAPESTOP_TOOLTIP")); + rewei->set_tooltip_text(M("TP_LOCALLAB_TONEMAPREWEI_TOOLTIP")); + scaltm->set_tooltip_text(M("TP_LOCALLAB_TONEMASCALE_TOOLTIP")); + gamma->set_tooltip_text(M("TP_LOCALLAB_TONEMAPGAM_TOOLTIP")); + equiltm->set_tooltip_text(M("TP_LOCALLAB_EQUILTM_TOOLTIP")); + sensitm->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + expmasktm->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmasktmshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmasktmshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmasktmshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + lapmasktm->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + radmasktm->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + Lmasktmshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + blendmasktm->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2tmCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + estop->set_tooltip_text(""); + rewei->set_tooltip_text(""); + scaltm->set_tooltip_text(M("")); + gamma->set_tooltip_text(M("")); + equiltm->set_tooltip_text(M("")); + sensitm->set_tooltip_text(""); + expmasktm->set_tooltip_text(""); + CCmasktmshape->setTooltip(""); + LLmasktmshape->setTooltip(""); + HHmasktmshape->setTooltip(""); + lapmasktm->set_tooltip_text(""); + radmasktm->set_tooltip_text(""); + Lmasktmshape->setTooltip(""); + blendmasktm->set_tooltip_text(M("")); + mask2tmCurveEditorG->set_tooltip_text(M("")); + } +} + +void LocallabTone::setDefaultExpanderVisibility() +{ + expmasktm->set_expanded(false); +} + +void LocallabTone::disableListener() +{ + LocallabTool::disableListener(); + + equiltmConn.block(true); + showmasktmMethodConn.block(true); + enatmMaskConn.block(true); + enatmMaskaftConn.block(true); +} + +void LocallabTone::enableListener() +{ + LocallabTool::enableListener(); + + equiltmConn.block(false); + showmasktmMethodConn.block(false); + enatmMaskConn.block(false); + enatmMaskaftConn.block(false); +} + +void LocallabTone::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visitonemap); + exp->setEnabled(spot.exptonemap); + complexity->set_active(spot.complextonemap); + + amount->setValue(spot.amount); + stren->setValue(spot.stren); + equiltm->set_active(spot.equiltm); + gamma->setValue(spot.gamma); + satur->setValue(spot.satur); + estop->setValue(spot.estop); + scaltm->setValue(spot.scaltm); + rewei->setValue((double)spot.rewei); + softradiustm->setValue(spot.softradiustm); + sensitm->setValue((double)spot.sensitm); + enatmMask->set_active(spot.enatmMask); + enatmMaskaft->set_active(spot.enatmMaskaft); + CCmasktmshape->setCurve(spot.CCmasktmcurve); + LLmasktmshape->setCurve(spot.LLmasktmcurve); + HHmasktmshape->setCurve(spot.HHmasktmcurve); + blendmasktm->setValue((double)spot.blendmasktm); + lapmasktm->setValue(spot.lapmasktm); + radmasktm->setValue(spot.radmasktm); + chromasktm->setValue(spot.chromasktm); + gammasktm->setValue(spot.gammasktm); + slomasktm->setValue(spot.slomasktm); + Lmasktmshape->setCurve(spot.Lmasktmcurve); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabTone::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.exptonemap = exp->getEnabled(); + spot.visitonemap = exp->get_visible(); + spot.complextonemap = complexity->get_active_row_number(); + + spot.amount = amount->getValue(); + spot.stren = stren->getValue(); + spot.equiltm = equiltm->get_active(); + spot.gamma = gamma->getValue(); + spot.satur = satur->getValue(); + spot.estop = estop->getValue(); + spot.scaltm = scaltm->getValue(); + spot.rewei = rewei->getIntValue(); + spot.softradiustm = softradiustm->getValue(); + spot.sensitm = sensitm->getIntValue(); + spot.enatmMask = enatmMask->get_active(); + spot.enatmMaskaft = enatmMaskaft->get_active(); + spot.LLmasktmcurve = LLmasktmshape->getCurve(); + spot.CCmasktmcurve = CCmasktmshape->getCurve(); + spot.HHmasktmcurve = HHmasktmshape->getCurve(); + spot.blendmasktm = blendmasktm->getIntValue(); + spot.lapmasktm = lapmasktm->getValue(); + spot.radmasktm = radmasktm->getValue(); + spot.chromasktm = chromasktm->getValue(); + spot.gammasktm = gammasktm->getValue(); + spot.slomasktm = slomasktm->getValue(); + spot.Lmasktmcurve = Lmasktmshape->getCurve(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabTone::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + amount->setDefault(defSpot.amount); + stren->setDefault(defSpot.stren); + gamma->setDefault(defSpot.gamma); + satur->setDefault(defSpot.satur); + estop->setDefault(defSpot.estop); + scaltm->setDefault(defSpot.scaltm); + rewei->setDefault((double)defSpot.rewei); + softradiustm->setDefault(defSpot.softradiustm); + sensitm->setDefault((double)defSpot.sensitm); + blendmasktm->setDefault((double)defSpot.blendmasktm); + lapmasktm->setDefault(defSpot.lapmasktm); + radmasktm->setDefault(defSpot.radmasktm); + chromasktm->setDefault(defSpot.chromasktm); + gammasktm->setDefault(defSpot.gammasktm); + slomasktm->setDefault(defSpot.slomasktm); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabTone::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == amount) { + if (listener) { + listener->panelChanged(Evlocallabamount, + amount->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == stren) { + if (listener) { + listener->panelChanged(Evlocallabstren, + stren->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gamma) { + if (listener) { + listener->panelChanged(Evlocallabgamma, + gamma->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == satur) { + if (listener) { + listener->panelChanged(Evlocallabsatur, + satur->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == estop) { + if (listener) { + listener->panelChanged(Evlocallabestop, + estop->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == scaltm) { + if (listener) { + listener->panelChanged(Evlocallabscaltm, + scaltm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == rewei) { + if (listener) { + listener->panelChanged(Evlocallabrewei, + rewei->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == softradiustm) { + if (listener) { + listener->panelChanged(Evlocallabsoftradiustm, + softradiustm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensitm) { + if (listener) { + listener->panelChanged(Evlocallabsensitm, + sensitm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmasktm) { + if (listener) { + listener->panelChanged(Evlocallabblendmasktm, + blendmasktm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmasktm) { + if (listener) { + listener->panelChanged(Evlocallablapmasktm, + lapmasktm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmasktm) { + if (listener) { + listener->panelChanged(Evlocallabradmasktm, + radmasktm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromasktm) { + if (listener) { + listener->panelChanged(Evlocallabchromasktm, + chromasktm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammasktm) { + if (listener) { + listener->panelChanged(Evlocallabgammasktm, + gammasktm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomasktm) { + if (listener) { + listener->panelChanged(Evlocallabslomasktm, + slomasktm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabTone::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == CCmasktmshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmasktmshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmasktmshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmasktmshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmasktmshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmasktmshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmasktmshape) { + if (listener) { + listener->panelChanged(EvlocallabLmasktmshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabTone::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenatonemap, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenatonemap, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabTone::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + gamma->setValue(defSpot.gamma); + satur->setValue(defSpot.satur); + rewei->setValue((double)defSpot.rewei); + lapmasktm->setValue(defSpot.lapmasktm); + gammasktm->setValue(defSpot.gammasktm); + slomasktm->setValue(defSpot.slomasktm); + + // Enable all listeners + enableListener(); +} + +void LocallabTone::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + gamma->hide(); + satur->hide(); + rewei->hide(); + lapmasktm->hide(); + gammasktm->hide(); + slomasktm->hide(); + } else { + // Advanced widgets are shown in Expert mode + gamma->show(); + satur->show(); + rewei->show(); + lapmasktm->show(); + gammasktm->show(); + slomasktm->show(); + } +} + +void LocallabTone::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmasktmshape->updateLocallabBackground(normChromar); + LLmasktmshape->updateLocallabBackground(normLumar); + HHmasktmshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabTone::equiltmChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (equiltm->get_active()) { + listener->panelChanged(Evlocallabequiltm, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabequiltm, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabTone::showmasktmMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabTone::enatmMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enatmMask->get_active()) { + listener->panelChanged(EvLocallabEnatmMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnatmMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabTone::enatmMaskaftChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enatmMaskaft->get_active()) { + listener->panelChanged(EvLocallabEnatmMaskaft, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnatmMaskaft, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +/* ==== LocallabRetinex ==== */ +LocallabRetinex::LocallabRetinex(): + LocallabTool(this, M("TP_LOCALLAB_RET_TOOLNAME"), M("TP_LOCALLAB_RETI"), true), + + // Retinex specific widgets + dehaz(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DEHAZ"), -100, 100, 1, 0))), + depth(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DEPTH"), 0, 100, 1, 25))), + lumonly(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_LUMONLY")))), + retiFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_RETIFRA")))), + str(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STR"), 0., 100., 0.2, 0.))), + loglin(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_LOGLIN")))), + sensih(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIH"), 0, 100, 1, 60))), + retitoolFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_RETITOOLFRA")))), + retinexMethod(Gtk::manage(new MyComboBoxText())), + fftwreti(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FFTW")))), + equilret(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EQUIL")))), + neigh(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NEIGH"), MINNEIGH, MAXNEIGH, 0.5, 50., nullptr, nullptr, &retiSlider2neigh, &retiNeigh2Slider))), + vart(Gtk::manage(new Adjuster(M("TP_LOCALLAB_VART"), 0.1, 500., 0.1, 150.))), + scalereti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCALERETI"), 1.0, 10.0, 1., 2.))), + limd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_THRESRETI"), 1.2, 100.0, 0.1, 8.))), + offs(Gtk::manage(new Adjuster(M("TP_LOCALLAB_OFFS"), -16386., 32768., 1., 0.))), + expretitools(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_EXPRETITOOLS")))), + chrrt(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHRRT"), 0.0, 100.0, 0.1, 0.0))), + darkness(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DARKRETI"), 0.01, 6.0, 0.01, 2.0))), + lightnessreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LIGHTRETI"), 0.01, 4.0, 0.01, 1.))), + cliptm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CLIPTM"), 0.02, 2.0, 0.01, 1.))), + softradiusret(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRETI"), 0.0, 1000.0, 0.5, 40.))), + LocalcurveEditortransT(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_TRANSMISSIONMAP"))), + cTtransshape(static_cast(LocalcurveEditortransT->addCurve(CT_Flat, "", nullptr, false, false))), + mMLabels(Gtk::manage(new Gtk::Label("---"))), + transLabels(Gtk::manage(new Gtk::Label("---"))), + transLabels2(Gtk::manage(new Gtk::Label("---"))), + LocalcurveEditorgainT(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_TRANSMISSIONGAIN"))), + cTgainshape(static_cast(LocalcurveEditorgainT->addCurve(CT_Flat, "", nullptr, false, false))), + expmaskreti(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWR")))), + showmaskretiMethod(Gtk::manage(new MyComboBoxText())), + enaretiMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + enaretiMasktmap(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TM_MASK")))), + maskretiCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 10.))), + lapmaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.05, 5.0, 0.01, 1.))), + slomaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + mask2retiCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmaskretishape(static_cast(mask2retiCurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + inversret(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVERS")))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Retinex specific widgets + dehaz->set_tooltip_text(M("TP_LOCALLAB_DEHAZ_TOOLTIP")); + dehaz->setAdjusterListener(this); + + depth->setAdjusterListener(this); + + lumonlyConn = lumonly->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::lumonlyChanged)); + + retiFrame->set_label_align(0.025, 0.5); + + str->setAdjusterListener(this); + + loglinConn = loglin->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::loglinChanged)); + + sensih->setAdjusterListener(this); + + retitoolFrame->set_label_align(0.025, 0.5); + + retinexMethod->append(M("TP_RETINEX_LOW")); + retinexMethod->append(M("TP_RETINEX_UNIFORM")); + retinexMethod->append(M("TP_RETINEX_HIGH")); + retinexMethod->set_active(0); + retinexMethod->set_tooltip_markup(M("TP_LOCRETI_METHOD_TOOLTIP")); + retinexMethodConn = retinexMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabRetinex::retinexMethodChanged)); + + fftwretiConn = fftwreti->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::fftwretiChanged)); + + equilretConn = equilret->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::equilretChanged)); + + neigh->setAdjusterListener(this); + + vart->setAdjusterListener(this); + + scalereti->setAdjusterListener(this); + + limd->setAdjusterListener(this); + + offs->setAdjusterListener(this); + + setExpandAlignProperties(expretitools, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + chrrt->setAdjusterListener(this); + + darkness->setAdjusterListener(this); + + lightnessreti->setAdjusterListener(this); + + cliptm->setAdjusterListener(this); + + softradiusret->setLogScale(10, 0); + softradiusret->setAdjusterListener(this); + + LocalcurveEditortransT->setCurveListener(this); + + cTtransshape->setIdentityValue(0.); + cTtransshape->setResetCurve(FlatCurveType(defSpot.localTtranscurve.at(0)), defSpot.localTtranscurve); + + LocalcurveEditortransT->curveListComplete(); + + setExpandAlignProperties(mMLabels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + + setExpandAlignProperties(transLabels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + + setExpandAlignProperties(transLabels2, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + + LocalcurveEditorgainT->setCurveListener(this); + + cTgainshape->setIdentityValue(0.); + cTgainshape->setResetCurve(FlatCurveType(defSpot.localTgaincurve.at(0)), defSpot.localTgaincurve); + + LocalcurveEditorgainT->curveListComplete(); + + setExpandAlignProperties(expmaskreti, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskretiMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskretiMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskretiMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskretiMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskretiMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskretiMethod->set_active(0); + showmaskretiMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskretiMethodConn = showmaskretiMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabRetinex::showmaskretiMethodChanged)); + + enaretiMaskConn = enaretiMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::enaretiMaskChanged)); + + enaretiMasktmapConn = enaretiMasktmap->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::enaretiMasktmapChanged)); + + maskretiCurveEditorG->setCurveListener(this); + + CCmaskretishape->setIdentityValue(0.); + CCmaskretishape->setResetCurve(FlatCurveType(defSpot.CCmaskreticurve.at(0)), defSpot.CCmaskreticurve); + CCmaskretishape->setBottomBarColorProvider(this, 1); + + LLmaskretishape->setIdentityValue(0.); + LLmaskretishape->setResetCurve(FlatCurveType(defSpot.LLmaskreticurve.at(0)), defSpot.LLmaskreticurve); + LLmaskretishape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskretishape->setIdentityValue(0.); + HHmaskretishape->setResetCurve(FlatCurveType(defSpot.HHmaskreticurve.at(0)), defSpot.HHmaskreticurve); + HHmaskretishape->setCurveColorProvider(this, 2); + HHmaskretishape->setBottomBarColorProvider(this, 2); + + maskretiCurveEditorG->curveListComplete(); + + blendmaskreti->setAdjusterListener(this); + + radmaskreti->setAdjusterListener(this); + + lapmaskreti->setAdjusterListener(this); + + chromaskreti->setAdjusterListener(this); + + gammaskreti->setAdjusterListener(this); + + slomaskreti->setAdjusterListener(this); + + mask2retiCurveEditorG->setCurveListener(this); + + Lmaskretishape->setResetCurve(DiagonalCurveType(defSpot.Lmaskreticurve.at(0)), defSpot.Lmaskreticurve); + Lmaskretishape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmaskretishape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2retiCurveEditorG->curveListComplete(); + + inversretConn = inversret->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::inversretChanged)); + + // Add Retinex specific widgets to GUI + ToolParamBlock* const auxBox = Gtk::manage(new ToolParamBlock()); + Gtk::Frame* const dehaFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_DEHAFRA"))); + dehaFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const dehaBox = Gtk::manage(new ToolParamBlock()); + dehaBox->pack_start(*dehaz); + dehaBox->pack_start(*depth); + dehaBox->pack_start(*lumonly); + dehaFrame->add(*dehaBox); + auxBox->add(*dehaFrame); + ToolParamBlock* const deharetiBox = Gtk::manage(new ToolParamBlock()); + deharetiBox->pack_start(*str); + deharetiBox->pack_start(*loglin); + retiFrame->add(*deharetiBox); + auxBox->add(*retiFrame); + ToolParamBlock* const scopeBox = Gtk::manage(new ToolParamBlock()); + scopeBox->pack_start(*sensih); + auxBox->add(*scopeBox); + pack_start(*auxBox); + ToolParamBlock* const retiBox = Gtk::manage(new ToolParamBlock()); + retiBox->pack_start(*retinexMethod); + retiBox->pack_start(*fftwreti); + retiBox->pack_start(*equilret); + retiBox->pack_start(*neigh); + retiBox->pack_start(*vart); + retiBox->pack_start(*scalereti); + retiBox->pack_start(*limd); + retiBox->pack_start(*offs); + ToolParamBlock* const toolretiBox = Gtk::manage(new ToolParamBlock()); + toolretiBox->pack_start(*chrrt); + toolretiBox->pack_start(*darkness); + toolretiBox->pack_start(*lightnessreti); + toolretiBox->pack_start(*cliptm); + toolretiBox->pack_start(*softradiusret); + toolretiBox->pack_start(*LocalcurveEditortransT, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolretiBox->pack_start(*mMLabels); + toolretiBox->pack_start(*transLabels); + toolretiBox->pack_start(*transLabels2); + toolretiBox->pack_start(*LocalcurveEditorgainT, Gtk::PACK_SHRINK, 4); + expretitools->add(*toolretiBox, false); + retiBox->pack_start(*expretitools, false, false); + ToolParamBlock* const maskretiBox = Gtk::manage(new ToolParamBlock()); + maskretiBox->pack_start(*showmaskretiMethod, Gtk::PACK_SHRINK, 4); + maskretiBox->pack_start(*enaretiMask, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*enaretiMasktmap, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*maskretiCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + maskretiBox->pack_start(*blendmaskreti, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*radmaskreti, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*lapmaskreti, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*chromaskreti, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*gammaskreti, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*slomaskreti, Gtk::PACK_SHRINK, 0); + maskretiBox->pack_start(*mask2retiCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + expmaskreti->add(*maskretiBox, false); + retiBox->pack_start(*expmaskreti, false, false); + // retiBox->pack_start(*inversret); + retitoolFrame->add(*retiBox); + pack_start(*retitoolFrame); +} + +LocallabRetinex::~LocallabRetinex() +{ + delete LocalcurveEditortransT; + delete LocalcurveEditorgainT; + delete maskretiCurveEditorG; + delete mask2retiCurveEditorG; +} + +void LocallabRetinex::updateMinMax(const double cdma, const double cdmin, const double mini, const double maxi, const double Tmean, const double Tsigma, const double Tmin, const double Tmax) +{ + idle_register.add( + [this, cdma, cdmin, mini, maxi, Tmean, Tsigma, Tmin, Tmax]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + mMLabels->set_text( + Glib::ustring::compose(M("TP_LOCALLAB_MLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(0), cdmin), + Glib::ustring::format(std::fixed, std::setprecision(0), cdma)) + ); + transLabels->set_text( + Glib::ustring::compose(M("TP_LOCALLAB_TLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(1), mini), + Glib::ustring::format(std::fixed, std::setprecision(1), maxi), + Glib::ustring::format(std::fixed, std::setprecision(1), Tmean), + Glib::ustring::format(std::fixed, std::setprecision(1), Tsigma)) + ); + transLabels2->set_text( + Glib::ustring::compose(M("TP_RETINEX_TLABEL2"), + Glib::ustring::format(std::fixed, std::setprecision(1), Tmin), + Glib::ustring::format(std::fixed, std::setprecision(1), Tmax)) + ); + + return false; + } + ); +} + +bool LocallabRetinex::isMaskViewActive() +{ + return (showmaskretiMethod->get_active_row_number() != 0); +} + +void LocallabRetinex::resetMaskView() +{ + showmaskretiMethodConn.block(true); + showmaskretiMethod->set_active(0); + showmaskretiMethodConn.block(false); +} + +void LocallabRetinex::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + retiMask = showmaskretiMethod->get_active_row_number(); +} + +void LocallabRetinex::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + sensih->set_tooltip_text(M("TP_LOCALLAB_SENSIH_TOOLTIP")); + fftwreti->set_tooltip_text(M("TP_LOCALLAB_RETI_FFTW_TOOLTIP")); + loglin->set_tooltip_text(M("TP_LOCALLAB_RETI_LOGLIN_TOOLTIP")); + scalereti->set_tooltip_text(M("TP_LOCALLAB_RETI_SCALE_TOOLTIP")); + limd->set_tooltip_text(M("TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP")); + offs->set_tooltip_text(M("TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP")); + cliptm->set_tooltip_text(M("TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP")); + lightnessreti->set_tooltip_text(M("TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP")); + darkness->set_tooltip_text(M("TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP")); + neigh->set_tooltip_text(M("TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP")); + vart->set_tooltip_text(M("TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP")); + equilret->set_tooltip_text(M("TP_LOCALLAB_EQUILTM_TOOLTIP")); + softradiusret->set_tooltip_text(M("TP_LOCALLAB_GUIDFILTER_TOOLTIP")); + cTtransshape->setTooltip(M("TP_LOCALLAB_TRANSMISSION_TOOLTIP")); + mMLabels->set_tooltip_markup(M("TP_LOCALLAB_MLABEL_TOOLTIP")); + transLabels->set_tooltip_markup(M("TP_LOCALLAB_TLABEL_TOOLTIP")); + cTgainshape->setTooltip(M("TP_RETINEX_GAINTRANSMISSION_TOOLTIP")); + expmaskreti->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + enaretiMasktmap->set_tooltip_markup(M("TP_LOCALLAB_ENARETIMASKTMAP_TOOLTIP")); + CCmaskretishape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskretishape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskretishape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + radmaskreti->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskreti->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + Lmaskretishape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + blendmaskreti->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2retiCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + } else { + sensih->set_tooltip_text(""); + fftwreti->set_tooltip_text(""); + neigh->set_tooltip_text(""); + vart->set_tooltip_text(""); + loglin->set_tooltip_text(M("")); + scalereti->set_tooltip_text(M("")); + limd->set_tooltip_text(M("")); + offs->set_tooltip_text(M("")); + lightnessreti->set_tooltip_text(M("")); + darkness->set_tooltip_text(M("")); + equilret->set_tooltip_text(M("")); + softradiusret->set_tooltip_text(""); + cTtransshape->setTooltip(""); + mMLabels->set_tooltip_text(""); + transLabels->set_tooltip_text(""); + cTgainshape->setTooltip(""); + expmaskreti->set_tooltip_text(""); + enaretiMasktmap->set_tooltip_text(""); + CCmaskretishape->setTooltip(""); + LLmaskretishape->setTooltip(""); + HHmaskretishape->setTooltip(""); + radmaskreti->set_tooltip_text(""); + lapmaskreti->set_tooltip_text(""); + Lmaskretishape->setTooltip(""); + blendmaskreti->set_tooltip_text(M("")); + mask2retiCurveEditorG->set_tooltip_text(M("")); + } +} + +void LocallabRetinex::setDefaultExpanderVisibility() +{ + expretitools->set_expanded(false); + expmaskreti->set_expanded(false); +} + +void LocallabRetinex::disableListener() +{ + LocallabTool::disableListener(); + + lumonlyConn.block(true); + loglinConn.block(true); + retinexMethodConn.block(true); + fftwretiConn.block(true); + equilretConn.block(true); + showmaskretiMethodConn.block(true); + enaretiMaskConn.block(true); + enaretiMasktmapConn.block(true); + inversretConn.block(true); +} + +void LocallabRetinex::enableListener() +{ + LocallabTool::enableListener(); + + lumonlyConn.block(false); + loglinConn.block(false); + retinexMethodConn.block(false); + fftwretiConn.block(false); + equilretConn.block(false); + showmaskretiMethodConn.block(false); + enaretiMaskConn.block(false); + enaretiMasktmapConn.block(false); + inversretConn.block(false); +} + +void LocallabRetinex::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visireti); + exp->setEnabled(spot.expreti); + complexity->set_active(spot.complexreti); + + dehaz->setValue((double)spot.dehaz); + depth->setValue((double)spot.depth); + lumonly->set_active(spot.lumonly); + str->setValue(spot.str); + loglin->set_active(spot.loglin); + sensih->setValue((double)spot.sensih); + + if (spot.retinexMethod == "low") { + retinexMethod->set_active(0); + } else if (spot.retinexMethod == "uni") { + retinexMethod->set_active(1); + } else { + retinexMethod->set_active(2); + } + + fftwreti->set_active(spot.fftwreti); + equilret->set_active(spot.equilret); + neigh->setValue(spot.neigh); + vart->setValue(spot.vart); + scalereti->setValue(spot.scalereti); + limd->setValue(spot.limd); + offs->setValue(spot.offs); + chrrt->setValue(spot.chrrt); + darkness->setValue(spot.darkness); + lightnessreti->setValue(spot.lightnessreti); + cliptm->setValue(spot.cliptm); + softradiusret->setValue(spot.softradiusret); + cTtransshape->setCurve(spot.localTtranscurve); + cTgainshape->setCurve(spot.localTgaincurve); + enaretiMask->set_active(spot.enaretiMask); + enaretiMasktmap->set_active(spot.enaretiMasktmap); + CCmaskretishape->setCurve(spot.CCmaskreticurve); + LLmaskretishape->setCurve(spot.LLmaskreticurve); + HHmaskretishape->setCurve(spot.HHmaskreticurve); + blendmaskreti->setValue((double)spot.blendmaskreti); + radmaskreti->setValue(spot.radmaskreti); + lapmaskreti->setValue(spot.lapmaskreti); + chromaskreti->setValue(spot.chromaskreti); + gammaskreti->setValue(spot.gammaskreti); + slomaskreti->setValue(spot.slomaskreti); + Lmaskretishape->setCurve(spot.Lmaskreticurve); + inversret->set_active(spot.inversret); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update Retinex GUI according to scalereti adjuster value + updateRetinexGUI1(); + + // Update Retinex GUI according to inversret button state + updateRetinexGUI2(); + + // Update Retinex GUI according to str adjuster value + updateRetinexGUI3(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabRetinex::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expreti = exp->getEnabled(); + spot.visireti = exp->get_visible(); + spot.complexreti = complexity->get_active_row_number(); + + spot.dehaz = dehaz->getIntValue(); + spot.depth = depth->getIntValue(); + spot.lumonly = lumonly->get_active(); + spot.str = str->getValue(); + spot.loglin = loglin->get_active(); + spot.sensih = sensih->getIntValue(); + + if (retinexMethod->get_active_row_number() == 0) { + spot.retinexMethod = "low"; + } else if (retinexMethod->get_active_row_number() == 1) { + spot.retinexMethod = "uni"; + } else if (retinexMethod->get_active_row_number() == 2) { + spot.retinexMethod = "high"; + } + + spot.fftwreti = fftwreti->get_active(); + spot.equilret = equilret->get_active(); + spot.neigh = neigh->getValue(); + spot.vart = vart->getValue(); + spot.scalereti = scalereti->getValue(); + spot.limd = limd->getValue(); + spot.offs = offs->getValue(); + spot.chrrt = chrrt->getValue(); + spot.darkness = darkness->getValue(); + spot.lightnessreti = lightnessreti->getValue(); + spot.cliptm = cliptm->getValue(); + spot.softradiusret = softradiusret->getValue(); + spot.localTtranscurve = cTtransshape->getCurve(); + spot.localTgaincurve = cTgainshape->getCurve(); + spot.enaretiMask = enaretiMask->get_active(); + spot.enaretiMasktmap = enaretiMasktmap->get_active(); + spot.CCmaskreticurve = CCmaskretishape->getCurve(); + spot.LLmaskreticurve = LLmaskretishape->getCurve(); + spot.HHmaskreticurve = HHmaskretishape->getCurve(); + spot.blendmaskreti = blendmaskreti->getIntValue(); + spot.radmaskreti = radmaskreti->getValue(); + spot.lapmaskreti = lapmaskreti->getValue(); + spot.chromaskreti = chromaskreti->getValue(); + spot.gammaskreti = gammaskreti->getValue(); + spot.slomaskreti = slomaskreti->getValue(); + spot.Lmaskreticurve = Lmaskretishape->getCurve(); + spot.inversret = inversret->get_active(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabRetinex::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + dehaz->setDefault((double)defSpot.dehaz); + depth->setDefault((double)defSpot.depth); + str->setDefault(defSpot.str); + sensih->setDefault((double)defSpot.sensih); + neigh->setDefault(defSpot.neigh); + vart->setDefault(defSpot.vart); + scalereti->setDefault(defSpot.scalereti); + limd->setDefault(defSpot.limd); + offs->setDefault(defSpot.offs); + chrrt->setDefault(defSpot.chrrt); + darkness->setDefault(defSpot.darkness); + lightnessreti->setDefault(defSpot.lightnessreti); + cliptm->setDefault(defSpot.cliptm); + softradiusret->setDefault(defSpot.softradiusret); + blendmaskreti->setDefault((double)defSpot.blendmaskreti); + radmaskreti->setDefault(defSpot.radmaskreti); + lapmaskreti->setDefault(defSpot.lapmaskreti); + chromaskreti->setDefault(defSpot.chromaskreti); + gammaskreti->setDefault(defSpot.gammaskreti); + slomaskreti->setDefault(defSpot.slomaskreti); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabRetinex::adjusterChanged(Adjuster* a, double newval) +{ + // Update Retinex GUI according to scalereti adjuster value + if (a == scalereti) { + updateRetinexGUI1(); + } + + // Update Retinex GUI according to str adjuster value + if (a == str) { + updateRetinexGUI3(); + } + + if (isLocActivated && exp->getEnabled()) { + if (a == dehaz) { + if (listener) { + listener->panelChanged(Evlocallabdehaz, + dehaz->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == depth) { + if (listener) { + listener->panelChanged(Evlocallabdepth, + depth->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == str) { + if (listener) { + listener->panelChanged(Evlocallabstr, + str->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensih) { + if (listener) { + listener->panelChanged(Evlocallabsensih, + sensih->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == neigh) { + if (listener) { + listener->panelChanged(Evlocallabneigh, + neigh->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == vart) { + if (listener) { + listener->panelChanged(Evlocallabvart, + vart->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == scalereti) { + if (listener) { + listener->panelChanged(Evlocallabscalereti, + scalereti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == limd) { + if (listener) { + listener->panelChanged(Evlocallablimd, + limd->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == offs) { + if (listener) { + listener->panelChanged(Evlocallaboffs, + offs->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chrrt) { + if (listener) { + listener->panelChanged(Evlocallabchrrt, + chrrt->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == darkness) { + if (listener) { + listener->panelChanged(Evlocallabdarkness, + darkness->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lightnessreti) { + if (listener) { + listener->panelChanged(Evlocallablightnessreti, + lightnessreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == cliptm) { + if (listener) { + listener->panelChanged(Evlocallabcliptm, + cliptm->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == softradiusret) { + if (listener) { + listener->panelChanged(Evlocallabsoftradiusret, + softradiusret->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskreti) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskreti, + blendmaskreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskreti) { + if (listener) { + listener->panelChanged(Evlocallabradmaskreti, + radmaskreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskreti) { + if (listener) { + listener->panelChanged(Evlocallablapmaskreti, + lapmaskreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskreti) { + if (listener) { + listener->panelChanged(Evlocallabchromaskreti, + chromaskreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskreti) { + if (listener) { + listener->panelChanged(Evlocallabgammaskreti, + gammaskreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskreti) { + if (listener) { + listener->panelChanged(Evlocallabslomaskreti, + slomaskreti->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == cTtransshape) { + if (listener) { + listener->panelChanged(EvlocallabCTtransCurve, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == cTgainshape) { + if (listener) { + listener->panelChanged(EvlocallabCTgainCurve, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmaskretishape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskretishape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskretishape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskretishape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskretishape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskretishape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmaskretishape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskretishape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenareti, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenareti, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + str->setValue(defSpot.str); + loglin->set_active(defSpot.loglin); + + if (defSpot.retinexMethod == "low") { + retinexMethod->set_active(0); + } else if (defSpot.retinexMethod == "uni") { + retinexMethod->set_active(1); + } else { + retinexMethod->set_active(2); + } + + fftwreti->set_active(defSpot.fftwreti); + equilret->set_active(defSpot.equilret); + neigh->setValue(defSpot.neigh); + vart->setValue(defSpot.vart); + scalereti->setValue(defSpot.scalereti); + limd->setValue(defSpot.limd); + offs->setValue(defSpot.offs); + chrrt->setValue(defSpot.chrrt); + darkness->setValue(defSpot.darkness); + lightnessreti->setValue(defSpot.lightnessreti); + cliptm->setValue(defSpot.cliptm); + softradiusret->setValue(defSpot.softradiusret); + cTtransshape->setCurve(defSpot.localTtranscurve); + cTgainshape->setCurve(defSpot.localTgaincurve); + enaretiMask->set_active(defSpot.enaretiMask); + enaretiMasktmap->set_active(defSpot.enaretiMasktmap); + CCmaskretishape->setCurve(defSpot.CCmaskreticurve); + LLmaskretishape->setCurve(defSpot.LLmaskreticurve); + HHmaskretishape->setCurve(defSpot.HHmaskreticurve); + blendmaskreti->setValue((double)defSpot.blendmaskreti); + radmaskreti->setValue(defSpot.radmaskreti); + lapmaskreti->setValue(defSpot.lapmaskreti); + chromaskreti->setValue(defSpot.chromaskreti); + gammaskreti->setValue(defSpot.gammaskreti); + slomaskreti->setValue(defSpot.slomaskreti); + Lmaskretishape->setCurve(defSpot.Lmaskreticurve); + inversret->set_active(defSpot.inversret); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update Retinex GUI according to scalereti adjuster value + updateRetinexGUI1(); + // - Update Retinex GUI according to inversret button state + updateRetinexGUI2(); + // - Update Retinex GUI according to str adjuster value + updateRetinexGUI3(); +} + +void LocallabRetinex::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + retiFrame->hide(); + retitoolFrame->hide(); + } else { + // Advanced widgets are shown in Expert mode + retiFrame->show(); + retitoolFrame->show(); + } +} + +void LocallabRetinex::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskretishape->updateLocallabBackground(normChromar); + LLmaskretishape->updateLocallabBackground(normLumar); + HHmaskretishape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabRetinex::lumonlyChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (lumonly->get_active()) { + listener->panelChanged(Evlocallablumonly, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallablumonly, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::loglinChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (loglin->get_active()) { + listener->panelChanged(Evlocallabloglin, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabloglin, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::retinexMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabretinexMethod, + retinexMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabRetinex::fftwretiChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (fftwreti->get_active()) { + listener->panelChanged(Evlocallabfftwreti, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabfftwreti, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::equilretChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (inversret->get_active()) { + listener->panelChanged(Evlocallabequilret, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabequilret, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::showmaskretiMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabRetinex::enaretiMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaretiMask->get_active()) { + listener->panelChanged(EvLocallabEnaretiMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaretiMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::enaretiMasktmapChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaretiMasktmap->get_active()) { + listener->panelChanged(EvLocallabEnaretiMasktmap, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaretiMasktmap, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::inversretChanged() +{ + // Update Retinex GUI according to inversret button state + updateRetinexGUI2(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (inversret->get_active()) { + listener->panelChanged(Evlocallabinversret, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabinversret, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabRetinex::updateRetinexGUI1() +{ + // Update Retinex GUI according to scalereti adjuster value + if (scalereti->getValue() == 1) { + retinexMethod->hide(); + softradiusret->hide(); + LocalcurveEditortransT->hide(); + LocalcurveEditorgainT->hide(); + } else { + retinexMethod->show(); + softradiusret->show(); + LocalcurveEditortransT->show(); + LocalcurveEditorgainT->show(); + } +} + +void LocallabRetinex::updateRetinexGUI2() +{ + // Update Retinex GUI according to inversret button state + if (inversret->get_active()) { + expmaskreti->hide(); + } else { + expmaskreti->show(); + } +} + +void LocallabRetinex::updateRetinexGUI3() +{ + if (str->getValue() >= 0.1f) { + retitoolFrame->show(); + } else { + retitoolFrame->hide(); + } +} + +/* ==== LocallabSharp ==== */ +LocallabSharp::LocallabSharp(): + LocallabTool(this, M("TP_LOCALLAB_SHARP_TOOLNAME"), M("TP_LOCALLAB_SHARP"), true), + + // Sharpening specific widgets + sharcontrast(Gtk::manage(new Adjuster(M("TP_SHARPENING_CONTRAST"), 0, 200, 1, 20))), + sharblur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHARBLUR"), 0.2, 2.0, 0.05, 0.2))), + sharamount(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHARAMOUNT"), 0, 100, 1, 100))), + shardamping(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHARDAMPING"), 0, 100, 1, 0))), + shariter(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHARITER"), 5, 100, 1, 30))), + sharradius(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHARRADIUS"), 0.4, 2.5, 0.01, 0.75))), + sensisha(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIS"), 0, 100, 1, 40))), + inverssha(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVERS")))), + showmasksharMethod(Gtk::manage(new MyComboBoxText())) +{ + // Parameter Sharpening specific widgets + sharcontrast->setAdjusterListener(this); + + sharradius->setAdjusterListener(this); + + sharamount->setAdjusterListener(this); + + shardamping->setAdjusterListener(this); + + shariter->setAdjusterListener(this); + + sharblur->setAdjusterListener(this); + + sensisha->setAdjusterListener(this); + + inversshaConn = inverssha->signal_toggled().connect(sigc::mem_fun(*this, &LocallabSharp::inversshaChanged)); + + showmasksharMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmasksharMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmasksharMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmasksharMethod->set_active(0); + showmasksharMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmasksharMethodConn = showmasksharMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabSharp::showmasksharMethodChanged)); + + // Add Sharpening specific widgets to GUI + pack_start(*sharcontrast); + pack_start(*sharblur); + pack_start(*sharradius); + pack_start(*sharamount); + pack_start(*shardamping); + pack_start(*shariter); + pack_start(*sensisha); + pack_start(*inverssha); + Gtk::Frame* const sharFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_SHARFRAME"))); + sharFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const sharfBox = Gtk::manage(new ToolParamBlock()); + sharfBox->pack_start(*showmasksharMethod); + sharFrame->add(*sharfBox); + pack_start(*sharFrame); +} + +bool LocallabSharp::isMaskViewActive() +{ + return (showmasksharMethod->get_active_row_number() != 0); +} + +void LocallabSharp::resetMaskView() +{ + showmasksharMethodConn.block(true); + showmasksharMethod->set_active(0); + showmasksharMethodConn.block(false); +} + +void LocallabSharp::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + sharMask = showmasksharMethod->get_active_row_number(); +} + +void LocallabSharp::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_EXPSHARP_TOOLTIP")); + sensisha->set_tooltip_text(M("TP_LOCALLAB_SENSIS_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + sensisha->set_tooltip_text(""); + } +} + +void LocallabSharp::disableListener() +{ + LocallabTool::disableListener(); + + inversshaConn.block(true); + showmasksharMethodConn.block(true); +} + +void LocallabSharp::enableListener() +{ + LocallabTool::enableListener(); + + inversshaConn.block(false); + showmasksharMethodConn.block(false); +} + +void LocallabSharp::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visisharp); + exp->setEnabled(spot.expsharp); + complexity->set_active(spot.complexsharp); + + sharcontrast->setValue((double)spot.sharcontrast); + sharradius->setValue(spot.sharradius); + sharamount->setValue((double)spot.sharamount); + shardamping->setValue((double)spot.shardamping); + shariter->setValue((double)spot.shariter); + sharblur->setValue(spot.sharblur); + sensisha->setValue((double)spot.sensisha); + inverssha->set_active(spot.inverssha); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabSharp::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expsharp = exp->getEnabled(); + spot.visisharp = exp->get_visible(); + spot.complexsharp = complexity->get_active_row_number(); + + spot.sharcontrast = sharcontrast->getIntValue(); + spot.sharradius = sharradius->getValue(); + spot.sharamount = sharamount->getIntValue(); + spot.shardamping = shardamping->getIntValue(); + spot.shariter = shariter->getIntValue(); + spot.sharblur = sharblur->getValue(); + spot.sensisha = sensisha->getIntValue(); + spot.inverssha = inverssha->get_active(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabSharp::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + sharcontrast->setDefault((double)defSpot.sharcontrast); + sharradius->setDefault(defSpot.sharradius); + sharamount->setDefault((double)defSpot.sharamount); + shardamping->setDefault((double)defSpot.shardamping); + shariter->setDefault((double)defSpot.shariter); + sharblur->setDefault(defSpot.sharblur); + sensisha->setDefault((double)defSpot.sensisha); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabSharp::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == sharcontrast) { + if (listener) { + listener->panelChanged(Evlocallabsharcontrast, + sharcontrast->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sharradius) { + if (listener) { + listener->panelChanged(Evlocallabsharradius, + sharradius->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sharamount) { + if (listener) { + listener->panelChanged(Evlocallabsharamount, + sharamount->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shardamping) { + if (listener) { + listener->panelChanged(Evlocallabshardamping, + shardamping->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shariter) { + if (listener) { + listener->panelChanged(Evlocallabshariter, + shariter->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sharblur) { + if (listener) { + listener->panelChanged(Evlocallabsharblur, + sharblur->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensisha) { + if (listener) { + listener->panelChanged(Evlocallabsensis, + sensisha->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabSharp::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenasharp, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenasharp, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabSharp::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + shardamping->setValue((double)defSpot.shardamping); + shariter->setValue((double)defSpot.shariter); + sharblur->setValue(defSpot.sharblur); + sharamount->setValue(defSpot.sharamount); + + // Enable all listeners + enableListener(); +} + +void LocallabSharp::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + shardamping->hide(); + shariter->hide(); + sharblur->hide(); + sharcontrast->hide(); + sharamount->hide(); + } else { + // Advanced widgets are shown in Expert mode + shardamping->show(); + shariter->show(); + sharblur->hide(); + sharcontrast->hide(); + sharamount->show(); + } +} + +void LocallabSharp::inversshaChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (inverssha->get_active()) { + listener->panelChanged(Evlocallabinverssha, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabinverssha, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabSharp::showmasksharMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +/* ==== LocallabContrast ==== */ +LocallabContrast::LocallabContrast(): + LocallabTool(this, M("TP_LOCALLAB_LC_TOOLNAME"), M("TP_LOCALLAB_LOC_CONTRAST"), true), + + // Local contrast specific widgets + localcontMethod(Gtk::manage(new MyComboBoxText())), + lcradius(Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_RADIUS"), 10, 100, 1, 80))), + lcamount(Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_AMOUNT"), 0, 1.0, 0.01, 0))), + lcdarkness(Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_DARKNESS"), 0, 3.0, 0.01, 1.0))), + lclightness(Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_LIGHTNESS"), 0, 3.0, 0.01, 1.0))), + sigmalc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 2.5, 0.01, 1.))), + LocalcurveEditorwav(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAV"))), + wavshape(static_cast(LocalcurveEditorwav->addCurve(CT_Flat, "", nullptr, false, false))), + levelwav(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LEVELWAV"), 1, 9, 1, 4))), + csThreshold(Gtk::manage(new ThresholdAdjuster(M("TP_LOCALLAB_CSTHRESHOLD"), 0, 9, 0, 0, 6, 6, 0, false))), + expresidpyr(Gtk::manage(new MyExpander(false, Gtk::manage(new Gtk::HBox())))), + residcont(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDCONT"), -100, 100, 1, 0))), + residchro(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDCHRO"), -100., 100., 1., 0.))), + residsha(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDSHA"), -100., 100., 1., 0.))), + residshathr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDSHATHR"), 0., 100., 1., 30.))), + residhi(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDHI"), -100., 100., 1., 0.))), + residhithr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDHITHR"), 0., 100., 1., 70.))), + sensilc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIS"), 0, 100, 1, 60))), + clariFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_CLARIFRA")))), + clarilres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CLARILRES"), -20., 100., 0.5, 0.))), + claricres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CLARICRES"), -20., 100., 0.5, 0.))), + clarisoft(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 1000.0, 0.5, 1.))), + origlc(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ORIGLC")))), + expcontrastpyr(Gtk::manage(new MyExpander(false, Gtk::manage(new Gtk::HBox())))), + wavgradl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_GRALWFRA")))), + sigmalc2(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 2.5, 0.01, 1.))), + strwav(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -4.0, 4.0, 0.05, 0.))), + angwav(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180, 180, 0.1, 0.))), + wavedg(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EDGFRA")))), + strengthw(Gtk::manage(new Adjuster(M("TP_WAVELET_EDVAL"), 0., 100.0, 0.5, 0.))), + sigmaed(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 2.5, 0.01, 1.))), + LocalcurveEditorwavedg(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVEDG"))), + wavshapeedg(static_cast(LocalcurveEditorwavedg->addCurve(CT_Flat, "", nullptr, false, false))), + gradw(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEDETECT"), 0., 100.0, 0.5, 90.))), + waveshow(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EDGSHOW")))), + edgsBoxshow(Gtk::manage(new ToolParamBlock())), + radiusw(Gtk::manage(new Adjuster(M("TP_WAVELET_EDRAD"), 5., 100.0, 0.5, 15.))), + detailw(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGTHRESH"), -50., 100.0, 1., 10.))), + localedgMethod(Gtk::manage(new MyComboBoxText())), + tloww(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEDETECTTHR"), 0., 100.0, 1., 20.))), + thigw(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEDETECTTHR2"), -10., 100.0, 1., 0.))), + edgw(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGESENSI"), 0., 100.0, 1., 60.))), + basew(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEAMPLI"), 0., 100.0, 1., 10.))), + localneiMethod(Gtk::manage(new MyComboBoxText())), + wavblur(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_BLURLEVELFRA")))), + levelblur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LEVELBLUR"), 0., 100., 0.5, 0.))), + sigmabl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 2.5, 0.01, 1.))), + chromablu(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMABLU"), 0.0, 5., 0.1, 0.))), + LocalcurveEditorwavlev(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVLEV"))), + wavshapelev(static_cast(LocalcurveEditorwavlev->addCurve(CT_Flat, "", nullptr, false, false))), + residblur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDBLUR"), 0., 100., 0.5, 0.))), + blurlc(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_BLURLC")))), + expcontrastpyr2(Gtk::manage(new MyExpander(false, Gtk::manage(new Gtk::HBox())))), + wavcont(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_CONTFRA")))), + sigma(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 2.5, 0.01, 1.))), + offset(Gtk::manage(new Adjuster(M("TP_LOCALLAB_OFFSETWAV"), 0.33, 1.66, 0.01, 1., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + chromalev(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMALEV"), 0.1, 5., 0.1, 1.))), + LocalcurveEditorwavcon(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVCON"))), + wavshapecon(static_cast(LocalcurveEditorwavcon->addCurve(CT_Flat, "", nullptr, false, false))), + wavcompre(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_COMPREFRA")))), + LocalcurveEditorwavcompre(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVCOMPRE"))), + wavshapecompre(static_cast(LocalcurveEditorwavcompre->addCurve(CT_Flat, "", nullptr, false, false))), + sigmadr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 2.5, 0.01, 1.))), + threswav(Gtk::manage(new Adjuster(M("TP_LOCALLAB_THRESWAV"), 0.9, 2., 0.01, 1.4))), + residcomp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDCOMP"), -1., 1., 0.01, 0.))), + wavcomp(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_COMPFRA")))), + sigmadc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SIGMAWAV"), 0.2, 3., 0.01, 1.))), + deltad(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DELTAD"), -3., 3., 0.1, 0.))),//, Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + LocalcurveEditorwavcomp(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVCOMP"))), + wavshapecomp(static_cast(LocalcurveEditorwavcomp->addCurve(CT_Flat, "", nullptr, false, false))), + fatres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATRES"), 0., 100., 1., 0.))), + fftwlc(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FFTW")))), + expmasklc(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWLC")))), + showmasklcMethod(Gtk::manage(new MyComboBoxText())), + enalcMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + masklcCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmasklc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmasklc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + chromasklc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + mask2lcCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmasklcshape(static_cast(mask2lcCurveEditorG->addCurve(CT_Diagonal, "L(L)"))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Local contrast specific widgets + localcontMethod->append(M("TP_LOCALLAB_LOCCONT")); + localcontMethod->append(M("TP_LOCALLAB_WAVE")); + localcontMethod->set_active(0); + localcontMethodConn = localcontMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabContrast::localcontMethodChanged)); + + lcradius->setAdjusterListener(this); + + lcamount->setAdjusterListener(this); + + lcdarkness->setAdjusterListener(this); + + lclightness->setAdjusterListener(this); + sigmalc->setAdjusterListener(this); + + LocalcurveEditorwav->setCurveListener(this); + + wavshape->setIdentityValue(0.); + wavshape->setResetCurve(FlatCurveType(defSpot.locwavcurve.at(0)), defSpot.locwavcurve); + wavshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + LocalcurveEditorwav->curveListComplete(); + + levelwav->setAdjusterListener(this); + + csThreshold->setAdjusterListener(this); + + Gtk::HBox* const LresTitleHBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const LresLabel = Gtk::manage(new Gtk::Label()); + LresLabel->set_markup(Glib::ustring("") + escapeHtmlChars(M("TP_LOCALLAB_LOC_RESIDPYR")) + Glib::ustring("")); + LresLabel->set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + LresTitleHBox->pack_start(*LresLabel, Gtk::PACK_EXPAND_WIDGET, 0); + expresidpyr->setLabel(LresTitleHBox); + setExpandAlignProperties(expresidpyr, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + residcont->setAdjusterListener(this); + + residchro->setAdjusterListener(this); + + residsha->setAdjusterListener(this); + + residshathr->setAdjusterListener(this); + + residhi->setAdjusterListener(this); + + residhithr->setAdjusterListener(this); + + sensilc->setAdjusterListener(this); + + clariFrame->set_label_align(0.025, 0.5); + + clarilres->setAdjusterListener(this); + + claricres->setAdjusterListener(this); + + clarisoft->setLogScale(10, 0); + clarisoft->setAdjusterListener(this); + + origlcConn = origlc->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::origlcChanged)); + + Gtk::HBox* const LCTitleHBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const LCLabel = Gtk::manage(new Gtk::Label()); + LCLabel->set_markup(Glib::ustring("") + escapeHtmlChars(M("TP_LOCALLAB_LOC_CONTRASTPYR")) + Glib::ustring("") + escapeHtmlChars(M("TP_LOCALLAB_LOC_CONTRASTPYRLAB"))); + LCLabel->set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + LCTitleHBox->pack_start(*LCLabel, Gtk::PACK_EXPAND_WIDGET, 0); + expcontrastpyr->setLabel(LCTitleHBox); + setExpandAlignProperties(expcontrastpyr, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + wavgradlConn = wavgradl->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::wavgradlChanged)); + + sigmalc2->setAdjusterListener(this); + + strwav->setAdjusterListener(this); + + angwav->setAdjusterListener(this); + + wavedgConn = wavedg->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::wavedgChanged)); + + strengthw->setAdjusterListener(this); + + sigmaed->setAdjusterListener(this); + + LocalcurveEditorwavedg->setCurveListener(this); + + wavshapeedg->setIdentityValue(0.); + wavshapeedg->setResetCurve(FlatCurveType(defSpot.locedgwavcurve.at(0)), defSpot.locedgwavcurve); + wavshapeedg->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + LocalcurveEditorwavedg->curveListComplete(); + + gradw->setAdjusterListener(this); + + waveshowConn = waveshow->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::waveshowChanged)); + + radiusw->setAdjusterListener(this); + + detailw->setAdjusterListener(this); + + localedgMethod->append(M("TP_WAVELET_RE1")); + localedgMethod->append(M("TP_WAVELET_RE2")); + localedgMethod->append(M("TP_WAVELET_RE3")); + localedgMethod->set_active(0); + localedgMethodConn = localedgMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabContrast::localedgMethodChanged)); + + tloww->setAdjusterListener(this); + + thigw->setAdjusterListener(this); + + edgw->setAdjusterListener(this); + + basew->setAdjusterListener(this); + + localneiMethod->append(M("TP_WAVELET_NPNONE")); + localneiMethod->append(M("TP_WAVELET_NPLOW")); + localneiMethod->append(M("TP_WAVELET_NPHIGH")); + localneiMethod->set_active(0); + localneiMethodConn = localneiMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabContrast::localneiMethodChanged)); + + wavblurConn = wavblur->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::wavblurChanged)); + + levelblur->setAdjusterListener(this); + + sigmabl->setAdjusterListener(this); + + chromablu->setAdjusterListener(this); + + LocalcurveEditorwavlev->setCurveListener(this); + + wavshapelev->setIdentityValue(0.); + wavshapelev->setResetCurve(FlatCurveType(defSpot.loclevwavcurve.at(0)), defSpot.loclevwavcurve); + + LocalcurveEditorwavlev->curveListComplete(); + + residblur->setAdjusterListener(this); + + blurlcConn = blurlc->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::blurlcChanged)); + + Gtk::HBox* const LCTitleHBox2 = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const LCLabel2 = Gtk::manage(new Gtk::Label()); + LCLabel2->set_markup(Glib::ustring("") + escapeHtmlChars(M("TP_LOCALLAB_LOC_CONTRASTPYR2")) + Glib::ustring("") + escapeHtmlChars(M("TP_LOCALLAB_LOC_CONTRASTPYR2LAB"))); + LCLabel2->set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + LCTitleHBox2->pack_start(*LCLabel2, Gtk::PACK_EXPAND_WIDGET, 0); + expcontrastpyr2->setLabel(LCTitleHBox2); + setExpandAlignProperties(expcontrastpyr2, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + wavcontConn = wavcont->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::wavcontChanged)); + + sigma->setAdjusterListener(this); + + offset->setAdjusterListener(this); + + chromalev->setAdjusterListener(this); + + LocalcurveEditorwavcon->setCurveListener(this); + + wavshapecon->setIdentityValue(0.); + wavshapecon->setResetCurve(FlatCurveType(defSpot.locconwavcurve.at(0)), defSpot.locconwavcurve); + + LocalcurveEditorwavcon->curveListComplete(); + + wavcompreConn = wavcompre->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::wavcompreChanged)); + + LocalcurveEditorwavcompre->setCurveListener(this); + + wavshapecompre->setIdentityValue(0.); + wavshapecompre->setResetCurve(FlatCurveType(defSpot.loccomprewavcurve.at(0)), defSpot.loccomprewavcurve); + wavshapecompre->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + + LocalcurveEditorwavcompre->curveListComplete(); + + sigmadr->setAdjusterListener(this); + + threswav->setAdjusterListener(this); + + residcomp->setAdjusterListener(this); + + wavcompConn = wavcomp->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::wavcompChanged)); + + sigmadc->setAdjusterListener(this); + + deltad->setAdjusterListener(this); + + LocalcurveEditorwavcomp->setCurveListener(this); + + wavshapecomp->setIdentityValue(0.); + wavshapecomp->setResetCurve(FlatCurveType(defSpot.loccompwavcurve.at(0)), defSpot.loccompwavcurve); + wavshapecomp->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + LocalcurveEditorwavcomp->curveListComplete(); + + fatres->setAdjusterListener(this); + + fftwlcConn = fftwlc->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::fftwlcChanged)); + + setExpandAlignProperties(expmasklc, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmasklcMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmasklcMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmasklcMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmasklcMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmasklcMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmasklcMethod->set_active(0); + showmasklcMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmasklcMethodConn = showmasklcMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabContrast::showmasklcMethodChanged)); + + enalcMaskConn = enalcMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabContrast::enalcMaskChanged)); + + masklcCurveEditorG->setCurveListener(this); + + CCmasklcshape->setIdentityValue(0.); + CCmasklcshape->setResetCurve(FlatCurveType(defSpot.CCmasklccurve.at(0)), defSpot.CCmasklccurve); + CCmasklcshape->setBottomBarColorProvider(this, 1); + + LLmasklcshape->setIdentityValue(0.); + LLmasklcshape->setResetCurve(FlatCurveType(defSpot.LLmasklccurve.at(0)), defSpot.LLmasklccurve); + LLmasklcshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmasklcshape->setIdentityValue(0.); + HHmasklcshape->setResetCurve(FlatCurveType(defSpot.HHmasklccurve.at(0)), defSpot.HHmasklccurve); + HHmasklcshape->setCurveColorProvider(this, 2); + HHmasklcshape->setBottomBarColorProvider(this, 2); + + masklcCurveEditorG->curveListComplete(); + + blendmasklc->setAdjusterListener(this); + + radmasklc->setLogScale(10, -10); + radmasklc->setAdjusterListener(this); + + chromasklc->setAdjusterListener(this); + + mask2lcCurveEditorG->setCurveListener(this); + + Lmasklcshape->setResetCurve(DiagonalCurveType(defSpot.Lmasklccurve.at(0)), defSpot.Lmasklccurve); + Lmasklcshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmasklcshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2lcCurveEditorG->curveListComplete(); + + // Add Local contrast specific widgets to GUI + pack_start(*localcontMethod); + pack_start(*lcradius); + pack_start(*lcamount); + pack_start(*lcdarkness); + pack_start(*lclightness); + pack_start(*sigmalc); + pack_start(*LocalcurveEditorwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + // pack_start(*levelwav); + pack_start(*csThreshold); + Gtk::Frame* const shresFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_SHRESFRA"))); + shresFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const resiBox = Gtk::manage(new ToolParamBlock()); + resiBox->pack_start(*residcont); + resiBox->pack_start(*residchro); + ToolParamBlock* const shresBox = Gtk::manage(new ToolParamBlock()); + shresBox->pack_start(*residsha); + shresBox->pack_start(*residshathr); + shresBox->pack_start(*residhi); + shresBox->pack_start(*residhithr); + shresFrame->add(*shresBox); + resiBox->pack_start(*shresFrame); + expresidpyr->add(*resiBox, false); + pack_start(*expresidpyr); + pack_start(*sensilc); + Gtk::HSeparator* const separatorcontr = Gtk::manage(new Gtk::HSeparator()); + pack_start(*separatorcontr); + ToolParamBlock* const clariBox = Gtk::manage(new ToolParamBlock()); + clariBox->pack_start(*clarilres); + clariBox->pack_start(*claricres); + clariBox->pack_start(*clarisoft); + clariBox->pack_start(*origlc); + clariFrame->add(*clariBox); + pack_start(*clariFrame); + ToolParamBlock* const blurcontBox = Gtk::manage(new ToolParamBlock()); + Gtk::Frame* const gradwavFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRADWAVFRA"))); + gradwavFrame->set_label_align(0.025, 0.5); + gradwavFrame->set_label_widget(*wavgradl); + ToolParamBlock* const gradwavBox = Gtk::manage(new ToolParamBlock()); + gradwavBox->pack_start(*sigmalc2); + gradwavBox->pack_start(*strwav); + gradwavBox->pack_start(*angwav); + gradwavFrame->add(*gradwavBox); + blurcontBox->pack_start(*gradwavFrame); + Gtk::Frame* const edgFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_EDGSHARPFRA"))); + edgFrame->set_label_align(0.025, 0.5); + edgFrame->set_label_widget(*wavedg); + ToolParamBlock* const edgsBox = Gtk::manage(new ToolParamBlock()); + edgsBox->pack_start(*strengthw); + edgsBox->pack_start(*sigmaed); + edgsBox->pack_start(*LocalcurveEditorwavedg, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + edgsBox->pack_start(*gradw); + edgsBox->pack_start(*waveshow); + edgsBoxshow->pack_start(*radiusw); + edgsBoxshow->pack_start(*detailw); + Gtk::HBox* const edbox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labmedgr = Gtk::manage(new Gtk::Label(M("TP_WAVELET_MEDGREINF") + ":")); + edbox->pack_start(*labmedgr, Gtk::PACK_SHRINK, 1); + edbox->pack_start(*localedgMethod); + edgsBoxshow->pack_start(*edbox); + Gtk::HSeparator* const separatoredg2 = Gtk::manage(new Gtk::HSeparator()); + edgsBoxshow->pack_start(*separatoredg2); + edgsBoxshow->pack_start(*tloww); + edgsBoxshow->pack_start(*thigw); + Gtk::HSeparator* const separatoredg = Gtk::manage(new Gtk::HSeparator()); + edgsBoxshow->pack_start(*separatoredg); + edgsBoxshow->pack_start(*edgw); + edgsBoxshow->pack_start(*basew); + Gtk::HBox* const ctboxNP = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const labmNP = Gtk::manage(new Gtk::Label(M("TP_WAVELET_NPTYPE") + ":")); + ctboxNP->pack_start(*labmNP, Gtk::PACK_SHRINK, 1); + ctboxNP->pack_start(*localneiMethod); + edgsBoxshow->pack_start(*ctboxNP); + edgsBox->pack_start(*edgsBoxshow); + edgFrame->add(*edgsBox); + blurcontBox->pack_start(*edgFrame); + Gtk::Frame* const blurlevelFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_BLURLEVELFRA"))); + blurlevelFrame->set_label_align(0.025, 0.5); + blurlevelFrame->set_label_widget(*wavblur); + Gtk::VBox* const blurlevcontBox = Gtk::manage(new Gtk::VBox()); + blurlevcontBox->set_spacing(2); + blurlevcontBox->pack_start(*levelblur); + blurlevcontBox->pack_start(*sigmabl); + blurlevcontBox->pack_start(*chromablu); + blurlevcontBox->pack_start(*LocalcurveEditorwavlev, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + Gtk::HSeparator* const separatorblu = Gtk::manage(new Gtk::HSeparator()); + blurlevcontBox->pack_start(*separatorblu); + blurlevcontBox->pack_start(*residblur); + blurlevcontBox->pack_start(*blurlc); + blurlevelFrame->add(*blurlevcontBox); + blurcontBox->pack_start(*blurlevelFrame); + expcontrastpyr->add(*blurcontBox, false); + pack_start(*expcontrastpyr); + ToolParamBlock* const blurcontBox2 = Gtk::manage(new ToolParamBlock()); + Gtk::Frame* const contFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_CONTFRA"))); + contFrame->set_label_align(0.025, 0.5); + Gtk::VBox* const contlevBox = Gtk::manage(new Gtk::VBox()); + contlevBox->set_spacing(2); + contFrame->set_label_widget(*wavcont); + contlevBox->pack_start(*sigma); + contlevBox->pack_start(*offset); + contlevBox->pack_start(*chromalev); + contlevBox->pack_start(*LocalcurveEditorwavcon, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + contFrame->add(*contlevBox); + blurcontBox2->pack_start(*contFrame); + Gtk::Frame* const compreFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_COMPREFRA"))); + compreFrame->set_label_align(0.025, 0.5); + Gtk::VBox* const compreBox = Gtk::manage(new Gtk::VBox()); + compreBox->set_spacing(2); + compreFrame->set_label_widget(*wavcompre); + compreBox->pack_start(*LocalcurveEditorwavcompre, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + compreBox->pack_start(*sigmadr); + compreBox->pack_start(*threswav); + compreBox->pack_start(*residcomp); + compreFrame->add(*compreBox); + blurcontBox2->pack_start(*compreFrame); + Gtk::Frame* const compFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_COMPFRA"))); + compFrame->set_label_align(0.025, 0.5); + Gtk::VBox* const compBox = Gtk::manage(new Gtk::VBox()); + compBox->set_spacing(2); + compFrame->set_label_widget(*wavcomp); + compBox->pack_start(*sigmadc); + compBox->pack_start(*deltad); + compBox->pack_start(*LocalcurveEditorwavcomp, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + // Gtk::HSeparator* const separatorcomp = Gtk::manage(new Gtk::HSeparator()); + // compBox->pack_start(*separatorcomp); + // compBox->pack_start(*fatres); + compFrame->add(*compBox); + blurcontBox2->pack_start(*compFrame); + expcontrastpyr2->add(*blurcontBox2, false); + pack_start(*expcontrastpyr2); + pack_start(*fftwlc); + ToolParamBlock* const masklcBox = Gtk::manage(new ToolParamBlock()); + masklcBox->pack_start(*showmasklcMethod, Gtk::PACK_SHRINK, 4); + masklcBox->pack_start(*enalcMask, Gtk::PACK_SHRINK, 0); + masklcBox->pack_start(*masklcCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + masklcBox->pack_start(*blendmasklc, Gtk::PACK_SHRINK, 0); + masklcBox->pack_start(*radmasklc, Gtk::PACK_SHRINK, 0); + masklcBox->pack_start(*chromasklc, Gtk::PACK_SHRINK, 0); + masklcBox->pack_start(*mask2lcCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + expmasklc->add(*masklcBox, false); + pack_start(*expmasklc, false, false); +} + +LocallabContrast::~LocallabContrast() +{ + delete LocalcurveEditorwav; + delete LocalcurveEditorwavedg; + delete LocalcurveEditorwavlev; + delete LocalcurveEditorwavcon; + delete LocalcurveEditorwavcompre; + delete LocalcurveEditorwavcomp; + delete masklcCurveEditorG; + delete mask2lcCurveEditorG; +} + +bool LocallabContrast::isMaskViewActive() +{ + return (showmasklcMethod->get_active_row_number() != 0); +} + +void LocallabContrast::resetMaskView() +{ + showmasklcMethodConn.block(true); + showmasklcMethod->set_active(0); + showmasklcMethodConn.block(false); +} + +void LocallabContrast::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + lcMask = showmasklcMethod->get_active_row_number(); +} + +void LocallabContrast::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_EXPCONTRAST_TOOLTIP")); + levelwav->set_tooltip_markup(M("TP_LOCALLAB_LEVELWAV_TOOLTIP")); + LocalcurveEditorwav->set_tooltip_markup(M("TP_LOCALLAB_LEVELLOCCONTRAST_TOOLTIP")); + wavgradl->set_tooltip_text(M("TP_LOCALLAB_WAVGRAD_TOOLTIP")); + clariFrame->set_tooltip_markup(M("TP_LOCALLAB_CLARI_TOOLTIP")); + clarisoft->set_tooltip_markup(M("TP_LOCALLAB_CLARISOFT_TOOLTIP")); + wavedg->set_tooltip_text(M("TP_LOCALLAB_WAVEEDG_TOOLTIP")); + wavblur->set_tooltip_text(M("TP_LOCALLAB_WAVBLUR_TOOLTIP")); + wavcont->set_tooltip_text(M("TP_LOCALLAB_WAVCONTF_TOOLTIP")); + wavcompre->set_tooltip_text(M("TP_LOCALLAB_WAVCOMPRE_TOOLTIP")); + wavcomp->set_tooltip_text(M("TP_LOCALLAB_WAVCOMP_TOOLTIP")); + chromablu->set_tooltip_text(M("TP_LOCALLAB_CHROMABLU_TOOLTIP")); + chromalev->set_tooltip_text(M("TP_LOCALLAB_CHROMABLU_TOOLTIP")); + fftwlc->set_tooltip_text(M("TP_LOCALLAB_LC_FFTW_TOOLTIP")); + expmasklc->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmasklcshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmasklcshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmasklcshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + Lmasklcshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + expcontrastpyr->set_tooltip_text(M("TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP")); + expcontrastpyr2->set_tooltip_text(M("TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP")); + blendmasklc->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2lcCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + levelwav->set_tooltip_text(""); + LocalcurveEditorwav->set_tooltip_markup(M("")); + wavgradl->set_tooltip_text(""); + clariFrame->set_tooltip_text(""); + clarisoft->set_tooltip_text(""); + wavedg->set_tooltip_text(""); + wavblur->set_tooltip_text(M("")); + wavcont->set_tooltip_text(M("")); + wavcompre->set_tooltip_text(M("")); + wavcomp->set_tooltip_text(M("")); + chromablu->set_tooltip_text(""); + chromalev->set_tooltip_text(""); + fftwlc->set_tooltip_text(""); + expmasklc->set_tooltip_text(""); + CCmasklcshape->setTooltip(""); + LLmasklcshape->setTooltip(""); + HHmasklcshape->setTooltip(""); + Lmasklcshape->setTooltip(""); + expcontrastpyr->set_tooltip_text(M("")); + expcontrastpyr2->set_tooltip_text(M("")); + blendmasklc->set_tooltip_text(M("")); + mask2lcCurveEditorG->set_tooltip_text(M("")); + } +} + +void LocallabContrast::setDefaultExpanderVisibility() +{ + expresidpyr->set_expanded(false); + expcontrastpyr->set_expanded(false); + expcontrastpyr2->set_expanded(false); + expmasklc->set_expanded(false); +} + +void LocallabContrast::disableListener() +{ + LocallabTool::disableListener(); + + localcontMethodConn.block(true); + origlcConn.block(true); + wavgradlConn.block(true); + wavedgConn.block(true); + localedgMethodConn.block(true); + waveshowConn.block(true); + localneiMethodConn.block(true); + wavblurConn.block(true); + blurlcConn.block(true); + wavcontConn.block(true); + wavcompreConn.block(true); + wavcompConn.block(true); + fftwlcConn.block(true); + showmasklcMethodConn.block(true); + enalcMaskConn.block(true); +} + +void LocallabContrast::enableListener() +{ + LocallabTool::enableListener(); + + localcontMethodConn.block(false); + origlcConn.block(false); + wavgradlConn.block(false); + wavedgConn.block(false); + localedgMethodConn.block(false); + waveshowConn.block(false); + localneiMethodConn.block(false); + wavblurConn.block(false); + blurlcConn.block(false); + wavcontConn.block(false); + wavcompreConn.block(false); + wavcompConn.block(false); + fftwlcConn.block(false); + showmasklcMethodConn.block(false); + enalcMaskConn.block(false); +} + +void LocallabContrast::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visicontrast); + exp->setEnabled(spot.expcontrast); + complexity->set_active(spot.complexcontrast); + + if (spot.localcontMethod == "loc") { + localcontMethod->set_active(0); + } else if (spot.localcontMethod == "wav") { + localcontMethod->set_active(1); + } + + fftwlc->set_active(spot.fftwlc); + // Update Local contrast GUI according to fftwlc button state + // Note: Contrary to the others, shall be called before setting 'lcradius' value + updateContrastGUI3(); + lcradius->setValue((double)spot.lcradius); + lcamount->setValue(spot.lcamount); + lcdarkness->setValue(spot.lcdarkness); + lclightness->setValue(spot.lclightness); + sigmalc->setValue(spot.sigmalc); + wavshape->setCurve(spot.locwavcurve); + levelwav->setValue((double)spot.levelwav); + csThreshold->setValue(spot.csthreshold); + residcont->setValue(spot.residcont); + residchro->setValue(spot.residchro); + residsha->setValue(spot.residsha); + residshathr->setValue(spot.residshathr); + residhi->setValue(spot.residhi); + residhithr->setValue(spot.residhithr); + sensilc->setValue((double)spot.sensilc); + clarilres->setValue(spot.clarilres); + claricres->setValue(spot.claricres); + clarisoft->setValue(spot.clarisoft); + origlc->set_active(spot.origlc); + wavgradl->set_active(spot.wavgradl); + sigmalc2->setValue(spot.sigmalc2); + strwav->setValue(spot.strwav); + angwav->setValue(spot.angwav); + wavedg->set_active(spot.wavedg); + strengthw->setValue(spot.strengthw); + sigmaed->setValue(spot.sigmaed); + wavshapeedg->setCurve(spot.locedgwavcurve); + gradw->setValue(spot.gradw); + waveshow->set_active(spot.waveshow); + radiusw->setValue(spot.radiusw); + detailw->setValue(spot.detailw); + + if (spot.localedgMethod == "fir") { + localedgMethod->set_active(0); + } else if (spot.localedgMethod == "sec") { + localedgMethod->set_active(1); + } else if (spot.localedgMethod == "thr") { + localedgMethod->set_active(2); + } + + tloww->setValue(spot.tloww); + thigw->setValue(spot.thigw); + edgw->setValue(spot.edgw); + basew->setValue(spot.basew); + + if (spot.localneiMethod == "none") { + localneiMethod->set_active(0); + } else if (spot.localneiMethod == "low") { + localneiMethod->set_active(1); + } else if (spot.localneiMethod == "high") { + localneiMethod->set_active(2); + } + + wavblur->set_active(spot.wavblur); + levelblur->setValue(spot.levelblur); + sigmabl->setValue(spot.sigmabl); + chromablu->setValue(spot.chromablu); + wavshapelev->setCurve(spot.loclevwavcurve); + residblur->setValue(spot.residblur); + blurlc->set_active(spot.blurlc); + wavcont->set_active(spot.wavcont); + sigma->setValue(spot.sigma); + offset->setValue(spot.offset); + chromalev->setValue(spot.chromalev); + wavshapecon->setCurve(spot.locconwavcurve); + wavcompre->set_active(spot.wavcompre); + wavshapecompre->setCurve(spot.loccomprewavcurve); + sigmadr->setValue(spot.sigmadr); + threswav->setValue(spot.threswav); + residcomp->setValue(spot.residcomp); + wavcomp->set_active(spot.wavcomp); + sigmadc->setValue(spot.sigmadc); + deltad->setValue(spot.deltad); + wavshapecomp->setCurve(spot.loccompwavcurve); + fatres->setValue(spot.fatres); + enalcMask->set_active(spot.enalcMask); + CCmasklcshape->setCurve(spot.CCmasklccurve); + LLmasklcshape->setCurve(spot.LLmasklccurve); + HHmasklcshape->setCurve(spot.HHmasklccurve); + blendmasklc->setValue((double)spot.blendmasklc); + radmasklc->setValue(spot.radmasklc); + chromasklc->setValue(spot.chromasklc); + Lmasklcshape->setCurve(spot.Lmasklccurve); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update Local contrast GUI according to localcontMethod combobox value + updateContrastGUI1(); + + // Update Local contrast GUI according to waveshow button state + updateContrastGUI2(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabContrast::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expcontrast = exp->getEnabled(); + spot.visicontrast = exp->get_visible(); + spot.complexcontrast = complexity->get_active_row_number(); + + if (localcontMethod->get_active_row_number() == 0) { + spot.localcontMethod = "loc"; + } else if (localcontMethod->get_active_row_number() == 1) { + spot.localcontMethod = "wav"; + } + + spot.lcradius = lcradius->getIntValue(); + spot.lcamount = lcamount->getValue(); + spot.lcdarkness = lcdarkness->getValue(); + spot.lclightness = lclightness->getValue(); + spot.sigmalc = sigmalc->getValue(); + spot.locwavcurve = wavshape->getCurve(); + spot.levelwav = levelwav->getIntValue(); + spot.csthreshold = csThreshold->getValue(); + spot.residcont = residcont->getValue(); + spot.residchro = residchro->getValue(); + spot.residsha = residsha->getValue(); + spot.residshathr = residshathr->getValue(); + spot.residhi = residhi->getValue(); + spot.residhithr = residhithr->getValue(); + spot.sensilc = sensilc->getIntValue(); + spot.clarilres = clarilres->getValue(); + spot.claricres = claricres->getValue(); + spot.clarisoft = clarisoft->getValue(); + spot.origlc = origlc->get_active(); + spot.wavgradl = wavgradl->get_active(); + spot.sigmalc2 = sigmalc2->getValue(); + spot.strwav = strwav->getValue(); + spot.angwav = angwav->getValue(); + spot.wavedg = wavedg->get_active(); + spot.strengthw = strengthw->getValue(); + spot.sigmaed = sigmaed->getValue(); + spot.locedgwavcurve = wavshapeedg->getCurve(); + spot.gradw = gradw->getValue(); + spot.waveshow = waveshow->get_active(); + spot.radiusw = radiusw->getValue(); + spot.detailw = detailw->getValue(); + + if (localedgMethod->get_active_row_number() == 0) { + spot.localedgMethod = "fir"; + } else if (localedgMethod->get_active_row_number() == 1) { + spot.localedgMethod = "sec"; + } else if (localedgMethod->get_active_row_number() == 2) { + spot.localedgMethod = "thr"; + } + + spot.tloww = tloww->getValue(); + spot.thigw = thigw->getValue(); + spot.edgw = edgw->getValue(); + spot.basew = basew->getValue(); + + if (localneiMethod->get_active_row_number() == 0) { + spot.localneiMethod = "none"; + } else if (localneiMethod->get_active_row_number() == 1) { + spot.localneiMethod = "low"; + } else if (localneiMethod->get_active_row_number() == 2) { + spot.localneiMethod = "high"; + } + + spot.wavblur = wavblur->get_active(); + spot.levelblur = levelblur->getValue(); + spot.sigmabl = sigmabl->getValue(); + spot.chromablu = chromablu->getValue(); + spot.loclevwavcurve = wavshapelev->getCurve(); + spot.residblur = residblur->getValue(); + spot.blurlc = blurlc->get_active(); + spot.wavcont = wavcont->get_active(); + spot.sigma = sigma->getValue(); + spot.offset = offset->getValue(); + spot.chromalev = chromalev->getValue(); + spot.locconwavcurve = wavshapecon->getCurve(); + spot.wavcompre = wavcompre->get_active(); + spot.loccomprewavcurve = wavshapecompre->getCurve(); + spot.sigmadr = sigmadr->getValue(); + spot.threswav = threswav->getValue(); + spot.residcomp = residcomp->getValue(); + spot.wavcomp = wavcomp->get_active(); + spot.sigmadc = sigmadc->getValue(); + spot.deltad = deltad->getValue(); + spot.loccompwavcurve = wavshapecomp->getCurve(); + spot.fatres = fatres->getValue(); + spot.fftwlc = fftwlc->get_active(); + spot.enalcMask = enalcMask->get_active(); + spot.CCmasklccurve = CCmasklcshape->getCurve(); + spot.LLmasklccurve = LLmasklcshape->getCurve(); + spot.HHmasklccurve = HHmasklcshape->getCurve(); + spot.blendmasklc = blendmasklc->getIntValue(); + spot.radmasklc = radmasklc->getValue(); + spot.chromasklc = chromasklc->getValue(); + spot.Lmasklccurve = Lmasklcshape->getCurve(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabContrast::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster and threshold adjuster widgets + lcradius->setDefault((double)defSpot.lcradius); + lcamount->setDefault(defSpot.lcamount); + lcdarkness->setDefault(defSpot.lcdarkness); + lclightness->setDefault(defSpot.lclightness); + sigmalc->setDefault(defSpot.sigmalc); + levelwav->setDefault((double)defSpot.levelwav); + csThreshold->setDefault(defSpot.csthreshold); + residcont->setDefault(defSpot.residcont); + residchro->setDefault(defSpot.residchro); + residsha->setDefault(defSpot.residsha); + residshathr->setDefault(defSpot.residshathr); + residhi->setDefault(defSpot.residhi); + residhithr->setDefault(defSpot.residhithr); + sensilc->setDefault((double)defSpot.sensilc); + clarilres->setDefault(defSpot.clarilres); + claricres->setDefault(defSpot.claricres); + clarisoft->setDefault(defSpot.clarisoft); + sigmalc2->setDefault(defSpot.sigmalc2); + strwav->setDefault(defSpot.strwav); + angwav->setDefault(defSpot.angwav); + strengthw->setDefault(defSpot.strengthw); + sigmaed->setDefault(defSpot.sigmaed); + gradw->setDefault(defSpot.gradw); + radiusw->setDefault(defSpot.radiusw); + detailw->setDefault(defSpot.detailw); + tloww->setDefault(defSpot.tloww); + thigw->setDefault(defSpot.thigw); + edgw->setDefault(defSpot.edgw); + basew->setDefault(defSpot.basew); + levelblur->setDefault(defSpot.levelblur); + sigmabl->setDefault(defSpot.sigmabl); + chromablu->setDefault(defSpot.chromablu); + residblur->setDefault(defSpot.residblur); + sigma->setDefault(defSpot.sigma); + offset->setDefault(defSpot.offset); + chromalev->setDefault(defSpot.chromalev); + sigmadr->setDefault(defSpot.sigmadr); + threswav->setDefault(defSpot.threswav); + residcomp->setDefault(defSpot.residcomp); + sigmadc->setDefault(defSpot.sigmadc); + deltad->setDefault(defSpot.deltad); + fatres->setDefault(defSpot.fatres); + blendmasklc->setDefault((double)defSpot.blendmasklc); + radmasklc->setDefault(defSpot.radmasklc); + chromasklc->setDefault(defSpot.chromasklc); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabContrast::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == lcradius) { + if (listener) { + listener->panelChanged(Evlocallablcradius, + lcradius->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lcamount) { + if (listener) { + listener->panelChanged(Evlocallablcamount, + lcamount->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lcdarkness) { + if (listener) { + listener->panelChanged(Evlocallablcdarkness, + lcdarkness->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lclightness) { + if (listener) { + listener->panelChanged(Evlocallablclightness, + lclightness->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigmalc) { + if (listener) { + listener->panelChanged(Evlocallabsigmalc, + sigmalc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == levelwav) { + if (listener) { + listener->panelChanged(Evlocallablevelwav, + levelwav->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residcont) { + if (listener) { + listener->panelChanged(Evlocallabresidcont, + residcont->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residchro) { + if (listener) { + listener->panelChanged(Evlocallabresidchro, + residchro->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residsha) { + if (listener) { + listener->panelChanged(Evlocallabresidsha, + residsha->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residshathr) { + if (listener) { + listener->panelChanged(Evlocallabresidshathr, + residshathr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residhi) { + if (listener) { + listener->panelChanged(Evlocallabresidhi, + residhi->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residhithr) { + if (listener) { + listener->panelChanged(Evlocallabresidhithr, + residhithr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensilc) { + if (listener) { + listener->panelChanged(Evlocallabsensilc, + sensilc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == clarilres) { + if (listener) { + listener->panelChanged(Evlocallabclarilres, + clarilres->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == claricres) { + if (listener) { + listener->panelChanged(Evlocallabclaricres, + claricres->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == clarisoft) { + if (listener) { + listener->panelChanged(Evlocallabclarisoft, + clarisoft->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigmalc2) { + if (listener) { + listener->panelChanged(Evlocallabsigmalc2, + sigmalc2->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strwav) { + if (listener) { + listener->panelChanged(Evlocallabstrwav, + strwav->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == angwav) { + if (listener) { + listener->panelChanged(Evlocallabangwav, + angwav->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strengthw) { + if (listener) { + listener->panelChanged(Evlocallabstrengthw, + strengthw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigmaed) { + if (listener) { + listener->panelChanged(Evlocallabsigmaed, + sigmaed->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gradw) { + if (listener) { + listener->panelChanged(Evlocallabgradw, + gradw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radiusw) { + if (listener) { + listener->panelChanged(Evlocallabradiusw, + radiusw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == detailw) { + if (listener) { + listener->panelChanged(Evlocallabdetailw, + detailw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == tloww) { + if (listener) { + listener->panelChanged(Evlocallabtloww, + tloww->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == thigw) { + if (listener) { + listener->panelChanged(Evlocallabthigw, + thigw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == edgw) { + if (listener) { + listener->panelChanged(Evlocallabedgw, + edgw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == basew) { + if (listener) { + listener->panelChanged(Evlocallabbasew, + basew->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == levelblur) { + if (listener) { + listener->panelChanged(Evlocallablevelblur, + levelblur->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigmabl) { + if (listener) { + listener->panelChanged(Evlocallabsigmabl, + sigmabl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromablu) { + if (listener) { + listener->panelChanged(Evlocallabchromablu, + chromablu->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residblur) { + if (listener) { + listener->panelChanged(Evlocallabresidblur, + residblur->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigma) { + if (listener) { + listener->panelChanged(Evlocallabsigma, + sigma->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == offset) { + if (listener) { + listener->panelChanged(Evlocallaboffset, + offset->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromalev) { + if (listener) { + listener->panelChanged(Evlocallabchromalev, + chromalev->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigmadr) { + if (listener) { + listener->panelChanged(Evlocallabsigmadr, + sigmadr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + + if (a == threswav) { + if (listener) { + listener->panelChanged(Evlocallabthreswav, + threswav->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == residcomp) { + if (listener) { + listener->panelChanged(Evlocallabresidcomp, + residcomp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sigmadc) { + if (listener) { + listener->panelChanged(Evlocallabsigmadc, + sigmadc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == deltad) { + if (listener) { + listener->panelChanged(Evlocallabdeltad, + deltad->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == fatres) { + if (listener) { + listener->panelChanged(Evlocallabfatres, + fatres->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmasklc) { + if (listener) { + listener->panelChanged(Evlocallabblendmasklc, + blendmasklc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmasklc) { + if (listener) { + listener->panelChanged(Evlocallabradmasklc, + radmasklc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromasklc) { + if (listener) { + listener->panelChanged(Evlocallabchromasklc, + chromasklc->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabcsThreshold, + csThreshold->getHistoryString() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabContrast::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == wavshape) { + if (listener) { + listener->panelChanged(EvlocallabwavCurve, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == wavshapeedg) { + if (listener) { + listener->panelChanged(EvlocallabwavCurveedg, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == wavshapelev) { + if (listener) { + listener->panelChanged(EvlocallabwavCurvelev, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == wavshapecon) { + if (listener) { + listener->panelChanged(EvlocallabwavCurvecon, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == wavshapecompre) { + if (listener) { + listener->panelChanged(EvlocallabwavCurvecompre, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == wavshapecomp) { + if (listener) { + listener->panelChanged(EvlocallabwavCurvecomp, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmasklcshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmasklcshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmasklcshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmasklcshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmasklcshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmasklcshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmasklcshape) { + if (listener) { + listener->panelChanged(EvlocallabLmasklcshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenacontrast, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenacontrast, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + if (defSpot.localcontMethod == "loc") { + localcontMethod->set_active(0); + } else if (defSpot.localcontMethod == "wav") { + localcontMethod->set_active(1); + } + + fftwlc->set_active(defSpot.fftwlc); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update Local contrast GUI according to localcontMethod combobox value + updateContrastGUI1(); + // - Update Local contrast GUI according to fftwlc button state + updateContrastGUI3(); +} + +void LocallabContrast::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + localcontMethod->hide(); + fftwlc->hide(); + } else { + // Advanced widgets are shown in Expert mode + localcontMethod->show(); + fftwlc->show(); + } +} + +void LocallabContrast::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmasklcshape->updateLocallabBackground(normChromar); + LLmasklcshape->updateLocallabBackground(normLumar); + HHmasklcshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabContrast::localcontMethodChanged() +{ + // Update Local contrast GUI according to localcontMethod combobox value + updateContrastGUI1(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallablocalcontMethod, + localcontMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabContrast::origlcChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (origlc->get_active()) { + listener->panelChanged(Evlocallaboriglc, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallaboriglc, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::wavgradlChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (wavgradl->get_active()) { + listener->panelChanged(Evlocallabwavgradl, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwavgradl, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::wavedgChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (wavedg->get_active()) { + listener->panelChanged(Evlocallabwavedg, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwavedg, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::localedgMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallablocaledgMethod, + localedgMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabContrast::waveshowChanged() +{ + // Update Local contrast GUI according to waveshow button state + updateContrastGUI2(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (waveshow->get_active()) { + listener->panelChanged(Evlocallabwaveshow, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwaveshow, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::localneiMethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallablocalneiMethod, + localneiMethod->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabContrast::wavblurChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (wavblur->get_active()) { + listener->panelChanged(Evlocallabwavblur, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwavblur, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::blurlcChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (blurlc->get_active()) { + listener->panelChanged(Evlocallabblurlc, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabblurlc, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::wavcontChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (wavcont->get_active()) { + listener->panelChanged(Evlocallabwavcont, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwavcont, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::wavcompreChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (wavcompre->get_active()) { + listener->panelChanged(Evlocallabwavcompre, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwavcompre, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::wavcompChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (wavcomp->get_active()) { + listener->panelChanged(Evlocallabwavcomp, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabwavcomp, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::fftwlcChanged() +{ + // Update Local contrast GUI according to fftwlc button state + updateContrastGUI3(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (fftwlc->get_active()) { + listener->panelChanged(Evlocallabfftwlc, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabfftwlc, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::showmasklcMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabContrast::enalcMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enalcMask->get_active()) { + listener->panelChanged(EvLocallabEnalcMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnalcMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabContrast::updateContrastGUI1() +{ + // Update Local contrast GUI according to localcontMethod combobox value + if (localcontMethod->get_active_row_number() == 0) { + lcradius->show(); + lcamount->show(); + lcdarkness->show(); + lclightness->show(); + sigmalc->hide(); + LocalcurveEditorwav->hide(); + levelwav->hide(); + csThreshold->hide(); + expresidpyr->hide(); + clariFrame->hide(); + expcontrastpyr->hide(); + expcontrastpyr2->hide(); + fftwlc->show(); + } else if (localcontMethod->get_active_row_number() == 1) { + lcradius->hide(); + lcamount->hide(); + lcdarkness->hide(); + lclightness->hide(); + sigmalc->show(); + LocalcurveEditorwav->show(); + levelwav->show(); + csThreshold->show(); + expresidpyr->show(); + clariFrame->show(); + expcontrastpyr->show(); + expcontrastpyr2->show(); + fftwlc->hide(); + } +} + +void LocallabContrast::updateContrastGUI2() +{ + // Update Local contrast GUI according to waveshow button state + if (waveshow->get_active()) { + edgsBoxshow->show(); + } else { + edgsBoxshow->hide(); + } +} + +void LocallabContrast::updateContrastGUI3() +{ + // Update Local contrast GUI according to fftwlc button state + const double temp = lcradius->getValue(); + + if (fftwlc->get_active()) { + lcradius->setLimits(20, 1000, 1, 80); + } else { + lcradius->setLimits(20, 100, 1, 80); + } + + lcradius->setValue(temp); +} + +/* ==== LocallabCBDL ==== */ +LocallabCBDL::LocallabCBDL(): + LocallabTool(this, M("TP_LOCALLAB_CBDL_TOOLNAME"), M("TP_LOCALLAB_CBDL"), true), + + // CBDL specific widgets + multiplier([]() -> std::array + { + std::array res = {}; + + for (unsigned int i = 0; i < res.size(); ++i) { + Glib::ustring ss = Glib::ustring::format(i); + + if (i == 0) { + ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMAFINEST")); + } else if (i == 5) { + ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMACOARSEST")); + } + + res[i] = Gtk::manage(new Adjuster(std::move(ss), 0.0, 4.0, 0.01, 1.0)); + } + + return res; + } + ()), + chromacbdl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMACBDL"), 0., 1.5, 0.01, 0.))), + threshold(Gtk::manage(new Adjuster(M("TP_DIRPYREQUALIZER_THRESHOLD"), 0, 1., 0.01, 0.2))), + blurcbdl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURCBDL"), 0., 100., 0.1, 0.))), + clarityml(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CLARITYML"), 0.1, 100., 0.1, 0.1))), + contresid(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CONTRESID"), -100, 100, 1, 0))), + softradiuscb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 1000.0, 0.5, 0.))), + sensicb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSICB"), 0, 100, 1, 60))), + expmaskcb(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWCB")))), + showmaskcbMethod(Gtk::manage(new MyComboBoxText())), + enacbMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + maskcbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + CCmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), -10.0, 1000.0, 0.1, 0.))), + lapmaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), + slomaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + mask2cbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmaskcbshape(static_cast(mask2cbCurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + + lumacontrastMinusButton(Gtk::manage(new Gtk::Button(M("TP_DIRPYREQUALIZER_LUMACONTRAST_MINUS")))), + lumaneutralButton(Gtk::manage(new Gtk::Button(M("TP_DIRPYREQUALIZER_LUMANEUTRAL")))), + lumacontrastPlusButton(Gtk::manage(new Gtk::Button(M("TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS")))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter CBDL specific widgets + for (const auto adj : multiplier) { + adj->setAdjusterListener(this); + } + + chromacbdl->setAdjusterListener(this); + + threshold->setAdjusterListener(this); + + blurcbdl->setAdjusterListener(this); + + clarityml->setAdjusterListener(this); + + contresid->setAdjusterListener(this); + + softradiuscb->setLogScale(10, 0); + softradiuscb->setAdjusterListener(this); + + sensicb->setAdjusterListener(this); + + showmaskcbMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskcbMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskcbMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskcbMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskcbMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskcbMethod->set_active(0); + showmaskcbMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskcbMethodConn = showmaskcbMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabCBDL::showmaskcbMethodChanged)); + + enacbMaskConn = enacbMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabCBDL::enacbMaskChanged)); + + maskcbCurveEditorG->setCurveListener(this); + + CCmaskcbshape->setIdentityValue(0.); + CCmaskcbshape->setResetCurve(FlatCurveType(defSpot.CCmaskcbcurve.at(0)), defSpot.CCmaskcbcurve); + CCmaskcbshape->setBottomBarColorProvider(this, 1); + + LLmaskcbshape->setIdentityValue(0.); + LLmaskcbshape->setResetCurve(FlatCurveType(defSpot.LLmaskcbcurve.at(0)), defSpot.LLmaskcbcurve); + LLmaskcbshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskcbshape->setIdentityValue(0.); + HHmaskcbshape->setResetCurve(FlatCurveType(defSpot.HHmaskcbcurve.at(0)), defSpot.HHmaskcbcurve); + HHmaskcbshape->setCurveColorProvider(this, 2); + HHmaskcbshape->setBottomBarColorProvider(this, 2); + + maskcbCurveEditorG->curveListComplete(); + + blendmaskcb->setAdjusterListener(this); + + radmaskcb->setLogScale(10, -10); + radmaskcb->setAdjusterListener(this); + + lapmaskcb->setAdjusterListener(this); + + chromaskcb->setAdjusterListener(this); + + gammaskcb->setAdjusterListener(this); + + slomaskcb->setAdjusterListener(this); + + mask2cbCurveEditorG->setCurveListener(this); + + Lmaskcbshape->setResetCurve(DiagonalCurveType(defSpot.Lmaskcbcurve.at(0)), defSpot.Lmaskcbcurve); + Lmaskcbshape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmaskcbshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2cbCurveEditorG->curveListComplete(); + + lumacontrastMinusPressedConn = lumacontrastMinusButton->signal_pressed().connect(sigc::mem_fun(*this, &LocallabCBDL::lumacontrastMinusPressed)); + + lumaneutralPressedConn = lumaneutralButton->signal_pressed().connect(sigc::mem_fun(*this, &LocallabCBDL::lumaneutralPressed)); + + lumacontrastPlusPressedConn = lumacontrastPlusButton->signal_pressed().connect(sigc::mem_fun(*this, &LocallabCBDL::lumacontrastPlusPressed)); + + // Add CBDL specific widgets to GUI + Gtk::HBox* buttonBox = Gtk::manage(new Gtk::HBox(true, 10)); + buttonBox->pack_start(*lumacontrastMinusButton); + buttonBox->pack_start(*lumaneutralButton); + buttonBox->pack_start(*lumacontrastPlusButton); + pack_start(*buttonBox); + + for (const auto adj : multiplier) { + pack_start(*adj); + } + + Gtk::HSeparator* const separator = Gtk::manage(new Gtk::HSeparator()); + pack_start(*separator, Gtk::PACK_SHRINK, 2); + pack_start(*chromacbdl); + pack_start(*threshold); + // pack_start(*blurcbdl); + Gtk::Frame* const residFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_RESID"))); + residFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const residBox = Gtk::manage(new ToolParamBlock()); + residBox->pack_start(*clarityml); + residBox->pack_start(*contresid); + residFrame->add(*residBox); + pack_start(*residFrame); + pack_start(*softradiuscb); + pack_start(*sensicb); + ToolParamBlock* const maskcbBox = Gtk::manage(new ToolParamBlock()); + maskcbBox->pack_start(*showmaskcbMethod, Gtk::PACK_SHRINK, 4); + maskcbBox->pack_start(*enacbMask, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*maskcbCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + maskcbBox->pack_start(*blendmaskcb, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*radmaskcb, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*lapmaskcb, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*chromaskcb, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*gammaskcb, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*slomaskcb, Gtk::PACK_SHRINK, 0); + maskcbBox->pack_start(*mask2cbCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + expmaskcb->add(*maskcbBox, false); + pack_start(*expmaskcb, false, false); +} + +LocallabCBDL::~LocallabCBDL() +{ + delete maskcbCurveEditorG; + delete mask2cbCurveEditorG; +} + +bool LocallabCBDL::isMaskViewActive() +{ + return (showmaskcbMethod->get_active_row_number() != 0); +} + + +void LocallabCBDL::resetMaskView() +{ + showmaskcbMethodConn.block(true); + showmaskcbMethod->set_active(0); + showmaskcbMethodConn.block(false); +} + +void LocallabCBDL::getMaskView(int &colorMask, int &colorMaskinv, int &expMask, int &expMaskinv, int &shMask, int &shMaskinv, int &vibMask, int &softMask, int &blMask, int &tmMask, int &retiMask, int &sharMask, int &lcMask, int &cbMask) +{ + cbMask = showmaskcbMethod->get_active_row_number(); +} + +void LocallabCBDL::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_EXPCBDL_TOOLTIP")); + for (const auto adj : multiplier) { + adj->set_tooltip_text(M("TP_LOCALLAB_CBDL_ADJ_TOOLTIP")); + } + threshold->set_tooltip_text(M("TP_LOCALLAB_CBDL_THRES_TOOLTIP")); + chromacbdl->set_tooltip_text(M("TP_LOCALLAB_CHROMACB_TOOLTIP")); + clarityml->set_tooltip_text(M("TP_LOCALLAB_CBDLCLARI_TOOLTIP")); + sensicb->set_tooltip_text(M("TP_LOCALLAB_SENSIH_TOOLTIP")); + expmaskcb->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskcbshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskcbshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskcbshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + radmaskcb->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskcb->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + Lmaskcbshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + blendmaskcb->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2cbCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + for (const auto adj : multiplier) { + adj->set_tooltip_text(M("")); + } + threshold->set_tooltip_text(M("")); + chromacbdl->set_tooltip_text(""); + clarityml->set_tooltip_text(M("")); + sensicb->set_tooltip_text(""); + expmaskcb->set_tooltip_text(""); + CCmaskcbshape->setTooltip(""); + LLmaskcbshape->setTooltip(""); + HHmaskcbshape->setTooltip(""); + radmaskcb->set_tooltip_text(""); + lapmaskcb->set_tooltip_text(""); + Lmaskcbshape->setTooltip(""); + blendmaskcb->set_tooltip_text(M("")); + mask2cbCurveEditorG->set_tooltip_text(M("")); + } +} + +void LocallabCBDL::setDefaultExpanderVisibility() +{ + expmaskcb->set_expanded(false); +} + +void LocallabCBDL::disableListener() +{ + LocallabTool::disableListener(); + + showmaskcbMethodConn.block(true); + enacbMaskConn.block(true); + + lumacontrastMinusPressedConn.block(true); + lumaneutralPressedConn.block(true); + lumacontrastPlusPressedConn.block(true); +} + +void LocallabCBDL::enableListener() +{ + LocallabTool::enableListener(); + + showmaskcbMethodConn.block(false); + enacbMaskConn.block(false); + + lumacontrastMinusPressedConn.block(false); + lumaneutralPressedConn.block(false); + lumacontrastPlusPressedConn.block(false); +} + +void LocallabCBDL::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visicbdl); + exp->setEnabled(spot.expcbdl); + complexity->set_active(spot.complexcbdl); + + for (int i = 0; i < 6; i++) { + multiplier[i]->setValue(spot.mult[i]); + } + + chromacbdl->setValue(spot.chromacbdl); + threshold->setValue(spot.threshold); + blurcbdl->setValue(spot.blurcbdl); + clarityml->setValue(spot.clarityml); + contresid->setValue((double)spot.contresid); + softradiuscb->setValue(spot.softradiuscb); + sensicb->setValue((double)spot.sensicb); + enacbMask->set_active(spot.enacbMask); + CCmaskcbshape->setCurve(spot.CCmaskcbcurve); + LLmaskcbshape->setCurve(spot.LLmaskcbcurve); + HHmaskcbshape->setCurve(spot.HHmaskcbcurve); + blendmaskcb->setValue((double)spot.blendmaskcb); + radmaskcb->setValue(spot.radmaskcb); + lapmaskcb->setValue(spot.lapmaskcb); + chromaskcb->setValue(spot.chromaskcb); + gammaskcb->setValue(spot.gammaskcb); + slomaskcb->setValue(spot.slomaskcb); + Lmaskcbshape->setCurve(spot.Lmaskcbcurve); + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabCBDL::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.expcbdl = exp->getEnabled(); + spot.visicbdl = exp->get_visible(); + spot.complexcbdl = complexity->get_active_row_number(); + + for (int i = 0; i < 6; i++) { + spot.mult[i] = multiplier[i]->getValue(); + } + + spot.chromacbdl = chromacbdl->getValue(); + spot.threshold = threshold->getValue(); + spot.blurcbdl = blurcbdl->getValue(); + spot.clarityml = clarityml->getValue(); + spot.contresid = contresid->getIntValue(); + spot.softradiuscb = softradiuscb->getValue(); + spot.sensicb = sensicb->getIntValue(); + spot.enacbMask = enacbMask->get_active(); + spot.LLmaskcbcurve = LLmaskcbshape->getCurve(); + spot.CCmaskcbcurve = CCmaskcbshape->getCurve(); + spot.HHmaskcbcurve = HHmaskcbshape->getCurve(); + spot.blendmaskcb = blendmaskcb->getIntValue(); + spot.radmaskcb = radmaskcb->getValue(); + spot.lapmaskcb = lapmaskcb->getValue(); + spot.chromaskcb = chromaskcb->getValue(); + spot.gammaskcb = gammaskcb->getValue(); + spot.slomaskcb = slomaskcb->getValue(); + spot.Lmaskcbcurve = Lmaskcbshape->getCurve(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabCBDL::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default values for adjuster widgets + for (int i = 0; i < 6; i++) { + multiplier[i]->setDefault(defSpot.mult[i]); + } + + chromacbdl->setDefault(defSpot.chromacbdl); + threshold->setDefault(defSpot.threshold); + blurcbdl->setDefault(defSpot.blurcbdl); + clarityml->setDefault(defSpot.clarityml); + contresid->setDefault((double)defSpot.contresid); + softradiuscb->setDefault(defSpot.softradiuscb); + sensicb->setDefault((double)defSpot.sensicb); + blendmaskcb->setDefault((double)defSpot.blendmaskcb); + radmaskcb->setDefault(defSpot.radmaskcb); + lapmaskcb->setDefault(defSpot.lapmaskcb); + chromaskcb->setDefault(defSpot.chromaskcb); + gammaskcb->setDefault(defSpot.gammaskcb); + slomaskcb->setDefault(defSpot.slomaskcb); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabCBDL::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == multiplier[0] || a == multiplier[1] || a == multiplier[2] || a == multiplier[3] || a == multiplier[4] || a == multiplier[5]) { + if (listener) { + listener->panelChanged(EvlocallabEqualizer, + Glib::ustring::compose("%1, %2, %3, %4, %5, %6", + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[0]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[1]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[2]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[3]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[4]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[5]->getValue())) + + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromacbdl) { + if (listener) { + listener->panelChanged(Evlocallabchromacbdl, + chromacbdl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == threshold) { + if (listener) { + listener->panelChanged(EvlocallabThresho, + threshold->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blurcbdl) { + if (listener) { + listener->panelChanged(EvLocallabblurcbdl, + blurcbdl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == clarityml) { + if (listener) { + listener->panelChanged(EvLocallabclarityml, + clarityml->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == contresid) { + if (listener) { + listener->panelChanged(EvLocallabcontresid, + contresid->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == softradiuscb) { + if (listener) { + listener->panelChanged(Evlocallabsoftradiuscb, + softradiuscb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensicb) { + if (listener) { + listener->panelChanged(Evlocallabsensicb, + sensicb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskcb) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskcb, + blendmaskcb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskcb) { + if (listener) { + listener->panelChanged(Evlocallabradmaskcb, + radmaskcb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmaskcb) { + if (listener) { + listener->panelChanged(Evlocallablapmaskcb, + lapmaskcb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskcb) { + if (listener) { + listener->panelChanged(Evlocallabchromaskcb, + chromaskcb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammaskcb) { + if (listener) { + listener->panelChanged(Evlocallabgammaskcb, + gammaskcb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slomaskcb) { + if (listener) { + listener->panelChanged(Evlocallabslomaskcb, + slomaskcb->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabCBDL::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == CCmaskcbshape) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskcbshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskcbshape) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskcbshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmaskcbshape) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskcbshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmaskcbshape) { + if (listener) { + listener->panelChanged(EvlocallabLmaskcbshape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabCBDL::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenacbdl, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenacbdl, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabCBDL::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + lapmaskcb->setValue(defSpot.lapmaskcb); + + // Enable all listeners + enableListener(); +} + +void LocallabCBDL::updateGUIToMode(const modeType new_type) +{ + if (new_type == Normal) { + // Advanced widgets are hidden in Normal mode + lapmaskcb->hide(); + } else { + // Advanced widgets are shown in Expert mode + lapmaskcb->show(); + } +} + +void LocallabCBDL::updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) +{ + idle_register.add( + [this, normHuer, normLumar, normChromar]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update mask background + CCmaskcbshape->updateLocallabBackground(normChromar); + LLmaskcbshape->updateLocallabBackground(normLumar); + HHmaskcbshape->updateLocallabBackground(normHuer); + + return false; + } + ); +} + +void LocallabCBDL::showmaskcbMethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabCBDL::enacbMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enacbMask->get_active()) { + listener->panelChanged(EvLocallabEnacbMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnacbMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabCBDL::lumacontrastMinusPressed() +{ + for (int i = 0; i < 6; i++) { + float inc = - (5 - i); + multiplier[i]->setValue(multiplier[i]->getValue() + 0.01f * inc); + } + + // Raise event (only for first multiplier because associated event concerns all multipliers) + adjusterChanged(multiplier[0], multiplier[0]->getValue()); // Value isn't used +} + +void LocallabCBDL::lumaneutralPressed() +{ + for (int i = 0; i < 6; i++) { + multiplier[i]->setValue(1.0); + } + + // Raise event (only for first multiplier because associated event concerns all multipliers) + adjusterChanged(multiplier[0], multiplier[0]->getValue()); // Value isn't used +} + +void LocallabCBDL::lumacontrastPlusPressed() +{ + for (int i = 0; i < 6; i++) { + float inc = (5 - i); + multiplier[i]->setValue(multiplier[i]->getValue() + 0.01f * inc); + } + + // Raise event (only for first multiplier because associated event concerns all multipliers) + adjusterChanged(multiplier[0], multiplier[0]->getValue()); // Value isn't used +} + +/* ==== LocallabLog ==== */ +LocallabLog::LocallabLog(): + LocallabTool(this, M("TP_LOCALLAB_LOG_TOOLNAME"), M("TP_LOCALLAB_LOG"), false, false), + + // Log encoding specific widgets + autocompute(Gtk::manage(new Gtk::ToggleButton(M("TP_LOCALLAB_LOGAUTO")))), + logPFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LOGPFRA")))), + blackEv(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLACK_EV"), -16.0, 0.0, 0.1, -5.0))), + whiteEv(Gtk::manage(new Adjuster(M("TP_LOCALLAB_WHITE_EV"), 0.0, 32.0, 0.1, 10.0))), + fullimage(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FULLIMAGE")))), + Autogray(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AUTOGRAY")))), + sourceGray(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOURCE_GRAY"), 1.0, 100.0, 0.1, 10.0))), + targetGray(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TARGET_GRAY"), 5.0, 80.0, 0.1, 18.0))), + detail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAIL"), 0., 1., 0.01, 0.6))), + baselog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BASELOG"), 1.3, 8., 0.05, 2., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + sensilog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSILOG"), 0, 100, 1, 60))), + strlog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -2.0, 2.0, 0.05, 0.))), + anglog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180, 180, 0.1, 0.))) +{ + // Parameter Log encoding specific widgets + autoconn = autocompute->signal_toggled().connect(sigc::mem_fun(*this, &LocallabLog::autocomputeToggled)); + + blackEv->setLogScale(2, -8); + blackEv->setAdjusterListener(this); + + whiteEv->setLogScale(16, 0); + whiteEv->setAdjusterListener(this); + + fullimageConn = fullimage->signal_toggled().connect(sigc::mem_fun(*this, &LocallabLog::fullimageChanged)); + + AutograyConn = Autogray->signal_toggled().connect(sigc::mem_fun(*this, &LocallabLog::AutograyChanged)); + + sourceGray->setAdjusterListener(this); + + targetGray->setAdjusterListener(this); + + detail->setAdjusterListener(this); + + baselog->setAdjusterListener(this); + + sensilog->setAdjusterListener(this); + + strlog->setAdjusterListener(this); + + anglog->setAdjusterListener(this); + + // Add Log encoding specific widgets to GUI + logPFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const logPBox = Gtk::manage(new ToolParamBlock()); + logPBox->pack_start(*autocompute); + logPBox->pack_start(*blackEv); + logPBox->pack_start(*whiteEv); + logPBox->pack_start(*fullimage); + logPFrame->add(*logPBox); + pack_start(*logPFrame); + Gtk::Frame* const logFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LOGFRA"))); + logFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const logFBox = Gtk::manage(new ToolParamBlock()); + logFBox->pack_start(*Autogray); + logFBox->pack_start(*sourceGray); + logFrame->add(*logFBox); + pack_start(*logFrame); + pack_start(*targetGray); + pack_start(*detail); + pack_start(*baselog); + pack_start(*sensilog); + Gtk::Frame* const gradlogFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRADLOGFRA"))); + gradlogFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const gradlogBox = Gtk::manage(new ToolParamBlock()); + gradlogBox->pack_start(*strlog); + gradlogBox->pack_start(*anglog); + gradlogFrame->add(*gradlogBox); + pack_start(*gradlogFrame); +} + +void LocallabLog::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_LOGENCOD_TOOLTIP")); + logPFrame->set_tooltip_text(M("TP_LOCALLAB_LOGFRAME_TOOLTIP")); + autocompute->set_tooltip_text(M("TP_LOCALLAB_LOGAUTO_TOOLTIP")); + blackEv->set_tooltip_text(M("TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP")); + whiteEv->set_tooltip_text(M("TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP")); + // Autogray->set_tooltip_text(M("TP_LOCALLAB_LOGAUTOGREY_TOOLTIP")); + Autogray->set_tooltip_text(M("")); + sourceGray->set_tooltip_text(M("TP_LOCALLAB_LOGSRCGREY_TOOLTIP")); + targetGray->set_tooltip_text(M("TP_LOCALLAB_LOGTARGGREY_TOOLTIP")); + // detail->set_tooltip_text(M("TP_LOCALLAB_LOGDET_TOOLTIP")); + detail->set_tooltip_text(M("")); + baselog->set_tooltip_text(M("TP_LOCALLAB_LOGBASE_TOOLTIP")); + strlog->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + anglog->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + } else { + exp->set_tooltip_text(M("")); + logPFrame->set_tooltip_text(""); + autocompute->set_tooltip_text(M("")); + blackEv->set_tooltip_text(M("")); + whiteEv->set_tooltip_text(M("")); + Autogray->set_tooltip_text(M("")); + sourceGray->set_tooltip_text(M("")); + targetGray->set_tooltip_text(M("")); + detail->set_tooltip_text(M("")); + baselog->set_tooltip_text(M("")); + strlog->set_tooltip_text(M("")); + anglog->set_tooltip_text(M("")); + } +} + +void LocallabLog::disableListener() +{ + LocallabTool::disableListener(); + + autoconn.block(true); + fullimageConn.block(true); + AutograyConn.block(true); +} + +void LocallabLog::enableListener() +{ + LocallabTool::enableListener(); + + autoconn.block(false); + fullimageConn.block(false); + AutograyConn.block(false); +} + +void LocallabLog::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + // Disable all listeners + disableListener(); + + // Update GUI to selected spot value + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + const LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spotName = spot.name; // Update spot name according to selected spot + + exp->set_visible(spot.visilog); + exp->setEnabled(spot.explog); + + autocompute->set_active(spot.autocompute); + blackEv->setValue(spot.blackEv); + whiteEv->setValue(spot.whiteEv); + fullimage->set_active(spot.fullimage); + Autogray->set_active(spot.Autogray); + sourceGray->setValue(spot.sourceGray); + targetGray->setValue(spot.targetGray); + detail->setValue(spot.detail); + baselog->setValue(spot.baselog); + sensilog->setValue((double)spot.sensilog); + strlog->setValue(spot.strlog); + anglog->setValue(spot.anglog); + } + + // Enable all listeners + enableListener(); + + // Update Log Encoding GUI according to autocompute button state + updateLogGUI(); + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabLog::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + const int index = pp->locallab.selspot; + + if (index < (int)pp->locallab.spots.size()) { + LocallabParams::LocallabSpot& spot = pp->locallab.spots.at(index); + + spot.explog = exp->getEnabled(); + spot.visilog = exp->get_visible(); + + spot.autocompute = autocompute->get_active(); + spot.blackEv = blackEv->getValue(); + spot.whiteEv = whiteEv->getValue(); + spot.fullimage = fullimage->get_active(); + spot.Autogray = Autogray->get_active(); + spot.sourceGray = sourceGray->getValue(); + spot.targetGray = targetGray->getValue(); + spot.detail = detail->getValue(); + spot.baselog = baselog->getValue(); + spot.sensilog = sensilog->getIntValue(); + spot.strlog = strlog->getValue(); + spot.anglog = anglog->getValue(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabLog::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + const int index = defParams->locallab.selspot; + + if (index < (int)defParams->locallab.spots.size()) { + const LocallabParams::LocallabSpot& defSpot = defParams->locallab.spots.at(index); + + // Set default value for adjuster widgets + blackEv->setDefault(defSpot.blackEv); + whiteEv->setDefault(defSpot.whiteEv); + sourceGray->setDefault(defSpot.sourceGray); + targetGray->setDefault(defSpot.targetGray); + detail->setDefault(defSpot.detail); + baselog->setDefault(defSpot.baselog); + sensilog->setDefault((double)defSpot.sensilog); + strlog->setDefault(defSpot.strlog); + anglog->setDefault(defSpot.anglog); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabLog::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == blackEv) { + if (listener) { + listener->panelChanged(EvlocallabblackEv, + blackEv->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == whiteEv) { + if (listener) { + listener->panelChanged(EvlocallabwhiteEv, + whiteEv->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sourceGray) { + if (listener) { + listener->panelChanged(EvlocallabsourceGray, + sourceGray->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == targetGray) { + if (listener) { + listener->panelChanged(EvlocallabtargetGray, + targetGray->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == detail) { + if (listener) { + listener->panelChanged(Evlocallabdetail, + detail->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == baselog) { + if (listener) { + listener->panelChanged(Evlocallabbaselog, + baselog->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == sensilog) { + if (listener) { + listener->panelChanged(Evlocallabsensilog, + sensilog->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strlog) { + if (listener) { + listener->panelChanged(Evlocallabstrlog, + strlog->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == anglog) { + if (listener) { + listener->panelChanged(Evlocallabanglog, + anglog->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabLog::updateAutocompute(const float blackev, const float whiteev, const float sourceg, const float targetg) +{ + idle_register.add( + [this, blackev, whiteev, sourceg, targetg]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + // Update adjuster values according to autocomputed ones + disableListener(); + + blackEv->setValue(blackev); + whiteEv->setValue(whiteev); + sourceGray->setValue(sourceg); + targetGray->setValue(targetg); + + enableListener(); + + return false; + } + ); +} + +void LocallabLog::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocenalog, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocenalog, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabLog::autocomputeToggled() +{ + // Update Log Encoding GUI according to autocompute button state + updateLogGUI(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (autocompute->get_active()) { + listener->panelChanged(EvLocallabAuto, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabAuto, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabLog::fullimageChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (fullimage->get_active()) { + listener->panelChanged(Evlocallabfullimage, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabfullimage, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabLog::AutograyChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (Autogray->get_active()) { + listener->panelChanged(EvlocallabAutogray, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvlocallabAutogray, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabLog::updateLogGUI() +{ + if (autocompute->get_active()) { + blackEv->set_sensitive(false); + whiteEv->set_sensitive(false); + sourceGray->set_sensitive(false); + // targetGray->set_sensitive(true); + } else { + blackEv->set_sensitive(true); + whiteEv->set_sensitive(true); + sourceGray->set_sensitive(true); + // targetGray->set_sensitive(true); + } +} diff --git a/rtgui/main.cc b/rtgui/main.cc index f669bcf4a..7bb4afdc9 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -121,6 +121,7 @@ static void myGdkLockLeave() * -1 if there is an error in parameters * -2 if an error occurred during processing * -3 if at least one required procparam file was not found */ +//int processLineParams ( int argc, char **argv ); int processLineParams ( int argc, char **argv ) { int ret = 1; @@ -255,6 +256,7 @@ RTWindow *create_rt_window() //gdk_threads_enter (); RTWindow *rtWindow = new RTWindow(); + rtWindow->setWindowSize(); // Need to be called after RTWindow creation to work with all OS Windows Manager return rtWindow; } @@ -439,7 +441,7 @@ int main (int argc, char **argv) if (argc > 1) { if (!remote && !Glib::file_test (argv1, Glib::FILE_TEST_EXISTS ) && !Glib::file_test (argv1, Glib::FILE_TEST_IS_DIR)) { - bool stdoutRedirecttoConsole = (GetFileType (GetStdHandle (STD_OUTPUT_HANDLE)) == 0x0000); + const bool stdoutRedirecttoConsole = (GetFileType (GetStdHandle (STD_OUTPUT_HANDLE)) == 0x0000); // open console, if stdout is invalid if (stdoutRedirecttoConsole) { // check if parameter -w was passed. @@ -471,10 +473,9 @@ int main (int argc, char **argv) cursorInfo.bVisible = false; SetConsoleCursorInfo ( GetStdHandle ( STD_OUTPUT_HANDLE ), &cursorInfo ); - if (stdoutRedirecttoConsole) { // if stdout is Redirect to console, we also redirect stderr to console - freopen ( "CON", "w", stdout ) ; - freopen ( "CON", "w", stderr ) ; - } + // we also redirect stderr to console + freopen ( "CON", "w", stdout ) ; + freopen ( "CON", "w", stderr ) ; freopen ( "CON", "r", stdin ) ; diff --git a/rtgui/md5helper.h b/rtgui/md5helper.h new file mode 100644 index 000000000..17ee70f3a --- /dev/null +++ b/rtgui/md5helper.h @@ -0,0 +1,69 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-201 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 +#include + +#include +#include + +#ifdef WIN32 +#include +#endif + +namespace { +std::string getMD5 (const Glib::ustring& fname) +{ + + auto file = Gio::File::create_for_path (fname); + + if (file && file->query_exists ()) { + +#ifdef WIN32 + + std::unique_ptr wfname (reinterpret_cast (g_utf8_to_utf16 (fname.c_str (), -1, NULL, NULL, NULL)), g_free); + + WIN32_FILE_ATTRIBUTE_DATA fileAttr; + + if (GetFileAttributesExW (wfname.get (), GetFileExInfoStandard, &fileAttr)) { + // We use name, size and creation time to identify a file. + const auto identifier = Glib::ustring::compose ("%1-%2-%3-%4", fileAttr.nFileSizeLow, fileAttr.ftCreationTime.dwHighDateTime, fileAttr.ftCreationTime.dwLowDateTime, fname); + return Glib::Checksum::compute_checksum (Glib::Checksum::CHECKSUM_MD5, identifier); + } + +#else + + try { + + if (auto info = file->query_info ()) { + // We only use name and size to identify a file. + const auto identifier = Glib::ustring::compose ("%1%2", fname, info->get_size ()); + return Glib::Checksum::compute_checksum (Glib::Checksum::CHECKSUM_MD5, identifier); + } + + } catch (Gio::Error&) {} + +#endif + + } + + return {}; +} + +} diff --git a/rtgui/myflatcurve.cc b/rtgui/myflatcurve.cc index da993987c..11d89ebd8 100644 --- a/rtgui/myflatcurve.cc +++ b/rtgui/myflatcurve.cc @@ -46,7 +46,8 @@ MyFlatCurve::MyFlatCurve () : deletedPointX(0.0), leftTanHandle({0.0, 0.0}), rightTanHandle({0.0, 0.0}), - draggingElement(false) + draggingElement(false), + locallabRef(0.0) { lit_point = -1; @@ -169,6 +170,20 @@ void MyFlatCurve::draw () cr->set_line_width (1.0 * s); + // Draw Locallab reference value in the background + if (locallabRef > 0.0) { + cr->set_line_width(1.0); + cr->move_to(double(graphX + 1), double(graphY - 1)); + c = style->get_color(state); + cr->set_source_rgba(c.get_red(), c.get_green(), c.get_blue(), 0.2); + cr->line_to(double(graphX + 1), double(graphY - 1) - double(graphH - 2)); + cr->line_to(double(graphX) + 1.5 + locallabRef*double(graphW -2), double(graphY - 1) - double(graphH - 2)); + cr->line_to(double(graphX) + 1.5 + locallabRef*double(graphW -2), double(graphY - 1)); + cr->close_path(); + cr->fill(); + cr->stroke(); + } + // draw the left colored bar if (leftBar) { // first the background @@ -1870,6 +1885,35 @@ void MyFlatCurve::stopNumericalAdjustment() } } +void MyFlatCurve::updateLocallabBackground(double ref) +{ + locallabRef = ref; + + mcih->pending++; + + idle_register.add( + [this]() -> bool + { + if (mcih->destroyed) { + if (mcih->pending == 1) { + delete mcih; + } else { + --mcih->pending; + } + + return false; + } + + mcih->clearPixmap(); + mcih->myCurve->queue_draw(); + + --mcih->pending; + + return false; + } + ); +} + void MyFlatCurve::setType (FlatCurveType t) { diff --git a/rtgui/myflatcurve.h b/rtgui/myflatcurve.h index 5da1d09ad..f51586567 100644 --- a/rtgui/myflatcurve.h +++ b/rtgui/myflatcurve.h @@ -68,6 +68,8 @@ public: class MyFlatCurve final : public MyCurve { +private: + IdleRegister idle_register; protected: FlatCurveDescr curve; @@ -95,6 +97,7 @@ protected: enum EditedHandle editedHandle; bool draggingElement; enum MouseOverAreas area; + double locallabRef; // Locallab reference value to display in the background void draw (); void movePoint(bool moveX, bool moveY, bool pipetteDrag = false); @@ -129,4 +132,6 @@ public: void setPos(double pos, int chanIdx) override; void stopNumericalAdjustment() override; + + void updateLocallabBackground(double ref); }; diff --git a/rtgui/options.cc b/rtgui/options.cc index 7ae6c24aa..cc49f1fcd 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -177,6 +177,10 @@ void Options::updatePaths() lastWaveletCurvesDir = preferredPath; } + if (lastlocalCurvesDir.empty() || !Glib::file_test(lastlocalCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastlocalCurvesDir, Glib::FILE_TEST_IS_DIR)) { + lastlocalCurvesDir = preferredPath; + } + if (lastPFCurvesDir.empty() || !Glib::file_test(lastPFCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastPFCurvesDir, Glib::FILE_TEST_IS_DIR)) { lastPFCurvesDir = preferredPath; } @@ -447,7 +451,9 @@ void Options::setDefaults() histogramHeight = 200; histogramDrawMode = 0; curvebboxpos = 1; + complexity = 1; prevdemo = PD_Sidecar; + rgbDenoiseThreadLimit = 0; #if defined( _OPENMP ) && defined( __x86_64__ ) clutCacheSize = omp_get_num_procs(); @@ -473,6 +479,7 @@ void Options::setDefaults() menuGroupFileOperations = true; menuGroupProfileOperations = true; menuGroupExtProg = true; + showtooltip = true; ICCPC_primariesPreset = "sRGB", ICCPC_redPrimaryX = 0.6400; @@ -590,6 +597,15 @@ void Options::setDefaults() rtSettings.amchroma = 40;//between 20 and 140 low values increase effect..and also artifacts, high values reduces rtSettings.level0_cbdl = 0; rtSettings.level123_cbdl = 30; +//locallab + rtSettings.cropsleep = 50;//generate a pause of 50 µs for dcrop (100%)to avoid crash when moving window, between 0 to ?? + rtSettings.reduchigh = 0.85;//transition for luminance in scope + rtSettings.reduclow = 0.85;//transition for luminance out scope + rtSettings.detectshape = true;//experimental new detection shape + rtSettings.previewselection = 5;//between 1 to 40 + rtSettings.cbdlsensi = 1.0;//between 0.001 to 1 + rtSettings.fftwsigma = true; //choice between sigma^2 or empirical formula + rtSettings.itcwb_thres = 34;//between 10 to 55 rtSettings.itcwb_sort = false; rtSettings.itcwb_greenrange = 0;//between 0 to 2 @@ -599,6 +615,7 @@ void Options::setDefaults() rtSettings.itcwb_delta = 1;//between 0 and 5 rtSettings.itcwb_stdobserver10 = true; rtSettings.itcwb_precis = 5;//3 or 5 or 9 +// end locallab rtSettings.protectred = 60; rtSettings.protectredh = 0.3; @@ -638,6 +655,7 @@ void Options::setDefaults() lastRetinexDir = ""; lastDenoiseCurvesDir = ""; lastWaveletCurvesDir = ""; + lastlocalCurvesDir = ""; lastPFCurvesDir = ""; lastHsvCurvesDir = ""; lastToneCurvesDir = ""; @@ -757,6 +775,26 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("General", "Verbose")) { rtSettings.verbose = keyFile.get_boolean("General", "Verbose"); } + + if (keyFile.has_key("General", "Detectshape")) { + rtSettings.detectshape = keyFile.get_boolean("General", "Detectshape"); + } + + if (keyFile.has_key("General", "Fftwsigma")) { + rtSettings.fftwsigma = keyFile.get_boolean("General", "Fftwsigma"); + } + + if (keyFile.has_key("General", "Cropsleep")) { + rtSettings.cropsleep = keyFile.get_integer("General", "Cropsleep"); + } + + if (keyFile.has_key("General", "Reduchigh")) { + rtSettings.reduchigh = keyFile.get_double("General", "Reduchigh"); + } + + if (keyFile.has_key("General", "Reduclow")) { + rtSettings.reduclow = keyFile.get_double("General", "Reduclow"); + } } if (keyFile.has_group("External Editor")) { @@ -798,8 +836,8 @@ void Options::readFromFile(Glib::ustring fname) saveFormat.tiffBits = keyFile.get_integer("Output", "TiffBps"); } - if (keyFile.has_key ("Output", "TiffFloat")) { - saveFormat.tiffFloat = keyFile.get_boolean ("Output", "TiffFloat"); + if (keyFile.has_key("Output", "TiffFloat")) { + saveFormat.tiffFloat = keyFile.get_boolean("Output", "TiffFloat"); } if (keyFile.has_key("Output", "TiffUncompressed")) { @@ -831,8 +869,8 @@ void Options::readFromFile(Glib::ustring fname) saveFormatBatch.tiffBits = keyFile.get_integer("Output", "TiffBpsBatch"); } - if (keyFile.has_key ("Output", "TiffFloatBatch")) { - saveFormatBatch.tiffFloat = keyFile.get_boolean ("Output", "TiffFloatBatch"); + if (keyFile.has_key("Output", "TiffFloatBatch")) { + saveFormatBatch.tiffFloat = keyFile.get_boolean("Output", "TiffFloatBatch"); } if (keyFile.has_key("Output", "TiffUncompressedBatch")) { @@ -1380,12 +1418,12 @@ void Options::readFromFile(Glib::ustring fname) histogramBar = keyFile.get_boolean("GUI", "HistogramBar"); } - if (keyFile.has_key ("GUI", "HistogramHeight")) { - histogramHeight = keyFile.get_integer ("GUI", "HistogramHeight"); + if (keyFile.has_key("GUI", "HistogramHeight")) { + histogramHeight = keyFile.get_integer("GUI", "HistogramHeight"); } - if (keyFile.has_key ("GUI", "HistogramDrawMode")) { - histogramDrawMode = keyFile.get_integer ("GUI", "HistogramDrawMode"); + if (keyFile.has_key("GUI", "HistogramDrawMode")) { + histogramDrawMode = keyFile.get_integer("GUI", "HistogramDrawMode"); } if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { @@ -1396,10 +1434,15 @@ void Options::readFromFile(Glib::ustring fname) navHSVUnit = (NavigatorUnit)keyFile.get_integer("GUI", "NavigatorHSVUnit"); } + if (keyFile.has_key("GUI", "ShowFilmStripToolBar")) { showFilmStripToolBar = keyFile.get_boolean("GUI", "ShowFilmStripToolBar"); } + if (keyFile.has_key("GUI", "Showtooltip")) {//show tooltip in locallab + showtooltip = keyFile.get_boolean("GUI", "Showtooltip"); + } + if (keyFile.has_key("GUI", "FileBrowserToolbarSingleRow")) { FileBrowserToolbarSingleRow = keyFile.get_boolean("GUI", "FileBrowserToolbarSingleRow"); } @@ -1415,6 +1458,11 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("GUI", "CurveBBoxPosition")) { curvebboxpos = keyFile.get_integer("GUI", "CurveBBoxPosition"); } + + if (keyFile.has_key("GUI", "Complexity")) { + complexity = keyFile.get_integer("GUI", "Complexity"); + } + } if (keyFile.has_group("Crop Settings")) { @@ -1644,51 +1692,75 @@ void Options::readFromFile(Glib::ustring fname) //if( keyFile.has_key ("Color Management", "Ciebadpixgauss")) rtSettings.ciebadpixgauss = keyFile.get_boolean("Color Management", "Ciebadpixgauss"); + if (keyFile.has_key("Color Management", "Previewselection")) {//Intensity of preview selection deltaE + rtSettings.previewselection = keyFile.get_integer("Color Management", "Previewselection"); + } + + + if (keyFile.has_key("Color Management", "Cbdlsensi")) {//sensibility to crash for cbdl + rtSettings.cbdlsensi = keyFile.get_double("Color Management", "Cbdlsensi"); + } + + } if (keyFile.has_group("ICC Profile Creator")) { if (keyFile.has_key("ICC Profile Creator", "PimariesPreset")) { ICCPC_primariesPreset = keyFile.get_string("ICC Profile Creator", "PimariesPreset"); } + if (keyFile.has_key("ICC Profile Creator", "RedPrimaryX")) { ICCPC_redPrimaryX = keyFile.get_double("ICC Profile Creator", "RedPrimaryX"); } + if (keyFile.has_key("ICC Profile Creator", "RedPrimaryY")) { ICCPC_redPrimaryY = keyFile.get_double("ICC Profile Creator", "RedPrimaryY"); } + if (keyFile.has_key("ICC Profile Creator", "GreenPrimaryX")) { ICCPC_greenPrimaryX = keyFile.get_double("ICC Profile Creator", "GreenPrimaryX"); } + if (keyFile.has_key("ICC Profile Creator", "GreenPrimaryY")) { ICCPC_greenPrimaryY = keyFile.get_double("ICC Profile Creator", "GreenPrimaryY"); } + if (keyFile.has_key("ICC Profile Creator", "BluePrimaryX")) { ICCPC_bluePrimaryX = keyFile.get_double("ICC Profile Creator", "BluePrimaryX"); } + if (keyFile.has_key("ICC Profile Creator", "BluePrimaryY")) { ICCPC_bluePrimaryY = keyFile.get_double("ICC Profile Creator", "BluePrimaryY"); } + if (keyFile.has_key("ICC Profile Creator", "GammaPreset")) { ICCPC_gammaPreset = keyFile.get_string("ICC Profile Creator", "GammaPreset"); } + if (keyFile.has_key("ICC Profile Creator", "Gamma")) { ICCPC_gamma = keyFile.get_double("ICC Profile Creator", "Gamma"); } + if (keyFile.has_key("ICC Profile Creator", "Slope")) { ICCPC_slope = keyFile.get_double("ICC Profile Creator", "Slope"); } + if (keyFile.has_key("ICC Profile Creator", "ProfileVersion")) { ICCPC_profileVersion = keyFile.get_string("ICC Profile Creator", "ProfileVersion"); } + if (keyFile.has_key("ICC Profile Creator", "Illuminant")) { ICCPC_illuminant = keyFile.get_string("ICC Profile Creator", "Illuminant"); } + if (keyFile.has_key("ICC Profile Creator", "Description")) { ICCPC_description = keyFile.get_string("ICC Profile Creator", "Description"); } + if (keyFile.has_key("ICC Profile Creator", "Copyright")) { ICCPC_copyright = keyFile.get_string("ICC Profile Creator", "Copyright"); } + if (keyFile.has_key("ICC Profile Creator", "AppendParamsToDesc")) { ICCPC_appendParamsToDesc = keyFile.get_boolean("ICC Profile Creator", "AppendParamsToDesc"); } @@ -1881,6 +1953,8 @@ void Options::readFromFile(Glib::ustring fname) safeDirGet(keyFile, "Dialogs", "LastRetinexDir", lastRetinexDir); safeDirGet(keyFile, "Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); safeDirGet(keyFile, "Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastlocalCurvesDir", lastlocalCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastPFCurvesDir", lastPFCurvesDir); safeDirGet(keyFile, "Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); safeDirGet(keyFile, "Dialogs", "LastBWCurvesDir", lastBWCurvesDir); @@ -1978,6 +2052,12 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("General", "DarkFramesPath", rtSettings.darkFramesPath); keyFile.set_string("General", "FlatFieldsPath", rtSettings.flatFieldsPath); keyFile.set_boolean("General", "Verbose", rtSettings.verbose); + keyFile.set_integer("General", "Cropsleep", rtSettings.cropsleep); + keyFile.set_double("General", "Reduchigh", rtSettings.reduchigh); + keyFile.set_double("General", "Reduclow", rtSettings.reduclow); + keyFile.set_boolean("General", "Detectshape", rtSettings.detectshape); + keyFile.set_boolean("General", "Fftwsigma", rtSettings.fftwsigma); + keyFile.set_integer("External Editor", "EditorKind", editorToSendTo); keyFile.set_string("External Editor", "GimpDir", gimpDir); keyFile.set_string("External Editor", "PhotoshopDir", psDir); @@ -2048,6 +2128,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Performance", "ChunkSizeCA", chunkSizeCA); keyFile.set_integer("Performance", "ThumbnailInspectorMode", int(rtSettings.thumbnail_inspector_mode)); + keyFile.set_string("Output", "Format", saveFormat.format); keyFile.set_integer("Output", "JpegQuality", saveFormat.jpegQuality); keyFile.set_integer("Output", "JpegSubSamp", saveFormat.jpegSubSamp); @@ -2137,28 +2218,30 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("GUI", "FrameColor", bgcolor); keyFile.set_boolean("GUI", "ProcessingQueueEnbled", procQueueEnabled); Glib::ArrayHandle tpopen = tpOpen; - keyFile.set_integer_list ("GUI", "ToolPanelsExpanded", tpopen); - keyFile.set_boolean ("GUI", "ToolPanelsExpandedAutoSave", autoSaveTpOpen); - keyFile.set_integer ("GUI", "MultiDisplayMode", multiDisplayMode); - keyFile.set_double_list ("GUI", "CutOverlayBrush", cutOverlayBrush); - keyFile.set_double_list ("GUI", "NavGuideBrush", navGuideBrush); - keyFile.set_integer ("GUI", "HistogramPosition", histogramPosition); - keyFile.set_boolean ("GUI", "HistogramRed", histogramRed); - keyFile.set_boolean ("GUI", "HistogramGreen", histogramGreen); - keyFile.set_boolean ("GUI", "HistogramBlue", histogramBlue); - keyFile.set_boolean ("GUI", "HistogramLuma", histogramLuma); - keyFile.set_boolean ("GUI", "HistogramChroma", histogramChroma); - keyFile.set_boolean ("GUI", "HistogramRAW", histogramRAW); - keyFile.set_boolean ("GUI", "HistogramBar", histogramBar); - keyFile.set_integer ("GUI", "HistogramHeight", histogramHeight); - keyFile.set_integer ("GUI", "HistogramDrawMode", histogramDrawMode); - keyFile.set_integer ("GUI", "NavigatorRGBUnit", (int)navRGBUnit); - keyFile.set_integer ("GUI", "NavigatorHSVUnit", (int)navHSVUnit); - keyFile.set_boolean ("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); - keyFile.set_boolean ("GUI", "FileBrowserToolbarSingleRow", FileBrowserToolbarSingleRow); - keyFile.set_boolean ("GUI", "HideTPVScrollbar", hideTPVScrollbar); - keyFile.set_boolean ("GUI", "HistogramWorking", rtSettings.HistogramWorking); - keyFile.set_integer ("GUI", "CurveBBoxPosition", curvebboxpos); + keyFile.set_integer_list("GUI", "ToolPanelsExpanded", tpopen); + keyFile.set_boolean("GUI", "ToolPanelsExpandedAutoSave", autoSaveTpOpen); + keyFile.set_integer("GUI", "MultiDisplayMode", multiDisplayMode); + keyFile.set_double_list("GUI", "CutOverlayBrush", cutOverlayBrush); + keyFile.set_double_list("GUI", "NavGuideBrush", navGuideBrush); + keyFile.set_integer("GUI", "HistogramPosition", histogramPosition); + keyFile.set_boolean("GUI", "HistogramRed", histogramRed); + keyFile.set_boolean("GUI", "HistogramGreen", histogramGreen); + keyFile.set_boolean("GUI", "HistogramBlue", histogramBlue); + keyFile.set_boolean("GUI", "HistogramLuma", histogramLuma); + keyFile.set_boolean("GUI", "HistogramChroma", histogramChroma); + keyFile.set_boolean("GUI", "HistogramRAW", histogramRAW); + keyFile.set_boolean("GUI", "HistogramBar", histogramBar); + keyFile.set_integer("GUI", "HistogramHeight", histogramHeight); + keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); + keyFile.set_integer("GUI", "NavigatorRGBUnit", (int)navRGBUnit); + keyFile.set_integer("GUI", "NavigatorHSVUnit", (int)navHSVUnit); + keyFile.set_boolean("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); + keyFile.set_boolean("GUI", "FileBrowserToolbarSingleRow", FileBrowserToolbarSingleRow); + keyFile.set_boolean("GUI", "HideTPVScrollbar", hideTPVScrollbar); + keyFile.set_boolean("GUI", "HistogramWorking", rtSettings.HistogramWorking); + keyFile.set_integer("GUI", "CurveBBoxPosition", curvebboxpos); + keyFile.set_boolean("GUI", "Showtooltip", showtooltip); + keyFile.set_integer("GUI", "Complexity", complexity); //Glib::ArrayHandle crvopen = crvOpen; //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); @@ -2216,6 +2299,8 @@ void Options::saveToFile(Glib::ustring fname) //keyFile.set_double ("Color Management", "Colortoningab", rtSettings.colortoningab); //keyFile.set_double ("Color Management", "Decaction", rtSettings.decaction); keyFile.set_string("Color Management", "ClutsDirectory", clutsDir); + keyFile.set_integer("Color Management", "Previewselection", rtSettings.previewselection); + keyFile.set_double("Color Management", "Cbdlsensi", rtSettings.cbdlsensi); keyFile.set_string("ICC Profile Creator", "PimariesPreset", ICCPC_primariesPreset); keyFile.set_double("ICC Profile Creator", "RedPrimaryX", ICCPC_redPrimaryX); @@ -2286,6 +2371,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("Dialogs", "LastRetinexDir", lastRetinexDir); keyFile.set_string("Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); keyFile.set_string("Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); + keyFile.set_string("Dialogs", "LastlocalCurvesDir", lastlocalCurvesDir); keyFile.set_string("Dialogs", "LastPFCurvesDir", lastPFCurvesDir); keyFile.set_string("Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); keyFile.set_string("Dialogs", "LastBWCurvesDir", lastBWCurvesDir); @@ -2325,18 +2411,8 @@ void Options::load(bool lightweight) const gchar* path; Glib::ustring dPath; -#ifdef __APPLE__ - // Build Application Support directory path for macOS. - const char* homedir = g_getenv("HOME"); // This returns the current container data dir in ~/Library - std::string homebuf{homedir}; - int homelength = strlen(homebuf.c_str()); - homebuf[homelength-44] = '\0'; // Terminate string after ${HOME}/Library - std::string homeconfig{homebuf}; - std::strcat(&homeconfig[0], "/Application Support/RawTherapee/config"); - path = homeconfig.c_str(); -#else path = g_getenv("RT_SETTINGS"); -#endif + if (path != nullptr) { rtdir = Glib::ustring(path); @@ -2356,7 +2432,11 @@ void Options::load(bool lightweight) } #else + #ifdef __APPLE__ + rtdir = Glib::build_filename(Glib::ustring(g_get_home_dir()), "/Library/Application Support/", Glib::ustring(CACHEFOLDERNAME), "/config/"); + #else rtdir = Glib::build_filename(Glib::ustring(g_get_user_config_dir()), Glib::ustring(CACHEFOLDERNAME)); + #endif #endif } @@ -2378,14 +2458,9 @@ void Options::load(bool lightweight) rtdir = Glib::build_filename(argv0, "mysettings"); } - // Modify the path of the cache folder to the one provided in RT_CACHE environment variable. Build the cache folder name in macOS. -#ifdef __APPLE__ - std::string homecache{homebuf}; - std::strcat(&homecache[0], "/Application Support/RawTherapee/cache"); - path = homecache.c_str(); -#else + // Modify the path of the cache folder to the one provided in RT_CACHE environment variable. path = g_getenv("RT_CACHE"); -#endif + if (path != nullptr) { cacheBaseDir = Glib::ustring(path); @@ -2400,7 +2475,11 @@ void Options::load(bool lightweight) #ifdef WIN32 cacheBaseDir = Glib::build_filename(rtdir, "cache"); #else + #ifdef __APPLE__ + cacheBaseDir = Glib::build_filename(Glib::ustring(g_get_home_dir()), "/Library/Application Support/", Glib::ustring(CACHEFOLDERNAME), "/cache/"); + #else cacheBaseDir = Glib::build_filename(Glib::ustring(g_get_user_cache_dir()), Glib::ustring(CACHEFOLDERNAME)); + #endif #endif } diff --git a/rtgui/options.h b/rtgui/options.h index b8a71c9cb..02d62292c 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -282,12 +282,13 @@ public: //std::vector crvOpen; std::vector baBehav; rtengine::Settings rtSettings; - + bool showtooltip; std::vector favoriteDirs; std::vector renameTemplates; bool renameUseTemplates; bool internalThumbIfUntouched; bool overwriteOutputFile; + int complexity; std::vector thumbnailZoomRatios; bool overlayedFileNames; @@ -409,6 +410,7 @@ public: Glib::ustring lastRetinexDir; Glib::ustring lastDenoiseCurvesDir; Glib::ustring lastWaveletCurvesDir; + Glib::ustring lastlocalCurvesDir; Glib::ustring lastPFCurvesDir; Glib::ustring lastHsvCurvesDir; Glib::ustring lastToneCurvesDir; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 09b3566bd..bbfb7cc4e 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -359,6 +359,14 @@ void ParamsEdited::set(bool v) gradient.strength = v; gradient.centerX = v; gradient.centerY = v; + + locallab.enabled = v; + locallab.selspot = v; + + for (size_t i = 0; i < locallab.spots.size(); i++) { + locallab.spots.at(i).set(v); + } + pcvignette.enabled = v; pcvignette.strength = v; pcvignette.feather = v; @@ -488,6 +496,12 @@ void ParamsEdited::set(bool v) wavelet.strength = v; wavelet.balance = v; wavelet.iter = v; + wavelet.sigmafin = v; + wavelet.sigmaton = v; + wavelet.sigmacol = v; + wavelet.sigmadir = v; + wavelet.rangeab = v; + wavelet.protab = v; wavelet.median = v; wavelet.medianlev = v; wavelet.linkedg = v; @@ -527,9 +541,9 @@ void ParamsEdited::set(bool v) wavelet.HSmethod = v; wavelet.Dirmethod = v; wavelet.sigma = v; - wavelet.sigma = v; wavelet.offset = v; wavelet.lowthr = v; + wavelet.rescon = v; wavelet.resconH = v; wavelet.reschro = v; wavelet.resblur = v; @@ -572,6 +586,7 @@ void ParamsEdited::set(bool v) wavelet.level3noise = v; wavelet.ccwcurve = v; wavelet.blcurve = v; + wavelet.opacityCurveSH = v; wavelet.opacityCurveRG = v; wavelet.opacityCurveBY = v; wavelet.opacityCurveW = v; @@ -595,6 +610,10 @@ void ParamsEdited::set(bool v) wavelet.expresid = v; wavelet.exptoning = v; wavelet.expnoise = v; + wavelet.labgridALow = v; + wavelet.labgridBLow = v; + wavelet.labgridAHigh = v; + wavelet.labgridBHigh = v; for (int i = 0; i < 9; i++) { wavelet.c[i] = v; @@ -637,6 +656,7 @@ void ParamsEdited::set(bool v) filmNegative.greenExp = v; filmNegative.blueRatio = v; filmNegative.baseValues = v; + raw.preprocessWB.mode = v; exif = v; iptc = v; @@ -656,6 +676,13 @@ void ParamsEdited::initFrom(const std::vector& const ProcParams& p = src[0]; + // Resize LocallabSpotEdited according to src[0] + locallab.spots.clear(); + locallab.spots.resize(p.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + + // Variable used to determined if Locallab spots number is equal and so spots can be combined + bool isSpotNumberEqual = true; + for (size_t i = 1; i < src.size(); i++) { const ProcParams& other = src[i]; toneCurve.curve = toneCurve.curve && p.toneCurve.curve == other.toneCurve.curve; @@ -985,6 +1012,480 @@ void ParamsEdited::initFrom(const std::vector& gradient.strength = gradient.strength && p.gradient.strength == other.gradient.strength; gradient.centerX = gradient.centerX && p.gradient.centerX == other.gradient.centerX; gradient.centerY = gradient.centerY && p.gradient.centerY == other.gradient.centerY; + + locallab.enabled = locallab.enabled && p.locallab.enabled == other.locallab.enabled; + isSpotNumberEqual = isSpotNumberEqual && p.locallab.spots.size() == other.locallab.spots.size(); + locallab.selspot = locallab.selspot && p.locallab.selspot == other.locallab.selspot; + + if (isSpotNumberEqual) { + for (size_t j = 0; j < locallab.spots.size() && j < p.locallab.spots.size() && j < other.locallab.spots.size(); j++) { + const LocallabParams::LocallabSpot& pSpot = p.locallab.spots.at(j); + const LocallabParams::LocallabSpot& otherSpot = other.locallab.spots.at(j); + // Control spot settings + locallab.spots.at(j).name = locallab.spots.at(j).name && pSpot.name == otherSpot.name; + locallab.spots.at(j).isvisible = locallab.spots.at(j).isvisible && pSpot.isvisible == otherSpot.isvisible; + locallab.spots.at(j).shape = locallab.spots.at(j).shape && pSpot.shape == otherSpot.shape; + locallab.spots.at(j).spotMethod = locallab.spots.at(j).spotMethod && pSpot.spotMethod == otherSpot.spotMethod; + locallab.spots.at(j).wavMethod = locallab.spots.at(j).wavMethod && pSpot.wavMethod == otherSpot.wavMethod; + locallab.spots.at(j).sensiexclu = locallab.spots.at(j).sensiexclu && pSpot.sensiexclu == otherSpot.sensiexclu; + locallab.spots.at(j).structexclu = locallab.spots.at(j).structexclu && pSpot.structexclu == otherSpot.structexclu; + locallab.spots.at(j).struc = locallab.spots.at(j).struc && pSpot.struc == otherSpot.struc; + locallab.spots.at(j).shapeMethod = locallab.spots.at(j).shapeMethod && pSpot.shapeMethod == otherSpot.shapeMethod; + locallab.spots.at(j).loc = locallab.spots.at(j).loc && pSpot.loc == otherSpot.loc; + locallab.spots.at(j).centerX = locallab.spots.at(j).centerX && pSpot.centerX == otherSpot.centerX; + locallab.spots.at(j).centerY = locallab.spots.at(j).centerY && pSpot.centerY == otherSpot.centerY; + locallab.spots.at(j).circrad = locallab.spots.at(j).circrad && pSpot.circrad == otherSpot.circrad; + locallab.spots.at(j).qualityMethod = locallab.spots.at(j).qualityMethod && pSpot.qualityMethod == otherSpot.qualityMethod; + locallab.spots.at(j).complexMethod = locallab.spots.at(j).complexMethod && pSpot.complexMethod == otherSpot.complexMethod; + locallab.spots.at(j).transit = locallab.spots.at(j).transit && pSpot.transit == otherSpot.transit; + locallab.spots.at(j).feather = locallab.spots.at(j).feather && pSpot.feather == otherSpot.feather; + locallab.spots.at(j).thresh = locallab.spots.at(j).thresh && pSpot.thresh == otherSpot.thresh; + locallab.spots.at(j).iter = locallab.spots.at(j).iter && pSpot.iter == otherSpot.iter; + locallab.spots.at(j).balan = locallab.spots.at(j).balan && pSpot.balan == otherSpot.balan; + locallab.spots.at(j).balanh = locallab.spots.at(j).balanh && pSpot.balanh == otherSpot.balanh; + locallab.spots.at(j).colorde = locallab.spots.at(j).colorde && pSpot.colorde == otherSpot.colorde; + locallab.spots.at(j).colorscope = locallab.spots.at(j).colorscope && pSpot.colorscope == otherSpot.colorscope; + locallab.spots.at(j).transitweak = locallab.spots.at(j).transitweak && pSpot.transitweak == otherSpot.transitweak; + locallab.spots.at(j).transitgrad = locallab.spots.at(j).transitgrad && pSpot.transitgrad == otherSpot.transitgrad; + locallab.spots.at(j).avoid = locallab.spots.at(j).avoid && pSpot.avoid == otherSpot.avoid; + locallab.spots.at(j).blwh = locallab.spots.at(j).blwh && pSpot.blwh == otherSpot.blwh; + locallab.spots.at(j).recurs = locallab.spots.at(j).recurs && pSpot.recurs == otherSpot.recurs; + locallab.spots.at(j).laplac = locallab.spots.at(j).laplac && pSpot.laplac == otherSpot.laplac; + locallab.spots.at(j).deltae = locallab.spots.at(j).deltae && pSpot.deltae == otherSpot.deltae; + locallab.spots.at(j).shortc = locallab.spots.at(j).shortc && pSpot.shortc == otherSpot.shortc; + locallab.spots.at(j).savrest = locallab.spots.at(j).savrest && pSpot.savrest == otherSpot.savrest; + locallab.spots.at(j).scopemask = locallab.spots.at(j).scopemask && pSpot.scopemask == otherSpot.scopemask; + locallab.spots.at(j).lumask = locallab.spots.at(j).lumask && pSpot.lumask == otherSpot.lumask; + // Color & Light + locallab.spots.at(j).visicolor = locallab.spots.at(j).visicolor && pSpot.visicolor == otherSpot.visicolor; + locallab.spots.at(j).expcolor = locallab.spots.at(j).expcolor && pSpot.expcolor == otherSpot.expcolor; + locallab.spots.at(j).complexcolor = locallab.spots.at(j).complexcolor && pSpot.complexcolor == otherSpot.complexcolor; + locallab.spots.at(j).curvactiv = locallab.spots.at(j).curvactiv && pSpot.curvactiv == otherSpot.curvactiv; + locallab.spots.at(j).lightness = locallab.spots.at(j).lightness && pSpot.lightness == otherSpot.lightness; + locallab.spots.at(j).contrast = locallab.spots.at(j).contrast && pSpot.contrast == otherSpot.contrast; + locallab.spots.at(j).chroma = locallab.spots.at(j).chroma && pSpot.chroma == otherSpot.chroma; + locallab.spots.at(j).labgridALow = locallab.spots.at(j).labgridALow && pSpot.labgridALow == otherSpot.labgridALow; + locallab.spots.at(j).labgridBLow = locallab.spots.at(j).labgridBLow && pSpot.labgridBLow == otherSpot.labgridBLow; + locallab.spots.at(j).labgridAHigh = locallab.spots.at(j).labgridAHigh && pSpot.labgridAHigh == otherSpot.labgridAHigh; + locallab.spots.at(j).labgridBHigh = locallab.spots.at(j).labgridBHigh && pSpot.labgridBHigh == otherSpot.labgridBHigh; + locallab.spots.at(j).labgridALowmerg = locallab.spots.at(j).labgridALowmerg && pSpot.labgridALowmerg == otherSpot.labgridALowmerg; + locallab.spots.at(j).labgridBLowmerg = locallab.spots.at(j).labgridBLowmerg && pSpot.labgridBLowmerg == otherSpot.labgridBLowmerg; + locallab.spots.at(j).labgridAHighmerg = locallab.spots.at(j).labgridAHighmerg && pSpot.labgridAHighmerg == otherSpot.labgridAHighmerg; + locallab.spots.at(j).labgridBHighmerg = locallab.spots.at(j).labgridBHighmerg && pSpot.labgridBHighmerg == otherSpot.labgridBHighmerg; + locallab.spots.at(j).strengthgrid = locallab.spots.at(j).strengthgrid && pSpot.strengthgrid == otherSpot.strengthgrid; + locallab.spots.at(j).sensi = locallab.spots.at(j).sensi && pSpot.sensi == otherSpot.sensi; + locallab.spots.at(j).structcol = locallab.spots.at(j).structcol && pSpot.structcol == otherSpot.structcol; + locallab.spots.at(j).strcol = locallab.spots.at(j).strcol && pSpot.strcol == otherSpot.strcol; + locallab.spots.at(j).strcolab = locallab.spots.at(j).strcolab && pSpot.strcolab == otherSpot.strcolab; + locallab.spots.at(j).strcolh = locallab.spots.at(j).strcolh && pSpot.strcolh == otherSpot.strcolh; + locallab.spots.at(j).angcol = locallab.spots.at(j).angcol && pSpot.angcol == otherSpot.angcol; + locallab.spots.at(j).blurcolde = locallab.spots.at(j).blurcolde && pSpot.blurcolde == otherSpot.blurcolde; + locallab.spots.at(j).blurcol = locallab.spots.at(j).blurcol && pSpot.blurcol == otherSpot.blurcol; + locallab.spots.at(j).contcol = locallab.spots.at(j).contcol && pSpot.contcol == otherSpot.contcol; + locallab.spots.at(j).blendmaskcol = locallab.spots.at(j).blendmaskcol && pSpot.blendmaskcol == otherSpot.blendmaskcol; + locallab.spots.at(j).radmaskcol = locallab.spots.at(j).radmaskcol && pSpot.radmaskcol == otherSpot.radmaskcol; + locallab.spots.at(j).chromaskcol = locallab.spots.at(j).chromaskcol && pSpot.chromaskcol == otherSpot.chromaskcol; + locallab.spots.at(j).gammaskcol = locallab.spots.at(j).gammaskcol && pSpot.gammaskcol == otherSpot.gammaskcol; + locallab.spots.at(j).slomaskcol = locallab.spots.at(j).slomaskcol && pSpot.slomaskcol == otherSpot.slomaskcol; + locallab.spots.at(j).shadmaskcol = locallab.spots.at(j).shadmaskcol && pSpot.shadmaskcol == otherSpot.shadmaskcol; + locallab.spots.at(j).strumaskcol = locallab.spots.at(j).strumaskcol && pSpot.strumaskcol == otherSpot.strumaskcol; + locallab.spots.at(j).lapmaskcol = locallab.spots.at(j).lapmaskcol && pSpot.lapmaskcol == otherSpot.lapmaskcol; + locallab.spots.at(j).qualitycurveMethod = locallab.spots.at(j).qualitycurveMethod && pSpot.qualitycurveMethod == otherSpot.qualitycurveMethod; + locallab.spots.at(j).gridMethod = locallab.spots.at(j).gridMethod && pSpot.gridMethod == otherSpot.gridMethod; + locallab.spots.at(j).merMethod = locallab.spots.at(j).merMethod && pSpot.merMethod == otherSpot.merMethod; + locallab.spots.at(j).toneMethod = locallab.spots.at(j).toneMethod && pSpot.toneMethod == otherSpot.toneMethod; + locallab.spots.at(j).mergecolMethod = locallab.spots.at(j).mergecolMethod && pSpot.mergecolMethod == otherSpot.mergecolMethod; + locallab.spots.at(j).llcurve = locallab.spots.at(j).llcurve && pSpot.llcurve == otherSpot.llcurve; + locallab.spots.at(j).lccurve = locallab.spots.at(j).lccurve && pSpot.lccurve == otherSpot.lccurve; + locallab.spots.at(j).cccurve = locallab.spots.at(j).cccurve && pSpot.cccurve == otherSpot.cccurve; + locallab.spots.at(j).clcurve = locallab.spots.at(j).clcurve && pSpot.cccurve == otherSpot.clcurve; + locallab.spots.at(j).rgbcurve = locallab.spots.at(j).rgbcurve && pSpot.rgbcurve == otherSpot.rgbcurve; + locallab.spots.at(j).LHcurve = locallab.spots.at(j).LHcurve && pSpot.LHcurve == otherSpot.LHcurve; + locallab.spots.at(j).HHcurve = locallab.spots.at(j).HHcurve && pSpot.HHcurve == otherSpot.HHcurve; + locallab.spots.at(j).invers = locallab.spots.at(j).invers && pSpot.invers == otherSpot.invers; + locallab.spots.at(j).special = locallab.spots.at(j).special && pSpot.special == otherSpot.special; + locallab.spots.at(j).toolcol = locallab.spots.at(j).toolcol && pSpot.toolcol == otherSpot.toolcol; + locallab.spots.at(j).enaColorMask = locallab.spots.at(j).enaColorMask && pSpot.enaColorMask == otherSpot.enaColorMask; + locallab.spots.at(j).fftColorMask = locallab.spots.at(j).fftColorMask && pSpot.fftColorMask == otherSpot.fftColorMask; + locallab.spots.at(j).CCmaskcurve = locallab.spots.at(j).CCmaskcurve && pSpot.CCmaskcurve == otherSpot.CCmaskcurve; + locallab.spots.at(j).LLmaskcurve = locallab.spots.at(j).LLmaskcurve && pSpot.LLmaskcurve == otherSpot.LLmaskcurve; + locallab.spots.at(j).HHmaskcurve = locallab.spots.at(j).HHmaskcurve && pSpot.HHmaskcurve == otherSpot.HHmaskcurve; + locallab.spots.at(j).HHhmaskcurve = locallab.spots.at(j).HHhmaskcurve && pSpot.HHhmaskcurve == otherSpot.HHhmaskcurve; + locallab.spots.at(j).softradiuscol = locallab.spots.at(j).softradiuscol && pSpot.softradiuscol == otherSpot.softradiuscol; + locallab.spots.at(j).opacol = locallab.spots.at(j).opacol && pSpot.opacol == otherSpot.opacol; + locallab.spots.at(j).mercol = locallab.spots.at(j).mercol && pSpot.mercol == otherSpot.mercol; + locallab.spots.at(j).merlucol = locallab.spots.at(j).merlucol && pSpot.merlucol == otherSpot.merlucol; + locallab.spots.at(j).conthrcol = locallab.spots.at(j).conthrcol && pSpot.conthrcol == otherSpot.conthrcol; + locallab.spots.at(j).Lmaskcurve = locallab.spots.at(j).Lmaskcurve && pSpot.Lmaskcurve == otherSpot.Lmaskcurve; + locallab.spots.at(j).LLmaskcolcurvewav = locallab.spots.at(j).LLmaskcolcurvewav && pSpot.LLmaskcolcurvewav == otherSpot.LLmaskcolcurvewav; + locallab.spots.at(j).csthresholdcol = locallab.spots.at(j).csthresholdcol && pSpot.csthresholdcol == otherSpot.csthresholdcol; + // Exposure + locallab.spots.at(j).visiexpose = locallab.spots.at(j).visiexpose && pSpot.visiexpose == otherSpot.visiexpose; + locallab.spots.at(j).expexpose = locallab.spots.at(j).expexpose && pSpot.expexpose == otherSpot.expexpose; + locallab.spots.at(j).complexexpose = locallab.spots.at(j).complexexpose && pSpot.complexexpose == otherSpot.complexexpose; + locallab.spots.at(j).expcomp = locallab.spots.at(j).expcomp && pSpot.expcomp == otherSpot.expcomp; + locallab.spots.at(j).hlcompr = locallab.spots.at(j).hlcompr && pSpot.hlcompr == otherSpot.hlcompr; + locallab.spots.at(j).hlcomprthresh = locallab.spots.at(j).hlcomprthresh && pSpot.hlcomprthresh == otherSpot.hlcomprthresh; + locallab.spots.at(j).black = locallab.spots.at(j).black && pSpot.black == otherSpot.black; + locallab.spots.at(j).shadex = locallab.spots.at(j).shadex && pSpot.shadex == otherSpot.shadex; + locallab.spots.at(j).shcompr = locallab.spots.at(j).shcompr && pSpot.shcompr == otherSpot.shcompr; + locallab.spots.at(j).expchroma = locallab.spots.at(j).expchroma && pSpot.expchroma == otherSpot.expchroma; + locallab.spots.at(j).sensiex = locallab.spots.at(j).sensiex && pSpot.sensiex == otherSpot.sensiex; + locallab.spots.at(j).structexp = locallab.spots.at(j).structexp && pSpot.structexp == otherSpot.structexp; + locallab.spots.at(j).blurexpde = locallab.spots.at(j).blurexpde && pSpot.blurexpde == otherSpot.blurexpde; + locallab.spots.at(j).strexp = locallab.spots.at(j).strexp && pSpot.strexp == otherSpot.strexp; + locallab.spots.at(j).angexp = locallab.spots.at(j).angexp && pSpot.angexp == otherSpot.angexp; + locallab.spots.at(j).excurve = locallab.spots.at(j).excurve && pSpot.excurve == otherSpot.excurve; + locallab.spots.at(j).inversex = locallab.spots.at(j).inversex && pSpot.inversex == otherSpot.inversex; + locallab.spots.at(j).enaExpMask = locallab.spots.at(j).enaExpMask && pSpot.enaExpMask == otherSpot.enaExpMask; + locallab.spots.at(j).enaExpMaskaft = locallab.spots.at(j).enaExpMaskaft && pSpot.enaExpMaskaft == otherSpot.enaExpMaskaft; + locallab.spots.at(j).CCmaskexpcurve = locallab.spots.at(j).CCmaskexpcurve && pSpot.CCmaskexpcurve == otherSpot.CCmaskexpcurve; + locallab.spots.at(j).LLmaskexpcurve = locallab.spots.at(j).LLmaskexpcurve && pSpot.LLmaskexpcurve == otherSpot.LLmaskexpcurve; + locallab.spots.at(j).HHmaskexpcurve = locallab.spots.at(j).HHmaskexpcurve && pSpot.HHmaskexpcurve == otherSpot.HHmaskexpcurve; + locallab.spots.at(j).blendmaskexp = locallab.spots.at(j).blendmaskexp && pSpot.blendmaskexp == otherSpot.blendmaskexp; + locallab.spots.at(j).radmaskexp = locallab.spots.at(j).radmaskexp && pSpot.radmaskexp == otherSpot.radmaskexp; + locallab.spots.at(j).chromaskexp = locallab.spots.at(j).chromaskexp && pSpot.chromaskexp == otherSpot.chromaskexp; + locallab.spots.at(j).gammaskexp = locallab.spots.at(j).gammaskexp && pSpot.gammaskexp == otherSpot.gammaskexp; + locallab.spots.at(j).slomaskexp = locallab.spots.at(j).slomaskexp && pSpot.slomaskexp == otherSpot.slomaskexp; + locallab.spots.at(j).lapmaskexp = locallab.spots.at(j).lapmaskexp && pSpot.lapmaskexp == otherSpot.lapmaskexp; + locallab.spots.at(j).strmaskexp = locallab.spots.at(j).strmaskexp && pSpot.strmaskexp == otherSpot.strmaskexp; + locallab.spots.at(j).angmaskexp = locallab.spots.at(j).angmaskexp && pSpot.angmaskexp == otherSpot.angmaskexp; + locallab.spots.at(j).softradiusexp = locallab.spots.at(j).softradiusexp && pSpot.softradiusexp == otherSpot.softradiusexp; + locallab.spots.at(j).Lmaskexpcurve = locallab.spots.at(j).Lmaskexpcurve && pSpot.Lmaskexpcurve == otherSpot.Lmaskexpcurve; + locallab.spots.at(j).expMethod = locallab.spots.at(j).expMethod && pSpot.expMethod == otherSpot.expMethod; + locallab.spots.at(j).exnoiseMethod = locallab.spots.at(j).exnoiseMethod && pSpot.exnoiseMethod == otherSpot.exnoiseMethod; + locallab.spots.at(j).laplacexp = locallab.spots.at(j).laplacexp && pSpot.laplacexp == otherSpot.laplacexp; + locallab.spots.at(j).balanexp = locallab.spots.at(j).balanexp && pSpot.balanexp == otherSpot.balanexp; + locallab.spots.at(j).linear = locallab.spots.at(j).linear && pSpot.linear == otherSpot.linear; + locallab.spots.at(j).gamm = locallab.spots.at(j).gamm && pSpot.gamm == otherSpot.gamm; + locallab.spots.at(j).fatamount = locallab.spots.at(j).fatamount && pSpot.fatamount == otherSpot.fatamount; + locallab.spots.at(j).fatdetail = locallab.spots.at(j).fatdetail && pSpot.fatdetail == otherSpot.fatdetail; + locallab.spots.at(j).fatanchor = locallab.spots.at(j).fatanchor && pSpot.fatanchor == otherSpot.fatanchor; + locallab.spots.at(j).fatlevel = locallab.spots.at(j).fatlevel && pSpot.fatlevel == otherSpot.fatlevel; + // Shadow highlight + locallab.spots.at(j).visishadhigh = locallab.spots.at(j).visishadhigh && pSpot.visishadhigh == otherSpot.visishadhigh; + locallab.spots.at(j).expshadhigh = locallab.spots.at(j).expshadhigh && pSpot.expshadhigh == otherSpot.expshadhigh; + locallab.spots.at(j).complexshadhigh = locallab.spots.at(j).complexshadhigh && pSpot.complexshadhigh == otherSpot.complexshadhigh; + locallab.spots.at(j).shMethod = locallab.spots.at(j).shMethod && pSpot.shMethod == otherSpot.shMethod; + + for (int k = 0; k < 5; k++) { + locallab.spots.at(j).multsh[k] = locallab.spots.at(j).multsh[k] && pSpot.multsh[k] == otherSpot.multsh[k]; + } + + locallab.spots.at(j).highlights = locallab.spots.at(j).highlights && pSpot.highlights == otherSpot.highlights; + locallab.spots.at(j).h_tonalwidth = locallab.spots.at(j).h_tonalwidth && pSpot.h_tonalwidth == otherSpot.h_tonalwidth; + locallab.spots.at(j).shadows = locallab.spots.at(j).shadows && pSpot.shadows == otherSpot.shadows; + locallab.spots.at(j).s_tonalwidth = locallab.spots.at(j).s_tonalwidth && pSpot.s_tonalwidth == otherSpot.s_tonalwidth; + locallab.spots.at(j).sh_radius = locallab.spots.at(j).sh_radius && pSpot.sh_radius == otherSpot.sh_radius; + locallab.spots.at(j).sensihs = locallab.spots.at(j).sensihs && pSpot.sensihs == otherSpot.sensihs; + locallab.spots.at(j).enaSHMask = locallab.spots.at(j).enaSHMask && pSpot.enaSHMask == otherSpot.enaSHMask; + locallab.spots.at(j).CCmaskSHcurve = locallab.spots.at(j).CCmaskSHcurve && pSpot.CCmaskSHcurve == otherSpot.CCmaskSHcurve; + locallab.spots.at(j).LLmaskSHcurve = locallab.spots.at(j).LLmaskSHcurve && pSpot.LLmaskSHcurve == otherSpot.LLmaskSHcurve; + locallab.spots.at(j).HHmaskSHcurve = locallab.spots.at(j).HHmaskSHcurve && pSpot.HHmaskSHcurve == otherSpot.HHmaskSHcurve; + locallab.spots.at(j).blendmaskSH = locallab.spots.at(j).blendmaskSH && pSpot.blendmaskSH == otherSpot.blendmaskSH; + locallab.spots.at(j).radmaskSH = locallab.spots.at(j).radmaskSH && pSpot.radmaskSH == otherSpot.radmaskSH; + locallab.spots.at(j).blurSHde = locallab.spots.at(j).blurSHde && pSpot.blurSHde == otherSpot.blurSHde; + locallab.spots.at(j).strSH = locallab.spots.at(j).strSH && pSpot.strSH == otherSpot.strSH; + locallab.spots.at(j).angSH = locallab.spots.at(j).angSH && pSpot.angSH == otherSpot.angSH; + locallab.spots.at(j).inverssh = locallab.spots.at(j).inverssh && pSpot.inverssh == otherSpot.inverssh; + locallab.spots.at(j).chromaskSH = locallab.spots.at(j).chromaskSH && pSpot.chromaskSH == otherSpot.chromaskSH; + locallab.spots.at(j).gammaskSH = locallab.spots.at(j).gammaskSH && pSpot.gammaskSH == otherSpot.gammaskSH; + locallab.spots.at(j).slomaskSH = locallab.spots.at(j).slomaskSH && pSpot.slomaskSH == otherSpot.slomaskSH; + locallab.spots.at(j).lapmaskSH = locallab.spots.at(j).lapmaskSH && pSpot.lapmaskSH == otherSpot.lapmaskSH; + locallab.spots.at(j).detailSH = locallab.spots.at(j).detailSH && pSpot.detailSH == otherSpot.detailSH; + locallab.spots.at(j).LmaskSHcurve = locallab.spots.at(j).LmaskSHcurve && pSpot.LmaskSHcurve == otherSpot.LmaskSHcurve; + locallab.spots.at(j).fatamountSH = locallab.spots.at(j).fatamountSH && pSpot.fatamountSH == otherSpot.fatamountSH; + locallab.spots.at(j).fatanchorSH = locallab.spots.at(j).fatanchorSH && pSpot.fatanchorSH == otherSpot.fatanchorSH; + locallab.spots.at(j).gamSH = locallab.spots.at(j).gamSH && pSpot.gamSH == otherSpot.gamSH; + locallab.spots.at(j).sloSH = locallab.spots.at(j).sloSH && pSpot.sloSH == otherSpot.sloSH; + // Vibrance + locallab.spots.at(j).visivibrance = locallab.spots.at(j).visivibrance && pSpot.visivibrance == otherSpot.visivibrance; + locallab.spots.at(j).expvibrance = locallab.spots.at(j).expvibrance && pSpot.expvibrance == otherSpot.expvibrance; + locallab.spots.at(j).complexvibrance = locallab.spots.at(j).complexvibrance && pSpot.complexvibrance == otherSpot.complexvibrance; + locallab.spots.at(j).saturated = locallab.spots.at(j).saturated && pSpot.saturated == otherSpot.saturated; + locallab.spots.at(j).pastels = locallab.spots.at(j).pastels && pSpot.pastels == otherSpot.pastels; + locallab.spots.at(j).warm = locallab.spots.at(j).warm && pSpot.warm == otherSpot.warm; + locallab.spots.at(j).psthreshold = locallab.spots.at(j).psthreshold && pSpot.psthreshold == otherSpot.psthreshold; + locallab.spots.at(j).protectskins = locallab.spots.at(j).protectskins && pSpot.protectskins == otherSpot.protectskins; + locallab.spots.at(j).avoidcolorshift = locallab.spots.at(j).avoidcolorshift && pSpot.avoidcolorshift == otherSpot.avoidcolorshift; + locallab.spots.at(j).pastsattog = locallab.spots.at(j).pastsattog && pSpot.pastsattog == otherSpot.pastsattog; + locallab.spots.at(j).sensiv = locallab.spots.at(j).sensiv && pSpot.sensiv == otherSpot.sensiv; + locallab.spots.at(j).skintonescurve = locallab.spots.at(j).skintonescurve && pSpot.skintonescurve == otherSpot.skintonescurve; + locallab.spots.at(j).CCmaskvibcurve = locallab.spots.at(j).CCmaskvibcurve && pSpot.CCmaskvibcurve == otherSpot.CCmaskvibcurve; + locallab.spots.at(j).LLmaskvibcurve = locallab.spots.at(j).LLmaskvibcurve && pSpot.LLmaskvibcurve == otherSpot.LLmaskvibcurve; + locallab.spots.at(j).HHmaskvibcurve = locallab.spots.at(j).HHmaskvibcurve && pSpot.HHmaskvibcurve == otherSpot.HHmaskvibcurve; + locallab.spots.at(j).enavibMask = locallab.spots.at(j).enavibMask && pSpot.enavibMask == otherSpot.enavibMask; + locallab.spots.at(j).blendmaskvib = locallab.spots.at(j).blendmaskvib && pSpot.blendmaskvib == otherSpot.blendmaskvib; + locallab.spots.at(j).radmaskvib = locallab.spots.at(j).radmaskvib && pSpot.radmaskvib == otherSpot.radmaskvib; + locallab.spots.at(j).chromaskvib = locallab.spots.at(j).chromaskvib && pSpot.chromaskvib == otherSpot.chromaskvib; + locallab.spots.at(j).gammaskvib = locallab.spots.at(j).gammaskvib && pSpot.gammaskvib == otherSpot.gammaskvib; + locallab.spots.at(j).slomaskvib = locallab.spots.at(j).slomaskvib && pSpot.slomaskvib == otherSpot.slomaskvib; + locallab.spots.at(j).lapmaskvib = locallab.spots.at(j).lapmaskvib && pSpot.lapmaskvib == otherSpot.lapmaskvib; + locallab.spots.at(j).strvib = locallab.spots.at(j).strvib && pSpot.strvib == otherSpot.strvib; + locallab.spots.at(j).strvibab = locallab.spots.at(j).strvibab && pSpot.strvibab == otherSpot.strvibab; + locallab.spots.at(j).strvibh = locallab.spots.at(j).strvibh && pSpot.strvibh == otherSpot.strvibh; + locallab.spots.at(j).angvib = locallab.spots.at(j).angvib && pSpot.angvib == otherSpot.angvib; + locallab.spots.at(j).Lmaskvibcurve = locallab.spots.at(j).Lmaskvibcurve && pSpot.Lmaskvibcurve == otherSpot.Lmaskvibcurve; + // Soft Light + locallab.spots.at(j).visisoft = locallab.spots.at(j).visisoft && pSpot.visisoft == otherSpot.visisoft; + locallab.spots.at(j).expsoft = locallab.spots.at(j).expsoft && pSpot.expsoft == otherSpot.expsoft; + locallab.spots.at(j).complexsoft = locallab.spots.at(j).complexsoft && pSpot.complexsoft == otherSpot.complexsoft; + locallab.spots.at(j).streng = locallab.spots.at(j).streng && pSpot.streng == otherSpot.streng; + locallab.spots.at(j).sensisf = locallab.spots.at(j).sensisf && pSpot.sensisf == otherSpot.sensisf; + locallab.spots.at(j).laplace = locallab.spots.at(j).laplace && pSpot.laplace == otherSpot.laplace; + locallab.spots.at(j).softMethod = locallab.spots.at(j).softMethod && pSpot.softMethod == otherSpot.softMethod; + // Blur & Noise + locallab.spots.at(j).visiblur = locallab.spots.at(j).visiblur && pSpot.visiblur == otherSpot.visiblur; + locallab.spots.at(j).expblur = locallab.spots.at(j).expblur && pSpot.expblur == otherSpot.expblur; + locallab.spots.at(j).complexblur = locallab.spots.at(j).complexblur && pSpot.complexblur == otherSpot.complexblur; + locallab.spots.at(j).radius = locallab.spots.at(j).radius && pSpot.radius == otherSpot.radius; + locallab.spots.at(j).strength = locallab.spots.at(j).strength && pSpot.strength == otherSpot.strength; + locallab.spots.at(j).sensibn = locallab.spots.at(j).sensibn && pSpot.sensibn == otherSpot.sensibn; + locallab.spots.at(j).itera = locallab.spots.at(j).itera && pSpot.itera == otherSpot.itera; + locallab.spots.at(j).guidbl = locallab.spots.at(j).guidbl && pSpot.guidbl == otherSpot.guidbl; + locallab.spots.at(j).strbl = locallab.spots.at(j).strbl && pSpot.strbl == otherSpot.strbl; + locallab.spots.at(j).isogr = locallab.spots.at(j).isogr && pSpot.isogr == otherSpot.isogr; + locallab.spots.at(j).strengr = locallab.spots.at(j).strengr && pSpot.strengr == otherSpot.strengr; + locallab.spots.at(j).scalegr = locallab.spots.at(j).scalegr && pSpot.scalegr == otherSpot.scalegr; + locallab.spots.at(j).epsbl = locallab.spots.at(j).epsbl && pSpot.epsbl == otherSpot.epsbl; + locallab.spots.at(j).blMethod = locallab.spots.at(j).blMethod && pSpot.blMethod == otherSpot.blMethod; + locallab.spots.at(j).chroMethod = locallab.spots.at(j).chroMethod && pSpot.chroMethod == otherSpot.chroMethod; + locallab.spots.at(j).blurMethod = locallab.spots.at(j).blurMethod && pSpot.blurMethod == otherSpot.blurMethod; + locallab.spots.at(j).medMethod = locallab.spots.at(j).medMethod && pSpot.medMethod == otherSpot.medMethod; + locallab.spots.at(j).activlum = locallab.spots.at(j).activlum && pSpot.activlum == otherSpot.activlum; + locallab.spots.at(j).noiselumf = locallab.spots.at(j).noiselumf && pSpot.noiselumf == otherSpot.noiselumf; + locallab.spots.at(j).noiselumf0 = locallab.spots.at(j).noiselumf0 && pSpot.noiselumf0 == otherSpot.noiselumf0; + locallab.spots.at(j).noiselumf2 = locallab.spots.at(j).noiselumf2 && pSpot.noiselumf2 == otherSpot.noiselumf2; + locallab.spots.at(j).noiselumc = locallab.spots.at(j).noiselumc && pSpot.noiselumc == otherSpot.noiselumc; + locallab.spots.at(j).noiselumdetail = locallab.spots.at(j).noiselumdetail && pSpot.noiselumdetail == otherSpot.noiselumdetail; + locallab.spots.at(j).noiselequal = locallab.spots.at(j).noiselequal && pSpot.noiselequal == otherSpot.noiselequal; + locallab.spots.at(j).noisechrof = locallab.spots.at(j).noisechrof && pSpot.noisechrof == otherSpot.noisechrof; + locallab.spots.at(j).noisechroc = locallab.spots.at(j).noisechroc && pSpot.noisechroc == otherSpot.noisechroc; + locallab.spots.at(j).noisechrodetail = locallab.spots.at(j).noisechrodetail && pSpot.noisechrodetail == otherSpot.noisechrodetail; + locallab.spots.at(j).adjblur = locallab.spots.at(j).adjblur && pSpot.adjblur == otherSpot.adjblur; + locallab.spots.at(j).bilateral = locallab.spots.at(j).bilateral && pSpot.bilateral == otherSpot.bilateral; + locallab.spots.at(j).sensiden = locallab.spots.at(j).sensiden && pSpot.sensiden == otherSpot.sensiden; + locallab.spots.at(j).detailthr = locallab.spots.at(j).detailthr && pSpot.detailthr == otherSpot.detailthr; + locallab.spots.at(j).locwavcurveden = locallab.spots.at(j).locwavcurveden && pSpot.locwavcurveden == otherSpot.locwavcurveden; + locallab.spots.at(j).showmaskblMethodtyp = locallab.spots.at(j).showmaskblMethodtyp && pSpot.showmaskblMethodtyp == otherSpot.showmaskblMethodtyp; + locallab.spots.at(j).CCmaskblcurve = locallab.spots.at(j).CCmaskblcurve && pSpot.CCmaskblcurve == otherSpot.CCmaskblcurve; + locallab.spots.at(j).LLmaskblcurve = locallab.spots.at(j).LLmaskblcurve && pSpot.LLmaskblcurve == otherSpot.LLmaskblcurve; + locallab.spots.at(j).HHmaskblcurve = locallab.spots.at(j).HHmaskblcurve && pSpot.HHmaskblcurve == otherSpot.HHmaskblcurve; + locallab.spots.at(j).enablMask = locallab.spots.at(j).enablMask && pSpot.enablMask == otherSpot.enablMask; + locallab.spots.at(j).fftwbl = locallab.spots.at(j).fftwbl && pSpot.fftwbl == otherSpot.fftwbl; + locallab.spots.at(j).toolbl = locallab.spots.at(j).toolbl && pSpot.toolbl == otherSpot.toolbl; + locallab.spots.at(j).blendmaskbl = locallab.spots.at(j).blendmaskbl && pSpot.blendmaskbl == otherSpot.blendmaskbl; + locallab.spots.at(j).radmaskbl = locallab.spots.at(j).radmaskbl && pSpot.radmaskbl == otherSpot.radmaskbl; + locallab.spots.at(j).chromaskbl = locallab.spots.at(j).chromaskbl && pSpot.chromaskbl == otherSpot.chromaskbl; + locallab.spots.at(j).gammaskbl = locallab.spots.at(j).gammaskbl && pSpot.gammaskbl == otherSpot.gammaskbl; + locallab.spots.at(j).slomaskbl = locallab.spots.at(j).slomaskbl && pSpot.slomaskbl == otherSpot.slomaskbl; + locallab.spots.at(j).lapmaskbl = locallab.spots.at(j).lapmaskbl && pSpot.lapmaskbl == otherSpot.lapmaskbl; + locallab.spots.at(j).shadmaskbl = locallab.spots.at(j).shadmaskbl && pSpot.shadmaskbl == otherSpot.shadmaskbl; + locallab.spots.at(j).shadmaskblsha = locallab.spots.at(j).shadmaskblsha && pSpot.shadmaskblsha == otherSpot.shadmaskblsha; + locallab.spots.at(j).strumaskbl = locallab.spots.at(j).strumaskbl && pSpot.strumaskbl == otherSpot.strumaskbl; + locallab.spots.at(j).Lmaskblcurve = locallab.spots.at(j).Lmaskblcurve && pSpot.Lmaskblcurve == otherSpot.Lmaskblcurve; + locallab.spots.at(j).LLmaskblcurvewav = locallab.spots.at(j).LLmaskblcurvewav && pSpot.LLmaskblcurvewav == otherSpot.LLmaskblcurvewav; + locallab.spots.at(j).csthresholdblur = locallab.spots.at(j).csthresholdblur && pSpot.csthresholdblur == otherSpot.csthresholdblur; + // Tone Mapping + locallab.spots.at(j).visitonemap = locallab.spots.at(j).visitonemap && pSpot.visitonemap == otherSpot.visitonemap; + locallab.spots.at(j).exptonemap = locallab.spots.at(j).exptonemap && pSpot.exptonemap == otherSpot.exptonemap; + locallab.spots.at(j).complextonemap = locallab.spots.at(j).complextonemap && pSpot.complextonemap == otherSpot.complextonemap; + locallab.spots.at(j).stren = locallab.spots.at(j).stren && pSpot.stren == otherSpot.stren; + locallab.spots.at(j).gamma = locallab.spots.at(j).gamma && pSpot.gamma == otherSpot.gamma; + locallab.spots.at(j).estop = locallab.spots.at(j).estop && pSpot.estop == otherSpot.estop; + locallab.spots.at(j).scaltm = locallab.spots.at(j).scaltm && pSpot.scaltm == otherSpot.scaltm; + locallab.spots.at(j).rewei = locallab.spots.at(j).rewei && pSpot.rewei == otherSpot.rewei; + locallab.spots.at(j).satur = locallab.spots.at(j).satur && pSpot.satur == otherSpot.satur; + locallab.spots.at(j).sensitm = locallab.spots.at(j).sensitm && pSpot.sensitm == otherSpot.sensitm; + locallab.spots.at(j).softradiustm = locallab.spots.at(j).softradiustm && pSpot.softradiustm == otherSpot.softradiustm; + locallab.spots.at(j).amount = locallab.spots.at(j).amount && pSpot.amount == otherSpot.amount; + locallab.spots.at(j).equiltm = locallab.spots.at(j).equiltm && pSpot.equiltm == otherSpot.equiltm; + locallab.spots.at(j).CCmasktmcurve = locallab.spots.at(j).CCmasktmcurve && pSpot.CCmasktmcurve == otherSpot.CCmasktmcurve; + locallab.spots.at(j).LLmasktmcurve = locallab.spots.at(j).LLmasktmcurve && pSpot.LLmasktmcurve == otherSpot.LLmasktmcurve; + locallab.spots.at(j).HHmasktmcurve = locallab.spots.at(j).HHmasktmcurve && pSpot.HHmasktmcurve == otherSpot.HHmasktmcurve; + locallab.spots.at(j).enatmMask = locallab.spots.at(j).enatmMask && pSpot.enatmMask == otherSpot.enatmMask; + locallab.spots.at(j).enatmMaskaft = locallab.spots.at(j).enatmMaskaft && pSpot.enatmMaskaft == otherSpot.enatmMaskaft; + locallab.spots.at(j).blendmasktm = locallab.spots.at(j).blendmasktm && pSpot.blendmasktm == otherSpot.blendmasktm; + locallab.spots.at(j).radmasktm = locallab.spots.at(j).radmasktm && pSpot.radmasktm == otherSpot.radmasktm; + locallab.spots.at(j).chromasktm = locallab.spots.at(j).chromasktm && pSpot.chromasktm == otherSpot.chromasktm; + locallab.spots.at(j).gammasktm = locallab.spots.at(j).gammasktm && pSpot.gammasktm == otherSpot.gammasktm; + locallab.spots.at(j).slomasktm = locallab.spots.at(j).slomasktm && pSpot.slomasktm == otherSpot.slomasktm; + locallab.spots.at(j).lapmasktm = locallab.spots.at(j).lapmasktm && pSpot.lapmasktm == otherSpot.lapmasktm; + locallab.spots.at(j).Lmasktmcurve = locallab.spots.at(j).Lmasktmcurve && pSpot.Lmasktmcurve == otherSpot.Lmasktmcurve; + // Retinex + locallab.spots.at(j).visireti = locallab.spots.at(j).visireti && pSpot.visireti == otherSpot.visireti; + locallab.spots.at(j).expreti = locallab.spots.at(j).expreti && pSpot.expreti == otherSpot.expreti; + locallab.spots.at(j).complexreti = locallab.spots.at(j).complexreti && pSpot.complexreti == otherSpot.complexreti; + locallab.spots.at(j).retinexMethod = locallab.spots.at(j).retinexMethod && pSpot.retinexMethod == otherSpot.retinexMethod; + locallab.spots.at(j).str = locallab.spots.at(j).str && pSpot.str == otherSpot.str; + locallab.spots.at(j).chrrt = locallab.spots.at(j).chrrt && pSpot.chrrt == otherSpot.chrrt; + locallab.spots.at(j).neigh = locallab.spots.at(j).neigh && pSpot.neigh == otherSpot.neigh; + locallab.spots.at(j).vart = locallab.spots.at(j).vart && pSpot.vart == otherSpot.vart; + locallab.spots.at(j).offs = locallab.spots.at(j).offs && pSpot.offs == otherSpot.offs; + locallab.spots.at(j).dehaz = locallab.spots.at(j).dehaz && pSpot.dehaz == otherSpot.dehaz; + locallab.spots.at(j).depth = locallab.spots.at(j).depth && pSpot.depth == otherSpot.depth; + locallab.spots.at(j).sensih = locallab.spots.at(j).sensih && pSpot.sensih == otherSpot.sensih; + locallab.spots.at(j).localTgaincurve = locallab.spots.at(j).localTgaincurve && pSpot.localTgaincurve == otherSpot.localTgaincurve; + locallab.spots.at(j).localTtranscurve = locallab.spots.at(j).localTtranscurve && pSpot.localTtranscurve == otherSpot.localTtranscurve; + locallab.spots.at(j).inversret = locallab.spots.at(j).inversret && pSpot.inversret == otherSpot.inversret; + locallab.spots.at(j).equilret = locallab.spots.at(j).equilret && pSpot.equilret == otherSpot.equilret; + locallab.spots.at(j).loglin = locallab.spots.at(j).loglin && pSpot.loglin == otherSpot.loglin; + locallab.spots.at(j).lumonly = locallab.spots.at(j).lumonly && pSpot.lumonly == otherSpot.lumonly; + locallab.spots.at(j).softradiusret = locallab.spots.at(j).softradiusret && pSpot.softradiusret == otherSpot.softradiusret; + locallab.spots.at(j).CCmaskreticurve = locallab.spots.at(j).CCmaskreticurve && pSpot.CCmaskreticurve == otherSpot.CCmaskreticurve; + locallab.spots.at(j).LLmaskreticurve = locallab.spots.at(j).LLmaskreticurve && pSpot.LLmaskreticurve == otherSpot.LLmaskreticurve; + locallab.spots.at(j).HHmaskreticurve = locallab.spots.at(j).HHmaskreticurve && pSpot.HHmaskreticurve == otherSpot.HHmaskreticurve; + locallab.spots.at(j).enaretiMask = locallab.spots.at(j).enaretiMask && pSpot.enaretiMask == otherSpot.enaretiMask; + locallab.spots.at(j).enaretiMasktmap = locallab.spots.at(j).enaretiMasktmap && pSpot.enaretiMasktmap == otherSpot.enaretiMasktmap; + locallab.spots.at(j).blendmaskreti = locallab.spots.at(j).blendmaskreti && pSpot.blendmaskreti == otherSpot.blendmaskreti; + locallab.spots.at(j).radmaskreti = locallab.spots.at(j).radmaskreti && pSpot.radmaskreti == otherSpot.radmaskreti; + locallab.spots.at(j).chromaskreti = locallab.spots.at(j).chromaskreti && pSpot.chromaskreti == otherSpot.chromaskreti; + locallab.spots.at(j).gammaskreti = locallab.spots.at(j).gammaskreti && pSpot.gammaskreti == otherSpot.gammaskreti; + locallab.spots.at(j).slomaskreti = locallab.spots.at(j).slomaskreti && pSpot.slomaskreti == otherSpot.slomaskreti; + locallab.spots.at(j).lapmaskreti = locallab.spots.at(j).lapmaskreti && pSpot.lapmaskreti == otherSpot.lapmaskreti; + locallab.spots.at(j).scalereti = locallab.spots.at(j).scalereti && pSpot.scalereti == otherSpot.scalereti; + locallab.spots.at(j).darkness = locallab.spots.at(j).darkness && pSpot.darkness == otherSpot.darkness; + locallab.spots.at(j).lightnessreti = locallab.spots.at(j).lightnessreti && pSpot.lightnessreti == otherSpot.lightnessreti; + locallab.spots.at(j).limd = locallab.spots.at(j).limd && pSpot.limd == otherSpot.limd; + locallab.spots.at(j).cliptm = locallab.spots.at(j).cliptm && pSpot.cliptm == otherSpot.cliptm; + locallab.spots.at(j).fftwreti = locallab.spots.at(j).fftwreti && pSpot.fftwreti == otherSpot.fftwreti; + locallab.spots.at(j).Lmaskreticurve = locallab.spots.at(j).Lmaskreticurve && pSpot.Lmaskreticurve == otherSpot.Lmaskreticurve; + // Sharpening + locallab.spots.at(j).visisharp = locallab.spots.at(j).visisharp && pSpot.visisharp == otherSpot.visisharp; + locallab.spots.at(j).expsharp = locallab.spots.at(j).expsharp && pSpot.expsharp == otherSpot.expsharp; + locallab.spots.at(j).complexsharp = locallab.spots.at(j).complexsharp && pSpot.complexsharp == otherSpot.complexsharp; + locallab.spots.at(j).sharcontrast = locallab.spots.at(j).sharcontrast && pSpot.sharcontrast == otherSpot.sharcontrast; + locallab.spots.at(j).sharradius = locallab.spots.at(j).sharradius && pSpot.sharradius == otherSpot.sharradius; + locallab.spots.at(j).sharamount = locallab.spots.at(j).sharamount && pSpot.sharamount == otherSpot.sharamount; + locallab.spots.at(j).shardamping = locallab.spots.at(j).shardamping && pSpot.shardamping == otherSpot.shardamping; + locallab.spots.at(j).shariter = locallab.spots.at(j).shariter && pSpot.shariter == otherSpot.shariter; + locallab.spots.at(j).sharblur = locallab.spots.at(j).sharblur && pSpot.sharblur == otherSpot.sharblur; + locallab.spots.at(j).sensisha = locallab.spots.at(j).sensisha && pSpot.sensisha == otherSpot.sensisha; + locallab.spots.at(j).inverssha = locallab.spots.at(j).inverssha && pSpot.inverssha == otherSpot.inverssha; + // Local Contrast + locallab.spots.at(j).visicontrast = locallab.spots.at(j).visicontrast && pSpot.visicontrast == otherSpot.visicontrast; + locallab.spots.at(j).expcontrast = locallab.spots.at(j).expcontrast && pSpot.expcontrast == otherSpot.expcontrast; + locallab.spots.at(j).complexcontrast = locallab.spots.at(j).complexcontrast && pSpot.complexcontrast == otherSpot.complexcontrast; + locallab.spots.at(j).lcradius = locallab.spots.at(j).lcradius && pSpot.lcradius == otherSpot.lcradius; + locallab.spots.at(j).lcamount = locallab.spots.at(j).lcamount && pSpot.lcamount == otherSpot.lcamount; + locallab.spots.at(j).lcdarkness = locallab.spots.at(j).lcdarkness && pSpot.lcdarkness == otherSpot.lcdarkness; + locallab.spots.at(j).lclightness = locallab.spots.at(j).lclightness && pSpot.lclightness == otherSpot.lclightness; + locallab.spots.at(j).sigmalc = locallab.spots.at(j).sigmalc && pSpot.sigmalc == otherSpot.sigmalc; + locallab.spots.at(j).levelwav = locallab.spots.at(j).levelwav && pSpot.levelwav == otherSpot.levelwav; + locallab.spots.at(j).residcont = locallab.spots.at(j).residcont && pSpot.residcont == otherSpot.residcont; + locallab.spots.at(j).residsha = locallab.spots.at(j).residsha && pSpot.residsha == otherSpot.residsha; + locallab.spots.at(j).residshathr = locallab.spots.at(j).residshathr && pSpot.residshathr == otherSpot.residshathr; + locallab.spots.at(j).residhi = locallab.spots.at(j).residhi && pSpot.residhi == otherSpot.residhi; + locallab.spots.at(j).residhithr = locallab.spots.at(j).residhithr && pSpot.residhithr == otherSpot.residhithr; + locallab.spots.at(j).residblur = locallab.spots.at(j).residblur && pSpot.residblur == otherSpot.residblur; + locallab.spots.at(j).levelblur = locallab.spots.at(j).levelblur && pSpot.levelblur == otherSpot.levelblur; + locallab.spots.at(j).sigmabl = locallab.spots.at(j).sigmabl && pSpot.sigmabl == otherSpot.sigmabl; + locallab.spots.at(j).residchro = locallab.spots.at(j).residchro && pSpot.residchro == otherSpot.residchro; + locallab.spots.at(j).residcomp = locallab.spots.at(j).residcomp && pSpot.residcomp == otherSpot.residcomp; + locallab.spots.at(j).sigma = locallab.spots.at(j).sigma && pSpot.sigma == otherSpot.sigma; + locallab.spots.at(j).offset = locallab.spots.at(j).offset && pSpot.offset == otherSpot.offset; + locallab.spots.at(j).sigmadr = locallab.spots.at(j).sigmadr && pSpot.sigmadr == otherSpot.sigmadr; + locallab.spots.at(j).threswav = locallab.spots.at(j).threswav && pSpot.threswav == otherSpot.threswav; + locallab.spots.at(j).chromalev = locallab.spots.at(j).chromalev && pSpot.chromalev == otherSpot.chromalev; + locallab.spots.at(j).chromablu = locallab.spots.at(j).chromablu && pSpot.chromablu == otherSpot.chromablu; + locallab.spots.at(j).sigmadc = locallab.spots.at(j).sigmadc && pSpot.sigmadc == otherSpot.sigmadc; + locallab.spots.at(j).deltad = locallab.spots.at(j).deltad && pSpot.deltad == otherSpot.deltad; + locallab.spots.at(j).fatres = locallab.spots.at(j).fatres && pSpot.fatres == otherSpot.fatres; + locallab.spots.at(j).clarilres = locallab.spots.at(j).clarilres && pSpot.clarilres == otherSpot.clarilres; + locallab.spots.at(j).claricres = locallab.spots.at(j).claricres && pSpot.claricres == otherSpot.claricres; + locallab.spots.at(j).clarisoft = locallab.spots.at(j).clarisoft && pSpot.clarisoft == otherSpot.clarisoft; + locallab.spots.at(j).sigmalc2 = locallab.spots.at(j).sigmalc2 && pSpot.sigmalc2 == otherSpot.sigmalc2; + locallab.spots.at(j).strwav = locallab.spots.at(j).strwav && pSpot.strwav == otherSpot.strwav; + locallab.spots.at(j).angwav = locallab.spots.at(j).angwav && pSpot.angwav == otherSpot.angwav; + locallab.spots.at(j).strengthw = locallab.spots.at(j).strengthw && pSpot.strengthw == otherSpot.strengthw; + locallab.spots.at(j).sigmaed = locallab.spots.at(j).sigmaed && pSpot.sigmaed == otherSpot.sigmaed; + locallab.spots.at(j).radiusw = locallab.spots.at(j).radiusw && pSpot.radiusw == otherSpot.radiusw; + locallab.spots.at(j).detailw = locallab.spots.at(j).detailw && pSpot.detailw == otherSpot.detailw; + locallab.spots.at(j).gradw = locallab.spots.at(j).gradw && pSpot.gradw == otherSpot.gradw; + locallab.spots.at(j).tloww = locallab.spots.at(j).tloww && pSpot.tloww == otherSpot.tloww; + locallab.spots.at(j).thigw = locallab.spots.at(j).thigw && pSpot.thigw == otherSpot.thigw; + locallab.spots.at(j).edgw = locallab.spots.at(j).edgw && pSpot.edgw == otherSpot.edgw; + locallab.spots.at(j).basew = locallab.spots.at(j).basew && pSpot.basew == otherSpot.basew; + locallab.spots.at(j).sensilc = locallab.spots.at(j).sensilc && pSpot.sensilc == otherSpot.sensilc; + locallab.spots.at(j).fftwlc = locallab.spots.at(j).fftwlc && pSpot.fftwlc == otherSpot.fftwlc; + locallab.spots.at(j).blurlc = locallab.spots.at(j).blurlc && pSpot.blurlc == otherSpot.blurlc; + locallab.spots.at(j).wavblur = locallab.spots.at(j).wavblur && pSpot.wavblur == otherSpot.wavblur; + locallab.spots.at(j).wavedg = locallab.spots.at(j).wavedg && pSpot.wavedg == otherSpot.wavedg; + locallab.spots.at(j).waveshow = locallab.spots.at(j).waveshow && pSpot.waveshow == otherSpot.waveshow; + locallab.spots.at(j).wavcont = locallab.spots.at(j).wavcont && pSpot.wavcont == otherSpot.wavcont; + locallab.spots.at(j).wavcomp = locallab.spots.at(j).wavcomp && pSpot.wavcomp == otherSpot.wavcomp; + locallab.spots.at(j).wavgradl = locallab.spots.at(j).wavgradl && pSpot.wavgradl == otherSpot.wavgradl; + locallab.spots.at(j).wavcompre = locallab.spots.at(j).wavcompre && pSpot.wavcompre == otherSpot.wavcompre; + locallab.spots.at(j).origlc = locallab.spots.at(j).origlc && pSpot.origlc == otherSpot.origlc; + locallab.spots.at(j).localcontMethod = locallab.spots.at(j).localcontMethod && pSpot.localcontMethod == otherSpot.localcontMethod; + locallab.spots.at(j).localedgMethod = locallab.spots.at(j).localedgMethod && pSpot.localedgMethod == otherSpot.localedgMethod; + locallab.spots.at(j).localneiMethod = locallab.spots.at(j).localneiMethod && pSpot.localneiMethod == otherSpot.localneiMethod; + locallab.spots.at(j).locwavcurve = locallab.spots.at(j).locwavcurve && pSpot.locwavcurve == otherSpot.locwavcurve; + locallab.spots.at(j).csthreshold = locallab.spots.at(j).csthreshold && pSpot.csthreshold == otherSpot.csthreshold; + locallab.spots.at(j).loclevwavcurve = locallab.spots.at(j).loclevwavcurve && pSpot.loclevwavcurve == otherSpot.loclevwavcurve; + locallab.spots.at(j).locconwavcurve = locallab.spots.at(j).locconwavcurve && pSpot.locconwavcurve == otherSpot.locconwavcurve; + locallab.spots.at(j).loccompwavcurve = locallab.spots.at(j).loccompwavcurve && pSpot.loccompwavcurve == otherSpot.loccompwavcurve; + locallab.spots.at(j).loccomprewavcurve = locallab.spots.at(j).loccomprewavcurve && pSpot.loccomprewavcurve == otherSpot.loccomprewavcurve; + locallab.spots.at(j).locedgwavcurve = locallab.spots.at(j).locedgwavcurve && pSpot.locedgwavcurve == otherSpot.locedgwavcurve; + locallab.spots.at(j).CCmasklccurve = locallab.spots.at(j).CCmasklccurve && pSpot.CCmasklccurve == otherSpot.CCmasklccurve; + locallab.spots.at(j).LLmasklccurve = locallab.spots.at(j).LLmasklccurve && pSpot.LLmasklccurve == otherSpot.LLmasklccurve; + locallab.spots.at(j).HHmasklccurve = locallab.spots.at(j).HHmasklccurve && pSpot.HHmasklccurve == otherSpot.HHmasklccurve; + locallab.spots.at(j).enalcMask = locallab.spots.at(j).enalcMask && pSpot.enalcMask == otherSpot.enalcMask; + locallab.spots.at(j).blendmasklc = locallab.spots.at(j).blendmasklc && pSpot.blendmasklc == otherSpot.blendmasklc; + locallab.spots.at(j).radmasklc = locallab.spots.at(j).radmasklc && pSpot.radmaskcb == otherSpot.radmasklc; + locallab.spots.at(j).chromasklc = locallab.spots.at(j).chromasklc && pSpot.chromasklc == otherSpot.chromasklc; + locallab.spots.at(j).Lmasklccurve = locallab.spots.at(j).Lmasklccurve && pSpot.Lmasklccurve == otherSpot.Lmasklccurve; + // Contrast by detail levels + locallab.spots.at(j).visicbdl = locallab.spots.at(j).visicbdl && pSpot.visicbdl == otherSpot.visicbdl; + locallab.spots.at(j).expcbdl = locallab.spots.at(j).expcbdl && pSpot.expcbdl == otherSpot.expcbdl; + locallab.spots.at(j).complexcbdl = locallab.spots.at(j).complexcbdl && pSpot.complexcbdl == otherSpot.complexcbdl; + + for (int k = 0; k < 6; k++) { + locallab.spots.at(j).mult[k] = locallab.spots.at(j).mult[k] && pSpot.mult[k] == otherSpot.mult[k]; + } + + locallab.spots.at(j).chromacbdl = locallab.spots.at(j).chromacbdl && pSpot.chromacbdl == otherSpot.chromacbdl; + locallab.spots.at(j).threshold = locallab.spots.at(j).threshold && pSpot.threshold == otherSpot.threshold; + locallab.spots.at(j).sensicb = locallab.spots.at(j).sensicb && pSpot.sensicb == otherSpot.sensicb; + locallab.spots.at(j).clarityml = locallab.spots.at(j).clarityml && pSpot.clarityml == otherSpot.clarityml; + locallab.spots.at(j).contresid = locallab.spots.at(j).contresid && pSpot.contresid == otherSpot.contresid; + locallab.spots.at(j).blurcbdl = locallab.spots.at(j).blurcbdl && pSpot.blurcbdl == otherSpot.blurcbdl; + locallab.spots.at(j).softradiuscb = locallab.spots.at(j).softradiuscb && pSpot.softradiuscb == otherSpot.softradiuscb; + locallab.spots.at(j).enacbMask = locallab.spots.at(j).enacbMask && pSpot.enacbMask == otherSpot.enacbMask; + locallab.spots.at(j).CCmaskcbcurve = locallab.spots.at(j).CCmaskcbcurve && pSpot.CCmaskcbcurve == otherSpot.CCmaskcbcurve; + locallab.spots.at(j).LLmaskcbcurve = locallab.spots.at(j).LLmaskcbcurve && pSpot.LLmaskcbcurve == otherSpot.LLmaskcbcurve; + locallab.spots.at(j).HHmaskcbcurve = locallab.spots.at(j).HHmaskcbcurve && pSpot.HHmaskcbcurve == otherSpot.HHmaskcbcurve; + locallab.spots.at(j).blendmaskcb = locallab.spots.at(j).blendmaskcb && pSpot.blendmaskcb == otherSpot.blendmaskcb; + locallab.spots.at(j).radmaskcb = locallab.spots.at(j).radmaskcb && pSpot.radmaskcb == otherSpot.radmaskcb; + locallab.spots.at(j).chromaskcb = locallab.spots.at(j).chromaskcb && pSpot.chromaskcb == otherSpot.chromaskcb; + locallab.spots.at(j).gammaskcb = locallab.spots.at(j).gammaskcb && pSpot.gammaskcb == otherSpot.gammaskcb; + locallab.spots.at(j).slomaskcb = locallab.spots.at(j).slomaskcb && pSpot.slomaskcb == otherSpot.slomaskcb; + locallab.spots.at(j).lapmaskcb = locallab.spots.at(j).lapmaskcb && pSpot.lapmaskcb == otherSpot.lapmaskcb; + locallab.spots.at(j).Lmaskcbcurve = locallab.spots.at(j).Lmaskcbcurve && pSpot.Lmaskcbcurve == otherSpot.Lmaskcbcurve; + // Log encoding + locallab.spots.at(j).visilog = locallab.spots.at(j).visilog && pSpot.visilog == otherSpot.visilog; + locallab.spots.at(j).explog = locallab.spots.at(j).explog && pSpot.explog == otherSpot.explog; + locallab.spots.at(j).autocompute = locallab.spots.at(j).autocompute && pSpot.autocompute == otherSpot.autocompute; + locallab.spots.at(j).sourceGray = locallab.spots.at(j).sourceGray && pSpot.sourceGray == otherSpot.sourceGray; + locallab.spots.at(j).targetGray = locallab.spots.at(j).targetGray && pSpot.targetGray == otherSpot.targetGray; + locallab.spots.at(j).Autogray = locallab.spots.at(j).Autogray && pSpot.Autogray == otherSpot.Autogray; + locallab.spots.at(j).fullimage = locallab.spots.at(j).fullimage && pSpot.fullimage == otherSpot.fullimage; + locallab.spots.at(j).blackEv = locallab.spots.at(j).blackEv && pSpot.blackEv == otherSpot.blackEv; + locallab.spots.at(j).whiteEv = locallab.spots.at(j).whiteEv && pSpot.whiteEv == otherSpot.whiteEv; + locallab.spots.at(j).detail = locallab.spots.at(j).detail && pSpot.detail == otherSpot.detail; + locallab.spots.at(j).sensilog = locallab.spots.at(j).sensilog && pSpot.sensilog == otherSpot.sensilog; + locallab.spots.at(j).baselog = locallab.spots.at(j).baselog && pSpot.baselog == otherSpot.baselog; + locallab.spots.at(j).strlog = locallab.spots.at(j).strlog && pSpot.strlog == otherSpot.strlog; + locallab.spots.at(j).anglog = locallab.spots.at(j).anglog && pSpot.anglog == otherSpot.anglog; + } + } + + if (!isSpotNumberEqual) { + // All LocallabSpotEdited are set to false because cannot be combined + locallab.spots.clear(); + locallab.spots.resize(p.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(false)); + } + pcvignette.enabled = pcvignette.enabled && p.pcvignette.enabled == other.pcvignette.enabled; pcvignette.strength = pcvignette.strength && p.pcvignette.strength == other.pcvignette.strength; pcvignette.feather = pcvignette.feather && p.pcvignette.feather == other.pcvignette.feather; @@ -1112,6 +1613,12 @@ void ParamsEdited::initFrom(const std::vector& wavelet.strength = wavelet.strength && p.wavelet.strength == other.wavelet.strength; wavelet.balance = wavelet.balance && p.wavelet.balance == other.wavelet.balance; wavelet.iter = wavelet.iter && p.wavelet.iter == other.wavelet.iter; + wavelet.sigmafin = wavelet.sigmafin && p.wavelet.sigmafin == other.wavelet.sigmafin; + wavelet.sigmaton = wavelet.sigmaton && p.wavelet.sigmaton == other.wavelet.sigmaton; + wavelet.sigmacol = wavelet.sigmacol && p.wavelet.sigmacol == other.wavelet.sigmacol; + wavelet.sigmadir = wavelet.sigmadir && p.wavelet.sigmadir == other.wavelet.sigmadir; + wavelet.rangeab = wavelet.rangeab && p.wavelet.rangeab == other.wavelet.rangeab; + wavelet.protab = wavelet.protab && p.wavelet.protab == other.wavelet.protab; wavelet.median = wavelet.median && p.wavelet.median == other.wavelet.median; wavelet.medianlev = wavelet.medianlev && p.wavelet.medianlev == other.wavelet.medianlev; wavelet.linkedg = wavelet.linkedg && p.wavelet.linkedg == other.wavelet.linkedg; @@ -1197,6 +1704,7 @@ void ParamsEdited::initFrom(const std::vector& wavelet.satlev = wavelet.satlev && p.wavelet.satlev == other.wavelet.satlev; wavelet.ccwcurve = wavelet.ccwcurve && p.wavelet.ccwcurve == other.wavelet.ccwcurve; wavelet.blcurve = wavelet.blcurve && p.wavelet.blcurve == other.wavelet.blcurve; + wavelet.opacityCurveSH = wavelet.opacityCurveSH && p.wavelet.opacityCurveSH == other.wavelet.opacityCurveSH; wavelet.opacityCurveRG = wavelet.opacityCurveRG && p.wavelet.opacityCurveRG == other.wavelet.opacityCurveRG; wavelet.opacityCurveBY = wavelet.opacityCurveBY && p.wavelet.opacityCurveBY == other.wavelet.opacityCurveBY; wavelet.opacityCurveW = wavelet.opacityCurveW && p.wavelet.opacityCurveW == other.wavelet.opacityCurveW; @@ -1215,6 +1723,10 @@ void ParamsEdited::initFrom(const std::vector& wavelet.exptoning = wavelet.exptoning && p.wavelet.exptoning == other.wavelet.exptoning; wavelet.expnoise = wavelet.expnoise && p.wavelet.expnoise == other.wavelet.expnoise; wavelet.expclari = wavelet.expclari && p.wavelet.expclari == other.wavelet.expclari; + wavelet.labgridALow = wavelet.labgridALow && p.wavelet.labgridALow == other.wavelet.labgridALow; + wavelet.labgridBLow = wavelet.labgridBLow && p.wavelet.labgridBLow == other.wavelet.labgridBLow; + wavelet.labgridAHigh = wavelet.labgridAHigh && p.wavelet.labgridAHigh == other.wavelet.labgridAHigh; + wavelet.labgridBHigh = wavelet.labgridBHigh && p.wavelet.labgridBHigh == other.wavelet.labgridBHigh; for (int level = 0; level < 9; ++level) { wavelet.c[level] = wavelet.c[level] && p.wavelet.c[level] == other.wavelet.c[level]; @@ -1255,6 +1767,7 @@ void ParamsEdited::initFrom(const std::vector& filmNegative.baseValues = filmNegative.baseValues && p.filmNegative.redBase == other.filmNegative.redBase && p.filmNegative.greenBase == other.filmNegative.greenBase && p.filmNegative.blueBase == other.filmNegative.blueBase; + raw.preprocessWB.mode = raw.preprocessWB.mode && p.raw.preprocessWB.mode == other.raw.preprocessWB.mode; // How the hell can we handle that??? // exif = exif && p.exif==other.exif @@ -1709,7 +2222,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng if (colorToning.labregionsShowMask) { toEdit.colorToning.labregionsShowMask = mods.colorToning.labregionsShowMask; } - + if (sharpenEdge.enabled) { toEdit.sharpenEdge.enabled = mods.sharpenEdge.enabled; } @@ -2497,6 +3010,1779 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.gradient.centerY = dontforceSet && options.baBehav[ADDSET_GRADIENT_CENTER] ? toEdit.gradient.centerY + mods.gradient.centerY : mods.gradient.centerY; } + + if (locallab.enabled) { + toEdit.locallab.enabled = mods.locallab.enabled; + } + + if (locallab.selspot) { + toEdit.locallab.selspot = mods.locallab.selspot; + } + + // Resizing locallab spots vector according to pedited + toEdit.locallab.spots.resize(locallab.spots.size()); + + // Updating each locallab spot according to pedited + for (size_t i = 0; i < toEdit.locallab.spots.size() && i < mods.locallab.spots.size() && i < locallab.spots.size(); i++) { + // Control spot settings + if (locallab.spots.at(i).name) { + toEdit.locallab.spots.at(i).name = mods.locallab.spots.at(i).name; + } + + if (locallab.spots.at(i).isvisible) { + toEdit.locallab.spots.at(i).isvisible = mods.locallab.spots.at(i).isvisible; + } + + if (locallab.spots.at(i).shape) { + toEdit.locallab.spots.at(i).shape = mods.locallab.spots.at(i).shape; + } + + if (locallab.spots.at(i).spotMethod) { + toEdit.locallab.spots.at(i).spotMethod = mods.locallab.spots.at(i).spotMethod; + } + + if (locallab.spots.at(i).wavMethod) { + toEdit.locallab.spots.at(i).wavMethod = mods.locallab.spots.at(i).wavMethod; + } + + if (locallab.spots.at(i).sensiexclu) { + toEdit.locallab.spots.at(i).sensiexclu = mods.locallab.spots.at(i).sensiexclu; + } + + if (locallab.spots.at(i).structexclu) { + toEdit.locallab.spots.at(i).structexclu = mods.locallab.spots.at(i).structexclu; + } + + if (locallab.spots.at(i).struc) { + toEdit.locallab.spots.at(i).struc = mods.locallab.spots.at(i).struc; + } + + if (locallab.spots.at(i).shapeMethod) { + toEdit.locallab.spots.at(i).shapeMethod = mods.locallab.spots.at(i).shapeMethod; + } + + if (locallab.spots.at(i).loc) { + toEdit.locallab.spots.at(i).loc = mods.locallab.spots.at(i).loc; + } + + if (locallab.spots.at(i).centerX) { + toEdit.locallab.spots.at(i).centerX = mods.locallab.spots.at(i).centerX; + } + + if (locallab.spots.at(i).centerY) { + toEdit.locallab.spots.at(i).centerY = mods.locallab.spots.at(i).centerY; + } + + if (locallab.spots.at(i).circrad) { + toEdit.locallab.spots.at(i).circrad = mods.locallab.spots.at(i).circrad; + } + + if (locallab.spots.at(i).qualityMethod) { + toEdit.locallab.spots.at(i).qualityMethod = mods.locallab.spots.at(i).qualityMethod; + } + + if (locallab.spots.at(i).complexMethod) { + toEdit.locallab.spots.at(i).complexMethod = mods.locallab.spots.at(i).complexMethod; + } + + if (locallab.spots.at(i).transit) { + toEdit.locallab.spots.at(i).transit = mods.locallab.spots.at(i).transit; + } + + if (locallab.spots.at(i).feather) { + toEdit.locallab.spots.at(i).feather = mods.locallab.spots.at(i).feather; + } + + if (locallab.spots.at(i).thresh) { + toEdit.locallab.spots.at(i).thresh = mods.locallab.spots.at(i).thresh; + } + + if (locallab.spots.at(i).iter) { + toEdit.locallab.spots.at(i).iter = mods.locallab.spots.at(i).iter; + } + + if (locallab.spots.at(i).balan) { + toEdit.locallab.spots.at(i).balan = mods.locallab.spots.at(i).balan; + } + + if (locallab.spots.at(i).balanh) { + toEdit.locallab.spots.at(i).balanh = mods.locallab.spots.at(i).balanh; + } + + if (locallab.spots.at(i).colorde) { + toEdit.locallab.spots.at(i).colorde = mods.locallab.spots.at(i).colorde; + } + + if (locallab.spots.at(i).colorscope) { + toEdit.locallab.spots.at(i).colorscope = mods.locallab.spots.at(i).colorscope; + } + + if (locallab.spots.at(i).transitweak) { + toEdit.locallab.spots.at(i).transitweak = mods.locallab.spots.at(i).transitweak; + } + + if (locallab.spots.at(i).transitgrad) { + toEdit.locallab.spots.at(i).transitgrad = mods.locallab.spots.at(i).transitgrad; + } + + if (locallab.spots.at(i).avoid) { + toEdit.locallab.spots.at(i).avoid = mods.locallab.spots.at(i).avoid; + } + + if (locallab.spots.at(i).blwh) { + toEdit.locallab.spots.at(i).blwh = mods.locallab.spots.at(i).blwh; + } + + if (locallab.spots.at(i).recurs) { + toEdit.locallab.spots.at(i).recurs = mods.locallab.spots.at(i).recurs; + } + + if (locallab.spots.at(i).laplac) { + toEdit.locallab.spots.at(i).laplac = mods.locallab.spots.at(i).laplac; + } + + if (locallab.spots.at(i).deltae) { + toEdit.locallab.spots.at(i).deltae = mods.locallab.spots.at(i).deltae; + } + + if (locallab.spots.at(i).shortc) { + toEdit.locallab.spots.at(i).shortc = mods.locallab.spots.at(i).shortc; + } + + if (locallab.spots.at(i).savrest) { + toEdit.locallab.spots.at(i).savrest = mods.locallab.spots.at(i).savrest; + } + + if (locallab.spots.at(i).scopemask) { + toEdit.locallab.spots.at(i).scopemask = mods.locallab.spots.at(i).scopemask; + } + + if (locallab.spots.at(i).lumask) { + toEdit.locallab.spots.at(i).lumask = mods.locallab.spots.at(i).lumask; + } + + // Color & Light + if (locallab.spots.at(i).visicolor) { + toEdit.locallab.spots.at(i).visicolor = mods.locallab.spots.at(i).visicolor; + } + + if (locallab.spots.at(i).expcolor) { + toEdit.locallab.spots.at(i).expcolor = mods.locallab.spots.at(i).expcolor; + } + + if (locallab.spots.at(i).complexcolor) { + toEdit.locallab.spots.at(i).complexcolor = mods.locallab.spots.at(i).complexcolor; + } + + if (locallab.spots.at(i).curvactiv) { + toEdit.locallab.spots.at(i).curvactiv = mods.locallab.spots.at(i).curvactiv; + } + + if (locallab.spots.at(i).lightness) { + toEdit.locallab.spots.at(i).lightness = mods.locallab.spots.at(i).lightness; + } + + if (locallab.spots.at(i).contrast) { + toEdit.locallab.spots.at(i).contrast = mods.locallab.spots.at(i).contrast; + } + + if (locallab.spots.at(i).chroma) { + toEdit.locallab.spots.at(i).chroma = mods.locallab.spots.at(i).chroma; + } + + if (locallab.spots.at(i).labgridALow) { + toEdit.locallab.spots.at(i).labgridALow = mods.locallab.spots.at(i).labgridALow; + } + + if (locallab.spots.at(i).labgridBLow) { + toEdit.locallab.spots.at(i).labgridBLow = mods.locallab.spots.at(i).labgridBLow; + } + + if (locallab.spots.at(i).labgridAHigh) { + toEdit.locallab.spots.at(i).labgridAHigh = mods.locallab.spots.at(i).labgridAHigh; + } + + if (locallab.spots.at(i).labgridBHigh) { + toEdit.locallab.spots.at(i).labgridBHigh = mods.locallab.spots.at(i).labgridBHigh; + } + + if (locallab.spots.at(i).labgridALowmerg) { + toEdit.locallab.spots.at(i).labgridALowmerg = mods.locallab.spots.at(i).labgridALowmerg; + } + + if (locallab.spots.at(i).labgridBLowmerg) { + toEdit.locallab.spots.at(i).labgridBLowmerg = mods.locallab.spots.at(i).labgridBLowmerg; + } + + if (locallab.spots.at(i).labgridAHighmerg) { + toEdit.locallab.spots.at(i).labgridAHighmerg = mods.locallab.spots.at(i).labgridAHighmerg; + } + + if (locallab.spots.at(i).labgridBHighmerg) { + toEdit.locallab.spots.at(i).labgridBHighmerg = mods.locallab.spots.at(i).labgridBHighmerg; + } + + if (locallab.spots.at(i).strengthgrid) { + toEdit.locallab.spots.at(i).strengthgrid = mods.locallab.spots.at(i).strengthgrid; + } + + if (locallab.spots.at(i).sensi) { + toEdit.locallab.spots.at(i).sensi = mods.locallab.spots.at(i).sensi; + } + + if (locallab.spots.at(i).structcol) { + toEdit.locallab.spots.at(i).structcol = mods.locallab.spots.at(i).structcol; + } + + if (locallab.spots.at(i).strcol) { + toEdit.locallab.spots.at(i).strcol = mods.locallab.spots.at(i).strcol; + } + + if (locallab.spots.at(i).strcolab) { + toEdit.locallab.spots.at(i).strcolab = mods.locallab.spots.at(i).strcolab; + } + + if (locallab.spots.at(i).strcolh) { + toEdit.locallab.spots.at(i).strcolh = mods.locallab.spots.at(i).strcolh; + } + + if (locallab.spots.at(i).angcol) { + toEdit.locallab.spots.at(i).angcol = mods.locallab.spots.at(i).angcol; + } + + if (locallab.spots.at(i).blurcolde) { + toEdit.locallab.spots.at(i).blurcolde = mods.locallab.spots.at(i).blurcolde; + } + + if (locallab.spots.at(i).blurcol) { + toEdit.locallab.spots.at(i).blurcol = mods.locallab.spots.at(i).blurcol; + } + + if (locallab.spots.at(i).contcol) { + toEdit.locallab.spots.at(i).contcol = mods.locallab.spots.at(i).contcol; + } + + if (locallab.spots.at(i).blendmaskcol) { + toEdit.locallab.spots.at(i).blendmaskcol = mods.locallab.spots.at(i).blendmaskcol; + } + + if (locallab.spots.at(i).radmaskcol) { + toEdit.locallab.spots.at(i).radmaskcol = mods.locallab.spots.at(i).radmaskcol; + } + + if (locallab.spots.at(i).chromaskcol) { + toEdit.locallab.spots.at(i).chromaskcol = mods.locallab.spots.at(i).chromaskcol; + } + + if (locallab.spots.at(i).gammaskcol) { + toEdit.locallab.spots.at(i).gammaskcol = mods.locallab.spots.at(i).gammaskcol; + } + + if (locallab.spots.at(i).slomaskcol) { + toEdit.locallab.spots.at(i).slomaskcol = mods.locallab.spots.at(i).slomaskcol; + } + + if (locallab.spots.at(i).shadmaskcol) { + toEdit.locallab.spots.at(i).shadmaskcol = mods.locallab.spots.at(i).shadmaskcol; + } + + if (locallab.spots.at(i).strumaskcol) { + toEdit.locallab.spots.at(i).strumaskcol = mods.locallab.spots.at(i).strumaskcol; + } + + if (locallab.spots.at(i).lapmaskcol) { + toEdit.locallab.spots.at(i).lapmaskcol = mods.locallab.spots.at(i).lapmaskcol; + } + + if (locallab.spots.at(i).qualitycurveMethod) { + toEdit.locallab.spots.at(i).qualitycurveMethod = mods.locallab.spots.at(i).qualitycurveMethod; + } + + if (locallab.spots.at(i).gridMethod) { + toEdit.locallab.spots.at(i).gridMethod = mods.locallab.spots.at(i).gridMethod; + } + + if (locallab.spots.at(i).merMethod) { + toEdit.locallab.spots.at(i).merMethod = mods.locallab.spots.at(i).merMethod; + } + + if (locallab.spots.at(i).toneMethod) { + toEdit.locallab.spots.at(i).toneMethod = mods.locallab.spots.at(i).toneMethod; + } + + if (locallab.spots.at(i).mergecolMethod) { + toEdit.locallab.spots.at(i).mergecolMethod = mods.locallab.spots.at(i).mergecolMethod; + } + + if (locallab.spots.at(i).llcurve) { + toEdit.locallab.spots.at(i).llcurve = mods.locallab.spots.at(i).llcurve; + } + + if (locallab.spots.at(i).lccurve) { + toEdit.locallab.spots.at(i).lccurve = mods.locallab.spots.at(i).lccurve; + } + + if (locallab.spots.at(i).cccurve) { + toEdit.locallab.spots.at(i).cccurve = mods.locallab.spots.at(i).cccurve; + } + + if (locallab.spots.at(i).clcurve) { + toEdit.locallab.spots.at(i).clcurve = mods.locallab.spots.at(i).clcurve; + } + + if (locallab.spots.at(i).rgbcurve) { + toEdit.locallab.spots.at(i).rgbcurve = mods.locallab.spots.at(i).rgbcurve; + } + + if (locallab.spots.at(i).LHcurve) { + toEdit.locallab.spots.at(i).LHcurve = mods.locallab.spots.at(i).LHcurve; + } + + if (locallab.spots.at(i).HHcurve) { + toEdit.locallab.spots.at(i).HHcurve = mods.locallab.spots.at(i).HHcurve; + } + + if (locallab.spots.at(i).invers) { + toEdit.locallab.spots.at(i).invers = mods.locallab.spots.at(i).invers; + } + + if (locallab.spots.at(i).special) { + toEdit.locallab.spots.at(i).special = mods.locallab.spots.at(i).special; + } + + if (locallab.spots.at(i).toolcol) { + toEdit.locallab.spots.at(i).toolcol = mods.locallab.spots.at(i).toolcol; + } + + if (locallab.spots.at(i).enaColorMask) { + toEdit.locallab.spots.at(i).enaColorMask = mods.locallab.spots.at(i).enaColorMask; + } + + if (locallab.spots.at(i).fftColorMask) { + toEdit.locallab.spots.at(i).fftColorMask = mods.locallab.spots.at(i).fftColorMask; + } + + if (locallab.spots.at(i).CCmaskcurve) { + toEdit.locallab.spots.at(i).CCmaskcurve = mods.locallab.spots.at(i).CCmaskcurve; + } + + if (locallab.spots.at(i).LLmaskcurve) { + toEdit.locallab.spots.at(i).LLmaskcurve = mods.locallab.spots.at(i).LLmaskcurve; + } + + if (locallab.spots.at(i).HHmaskcurve) { + toEdit.locallab.spots.at(i).HHmaskcurve = mods.locallab.spots.at(i).HHmaskcurve; + } + + if (locallab.spots.at(i).HHhmaskcurve) { + toEdit.locallab.spots.at(i).HHhmaskcurve = mods.locallab.spots.at(i).HHhmaskcurve; + } + + if (locallab.spots.at(i).softradiuscol) { + toEdit.locallab.spots.at(i).softradiuscol = mods.locallab.spots.at(i).softradiuscol; + } + + if (locallab.spots.at(i).opacol) { + toEdit.locallab.spots.at(i).opacol = mods.locallab.spots.at(i).opacol; + } + + if (locallab.spots.at(i).mercol) { + toEdit.locallab.spots.at(i).mercol = mods.locallab.spots.at(i).mercol; + } + + if (locallab.spots.at(i).merlucol) { + toEdit.locallab.spots.at(i).merlucol = mods.locallab.spots.at(i).merlucol; + } + + if (locallab.spots.at(i).conthrcol) { + toEdit.locallab.spots.at(i).conthrcol = mods.locallab.spots.at(i).conthrcol; + } + + if (locallab.spots.at(i).Lmaskcurve) { + toEdit.locallab.spots.at(i).Lmaskcurve = mods.locallab.spots.at(i).Lmaskcurve; + } + + if (locallab.spots.at(i).LLmaskcolcurvewav) { + toEdit.locallab.spots.at(i).LLmaskcolcurvewav = mods.locallab.spots.at(i).LLmaskcolcurvewav; + } + + if (locallab.spots.at(i).csthresholdcol) { + toEdit.locallab.spots.at(i).csthresholdcol = mods.locallab.spots.at(i).csthresholdcol; + } + + // Exposure + if (locallab.spots.at(i).visiexpose) { + toEdit.locallab.spots.at(i).visiexpose = mods.locallab.spots.at(i).visiexpose; + } + + if (locallab.spots.at(i).expexpose) { + toEdit.locallab.spots.at(i).expexpose = mods.locallab.spots.at(i).expexpose; + } + + if (locallab.spots.at(i).complexexpose) { + toEdit.locallab.spots.at(i).complexexpose = mods.locallab.spots.at(i).complexexpose; + } + + if (locallab.spots.at(i).expcomp) { + toEdit.locallab.spots.at(i).expcomp = mods.locallab.spots.at(i).expcomp; + } + + if (locallab.spots.at(i).hlcompr) { + toEdit.locallab.spots.at(i).hlcompr = mods.locallab.spots.at(i).hlcompr; + } + + if (locallab.spots.at(i).hlcomprthresh) { + toEdit.locallab.spots.at(i).hlcomprthresh = mods.locallab.spots.at(i).hlcomprthresh; + } + + if (locallab.spots.at(i).black) { + toEdit.locallab.spots.at(i).black = mods.locallab.spots.at(i).black; + } + + if (locallab.spots.at(i).shadex) { + toEdit.locallab.spots.at(i).shadex = mods.locallab.spots.at(i).shadex; + } + + if (locallab.spots.at(i).shcompr) { + toEdit.locallab.spots.at(i).shcompr = mods.locallab.spots.at(i).shcompr; + } + + if (locallab.spots.at(i).expchroma) { + toEdit.locallab.spots.at(i).expchroma = mods.locallab.spots.at(i).expchroma; + } + + if (locallab.spots.at(i).sensiex) { + toEdit.locallab.spots.at(i).sensiex = mods.locallab.spots.at(i).sensiex; + } + + if (locallab.spots.at(i).structexp) { + toEdit.locallab.spots.at(i).structexp = mods.locallab.spots.at(i).structexp; + } + + if (locallab.spots.at(i).blurexpde) { + toEdit.locallab.spots.at(i).blurexpde = mods.locallab.spots.at(i).blurexpde; + } + + if (locallab.spots.at(i).strexp) { + toEdit.locallab.spots.at(i).strexp = mods.locallab.spots.at(i).strexp; + } + + if (locallab.spots.at(i).angexp) { + toEdit.locallab.spots.at(i).angexp = mods.locallab.spots.at(i).angexp; + } + + if (locallab.spots.at(i).excurve) { + toEdit.locallab.spots.at(i).excurve = mods.locallab.spots.at(i).excurve; + } + + if (locallab.spots.at(i).inversex) { + toEdit.locallab.spots.at(i).inversex = mods.locallab.spots.at(i).inversex; + } + + if (locallab.spots.at(i).enaExpMask) { + toEdit.locallab.spots.at(i).enaExpMask = mods.locallab.spots.at(i).enaExpMask; + } + + if (locallab.spots.at(i).enaExpMaskaft) { + toEdit.locallab.spots.at(i).enaExpMaskaft = mods.locallab.spots.at(i).enaExpMaskaft; + } + + if (locallab.spots.at(i).CCmaskexpcurve) { + toEdit.locallab.spots.at(i).CCmaskexpcurve = mods.locallab.spots.at(i).CCmaskexpcurve; + } + + if (locallab.spots.at(i).LLmaskexpcurve) { + toEdit.locallab.spots.at(i).LLmaskexpcurve = mods.locallab.spots.at(i).LLmaskexpcurve; + } + + if (locallab.spots.at(i).HHmaskexpcurve) { + toEdit.locallab.spots.at(i).HHmaskexpcurve = mods.locallab.spots.at(i).HHmaskexpcurve; + } + + if (locallab.spots.at(i).blendmaskexp) { + toEdit.locallab.spots.at(i).blendmaskexp = mods.locallab.spots.at(i).blendmaskexp; + } + + if (locallab.spots.at(i).radmaskexp) { + toEdit.locallab.spots.at(i).radmaskexp = mods.locallab.spots.at(i).radmaskexp; + } + + if (locallab.spots.at(i).chromaskexp) { + toEdit.locallab.spots.at(i).chromaskexp = mods.locallab.spots.at(i).chromaskexp; + } + + if (locallab.spots.at(i).gammaskexp) { + toEdit.locallab.spots.at(i).gammaskexp = mods.locallab.spots.at(i).gammaskexp; + } + + if (locallab.spots.at(i).slomaskexp) { + toEdit.locallab.spots.at(i).slomaskexp = mods.locallab.spots.at(i).slomaskexp; + } + + if (locallab.spots.at(i).lapmaskexp) { + toEdit.locallab.spots.at(i).lapmaskexp = mods.locallab.spots.at(i).lapmaskexp; + } + + if (locallab.spots.at(i).strmaskexp) { + toEdit.locallab.spots.at(i).strmaskexp = mods.locallab.spots.at(i).strmaskexp; + } + + if (locallab.spots.at(i).angmaskexp) { + toEdit.locallab.spots.at(i).angmaskexp = mods.locallab.spots.at(i).angmaskexp; + } + + if (locallab.spots.at(i).softradiusexp) { + toEdit.locallab.spots.at(i).softradiusexp = mods.locallab.spots.at(i).softradiusexp; + } + + if (locallab.spots.at(i).Lmaskexpcurve) { + toEdit.locallab.spots.at(i).Lmaskexpcurve = mods.locallab.spots.at(i).Lmaskexpcurve; + } + + if (locallab.spots.at(i).expMethod) { + toEdit.locallab.spots.at(i).expMethod = mods.locallab.spots.at(i).expMethod; + } + + if (locallab.spots.at(i).exnoiseMethod) { + toEdit.locallab.spots.at(i).exnoiseMethod = mods.locallab.spots.at(i).exnoiseMethod; + } + + if (locallab.spots.at(i).laplacexp) { + toEdit.locallab.spots.at(i).laplacexp = mods.locallab.spots.at(i).laplacexp; + } + + if (locallab.spots.at(i).balanexp) { + toEdit.locallab.spots.at(i).balanexp = mods.locallab.spots.at(i).balanexp; + } + + if (locallab.spots.at(i).linear) { + toEdit.locallab.spots.at(i).linear = mods.locallab.spots.at(i).linear; + } + + if (locallab.spots.at(i).gamm) { + toEdit.locallab.spots.at(i).gamm = mods.locallab.spots.at(i).gamm; + } + + if (locallab.spots.at(i).fatamount) { + toEdit.locallab.spots.at(i).fatamount = mods.locallab.spots.at(i).fatamount; + } + + if (locallab.spots.at(i).fatdetail) { + toEdit.locallab.spots.at(i).fatdetail = mods.locallab.spots.at(i).fatdetail; + } + + if (locallab.spots.at(i).fatanchor) { + toEdit.locallab.spots.at(i).fatanchor = mods.locallab.spots.at(i).fatanchor; + } + + if (locallab.spots.at(i).fatlevel) { + toEdit.locallab.spots.at(i).fatlevel = mods.locallab.spots.at(i).fatlevel; + } + + // Shadow highlight + if (locallab.spots.at(i).visishadhigh) { + toEdit.locallab.spots.at(i).visishadhigh = mods.locallab.spots.at(i).visishadhigh; + } + + if (locallab.spots.at(i).expshadhigh) { + toEdit.locallab.spots.at(i).expshadhigh = mods.locallab.spots.at(i).expshadhigh; + } + + if (locallab.spots.at(i).complexshadhigh) { + toEdit.locallab.spots.at(i).complexshadhigh = mods.locallab.spots.at(i).complexshadhigh; + } + + if (locallab.spots.at(i).shMethod) { + toEdit.locallab.spots.at(i).shMethod = mods.locallab.spots.at(i).shMethod; + } + + for (int j = 0; j < 5; j++) { + if (locallab.spots.at(i).multsh[j]) { + toEdit.locallab.spots.at(i).multsh[j] = mods.locallab.spots.at(i).multsh[j]; + } + } + + if (locallab.spots.at(i).highlights) { + toEdit.locallab.spots.at(i).highlights = mods.locallab.spots.at(i).highlights; + } + + if (locallab.spots.at(i).h_tonalwidth) { + toEdit.locallab.spots.at(i).h_tonalwidth = mods.locallab.spots.at(i).h_tonalwidth; + } + + if (locallab.spots.at(i).shadows) { + toEdit.locallab.spots.at(i).shadows = mods.locallab.spots.at(i).shadows; + } + + if (locallab.spots.at(i).s_tonalwidth) { + toEdit.locallab.spots.at(i).s_tonalwidth = mods.locallab.spots.at(i).s_tonalwidth; + } + + if (locallab.spots.at(i).sh_radius) { + toEdit.locallab.spots.at(i).sh_radius = mods.locallab.spots.at(i).sh_radius; + } + + if (locallab.spots.at(i).sensihs) { + toEdit.locallab.spots.at(i).sensihs = mods.locallab.spots.at(i).sensihs; + } + + if (locallab.spots.at(i).enaSHMask) { + toEdit.locallab.spots.at(i).enaSHMask = mods.locallab.spots.at(i).enaSHMask; + } + + if (locallab.spots.at(i).CCmaskSHcurve) { + toEdit.locallab.spots.at(i).CCmaskSHcurve = mods.locallab.spots.at(i).CCmaskSHcurve; + } + + if (locallab.spots.at(i).LLmaskSHcurve) { + toEdit.locallab.spots.at(i).LLmaskSHcurve = mods.locallab.spots.at(i).LLmaskSHcurve; + } + + if (locallab.spots.at(i).HHmaskSHcurve) { + toEdit.locallab.spots.at(i).HHmaskSHcurve = mods.locallab.spots.at(i).HHmaskSHcurve; + } + + if (locallab.spots.at(i).blendmaskSH) { + toEdit.locallab.spots.at(i).blendmaskSH = mods.locallab.spots.at(i).blendmaskSH; + } + + if (locallab.spots.at(i).radmaskSH) { + toEdit.locallab.spots.at(i).radmaskSH = mods.locallab.spots.at(i).radmaskSH; + } + + if (locallab.spots.at(i).blurSHde) { + toEdit.locallab.spots.at(i).blurSHde = mods.locallab.spots.at(i).blurSHde; + } + + if (locallab.spots.at(i).strSH) { + toEdit.locallab.spots.at(i).strSH = mods.locallab.spots.at(i).strSH; + } + + if (locallab.spots.at(i).angSH) { + toEdit.locallab.spots.at(i).angSH = mods.locallab.spots.at(i).angSH; + } + + if (locallab.spots.at(i).inverssh) { + toEdit.locallab.spots.at(i).inverssh = mods.locallab.spots.at(i).inverssh; + } + + if (locallab.spots.at(i).chromaskSH) { + toEdit.locallab.spots.at(i).chromaskSH = mods.locallab.spots.at(i).chromaskSH; + } + + if (locallab.spots.at(i).gammaskSH) { + toEdit.locallab.spots.at(i).gammaskSH = mods.locallab.spots.at(i).gammaskSH; + } + + if (locallab.spots.at(i).slomaskSH) { + toEdit.locallab.spots.at(i).slomaskSH = mods.locallab.spots.at(i).slomaskSH; + } + + if (locallab.spots.at(i).lapmaskSH) { + toEdit.locallab.spots.at(i).lapmaskSH = mods.locallab.spots.at(i).lapmaskSH; + } + + if (locallab.spots.at(i).detailSH) { + toEdit.locallab.spots.at(i).detailSH = mods.locallab.spots.at(i).detailSH; + } + + if (locallab.spots.at(i).LmaskSHcurve) { + toEdit.locallab.spots.at(i).LmaskSHcurve = mods.locallab.spots.at(i).LmaskSHcurve; + } + + if (locallab.spots.at(i).fatamountSH) { + toEdit.locallab.spots.at(i).fatamountSH = mods.locallab.spots.at(i).fatamountSH; + } + + if (locallab.spots.at(i).fatanchorSH) { + toEdit.locallab.spots.at(i).fatanchorSH = mods.locallab.spots.at(i).fatanchorSH; + } + + if (locallab.spots.at(i).gamSH) { + toEdit.locallab.spots.at(i).gamSH = mods.locallab.spots.at(i).gamSH; + } + + if (locallab.spots.at(i).sloSH) { + toEdit.locallab.spots.at(i).sloSH = mods.locallab.spots.at(i).sloSH; + } + + // Vibrance + if (locallab.spots.at(i).visivibrance) { + toEdit.locallab.spots.at(i).visivibrance = mods.locallab.spots.at(i).visivibrance; + } + + if (locallab.spots.at(i).expvibrance) { + toEdit.locallab.spots.at(i).expvibrance = mods.locallab.spots.at(i).expvibrance; + } + + if (locallab.spots.at(i).complexvibrance) { + toEdit.locallab.spots.at(i).complexvibrance = mods.locallab.spots.at(i).complexvibrance; + } + + if (locallab.spots.at(i).saturated) { + toEdit.locallab.spots.at(i).saturated = mods.locallab.spots.at(i).saturated; + } + + if (locallab.spots.at(i).pastels) { + toEdit.locallab.spots.at(i).pastels = mods.locallab.spots.at(i).pastels; + } + + if (locallab.spots.at(i).warm) { + toEdit.locallab.spots.at(i).warm = mods.locallab.spots.at(i).warm; + } + + if (locallab.spots.at(i).psthreshold) { + toEdit.locallab.spots.at(i).psthreshold = mods.locallab.spots.at(i).psthreshold; + } + + if (locallab.spots.at(i).protectskins) { + toEdit.locallab.spots.at(i).protectskins = mods.locallab.spots.at(i).protectskins; + } + + if (locallab.spots.at(i).avoidcolorshift) { + toEdit.locallab.spots.at(i).avoidcolorshift = mods.locallab.spots.at(i).avoidcolorshift; + } + + if (locallab.spots.at(i).pastsattog) { + toEdit.locallab.spots.at(i).pastsattog = mods.locallab.spots.at(i).pastsattog; + } + + if (locallab.spots.at(i).sensiv) { + toEdit.locallab.spots.at(i).sensiv = mods.locallab.spots.at(i).sensiv; + } + + if (locallab.spots.at(i).skintonescurve) { + toEdit.locallab.spots.at(i).skintonescurve = mods.locallab.spots.at(i).skintonescurve; + } + + if (locallab.spots.at(i).CCmaskvibcurve) { + toEdit.locallab.spots.at(i).CCmaskvibcurve = mods.locallab.spots.at(i).CCmaskvibcurve; + } + + if (locallab.spots.at(i).LLmaskvibcurve) { + toEdit.locallab.spots.at(i).LLmaskvibcurve = mods.locallab.spots.at(i).LLmaskvibcurve; + } + + if (locallab.spots.at(i).HHmaskvibcurve) { + toEdit.locallab.spots.at(i).HHmaskvibcurve = mods.locallab.spots.at(i).HHmaskvibcurve; + } + + if (locallab.spots.at(i).enavibMask) { + toEdit.locallab.spots.at(i).enavibMask = mods.locallab.spots.at(i).enavibMask; + } + + if (locallab.spots.at(i).blendmaskvib) { + toEdit.locallab.spots.at(i).blendmaskvib = mods.locallab.spots.at(i).blendmaskvib; + } + + if (locallab.spots.at(i).radmaskvib) { + toEdit.locallab.spots.at(i).radmaskvib = mods.locallab.spots.at(i).radmaskvib; + } + + if (locallab.spots.at(i).chromaskvib) { + toEdit.locallab.spots.at(i).chromaskvib = mods.locallab.spots.at(i).chromaskvib; + } + + if (locallab.spots.at(i).gammaskvib) { + toEdit.locallab.spots.at(i).gammaskvib = mods.locallab.spots.at(i).gammaskvib; + } + + if (locallab.spots.at(i).slomaskvib) { + toEdit.locallab.spots.at(i).slomaskvib = mods.locallab.spots.at(i).slomaskvib; + } + + if (locallab.spots.at(i).lapmaskvib) { + toEdit.locallab.spots.at(i).lapmaskvib = mods.locallab.spots.at(i).lapmaskvib; + } + + if (locallab.spots.at(i).strvib) { + toEdit.locallab.spots.at(i).strvib = mods.locallab.spots.at(i).strvib; + } + + if (locallab.spots.at(i).strvibab) { + toEdit.locallab.spots.at(i).strvibab = mods.locallab.spots.at(i).strvibab; + } + + if (locallab.spots.at(i).strvibh) { + toEdit.locallab.spots.at(i).strvibh = mods.locallab.spots.at(i).strvibh; + } + + if (locallab.spots.at(i).angvib) { + toEdit.locallab.spots.at(i).angvib = mods.locallab.spots.at(i).angvib; + } + + if (locallab.spots.at(i).Lmaskvibcurve) { + toEdit.locallab.spots.at(i).Lmaskvibcurve = mods.locallab.spots.at(i).Lmaskvibcurve; + } + + // Soft Light + if (locallab.spots.at(i).visisoft) { + toEdit.locallab.spots.at(i).visisoft = mods.locallab.spots.at(i).visisoft; + } + + if (locallab.spots.at(i).expsoft) { + toEdit.locallab.spots.at(i).expsoft = mods.locallab.spots.at(i).expsoft; + } + + if (locallab.spots.at(i).complexsoft) { + toEdit.locallab.spots.at(i).complexsoft = mods.locallab.spots.at(i).complexsoft; + } + + if (locallab.spots.at(i).streng) { + toEdit.locallab.spots.at(i).streng = mods.locallab.spots.at(i).streng; + } + + if (locallab.spots.at(i).sensisf) { + toEdit.locallab.spots.at(i).sensisf = mods.locallab.spots.at(i).sensisf; + } + + if (locallab.spots.at(i).laplace) { + toEdit.locallab.spots.at(i).laplace = mods.locallab.spots.at(i).laplace; + } + + if (locallab.spots.at(i).softMethod) { + toEdit.locallab.spots.at(i).softMethod = mods.locallab.spots.at(i).softMethod; + } + + // Blur & Noise + if (locallab.spots.at(i).visiblur) { + toEdit.locallab.spots.at(i).visiblur = mods.locallab.spots.at(i).visiblur; + } + + if (locallab.spots.at(i).expblur) { + toEdit.locallab.spots.at(i).expblur = mods.locallab.spots.at(i).expblur; + } + + if (locallab.spots.at(i).complexblur) { + toEdit.locallab.spots.at(i).complexblur = mods.locallab.spots.at(i).complexblur; + } + + if (locallab.spots.at(i).radius) { + toEdit.locallab.spots.at(i).radius = mods.locallab.spots.at(i).radius; + } + + if (locallab.spots.at(i).strength) { + toEdit.locallab.spots.at(i).strength = mods.locallab.spots.at(i).strength; + } + + if (locallab.spots.at(i).sensibn) { + toEdit.locallab.spots.at(i).sensibn = mods.locallab.spots.at(i).sensibn; + } + + if (locallab.spots.at(i).itera) { + toEdit.locallab.spots.at(i).itera = mods.locallab.spots.at(i).itera; + } + + if (locallab.spots.at(i).guidbl) { + toEdit.locallab.spots.at(i).guidbl = mods.locallab.spots.at(i).guidbl; + } + + if (locallab.spots.at(i).strbl) { + toEdit.locallab.spots.at(i).strbl = mods.locallab.spots.at(i).strbl; + } + + if (locallab.spots.at(i).isogr) { + toEdit.locallab.spots.at(i).isogr = mods.locallab.spots.at(i).isogr; + } + + if (locallab.spots.at(i).strengr) { + toEdit.locallab.spots.at(i).strengr = mods.locallab.spots.at(i).strengr; + } + + if (locallab.spots.at(i).scalegr) { + toEdit.locallab.spots.at(i).scalegr = mods.locallab.spots.at(i).scalegr; + } + + if (locallab.spots.at(i).epsbl) { + toEdit.locallab.spots.at(i).epsbl = mods.locallab.spots.at(i).epsbl; + } + + if (locallab.spots.at(i).blMethod) { + toEdit.locallab.spots.at(i).blMethod = mods.locallab.spots.at(i).blMethod; + } + + if (locallab.spots.at(i).chroMethod) { + toEdit.locallab.spots.at(i).chroMethod = mods.locallab.spots.at(i).chroMethod; + } + + if (locallab.spots.at(i).blurMethod) { + toEdit.locallab.spots.at(i).blurMethod = mods.locallab.spots.at(i).blurMethod; + } + + if (locallab.spots.at(i).medMethod) { + toEdit.locallab.spots.at(i).medMethod = mods.locallab.spots.at(i).medMethod; + } + + if (locallab.spots.at(i).activlum) { + toEdit.locallab.spots.at(i).activlum = mods.locallab.spots.at(i).activlum; + } + + if (locallab.spots.at(i).noiselumf) { + toEdit.locallab.spots.at(i).noiselumf = mods.locallab.spots.at(i).noiselumf; + } + + if (locallab.spots.at(i).noiselumf0) { + toEdit.locallab.spots.at(i).noiselumf0 = mods.locallab.spots.at(i).noiselumf0; + } + + if (locallab.spots.at(i).noiselumf2) { + toEdit.locallab.spots.at(i).noiselumf2 = mods.locallab.spots.at(i).noiselumf2; + } + + if (locallab.spots.at(i).noiselumc) { + toEdit.locallab.spots.at(i).noiselumc = mods.locallab.spots.at(i).noiselumc; + } + + if (locallab.spots.at(i).noiselumdetail) { + toEdit.locallab.spots.at(i).noiselumdetail = mods.locallab.spots.at(i).noiselumdetail; + } + + if (locallab.spots.at(i).noiselequal) { + toEdit.locallab.spots.at(i).noiselequal = mods.locallab.spots.at(i).noiselequal; + } + + if (locallab.spots.at(i).noisechrof) { + toEdit.locallab.spots.at(i).noisechrof = mods.locallab.spots.at(i).noisechrof; + } + + if (locallab.spots.at(i).noisechroc) { + toEdit.locallab.spots.at(i).noisechroc = mods.locallab.spots.at(i).noisechroc; + } + + if (locallab.spots.at(i).noisechrodetail) { + toEdit.locallab.spots.at(i).noisechrodetail = mods.locallab.spots.at(i).noisechrodetail; + } + + if (locallab.spots.at(i).adjblur) { + toEdit.locallab.spots.at(i).adjblur = mods.locallab.spots.at(i).adjblur; + } + + if (locallab.spots.at(i).bilateral) { + toEdit.locallab.spots.at(i).bilateral = mods.locallab.spots.at(i).bilateral; + } + + if (locallab.spots.at(i).sensiden) { + toEdit.locallab.spots.at(i).sensiden = mods.locallab.spots.at(i).sensiden; + } + + if (locallab.spots.at(i).detailthr) { + toEdit.locallab.spots.at(i).detailthr = mods.locallab.spots.at(i).detailthr; + } + + if (locallab.spots.at(i).locwavcurveden) { + toEdit.locallab.spots.at(i).locwavcurveden = mods.locallab.spots.at(i).locwavcurveden; + } + + if (locallab.spots.at(i).showmaskblMethodtyp) { + toEdit.locallab.spots.at(i).showmaskblMethodtyp = mods.locallab.spots.at(i).showmaskblMethodtyp; + } + + if (locallab.spots.at(i).CCmaskblcurve) { + toEdit.locallab.spots.at(i).CCmaskblcurve = mods.locallab.spots.at(i).CCmaskblcurve; + } + + if (locallab.spots.at(i).LLmaskblcurve) { + toEdit.locallab.spots.at(i).LLmaskblcurve = mods.locallab.spots.at(i).LLmaskblcurve; + } + + if (locallab.spots.at(i).HHmaskblcurve) { + toEdit.locallab.spots.at(i).HHmaskblcurve = mods.locallab.spots.at(i).HHmaskblcurve; + } + + if (locallab.spots.at(i).enablMask) { + toEdit.locallab.spots.at(i).enablMask = mods.locallab.spots.at(i).enablMask; + } + + if (locallab.spots.at(i).fftwbl) { + toEdit.locallab.spots.at(i).fftwbl = mods.locallab.spots.at(i).fftwbl; + } + + if (locallab.spots.at(i).toolbl) { + toEdit.locallab.spots.at(i).toolbl = mods.locallab.spots.at(i).toolbl; + } + + if (locallab.spots.at(i).blendmaskbl) { + toEdit.locallab.spots.at(i).blendmaskbl = mods.locallab.spots.at(i).blendmaskbl; + } + + if (locallab.spots.at(i).radmaskbl) { + toEdit.locallab.spots.at(i).radmaskbl = mods.locallab.spots.at(i).radmaskbl; + } + + if (locallab.spots.at(i).chromaskbl) { + toEdit.locallab.spots.at(i).chromaskbl = mods.locallab.spots.at(i).chromaskbl; + } + + if (locallab.spots.at(i).gammaskbl) { + toEdit.locallab.spots.at(i).gammaskbl = mods.locallab.spots.at(i).gammaskbl; + } + + if (locallab.spots.at(i).slomaskbl) { + toEdit.locallab.spots.at(i).slomaskbl = mods.locallab.spots.at(i).slomaskbl; + } + + if (locallab.spots.at(i).lapmaskbl) { + toEdit.locallab.spots.at(i).lapmaskbl = mods.locallab.spots.at(i).lapmaskbl; + } + + if (locallab.spots.at(i).shadmaskbl) { + toEdit.locallab.spots.at(i).shadmaskbl = mods.locallab.spots.at(i).shadmaskbl; + } + + if (locallab.spots.at(i).shadmaskblsha) { + toEdit.locallab.spots.at(i).shadmaskblsha = mods.locallab.spots.at(i).shadmaskblsha; + } + + if (locallab.spots.at(i).strumaskbl) { + toEdit.locallab.spots.at(i).strumaskbl = mods.locallab.spots.at(i).strumaskbl; + } + + if (locallab.spots.at(i).Lmaskblcurve) { + toEdit.locallab.spots.at(i).Lmaskblcurve = mods.locallab.spots.at(i).Lmaskblcurve; + } + + if (locallab.spots.at(i).LLmaskblcurvewav) { + toEdit.locallab.spots.at(i).LLmaskblcurvewav = mods.locallab.spots.at(i).LLmaskblcurvewav; + } + + if (locallab.spots.at(i).csthresholdblur) { + toEdit.locallab.spots.at(i).csthresholdblur = mods.locallab.spots.at(i).csthresholdblur; + } + + // Tone Mapping + if (locallab.spots.at(i).visitonemap) { + toEdit.locallab.spots.at(i).visitonemap = mods.locallab.spots.at(i).visitonemap; + } + + if (locallab.spots.at(i).exptonemap) { + toEdit.locallab.spots.at(i).exptonemap = mods.locallab.spots.at(i).exptonemap; + } + + if (locallab.spots.at(i).complextonemap) { + toEdit.locallab.spots.at(i).complextonemap = mods.locallab.spots.at(i).complextonemap; + } + + if (locallab.spots.at(i).stren) { + toEdit.locallab.spots.at(i).stren = mods.locallab.spots.at(i).stren; + } + + if (locallab.spots.at(i).gamma) { + toEdit.locallab.spots.at(i).gamma = mods.locallab.spots.at(i).gamma; + } + + if (locallab.spots.at(i).estop) { + toEdit.locallab.spots.at(i).estop = mods.locallab.spots.at(i).estop; + } + + if (locallab.spots.at(i).scaltm) { + toEdit.locallab.spots.at(i).scaltm = mods.locallab.spots.at(i).scaltm; + } + + if (locallab.spots.at(i).rewei) { + toEdit.locallab.spots.at(i).rewei = mods.locallab.spots.at(i).rewei; + } + + if (locallab.spots.at(i).satur) { + toEdit.locallab.spots.at(i).satur = mods.locallab.spots.at(i).satur; + } + + if (locallab.spots.at(i).sensitm) { + toEdit.locallab.spots.at(i).sensitm = mods.locallab.spots.at(i).sensitm; + } + + if (locallab.spots.at(i).softradiustm) { + toEdit.locallab.spots.at(i).softradiustm = mods.locallab.spots.at(i).softradiustm; + } + + if (locallab.spots.at(i).amount) { + toEdit.locallab.spots.at(i).amount = mods.locallab.spots.at(i).amount; + } + + if (locallab.spots.at(i).equiltm) { + toEdit.locallab.spots.at(i).equiltm = mods.locallab.spots.at(i).equiltm; + } + + if (locallab.spots.at(i).CCmasktmcurve) { + toEdit.locallab.spots.at(i).CCmasktmcurve = mods.locallab.spots.at(i).CCmasktmcurve; + } + + if (locallab.spots.at(i).LLmasktmcurve) { + toEdit.locallab.spots.at(i).LLmasktmcurve = mods.locallab.spots.at(i).LLmasktmcurve; + } + + if (locallab.spots.at(i).HHmasktmcurve) { + toEdit.locallab.spots.at(i).HHmasktmcurve = mods.locallab.spots.at(i).HHmasktmcurve; + } + + if (locallab.spots.at(i).enatmMask) { + toEdit.locallab.spots.at(i).enatmMask = mods.locallab.spots.at(i).enatmMask; + } + + if (locallab.spots.at(i).enatmMaskaft) { + toEdit.locallab.spots.at(i).enatmMaskaft = mods.locallab.spots.at(i).enatmMaskaft; + } + + if (locallab.spots.at(i).blendmasktm) { + toEdit.locallab.spots.at(i).blendmasktm = mods.locallab.spots.at(i).blendmasktm; + } + + if (locallab.spots.at(i).radmasktm) { + toEdit.locallab.spots.at(i).radmasktm = mods.locallab.spots.at(i).radmasktm; + } + + if (locallab.spots.at(i).chromasktm) { + toEdit.locallab.spots.at(i).chromasktm = mods.locallab.spots.at(i).chromasktm; + } + + if (locallab.spots.at(i).gammasktm) { + toEdit.locallab.spots.at(i).gammasktm = mods.locallab.spots.at(i).gammasktm; + } + + if (locallab.spots.at(i).slomasktm) { + toEdit.locallab.spots.at(i).slomasktm = mods.locallab.spots.at(i).slomasktm; + } + + if (locallab.spots.at(i).lapmasktm) { + toEdit.locallab.spots.at(i).lapmasktm = mods.locallab.spots.at(i).lapmasktm; + } + + if (locallab.spots.at(i).Lmasktmcurve) { + toEdit.locallab.spots.at(i).Lmasktmcurve = mods.locallab.spots.at(i).Lmasktmcurve; + } + + // Retinex + if (locallab.spots.at(i).visireti) { + toEdit.locallab.spots.at(i).visireti = mods.locallab.spots.at(i).visireti; + } + + if (locallab.spots.at(i).expreti) { + toEdit.locallab.spots.at(i).expreti = mods.locallab.spots.at(i).expreti; + } + + if (locallab.spots.at(i).complexreti) { + toEdit.locallab.spots.at(i).complexreti = mods.locallab.spots.at(i).complexreti; + } + + if (locallab.spots.at(i).retinexMethod) { + toEdit.locallab.spots.at(i).retinexMethod = mods.locallab.spots.at(i).retinexMethod; + } + + if (locallab.spots.at(i).str) { + toEdit.locallab.spots.at(i).str = mods.locallab.spots.at(i).str; + } + + if (locallab.spots.at(i).chrrt) { + toEdit.locallab.spots.at(i).chrrt = mods.locallab.spots.at(i).chrrt; + } + + if (locallab.spots.at(i).neigh) { + toEdit.locallab.spots.at(i).neigh = mods.locallab.spots.at(i).neigh; + } + + if (locallab.spots.at(i).vart) { + toEdit.locallab.spots.at(i).vart = mods.locallab.spots.at(i).vart; + } + + if (locallab.spots.at(i).offs) { + toEdit.locallab.spots.at(i).offs = mods.locallab.spots.at(i).offs; + } + + if (locallab.spots.at(i).dehaz) { + toEdit.locallab.spots.at(i).dehaz = mods.locallab.spots.at(i).dehaz; + } + + if (locallab.spots.at(i).depth) { + toEdit.locallab.spots.at(i).depth = mods.locallab.spots.at(i).depth; + } + + if (locallab.spots.at(i).sensih) { + toEdit.locallab.spots.at(i).sensih = mods.locallab.spots.at(i).sensih; + } + + if (locallab.spots.at(i).localTgaincurve) { + toEdit.locallab.spots.at(i).localTgaincurve = mods.locallab.spots.at(i).localTgaincurve; + } + + if (locallab.spots.at(i).localTtranscurve) { + toEdit.locallab.spots.at(i).localTtranscurve = mods.locallab.spots.at(i).localTtranscurve; + } + + if (locallab.spots.at(i).inversret) { + toEdit.locallab.spots.at(i).inversret = mods.locallab.spots.at(i).inversret; + } + + if (locallab.spots.at(i).equilret) { + toEdit.locallab.spots.at(i).equilret = mods.locallab.spots.at(i).equilret; + } + + if (locallab.spots.at(i).loglin) { + toEdit.locallab.spots.at(i).loglin = mods.locallab.spots.at(i).loglin; + } + + if (locallab.spots.at(i).lumonly) { + toEdit.locallab.spots.at(i).lumonly = mods.locallab.spots.at(i).lumonly; + } + + if (locallab.spots.at(i).softradiusret) { + toEdit.locallab.spots.at(i).softradiusret = mods.locallab.spots.at(i).softradiusret; + } + + if (locallab.spots.at(i).CCmaskreticurve) { + toEdit.locallab.spots.at(i).CCmaskreticurve = mods.locallab.spots.at(i).CCmaskreticurve; + } + + if (locallab.spots.at(i).LLmaskreticurve) { + toEdit.locallab.spots.at(i).LLmaskreticurve = mods.locallab.spots.at(i).LLmaskreticurve; + } + + if (locallab.spots.at(i).HHmaskreticurve) { + toEdit.locallab.spots.at(i).HHmaskreticurve = mods.locallab.spots.at(i).HHmaskreticurve; + } + + if (locallab.spots.at(i).enaretiMask) { + toEdit.locallab.spots.at(i).enaretiMask = mods.locallab.spots.at(i).enaretiMask; + } + + if (locallab.spots.at(i).enaretiMasktmap) { + toEdit.locallab.spots.at(i).enaretiMasktmap = mods.locallab.spots.at(i).enaretiMasktmap; + } + + if (locallab.spots.at(i).blendmaskreti) { + toEdit.locallab.spots.at(i).blendmaskreti = mods.locallab.spots.at(i).blendmaskreti; + } + + if (locallab.spots.at(i).radmaskreti) { + toEdit.locallab.spots.at(i).radmaskreti = mods.locallab.spots.at(i).radmaskreti; + } + + if (locallab.spots.at(i).chromaskreti) { + toEdit.locallab.spots.at(i).chromaskreti = mods.locallab.spots.at(i).chromaskreti; + } + + if (locallab.spots.at(i).gammaskreti) { + toEdit.locallab.spots.at(i).gammaskreti = mods.locallab.spots.at(i).gammaskreti; + } + + if (locallab.spots.at(i).slomaskreti) { + toEdit.locallab.spots.at(i).slomaskreti = mods.locallab.spots.at(i).slomaskreti; + } + + if (locallab.spots.at(i).lapmaskreti) { + toEdit.locallab.spots.at(i).lapmaskreti = mods.locallab.spots.at(i).lapmaskreti; + } + + if (locallab.spots.at(i).scalereti) { + toEdit.locallab.spots.at(i).scalereti = mods.locallab.spots.at(i).scalereti; + } + + if (locallab.spots.at(i).darkness) { + toEdit.locallab.spots.at(i).darkness = mods.locallab.spots.at(i).darkness; + } + + if (locallab.spots.at(i).lightnessreti) { + toEdit.locallab.spots.at(i).lightnessreti = mods.locallab.spots.at(i).lightnessreti; + } + + if (locallab.spots.at(i).limd) { + toEdit.locallab.spots.at(i).limd = mods.locallab.spots.at(i).limd; + } + + if (locallab.spots.at(i).cliptm) { + toEdit.locallab.spots.at(i).cliptm = mods.locallab.spots.at(i).cliptm; + } + + if (locallab.spots.at(i).fftwreti) { + toEdit.locallab.spots.at(i).fftwreti = mods.locallab.spots.at(i).fftwreti; + } + + if (locallab.spots.at(i).Lmaskreticurve) { + toEdit.locallab.spots.at(i).Lmaskreticurve = mods.locallab.spots.at(i).Lmaskreticurve; + } + + // Sharpening + if (locallab.spots.at(i).visisharp) { + toEdit.locallab.spots.at(i).visisharp = mods.locallab.spots.at(i).visisharp; + } + + if (locallab.spots.at(i).expsharp) { + toEdit.locallab.spots.at(i).expsharp = mods.locallab.spots.at(i).expsharp; + } + + if (locallab.spots.at(i).complexsharp) { + toEdit.locallab.spots.at(i).complexsharp = mods.locallab.spots.at(i).complexsharp; + } + + if (locallab.spots.at(i).sharcontrast) { + toEdit.locallab.spots.at(i).sharcontrast = mods.locallab.spots.at(i).sharcontrast; + } + + if (locallab.spots.at(i).sharradius) { + toEdit.locallab.spots.at(i).sharradius = mods.locallab.spots.at(i).sharradius; + } + + if (locallab.spots.at(i).sharamount) { + toEdit.locallab.spots.at(i).sharamount = mods.locallab.spots.at(i).sharamount; + } + + if (locallab.spots.at(i).shardamping) { + toEdit.locallab.spots.at(i).shardamping = mods.locallab.spots.at(i).shardamping; + } + + if (locallab.spots.at(i).shariter) { + toEdit.locallab.spots.at(i).shariter = mods.locallab.spots.at(i).shariter; + } + + if (locallab.spots.at(i).sharblur) { + toEdit.locallab.spots.at(i).sharblur = mods.locallab.spots.at(i).sharblur; + } + + if (locallab.spots.at(i).sensisha) { + toEdit.locallab.spots.at(i).sensisha = mods.locallab.spots.at(i).sensisha; + } + + if (locallab.spots.at(i).inverssha) { + toEdit.locallab.spots.at(i).inverssha = mods.locallab.spots.at(i).inverssha; + } + + // Local Contrast + if (locallab.spots.at(i).visicontrast) { + toEdit.locallab.spots.at(i).visicontrast = mods.locallab.spots.at(i).visicontrast; + } + + if (locallab.spots.at(i).expcontrast) { + toEdit.locallab.spots.at(i).expcontrast = mods.locallab.spots.at(i).expcontrast; + } + + if (locallab.spots.at(i).complexcontrast) { + toEdit.locallab.spots.at(i).complexcontrast = mods.locallab.spots.at(i).complexcontrast; + } + + if (locallab.spots.at(i).lcradius) { + toEdit.locallab.spots.at(i).lcradius = mods.locallab.spots.at(i).lcradius; + } + + if (locallab.spots.at(i).lcamount) { + toEdit.locallab.spots.at(i).lcamount = mods.locallab.spots.at(i).lcamount; + } + + if (locallab.spots.at(i).lcdarkness) { + toEdit.locallab.spots.at(i).lcdarkness = mods.locallab.spots.at(i).lcdarkness; + } + + if (locallab.spots.at(i).lclightness) { + toEdit.locallab.spots.at(i).lclightness = mods.locallab.spots.at(i).lclightness; + } + + if (locallab.spots.at(i).sigmalc) { + toEdit.locallab.spots.at(i).sigmalc = mods.locallab.spots.at(i).sigmalc; + } + + if (locallab.spots.at(i).levelwav) { + toEdit.locallab.spots.at(i).levelwav = mods.locallab.spots.at(i).levelwav; + } + + if (locallab.spots.at(i).residcont) { + toEdit.locallab.spots.at(i).residcont = mods.locallab.spots.at(i).residcont; + } + + if (locallab.spots.at(i).residsha) { + toEdit.locallab.spots.at(i).residsha = mods.locallab.spots.at(i).residsha; + } + + if (locallab.spots.at(i).residshathr) { + toEdit.locallab.spots.at(i).residshathr = mods.locallab.spots.at(i).residshathr; + } + + if (locallab.spots.at(i).residhi) { + toEdit.locallab.spots.at(i).residhi = mods.locallab.spots.at(i).residhi; + } + + if (locallab.spots.at(i).residhithr) { + toEdit.locallab.spots.at(i).residhithr = mods.locallab.spots.at(i).residhithr; + } + + if (locallab.spots.at(i).residblur) { + toEdit.locallab.spots.at(i).residblur = mods.locallab.spots.at(i).residblur; + } + + if (locallab.spots.at(i).levelblur) { + toEdit.locallab.spots.at(i).levelblur = mods.locallab.spots.at(i).levelblur; + } + + if (locallab.spots.at(i).sigmabl) { + toEdit.locallab.spots.at(i).sigmabl = mods.locallab.spots.at(i).sigmabl; + } + + if (locallab.spots.at(i).residchro) { + toEdit.locallab.spots.at(i).residchro = mods.locallab.spots.at(i).residchro; + } + + if (locallab.spots.at(i).residcomp) { + toEdit.locallab.spots.at(i).residcomp = mods.locallab.spots.at(i).residcomp; + } + + + if (locallab.spots.at(i).sigma) { + toEdit.locallab.spots.at(i).sigma = mods.locallab.spots.at(i).sigma; + } + + if (locallab.spots.at(i).offset) { + toEdit.locallab.spots.at(i).offset = mods.locallab.spots.at(i).offset; + } + + if (locallab.spots.at(i).sigmadr) { + toEdit.locallab.spots.at(i).sigmadr = mods.locallab.spots.at(i).sigmadr; + } + + if (locallab.spots.at(i).threswav) { + toEdit.locallab.spots.at(i).threswav = mods.locallab.spots.at(i).threswav; + } + + if (locallab.spots.at(i).chromalev) { + toEdit.locallab.spots.at(i).chromalev = mods.locallab.spots.at(i).chromalev; + } + + if (locallab.spots.at(i).chromablu) { + toEdit.locallab.spots.at(i).chromablu = mods.locallab.spots.at(i).chromablu; + } + + if (locallab.spots.at(i).sigmadc) { + toEdit.locallab.spots.at(i).sigmadc = mods.locallab.spots.at(i).sigmadc; + } + + if (locallab.spots.at(i).deltad) { + toEdit.locallab.spots.at(i).deltad = mods.locallab.spots.at(i).deltad; + } + + if (locallab.spots.at(i).fatres) { + toEdit.locallab.spots.at(i).fatres = mods.locallab.spots.at(i).fatres; + } + + if (locallab.spots.at(i).clarilres) { + toEdit.locallab.spots.at(i).clarilres = mods.locallab.spots.at(i).clarilres; + } + + if (locallab.spots.at(i).claricres) { + toEdit.locallab.spots.at(i).claricres = mods.locallab.spots.at(i).claricres; + } + + if (locallab.spots.at(i).clarisoft) { + toEdit.locallab.spots.at(i).clarisoft = mods.locallab.spots.at(i).clarisoft; + } + + if (locallab.spots.at(i).sigmalc2) { + toEdit.locallab.spots.at(i).sigmalc2 = mods.locallab.spots.at(i).sigmalc2; + } + + if (locallab.spots.at(i).strwav) { + toEdit.locallab.spots.at(i).strwav = mods.locallab.spots.at(i).strwav; + } + + if (locallab.spots.at(i).angwav) { + toEdit.locallab.spots.at(i).angwav = mods.locallab.spots.at(i).angwav; + } + + if (locallab.spots.at(i).strengthw) { + toEdit.locallab.spots.at(i).strengthw = mods.locallab.spots.at(i).strengthw; + } + + if (locallab.spots.at(i).sigmaed) { + toEdit.locallab.spots.at(i).sigmaed = mods.locallab.spots.at(i).sigmaed; + } + + if (locallab.spots.at(i).radiusw) { + toEdit.locallab.spots.at(i).radiusw = mods.locallab.spots.at(i).radiusw; + } + + if (locallab.spots.at(i).detailw) { + toEdit.locallab.spots.at(i).detailw = mods.locallab.spots.at(i).detailw; + } + + if (locallab.spots.at(i).gradw) { + toEdit.locallab.spots.at(i).gradw = mods.locallab.spots.at(i).gradw; + } + + if (locallab.spots.at(i).tloww) { + toEdit.locallab.spots.at(i).tloww = mods.locallab.spots.at(i).tloww; + } + + if (locallab.spots.at(i).thigw) { + toEdit.locallab.spots.at(i).thigw = mods.locallab.spots.at(i).thigw; + } + + if (locallab.spots.at(i).edgw) { + toEdit.locallab.spots.at(i).edgw = mods.locallab.spots.at(i).edgw; + } + + if (locallab.spots.at(i).basew) { + toEdit.locallab.spots.at(i).basew = mods.locallab.spots.at(i).basew; + } + + if (locallab.spots.at(i).sensilc) { + toEdit.locallab.spots.at(i).sensilc = mods.locallab.spots.at(i).sensilc; + } + + if (locallab.spots.at(i).fftwlc) { + toEdit.locallab.spots.at(i).fftwlc = mods.locallab.spots.at(i).fftwlc; + } + + if (locallab.spots.at(i).blurlc) { + toEdit.locallab.spots.at(i).blurlc = mods.locallab.spots.at(i).blurlc; + } + + if (locallab.spots.at(i).wavblur) { + toEdit.locallab.spots.at(i).wavblur = mods.locallab.spots.at(i).wavblur; + } + + if (locallab.spots.at(i).wavedg) { + toEdit.locallab.spots.at(i).wavedg = mods.locallab.spots.at(i).wavedg; + } + + if (locallab.spots.at(i).waveshow) { + toEdit.locallab.spots.at(i).waveshow = mods.locallab.spots.at(i).waveshow; + } + + if (locallab.spots.at(i).wavcont) { + toEdit.locallab.spots.at(i).wavcont = mods.locallab.spots.at(i).wavcont; + } + + if (locallab.spots.at(i).wavcomp) { + toEdit.locallab.spots.at(i).wavcomp = mods.locallab.spots.at(i).wavcomp; + } + + if (locallab.spots.at(i).wavgradl) { + toEdit.locallab.spots.at(i).wavgradl = mods.locallab.spots.at(i).wavgradl; + } + + if (locallab.spots.at(i).wavcompre) { + toEdit.locallab.spots.at(i).wavcompre = mods.locallab.spots.at(i).wavcompre; + } + + if (locallab.spots.at(i).origlc) { + toEdit.locallab.spots.at(i).origlc = mods.locallab.spots.at(i).origlc; + } + + if (locallab.spots.at(i).localcontMethod) { + toEdit.locallab.spots.at(i).localcontMethod = mods.locallab.spots.at(i).localcontMethod; + } + + if (locallab.spots.at(i).localedgMethod) { + toEdit.locallab.spots.at(i).localedgMethod = mods.locallab.spots.at(i).localedgMethod; + } + + if (locallab.spots.at(i).localneiMethod) { + toEdit.locallab.spots.at(i).localneiMethod = mods.locallab.spots.at(i).localneiMethod; + } + + if (locallab.spots.at(i).locwavcurve) { + toEdit.locallab.spots.at(i).locwavcurve = mods.locallab.spots.at(i).locwavcurve; + } + + if (locallab.spots.at(i).csthreshold) { + toEdit.locallab.spots.at(i).csthreshold = mods.locallab.spots.at(i).csthreshold; + } + + if (locallab.spots.at(i).loclevwavcurve) { + toEdit.locallab.spots.at(i).loclevwavcurve = mods.locallab.spots.at(i).loclevwavcurve; + } + + if (locallab.spots.at(i).locconwavcurve) { + toEdit.locallab.spots.at(i).locconwavcurve = mods.locallab.spots.at(i).locconwavcurve; + } + + if (locallab.spots.at(i).loccompwavcurve) { + toEdit.locallab.spots.at(i).loccompwavcurve = mods.locallab.spots.at(i).loccompwavcurve; + } + + if (locallab.spots.at(i).loccomprewavcurve) { + toEdit.locallab.spots.at(i).loccomprewavcurve = mods.locallab.spots.at(i).loccomprewavcurve; + } + + if (locallab.spots.at(i).locedgwavcurve) { + toEdit.locallab.spots.at(i).locedgwavcurve = mods.locallab.spots.at(i).locedgwavcurve; + } + + if (locallab.spots.at(i).CCmasklccurve) { + toEdit.locallab.spots.at(i).CCmasklccurve = mods.locallab.spots.at(i).CCmasklccurve; + } + + if (locallab.spots.at(i).LLmasklccurve) { + toEdit.locallab.spots.at(i).LLmasklccurve = mods.locallab.spots.at(i).LLmasklccurve; + } + + if (locallab.spots.at(i).HHmasklccurve) { + toEdit.locallab.spots.at(i).HHmasklccurve = mods.locallab.spots.at(i).HHmasklccurve; + } + + if (locallab.spots.at(i).enalcMask) { + toEdit.locallab.spots.at(i).enalcMask = mods.locallab.spots.at(i).enalcMask; + } + + if (locallab.spots.at(i).blendmasklc) { + toEdit.locallab.spots.at(i).blendmasklc = mods.locallab.spots.at(i).blendmasklc; + } + + if (locallab.spots.at(i).radmasklc) { + toEdit.locallab.spots.at(i).radmasklc = mods.locallab.spots.at(i).radmasklc; + } + + if (locallab.spots.at(i).chromasklc) { + toEdit.locallab.spots.at(i).chromasklc = mods.locallab.spots.at(i).chromasklc; + } + + if (locallab.spots.at(i).Lmasklccurve) { + toEdit.locallab.spots.at(i).Lmasklccurve = mods.locallab.spots.at(i).Lmasklccurve; + } + + // Contrast by detail levels + if (locallab.spots.at(i).visicbdl) { + toEdit.locallab.spots.at(i).visicbdl = mods.locallab.spots.at(i).visicbdl; + } + + if (locallab.spots.at(i).expcbdl) { + toEdit.locallab.spots.at(i).expcbdl = mods.locallab.spots.at(i).expcbdl; + } + + if (locallab.spots.at(i).complexcbdl) { + toEdit.locallab.spots.at(i).complexcbdl = mods.locallab.spots.at(i).complexcbdl; + } + + for (int j = 0; j < 6; j++) { + if (locallab.spots.at(i).mult[j]) { + toEdit.locallab.spots.at(i).mult[j] = mods.locallab.spots.at(i).mult[j]; + } + } + + if (locallab.spots.at(i).chromacbdl) { + toEdit.locallab.spots.at(i).chromacbdl = mods.locallab.spots.at(i).chromacbdl; + } + + if (locallab.spots.at(i).threshold) { + toEdit.locallab.spots.at(i).threshold = mods.locallab.spots.at(i).threshold; + } + + if (locallab.spots.at(i).sensicb) { + toEdit.locallab.spots.at(i).sensicb = mods.locallab.spots.at(i).sensicb; + } + + if (locallab.spots.at(i).clarityml) { + toEdit.locallab.spots.at(i).clarityml = mods.locallab.spots.at(i).clarityml; + } + + if (locallab.spots.at(i).contresid) { + toEdit.locallab.spots.at(i).contresid = mods.locallab.spots.at(i).contresid; + } + + if (locallab.spots.at(i).blurcbdl) { + toEdit.locallab.spots.at(i).blurcbdl = mods.locallab.spots.at(i).blurcbdl; + } + + if (locallab.spots.at(i).softradiuscb) { + toEdit.locallab.spots.at(i).softradiuscb = mods.locallab.spots.at(i).softradiuscb; + } + + if (locallab.spots.at(i).enacbMask) { + toEdit.locallab.spots.at(i).enacbMask = mods.locallab.spots.at(i).enacbMask; + } + + if (locallab.spots.at(i).CCmaskcbcurve) { + toEdit.locallab.spots.at(i).CCmaskcbcurve = mods.locallab.spots.at(i).CCmaskcbcurve; + } + + if (locallab.spots.at(i).LLmaskcbcurve) { + toEdit.locallab.spots.at(i).LLmaskcbcurve = mods.locallab.spots.at(i).LLmaskcbcurve; + } + + if (locallab.spots.at(i).HHmaskcbcurve) { + toEdit.locallab.spots.at(i).HHmaskcbcurve = mods.locallab.spots.at(i).HHmaskcbcurve; + } + + if (locallab.spots.at(i).blendmaskcb) { + toEdit.locallab.spots.at(i).blendmaskcb = mods.locallab.spots.at(i).blendmaskcb; + } + + if (locallab.spots.at(i).radmaskcb) { + toEdit.locallab.spots.at(i).radmaskcb = mods.locallab.spots.at(i).radmaskcb; + } + + if (locallab.spots.at(i).chromaskcb) { + toEdit.locallab.spots.at(i).chromaskcb = mods.locallab.spots.at(i).chromaskcb; + } + + if (locallab.spots.at(i).gammaskcb) { + toEdit.locallab.spots.at(i).gammaskcb = mods.locallab.spots.at(i).gammaskcb; + } + + if (locallab.spots.at(i).slomaskcb) { + toEdit.locallab.spots.at(i).slomaskcb = mods.locallab.spots.at(i).slomaskcb; + } + + if (locallab.spots.at(i).lapmaskcb) { + toEdit.locallab.spots.at(i).lapmaskcb = mods.locallab.spots.at(i).lapmaskcb; + } + + if (locallab.spots.at(i).Lmaskcbcurve) { + toEdit.locallab.spots.at(i).Lmaskcbcurve = mods.locallab.spots.at(i).Lmaskcbcurve; + } + + // Log encoding + if (locallab.spots.at(i).visilog) { + toEdit.locallab.spots.at(i).visilog = mods.locallab.spots.at(i).visilog; + } + + if (locallab.spots.at(i).explog) { + toEdit.locallab.spots.at(i).explog = mods.locallab.spots.at(i).explog; + } + + if (locallab.spots.at(i).autocompute) { + toEdit.locallab.spots.at(i).autocompute = mods.locallab.spots.at(i).autocompute; + } + + if (locallab.spots.at(i).sourceGray) { + toEdit.locallab.spots.at(i).sourceGray = mods.locallab.spots.at(i).sourceGray; + } + + if (locallab.spots.at(i).targetGray) { + toEdit.locallab.spots.at(i).targetGray = mods.locallab.spots.at(i).targetGray; + } + + if (locallab.spots.at(i).Autogray) { + toEdit.locallab.spots.at(i).Autogray = mods.locallab.spots.at(i).Autogray; + } + + if (locallab.spots.at(i).fullimage) { + toEdit.locallab.spots.at(i).fullimage = mods.locallab.spots.at(i).fullimage; + } + + if (locallab.spots.at(i).blackEv) { + toEdit.locallab.spots.at(i).blackEv = mods.locallab.spots.at(i).blackEv; + } + + if (locallab.spots.at(i).whiteEv) { + toEdit.locallab.spots.at(i).whiteEv = mods.locallab.spots.at(i).whiteEv; + } + + if (locallab.spots.at(i).detail) { + toEdit.locallab.spots.at(i).detail = mods.locallab.spots.at(i).detail; + } + + if (locallab.spots.at(i).sensilog) { + toEdit.locallab.spots.at(i).sensilog = mods.locallab.spots.at(i).sensilog; + } + + if (locallab.spots.at(i).baselog) { + toEdit.locallab.spots.at(i).baselog = mods.locallab.spots.at(i).baselog; + } + + if (locallab.spots.at(i).strlog) { + toEdit.locallab.spots.at(i).strlog = mods.locallab.spots.at(i).strlog; + } + + if (locallab.spots.at(i).anglog) { + toEdit.locallab.spots.at(i).anglog = mods.locallab.spots.at(i).anglog; + } + } + if (pcvignette.enabled) { toEdit.pcvignette.enabled = mods.pcvignette.enabled; } @@ -2967,6 +5253,22 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.enabled = mods.wavelet.enabled; } + if (wavelet.labgridALow) { + toEdit.wavelet.labgridALow = mods.wavelet.labgridALow; + } + + if (wavelet.labgridBLow) { + toEdit.wavelet.labgridBLow = mods.wavelet.labgridBLow; + } + + if (wavelet.labgridAHigh) { + toEdit.wavelet.labgridAHigh = mods.wavelet.labgridAHigh; + } + + if (wavelet.labgridBHigh) { + toEdit.wavelet.labgridBHigh = mods.wavelet.labgridBHigh; + } + if (wavelet.strength) { toEdit.wavelet.strength = mods.wavelet.strength; } @@ -2975,6 +5277,30 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.balance = mods.wavelet.balance; } + if (wavelet.sigmafin) { + toEdit.wavelet.sigmafin = mods.wavelet.sigmafin; + } + + if (wavelet.sigmaton) { + toEdit.wavelet.sigmaton = mods.wavelet.sigmaton; + } + + if (wavelet.sigmacol) { + toEdit.wavelet.sigmacol = mods.wavelet.sigmacol; + } + + if (wavelet.sigmadir) { + toEdit.wavelet.sigmadir = mods.wavelet.sigmadir; + } + + if (wavelet.rangeab) { + toEdit.wavelet.rangeab = mods.wavelet.rangeab; + } + + if (wavelet.protab) { + toEdit.wavelet.protab = mods.wavelet.protab; + } + if (wavelet.iter) { toEdit.wavelet.iter = mods.wavelet.iter; } @@ -3207,6 +5533,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.blcurve = mods.wavelet.blcurve; } + if (wavelet.opacityCurveSH) { + toEdit.wavelet.opacityCurveSH = mods.wavelet.opacityCurveSH; + } + if (wavelet.opacityCurveRG) { toEdit.wavelet.opacityCurveRG = mods.wavelet.opacityCurveRG; } @@ -3479,7 +5809,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng if (dehaze.strength) { toEdit.dehaze.strength = dontforceSet && options.baBehav[ADDSET_DEHAZE_STRENGTH] ? toEdit.dehaze.strength + mods.dehaze.strength : mods.dehaze.strength; } - + if (dehaze.depth) { toEdit.dehaze.depth = mods.dehaze.depth; } @@ -3518,6 +5848,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.filmNegative.blueBase = mods.filmNegative.blueBase; } + if (raw.preprocessWB.mode) { + toEdit.raw.preprocessWB.mode = mods.raw.preprocessWB.mode; + } + // Exif changes are added to the existing ones if (exif) { for (procparams::ExifPairs::const_iterator i = mods.exif.begin(); i != mods.exif.end(); ++i) { @@ -3567,7 +5901,923 @@ bool FilmNegativeParamsEdited::isUnchanged() const return enabled && redRatio && greenExp && blueRatio && baseValues; } +LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : + // Control spot settings + name(v), + isvisible(v), + shape(v), + spotMethod(v), + wavMethod(v), + sensiexclu(v), + structexclu(v), + struc(v), + shapeMethod(v), + loc(v), + centerX(v), + centerY(v), + circrad(v), + qualityMethod(v), + complexMethod(v), + transit(v), + feather(v), + thresh(v), + iter(v), + balan(v), + balanh(v), + colorde(v), + colorscope(v), + transitweak(v), + transitgrad(v), + avoid(v), + blwh(v), + recurs(v), + laplac(v), + deltae(v), + shortc(v), + savrest(v), + scopemask(v), + lumask(v), + // Color & Light + visicolor(v), + expcolor(v), + complexcolor(v), + curvactiv(v), + lightness(v), + contrast(v), + chroma(v), + labgridALow(v), + labgridBLow(v), + labgridAHigh(v), + labgridBHigh(v), + labgridALowmerg(v), + labgridBLowmerg(v), + labgridAHighmerg(v), + labgridBHighmerg(v), + strengthgrid(v), + sensi(v), + structcol(v), + strcol(v), + strcolab(v), + strcolh(v), + angcol(v), + blurcolde(v), + blurcol(v), + contcol(v), + blendmaskcol(v), + radmaskcol(v), + chromaskcol(v), + gammaskcol(v), + slomaskcol(v), + shadmaskcol(v), + strumaskcol(v), + lapmaskcol(v), + qualitycurveMethod(v), + gridMethod(v), + merMethod(v), + toneMethod(v), + mergecolMethod(v), + llcurve(v), + lccurve(v), + cccurve(v), + clcurve(v), + rgbcurve(v), + LHcurve(v), + HHcurve(v), + invers(v), + special(v), + toolcol(v), + enaColorMask(v), + fftColorMask(v), + CCmaskcurve(v), + LLmaskcurve(v), + HHmaskcurve(v), + HHhmaskcurve(v), + softradiuscol(v), + opacol(v), + mercol(v), + merlucol(v), + conthrcol(v), + Lmaskcurve(v), + LLmaskcolcurvewav(v), + csthresholdcol(v), + // Exposure + visiexpose(v), + expexpose(v), + complexexpose(v), + expcomp(v), + hlcompr(v), + hlcomprthresh(v), + black(v), + shadex(v), + shcompr(v), + expchroma(v), + sensiex(v), + structexp(v), + blurexpde(v), + strexp(v), + angexp(v), + excurve(v), + inversex(v), + enaExpMask(v), + enaExpMaskaft(v), + CCmaskexpcurve(v), + LLmaskexpcurve(v), + HHmaskexpcurve(v), + blendmaskexp(v), + radmaskexp(v), + chromaskexp(v), + gammaskexp(v), + slomaskexp(v), + lapmaskexp(v), + strmaskexp(v), + angmaskexp(v), + softradiusexp(v), + Lmaskexpcurve(v), + expMethod(v), + exnoiseMethod(v), + laplacexp(v), + balanexp(v), + linear(v), + gamm(v), + fatamount(v), + fatdetail(v), + fatanchor(v), + fatlevel(v), + // Shadow highlight + visishadhigh(v), + expshadhigh(v), + complexshadhigh(v), + shMethod(v), + multsh{v, v, v, v, v, v}, + highlights(v), + h_tonalwidth(v), + shadows(v), + s_tonalwidth(v), + sh_radius(v), + sensihs(v), + enaSHMask(v), + CCmaskSHcurve(v), + LLmaskSHcurve(v), + HHmaskSHcurve(v), + blendmaskSH(v), + radmaskSH(v), + blurSHde(v), + strSH(v), + angSH(v), + inverssh(v), + chromaskSH(v), + gammaskSH(v), + slomaskSH(v), + lapmaskSH(v), + detailSH(v), + LmaskSHcurve(v), + fatamountSH(v), + fatanchorSH(v), + gamSH(v), + sloSH(v), + // Vibrance + visivibrance(v), + expvibrance(v), + complexvibrance(v), + saturated(v), + pastels(v), + warm(v), + psthreshold(v), + protectskins(v), + avoidcolorshift(v), + pastsattog(v), + sensiv(v), + skintonescurve(v), + CCmaskvibcurve(v), + LLmaskvibcurve(v), + HHmaskvibcurve(v), + enavibMask(v), + blendmaskvib(v), + radmaskvib(v), + chromaskvib(v), + gammaskvib(v), + slomaskvib(v), + lapmaskvib(v), + strvib(v), + strvibab(v), + strvibh(v), + angvib(v), + Lmaskvibcurve(v), + // Soft Light + visisoft(v), + expsoft(v), + complexsoft(v), + streng(v), + sensisf(v), + laplace(v), + softMethod(v), + // Blur & Noise + visiblur(v), + expblur(v), + complexblur(v), + radius(v), + strength(v), + sensibn(v), + itera(v), + guidbl(v), + strbl(v), + isogr(v), + strengr(v), + scalegr(v), + epsbl(v), + blMethod(v), + chroMethod(v), + blurMethod(v), + medMethod(v), + activlum(v), + noiselumf(v), + noiselumf0(v), + noiselumf2(v), + noiselumc(v), + noiselumdetail(v), + noiselequal(v), + noisechrof(v), + noisechroc(v), + noisechrodetail(v), + adjblur(v), + bilateral(v), + sensiden(v), + detailthr(v), + locwavcurveden(v), + showmaskblMethodtyp(v), + CCmaskblcurve(v), + LLmaskblcurve(v), + HHmaskblcurve(v), + enablMask(v), + fftwbl(v), + toolbl(v), + blendmaskbl(v), + radmaskbl(v), + chromaskbl(v), + gammaskbl(v), + slomaskbl(v), + lapmaskbl(v), + shadmaskbl(v), + shadmaskblsha(v), + strumaskbl(v), + Lmaskblcurve(v), + LLmaskblcurvewav(v), + csthresholdblur(v), + // Tone Mapping + visitonemap(v), + exptonemap(v), + complextonemap(v), + stren(v), + gamma(v), + estop(v), + scaltm(v), + rewei(v), + satur(v), + sensitm(v), + softradiustm(v), + amount(v), + equiltm(v), + CCmasktmcurve(v), + LLmasktmcurve(v), + HHmasktmcurve(v), + enatmMask(v), + enatmMaskaft(v), + blendmasktm(v), + radmasktm(v), + chromasktm(v), + gammasktm(v), + slomasktm(v), + lapmasktm(v), + Lmasktmcurve(v), + // Retinex + visireti(v), + expreti(v), + complexreti(v), + retinexMethod(v), + str(v), + chrrt(v), + neigh(v), + vart(v), + offs(v), + dehaz(v), + depth(v), + sensih(v), + localTgaincurve(v), + localTtranscurve(v), + inversret(v), + equilret(v), + loglin(v), + lumonly(v), + softradiusret(v), + CCmaskreticurve(v), + LLmaskreticurve(v), + HHmaskreticurve(v), + enaretiMask(v), + enaretiMasktmap(v), + blendmaskreti(v), + radmaskreti(v), + chromaskreti(v), + gammaskreti(v), + slomaskreti(v), + lapmaskreti(v), + scalereti(v), + darkness(v), + lightnessreti(v), + limd(v), + cliptm(v), + fftwreti(v), + Lmaskreticurve(v), + // Sharpening + visisharp(v), + expsharp(v), + complexsharp(v), + sharcontrast(v), + sharradius(v), + sharamount(v), + shardamping(v), + shariter(v), + sharblur(v), + sensisha(v), + inverssha(v), + // Local Contrast + visicontrast(v), + expcontrast(v), + complexcontrast(v), + lcradius(v), + lcamount(v), + lcdarkness(v), + lclightness(v), + sigmalc(v), + levelwav(v), + residcont(v), + residsha(v), + residshathr(v), + residhi(v), + residhithr(v), + residblur(v), + levelblur(v), + sigmabl(v), + residchro(v), + residcomp(v), + sigma(v), + offset(v), + sigmadr(v), + threswav(v), + chromalev(v), + chromablu(v), + sigmadc(v), + deltad(v), + fatres(v), + clarilres(v), + claricres(v), + clarisoft(v), + sigmalc2(v), + strwav(v), + angwav(v), + strengthw(v), + sigmaed(v), + radiusw(v), + detailw(v), + gradw(v), + tloww(v), + thigw(v), + edgw(v), + basew(v), + sensilc(v), + fftwlc(v), + blurlc(v), + wavblur(v), + wavedg(v), + waveshow(v), + wavcont(v), + wavcomp(v), + wavgradl(v), + wavcompre(v), + origlc(v), + localcontMethod(v), + localedgMethod(v), + localneiMethod(v), + locwavcurve(v), + csthreshold(v), + loclevwavcurve(v), + locconwavcurve(v), + loccompwavcurve(v), + loccomprewavcurve(v), + locedgwavcurve(v), + CCmasklccurve(v), + LLmasklccurve(v), + HHmasklccurve(v), + enalcMask(v), + blendmasklc(v), + radmasklc(v), + chromasklc(v), + Lmasklccurve(v), + // Contrast by detail levels + visicbdl(v), + expcbdl(v), + complexcbdl(v), + mult{v, v, v, v, v, v}, + chromacbdl(v), + threshold(v), + sensicb(v), + clarityml(v), + contresid(v), + blurcbdl(v), + softradiuscb(v), + enacbMask(v), + CCmaskcbcurve(v), + LLmaskcbcurve(v), + HHmaskcbcurve(v), + blendmaskcb(v), + radmaskcb(v), + chromaskcb(v), + gammaskcb(v), + slomaskcb(v), + lapmaskcb(v), + Lmaskcbcurve(v), + // Log encoding + visilog(v), + explog(v), + autocompute(v), + sourceGray(v), + targetGray(v), + Autogray(v), + fullimage(v), + blackEv(v), + whiteEv(v), + detail(v), + sensilog(v), + baselog(v), + strlog(v), + anglog(v) +{ +} + +void LocallabParamsEdited::LocallabSpotEdited::set(bool v) +{ + name = v; + isvisible = v; + shape = v; + spotMethod = v; + wavMethod = v; + sensiexclu = v; + structexclu = v; + struc = v; + shapeMethod = v; + loc = v; + centerX = v; + centerY = v; + circrad = v; + qualityMethod = v; + complexMethod = v; + transit = v; + feather = v; + thresh = v; + iter = v; + balan = v; + balanh = v; + colorde = v; + colorscope = v; + transitweak = v; + transitgrad = v; + avoid = v; + blwh = v; + recurs = v; + laplac = v; + deltae = v; + shortc = v; + savrest = v; + scopemask = v; + lumask = v; + // Color & Light + visicolor = v; + expcolor = v; + complexcolor = v; + curvactiv = v; + lightness = v; + contrast = v; + chroma = v; + labgridALow = v; + labgridBLow = v; + labgridAHigh = v; + labgridBHigh = v; + labgridALowmerg = v; + labgridBLowmerg = v; + labgridAHighmerg = v; + labgridBHighmerg = v; + strengthgrid = v; + sensi = v; + structcol = v; + strcol = v; + strcolab = v; + strcolh = v; + angcol = v; + blurcolde = v; + blurcol = v; + contcol = v; + blendmaskcol = v; + radmaskcol = v; + chromaskcol = v; + gammaskcol = v; + slomaskcol = v; + shadmaskcol = v; + strumaskcol = v; + lapmaskcol = v; + qualitycurveMethod = v; + gridMethod = v; + merMethod = v; + toneMethod = v; + mergecolMethod = v; + llcurve = v; + lccurve = v; + cccurve = v; + clcurve = v; + rgbcurve = v; + LHcurve = v; + HHcurve = v; + invers = v; + special = v; + toolcol = v; + enaColorMask = v; + fftColorMask = v; + CCmaskcurve = v; + LLmaskcurve = v; + HHmaskcurve = v; + HHhmaskcurve = v; + softradiuscol = v; + opacol = v; + mercol = v; + merlucol = v; + conthrcol = v; + Lmaskcurve = v; + LLmaskcolcurvewav = v; + csthresholdcol = v; + // Exposure + visiexpose = v; + expexpose = v; + complexexpose = v; + expcomp = v; + hlcompr = v; + hlcomprthresh = v; + black = v; + shadex = v; + shcompr = v; + expchroma = v; + sensiex = v; + structexp = v; + blurexpde = v; + strexp = v; + angexp = v; + excurve = v; + inversex = v; + enaExpMask = v; + enaExpMaskaft = v; + CCmaskexpcurve = v; + LLmaskexpcurve = v; + HHmaskexpcurve = v; + blendmaskexp = v; + radmaskexp = v; + chromaskexp = v; + gammaskexp = v; + slomaskexp = v; + lapmaskexp = v; + strmaskexp = v; + angmaskexp = v; + softradiusexp = v; + Lmaskexpcurve = v; + expMethod = v; + exnoiseMethod = v; + laplacexp = v; + balanexp = v; + linear = v; + gamm = v; + fatamount = v; + fatdetail = v; + fatanchor = v; + fatlevel = v; + // Shadow highlight + visishadhigh = v; + expshadhigh = v; + complexshadhigh = v; + shMethod = v; + + for (int i = 0; i < 5; i++) { + multsh[i] = v; + } + + highlights = v; + h_tonalwidth = v; + shadows = v; + s_tonalwidth = v; + sh_radius = v; + sensihs = v; + enaSHMask = v; + CCmaskSHcurve = v; + LLmaskSHcurve = v; + HHmaskSHcurve = v; + blendmaskSH = v; + radmaskSH = v; + blurSHde = v; + strSH = v; + angSH = v; + inverssh = v; + chromaskSH = v; + gammaskSH = v; + slomaskSH = v; + lapmaskSH = v; + detailSH = v; + LmaskSHcurve = v; + fatamountSH = v; + fatanchorSH = v; + gamSH = v; + sloSH = v; + // Vibrance + visivibrance = v; + expvibrance = v; + complexvibrance = v; + saturated = v; + pastels = v; + warm = v; + psthreshold = v; + protectskins = v; + avoidcolorshift = v; + pastsattog = v; + sensiv = v; + skintonescurve = v; + CCmaskvibcurve = v; + LLmaskvibcurve = v; + HHmaskvibcurve = v; + enavibMask = v; + blendmaskvib = v; + radmaskvib = v; + chromaskvib = v; + gammaskvib = v; + slomaskvib = v; + lapmaskvib = v; + strvib = v; + strvibab = v; + strvibh = v; + angvib = v; + Lmaskvibcurve = v; + // Soft Light + visisoft = v; + expsoft = v; + complexsoft = v; + streng = v; + sensisf = v; + laplace = v; + softMethod = v; + // Blur & Noise + visiblur = v; + expblur = v; + complexblur = v; + radius = v; + strength = v; + sensibn = v; + itera = v; + guidbl = v; + strbl = v; + isogr = v; + strengr = v; + scalegr = v; + epsbl = v; + blMethod = v; + chroMethod = v; + blurMethod = v; + medMethod = v; + activlum = v; + noiselumf = v; + noiselumf0 = v; + noiselumf2 = v; + noiselumc = v; + noiselumdetail = v; + noiselequal = v; + noisechrof = v; + noisechroc = v; + noisechrodetail = v; + adjblur = v; + bilateral = v; + sensiden = v; + detailthr = v; + locwavcurveden = v; + showmaskblMethodtyp = v; + CCmaskblcurve = v; + LLmaskblcurve = v; + HHmaskblcurve = v; + enablMask = v; + fftwbl = v; + toolbl = v; + blendmaskbl = v; + radmaskbl = v; + chromaskbl = v; + gammaskbl = v; + slomaskbl = v; + lapmaskbl = v; + shadmaskbl = v; + shadmaskblsha = v; + strumaskbl = v; + Lmaskblcurve = v; + LLmaskblcurvewav = v; + csthresholdblur = v; + // Tone Mapping + visitonemap = v; + exptonemap = v; + complextonemap = v; + stren = v; + gamma = v; + estop = v; + scaltm = v; + rewei = v; + satur = v; + sensitm = v; + softradiustm = v; + amount = v; + equiltm = v; + CCmasktmcurve = v; + LLmasktmcurve = v; + HHmasktmcurve = v; + enatmMask = v; + enatmMaskaft = v; + blendmasktm = v; + radmasktm = v; + chromasktm = v; + gammasktm = v; + slomasktm = v; + lapmasktm = v; + Lmasktmcurve = v; + // Retinex + visireti = v; + expreti = v; + complexreti = v; + retinexMethod = v; + str = v; + chrrt = v; + neigh = v; + vart = v; + offs = v; + dehaz = v; + depth = v; + sensih = v; + localTgaincurve = v; + localTtranscurve = v; + inversret = v; + equilret = v; + loglin = v; + lumonly = v; + softradiusret = v; + CCmaskreticurve = v; + LLmaskreticurve = v; + HHmaskreticurve = v; + enaretiMask = v; + enaretiMasktmap = v; + blendmaskreti = v; + radmaskreti = v; + chromaskreti = v; + gammaskreti = v; + slomaskreti = v; + lapmaskreti = v; + scalereti = v; + darkness = v; + lightnessreti = v; + limd = v; + cliptm = v; + fftwreti = v; + Lmaskreticurve = v; + // Sharpening + visisharp = v; + expsharp = v; + complexsharp = v; + sharcontrast = v; + sharradius = v; + sharamount = v; + shardamping = v; + shariter = v; + sharblur = v; + sensisha = v; + inverssha = v; + // Local Contrast + visicontrast = v; + expcontrast = v; + complexcontrast = v; + lcradius = v; + lcamount = v; + lcdarkness = v; + lclightness = v; + sigmalc = v; + levelwav = v; + residcont = v; + residsha = v; + residshathr = v; + residhi = v; + residhithr = v; + residblur = v; + levelblur = v; + sigmabl = v; + residchro = v; + residcomp = v; + sigma = v; + offset = v; + sigmadr = v; + threswav = v; + chromalev = v; + chromablu = v; + sigmadc = v; + deltad = v; + fatres = v; + clarilres = v; + claricres = v; + clarisoft = v; + sigmalc2 = v; + strwav = v; + angwav = v; + strengthw = v; + sigmaed = v; + radiusw = v; + detailw = v; + gradw = v; + tloww = v; + thigw = v; + edgw = v; + basew = v; + sensilc = v; + fftwlc = v; + blurlc = v; + wavblur = v; + wavedg = v; + waveshow = v; + wavcont = v; + wavcomp = v; + wavgradl = v; + wavcompre = v; + origlc = v; + localcontMethod = v; + localedgMethod = v; + localneiMethod = v; + locwavcurve = v; + csthreshold = v; + loclevwavcurve = v; + locconwavcurve = v; + loccompwavcurve = v; + loccomprewavcurve = v; + locedgwavcurve = v; + CCmasklccurve = v; + LLmasklccurve = v; + HHmasklccurve = v; + enalcMask = v; + blendmasklc = v; + radmasklc = v; + chromasklc = v; + Lmasklccurve = v; + // Contrast by detail levels + visicbdl = v; + expcbdl = v; + complexcbdl = v; + + for (int i = 0; i < 6; i++) { + mult[i] = v; + } + + chromacbdl = v; + threshold = v; + sensicb = v; + clarityml = v; + contresid = v; + softradiuscb = v; + enacbMask = v; + CCmaskcbcurve = v; + LLmaskcbcurve = v; + HHmaskcbcurve = v; + blurcbdl = v; + blendmaskcb = v; + radmaskcb = v; + chromaskcb = v; + gammaskcb = v; + slomaskcb = v; + lapmaskcb = v; + Lmaskcbcurve = v; + // Log encoding + visilog = v; + explog = v; + autocompute = v; + sourceGray = v; + targetGray = v; + Autogray = v; + fullimage = v; + blackEv = v; + whiteEv = v; + detail = v; + sensilog = v; + baselog = v; + strlog = v; + anglog = v; +} + bool CaptureSharpeningParamsEdited::isUnchanged() const { return enabled && contrast && autoContrast && autoRadius && deconvradius && deconvradiusOffset && deconviter && deconvitercheck; } + +bool RAWParamsEdited::PreprocessWBParamsEdited::isUnchanged() const +{ + return mode; +} diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index edfdbeafb..1bd2e045e 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -169,6 +169,10 @@ struct ColorToningEdited { bool labgridBLow; bool labgridAHigh; bool labgridBHigh; + bool labgridALowmerg; + bool labgridBLowmerg; + bool labgridAHighmerg; + bool labgridBHighmerg; bool labregions; bool labregionsShowMask; }; @@ -379,6 +383,468 @@ struct RotateParamsEdited { struct DistortionParamsEdited { bool amount; }; +class LocallabParamsEdited +{ +public: + struct LocallabSpotEdited { + // Control spot settings + bool name; + bool isvisible; + bool shape; + bool spotMethod; + bool wavMethod; + bool sensiexclu; + bool structexclu; + bool struc; + bool shapeMethod; + bool loc; + bool centerX; + bool centerY; + bool circrad; + bool qualityMethod; + bool complexMethod; + bool transit; + bool feather; + bool thresh; + bool iter; + bool balan; + bool balanh; + bool colorde; + bool colorscope; + bool transitweak; + bool transitgrad; + bool avoid; + bool blwh; + bool recurs; + bool laplac; + bool deltae; + bool shortc; + bool savrest; + bool scopemask; + bool lumask; + // Color & Light + bool visicolor; + bool expcolor; + bool complexcolor; + bool curvactiv; + bool lightness; + bool contrast; + bool chroma; + bool labgridALow; + bool labgridBLow; + bool labgridAHigh; + bool labgridBHigh; + bool labgridALowmerg; + bool labgridBLowmerg; + bool labgridAHighmerg; + bool labgridBHighmerg; + bool strengthgrid; + bool sensi; + bool structcol; + bool strcol; + bool strcolab; + bool strcolh; + bool angcol; + bool blurcolde; + bool blurcol; + bool contcol; + bool blendmaskcol; + bool radmaskcol; + bool chromaskcol; + bool gammaskcol; + bool slomaskcol; + bool shadmaskcol; + bool strumaskcol; + bool lapmaskcol; + bool qualitycurveMethod; + bool gridMethod; + bool merMethod; + bool toneMethod; + bool mergecolMethod; + bool llcurve; + bool lccurve; + bool cccurve; + bool clcurve; + bool rgbcurve; + bool LHcurve; + bool HHcurve; + bool invers; + bool special; + bool toolcol; + bool enaColorMask; + bool fftColorMask; + bool CCmaskcurve; + bool LLmaskcurve; + bool HHmaskcurve; + bool HHhmaskcurve; + bool softradiuscol; + bool opacol; + bool mercol; + bool merlucol; + bool conthrcol; + bool Lmaskcurve; + bool LLmaskcolcurvewav; + bool csthresholdcol; + // Exposure + bool visiexpose; + bool expexpose; + bool complexexpose; + bool expcomp; + bool hlcompr; + bool hlcomprthresh; + bool black; + bool shadex; + bool shcompr; + bool expchroma; + bool sensiex; + bool structexp; + bool blurexpde; + bool strexp; + bool angexp; + bool excurve; + bool inversex; + bool enaExpMask; + bool enaExpMaskaft; + bool CCmaskexpcurve; + bool LLmaskexpcurve; + bool HHmaskexpcurve; + bool blendmaskexp; + bool radmaskexp; + bool chromaskexp; + bool gammaskexp; + bool slomaskexp; + bool lapmaskexp; + bool strmaskexp; + bool angmaskexp; + bool softradiusexp; + bool Lmaskexpcurve; + bool expMethod; + bool exnoiseMethod; + bool laplacexp; + bool balanexp; + bool linear; + bool gamm; + bool fatamount; + bool fatdetail; + bool fatanchor; + bool fatlevel; + // Shadow highlight + bool visishadhigh; + bool expshadhigh; + bool complexshadhigh; + bool shMethod; + bool multsh[6]; + bool highlights; + bool h_tonalwidth; + bool shadows; + bool s_tonalwidth; + bool sh_radius; + bool sensihs; + bool enaSHMask; + bool CCmaskSHcurve; + bool LLmaskSHcurve; + bool HHmaskSHcurve; + bool blendmaskSH; + bool radmaskSH; + bool blurSHde; + bool strSH; + bool angSH; + bool inverssh; + bool chromaskSH; + bool gammaskSH; + bool slomaskSH; + bool lapmaskSH; + bool detailSH; + bool LmaskSHcurve; + bool fatamountSH; + bool fatanchorSH; + bool gamSH; + bool sloSH; + // Vibrance + bool visivibrance; + bool expvibrance; + bool complexvibrance; + bool saturated; + bool pastels; + bool warm; + bool psthreshold; + bool protectskins; + bool avoidcolorshift; + bool pastsattog; + bool sensiv; + bool skintonescurve; + bool CCmaskvibcurve; + bool LLmaskvibcurve; + bool HHmaskvibcurve; + bool enavibMask; + bool blendmaskvib; + bool radmaskvib; + bool chromaskvib; + bool gammaskvib; + bool slomaskvib; + bool lapmaskvib; + bool strvib; + bool strvibab; + bool strvibh; + bool angvib; + bool Lmaskvibcurve; + // Soft Light + bool visisoft; + bool expsoft; + bool complexsoft; + bool streng; + bool sensisf; + bool laplace; + bool softMethod; + // Blur & Noise + bool visiblur; + bool expblur; + bool complexblur; + bool radius; + bool strength; + bool sensibn; + bool itera; + bool guidbl; + bool strbl; + bool isogr; + bool strengr; + bool scalegr; + bool epsbl; + bool blMethod; + bool chroMethod; + bool blurMethod; + bool medMethod; + bool activlum; + bool noiselumf; + bool noiselumf0; + bool noiselumf2; + bool noiselumc; + bool noiselumdetail; + bool noiselequal; + bool noisechrof; + bool noisechroc; + bool noisechrodetail; + bool adjblur; + bool bilateral; + bool sensiden; + bool detailthr; + bool locwavcurveden; + bool showmaskblMethodtyp; + bool CCmaskblcurve; + bool LLmaskblcurve; + bool HHmaskblcurve; + bool enablMask; + bool fftwbl; + bool toolbl; + bool blendmaskbl; + bool radmaskbl; + bool chromaskbl; + bool gammaskbl; + bool slomaskbl; + bool lapmaskbl; + bool shadmaskbl; + bool shadmaskblsha; + bool strumaskbl; + bool Lmaskblcurve; + bool LLmaskblcurvewav; + bool csthresholdblur; + // Tone Mapping + bool visitonemap; + bool exptonemap; + bool complextonemap; + bool stren; + bool gamma; + bool estop; + bool scaltm; + bool rewei; + bool satur; + bool sensitm; + bool softradiustm; + bool amount; + bool equiltm; + bool CCmasktmcurve; + bool LLmasktmcurve; + bool HHmasktmcurve; + bool enatmMask; + bool enatmMaskaft; + bool blendmasktm; + bool radmasktm; + bool chromasktm; + bool gammasktm; + bool slomasktm; + bool lapmasktm; + bool Lmasktmcurve; + // Retinex + bool visireti; + bool expreti; + bool complexreti; + bool retinexMethod; + bool str; + bool chrrt; + bool neigh; + bool vart; + bool offs; + bool dehaz; + bool depth; + bool sensih; + bool localTgaincurve; + bool localTtranscurve; + bool inversret; + bool equilret; + bool loglin; + bool lumonly; + bool softradiusret; + bool CCmaskreticurve; + bool LLmaskreticurve; + bool HHmaskreticurve; + bool enaretiMask; + bool enaretiMasktmap; + bool blendmaskreti; + bool radmaskreti; + bool chromaskreti; + bool gammaskreti; + bool slomaskreti; + bool lapmaskreti; + bool scalereti; + bool darkness; + bool lightnessreti; + bool limd; + bool cliptm; + bool fftwreti; + bool Lmaskreticurve; + // Sharpening + bool visisharp; + bool expsharp; + bool complexsharp; + bool sharcontrast; + bool sharradius; + bool sharamount; + bool shardamping; + bool shariter; + bool sharblur; + bool sensisha; + bool inverssha; + // Local Contrast + bool visicontrast; + bool expcontrast; + bool complexcontrast; + bool lcradius; + bool lcamount; + bool lcdarkness; + bool lclightness; + bool sigmalc; + bool levelwav; + bool residcont; + bool residsha; + bool residshathr; + bool residhi; + bool residhithr; + bool residblur; + bool levelblur; + bool sigmabl; + bool residchro; + bool residcomp; + bool sigma; + bool offset; + bool sigmadr; + bool threswav; + bool chromalev; + bool chromablu; + bool sigmadc; + bool deltad; + bool fatres; + bool clarilres; + bool claricres; + bool clarisoft; + bool sigmalc2; + bool strwav; + bool angwav; + bool strengthw; + bool sigmaed; + bool radiusw; + bool detailw; + bool gradw; + bool tloww; + bool thigw; + bool edgw; + bool basew; + bool sensilc; + bool fftwlc; + bool blurlc; + bool wavblur; + bool wavedg; + bool waveshow; + bool wavcont; + bool wavcomp; + bool wavgradl; + bool wavcompre; + bool origlc; + bool localcontMethod; + bool localedgMethod; + bool localneiMethod; + bool locwavcurve; + bool csthreshold; + bool loclevwavcurve; + bool locconwavcurve; + bool loccompwavcurve; + bool loccomprewavcurve; + bool locedgwavcurve; + bool CCmasklccurve; + bool LLmasklccurve; + bool HHmasklccurve; + bool enalcMask; + bool blendmasklc; + bool radmasklc; + bool chromasklc; + bool Lmasklccurve; + // Contrast by detail levels + bool visicbdl; + bool expcbdl; + bool complexcbdl; + bool mult[6]; + bool chromacbdl; + bool threshold; + bool sensicb; + bool clarityml; + bool contresid; + bool blurcbdl; + bool softradiuscb; + bool enacbMask; + bool CCmaskcbcurve; + bool LLmaskcbcurve; + bool HHmaskcbcurve; + bool blendmaskcb; + bool radmaskcb; + bool chromaskcb; + bool gammaskcb; + bool slomaskcb; + bool lapmaskcb; + bool Lmaskcbcurve; + // Log encoding + bool visilog; + bool explog; + bool autocompute; + bool sourceGray; + bool targetGray; + bool Autogray; + bool fullimage; + bool blackEv; + bool whiteEv; + bool detail; + bool sensilog; + bool baselog; + bool strlog; + bool anglog; + + LocallabSpotEdited(bool v); + + void set(bool v); + }; + + bool enabled; + bool selspot; + std::vector spots; +}; struct LensProfParamsEdited { bool lcpFile; @@ -512,6 +978,12 @@ struct WaveletParamsEdited { bool strength; bool balance; bool iter; + bool sigmafin; + bool sigmaton; + bool sigmacol; + bool sigmadir; + bool rangeab; + bool protab; bool median; bool medianlev; bool linkedg; @@ -584,6 +1056,7 @@ struct WaveletParamsEdited { bool level3noise; bool ccwcurve; bool blcurve; + bool opacityCurveSH; bool opacityCurveBY; bool opacityCurveRG; bool opacityCurveW; @@ -616,6 +1089,10 @@ struct WaveletParamsEdited { bool exptoning; bool expnoise; bool expclari; + bool labgridALow; + bool labgridBLow; + bool labgridAHigh; + bool labgridBHigh; }; struct DirPyrEqualizerParamsEdited { @@ -727,6 +1204,14 @@ struct RAWParamsEdited { bool ff_clipControl; bool exPos; + struct PreprocessWBParamsEdited { + bool mode; + + bool isUnchanged() const; + }; + + PreprocessWBParamsEdited preprocessWB; + bool isUnchanged() const; }; @@ -775,6 +1260,7 @@ struct ParamsEdited { LensProfParamsEdited lensProf; PerspectiveParamsEdited perspective; GradientParamsEdited gradient; + LocallabParamsEdited locallab; PCVignetteParamsEdited pcvignette; CACorrParamsEdited cacorrection; VignettingParamsEdited vignetting; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index b31852af2..6808a2cc6 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -17,10 +17,174 @@ * along with RawTherapee. If not, see . */ #include "partialpastedlg.h" + +#include "guiutils.h" #include "multilangmgr.h" #include "paramsedited.h" -#include "guiutils.h" +#include "../rtengine/procparams.h" + +using namespace rtengine::procparams; + +/* ==== PartialSpotWidget ==== */ +PartialSpotWidget::PartialSpotWidget(): + // Widget GUI elements + treeview(Gtk::manage(new Gtk::TreeView())), + treemodel(Gtk::ListStore::create(spotRow)), + + // Widget listener + selListener(nullptr) +{ + // Configure tree view + treeview->set_model(treemodel); + treeview->set_enable_search(false); + treeview->set_headers_visible(false); + + // Add tree view columns + auto cell1 = Gtk::manage(new Gtk::CellRendererToggle()); + cell1->signal_toggled().connect( + sigc::mem_fun( + *this, &PartialSpotWidget::keepToggled)); + int cols_count = treeview->append_column("", *cell1); + auto col = treeview->get_column(cols_count - 1); + + if (col) { + col->set_cell_data_func( + *cell1, sigc::mem_fun( + *this, &PartialSpotWidget::render_keep)); + } + + auto cell2 = Gtk::manage(new Gtk::CellRendererText()); + cols_count = treeview->append_column("", *cell2); + col = treeview->get_column(cols_count - 1); + + if (col) { + col->set_cell_data_func( + *cell2, sigc::mem_fun( + *this, &PartialSpotWidget::render_spotname)); + } + + // Create and configure scrolled window + Gtk::ScrolledWindow* const scrolledwindows = Gtk::manage(new Gtk::ScrolledWindow()); + scrolledwindows->add(*treeview); + scrolledwindows->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + scrolledwindows->set_min_content_height(100); + + // Add widgets to VBox + pack_start(*scrolledwindows); + show_all(); +} + +void PartialSpotWidget::updateSpotWidget(const rtengine::procparams::ProcParams* pp, const bool defValue) +{ + treeviewconn.block(true); + + // Clear tree model + treemodel->clear(); + + // Add tree model element according to pp + Gtk::TreeRow newspot; + + for (size_t i = 0; i < pp->locallab.spots.size(); i++) { + newspot = *(treemodel->append()); + newspot[spotRow.keep] = defValue; + newspot[spotRow.spotname] = pp->locallab.spots.at(i).name; + } + + treeviewconn.block(false); +} + +void PartialSpotWidget::enableAll() +{ + treeviewconn.block(true); + + for (auto &spot : treemodel->children()) { + spot[spotRow.keep] = true; + } + + treeviewconn.block(false); +} + +void PartialSpotWidget::disableAll() +{ + treeviewconn.block(true); + + for (auto &spot : treemodel->children()) { + spot[spotRow.keep] = false; + } + + treeviewconn.block(false); +} + +std::vector PartialSpotWidget::getSelectionStatus() +{ + std::vector keepVect; + + for (auto &spot : treemodel->children()) { + keepVect.push_back(spot[spotRow.keep]); + } + + return keepVect; +} + +void PartialSpotWidget::render_keep(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter) +{ + const auto spot = *iter; + Gtk::CellRendererToggle* const ct = static_cast(cell); + + // Render cell toggle + ct->property_active() = spot[spotRow.keep]; +} + +void PartialSpotWidget::render_spotname(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter) +{ + const auto spot = *iter; + Gtk::CellRendererText* const ct = static_cast(cell); + + // Render cell toggle + ct->property_text() = spot[spotRow.spotname]; +} + +void PartialSpotWidget::keepToggled(const Glib::ustring &path) +{ + PartialSpotWidgetListener::UpdateStatus status; + + // Get clicked row + const auto selRow = *(treemodel->get_iter(path)); + + // Update treeview according to selected row + selRow[spotRow.keep] = !selRow[spotRow.keep]; + + // Count total number of spot + const int totalnb = (int)treemodel->children().size(); + + // Count number of toggled elements + int togglednb = 0; + + for (auto &spot : treemodel->children()) { + if (spot[spotRow.keep]) { + togglednb++; + } + } + + // Compute status + if (togglednb == 0) { // No spot toggled + status = PartialSpotWidgetListener::UpdateStatus::NoSelection; + } else { + if (togglednb == totalnb) { // All spot toggled + status = PartialSpotWidgetListener::UpdateStatus::AllSelection; + } else { // Partial number of spots toggled + status = PartialSpotWidgetListener::UpdateStatus::PartialSelection; + } + } + + // Propagate event to listener + if (selListener) { + selListener->partialSpotUpdated(status); + } +} + +/* ==== PartialPasteDlg ==== */ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* parent) : Gtk::Dialog (title, *parent, true) { @@ -45,6 +209,8 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren raw ->set_name("PartialPasteHeader"); advanced = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_ADVANCEDGROUP"))); advanced ->set_name("PartialPasteHeader"); + locallab = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LOCALLABGROUP"))); + locallab ->set_name("PartialPasteHeader"); // Basic Settings: wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE"))); @@ -103,6 +269,10 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren exifch = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXIFCHANGES"))); iptc = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_IPTCINFO"))); + // Locallab: + spots = Gtk::manage(new PartialSpotWidget()); + spots->setPartialSpotWidgetListener(this); + // Raw Settings: raw_method = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_DMETHOD"))); raw_imagenum = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_IMAGENUM"))); @@ -134,15 +304,17 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren raw_ca_autocorrect = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_AUTO"))); raw_caredblue = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_CAREDBLUE"))); raw_ca_avoid_colourshift = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT"))); - //--- + //... filmNegative = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FILMNEGATIVE")) ); //--- captureSharpening = Gtk::manage (new Gtk::CheckButton (M("TP_PDSHARPENING_LABEL")) ); + //--- + raw_preprocwb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCWB"))); - Gtk::VBox* vboxes[8]; - Gtk::HSeparator* hseps[8]; + Gtk::VBox* vboxes[9]; + Gtk::HSeparator* hseps[9]; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 9; i++) { vboxes[i] = Gtk::manage (new Gtk::VBox ()); vboxes[i]->set_name("PartialPasteGroupContainer"); hseps[i] = Gtk::manage (new Gtk::HSeparator ()); @@ -213,49 +385,48 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[5]->pack_start (*colorappearance, Gtk::PACK_SHRINK, 2); vboxes[5]->pack_start (*wavelet, Gtk::PACK_SHRINK, 2); - //META - vboxes[6]->pack_start (*meta, Gtk::PACK_SHRINK, 2); + //LOCALLAB + vboxes[6]->pack_start(*locallab, Gtk::PACK_SHRINK, 2); + vboxes[6]->pack_start(*spots, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*hseps[6], Gtk::PACK_SHRINK, 2); - vboxes[6]->pack_start(*metadata, Gtk::PACK_SHRINK, 2); - vboxes[6]->pack_start (*exifch, Gtk::PACK_SHRINK, 2); - vboxes[6]->pack_start (*iptc, Gtk::PACK_SHRINK, 2); - //RAW - vboxes[7]->pack_start (*raw, Gtk::PACK_SHRINK, 2); + //META + vboxes[7]->pack_start (*meta, Gtk::PACK_SHRINK, 2); vboxes[7]->pack_start (*hseps[7], Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_method, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_border, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_imagenum, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_pixelshift, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_ccSteps, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_dcb_iterations, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_dcb_enhance, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_lmmse_iterations, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); - vboxes[7]->pack_start (*raw_linenoise, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_greenthresh, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_hotpix_filt, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_deadpix_filt, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_pdaf_lines_filter, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); - vboxes[7]->pack_start (*raw_expos, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_black, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); - vboxes[7]->pack_start (*df_file, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*df_AutoSelect, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); - vboxes[7]->pack_start (*ff_file, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*ff_AutoSelect, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*ff_BlurType, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*ff_BlurRadius, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*ff_ClipControl, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); - vboxes[7]->pack_start (*raw_ca_autocorrect, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_caredblue, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*raw_ca_avoid_colourshift, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); - vboxes[7]->pack_start (*filmNegative, Gtk::PACK_SHRINK, 2); - vboxes[7]->pack_start (*captureSharpening, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_method, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_border, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_imagenum, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_pixelshift, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_ccSteps, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_dcb_iterations, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_dcb_enhance, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_lmmse_iterations, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); + vboxes[8]->pack_start (*raw_linenoise, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_greenthresh, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_hotpix_filt, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_deadpix_filt, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_pdaf_lines_filter, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); + vboxes[8]->pack_start (*raw_expos, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_black, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_preprocwb, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); + vboxes[8]->pack_start (*df_file, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*df_AutoSelect, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); + vboxes[8]->pack_start (*ff_file, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*ff_AutoSelect, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*ff_BlurType, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*ff_BlurRadius, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*ff_ClipControl, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); + vboxes[8]->pack_start (*raw_ca_autocorrect, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_caredblue, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*raw_ca_avoid_colourshift, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); + vboxes[8]->pack_start (*filmNegative, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*captureSharpening, Gtk::PACK_SHRINK, 2); Gtk::VBox* vbCol1 = Gtk::manage (new Gtk::VBox ()); Gtk::VBox* vbCol2 = Gtk::manage (new Gtk::VBox ()); @@ -265,11 +436,11 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vbCol1->pack_start (*vboxes[i], Gtk::PACK_SHRINK, 2); } - for (int i = 3; i < 7; i++) { + for (int i = 3; i < 8; i++) { vbCol2->pack_start (*vboxes[i], Gtk::PACK_SHRINK, 2); } - for (int i = 7; i < 8; i++) { + for (int i = 8; i < 9; i++) { vbCol3->pack_start (*vboxes[i], Gtk::PACK_SHRINK, 2); } @@ -314,6 +485,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren metaConn = meta->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::metaToggled)); rawConn = raw->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::rawToggled)); advancedConn = advanced->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::advancedToggled)); + locallabConn = locallab->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::locallabToggled)); // Basic Settings wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); @@ -407,6 +579,8 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren filmNegativeConn = filmNegative->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); //--- captureSharpeningConn = captureSharpening->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + //--- + raw_preprocwbConn = raw_preprocwb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); add_button (M("GENERAL_OK"), Gtk::RESPONSE_OK); add_button (M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); @@ -426,6 +600,7 @@ void PartialPasteDlg::everythingToggled () ConnectionBlocker metaBlocker(metaConn); ConnectionBlocker rawBlocker(rawConn); ConnectionBlocker advancedBlocker(advancedConn); + ConnectionBlocker locallabBlocker(locallabConn); everything->set_inconsistent (false); @@ -438,6 +613,7 @@ void PartialPasteDlg::everythingToggled () meta->set_active(everything->get_active()); raw->set_active(everything->get_active()); advanced->set_active(everything->get_active()); + locallab->set_active(everything->get_active()); //toggle group children PartialPasteDlg::basicToggled (); @@ -448,6 +624,7 @@ void PartialPasteDlg::everythingToggled () PartialPasteDlg::metaToggled (); PartialPasteDlg::rawToggled (); PartialPasteDlg::advancedToggled (); + PartialPasteDlg::locallabToggled(); } void PartialPasteDlg::rawToggled () @@ -480,6 +657,7 @@ void PartialPasteDlg::rawToggled () ConnectionBlocker raw_ca_avoid_colourshiftBlocker(raw_ca_avoid_colourshiftconn); ConnectionBlocker filmNegativeBlocker(filmNegativeConn); ConnectionBlocker captureSharpeningBlocker(captureSharpeningConn); + ConnectionBlocker raw_preprocwbBlocker(raw_preprocwbConn); raw->set_inconsistent (false); @@ -510,6 +688,7 @@ void PartialPasteDlg::rawToggled () raw_ca_avoid_colourshift->set_active (raw->get_active ()); filmNegative->set_active (raw->get_active()); captureSharpening->set_active (raw->get_active()); + raw_preprocwb->set_active (raw->get_active()); } void PartialPasteDlg::basicToggled () @@ -654,6 +833,17 @@ void PartialPasteDlg::metaToggled () iptc->set_active (meta->get_active ()); } +void PartialPasteDlg::locallabToggled() +{ + locallab->set_inconsistent (false); + + if (locallab->get_active()) { + spots->enableAll(); + } else { + spots->disableAll(); + } +} + /* * Copies the selected items from the source ProcParams+ParamsEdited(optional) @@ -663,7 +853,9 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param { ParamsEdited falsePE; // falsePE is a workaround to set a group of ParamsEdited to false + falsePE.locallab.spots.resize(srcPP->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(false)); ParamsEdited filterPE(true); // Contains the initial information about the loaded values + filterPE.locallab.spots.resize(srcPP->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); if (srcPE) { filterPE = *srcPE; @@ -1000,10 +1192,69 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.pdsharpening.deconvitercheck = falsePE.pdsharpening.deconvitercheck; } - if (dstPE) { - *dstPE = filterPE; + if (!raw_preprocwb->get_active ()) { + filterPE.raw.preprocessWB.mode = falsePE.raw.preprocessWB.mode; } - // Apply the filter! - filterPE.combine(*dstPP, *srcPP, true); + // Locallab shall be kept in last position + if (!locallab->get_active () && !locallab->get_inconsistent()) { + filterPE.locallab = falsePE.locallab; + + if (dstPE) { + *dstPE = filterPE; + } + + // Apply the filter! + filterPE.combine(*dstPP, *srcPP, true); + } else { // Update PE and PP according to chosen spot + // Get chosen spots + std::vector chosenSpots = spots->getSelectionStatus(); + + // Create temporary PP and PE based on scrPP and scrPE + rtengine::procparams::ProcParams tmpPP = rtengine::procparams::ProcParams(*srcPP); + ParamsEdited tmpPE = ParamsEdited(filterPE); + + // Update tmpPP and tmpPE according to chosen spots + for (int i = ((int)chosenSpots.size() - 1); i >= 0; i--) { + if (!chosenSpots.at(i)) { + tmpPP.locallab.spots.erase(tmpPP.locallab.spots.begin() + i); + tmpPE.locallab.spots.erase(tmpPE.locallab.spots.begin() + i); + } + } + + if (dstPE) { + *dstPE = tmpPE; + } + + // Apply the filter! + tmpPE.combine(*dstPP, tmpPP, true); + } +} + +void PartialPasteDlg::updateSpotWidget(const rtengine::procparams::ProcParams* pp) +{ + locallab->set_inconsistent(false); + + if (pp->locallab.spots.size() > 0) { + spots->set_visible(true); + spots->updateSpotWidget(pp, locallab->get_active()); + } else { + spots->set_visible(false); // Hide widget if there is no locallab spot + } +} + +void PartialPasteDlg::partialSpotUpdated(const UpdateStatus status) +{ + switch (status) { + case (AllSelection): + locallab->set_active(true); + break; + + case (NoSelection): + locallab->set_active(false); + break; + + case (PartialSelection): + locallab->set_inconsistent(true); + } } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 75e18e83c..94bc2868c 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -34,7 +34,81 @@ class ProcParams; struct ParamsEdited; -class PartialPasteDlg final : public Gtk::Dialog +/* ==== PartialSpotWidgetListener ==== */ +class PartialSpotWidget; +class PartialSpotWidgetListener +{ +public: + enum UpdateStatus { + AllSelection = 1, + NoSelection = 2, + PartialSelection = 3 + }; + +public: + PartialSpotWidgetListener() {}; + virtual ~PartialSpotWidgetListener() {}; + + virtual void partialSpotUpdated(const UpdateStatus status) = 0; +}; + +/* ==== PartialSpotWidget ==== */ +class PartialSpotWidget: + public Gtk::VBox +{ +private: + // Tree model to manage spot selection widget + class SpotRow: + public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn keep; + Gtk::TreeModelColumn spotname; + + SpotRow() + { + add(keep); + add(spotname); + } + }; + + // Spot selection widgets + Gtk::TreeView* const treeview; + sigc::connection treeviewconn; + SpotRow spotRow; + Glib::RefPtr treemodel; + + // Spot selection listener + PartialSpotWidgetListener* selListener; + +public: + PartialSpotWidget(); + + // Setter for spot selection listener + void setPartialSpotWidgetListener(PartialSpotWidgetListener* pswl) + { + selListener = pswl; + } + + // Spot selection widget management functions + void updateSpotWidget(const rtengine::procparams::ProcParams* pp, const bool defValue); + void enableAll(); + void disableAll(); + std::vector getSelectionStatus(); + +private: + // GUI aspect management functions + void render_keep(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); + void render_spotname(Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); + + // Event management function + void keepToggled(const Glib::ustring &path); +}; + +/* ==== PartialPasteDlg ==== */ +class PartialPasteDlg final: + public Gtk::Dialog, + public PartialSpotWidgetListener { public: @@ -52,6 +126,7 @@ public: Gtk::CheckButton* meta; Gtk::CheckButton* raw; Gtk::CheckButton* advanced; + Gtk::CheckButton* locallab; // options in basic: Gtk::CheckButton* wb; @@ -111,6 +186,8 @@ public: Gtk::CheckButton* exifch; Gtk::CheckButton* iptc; + // options in locallab: + PartialSpotWidget* spots; // options in raw: Gtk::CheckButton* raw_expos; @@ -142,9 +219,10 @@ public: Gtk::CheckButton* filmNegative; Gtk::CheckButton* captureSharpening; + Gtk::CheckButton* raw_preprocwb; sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn; - + sigc::connection locallabConn; sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn; @@ -155,6 +233,7 @@ public: sigc::connection raw_caredblueConn, raw_ca_autocorrectConn, raw_ca_avoid_colourshiftconn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_pdaf_lines_filterConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_borderConn, raw_imagenumConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_pixelshiftConn, raw_dcb_enhanceConn, raw_exposConn, raw_blackConn; sigc::connection filmNegativeConn; sigc::connection captureSharpeningConn; + sigc::connection raw_preprocwbConn; public: PartialPasteDlg (const Glib::ustring &title, Gtk::Window* parent); @@ -170,4 +249,8 @@ public: void metaToggled (); void rawToggled (); void advancedToggled (); + void locallabToggled (); + + void updateSpotWidget(const rtengine::procparams::ProcParams* pp); + void partialSpotUpdated(const UpdateStatus status); }; diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index bdcc40a8b..8031772fd 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -50,6 +50,7 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M(" setCamBasedEventsActive(); lens_geom_listener = nullptr; + metadata = nullptr; Gtk::Image* ipers_draw_horiz = Gtk::manage (new RTImage ("draw-horizontal.png")); Gtk::Image* ipers_draw_vert = Gtk::manage (new RTImage ("draw-vertical.png")); diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 6a670733b..5aef01806 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,11 +1,13 @@ #pragma once // This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 347 +#define PPVERSION 348 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /* Log of version changes + 348 2018-09-25 + Added Locallab tool parameters 347 2019-11-17 added special values in filmNegative for backwards compatibility with previous channel scaling method 346 2019-01-01 diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 4edb4f2e2..aba30fbf2 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -56,49 +56,49 @@ extern Glib::ustring argv0; Glib::RefPtr themecss; Glib::RefPtr fontcss; -Preferences::Preferences (RTWindow *rtwindow) - : Gtk::Dialog (M ("MAIN_BUTTON_PREFERENCES"), *rtwindow, true) +Preferences::Preferences(RTWindow *rtwindow) + : Gtk::Dialog(M("MAIN_BUTTON_PREFERENCES"), *rtwindow, true) , regex(Glib::Regex::create (THEMEREGEXSTR, Glib::RegexCompileFlags::REGEX_CASELESS)) - , splash (nullptr) - , rprofiles (nullptr) - , iprofiles (nullptr) - , parent (rtwindow) - , newFont (false) - , newCPFont (false) + , splash(nullptr) + , rprofiles(nullptr) + , iprofiles(nullptr) + , parent(rtwindow) + , newFont(false) + , newCPFont(false) { - moptions.copyFrom (&options); + moptions.copyFrom(&options); - set_size_request (650, -1); - set_default_size (options.preferencesWidth, options.preferencesHeight); + set_size_request(650, -1); + set_default_size(options.preferencesWidth, options.preferencesHeight); - Pango::FontDescription defaultFont = get_style_context ()->get_font(); - initialFontFamily = defaultFont.get_family (); - initialFontSize = defaultFont.get_size () / Pango::SCALE; + Pango::FontDescription defaultFont = get_style_context()->get_font(); + initialFontFamily = defaultFont.get_family(); + initialFontSize = defaultFont.get_size() / Pango::SCALE; - Gtk::Box* mainBox = get_content_area (); + Gtk::Box* mainBox = get_content_area(); //GTK318 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20 - mainBox->set_spacing (8); + mainBox->set_spacing(8); #endif //GTK318 - Gtk::Notebook* nb = Gtk::manage (new Gtk::Notebook ()); + Gtk::Notebook* nb = Gtk::manage(new Gtk::Notebook()); nb->set_scrollable(true); - nb->set_name ("PrefNotebook"); - mainBox->pack_start (*nb); + nb->set_name("PrefNotebook"); + mainBox->pack_start(*nb); - Gtk::Button* about = Gtk::manage (new Gtk::Button (M ("GENERAL_ABOUT"))); - Gtk::Button* ok = Gtk::manage (new Gtk::Button (M ("GENERAL_OK"))); - Gtk::Button* cancel = Gtk::manage (new Gtk::Button (M ("GENERAL_CANCEL"))); + Gtk::Button* about = Gtk::manage(new Gtk::Button(M("GENERAL_ABOUT"))); + Gtk::Button* ok = Gtk::manage(new Gtk::Button(M("GENERAL_OK"))); + Gtk::Button* cancel = Gtk::manage(new Gtk::Button(M("GENERAL_CANCEL"))); - about->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::aboutPressed) ); - ok->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::okPressed) ); - cancel->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::cancelPressed) ); + about->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::aboutPressed)); + ok->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::okPressed)); + cancel->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::cancelPressed)); - get_action_area()->pack_start (*about); - get_action_area()->pack_end (*ok); - get_action_area()->pack_end (*cancel); + get_action_area()->pack_start(*about); + get_action_area()->pack_end(*ok); + get_action_area()->pack_end(*cancel); nb->append_page(*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL")); nb->append_page(*getImageProcessingPanel(), M("PREFERENCES_TAB_IMPROC")); @@ -111,29 +111,29 @@ Preferences::Preferences (RTWindow *rtwindow) #if defined(WIN32) || defined(__linux__) nb->append_page(*getSoundsPanel(), M("PREFERENCES_TAB_SOUND")); #endif - nb->set_current_page (0); + nb->set_current_page(0); - ProfileStore::getInstance()->addListener (this); + ProfileStore::getInstance()->addListener(this); - fillPreferences (); + fillPreferences(); - show_all_children (); + show_all_children(); } -Preferences::~Preferences () +Preferences::~Preferences() { - ProfileStore::getInstance()->removeListener (this); - get_size (options.preferencesWidth, options.preferencesHeight); + ProfileStore::getInstance()->removeListener(this); + get_size(options.preferencesWidth, options.preferencesHeight); } int Preferences::getThemeRowNumber (const Glib::ustring& longThemeFName) { - if (regex->match (longThemeFName + ".css", matchInfo)) { + if (regex->match(longThemeFName + ".css", matchInfo)) { for (size_t i = 0 ; i < themeFNames.size(); ++i) { - if (themeFNames.at (i).longFName == longThemeFName) { + if (themeFNames.at(i).longFName == longThemeFName) { return (int)i; } } @@ -142,43 +142,43 @@ int Preferences::getThemeRowNumber (const Glib::ustring& longThemeFName) return -1; } -Gtk::Widget* Preferences::getBatchProcPanel () +Gtk::Widget* Preferences::getBatchProcPanel() { swBatchProc = Gtk::manage(new Gtk::ScrolledWindow()); swBatchProc->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); Gtk::VBox* vbBatchProc = Gtk::manage (new Gtk::VBox ()); - Gtk::ScrolledWindow* behscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); - behscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - behscrollw->set_size_request (-1, 60); - Gtk::VBox* vbbeh = Gtk::manage ( new Gtk::VBox () ); - vbbeh->pack_start (*behscrollw, Gtk::PACK_EXPAND_WIDGET); - Gtk::Frame* behFrame = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_BEHAVIOR"))); - behFrame->add (*vbbeh); + Gtk::ScrolledWindow* behscrollw = Gtk::manage(new Gtk::ScrolledWindow()); + behscrollw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + behscrollw->set_size_request(-1, 60); + Gtk::VBox* vbbeh = Gtk::manage(new Gtk::VBox()); + vbbeh->pack_start(*behscrollw, Gtk::PACK_EXPAND_WIDGET); + Gtk::Frame* behFrame = Gtk::manage(new Gtk::Frame(M("PREFERENCES_BEHAVIOR"))); + behFrame->add(*vbbeh); vbBatchProc->pack_start (*behFrame, Gtk::PACK_EXPAND_WIDGET, 4); - Gtk::TreeView* behTreeView = Gtk::manage (new Gtk::TreeView ()); - behscrollw->add (*behTreeView); + Gtk::TreeView* behTreeView = Gtk::manage(new Gtk::TreeView()); + behscrollw->add(*behTreeView); - behModel = Gtk::TreeStore::create (behavColumns); - behTreeView->set_model (behModel); + behModel = Gtk::TreeStore::create(behavColumns); + behTreeView->set_model(behModel); - behTreeView->append_column (M ("PREFERENCES_PROPERTY"), behavColumns.label); - behTreeView->append_column_editable (M ("PREFERENCES_ADD"), behavColumns.badd); - behTreeView->append_column_editable (M ("PREFERENCES_SET"), behavColumns.bset); + behTreeView->append_column(M("PREFERENCES_PROPERTY"), behavColumns.label); + behTreeView->append_column_editable(M("PREFERENCES_ADD"), behavColumns.badd); + behTreeView->append_column_editable(M("PREFERENCES_SET"), behavColumns.bset); - Gtk::CellRendererToggle* cr_add = static_cast (behTreeView->get_column (1)->get_first_cell()); - Gtk::CellRendererToggle* cr_set = static_cast (behTreeView->get_column (2)->get_first_cell()); + Gtk::CellRendererToggle* cr_add = static_cast(behTreeView->get_column(1)->get_first_cell()); + Gtk::CellRendererToggle* cr_set = static_cast(behTreeView->get_column(2)->get_first_cell()); - cr_add->set_radio (true); - cr_add->set_property ("xalign", 0.0f); - sigc::connection addc = cr_add->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behAddRadioToggled)); - cr_set->set_radio (true); - cr_set->set_property ("xalign", 0.0f); - sigc::connection setc = cr_set->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behSetRadioToggled)); + cr_add->set_radio(true); + cr_add->set_property("xalign", 0.0f); + sigc::connection addc = cr_add->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::behAddRadioToggled)); + cr_set->set_radio(true); + cr_set->set_property("xalign", 0.0f); + sigc::connection setc = cr_set->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::behSetRadioToggled)); - behTreeView->get_column (1)->add_attribute (*cr_add, "visible", behavColumns.visible); - behTreeView->get_column (2)->add_attribute (*cr_set, "visible", behavColumns.visible); + behTreeView->get_column(1)->add_attribute(*cr_add, "visible", behavColumns.visible); + behTreeView->get_column(2)->add_attribute(*cr_set, "visible", behavColumns.visible); // fill model Gtk::TreeModel::iterator mi, ci; @@ -186,62 +186,62 @@ Gtk::Widget* Preferences::getBatchProcPanel () /* * The TRUE/FALSE values of appendBehavList are replaced by the one defined in options.cc, */ - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_EXPOSURE_LABEL")); - appendBehavList (mi, M ("TP_EXPOSURE_EXPCOMP"), ADDSET_TC_EXPCOMP, false); - appendBehavList (mi, M ("TP_EXPOSURE_COMPRHIGHLIGHTS"), ADDSET_TC_HLCOMPAMOUNT, false); - appendBehavList (mi, M ("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), ADDSET_TC_HLCOMPTHRESH, false); - appendBehavList (mi, M ("TP_EXPOSURE_BLACKLEVEL"), ADDSET_TC_BLACKLEVEL, false); - appendBehavList (mi, M ("TP_EXPOSURE_COMPRSHADOWS"), ADDSET_TC_SHCOMP, false); - appendBehavList (mi, M ("TP_EXPOSURE_BRIGHTNESS"), ADDSET_TC_BRIGHTNESS, false); - appendBehavList (mi, M ("TP_EXPOSURE_CONTRAST"), ADDSET_TC_CONTRAST, false); - appendBehavList (mi, M ("TP_EXPOSURE_SATURATION"), ADDSET_TC_SATURATION, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_EXPOSURE_LABEL")); + appendBehavList(mi, M("TP_EXPOSURE_EXPCOMP"), ADDSET_TC_EXPCOMP, false); + appendBehavList(mi, M("TP_EXPOSURE_COMPRHIGHLIGHTS"), ADDSET_TC_HLCOMPAMOUNT, false); + appendBehavList(mi, M("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), ADDSET_TC_HLCOMPTHRESH, false); + appendBehavList(mi, M("TP_EXPOSURE_BLACKLEVEL"), ADDSET_TC_BLACKLEVEL, false); + appendBehavList(mi, M("TP_EXPOSURE_COMPRSHADOWS"), ADDSET_TC_SHCOMP, false); + appendBehavList(mi, M("TP_EXPOSURE_BRIGHTNESS"), ADDSET_TC_BRIGHTNESS, false); + appendBehavList(mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_TC_CONTRAST, false); + appendBehavList(mi, M("TP_EXPOSURE_SATURATION"), ADDSET_TC_SATURATION, false); mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_EPD_LABEL")); - appendBehavList (mi, M ("TP_EPD_STRENGTH"), ADDSET_EPD_STRENGTH, false); - appendBehavList (mi, M ("TP_EPD_GAMMA"), ADDSET_EPD_GAMMA, false); - appendBehavList (mi, M ("TP_EPD_EDGESTOPPING"), ADDSET_EPD_EDGESTOPPING, false); - appendBehavList (mi, M ("TP_EPD_SCALE"), ADDSET_EPD_SCALE, false); - appendBehavList (mi, M ("TP_EPD_REWEIGHTINGITERATES"), ADDSET_EPD_REWEIGHTINGITERATES, false); + mi->set_value(behavColumns.label, M("TP_EPD_LABEL")); + appendBehavList(mi, M("TP_EPD_STRENGTH"), ADDSET_EPD_STRENGTH, false); + appendBehavList(mi, M("TP_EPD_GAMMA"), ADDSET_EPD_GAMMA, false); + appendBehavList(mi, M("TP_EPD_EDGESTOPPING"), ADDSET_EPD_EDGESTOPPING, false); + appendBehavList(mi, M("TP_EPD_SCALE"), ADDSET_EPD_SCALE, false); + appendBehavList(mi, M("TP_EPD_REWEIGHTINGITERATES"), ADDSET_EPD_REWEIGHTINGITERATES, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_TM_FATTAL_LABEL")); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_TM_FATTAL_LABEL")); appendBehavList (mi, M ("TP_TM_FATTAL_AMOUNT"), ADDSET_FATTAL_AMOUNT, false); appendBehavList (mi, M ("TP_TM_FATTAL_THRESHOLD"), ADDSET_FATTAL_THRESHOLD, false); appendBehavList (mi, M ("TP_TM_FATTAL_ANCHOR"), ADDSET_FATTAL_ANCHOR, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_RETINEX_LABEL")); - appendBehavList (mi, M ("TP_RETINEX_STRENGTH"), ADDSET_RETI_STR, false); - appendBehavList (mi, M ("TP_RETINEX_NEIGHBOR"), ADDSET_RETI_NEIGH, false); - appendBehavList (mi, M ("TP_RETINEX_VARIANCE"), ADDSET_RETI_VART, false); - appendBehavList (mi, M ("TP_RETINEX_GAMMA"), ADDSET_RETI_GAM, false); - appendBehavList (mi, M ("TP_RETINEX_SLOPE"), ADDSET_RETI_SLO, false); - appendBehavList (mi, M ("TP_RETINEX_GAIN"), ADDSET_RETI_GAIN, false); - appendBehavList (mi, M ("TP_RETINEX_OFFSET"), ADDSET_RETI_OFFS, false); - appendBehavList (mi, M ("TP_RETINEX_THRESHOLD"), ADDSET_RETI_LIMD, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_RETINEX_LABEL")); + appendBehavList(mi, M("TP_RETINEX_STRENGTH"), ADDSET_RETI_STR, false); + appendBehavList(mi, M("TP_RETINEX_NEIGHBOR"), ADDSET_RETI_NEIGH, false); + appendBehavList(mi, M("TP_RETINEX_VARIANCE"), ADDSET_RETI_VART, false); + appendBehavList(mi, M("TP_RETINEX_GAMMA"), ADDSET_RETI_GAM, false); + appendBehavList(mi, M("TP_RETINEX_SLOPE"), ADDSET_RETI_SLO, false); + appendBehavList(mi, M("TP_RETINEX_GAIN"), ADDSET_RETI_GAIN, false); + appendBehavList(mi, M("TP_RETINEX_OFFSET"), ADDSET_RETI_OFFS, false); + appendBehavList(mi, M("TP_RETINEX_THRESHOLD"), ADDSET_RETI_LIMD, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_SHADOWSHLIGHTS_LABEL")); - appendBehavList (mi, M ("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), ADDSET_SH_HIGHLIGHTS, false); - appendBehavList (mi, M ("TP_SHADOWSHLIGHTS_SHADOWS"), ADDSET_SH_SHADOWS, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_SHADOWSHLIGHTS_LABEL")); + appendBehavList(mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), ADDSET_SH_HIGHLIGHTS, false); + appendBehavList(mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), ADDSET_SH_SHADOWS, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_LABCURVE_LABEL")); - appendBehavList (mi, M ("TP_LABCURVE_BRIGHTNESS"), ADDSET_LC_BRIGHTNESS, false); - appendBehavList (mi, M ("TP_LABCURVE_CONTRAST"), ADDSET_LC_CONTRAST, false); - appendBehavList (mi, M ("TP_LABCURVE_CHROMATICITY"), ADDSET_LC_CHROMATICITY, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_LABCURVE_LABEL")); + appendBehavList(mi, M("TP_LABCURVE_BRIGHTNESS"), ADDSET_LC_BRIGHTNESS, false); + appendBehavList(mi, M("TP_LABCURVE_CONTRAST"), ADDSET_LC_CONTRAST, false); + appendBehavList(mi, M("TP_LABCURVE_CHROMATICITY"), ADDSET_LC_CHROMATICITY, false); - mi = behModel->append (); // Used for both Resize and Post-Resize sharpening - mi->set_value (behavColumns.label, M ("TP_SHARPENING_LABEL")); + mi = behModel->append(); // Used for both Resize and Post-Resize sharpening + mi->set_value(behavColumns.label, M("TP_SHARPENING_LABEL")); appendBehavList (mi, M ("TP_SHARPENING_CONTRAST"), ADDSET_SHARP_CONTRAST, false); - appendBehavList (mi, M ("TP_SHARPENING_RADIUS"), ADDSET_SHARP_RADIUS, false); - appendBehavList (mi, M ("TP_SHARPENING_AMOUNT"), ADDSET_SHARP_AMOUNT, false); - appendBehavList (mi, M ("TP_SHARPENING_RLD_DAMPING"), ADDSET_SHARP_DAMPING, false); - appendBehavList (mi, M ("TP_SHARPENING_RLD_ITERATIONS"), ADDSET_SHARP_ITER, false); - appendBehavList (mi, M ("TP_SHARPENING_EDTOLERANCE"), ADDSET_SHARP_EDGETOL, false); - appendBehavList (mi, M ("TP_SHARPENING_HALOCONTROL"), ADDSET_SHARP_HALOCTRL, false); + appendBehavList(mi, M("TP_SHARPENING_RADIUS"), ADDSET_SHARP_RADIUS, false); + appendBehavList(mi, M("TP_SHARPENING_AMOUNT"), ADDSET_SHARP_AMOUNT, false); + appendBehavList(mi, M("TP_SHARPENING_RLD_DAMPING"), ADDSET_SHARP_DAMPING, false); + appendBehavList(mi, M("TP_SHARPENING_RLD_ITERATIONS"), ADDSET_SHARP_ITER, false); + appendBehavList(mi, M("TP_SHARPENING_EDTOLERANCE"), ADDSET_SHARP_EDGETOL, false); + appendBehavList(mi, M("TP_SHARPENING_HALOCONTROL"), ADDSET_SHARP_HALOCTRL, false); mi = behModel->append(); mi->set_value(behavColumns.label, M("TP_LOCALCONTRAST_LABEL")); @@ -250,19 +250,19 @@ Gtk::Widget* Preferences::getBatchProcPanel () appendBehavList(mi, M("TP_LOCALCONTRAST_DARKNESS"), ADDSET_LOCALCONTRAST_DARKNESS, false); appendBehavList(mi, M("TP_LOCALCONTRAST_LIGHTNESS"), ADDSET_LOCALCONTRAST_LIGHTNESS, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_SHARPENEDGE_LABEL")); - appendBehavList (mi, M ("TP_SHARPENEDGE_PASSES"), ADDSET_SHARPENEDGE_PASS, false); - appendBehavList (mi, M ("TP_SHARPENEDGE_AMOUNT"), ADDSET_SHARPENEDGE_AMOUNT, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_SHARPENEDGE_LABEL")); + appendBehavList(mi, M("TP_SHARPENEDGE_PASSES"), ADDSET_SHARPENEDGE_PASS, false); + appendBehavList(mi, M("TP_SHARPENEDGE_AMOUNT"), ADDSET_SHARPENEDGE_AMOUNT, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_SHARPENMICRO_LABEL")); - appendBehavList (mi, M ("TP_SHARPENMICRO_AMOUNT"), ADDSET_SHARPENMICRO_AMOUNT, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_SHARPENMICRO_LABEL")); + appendBehavList(mi, M("TP_SHARPENMICRO_AMOUNT"), ADDSET_SHARPENMICRO_AMOUNT, false); appendBehavList (mi, M ("TP_SHARPENMICRO_CONTRAST"), ADDSET_SHARPENMICRO_CONTRAST, false); - appendBehavList (mi, M ("TP_SHARPENMICRO_UNIFORMITY"), ADDSET_SHARPENMICRO_UNIFORMITY, false); + appendBehavList(mi, M("TP_SHARPENMICRO_UNIFORMITY"), ADDSET_SHARPENMICRO_UNIFORMITY, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_DIRPYRDENOISE_LABEL")); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_DIRPYRDENOISE_LABEL")); appendBehavList (mi, M ("TP_DIRPYRDENOISE_LUMINANCE_SMOOTHING"), ADDSET_DIRPYRDN_LUMA, true); appendBehavList (mi, M ("TP_DIRPYRDENOISE_LUMINANCE_DETAIL"), ADDSET_DIRPYRDN_LUMDET, true); appendBehavList (mi, M ("TP_DIRPYRDENOISE_CHROMINANCE_MASTER"), ADDSET_DIRPYRDN_CHROMA, true); @@ -271,142 +271,142 @@ Gtk::Widget* Preferences::getBatchProcPanel () appendBehavList (mi, M ("TP_DIRPYRDENOISE_MAIN_GAMMA"), ADDSET_DIRPYRDN_GAMMA, true); appendBehavList (mi, M ("TP_DIRPYRDENOISE_MEDIAN_PASSES"), ADDSET_DIRPYRDN_PASSES, true); - mi = behModel->append (); + mi = behModel->append(); mi->set_value ( behavColumns.label, M ("TP_DEHAZE_LABEL") ); appendBehavList ( mi, M ( "TP_DEHAZE_STRENGTH" ), ADDSET_DEHAZE_STRENGTH, true ); mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_WBALANCE_LABEL")); - appendBehavList (mi, M ("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true); - appendBehavList (mi, M ("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true); - appendBehavList (mi, M ("TP_WBALANCE_EQBLUERED"), ADDSET_WB_EQUAL, true); - appendBehavList (mi, M ("TP_WBALANCE_TEMPBIAS"), ADDSET_WB_TEMPBIAS, true); + mi->set_value(behavColumns.label, M("TP_WBALANCE_LABEL")); + appendBehavList(mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true); + appendBehavList(mi, M("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true); + appendBehavList(mi, M("TP_WBALANCE_EQBLUERED"), ADDSET_WB_EQUAL, true); + appendBehavList(mi, M("TP_WBALANCE_TEMPBIAS"), ADDSET_WB_TEMPBIAS, true); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_COLORAPP_LABEL")); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_COLORAPP_LABEL")); appendBehavList (mi, M("TP_COLORAPP_LABEL_SCENE") + " - " + M("TP_COLORAPP_ABSOLUTELUMINANCE"), ADDSET_CAT_ADAPTSCENE, true); appendBehavList (mi, M("TP_COLORAPP_LABEL_VIEWING") + " - " + M("TP_COLORAPP_ABSOLUTELUMINANCE"), ADDSET_CAT_ADAPTVIEWING, true); - appendBehavList (mi, M ("TP_COLORAPP_LIGHT"), ADDSET_CAT_LIGHT, true); - appendBehavList (mi, M ("TP_COLORAPP_BRIGHT"), ADDSET_CAT_BRIGHT, true); - appendBehavList (mi, M ("TP_COLORAPP_CHROMA"), ADDSET_CAT_CHROMA, true); + appendBehavList(mi, M("TP_COLORAPP_LIGHT"), ADDSET_CAT_LIGHT, true); + appendBehavList(mi, M("TP_COLORAPP_BRIGHT"), ADDSET_CAT_BRIGHT, true); + appendBehavList(mi, M("TP_COLORAPP_CHROMA"), ADDSET_CAT_CHROMA, true); appendBehavList (mi, M ("TP_COLORAPP_CHROMA_S"), ADDSET_CAT_CHROMA_S, true); appendBehavList (mi, M ("TP_COLORAPP_CHROMA_M"), ADDSET_CAT_CHROMA_M, true); - appendBehavList (mi, M ("TP_COLORAPP_RSTPRO"), ADDSET_CAT_RSTPRO, true); - appendBehavList (mi, M ("TP_COLORAPP_CONTRAST"), ADDSET_CAT_CONTRAST, true); - appendBehavList (mi, M ("TP_COLORAPP_CONTRAST_Q"), ADDSET_CAT_CONTRAST_Q, true); - appendBehavList (mi, M ("TP_COLORAPP_HUE"), ADDSET_CAT_HUE, true); - appendBehavList (mi, M ("TP_COLORAPP_BADPIXSL"), ADDSET_CAT_BADPIX, true); + appendBehavList(mi, M("TP_COLORAPP_RSTPRO"), ADDSET_CAT_RSTPRO, true); + appendBehavList(mi, M("TP_COLORAPP_CONTRAST"), ADDSET_CAT_CONTRAST, true); + appendBehavList(mi, M("TP_COLORAPP_CONTRAST_Q"), ADDSET_CAT_CONTRAST_Q, true); + appendBehavList(mi, M("TP_COLORAPP_HUE"), ADDSET_CAT_HUE, true); + appendBehavList(mi, M("TP_COLORAPP_BADPIXSL"), ADDSET_CAT_BADPIX, true); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_VIBRANCE_LABEL")); - appendBehavList (mi, M ("TP_VIBRANCE_PASTELS"), ADDSET_VIBRANCE_PASTELS, false); - appendBehavList (mi, M ("TP_VIBRANCE_SATURATED"), ADDSET_VIBRANCE_SATURATED, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_VIBRANCE_LABEL")); + appendBehavList(mi, M("TP_VIBRANCE_PASTELS"), ADDSET_VIBRANCE_PASTELS, false); + appendBehavList(mi, M("TP_VIBRANCE_SATURATED"), ADDSET_VIBRANCE_SATURATED, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_CHMIXER_LABEL")); - appendBehavList (mi, M ("TP_CHMIXER_RED") + ", " + M ("TP_CHMIXER_GREEN") + ", " + M ("TP_CHMIXER_BLUE"), ADDSET_CHMIXER, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_CHMIXER_LABEL")); + appendBehavList(mi, M("TP_CHMIXER_RED") + ", " + M("TP_CHMIXER_GREEN") + ", " + M("TP_CHMIXER_BLUE"), ADDSET_CHMIXER, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_BWMIX_LABEL")); - appendBehavList (mi, M ("TP_BWMIX_MIXC"), ADDSET_BLACKWHITE_HUES, false); - appendBehavList (mi, M ("TP_BWMIX_GAMMA"), ADDSET_BLACKWHITE_GAMMA, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_BWMIX_LABEL")); + appendBehavList(mi, M("TP_BWMIX_MIXC"), ADDSET_BLACKWHITE_HUES, false); + appendBehavList(mi, M("TP_BWMIX_GAMMA"), ADDSET_BLACKWHITE_GAMMA, false); - mi = behModel->append (); - mi->set_value ( behavColumns.label, M ("TP_FILMSIMULATION_LABEL") ); - appendBehavList ( mi, M ( "TP_FILMSIMULATION_STRENGTH" ), ADDSET_FILMSIMULATION_STRENGTH, true ); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_FILMSIMULATION_LABEL")); + appendBehavList(mi, M("TP_FILMSIMULATION_STRENGTH"), ADDSET_FILMSIMULATION_STRENGTH, true); - mi = behModel->append (); + mi = behModel->append(); mi->set_value ( behavColumns.label, M ("TP_SOFTLIGHT_LABEL") ); appendBehavList ( mi, M ( "TP_SOFTLIGHT_STRENGTH" ), ADDSET_SOFTLIGHT_STRENGTH, true ); mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_COLORTONING_LABEL")); - appendBehavList (mi, M ("TP_COLORTONING_SPLITCOCO"), ADDSET_COLORTONING_SPLIT, true); - appendBehavList (mi, M ("TP_COLORTONING_SATURATIONTHRESHOLD"), ADDSET_COLORTONING_SATTHRESHOLD, true); - appendBehavList (mi, M ("TP_COLORTONING_SATURATEDOPACITY"), ADDSET_COLORTONING_SATOPACITY, true); - appendBehavList (mi, M ("TP_COLORTONING_BALANCE"), ADDSET_COLORTONING_BALANCE, true); - appendBehavList (mi, M ("TP_COLORTONING_STRENGTH"), ADDSET_COLORTONING_STRENGTH, true); + mi->set_value(behavColumns.label, M("TP_COLORTONING_LABEL")); + appendBehavList(mi, M("TP_COLORTONING_SPLITCOCO"), ADDSET_COLORTONING_SPLIT, true); + appendBehavList(mi, M("TP_COLORTONING_SATURATIONTHRESHOLD"), ADDSET_COLORTONING_SATTHRESHOLD, true); + appendBehavList(mi, M("TP_COLORTONING_SATURATEDOPACITY"), ADDSET_COLORTONING_SATOPACITY, true); + appendBehavList(mi, M("TP_COLORTONING_BALANCE"), ADDSET_COLORTONING_BALANCE, true); + appendBehavList(mi, M("TP_COLORTONING_STRENGTH"), ADDSET_COLORTONING_STRENGTH, true); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_ROTATE_LABEL")); - appendBehavList (mi, M ("TP_ROTATE_DEGREE"), ADDSET_ROTATE_DEGREE, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_ROTATE_LABEL")); + appendBehavList(mi, M("TP_ROTATE_DEGREE"), ADDSET_ROTATE_DEGREE, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_RESIZE_LABEL")); - appendBehavList (mi, M ("TP_RESIZE_SCALE"), ADDSET_RESIZE_SCALE, true); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_RESIZE_LABEL")); + appendBehavList(mi, M("TP_RESIZE_SCALE"), ADDSET_RESIZE_SCALE, true); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_DISTORTION_LABEL")); - appendBehavList (mi, M ("TP_DISTORTION_AMOUNT"), ADDSET_DIST_AMOUNT, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_DISTORTION_LABEL")); + appendBehavList(mi, M("TP_DISTORTION_AMOUNT"), ADDSET_DIST_AMOUNT, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_PERSPECTIVE_LABEL")); - appendBehavList (mi, M ("TP_PERSPECTIVE_METHOD_SIMPLE") + " - " + M ("TP_PERSPECTIVE_HORIZONTAL") + ", " + M ("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, false); - appendBehavList (mi, M ("TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH") + ", " + M ("TP_PERSPECTIVE_CAMERA_CROP_FACTOR"), ADDSET_PERSP_CAM_FOCAL_LENGTH, false); - appendBehavList (mi, M ("TP_PERSPECTIVE_CAMERA_FRAME") + " - " + M ("TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL") + ", " + M ("TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL"), ADDSET_PERSP_CAM_SHIFT, false); - appendBehavList (mi, M ("TP_PERSPECTIVE_CAMERA_FRAME") + " - " + M ("TP_PERSPECTIVE_CAMERA_ROLL") + ", " + M ("TP_PERSPECTIVE_CAMERA_YAW") + ", " + M ("TP_PERSPECTIVE_CAMERA_PITCH"), ADDSET_PERSP_CAM_ANGLE, false); - appendBehavList (mi, M ("TP_PERSPECTIVE_POST_CORRECTION_ADJUSTMENT_FRAME") + " - " + M ("TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL") + ", " + M ("TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL"), ADDSET_PERSP_PROJ_SHIFT, false); - appendBehavList (mi, M ("TP_PERSPECTIVE_PROJECTION_ROTATE"), ADDSET_PERSP_PROJ_ROTATE, false); - appendBehavList (mi, M ("TP_PERSPECTIVE_RECOVERY_FRAME") + " - " + M ("TP_PERSPECTIVE_PROJECTION_YAW") + ", " + M ("TP_PERSPECTIVE_PROJECTION_PITCH"), ADDSET_PERSP_PROJ_ANGLE, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_PERSPECTIVE_LABEL")); + appendBehavList(mi, M("TP_PERSPECTIVE_METHOD_SIMPLE") + " - " + M("TP_PERSPECTIVE_HORIZONTAL") + ", " + M("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, false); + appendBehavList(mi, M("TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH") + ", " + M("TP_PERSPECTIVE_CAMERA_CROP_FACTOR"), ADDSET_PERSP_CAM_FOCAL_LENGTH, false); + appendBehavList(mi, M("TP_PERSPECTIVE_CAMERA_FRAME") + " - " + M("TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL") + ", " + M("TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL"), ADDSET_PERSP_CAM_SHIFT, false); + appendBehavList(mi, M("TP_PERSPECTIVE_CAMERA_FRAME") + " - " + M("TP_PERSPECTIVE_CAMERA_ROLL") + ", " + M("TP_PERSPECTIVE_CAMERA_YAW") + ", " + M("TP_PERSPECTIVE_CAMERA_PITCH"), ADDSET_PERSP_CAM_ANGLE, false); + appendBehavList(mi, M("TP_PERSPECTIVE_POST_CORRECTION_ADJUSTMENT_FRAME") + " - " + M("TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL") + ", " + M("TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL"), ADDSET_PERSP_PROJ_SHIFT, false); + appendBehavList(mi, M("TP_PERSPECTIVE_PROJECTION_ROTATE"), ADDSET_PERSP_PROJ_ROTATE, false); + appendBehavList(mi, M("TP_PERSPECTIVE_RECOVERY_FRAME") + " - " + M("TP_PERSPECTIVE_PROJECTION_YAW") + ", " + M("TP_PERSPECTIVE_PROJECTION_PITCH"), ADDSET_PERSP_PROJ_ANGLE, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_GRADIENT_LABEL")); - appendBehavList (mi, M ("TP_GRADIENT_DEGREE"), ADDSET_GRADIENT_DEGREE, false); - appendBehavList (mi, M ("TP_GRADIENT_FEATHER"), ADDSET_GRADIENT_FEATHER, false); - appendBehavList (mi, M ("TP_GRADIENT_STRENGTH"), ADDSET_GRADIENT_STRENGTH, false); - appendBehavList (mi, M ("TP_GRADIENT_CENTER_X") + ", " + M ("TP_GRADIENT_CENTER_Y"), ADDSET_GRADIENT_CENTER, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_GRADIENT_LABEL")); + appendBehavList(mi, M("TP_GRADIENT_DEGREE"), ADDSET_GRADIENT_DEGREE, false); + appendBehavList(mi, M("TP_GRADIENT_FEATHER"), ADDSET_GRADIENT_FEATHER, false); + appendBehavList(mi, M("TP_GRADIENT_STRENGTH"), ADDSET_GRADIENT_STRENGTH, false); + appendBehavList(mi, M("TP_GRADIENT_CENTER_X") + ", " + M("TP_GRADIENT_CENTER_Y"), ADDSET_GRADIENT_CENTER, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_PCVIGNETTE_LABEL")); - appendBehavList (mi, M ("TP_PCVIGNETTE_STRENGTH"), ADDSET_PCVIGNETTE_STRENGTH, false); - appendBehavList (mi, M ("TP_PCVIGNETTE_FEATHER"), ADDSET_PCVIGNETTE_FEATHER, false); - appendBehavList (mi, M ("TP_PCVIGNETTE_ROUNDNESS"), ADDSET_PCVIGNETTE_ROUNDNESS, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_PCVIGNETTE_LABEL")); + appendBehavList(mi, M("TP_PCVIGNETTE_STRENGTH"), ADDSET_PCVIGNETTE_STRENGTH, false); + appendBehavList(mi, M("TP_PCVIGNETTE_FEATHER"), ADDSET_PCVIGNETTE_FEATHER, false); + appendBehavList(mi, M("TP_PCVIGNETTE_ROUNDNESS"), ADDSET_PCVIGNETTE_ROUNDNESS, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_CACORRECTION_LABEL")); - appendBehavList (mi, M ("TP_CACORRECTION_BLUE") + ", " + M ("TP_CACORRECTION_RED"), ADDSET_CA, true); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_CACORRECTION_LABEL")); + appendBehavList(mi, M("TP_CACORRECTION_BLUE") + ", " + M("TP_CACORRECTION_RED"), ADDSET_CA, true); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_VIGNETTING_LABEL")); - appendBehavList (mi, M ("TP_VIGNETTING_AMOUNT"), ADDSET_VIGN_AMOUNT, false); - appendBehavList (mi, M ("TP_VIGNETTING_RADIUS"), ADDSET_VIGN_RADIUS, false); - appendBehavList (mi, M ("TP_VIGNETTING_STRENGTH"), ADDSET_VIGN_STRENGTH, false); - appendBehavList (mi, M ("TP_VIGNETTING_CENTER_X") + ", " + M ("TP_VIGNETTING_CENTER_Y"), ADDSET_VIGN_CENTER, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_VIGNETTING_LABEL")); + appendBehavList(mi, M("TP_VIGNETTING_AMOUNT"), ADDSET_VIGN_AMOUNT, false); + appendBehavList(mi, M("TP_VIGNETTING_RADIUS"), ADDSET_VIGN_RADIUS, false); + appendBehavList(mi, M("TP_VIGNETTING_STRENGTH"), ADDSET_VIGN_STRENGTH, false); + appendBehavList(mi, M("TP_VIGNETTING_CENTER_X") + ", " + M("TP_VIGNETTING_CENTER_Y"), ADDSET_VIGN_CENTER, false); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_DIRPYREQUALIZER_LABEL")); - appendBehavList (mi, M ("TP_EXPOSURE_CONTRAST"), ADDSET_DIRPYREQ, true); - appendBehavList (mi, M ("TP_DIRPYREQUALIZER_THRESHOLD"), ADDSET_DIRPYREQ_THRESHOLD, true); - appendBehavList (mi, M ("TP_DIRPYREQUALIZER_SKIN"), ADDSET_DIRPYREQ_SKINPROTECT, true); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_DIRPYREQUALIZER_LABEL")); + appendBehavList(mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_DIRPYREQ, true); + appendBehavList(mi, M("TP_DIRPYREQUALIZER_THRESHOLD"), ADDSET_DIRPYREQ_THRESHOLD, true); + appendBehavList(mi, M("TP_DIRPYREQUALIZER_SKIN"), ADDSET_DIRPYREQ_SKINPROTECT, true); - mi = behModel->append (); - mi->set_value (behavColumns.label, M ("TP_WAVELET_LABEL")); - appendBehavList (mi, M ("TP_WAVELET_LEVELS"), ADDSET_WA_THRES, true); - appendBehavList (mi, M ("TP_WAVELET_THRESHOLD"), ADDSET_WA_THRESHOLD, true); - appendBehavList (mi, M ("TP_WAVELET_THRESHOLD2"), ADDSET_WA_THRESHOLD2, true); - appendBehavList (mi, M ("TP_WAVELET_CHRO"), ADDSET_WA_CHRO, true); - appendBehavList (mi, M ("TP_WAVELET_CHR"), ADDSET_WA_CHROMA, true); - appendBehavList (mi, M ("TP_WAVELET_SKIN"), ADDSET_WA_SKINPROTECT, true); - appendBehavList (mi, M ("TP_WAVELET_EDRAD"), ADDSET_WA_EDGRAD, true); - appendBehavList (mi, M ("TP_WAVELET_EDVAL"), ADDSET_WA_EDGVAL, true); - appendBehavList (mi, M ("TP_WAVELET_RESCON"), ADDSET_WA_RESCON, true); - appendBehavList (mi, M ("TP_WAVELET_THR"), ADDSET_WA_THRR, true); - appendBehavList (mi, M ("TP_WAVELET_RESCONH"), ADDSET_WA_RESCONH, true); - appendBehavList (mi, M ("TP_WAVELET_THRH"), ADDSET_WA_THRRH, true); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_WAVELET_LABEL")); + appendBehavList(mi, M("TP_WAVELET_LEVELS"), ADDSET_WA_THRES, true); + appendBehavList(mi, M("TP_WAVELET_THRESHOLD"), ADDSET_WA_THRESHOLD, true); + appendBehavList(mi, M("TP_WAVELET_THRESHOLD2"), ADDSET_WA_THRESHOLD2, true); + appendBehavList(mi, M("TP_WAVELET_CHRO"), ADDSET_WA_CHRO, true); + appendBehavList(mi, M("TP_WAVELET_CHR"), ADDSET_WA_CHROMA, true); + appendBehavList(mi, M("TP_WAVELET_SKIN"), ADDSET_WA_SKINPROTECT, true); + appendBehavList(mi, M("TP_WAVELET_EDRAD"), ADDSET_WA_EDGRAD, true); + appendBehavList(mi, M("TP_WAVELET_EDVAL"), ADDSET_WA_EDGVAL, true); + appendBehavList(mi, M("TP_WAVELET_RESCON"), ADDSET_WA_RESCON, true); + appendBehavList(mi, M("TP_WAVELET_THR"), ADDSET_WA_THRR, true); + appendBehavList(mi, M("TP_WAVELET_RESCONH"), ADDSET_WA_RESCONH, true); + appendBehavList(mi, M("TP_WAVELET_THRH"), ADDSET_WA_THRRH, true); appendBehavList (mi, M ("TP_WAVELET_RADIUS"), ADDSET_WA_RADIUS, true); - appendBehavList (mi, M ("TP_WAVELET_RESCHRO"), ADDSET_WA_RESCHRO, true); - appendBehavList (mi, M ("TP_WAVELET_TMSTRENGTH"), ADDSET_WA_TMRS, true); + appendBehavList(mi, M("TP_WAVELET_RESCHRO"), ADDSET_WA_RESCHRO, true); + appendBehavList(mi, M("TP_WAVELET_TMSTRENGTH"), ADDSET_WA_TMRS, true); appendBehavList (mi, M ("TP_WAVELET_TMEDGS"), ADDSET_WA_EDGS, true); appendBehavList (mi, M ("TP_WAVELET_TMSCALE"), ADDSET_WA_SCALE, true); - appendBehavList (mi, M ("TP_WAVELET_SKY"), ADDSET_WA_SKYPROTECT, true); - appendBehavList (mi, M ("TP_WAVELET_CONTRA"), ADDSET_WA_CONTRAST, true); - appendBehavList (mi, M ("TP_WAVELET_STRENGTH"), ADDSET_WA_STRENGTH, true); - appendBehavList (mi, M ("TP_WAVELET_COMPGAMMA"), ADDSET_WA_GAMMA, true); - appendBehavList (mi, M ("TP_WAVELET_EDGEDETECT"), ADDSET_WA_EDGEDETECT, true); - appendBehavList (mi, M ("TP_WAVELET_EDGEDETECTTHR"), ADDSET_WA_EDGEDETECTTHR, true); - appendBehavList (mi, M ("TP_WAVELET_EDGEDETECTTHR2"), ADDSET_WA_EDGEDETECTTHR2, true); + appendBehavList(mi, M("TP_WAVELET_SKY"), ADDSET_WA_SKYPROTECT, true); + appendBehavList(mi, M("TP_WAVELET_CONTRA"), ADDSET_WA_CONTRAST, true); + appendBehavList(mi, M("TP_WAVELET_STRENGTH"), ADDSET_WA_STRENGTH, true); + appendBehavList(mi, M("TP_WAVELET_COMPGAMMA"), ADDSET_WA_GAMMA, true); + appendBehavList(mi, M("TP_WAVELET_EDGEDETECT"), ADDSET_WA_EDGEDETECT, true); + appendBehavList(mi, M("TP_WAVELET_EDGEDETECTTHR"), ADDSET_WA_EDGEDETECTTHR, true); + appendBehavList(mi, M("TP_WAVELET_EDGEDETECTTHR2"), ADDSET_WA_EDGEDETECTTHR2, true); mi = behModel->append (); mi->set_value (behavColumns.label, M("MAIN_TAB_RAW") + " - " + M("TP_RAW_SENSOR_BAYER_LABEL")); @@ -442,52 +442,52 @@ Gtk::Widget* Preferences::getBatchProcPanel () mi->set_value (behavColumns.label, M("MAIN_TAB_RAW") + " - " + M("TP_RAWCACORR_LABEL")); appendBehavList (mi, M ("TP_RAWCACORR_CARED") + ", " + M ("TP_RAWCACORR_CABLUE"), ADDSET_RAWCACORR, true); - behTreeView->expand_all (); + behTreeView->expand_all(); - behAddAll = Gtk::manage ( new Gtk::Button (M ("PREFERENCES_BEHADDALL")) ); - behSetAll = Gtk::manage ( new Gtk::Button (M ("PREFERENCES_BEHSETALL")) ); - behAddAll->set_tooltip_markup (M ("PREFERENCES_BEHADDALLHINT")); - behSetAll->set_tooltip_markup (M ("PREFERENCES_BEHSETALLHINT")); + behAddAll = Gtk::manage(new Gtk::Button(M("PREFERENCES_BEHADDALL"))); + behSetAll = Gtk::manage(new Gtk::Button(M("PREFERENCES_BEHSETALL"))); + behAddAll->set_tooltip_markup(M("PREFERENCES_BEHADDALLHINT")); + behSetAll->set_tooltip_markup(M("PREFERENCES_BEHSETALLHINT")); - behAddAll->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::behAddAllPressed) ); - behSetAll->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::behSetAllPressed) ); + behAddAll->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::behAddAllPressed)); + behSetAll->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::behSetAllPressed)); - Gtk::HBox* buttonpanel1 = Gtk::manage (new Gtk::HBox ()); - buttonpanel1->pack_end (*behSetAll, Gtk::PACK_SHRINK, 4); - buttonpanel1->pack_end (*behAddAll, Gtk::PACK_SHRINK, 4); - vbbeh->pack_start (*buttonpanel1, Gtk::PACK_SHRINK, 4); + Gtk::HBox* buttonpanel1 = Gtk::manage(new Gtk::HBox()); + buttonpanel1->pack_end(*behSetAll, Gtk::PACK_SHRINK, 4); + buttonpanel1->pack_end(*behAddAll, Gtk::PACK_SHRINK, 4); + vbbeh->pack_start(*buttonpanel1, Gtk::PACK_SHRINK, 4); - chOverwriteOutputFile = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_OVERWRITEOUTPUTFILE")) ); + chOverwriteOutputFile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_OVERWRITEOUTPUTFILE"))); vbBatchProc->pack_start (*chOverwriteOutputFile, Gtk::PACK_SHRINK, 4); swBatchProc->add(*vbBatchProc); return swBatchProc; } -void Preferences::appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set) +void Preferences::appendBehavList(Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set) { - Gtk::TreeModel::iterator ci = behModel->append (parent->children()); - ci->set_value (behavColumns.label, label); - ci->set_value (behavColumns.visible, true); - ci->set_value (behavColumns.badd, !set); - ci->set_value (behavColumns.bset, set); - ci->set_value (behavColumns.addsetid, id); + Gtk::TreeModel::iterator ci = behModel->append(parent->children()); + ci->set_value(behavColumns.label, label); + ci->set_value(behavColumns.visible, true); + ci->set_value(behavColumns.badd, !set); + ci->set_value(behavColumns.bset, set); + ci->set_value(behavColumns.addsetid, id); } -void Preferences::behAddSetRadioToggled (const Glib::ustring& path, bool add) +void Preferences::behAddSetRadioToggled(const Glib::ustring& path, bool add) { - Gtk::TreeModel::iterator iter = behModel->get_iter (path); + Gtk::TreeModel::iterator iter = behModel->get_iter(path); iter->set_value(behavColumns.badd, add); iter->set_value(behavColumns.bset, !add); } -void Preferences::behAddRadioToggled (const Glib::ustring& path) +void Preferences::behAddRadioToggled(const Glib::ustring& path) { behAddSetRadioToggled(path, true); } -void Preferences::behSetRadioToggled (const Glib::ustring& path) +void Preferences::behSetRadioToggled(const Glib::ustring& path) { behAddSetRadioToggled(path, false); } @@ -498,7 +498,7 @@ Gtk::Widget *Preferences::getDynamicProfilePanel() swDynamicProfile = Gtk::manage(new Gtk::ScrolledWindow()); swDynamicProfile->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - dynProfilePanel = Gtk::manage (new DynamicProfilePanel()); + dynProfilePanel = Gtk::manage(new DynamicProfilePanel()); swDynamicProfile->add(*dynProfilePanel); return swDynamicProfile; @@ -512,79 +512,82 @@ Gtk::Widget* Preferences::getImageProcessingPanel () Gtk::VBox* vbImageProcessing = Gtk::manage (new Gtk::VBox ()); - Gtk::Frame* fpp = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_IMPROCPARAMS"))); - Gtk::VBox* vbpp = Gtk::manage (new Gtk::VBox ()); - Gtk::Label* drlab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_FORRAW") + ":", Gtk::ALIGN_START)); - rprofiles = Gtk::manage (new ProfileStoreComboBox ()); + Gtk::Frame* fpp = Gtk::manage(new Gtk::Frame(M("PREFERENCES_IMPROCPARAMS"))); + Gtk::VBox* vbpp = Gtk::manage(new Gtk::VBox()); + Gtk::Label* drlab = Gtk::manage(new Gtk::Label(M("PREFERENCES_FORRAW") + ":", Gtk::ALIGN_START)); + rprofiles = Gtk::manage(new ProfileStoreComboBox()); const ProfileStoreEntry* dynpse = ProfileStore::getInstance()->getInternalDynamicPSE(); - rprofiles->addRow (dynpse); - setExpandAlignProperties (rprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - rprofiles->set_size_request (50, -1); - rpconn = rprofiles->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::forRAWComboChanged) ); - Gtk::Label* drimg = Gtk::manage (new Gtk::Label (M ("PREFERENCES_FORIMAGE") + ":", Gtk::ALIGN_START)); - iprofiles = Gtk::manage (new ProfileStoreComboBox ()); - iprofiles->addRow (dynpse); - iprofiles->set_size_request (50, -1); - setExpandAlignProperties (iprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - ipconn = iprofiles->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::forImageComboChanged) ); - Gtk::Table* defpt = Gtk::manage (new Gtk::Table (2, 2)); - defpt->attach (*drlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - defpt->attach (*rprofiles, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - defpt->attach (*drimg, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - defpt->attach (*iprofiles, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - vbpp->pack_start (*defpt, Gtk::PACK_SHRINK, 4); - useBundledProfiles = Gtk::manage (new Gtk::CheckButton (M ("PREFERENCES_USEBUNDLEDPROFILES"))); - bpconn = useBundledProfiles->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::bundledProfilesChanged) ); - vbpp->pack_start (*useBundledProfiles, Gtk::PACK_SHRINK, 4); - fpp->add (*vbpp); + rprofiles->addRow(dynpse); + setExpandAlignProperties(rprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + rprofiles->set_size_request(50, -1); + rpconn = rprofiles->signal_changed().connect(sigc::mem_fun(*this, &Preferences::forRAWComboChanged)); + Gtk::Label* drimg = Gtk::manage(new Gtk::Label(M("PREFERENCES_FORIMAGE") + ":", Gtk::ALIGN_START)); + iprofiles = Gtk::manage(new ProfileStoreComboBox()); + iprofiles->addRow(dynpse); + iprofiles->set_size_request(50, -1); + setExpandAlignProperties(iprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + ipconn = iprofiles->signal_changed().connect(sigc::mem_fun(*this, &Preferences::forImageComboChanged)); + Gtk::Table* defpt = Gtk::manage(new Gtk::Table(2, 2)); + defpt->attach(*drlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + defpt->attach(*rprofiles, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + defpt->attach(*drimg, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + defpt->attach(*iprofiles, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + vbpp->pack_start(*defpt, Gtk::PACK_SHRINK, 4); + useBundledProfiles = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_USEBUNDLEDPROFILES"))); + bpconn = useBundledProfiles->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::bundledProfilesChanged)); + vbpp->pack_start(*useBundledProfiles, Gtk::PACK_SHRINK, 4); + fpp->add(*vbpp); vbImageProcessing->pack_start (*fpp, Gtk::PACK_SHRINK, 4); // Custom profile builder box - Gtk::Frame* cpfrm = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_CUSTPROFBUILD")) ); - Gtk::Label* cplab = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_CUSTPROFBUILDPATH") + ":", Gtk::ALIGN_START) ); - txtCustProfBuilderPath = Gtk::manage ( new Gtk::Entry () ); - txtCustProfBuilderPath->set_tooltip_markup (M ("PREFERENCES_CUSTPROFBUILDHINT")); - Gtk::Label* cpltypelab = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_CUSTPROFBUILDKEYFORMAT") + ":", Gtk::ALIGN_START) ); - custProfBuilderLabelType = Gtk::manage (new Gtk::ComboBoxText ()); - custProfBuilderLabelType->append (M ("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID")); - custProfBuilderLabelType->append (M ("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); - custProfBuilderLabelType->append (M ("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID") + "_" + M ("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); - Gtk::Table* cpbt = Gtk::manage (new Gtk::Table (2, 2)); - cpbt->attach (*cplab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - cpbt->attach (*txtCustProfBuilderPath, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - cpbt->attach (*cpltypelab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - cpbt->attach (*custProfBuilderLabelType, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - cpfrm->add (*cpbt); + Gtk::Frame* cpfrm = Gtk::manage(new Gtk::Frame(M("PREFERENCES_CUSTPROFBUILD"))); + Gtk::Label* cplab = Gtk::manage(new Gtk::Label(M("PREFERENCES_CUSTPROFBUILDPATH") + ":", Gtk::ALIGN_START)); + txtCustProfBuilderPath = Gtk::manage(new Gtk::Entry()); + txtCustProfBuilderPath->set_tooltip_markup(M("PREFERENCES_CUSTPROFBUILDHINT")); + Gtk::Label* cpltypelab = Gtk::manage(new Gtk::Label(M("PREFERENCES_CUSTPROFBUILDKEYFORMAT") + ":", Gtk::ALIGN_START)); + custProfBuilderLabelType = Gtk::manage(new Gtk::ComboBoxText()); + custProfBuilderLabelType->append(M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID")); + custProfBuilderLabelType->append(M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); + custProfBuilderLabelType->append(M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID") + "_" + M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); + Gtk::Table* cpbt = Gtk::manage(new Gtk::Table(2, 2)); + cpbt->attach(*cplab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + cpbt->attach(*txtCustProfBuilderPath, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cpbt->attach(*cpltypelab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + cpbt->attach(*custProfBuilderLabelType, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cpfrm->add(*cpbt); vbImageProcessing->pack_start (*cpfrm, Gtk::PACK_SHRINK, 4); - Gtk::Frame* fdp = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_PROFILEHANDLING"))); - Gtk::Table* vbdp = Gtk::manage (new Gtk::Table (2, 2)); - saveParamsPreference = Gtk::manage (new Gtk::ComboBoxText ()); - saveParamsPreference->append (M ("PREFERENCES_PROFILESAVEINPUT")); - saveParamsPreference->append (M ("PREFERENCES_PROFILESAVECACHE")); - saveParamsPreference->append (M ("PREFERENCES_PROFILESAVEBOTH")); + Gtk::Frame* fdp = Gtk::manage(new Gtk::Frame(M("PREFERENCES_PROFILEHANDLING"))); + Gtk::Table* vbdp = Gtk::manage(new Gtk::Table(2, 2)); + saveParamsPreference = Gtk::manage(new Gtk::ComboBoxText()); + saveParamsPreference->append(M("PREFERENCES_PROFILESAVEINPUT")); + saveParamsPreference->append(M("PREFERENCES_PROFILESAVECACHE")); + saveParamsPreference->append(M("PREFERENCES_PROFILESAVEBOTH")); Gtk::Label *splab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_PROFILESAVELOCATION") + ":", Gtk::ALIGN_START)); - vbdp->attach (*splab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - vbdp->attach (*saveParamsPreference, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + vbdp->attach(*splab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + vbdp->attach(*saveParamsPreference, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); Gtk::Label* lplab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_PROFILELOADPR") + ":", Gtk::ALIGN_START)); - loadParamsPreference = Gtk::manage (new Gtk::ComboBoxText ()); - loadParamsPreference->append (M ("PREFERENCES_PROFILEPRCACHE")); - loadParamsPreference->append (M ("PREFERENCES_PROFILEPRFILE")); - vbdp->attach (*lplab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - vbdp->attach (*loadParamsPreference, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - fdp->add (*vbdp); + loadParamsPreference = Gtk::manage(new Gtk::ComboBoxText()); + loadParamsPreference->append(M("PREFERENCES_PROFILEPRCACHE")); + loadParamsPreference->append(M("PREFERENCES_PROFILEPRFILE")); + vbdp->attach(*lplab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + vbdp->attach(*loadParamsPreference, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + fdp->add(*vbdp); vbImageProcessing->pack_start (*fdp, Gtk::PACK_SHRINK, 4); +// Gtk::Frame* fdf = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_DARKFRAME")) ); +// Gtk::HBox* hb42 = Gtk::manage (new Gtk::HBox ()); +// darkFrameDir = Gtk::manage (new Gtk::FileChooserButton (M ("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); // Directories - Gtk::Frame* cdf = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_DIRECTORIES")) ); - Gtk::Grid* dirgrid = Gtk::manage (new Gtk::Grid ()); + Gtk::Frame* cdf = Gtk::manage(new Gtk::Frame(M("PREFERENCES_DIRECTORIES"))); + Gtk::Grid* dirgrid = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(dirgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label *dfLab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_DIRDARKFRAMES") + ":")); + Gtk::Label *dfLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_DIRDARKFRAMES") + ":")); setExpandAlignProperties(dfLab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - darkFrameDir = Gtk::manage (new MyFileChooserButton (M ("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + darkFrameDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); setExpandAlignProperties(darkFrameDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - dfLabel = Gtk::manage (new Gtk::Label ("Found:")); + dfLabel = Gtk::manage(new Gtk::Label("Found:")); setExpandAlignProperties(dfLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); dirgrid->attach_next_to(*dfLab, Gtk::POS_TOP, 1, 1); @@ -594,11 +597,11 @@ Gtk::Widget* Preferences::getImageProcessingPanel () dfconn = darkFrameDir->signal_selection_changed().connect ( sigc::mem_fun (*this, &Preferences::darkFrameChanged)); // FLATFIELD - Gtk::Label *ffLab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_FLATFIELDSDIR") + ":")); + Gtk::Label *ffLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_FLATFIELDSDIR") + ":")); setExpandAlignProperties(ffLab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - flatFieldDir = Gtk::manage (new MyFileChooserButton (M ("PREFERENCES_FLATFIELDSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + flatFieldDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_FLATFIELDSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); setExpandAlignProperties(flatFieldDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - ffLabel = Gtk::manage (new Gtk::Label ("Found:")); + ffLabel = Gtk::manage(new Gtk::Label("Found:")); setExpandAlignProperties(ffLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); dirgrid->attach_next_to(*ffLab, *dfLab, Gtk::POS_BOTTOM, 1, 1); @@ -608,11 +611,11 @@ Gtk::Widget* Preferences::getImageProcessingPanel () ffconn = flatFieldDir->signal_selection_changed().connect ( sigc::mem_fun (*this, &Preferences::flatFieldChanged)); //Cluts Dir - Gtk::Label *clutsDirLabel = Gtk::manage (new Gtk::Label (M ("PREFERENCES_CLUTSDIR") + ":")); + Gtk::Label *clutsDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_CLUTSDIR") + ":")); setExpandAlignProperties(clutsDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - clutsDir = Gtk::manage (new MyFileChooserButton (M ("PREFERENCES_CLUTSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + clutsDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_CLUTSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); setExpandAlignProperties(clutsDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label* clutsRestartNeeded = Gtk::manage ( new Gtk::Label (Glib::ustring (" (") + M ("PREFERENCES_APPLNEXTSTARTUP") + ")") ); + Gtk::Label* clutsRestartNeeded = Gtk::manage(new Gtk::Label(Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); setExpandAlignProperties(clutsRestartNeeded, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); dirgrid->attach_next_to(*clutsDirLabel, *ffLab, Gtk::POS_BOTTOM, 1, 1); @@ -645,7 +648,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () return swImageProcessing; } -Gtk::Widget* Preferences::getPerformancePanel () +Gtk::Widget* Preferences::getPerformancePanel() { swPerformance = Gtk::manage(new Gtk::ScrolledWindow()); swPerformance->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); @@ -653,27 +656,27 @@ Gtk::Widget* Preferences::getPerformancePanel () Gtk::VBox* vbPerformance = Gtk::manage ( new Gtk::VBox () ); vbPerformance->set_spacing (4); - Gtk::Frame* fprevdemo = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_PREVDEMO"))); - Gtk::HBox* hbprevdemo = Gtk::manage (new Gtk::HBox (false, 4)); + Gtk::Frame* fprevdemo = Gtk::manage(new Gtk::Frame(M("PREFERENCES_PREVDEMO"))); + Gtk::HBox* hbprevdemo = Gtk::manage(new Gtk::HBox(false, 4)); Gtk::Label* lprevdemo = Gtk::manage (new Gtk::Label (M("PREFERENCES_PREVDEMO_LABEL"), Gtk::ALIGN_START)); - cprevdemo = Gtk::manage (new Gtk::ComboBoxText ()); - cprevdemo->append (M ("PREFERENCES_PREVDEMO_FAST")); - cprevdemo->append (M ("PREFERENCES_PREVDEMO_SIDECAR")); - cprevdemo->set_active (1); - hbprevdemo->pack_start (*lprevdemo, Gtk::PACK_SHRINK); - hbprevdemo->pack_start (*cprevdemo); - fprevdemo->add (*hbprevdemo); + cprevdemo = Gtk::manage(new Gtk::ComboBoxText()); + cprevdemo->append(M("PREFERENCES_PREVDEMO_FAST")); + cprevdemo->append(M("PREFERENCES_PREVDEMO_SIDECAR")); + cprevdemo->set_active(1); + hbprevdemo->pack_start(*lprevdemo, Gtk::PACK_SHRINK); + hbprevdemo->pack_start(*cprevdemo); + fprevdemo->add(*hbprevdemo); vbPerformance->pack_start (*fprevdemo, Gtk::PACK_SHRINK, 4); - Gtk::Frame* ftiffserialize = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_SERIALIZE_TIFF_READ"))); - Gtk::HBox* htiffserialize = Gtk::manage (new Gtk::HBox (false, 4)); - ctiffserialize = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_SERIALIZE_TIFF_READ_LABEL")) ); - ctiffserialize->set_tooltip_text (M ("PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP")); - htiffserialize->pack_start (*ctiffserialize); - ftiffserialize->add (*htiffserialize); + Gtk::Frame* ftiffserialize = Gtk::manage(new Gtk::Frame(M("PREFERENCES_SERIALIZE_TIFF_READ"))); + Gtk::HBox* htiffserialize = Gtk::manage(new Gtk::HBox(false, 4)); + ctiffserialize = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SERIALIZE_TIFF_READ_LABEL"))); + ctiffserialize->set_tooltip_text(M("PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP")); + htiffserialize->pack_start(*ctiffserialize); + ftiffserialize->add(*htiffserialize); vbPerformance->pack_start (*ftiffserialize, Gtk::PACK_SHRINK, 4); - Gtk::Frame* fclut = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_CLUTSCACHE")) ); + Gtk::Frame* fclut = Gtk::manage(new Gtk::Frame(M("PREFERENCES_CLUTSCACHE"))); #ifdef _OPENMP placeSpinBox(fclut, clutCacheSizeSB, "PREFERENCES_CLUTSCACHE_LABEL", 0, 1, 5, 2, 1, 3 * omp_get_num_procs()); #else @@ -725,6 +728,7 @@ Gtk::Widget* Preferences::getPerformancePanel () int maxThreadNumber = 10; #endif + placeSpinBox(threadsVBox, threadsSpinBtn, "PREFERENCES_PERFORMANCE_THREADS_LABEL", 0, 1, 5, 2, 0, maxThreadNumber); threadsFrame->add (*threadsVBox); @@ -743,46 +747,46 @@ Gtk::Widget* Preferences::getColorManPanel () Gtk::VBox* vbColorMan = Gtk::manage (new Gtk::VBox ()); vbColorMan->set_spacing (4); - iccDir = Gtk::manage (new MyFileChooserButton (M ("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - setExpandAlignProperties (iccDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M ("PREFERENCES_ICCDIR") + ":", Gtk::ALIGN_START)); - setExpandAlignProperties (pdlabel, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + iccDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(iccDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + Gtk::Label* pdlabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_ICCDIR") + ":", Gtk::ALIGN_START)); + setExpandAlignProperties(pdlabel, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Grid* iccdgrid = Gtk::manage (new Gtk::Grid ()); - setExpandAlignProperties (iccdgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - iccdgrid->set_column_spacing (4); + Gtk::Grid* iccdgrid = Gtk::manage(new Gtk::Grid()); + setExpandAlignProperties(iccdgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + iccdgrid->set_column_spacing(4); Gtk::Label* monProfileRestartNeeded = Gtk::manage ( new Gtk::Label (Glib::ustring (" (") + M ("PREFERENCES_APPLNEXTSTARTUP") + ")") ); setExpandAlignProperties(monProfileRestartNeeded, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - iccdgrid->attach (*pdlabel, 0, 0, 1, 1); - iccdgrid->attach (*iccDir, 1, 0, 1, 1); + iccdgrid->attach(*pdlabel, 0, 0, 1, 1); + iccdgrid->attach(*iccDir, 1, 0, 1, 1); iccdgrid->attach (*monProfileRestartNeeded, 2, 0, 1, 1); - iccDir->signal_selection_changed ().connect (sigc::mem_fun (this, &Preferences::iccDirChanged)); + iccDir->signal_selection_changed().connect(sigc::mem_fun(this, &Preferences::iccDirChanged)); vbColorMan->pack_start (*iccdgrid, Gtk::PACK_SHRINK); //------------------------- MONITOR ---------------------- - Gtk::Frame* fmonitor = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_MONITOR")) ); - Gtk::Grid* gmonitor = Gtk::manage ( new Gtk::Grid () ); - gmonitor->set_column_spacing (4); + Gtk::Frame* fmonitor = Gtk::manage(new Gtk::Frame(M("PREFERENCES_MONITOR"))); + Gtk::Grid* gmonitor = Gtk::manage(new Gtk::Grid()); + gmonitor->set_column_spacing(4); - monProfile = Gtk::manage (new Gtk::ComboBoxText ()); - setExpandAlignProperties (monProfile, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M ("PREFERENCES_MONPROFILE") + ":", Gtk::ALIGN_START)); - setExpandAlignProperties (mplabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + monProfile = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(monProfile, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + Gtk::Label* mplabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_MONPROFILE") + ":", Gtk::ALIGN_START)); + setExpandAlignProperties(mplabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - monIntent = Gtk::manage (new Gtk::ComboBoxText ()); - setExpandAlignProperties (monIntent, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label* milabel = Gtk::manage (new Gtk::Label (M ("PREFERENCES_MONINTENT") + ":", Gtk::ALIGN_START)); - setExpandAlignProperties (milabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + monIntent = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(monIntent, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + Gtk::Label* milabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_MONINTENT") + ":", Gtk::ALIGN_START)); + setExpandAlignProperties(milabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - monProfile->append (M ("PREFERENCES_PROFILE_NONE")); - monProfile->set_active (0); + monProfile->append(M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active(0); - const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (rtengine::ICCStore::ProfileType::MONITOR); + const std::vector profiles = rtengine::ICCStore::getInstance()->getProfiles(rtengine::ICCStore::ProfileType::MONITOR); for (const auto& profile : profiles) { if (profile.find("file:") != 0) { @@ -796,97 +800,96 @@ Gtk::Widget* Preferences::getColorManPanel () } // same order as the enum - monIntent->append (M ("PREFERENCES_INTENT_PERCEPTUAL")); - monIntent->append (M ("PREFERENCES_INTENT_RELATIVE")); - monIntent->append (M ("PREFERENCES_INTENT_ABSOLUTE")); - monIntent->set_active (1); - monIntent->set_size_request (120, -1); + monIntent->append(M("PREFERENCES_INTENT_PERCEPTUAL")); + monIntent->append(M("PREFERENCES_INTENT_RELATIVE")); + monIntent->append(M("PREFERENCES_INTENT_ABSOLUTE")); + monIntent->set_active(1); + monIntent->set_size_request(120, -1); - monBPC = Gtk::manage (new Gtk::CheckButton (M ("PREFERENCES_CMMBPC"))); - setExpandAlignProperties (monBPC, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - monBPC->set_active (true); + monBPC = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_CMMBPC"))); + setExpandAlignProperties(monBPC, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + monBPC->set_active(true); - cbAutoMonProfile = Gtk::manage (new Gtk::CheckButton (M ("PREFERENCES_AUTOMONPROFILE"))); - setExpandAlignProperties (cbAutoMonProfile, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - autoMonProfileConn = cbAutoMonProfile->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::autoMonProfileToggled)); + cbAutoMonProfile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_AUTOMONPROFILE"))); + setExpandAlignProperties(cbAutoMonProfile, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + autoMonProfileConn = cbAutoMonProfile->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::autoMonProfileToggled)); int row = 0; - gmonitor->attach (*mplabel, 0, row, 1, 1); + gmonitor->attach(*mplabel, 0, row, 1, 1); #if defined(__APPLE__) // monitor profile not supported on apple - Gtk::Label *osxwarn = Gtk::manage (new Gtk::Label (M ("PREFERENCES_MONPROFILE_WARNOSX"), Gtk::ALIGN_START)); - setExpandAlignProperties (osxwarn, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - gmonitor->attach (*osxwarn, 1, row, 1, 1); + Gtk::Label *osxwarn = Gtk::manage(new Gtk::Label(M("PREFERENCES_MONPROFILE_WARNOSX"), Gtk::ALIGN_START)); + setExpandAlignProperties(osxwarn, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + gmonitor->attach(*osxwarn, 1, row, 1, 1); #else - gmonitor->attach (*monProfile, 1, row, 1, 1); + gmonitor->attach(*monProfile, 1, row, 1, 1); #endif ++row; - gmonitor->attach (*cbAutoMonProfile, 1, row, 1, 1); + gmonitor->attach(*cbAutoMonProfile, 1, row, 1, 1); ++row; - gmonitor->attach (*milabel, 0, row, 1, 1); - gmonitor->attach (*monIntent, 1, row, 1, 1); + gmonitor->attach(*milabel, 0, row, 1, 1); + gmonitor->attach(*monIntent, 1, row, 1, 1); ++row; - gmonitor->attach (*monBPC, 0, row, 2, 1); + gmonitor->attach(*monBPC, 0, row, 2, 1); autoMonProfileToggled(); - fmonitor->add (*gmonitor); + fmonitor->add(*gmonitor); vbColorMan->pack_start (*fmonitor, Gtk::PACK_SHRINK); //------------------------- PRINTER ---------------------- - Gtk::Frame* fprinter = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_PRINTER")) ); - Gtk::Grid* gprinter = Gtk::manage ( new Gtk::Grid () ); - gprinter->set_column_spacing (4); - prtProfile = Gtk::manage (new Gtk::ComboBoxText ()); - setExpandAlignProperties (prtProfile, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label* pplabel = Gtk::manage (new Gtk::Label (M ("PREFERENCES_PRTPROFILE") + ":")); - setExpandAlignProperties (pplabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + Gtk::Frame* fprinter = Gtk::manage(new Gtk::Frame(M("PREFERENCES_PRINTER"))); + Gtk::Grid* gprinter = Gtk::manage(new Gtk::Grid()); + gprinter->set_column_spacing(4); + prtProfile = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(prtProfile, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + Gtk::Label* pplabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_PRTPROFILE") + ":")); + setExpandAlignProperties(pplabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - prtIntent = Gtk::manage (new Gtk::ComboBoxText ()); - setExpandAlignProperties (prtIntent, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - Gtk::Label* pilabel = Gtk::manage (new Gtk::Label (M ("PREFERENCES_PRTINTENT") + ":")); - setExpandAlignProperties (pilabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + prtIntent = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(prtIntent, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + Gtk::Label* pilabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_PRTINTENT") + ":")); + setExpandAlignProperties(pilabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - prtProfile->append (M ("PREFERENCES_PROFILE_NONE")); - prtProfile->set_active (0); + prtProfile->append(M("PREFERENCES_PROFILE_NONE")); + prtProfile->set_active(0); - const std::vector prtprofiles = rtengine::ICCStore::getInstance ()->getProfiles (rtengine::ICCStore::ProfileType::PRINTER); + const std::vector prtprofiles = rtengine::ICCStore::getInstance()->getProfiles(rtengine::ICCStore::ProfileType::PRINTER); for (const auto& prtprofile : prtprofiles) { - prtProfile->append (prtprofile); + prtProfile->append(prtprofile); } // same order as the enum - prtIntent->append (M ("PREFERENCES_INTENT_PERCEPTUAL")); - prtIntent->append (M ("PREFERENCES_INTENT_RELATIVE")); - prtIntent->append (M ("PREFERENCES_INTENT_ABSOLUTE")); - prtIntent->set_active (1); + prtIntent->append(M("PREFERENCES_INTENT_PERCEPTUAL")); + prtIntent->append(M("PREFERENCES_INTENT_RELATIVE")); + prtIntent->append(M("PREFERENCES_INTENT_ABSOLUTE")); + prtIntent->set_active(1); - prtBPC = Gtk::manage (new Gtk::CheckButton (M ("PREFERENCES_CMMBPC"))); - setExpandAlignProperties (prtBPC, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - prtBPC->set_active (true); + prtBPC = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_CMMBPC"))); + setExpandAlignProperties(prtBPC, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + prtBPC->set_active(true); row = 0; - gprinter->attach (*pplabel, 0, row, 1, 1); - gprinter->attach (*prtProfile, 1, row, 1, 1); + gprinter->attach(*pplabel, 0, row, 1, 1); + gprinter->attach(*prtProfile, 1, row, 1, 1); ++row; - gprinter->attach (*pilabel, 0, row, 1, 1); - gprinter->attach (*prtIntent, 1, row, 1, 1); + gprinter->attach(*pilabel, 0, row, 1, 1); + gprinter->attach(*prtIntent, 1, row, 1, 1); ++row; - gprinter->attach (*prtBPC, 0, row, 2, 1); + gprinter->attach(*prtBPC, 0, row, 2, 1); autoMonProfileToggled(); - fprinter->add (*gprinter); + fprinter->add(*gprinter); vbColorMan->pack_start (*fprinter, Gtk::PACK_SHRINK); - swColorMan->add(*vbColorMan); return swColorMan; } -Gtk::Widget* Preferences::getGeneralPanel () +Gtk::Widget* Preferences::getGeneralPanel() { swGeneral = Gtk::manage(new Gtk::ScrolledWindow()); swGeneral->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); @@ -895,114 +898,128 @@ Gtk::Widget* Preferences::getGeneralPanel () vbGeneral->set_column_spacing (4); vbGeneral->set_row_spacing (4); - Gtk::Frame* fworklflow = Gtk::manage (new Gtk::Frame (M ("PREFERENCES_WORKFLOW"))); - setExpandAlignProperties (fworklflow, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - Gtk::Grid* workflowGrid = Gtk::manage (new Gtk::Grid()); - workflowGrid->set_column_spacing (4); - workflowGrid->set_row_spacing (4); - setExpandAlignProperties (workflowGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Frame* fworklflow = Gtk::manage(new Gtk::Frame(M("PREFERENCES_WORKFLOW"))); + setExpandAlignProperties(fworklflow, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + Gtk::Grid* workflowGrid = Gtk::manage(new Gtk::Grid()); + workflowGrid->set_column_spacing(4); + workflowGrid->set_row_spacing(4); + setExpandAlignProperties(workflowGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - Gtk::Label* flayoutlab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_EDITORLAYOUT") + ":")); - setExpandAlignProperties (flayoutlab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + Gtk::Label* flayoutlab = Gtk::manage(new Gtk::Label(M("PREFERENCES_EDITORLAYOUT") + ":")); + setExpandAlignProperties(flayoutlab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); editorLayout = Gtk::manage (new MyComboBoxText ()); - setExpandAlignProperties (editorLayout, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - editorLayout->append (M ("PREFERENCES_SINGLETAB")); - editorLayout->append (M ("PREFERENCES_SINGLETABVERTAB")); - editorLayout->append (M ("PREFERENCES_MULTITAB")); - editorLayout->append (M ("PREFERENCES_MULTITABDUALMON")); - editorLayout->set_active (2); - Gtk::CellRendererText* cellRenderer = dynamic_cast (editorLayout->get_first_cell()); + setExpandAlignProperties(editorLayout, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); + editorLayout->append(M("PREFERENCES_SINGLETAB")); + editorLayout->append(M("PREFERENCES_SINGLETABVERTAB")); + editorLayout->append(M("PREFERENCES_MULTITAB")); + editorLayout->append(M("PREFERENCES_MULTITABDUALMON")); + editorLayout->set_active(2); + Gtk::CellRendererText* cellRenderer = dynamic_cast(editorLayout->get_first_cell()); cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE; cellRenderer->property_ellipsize_set() = true; - editorLayout->signal_changed().connect (sigc::mem_fun (*this, &Preferences::layoutComboChanged)); + editorLayout->signal_changed().connect(sigc::mem_fun(*this, &Preferences::layoutComboChanged)); layoutComboChanged(); // update the tooltip - Gtk::Label* lNextStart = Gtk::manage ( new Gtk::Label (Glib::ustring ("(") + M ("PREFERENCES_APPLNEXTSTARTUP") + ")") ); - setExpandAlignProperties (lNextStart, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - workflowGrid->attach_next_to (*flayoutlab, Gtk::POS_LEFT, 1, 1); - workflowGrid->attach_next_to (*editorLayout, *flayoutlab, Gtk::POS_RIGHT, 1, 1); - workflowGrid->attach_next_to (*lNextStart, *editorLayout, Gtk::POS_RIGHT, 1, 1); + Gtk::Label* lNextStart = Gtk::manage(new Gtk::Label(Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); + setExpandAlignProperties(lNextStart, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*flayoutlab, Gtk::POS_LEFT, 1, 1); + workflowGrid->attach_next_to(*editorLayout, *flayoutlab, Gtk::POS_RIGHT, 1, 1); + workflowGrid->attach_next_to(*lNextStart, *editorLayout, Gtk::POS_RIGHT, 1, 1); - Gtk::Label* curveBBoxPosL = Gtk::manage (new Gtk::Label (M ("PREFERENCES_CURVEBBOXPOS") + ":")); - setExpandAlignProperties (curveBBoxPosL, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - curveBBoxPosC = Gtk::manage (new Gtk::ComboBoxText ()); - setExpandAlignProperties (curveBBoxPosC, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - curveBBoxPosC->append (M ("PREFERENCES_CURVEBBOXPOS_ABOVE")); - curveBBoxPosC->append (M ("PREFERENCES_CURVEBBOXPOS_RIGHT")); - curveBBoxPosC->append (M ("PREFERENCES_CURVEBBOXPOS_BELOW")); - curveBBoxPosC->append (M ("PREFERENCES_CURVEBBOXPOS_LEFT")); - curveBBoxPosC->set_active (1); - Gtk::Label* curveBBoxPosRestartL = Gtk::manage (new Gtk::Label (Glib::ustring ("(") + M ("PREFERENCES_APPLNEXTSTARTUP") + ")")); - setExpandAlignProperties (curveBBoxPosRestartL, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - workflowGrid->attach_next_to (*curveBBoxPosL, *flayoutlab, Gtk::POS_BOTTOM, 1, 1); - workflowGrid->attach_next_to (*curveBBoxPosC, *editorLayout, Gtk::POS_BOTTOM, 1, 1); - workflowGrid->attach_next_to (*curveBBoxPosRestartL, *lNextStart, Gtk::POS_BOTTOM, 1, 1); + Gtk::Label* curveBBoxPosL = Gtk::manage(new Gtk::Label(M("PREFERENCES_CURVEBBOXPOS") + ":")); + setExpandAlignProperties(curveBBoxPosL, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + curveBBoxPosC = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(curveBBoxPosC, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); + curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_ABOVE")); + curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_RIGHT")); + curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_BELOW")); + curveBBoxPosC->append(M("PREFERENCES_CURVEBBOXPOS_LEFT")); + curveBBoxPosC->set_active(1); + Gtk::Label* curveBBoxPosRestartL = Gtk::manage(new Gtk::Label(Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); + setExpandAlignProperties(curveBBoxPosRestartL, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*curveBBoxPosL, *flayoutlab, Gtk::POS_BOTTOM, 1, 1); + workflowGrid->attach_next_to(*curveBBoxPosC, *editorLayout, Gtk::POS_BOTTOM, 1, 1); + workflowGrid->attach_next_to(*curveBBoxPosRestartL, *lNextStart, Gtk::POS_BOTTOM, 1, 1); - ckbHistogramPositionLeft = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_HISTOGRAMPOSITIONLEFT")) ); - setExpandAlignProperties (ckbHistogramPositionLeft, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - workflowGrid->attach_next_to (*ckbHistogramPositionLeft, *curveBBoxPosL, Gtk::POS_BOTTOM, 1, 1); + Gtk::Label* complexityL = Gtk::manage(new Gtk::Label(M("PREFERENCES_COMPLEXITYLOC") + ":")); + setExpandAlignProperties(complexityL, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + complexitylocal = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(complexitylocal, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); + complexitylocal->append(M("PREFERENCES_COMPLEXITY_EXP")); + complexitylocal->append(M("PREFERENCES_COMPLEXITY_NORM")); + complexitylocal->set_active(1); + workflowGrid->attach_next_to(*complexityL, *curveBBoxPosL, Gtk::POS_BOTTOM, 1, 1); + workflowGrid->attach_next_to(*complexitylocal, *curveBBoxPosC, Gtk::POS_BOTTOM, 1, 1); - ckbFileBrowserToolbarSingleRow = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_FILEBROWSERTOOLBARSINGLEROW")) ); - setExpandAlignProperties (ckbFileBrowserToolbarSingleRow, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); - ckbShowFilmStripToolBar = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_SHOWFILMSTRIPTOOLBAR")) ); - setExpandAlignProperties (ckbShowFilmStripToolBar, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); - workflowGrid->attach_next_to (*ckbFileBrowserToolbarSingleRow, *ckbHistogramPositionLeft, Gtk::POS_BOTTOM, 1, 1); - workflowGrid->attach_next_to (*ckbShowFilmStripToolBar, *curveBBoxPosC, Gtk::POS_BOTTOM, 2, 1); + ckbHistogramPositionLeft = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_HISTOGRAMPOSITIONLEFT"))); + setExpandAlignProperties(ckbHistogramPositionLeft, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*ckbHistogramPositionLeft, *complexityL, Gtk::POS_BOTTOM, 1, 1); - Gtk::Label* hb4label = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_TP_LABEL")) ); - setExpandAlignProperties (hb4label, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - ckbHideTPVScrollbar = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_TP_VSCROLLBAR")) ); - setExpandAlignProperties (ckbHideTPVScrollbar, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - workflowGrid->attach_next_to (*hb4label, *ckbFileBrowserToolbarSingleRow, Gtk::POS_BOTTOM, 1, 1); - workflowGrid->attach_next_to (*ckbHideTPVScrollbar, *hb4label, Gtk::POS_RIGHT, 1, 1); - ckbAutoSaveTpOpen = Gtk::manage (new Gtk::CheckButton (M ("PREFERENCES_AUTOSAVE_TP_OPEN"))); - workflowGrid->attach_next_to (*ckbAutoSaveTpOpen, *hb4label, Gtk::POS_BOTTOM, 1, 1); - btnSaveTpOpenNow = Gtk::manage (new Gtk::Button (M ("PREFERENCES_SAVE_TP_OPEN_NOW"))); - setExpandAlignProperties (btnSaveTpOpenNow, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - workflowGrid->attach_next_to (*btnSaveTpOpenNow, *ckbAutoSaveTpOpen, Gtk::POS_RIGHT, 1, 1); + ckbFileBrowserToolbarSingleRow = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_FILEBROWSERTOOLBARSINGLEROW"))); + setExpandAlignProperties(ckbFileBrowserToolbarSingleRow, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); + ckbShowFilmStripToolBar = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWFILMSTRIPTOOLBAR"))); + setExpandAlignProperties(ckbShowFilmStripToolBar, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); + workflowGrid->attach_next_to(*ckbFileBrowserToolbarSingleRow, *ckbHistogramPositionLeft, Gtk::POS_BOTTOM, 1, 1); + workflowGrid->attach_next_to(*ckbShowFilmStripToolBar, *complexitylocal, Gtk::POS_BOTTOM, 2, 1); + + Gtk::Label* hb4label = Gtk::manage(new Gtk::Label(M("PREFERENCES_TP_LABEL"))); + setExpandAlignProperties(hb4label, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + ckbHideTPVScrollbar = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_TP_VSCROLLBAR"))); + setExpandAlignProperties(ckbHideTPVScrollbar, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*hb4label, *ckbFileBrowserToolbarSingleRow, Gtk::POS_BOTTOM, 1, 1); + workflowGrid->attach_next_to(*ckbHideTPVScrollbar, *hb4label, Gtk::POS_RIGHT, 1, 1); + ckbAutoSaveTpOpen = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_AUTOSAVE_TP_OPEN"))); + workflowGrid->attach_next_to(*ckbAutoSaveTpOpen, *hb4label, Gtk::POS_BOTTOM, 1, 1); + btnSaveTpOpenNow = Gtk::manage(new Gtk::Button(M("PREFERENCES_SAVE_TP_OPEN_NOW"))); + setExpandAlignProperties(btnSaveTpOpenNow, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*btnSaveTpOpenNow, *ckbAutoSaveTpOpen, Gtk::POS_RIGHT, 1, 1); auto save_tp_open_now = [&]() -> void { - parent->writeToolExpandedStatus (moptions.tpOpen); + parent->writeToolExpandedStatus(moptions.tpOpen); }; - btnSaveTpOpenNow->signal_clicked().connect (save_tp_open_now); + btnSaveTpOpenNow->signal_clicked().connect(save_tp_open_now); - fworklflow->add (*workflowGrid); + ckbshowtooltiplocallab = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWTOOLTIP"))); + setExpandAlignProperties(ckbshowtooltiplocallab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_START); + workflowGrid->attach_next_to(*ckbshowtooltiplocallab, *ckbFileBrowserToolbarSingleRow, Gtk::POS_RIGHT, 1, 1); + + fworklflow->add(*workflowGrid); vbGeneral->attach_next_to (*fworklflow, Gtk::POS_TOP, 2, 1); // --------------------------------------------- - Gtk::Frame* flang = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_LANG")) ); - setExpandAlignProperties (flang, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - Gtk::Grid* langGrid = Gtk::manage ( new Gtk::Grid() ); - langGrid->set_column_spacing (4); - langGrid->set_row_spacing (4); - setExpandAlignProperties (langGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); + Gtk::Frame* flang = Gtk::manage(new Gtk::Frame(M("PREFERENCES_LANG"))); + setExpandAlignProperties(flang, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + Gtk::Grid* langGrid = Gtk::manage(new Gtk::Grid()); + langGrid->set_column_spacing(4); + langGrid->set_row_spacing(4); + setExpandAlignProperties(langGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - ckbLangAutoDetect = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_LANGAUTODETECT")) ); - setExpandAlignProperties (ckbLangAutoDetect, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + ckbLangAutoDetect = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_LANGAUTODETECT"))); + setExpandAlignProperties(ckbLangAutoDetect, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - Gtk::Label* langlab = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_SELECTLANG") + ":") ); - setExpandAlignProperties (langlab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - languages = Gtk::manage ( new Gtk::ComboBoxText () ); - setExpandAlignProperties (languages, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + Gtk::Label* langlab = Gtk::manage(new Gtk::Label(M("PREFERENCES_SELECTLANG") + ":")); + setExpandAlignProperties(langlab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + languages = Gtk::manage(new Gtk::ComboBoxText()); + setExpandAlignProperties(languages, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); std::vector langs; - parseDir (argv0 + "/languages", langs, ""); + parseDir(argv0 + "/languages", langs, ""); for (size_t i = 0; i < langs.size(); i++) { if ("default" != langs[i] && "README" != langs[i] && "LICENSE" != langs[i]) { - languages->append (langs[i]); + languages->append(langs[i]); } } - Gtk::Label* langw = Gtk::manage ( new Gtk::Label (Glib::ustring (" (") + M ("PREFERENCES_APPLNEXTSTARTUP") + ")") ); - setExpandAlignProperties (langw, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - langGrid->attach_next_to (*ckbLangAutoDetect, Gtk::POS_LEFT, 3, 1); - langGrid->attach_next_to (*langlab, *ckbLangAutoDetect, Gtk::POS_BOTTOM, 1, 1); - langGrid->attach_next_to (*languages, *langlab, Gtk::POS_RIGHT, 1, 1); - langGrid->attach_next_to (*langw, *languages, Gtk::POS_RIGHT, 1, 1); - flang->add (*langGrid); + Gtk::Label* langw = Gtk::manage(new Gtk::Label(Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); + setExpandAlignProperties(langw, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + langGrid->attach_next_to(*ckbLangAutoDetect, Gtk::POS_LEFT, 3, 1); + langGrid->attach_next_to(*langlab, *ckbLangAutoDetect, Gtk::POS_BOTTOM, 1, 1); + langGrid->attach_next_to(*languages, *langlab, Gtk::POS_RIGHT, 1, 1); + langGrid->attach_next_to(*langw, *languages, Gtk::POS_RIGHT, 1, 1); + flang->add(*langGrid); vbGeneral->attach_next_to (*flang, *fworklflow, Gtk::POS_BOTTOM, 2, 1); // Appearance --------------------------------------------- @@ -1063,6 +1080,7 @@ Gtk::Widget* Preferences::getGeneralPanel () setExpandAlignProperties(pseudoHiDPI, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); Gtk::VSeparator *vSep = Gtk::manage(new Gtk::VSeparator()); + appearanceGrid->attach(*themeLbl, 0, 0, 1, 1); appearanceGrid->attach(*themeCBT, 1, 0, 1, 1); @@ -1083,129 +1101,128 @@ Gtk::Widget* Preferences::getGeneralPanel () // --------------------------------------------- - Gtk::Frame* fclip = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_CLIPPINGIND"))); - setExpandAlignProperties (fclip, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - Gtk::Grid* clipGrid = Gtk::manage ( new Gtk::Grid() ); - clipGrid->set_column_spacing (4); - clipGrid->set_row_spacing (4); - setExpandAlignProperties (clipGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Frame* fclip = Gtk::manage(new Gtk::Frame(M("PREFERENCES_CLIPPINGIND"))); + setExpandAlignProperties(fclip, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Grid* clipGrid = Gtk::manage(new Gtk::Grid()); + clipGrid->set_column_spacing(4); + clipGrid->set_row_spacing(4); + setExpandAlignProperties(clipGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - Gtk::Label* hll = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_HLTHRESHOLD") + ": ")); - setExpandAlignProperties (hll, true, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - hlThresh = Gtk::manage ( new Gtk::SpinButton () ); - setExpandAlignProperties (hlThresh, false, false, Gtk::ALIGN_END, Gtk::ALIGN_BASELINE); - hlThresh->set_digits (0); - hlThresh->set_increments (1, 10); - hlThresh->set_range (0, 255); - clipGrid->attach_next_to (*hll, Gtk::POS_LEFT, 1, 1); - clipGrid->attach_next_to (*hlThresh, *hll, Gtk::POS_RIGHT, 1, 1); + Gtk::Label* hll = Gtk::manage(new Gtk::Label(M("PREFERENCES_HLTHRESHOLD") + ": ")); + setExpandAlignProperties(hll, true, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + hlThresh = Gtk::manage(new Gtk::SpinButton()); + setExpandAlignProperties(hlThresh, false, false, Gtk::ALIGN_END, Gtk::ALIGN_BASELINE); + hlThresh->set_digits(0); + hlThresh->set_increments(1, 10); + hlThresh->set_range(0, 255); + clipGrid->attach_next_to(*hll, Gtk::POS_LEFT, 1, 1); + clipGrid->attach_next_to(*hlThresh, *hll, Gtk::POS_RIGHT, 1, 1); - Gtk::Label* shl = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_SHTHRESHOLD") + ": ") ); - setExpandAlignProperties (shl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - shThresh = Gtk::manage ( new Gtk::SpinButton () ); - setExpandAlignProperties (shThresh, false, false, Gtk::ALIGN_END, Gtk::ALIGN_BASELINE); - shThresh->show (); - shThresh->set_digits (0); - shThresh->set_increments (1, 10); - shThresh->set_range (0, 255); - clipGrid->attach_next_to (*shl, *hll, Gtk::POS_BOTTOM, 1, 1); - clipGrid->attach_next_to (*shThresh, *shl, Gtk::POS_RIGHT, 1, 1); + Gtk::Label* shl = Gtk::manage(new Gtk::Label(M("PREFERENCES_SHTHRESHOLD") + ": ")); + setExpandAlignProperties(shl, true, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + shThresh = Gtk::manage(new Gtk::SpinButton()); + setExpandAlignProperties(shThresh, false, false, Gtk::ALIGN_END, Gtk::ALIGN_BASELINE); + shThresh->show(); + shThresh->set_digits(0); + shThresh->set_increments(1, 10); + shThresh->set_range(0, 255); + clipGrid->attach_next_to(*shl, *hll, Gtk::POS_BOTTOM, 1, 1); + clipGrid->attach_next_to(*shThresh, *shl, Gtk::POS_RIGHT, 1, 1); - fclip->add (*clipGrid); + fclip->add(*clipGrid); vbGeneral->attach_next_to (*fclip, *appearanceFrame, Gtk::POS_BOTTOM, 1, 1); // --------------------------------------------- - Gtk::Frame* fnav = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_NAVIGATIONFRAME")) ); - setExpandAlignProperties (fclip, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - Gtk::Grid* navigationGrid = Gtk::manage ( new Gtk::Grid() ); - navigationGrid->set_column_spacing (4); - navigationGrid->set_row_spacing (4); - setExpandAlignProperties (fclip, false, false, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + Gtk::Frame* fnav = Gtk::manage(new Gtk::Frame(M("PREFERENCES_NAVIGATIONFRAME"))); + setExpandAlignProperties(fclip, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Grid* navigationGrid = Gtk::manage(new Gtk::Grid()); + navigationGrid->set_column_spacing(4); + navigationGrid->set_row_spacing(4); + setExpandAlignProperties(fclip, false, false, Gtk::ALIGN_START, Gtk::ALIGN_FILL); - Gtk::Label* panFactorLabel = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_PANFACTORLABEL") + ":", Gtk::ALIGN_START)); - setExpandAlignProperties (panFactorLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - panFactor = Gtk::manage ( new Gtk::SpinButton () ); - setExpandAlignProperties (panFactor, true, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - panFactor->set_digits (0); - panFactor->set_increments (1, 5); - panFactor->set_range (1, 10); - navigationGrid->attach_next_to (*panFactorLabel, Gtk::POS_LEFT, 1, 1); - navigationGrid->attach_next_to (*panFactor, *panFactorLabel, Gtk::POS_RIGHT, 1, 1); + Gtk::Label* panFactorLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_PANFACTORLABEL") + ":", Gtk::ALIGN_START)); + setExpandAlignProperties(panFactorLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + panFactor = Gtk::manage(new Gtk::SpinButton()); + setExpandAlignProperties(panFactor, true, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + panFactor->set_digits(0); + panFactor->set_increments(1, 5); + panFactor->set_range(1, 10); + navigationGrid->attach_next_to(*panFactorLabel, Gtk::POS_LEFT, 1, 1); + navigationGrid->attach_next_to(*panFactor, *panFactorLabel, Gtk::POS_RIGHT, 1, 1); - rememberZoomPanCheckbutton = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_REMEMBERZOOMPAN")) ); - setExpandAlignProperties (rememberZoomPanCheckbutton, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); - rememberZoomPanCheckbutton->set_tooltip_text (M ("PREFERENCES_REMEMBERZOOMPAN_TOOLTIP")); + rememberZoomPanCheckbutton = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_REMEMBERZOOMPAN"))); + setExpandAlignProperties(rememberZoomPanCheckbutton, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + rememberZoomPanCheckbutton->set_tooltip_text(M("PREFERENCES_REMEMBERZOOMPAN_TOOLTIP")); - navigationGrid->attach_next_to (*rememberZoomPanCheckbutton, *panFactorLabel, Gtk::POS_BOTTOM, 2, 1); + navigationGrid->attach_next_to(*rememberZoomPanCheckbutton, *panFactorLabel, Gtk::POS_BOTTOM, 2, 1); - fnav->add (*navigationGrid); + fnav->add(*navigationGrid); vbGeneral->attach_next_to (*fnav, *fclip, Gtk::POS_RIGHT, 1, 1); // --------------------------------------------- - Gtk::Frame* fdg = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_EXTERNALEDITOR")) ); - setExpandAlignProperties (fdg, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - Gtk::Grid* externaleditorGrid = Gtk::manage ( new Gtk::Grid() ); - externaleditorGrid->set_column_spacing (4); - externaleditorGrid->set_row_spacing (4); - setExpandAlignProperties (externaleditorGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Frame* fdg = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTERNALEDITOR"))); + setExpandAlignProperties(fdg, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Grid* externaleditorGrid = Gtk::manage(new Gtk::Grid()); + externaleditorGrid->set_column_spacing(4); + externaleditorGrid->set_row_spacing(4); + setExpandAlignProperties(externaleditorGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - edOther = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_EDITORCMDLINE") + ":")); - setExpandAlignProperties (edOther, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - editorToSendTo = Gtk::manage ( new Gtk::Entry () ); - setExpandAlignProperties (editorToSendTo, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); + edOther = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EDITORCMDLINE") + ":")); + setExpandAlignProperties(edOther, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + editorToSendTo = Gtk::manage(new Gtk::Entry()); + setExpandAlignProperties(editorToSendTo, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); Gtk::RadioButton::Group ge = edOther->get_group(); #ifdef __APPLE__ - edGimp = Gtk::manage ( new Gtk::RadioButton ("GIMP") ); - setExpandAlignProperties (edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - edGimp->set_group (ge); - externaleditorGrid->attach_next_to (*edGimp, Gtk::POS_TOP, 2, 1); + edGimp = Gtk::manage(new Gtk::RadioButton("GIMP")); + setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + edGimp->set_group(ge); + externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1); - edPS = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_PSPATH") + ":")); - setExpandAlignProperties (edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - psDir = Gtk::manage ( new MyFileChooserButton (M ("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); - setExpandAlignProperties (psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to (*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to (*psDir, *edPS, Gtk::POS_RIGHT, 1, 1); - edPS->set_group (ge); + edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":")); + setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + psDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1); + externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1); + edPS->set_group(ge); - externaleditorGrid->attach_next_to (*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to (*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); + externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1); + externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); #elif defined WIN32 - edGimp = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_GIMPPATH") + ":") ); - setExpandAlignProperties (edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - gimpDir = Gtk::manage ( new MyFileChooserButton (M ("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); - setExpandAlignProperties (gimpDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to (*edGimp, Gtk::POS_TOP, 1, 1); - externaleditorGrid->attach_next_to (*gimpDir, *edGimp, Gtk::POS_RIGHT, 1, 1); - edGimp->set_group (ge); + edGimp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_GIMPPATH") + ":")); + setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + gimpDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(gimpDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 1, 1); + externaleditorGrid->attach_next_to(*gimpDir, *edGimp, Gtk::POS_RIGHT, 1, 1); + edGimp->set_group(ge); - edPS = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_PSPATH") + ":") ); - setExpandAlignProperties (edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - psDir = Gtk::manage ( new MyFileChooserButton (M ("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); - setExpandAlignProperties (psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to (*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to (*psDir, *edPS, Gtk::POS_RIGHT, 1, 1); - edPS->set_group (ge); + edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":")); + setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + psDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1); + externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1); + edPS->set_group(ge); - externaleditorGrid->attach_next_to (*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to (*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); + externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1); + externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); #else - edGimp = Gtk::manage ( new Gtk::RadioButton ("GIMP") ); - setExpandAlignProperties (edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to (*edGimp, Gtk::POS_TOP, 2, 1); - edGimp->set_group (ge); + edGimp = Gtk::manage(new Gtk::RadioButton("GIMP")); + setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1); + edGimp->set_group(ge); - externaleditorGrid->attach_next_to (*edOther, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to (*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); + externaleditorGrid->attach_next_to(*edOther, *edGimp, Gtk::POS_BOTTOM, 1, 1); + externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); #endif - fdg->add (*externaleditorGrid); + fdg->add(*externaleditorGrid); vbGeneral->attach_next_to (*fdg, *fclip, Gtk::POS_BOTTOM, 2, 1); - - langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::langAutoDetectToggled)); + langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::langAutoDetectToggled)); tconn = themeCBT->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::themeChanged) ); fconn = mainFontFB->signal_font_set().connect ( sigc::mem_fun (*this, &Preferences::fontChanged) ); cpfconn = colorPickerFontFB->signal_font_set().connect ( sigc::mem_fun (*this, &Preferences::cpFontChanged) ); @@ -1214,103 +1231,103 @@ Gtk::Widget* Preferences::getGeneralPanel () return swGeneral; } -Gtk::Widget* Preferences::getFileBrowserPanel () +Gtk::Widget* Preferences::getFileBrowserPanel() { swFileBrowser = Gtk::manage(new Gtk::ScrolledWindow()); swFileBrowser->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); Gtk::VBox* vbFileBrowser = Gtk::manage ( new Gtk::VBox () ); - Gtk::Frame* fsd = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_STARTUPIMDIR")) ); + Gtk::Frame* fsd = Gtk::manage(new Gtk::Frame(M("PREFERENCES_STARTUPIMDIR"))); - sdcurrent = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_DIRSOFTWARE")) ); - sdlast = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_DIRLAST")) ); - sdhome = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_DIRHOME")) ); - sdother = Gtk::manage ( new Gtk::RadioButton (M ("PREFERENCES_DIROTHER") + ": ") ); - startupdir = Gtk::manage ( new Gtk::Entry () ); + sdcurrent = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRSOFTWARE"))); + sdlast = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRLAST"))); + sdhome = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIRHOME"))); + sdother = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_DIROTHER") + ": ")); + startupdir = Gtk::manage(new Gtk::Entry()); - Gtk::Button* sdselect = Gtk::manage ( new Gtk::Button () ); + Gtk::Button* sdselect = Gtk::manage(new Gtk::Button()); sdselect->set_image (*Gtk::manage (new RTImage ("folder-open-small.png"))); Gtk::RadioButton::Group opts = sdcurrent->get_group(); - sdlast->set_group (opts); - sdhome->set_group (opts); - sdother->set_group (opts); + sdlast->set_group(opts); + sdhome->set_group(opts); + sdother->set_group(opts); - Gtk::VBox* vbsd = Gtk::manage ( new Gtk::VBox () ); - vbsd->pack_start (*sdcurrent, Gtk::PACK_SHRINK, 0); - vbsd->pack_start (*sdlast, Gtk::PACK_SHRINK, 0); - vbsd->pack_start (*sdhome, Gtk::PACK_SHRINK, 0); - Gtk::HBox* otherbox = Gtk::manage ( new Gtk::HBox () ); - otherbox->pack_start (*sdother, Gtk::PACK_SHRINK); - otherbox->pack_start (*startupdir); - otherbox->pack_end (*sdselect, Gtk::PACK_SHRINK, 4); - vbsd->pack_start (*otherbox, Gtk::PACK_SHRINK, 0); + Gtk::VBox* vbsd = Gtk::manage(new Gtk::VBox()); + vbsd->pack_start(*sdcurrent, Gtk::PACK_SHRINK, 0); + vbsd->pack_start(*sdlast, Gtk::PACK_SHRINK, 0); + vbsd->pack_start(*sdhome, Gtk::PACK_SHRINK, 0); + Gtk::HBox* otherbox = Gtk::manage(new Gtk::HBox()); + otherbox->pack_start(*sdother, Gtk::PACK_SHRINK); + otherbox->pack_start(*startupdir); + otherbox->pack_end(*sdselect, Gtk::PACK_SHRINK, 4); + vbsd->pack_start(*otherbox, Gtk::PACK_SHRINK, 0); - fsd->add (*vbsd); + fsd->add(*vbsd); vbFileBrowser->pack_start (*fsd, Gtk::PACK_SHRINK, 4); - sdselect->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::selectStartupDir) ); + sdselect->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::selectStartupDir)); //--- - Gtk::Frame* fro = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_FBROWSEROPTS")) ); - showDateTime = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_SHOWDATETIME")) ); - showBasicExif = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_SHOWBASICEXIF")) ); - showExpComp = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_SHOWEXPOSURECOMPENSATION")) ); - Gtk::VBox* vbro = Gtk::manage ( new Gtk::VBox () ); - Gtk::HBox* hbro1 = Gtk::manage ( new Gtk::HBox () ); - Gtk::HBox* hbro0 = Gtk::manage ( new Gtk::HBox () ); - overlayedFileNames = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_OVERLAY_FILENAMES")) ); - filmStripOverlayedFileNames = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_OVERLAY_FILENAMES_FILMSTRIP")) ); - sameThumbSize = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT")) ); - sameThumbSize->set_tooltip_text (M ("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT_HINT")); - ckbInternalThumbIfUntouched = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_INTERNALTHUMBIFUNTOUCHED"))); + Gtk::Frame* fro = Gtk::manage(new Gtk::Frame(M("PREFERENCES_FBROWSEROPTS"))); + showDateTime = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWDATETIME"))); + showBasicExif = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWBASICEXIF"))); + showExpComp = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_SHOWEXPOSURECOMPENSATION"))); + Gtk::VBox* vbro = Gtk::manage(new Gtk::VBox()); + Gtk::HBox* hbro1 = Gtk::manage(new Gtk::HBox()); + Gtk::HBox* hbro0 = Gtk::manage(new Gtk::HBox()); + overlayedFileNames = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_OVERLAY_FILENAMES"))); + filmStripOverlayedFileNames = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_OVERLAY_FILENAMES_FILMSTRIP"))); + sameThumbSize = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT"))); + sameThumbSize->set_tooltip_text(M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT_HINT")); + ckbInternalThumbIfUntouched = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_INTERNALTHUMBIFUNTOUCHED"))); - vbro->pack_start (*showDateTime, Gtk::PACK_SHRINK, 0); - Gtk::Label* dflab = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_DATEFORMAT") + ":", Gtk::ALIGN_START)); - dateformat = Gtk::manage ( new Gtk::Entry () ); - dateformat->set_tooltip_markup (M ("PREFERENCES_DATEFORMATHINT")); - dflab->set_tooltip_markup (M ("PREFERENCES_DATEFORMATHINT")); - hbro0->pack_start (*dflab, Gtk::PACK_SHRINK, 4); - hbro0->pack_start (*dateformat, Gtk::PACK_SHRINK, 0); + vbro->pack_start(*showDateTime, Gtk::PACK_SHRINK, 0); + Gtk::Label* dflab = Gtk::manage(new Gtk::Label(M("PREFERENCES_DATEFORMAT") + ":", Gtk::ALIGN_START)); + dateformat = Gtk::manage(new Gtk::Entry()); + dateformat->set_tooltip_markup(M("PREFERENCES_DATEFORMATHINT")); + dflab->set_tooltip_markup(M("PREFERENCES_DATEFORMATHINT")); + hbro0->pack_start(*dflab, Gtk::PACK_SHRINK, 4); + hbro0->pack_start(*dateformat, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*hbro0, Gtk::PACK_SHRINK, 0); - hbro1->pack_start (*showBasicExif, Gtk::PACK_SHRINK, 0); - hbro1->pack_start (*showExpComp, Gtk::PACK_SHRINK, 4); - vbro->pack_start (*hbro1, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*overlayedFileNames, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*filmStripOverlayedFileNames, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*sameThumbSize, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*ckbInternalThumbIfUntouched, Gtk::PACK_SHRINK, 0); + vbro->pack_start(*hbro0, Gtk::PACK_SHRINK, 0); + hbro1->pack_start(*showBasicExif, Gtk::PACK_SHRINK, 0); + hbro1->pack_start(*showExpComp, Gtk::PACK_SHRINK, 4); + vbro->pack_start(*hbro1, Gtk::PACK_SHRINK, 0); + vbro->pack_start(*overlayedFileNames, Gtk::PACK_SHRINK, 0); + vbro->pack_start(*filmStripOverlayedFileNames, Gtk::PACK_SHRINK, 0); + vbro->pack_start(*sameThumbSize, Gtk::PACK_SHRINK, 0); + vbro->pack_start(*ckbInternalThumbIfUntouched, Gtk::PACK_SHRINK, 0); - Gtk::HBox* hbrecent = Gtk::manage ( new Gtk::HBox () ); + Gtk::HBox* hbrecent = Gtk::manage(new Gtk::HBox()); Gtk::Label* labrecent = Gtk::manage (new Gtk::Label (M("PREFERENCES_MAXRECENTFOLDERS") + ":", Gtk::ALIGN_START)); - maxRecentFolders = Gtk::manage ( new Gtk::SpinButton () ); - hbrecent->pack_start (*labrecent, Gtk::PACK_SHRINK, 4); - hbrecent->pack_start (*maxRecentFolders, Gtk::PACK_SHRINK, 4); - maxRecentFolders->set_digits (0); - maxRecentFolders->set_increments (1, 5); - maxRecentFolders->set_range (1, 25); - vbro->pack_start (*hbrecent, Gtk::PACK_SHRINK, 4); + maxRecentFolders = Gtk::manage(new Gtk::SpinButton()); + hbrecent->pack_start(*labrecent, Gtk::PACK_SHRINK, 4); + hbrecent->pack_start(*maxRecentFolders, Gtk::PACK_SHRINK, 4); + maxRecentFolders->set_digits(0); + maxRecentFolders->set_increments(1, 5); + maxRecentFolders->set_range(1, 25); + vbro->pack_start(*hbrecent, Gtk::PACK_SHRINK, 4); - fro->add (*vbro); + fro->add(*vbro); - Gtk::Frame* frmnu = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_MENUOPTIONS")) ); + Gtk::Frame* frmnu = Gtk::manage(new Gtk::Frame(M("PREFERENCES_MENUOPTIONS"))); Gtk::Grid* menuGrid = Gtk::manage(new Gtk::Grid()); menuGrid->get_style_context()->add_class("grid-spacing"); setExpandAlignProperties(menuGrid, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - ckbmenuGroupRank = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPRANK")) ); + ckbmenuGroupRank = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPRANK"))); setExpandAlignProperties(ckbmenuGroupRank, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - ckbmenuGroupLabel = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPLABEL")) ); - ckbmenuGroupFileOperations = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPFILEOPERATIONS")) ); + ckbmenuGroupLabel = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPLABEL"))); + ckbmenuGroupFileOperations = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPFILEOPERATIONS"))); setExpandAlignProperties(ckbmenuGroupFileOperations, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - ckbmenuGroupProfileOperations = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPPROFILEOPERATIONS")) ); - ckbmenuGroupExtProg = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_MENUGROUPEXTPROGS")) ); + ckbmenuGroupProfileOperations = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPPROFILEOPERATIONS"))); + ckbmenuGroupExtProg = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPEXTPROGS"))); Gtk::Label* groupRestartNeeded = Gtk::manage(new Gtk::Label (Glib::ustring ("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")", Gtk::ALIGN_START)); @@ -1324,54 +1341,54 @@ Gtk::Widget* Preferences::getFileBrowserPanel () frmnu->add (*menuGrid); - Gtk::Frame* fre = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_PARSEDEXT")) ); - Gtk::VBox* vbre = Gtk::manage ( new Gtk::VBox () ); - Gtk::HBox* hb0 = Gtk::manage ( new Gtk::HBox () ); + Gtk::Frame* fre = Gtk::manage(new Gtk::Frame(M("PREFERENCES_PARSEDEXT"))); + Gtk::VBox* vbre = Gtk::manage(new Gtk::VBox()); + Gtk::HBox* hb0 = Gtk::manage(new Gtk::HBox()); Gtk::Label* elab = Gtk::manage (new Gtk::Label (M("PREFERENCES_PARSEDEXTADD") + ":", Gtk::ALIGN_START)); - hb0->pack_start (*elab, Gtk::PACK_SHRINK, 4); - extension = Gtk::manage ( new Gtk::Entry () ); - extension->set_width_chars (5); - extension->set_max_width_chars (5); - hb0->pack_start (*extension); - addExt = Gtk::manage ( new Gtk::Button () ); - delExt = Gtk::manage ( new Gtk::Button () ); - moveExtUp = Gtk::manage ( new Gtk::Button () ); - moveExtDown = Gtk::manage ( new Gtk::Button () ); - addExt->set_tooltip_text (M ("PREFERENCES_PARSEDEXTADDHINT")); - delExt->set_tooltip_text (M ("PREFERENCES_PARSEDEXTDELHINT")); - moveExtUp->set_tooltip_text (M ("PREFERENCES_PARSEDEXTUPHINT")); - moveExtDown->set_tooltip_text (M ("PREFERENCES_PARSEDEXTDOWNHINT")); + hb0->pack_start(*elab, Gtk::PACK_SHRINK, 4); + extension = Gtk::manage(new Gtk::Entry()); + extension->set_width_chars(5); + extension->set_max_width_chars(5); + hb0->pack_start(*extension); + addExt = Gtk::manage(new Gtk::Button()); + delExt = Gtk::manage(new Gtk::Button()); + moveExtUp = Gtk::manage(new Gtk::Button()); + moveExtDown = Gtk::manage(new Gtk::Button()); + addExt->set_tooltip_text(M("PREFERENCES_PARSEDEXTADDHINT")); + delExt->set_tooltip_text(M("PREFERENCES_PARSEDEXTDELHINT")); + moveExtUp->set_tooltip_text(M("PREFERENCES_PARSEDEXTUPHINT")); + moveExtDown->set_tooltip_text(M("PREFERENCES_PARSEDEXTDOWNHINT")); Gtk::Image* addExtImg = Gtk::manage ( new RTImage ("add-small.png") ); Gtk::Image* delExtImg = Gtk::manage ( new RTImage ("remove-small.png") ); - Gtk::Image* moveExtUpImg = Gtk::manage ( new RTImage ("arrow-up-small.png") ); - Gtk::Image* moveExtDownImg = Gtk::manage ( new RTImage ("arrow-down-small.png") ); - addExt->add (*addExtImg); - delExt->add (*delExtImg); - moveExtUp->set_image (*moveExtUpImg); - moveExtDown->set_image (*moveExtDownImg); - hb0->pack_end (*moveExtDown, Gtk::PACK_SHRINK, 4); - hb0->pack_end (*moveExtUp, Gtk::PACK_SHRINK, 4); - hb0->pack_end (*delExt, Gtk::PACK_SHRINK, 4); - hb0->pack_end (*addExt, Gtk::PACK_SHRINK, 4); - extensions = Gtk::manage ( new Gtk::TreeView () ); - Gtk::ScrolledWindow* hscrollw = Gtk::manage ( new Gtk::ScrolledWindow () ); - hscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); - hscrollw->add (*extensions); - extensionModel = Gtk::ListStore::create (extensionColumns); - extensions->set_model (extensionModel); - extensions->append_column_editable ("Enabled", extensionColumns.enabled); - extensions->append_column ("Extension", extensionColumns.ext); - extensions->set_headers_visible (false); - vbre->pack_start (*hscrollw); - vbre->pack_start (*hb0, Gtk::PACK_SHRINK, 4); + Gtk::Image* moveExtUpImg = Gtk::manage(new RTImage("arrow-up-small.png")); + Gtk::Image* moveExtDownImg = Gtk::manage(new RTImage("arrow-down-small.png")); + addExt->add(*addExtImg); + delExt->add(*delExtImg); + moveExtUp->set_image(*moveExtUpImg); + moveExtDown->set_image(*moveExtDownImg); + hb0->pack_end(*moveExtDown, Gtk::PACK_SHRINK, 4); + hb0->pack_end(*moveExtUp, Gtk::PACK_SHRINK, 4); + hb0->pack_end(*delExt, Gtk::PACK_SHRINK, 4); + hb0->pack_end(*addExt, Gtk::PACK_SHRINK, 4); + extensions = Gtk::manage(new Gtk::TreeView()); + Gtk::ScrolledWindow* hscrollw = Gtk::manage(new Gtk::ScrolledWindow()); + hscrollw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + hscrollw->add(*extensions); + extensionModel = Gtk::ListStore::create(extensionColumns); + extensions->set_model(extensionModel); + extensions->append_column_editable("Enabled", extensionColumns.enabled); + extensions->append_column("Extension", extensionColumns.ext); + extensions->set_headers_visible(false); + vbre->pack_start(*hscrollw); + vbre->pack_start(*hb0, Gtk::PACK_SHRINK, 4); - fre->add (*vbre); + fre->add(*vbre); // Cache Gtk::Frame* frc = Gtk::manage (new Gtk::Frame(M("PREFERENCES_CACHEOPTS"))); Gtk::VBox* vbc = Gtk::manage (new Gtk::VBox()); - frc->add (*vbc); + frc->add(*vbc); Gtk::Grid* cacheGrid = Gtk::manage(new Gtk::Grid()); cacheGrid->get_style_context()->add_class("grid-spacing"); @@ -1429,23 +1446,23 @@ Gtk::Widget* Preferences::getFileBrowserPanel () clearSafetyLbl->set_line_wrap(true); vbc->pack_start(*clearSafetyLbl, Gtk::PACK_SHRINK, 4); - Gtk::HBox* hb6 = Gtk::manage ( new Gtk::HBox () ); - Gtk::VBox* vb6 = Gtk::manage ( new Gtk::VBox () ); + Gtk::HBox* hb6 = Gtk::manage(new Gtk::HBox()); + Gtk::VBox* vb6 = Gtk::manage(new Gtk::VBox()); - vb6->pack_start (*fro); - vb6->pack_start (*frmnu); - vb6->pack_end (*frc); - hb6->pack_start (*vb6); - hb6->pack_start (*fre); - hb6->set_spacing (4); + vb6->pack_start(*fro); + vb6->pack_start(*frmnu); + vb6->pack_end(*frc); + hb6->pack_start(*vb6); + hb6->pack_start(*fre); + hb6->set_spacing(4); vbFileBrowser->pack_start (*hb6, Gtk::PACK_SHRINK, 4); - addExt->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::addExtPressed) ); - delExt->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::delExtPressed) ); - moveExtUp->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::moveExtUpPressed) ); - moveExtDown->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::moveExtDownPressed) ); - extension->signal_activate().connect ( sigc::mem_fun (*this, &Preferences::addExtPressed) ); + addExt->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::addExtPressed)); + delExt->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::delExtPressed)); + moveExtUp->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::moveExtUpPressed)); + moveExtDown->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::moveExtDownPressed)); + extension->signal_activate().connect(sigc::mem_fun(*this, &Preferences::addExtPressed)); clearThumbsBtn->signal_clicked().connect ( sigc::mem_fun (*this, &Preferences::clearThumbImagesPressed) ); if (moptions.saveParamsCache) { clearProfilesBtn->signal_clicked().connect(sigc::mem_fun(*this, &Preferences::clearProfilesPressed)); @@ -1463,44 +1480,44 @@ Gtk::Widget* Preferences::getSoundsPanel () Gtk::VBox* vbSounds = Gtk::manage(new Gtk::VBox ()); - ckbSndEnable = Gtk::manage ( new Gtk::CheckButton (M ("GENERAL_ENABLE"))); - sndEnableConn = ckbSndEnable->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::sndEnableToggled)); + ckbSndEnable = Gtk::manage(new Gtk::CheckButton(M("GENERAL_ENABLE"))); + sndEnableConn = ckbSndEnable->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::sndEnableToggled)); vbSounds->pack_start (*ckbSndEnable, Gtk::PACK_SHRINK, 4); - Gtk::HBox* hblSndHelp = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* hblSndHelp = Gtk::manage(new Gtk::HBox()); Gtk::Label* lSndHelp = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_HELP"), Gtk::ALIGN_START)); - hblSndHelp->pack_start (*lSndHelp, Gtk::PACK_SHRINK, 4); + hblSndHelp->pack_start(*lSndHelp, Gtk::PACK_SHRINK, 4); vbSounds->pack_start (*hblSndHelp, Gtk::PACK_SHRINK, 4); // BatchQueueDone - Gtk::HBox* pBatchQueueDone = Gtk::manage ( new Gtk::HBox() ); + Gtk::HBox* pBatchQueueDone = Gtk::manage(new Gtk::HBox()); Gtk::Label* lSndBatchQueueDone = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_QUEUEDONE") + Glib::ustring (":"), Gtk::ALIGN_START)); pBatchQueueDone->pack_start (*lSndBatchQueueDone, Gtk::PACK_SHRINK, 4); - txtSndBatchQueueDone = Gtk::manage (new Gtk::Entry()); - pBatchQueueDone->pack_end (*txtSndBatchQueueDone, Gtk::PACK_EXPAND_WIDGET, 4); + txtSndBatchQueueDone = Gtk::manage(new Gtk::Entry()); + pBatchQueueDone->pack_end(*txtSndBatchQueueDone, Gtk::PACK_EXPAND_WIDGET, 4); vbSounds->pack_start (*pBatchQueueDone, Gtk::PACK_SHRINK, 4); // LngEditProcDone - Gtk::HBox* pSndLngEditProcDone = Gtk::manage ( new Gtk::HBox() ); + Gtk::HBox* pSndLngEditProcDone = Gtk::manage(new Gtk::HBox()); Gtk::Label* lSndLngEditProcDone = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_LNGEDITPROCDONE") + Glib::ustring (":"), Gtk::ALIGN_START)); - pSndLngEditProcDone->pack_start (*lSndLngEditProcDone, Gtk::PACK_SHRINK, 4); + pSndLngEditProcDone->pack_start(*lSndLngEditProcDone, Gtk::PACK_SHRINK, 4); - txtSndLngEditProcDone = Gtk::manage (new Gtk::Entry()); - pSndLngEditProcDone->pack_start (*txtSndLngEditProcDone, Gtk::PACK_EXPAND_WIDGET, 4); + txtSndLngEditProcDone = Gtk::manage(new Gtk::Entry()); + pSndLngEditProcDone->pack_start(*txtSndLngEditProcDone, Gtk::PACK_EXPAND_WIDGET, 4); Gtk::Label* lSndLngEditProcDoneSecs = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_THRESHOLDSECS") + Glib::ustring (":"), Gtk::ALIGN_START)); - pSndLngEditProcDone->pack_start (*lSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 12); + pSndLngEditProcDone->pack_start(*lSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 12); - spbSndLngEditProcDoneSecs = Gtk::manage ( new Gtk::SpinButton () ); - spbSndLngEditProcDoneSecs->set_digits (1); - spbSndLngEditProcDoneSecs->set_increments (0.5, 1); - spbSndLngEditProcDoneSecs->set_range (0, 10); - pSndLngEditProcDone->pack_end (*spbSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 4); + spbSndLngEditProcDoneSecs = Gtk::manage(new Gtk::SpinButton()); + spbSndLngEditProcDoneSecs->set_digits(1); + spbSndLngEditProcDoneSecs->set_increments(0.5, 1); + spbSndLngEditProcDoneSecs->set_range(0, 10); + pSndLngEditProcDone->pack_end(*spbSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 4); vbSounds->pack_start (*pSndLngEditProcDone, Gtk::PACK_SHRINK, 4); @@ -1510,7 +1527,7 @@ Gtk::Widget* Preferences::getSoundsPanel () return swSounds; } -void Preferences::parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext) +void Preferences::parseDir(Glib::ustring dirname, std::vector& items, Glib::ustring ext) { if (dirname.empty()) { @@ -1521,26 +1538,26 @@ void Preferences::parseDir (Glib::ustring dirname, std::vector& i Glib::Dir* dir = nullptr; try { - dir = new Glib::Dir (dirname); + dir = new Glib::Dir(dirname); } catch (const Glib::Error& e) { return; } for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) { - Glib::ustring fname = Glib::build_filename (dirname, *i); + Glib::ustring fname = Glib::build_filename(dirname, *i); Glib::ustring sname = *i; // ignore directories - if (!Glib::file_test (fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= ext.size() && sname.substr (sname.size() - ext.size(), ext.size()).casefold() == ext) { - items.push_back (sname.substr (0, sname.size() - ext.size())); + if (!Glib::file_test(fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= ext.size() && sname.substr(sname.size() - ext.size(), ext.size()).casefold() == ext) { + items.push_back(sname.substr(0, sname.size() - ext.size())); } } - std::sort (items.begin(), items.end()); + std::sort(items.begin(), items.end()); delete dir; } -void Preferences::parseThemeDir (Glib::ustring dirname) +void Preferences::parseThemeDir(Glib::ustring dirname) { if (dirname.empty()) { @@ -1551,24 +1568,24 @@ void Preferences::parseThemeDir (Glib::ustring dirname) Glib::Dir* dir = nullptr; try { - dir = new Glib::Dir (dirname); + dir = new Glib::Dir(dirname); } catch (const Glib::Error& e) { return; } for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) { - Glib::ustring fname = Glib::build_filename (dirname, *i); + Glib::ustring fname = Glib::build_filename(dirname, *i); Glib::ustring sname = *i; // ignore directories and filter out unsupported theme - if (regex->match (sname, matchInfo) && !Glib::file_test (fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= 4) { + if (regex->match(sname, matchInfo) && !Glib::file_test(fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= 4) { bool keepIt = false; - Glib::ustring fname2 = matchInfo.fetch (1); - Glib::ustring minMinor = matchInfo.fetch (2); - Glib::ustring maxMinor = matchInfo.fetch (3); + Glib::ustring fname2 = matchInfo.fetch(1); + Glib::ustring minMinor = matchInfo.fetch(2); + Glib::ustring maxMinor = matchInfo.fetch(3); if (!minMinor.empty()) { - guint64 minMinorVal = g_ascii_strtoll (minMinor.c_str(), 0, 0); + guint64 minMinorVal = g_ascii_strtoll(minMinor.c_str(), 0, 0); if ((guint64)GTK_MINOR_VERSION >= minMinorVal) { keepIt = true; @@ -1576,7 +1593,7 @@ void Preferences::parseThemeDir (Glib::ustring dirname) } if (!maxMinor.empty()) { - guint64 maxMinorVal = g_ascii_strtoll (maxMinor.c_str(), 0, 0); + guint64 maxMinorVal = g_ascii_strtoll(maxMinor.c_str(), 0, 0); if ((guint64)GTK_MINOR_VERSION <= maxMinorVal) { keepIt = true; @@ -1584,19 +1601,19 @@ void Preferences::parseThemeDir (Glib::ustring dirname) } if (keepIt) { - themeFNames.push_back (ThemeFilename (matchInfo.fetch (1), sname.substr (0, sname.size() - 4))); + themeFNames.push_back(ThemeFilename(matchInfo.fetch(1), sname.substr(0, sname.size() - 4))); } } } - std::sort (themeFNames.begin(), themeFNames.end(), [] (const ThemeFilename & firstDir, const ThemeFilename & secondDir) { + std::sort(themeFNames.begin(), themeFNames.end(), [](const ThemeFilename & firstDir, const ThemeFilename & secondDir) { return firstDir.longFName < secondDir.longFName; }); delete dir; } -void Preferences::storePreferences () +void Preferences::storePreferences() { // With the new mechanism, we can't be sure of the availability of the DEFPROFILE_RAW & DEFPROFILE_IMG profiles, @@ -1617,18 +1634,18 @@ void Preferences::storePreferences () moptions.dateFormat = dateformat->get_text(); moptions.panAccelFactor = (int)panFactor->get_value(); moptions.rememberZoomAndPan = rememberZoomPanCheckbutton->get_active(); - moptions.fbShowDateTime = showDateTime->get_active (); - moptions.fbShowBasicExif = showBasicExif->get_active (); - moptions.fbShowExpComp = showExpComp->get_active (); + moptions.fbShowDateTime = showDateTime->get_active(); + moptions.fbShowBasicExif = showBasicExif->get_active(); + moptions.fbShowExpComp = showExpComp->get_active(); moptions.menuGroupRank = ckbmenuGroupRank->get_active(); moptions.menuGroupLabel = ckbmenuGroupLabel->get_active(); moptions.menuGroupFileOperations = ckbmenuGroupFileOperations->get_active(); moptions.menuGroupProfileOperations = ckbmenuGroupProfileOperations->get_active(); moptions.menuGroupExtProg = ckbmenuGroupExtProg->get_active(); - moptions.highlightThreshold = (int)hlThresh->get_value (); - moptions.shadowThreshold = (int)shThresh->get_value (); - moptions.language = languages->get_active_text (); - moptions.languageAutoDetect = ckbLangAutoDetect->get_active (); + moptions.highlightThreshold = (int)hlThresh->get_value(); + moptions.shadowThreshold = (int)shThresh->get_value(); + moptions.language = languages->get_active_text(); + moptions.languageAutoDetect = ckbLangAutoDetect->get_active(); moptions.theme = themeFNames.at (themeCBT->get_active_row_number ()).longFName; Gdk::RGBA cropCol = cropMaskColorCB->get_rgba(); @@ -1642,9 +1659,9 @@ void Preferences::storePreferences () moptions.navGuideBrush[1] = NavGuideCol.get_green(); moptions.navGuideBrush[2] = NavGuideCol.get_blue(); moptions.navGuideBrush[3] = navGuideColorCB->get_alpha() / 65535.0; - Pango::FontDescription fd (mainFontFB->get_font_name()); + if (newFont) { moptions.fontFamily = fd.get_family(); moptions.fontSize = fd.get_size() / Pango::SCALE; @@ -1660,42 +1677,42 @@ void Preferences::storePreferences () moptions.pseudoHiDPISupport = pseudoHiDPI->get_active(); #ifdef WIN32 - moptions.gimpDir = gimpDir->get_filename (); - moptions.psDir = psDir->get_filename (); + moptions.gimpDir = gimpDir->get_filename(); + moptions.psDir = psDir->get_filename(); #elif defined __APPLE__ - moptions.psDir = psDir->get_filename (); + moptions.psDir = psDir->get_filename(); #endif - moptions.customEditorProg = editorToSendTo->get_text (); + moptions.customEditorProg = editorToSendTo->get_text(); - if (edGimp->get_active ()) { + if (edGimp->get_active()) { moptions.editorToSendTo = 1; } #ifdef WIN32 - else if (edPS->get_active ()) { + else if (edPS->get_active()) { moptions.editorToSendTo = 2; } #elif defined __APPLE__ - else if (edPS->get_active ()) { + else if (edPS->get_active()) { moptions.editorToSendTo = 2; } #endif - else if (edOther->get_active ()) { + else if (edOther->get_active()) { moptions.editorToSendTo = 3; } moptions.CPBPath = txtCustProfBuilderPath->get_text(); - moptions.CPBKeys = CPBKeyType (custProfBuilderLabelType->get_active_row_number()); + moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); if (!prtProfile->get_active_row_number()) { moptions.rtSettings.printerProfile = ""; } else { - moptions.rtSettings.printerProfile = prtProfile->get_active_text (); + moptions.rtSettings.printerProfile = prtProfile->get_active_text(); } - switch (prtIntent->get_active_row_number ()) { + switch (prtIntent->get_active_row_number()) { default: case 0: moptions.rtSettings.printerIntent = rtengine::RI_PERCEPTUAL; @@ -1710,17 +1727,17 @@ void Preferences::storePreferences () break; } - moptions.rtSettings.printerBPC = prtBPC->get_active (); + moptions.rtSettings.printerBPC = prtBPC->get_active(); #if !defined(__APPLE__) // monitor profile not supported on apple if (!monProfile->get_active_row_number()) { moptions.rtSettings.monitorProfile = ""; } else { - moptions.rtSettings.monitorProfile = monProfile->get_active_text (); + moptions.rtSettings.monitorProfile = monProfile->get_active_text(); } - switch (monIntent->get_active_row_number ()) { + switch (monIntent->get_active_row_number()) { default: case 0: moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; @@ -1735,59 +1752,59 @@ void Preferences::storePreferences () break; } - moptions.rtSettings.monitorBPC = monBPC->get_active (); - moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); + moptions.rtSettings.monitorBPC = monBPC->get_active(); + moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active(); #endif - moptions.rtSettings.iccDirectory = iccDir->get_filename (); + moptions.rtSettings.iccDirectory = iccDir->get_filename(); moptions.prevdemo = (prevdemo_t)cprevdemo->get_active_row_number (); moptions.serializeTiffRead = ctiffserialize->get_active(); - if (sdcurrent->get_active ()) { + if (sdcurrent->get_active()) { moptions.startupDir = STARTUPDIR_CURRENT; - } else if (sdhome->get_active ()) { + } else if (sdhome->get_active()) { moptions.startupDir = STARTUPDIR_HOME; - } else if (sdlast->get_active ()) { + } else if (sdlast->get_active()) { moptions.startupDir = STARTUPDIR_LAST; - } else if (sdother->get_active ()) { + } else if (sdother->get_active()) { moptions.startupDir = STARTUPDIR_CUSTOM; moptions.startupPath = startupdir->get_text(); } - moptions.parseExtensions.clear (); - moptions.parseExtensionsEnabled.clear (); - Gtk::TreeNodeChildren c = extensionModel->children (); + moptions.parseExtensions.clear(); + moptions.parseExtensionsEnabled.clear(); + Gtk::TreeNodeChildren c = extensionModel->children(); for (size_t i = 0; i < c.size(); i++) { - moptions.parseExtensions.push_back (c[i][extensionColumns.ext]); - moptions.parseExtensionsEnabled.push_back (c[i][extensionColumns.enabled]); + moptions.parseExtensions.push_back(c[i][extensionColumns.ext]); + moptions.parseExtensionsEnabled.push_back(c[i][extensionColumns.enabled]); } moptions.maxRecentFolders = (int)maxRecentFolders->get_value(); moptions.maxThumbnailHeight = (int)maxThumbHeightSB->get_value (); moptions.maxCacheEntries = (int)maxCacheEntriesSB->get_value (); - moptions.overlayedFileNames = overlayedFileNames->get_active (); + moptions.overlayedFileNames = overlayedFileNames->get_active(); moptions.filmStripOverlayedFileNames = filmStripOverlayedFileNames->get_active(); moptions.sameThumbSize = sameThumbSize->get_active(); - moptions.internalThumbIfUntouched = ckbInternalThumbIfUntouched->get_active (); + moptions.internalThumbIfUntouched = ckbInternalThumbIfUntouched->get_active(); auto save_where = saveParamsPreference->get_active_row_number(); moptions.saveParamsFile = save_where == 0 || save_where == 2; moptions.saveParamsCache = save_where == 1 || save_where == 2; - moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); - moptions.useBundledProfiles = useBundledProfiles->get_active (); + moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number(); + moptions.useBundledProfiles = useBundledProfiles->get_active(); moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename(); moptions.clutsDir = clutsDir->get_filename(); - moptions.baBehav.resize (ADDSET_PARAM_NUM); + moptions.baBehav.resize(ADDSET_PARAM_NUM); for (Gtk::TreeIter sections = behModel->children().begin(); sections != behModel->children().end(); sections++) for (Gtk::TreeIter adjs = sections->children().begin(); adjs != sections->children().end(); adjs++) { - moptions.baBehav[adjs->get_value (behavColumns.addsetid)] = adjs->get_value (behavColumns.badd); + moptions.baBehav[adjs->get_value(behavColumns.addsetid)] = adjs->get_value(behavColumns.badd); } int editorMode = editorLayout->get_active_row_number(); @@ -1796,11 +1813,13 @@ void Preferences::storePreferences () moptions.mainNBVertical = editorMode == 1; moptions.curvebboxpos = curveBBoxPosC->get_active_row_number(); + moptions.complexity = complexitylocal->get_active_row_number(); moptions.histogramPosition = ckbHistogramPositionLeft->get_active() ? 1 : 2; moptions.FileBrowserToolbarSingleRow = ckbFileBrowserToolbarSingleRow->get_active(); moptions.showFilmStripToolBar = ckbShowFilmStripToolBar->get_active(); moptions.hideTPVScrollbar = ckbHideTPVScrollbar->get_active(); - moptions.overwriteOutputFile = chOverwriteOutputFile->get_active (); + moptions.overwriteOutputFile = chOverwriteOutputFile->get_active(); + moptions.showtooltip = ckbshowtooltiplocallab->get_active(); moptions.autoSaveTpOpen = ckbAutoSaveTpOpen->get_active(); @@ -1817,97 +1836,96 @@ void Preferences::storePreferences () // Sounds only on Windows and Linux #if defined(WIN32) || defined(__linux__) - moptions.sndEnable = ckbSndEnable->get_active (); - moptions.sndBatchQueueDone = txtSndBatchQueueDone->get_text (); - moptions.sndLngEditProcDone = txtSndLngEditProcDone->get_text (); - moptions.sndLngEditProcDoneSecs = spbSndLngEditProcDoneSecs->get_value (); + moptions.sndEnable = ckbSndEnable->get_active(); + moptions.sndBatchQueueDone = txtSndBatchQueueDone->get_text(); + moptions.sndLngEditProcDone = txtSndLngEditProcDone->get_text(); + moptions.sndLngEditProcDoneSecs = spbSndLngEditProcDoneSecs->get_value(); #endif moptions.cropGuides = Options::CropGuidesMode(cropGuidesCombo->get_active_row_number()); moptions.cropAutoFit = cropAutoFitCB->get_active(); } -void Preferences::fillPreferences () +void Preferences::fillPreferences() { - tconn.block (true); - fconn.block (true); - cpfconn.block (true); - sconn.block (true); - dfconn.block (true); - ffconn.block (true); - rpconn.block (true); - ipconn.block (true); - bpconn.block (true); + tconn.block(true); + fconn.block(true); + cpfconn.block(true); + sconn.block(true); + dfconn.block(true); + ffconn.block(true); + rpconn.block(true); + ipconn.block(true); + bpconn.block(true); - rprofiles->setActiveRowFromFullPath (moptions.defProfRaw); + rprofiles->setActiveRowFromFullPath(moptions.defProfRaw); forRAWComboChanged(); // update the tooltip - iprofiles->setActiveRowFromFullPath (moptions.defProfImg); + iprofiles->setActiveRowFromFullPath(moptions.defProfImg); forImageComboChanged(); // update the tooltip - dateformat->set_text (moptions.dateFormat); - panFactor->set_value (moptions.panAccelFactor); - rememberZoomPanCheckbutton->set_active (moptions.rememberZoomAndPan); - ctiffserialize->set_active (moptions.serializeTiffRead); + dateformat->set_text(moptions.dateFormat); + panFactor->set_value(moptions.panAccelFactor); + rememberZoomPanCheckbutton->set_active(moptions.rememberZoomAndPan); + ctiffserialize->set_active(moptions.serializeTiffRead); - setActiveTextOrIndex (*prtProfile, moptions.rtSettings.printerProfile, 0); + setActiveTextOrIndex(*prtProfile, moptions.rtSettings.printerProfile, 0); switch (moptions.rtSettings.printerIntent) { default: case rtengine::RI_PERCEPTUAL: - prtIntent->set_active (0); + prtIntent->set_active(0); break; case rtengine::RI_RELATIVE: - prtIntent->set_active (1); + prtIntent->set_active(1); break; case rtengine::RI_ABSOLUTE: - prtIntent->set_active (2); + prtIntent->set_active(2); break; } - prtBPC->set_active (moptions.rtSettings.printerBPC); + prtBPC->set_active(moptions.rtSettings.printerBPC); #if !defined(__APPLE__) // monitor profile not supported on apple - setActiveTextOrIndex (*monProfile, moptions.rtSettings.monitorProfile, 0); + setActiveTextOrIndex(*monProfile, moptions.rtSettings.monitorProfile, 0); switch (moptions.rtSettings.monitorIntent) { default: case rtengine::RI_PERCEPTUAL: - monIntent->set_active (0); + monIntent->set_active(0); break; case rtengine::RI_RELATIVE: - monIntent->set_active (1); + monIntent->set_active(1); break; case rtengine::RI_ABSOLUTE: - monIntent->set_active (2); + monIntent->set_active(2); break; } - monBPC->set_active (moptions.rtSettings.monitorBPC); - cbAutoMonProfile->set_active (moptions.rtSettings.autoMonitorProfile); + monBPC->set_active(moptions.rtSettings.monitorBPC); + cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif - if (Glib::file_test (moptions.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) { - iccDir->set_current_folder (moptions.rtSettings.iccDirectory); + if (Glib::file_test(moptions.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) { + iccDir->set_current_folder(moptions.rtSettings.iccDirectory); } cprevdemo->set_active (moptions.prevdemo); - - languages->set_active_text (moptions.language); - ckbLangAutoDetect->set_active (moptions.languageAutoDetect); - int themeNbr = getThemeRowNumber (moptions.theme); + languages->set_active_text(moptions.language); + ckbLangAutoDetect->set_active(moptions.languageAutoDetect); + int themeNbr = getThemeRowNumber(moptions.theme); themeCBT->set_active (themeNbr == -1 ? 0 : themeNbr); Gdk::RGBA cropCol; - cropCol.set_rgba (moptions.cutOverlayBrush[0], moptions.cutOverlayBrush[1], moptions.cutOverlayBrush[2]); + cropCol.set_rgba(moptions.cutOverlayBrush[0], moptions.cutOverlayBrush[1], moptions.cutOverlayBrush[2]); cropMaskColorCB->set_rgba (cropCol); cropMaskColorCB->set_alpha ( (unsigned short) (moptions.cutOverlayBrush[3] * 65535.0)); Gdk::RGBA NavGuideCol; - NavGuideCol.set_rgba (moptions.navGuideBrush[0], moptions.navGuideBrush[1], moptions.navGuideBrush[2]); + NavGuideCol.set_rgba(moptions.navGuideBrush[0], moptions.navGuideBrush[1], moptions.navGuideBrush[2]); navGuideColorCB->set_rgba (NavGuideCol); navGuideColorCB->set_alpha ( (unsigned short) (moptions.navGuideBrush[3] * 65535.0)); @@ -1925,63 +1943,63 @@ void Preferences::fillPreferences () pseudoHiDPI->set_active(options.pseudoHiDPISupport); - showDateTime->set_active (moptions.fbShowDateTime); - showBasicExif->set_active (moptions.fbShowBasicExif); - showExpComp->set_active (moptions.fbShowExpComp); - ckbmenuGroupRank->set_active (moptions.menuGroupRank); - ckbmenuGroupLabel->set_active (moptions.menuGroupLabel); - ckbmenuGroupFileOperations->set_active (moptions.menuGroupFileOperations); - ckbmenuGroupProfileOperations->set_active (moptions.menuGroupProfileOperations); - ckbmenuGroupExtProg->set_active (moptions.menuGroupExtProg); + showDateTime->set_active(moptions.fbShowDateTime); + showBasicExif->set_active(moptions.fbShowBasicExif); + showExpComp->set_active(moptions.fbShowExpComp); + ckbmenuGroupRank->set_active(moptions.menuGroupRank); + ckbmenuGroupLabel->set_active(moptions.menuGroupLabel); + ckbmenuGroupFileOperations->set_active(moptions.menuGroupFileOperations); + ckbmenuGroupProfileOperations->set_active(moptions.menuGroupProfileOperations); + ckbmenuGroupExtProg->set_active(moptions.menuGroupExtProg); - hlThresh->set_value (moptions.highlightThreshold); - shThresh->set_value (moptions.shadowThreshold); + hlThresh->set_value(moptions.highlightThreshold); + shThresh->set_value(moptions.shadowThreshold); - edGimp->set_active (moptions.editorToSendTo == 1); - edOther->set_active (moptions.editorToSendTo == 3); + edGimp->set_active(moptions.editorToSendTo == 1); + edOther->set_active(moptions.editorToSendTo == 3); #ifdef WIN32 - edPS->set_active (moptions.editorToSendTo == 2); + edPS->set_active(moptions.editorToSendTo == 2); - if (Glib::file_test (moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) { - gimpDir->set_current_folder (moptions.gimpDir); + if (Glib::file_test(moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) { + gimpDir->set_current_folder(moptions.gimpDir); } else { - gimpDir->set_current_folder (Glib::get_home_dir()); + gimpDir->set_current_folder(Glib::get_home_dir()); } - if (Glib::file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) { - psDir->set_current_folder (moptions.psDir); + if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) { + psDir->set_current_folder(moptions.psDir); } else { - psDir->set_current_folder (Glib::get_home_dir()); + psDir->set_current_folder(Glib::get_home_dir()); } #elif defined __APPLE__ - edPS->set_active (moptions.editorToSendTo == 2); + edPS->set_active(moptions.editorToSendTo == 2); - if (Glib::file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) { - psDir->set_current_folder (moptions.psDir); + if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) { + psDir->set_current_folder(moptions.psDir); } else { - psDir->set_current_folder (Glib::get_home_dir()); + psDir->set_current_folder(Glib::get_home_dir()); } #endif - editorToSendTo->set_text (moptions.customEditorProg); + editorToSendTo->set_text(moptions.customEditorProg); - txtCustProfBuilderPath->set_text (moptions.CPBPath); - custProfBuilderLabelType->set_active (moptions.CPBKeys); + txtCustProfBuilderPath->set_text(moptions.CPBPath); + custProfBuilderLabelType->set_active(moptions.CPBKeys); if (moptions.startupDir == STARTUPDIR_CURRENT) { - sdcurrent->set_active (); + sdcurrent->set_active(); } else if (moptions.startupDir == STARTUPDIR_LAST) { - sdlast->set_active (); + sdlast->set_active(); } else if (moptions.startupDir == STARTUPDIR_HOME) { - sdhome->set_active (); + sdhome->set_active(); } else if (moptions.startupDir == STARTUPDIR_CUSTOM) { - sdother->set_active (); - startupdir->set_text (moptions.startupPath); + sdother->set_active(); + startupdir->set_text(moptions.startupPath); } - extensionModel->clear (); + extensionModel->clear(); for (size_t i = 0; i < moptions.parseExtensions.size(); i++) { Gtk::TreeRow row = * (extensionModel->append()); @@ -1989,32 +2007,34 @@ void Preferences::fillPreferences () row[extensionColumns.ext] = moptions.parseExtensions[i]; } - maxRecentFolders->set_value (moptions.maxRecentFolders); + maxRecentFolders->set_value(moptions.maxRecentFolders); maxThumbHeightSB->set_value (moptions.maxThumbnailHeight); maxCacheEntriesSB->set_value (moptions.maxCacheEntries); - overlayedFileNames->set_active (moptions.overlayedFileNames); - filmStripOverlayedFileNames->set_active (moptions.filmStripOverlayedFileNames); - sameThumbSize->set_active (moptions.sameThumbSize); - ckbInternalThumbIfUntouched->set_active (moptions.internalThumbIfUntouched); + overlayedFileNames->set_active(moptions.overlayedFileNames); + filmStripOverlayedFileNames->set_active(moptions.filmStripOverlayedFileNames); + sameThumbSize->set_active(moptions.sameThumbSize); + ckbInternalThumbIfUntouched->set_active(moptions.internalThumbIfUntouched); - saveParamsPreference->set_active (moptions.saveParamsFile ? (moptions.saveParamsCache ? 2 : 0) : 1); + saveParamsPreference->set_active(moptions.saveParamsFile ? (moptions.saveParamsCache ? 2 : 0) : 1); - loadParamsPreference->set_active (moptions.paramsLoadLocation); - useBundledProfiles->set_active (moptions.useBundledProfiles); + loadParamsPreference->set_active(moptions.paramsLoadLocation); + useBundledProfiles->set_active(moptions.useBundledProfiles); if (!moptions.tabbedUI) { - editorLayout->set_active (moptions.mainNBVertical ? 1 : 0); + editorLayout->set_active(moptions.mainNBVertical ? 1 : 0); } else { - editorLayout->set_active (moptions.multiDisplayMode ? 3 : 2); + editorLayout->set_active(moptions.multiDisplayMode ? 3 : 2); } - curveBBoxPosC->set_active (moptions.curvebboxpos); - ckbHistogramPositionLeft->set_active (moptions.histogramPosition == 1); - ckbFileBrowserToolbarSingleRow->set_active (moptions.FileBrowserToolbarSingleRow); - ckbShowFilmStripToolBar->set_active (moptions.showFilmStripToolBar); - ckbHideTPVScrollbar->set_active (moptions.hideTPVScrollbar); + curveBBoxPosC->set_active(moptions.curvebboxpos); + complexitylocal->set_active(moptions.complexity); - ckbAutoSaveTpOpen->set_active (moptions.autoSaveTpOpen); + ckbHistogramPositionLeft->set_active(moptions.histogramPosition == 1); + ckbFileBrowserToolbarSingleRow->set_active(moptions.FileBrowserToolbarSingleRow); + ckbShowFilmStripToolBar->set_active(moptions.showFilmStripToolBar); + ckbHideTPVScrollbar->set_active(moptions.hideTPVScrollbar); + ckbshowtooltiplocallab->set_active(moptions.showtooltip); + ckbAutoSaveTpOpen->set_active(moptions.autoSaveTpOpen); threadsSpinBtn->set_value (moptions.rgbDenoiseThreadLimit); clutCacheSizeSB->set_value (moptions.clutCacheSize); @@ -2027,50 +2047,50 @@ void Preferences::fillPreferences () maxInspectorBuffersSB->set_value (moptions.maxInspectorBuffers); thumbnailInspectorMode->set_active(int(moptions.rtSettings.thumbnail_inspector_mode)); - darkFrameDir->set_current_folder ( moptions.rtSettings.darkFramesPath ); - darkFrameChanged (); + darkFrameDir->set_current_folder(moptions.rtSettings.darkFramesPath); + darkFrameChanged(); - flatFieldDir->set_current_folder ( moptions.rtSettings.flatFieldsPath ); - flatFieldChanged (); + flatFieldDir->set_current_folder(moptions.rtSettings.flatFieldsPath); + flatFieldChanged(); - clutsDir->set_current_folder ( moptions.clutsDir ); + clutsDir->set_current_folder(moptions.clutsDir); - addc.block (true); - setc.block (true); + addc.block(true); + setc.block(true); - moptions.baBehav.resize (ADDSET_PARAM_NUM); + moptions.baBehav.resize(ADDSET_PARAM_NUM); for (Gtk::TreeIter sections = behModel->children().begin(); sections != behModel->children().end(); ++sections) { for (Gtk::TreeIter adjs = sections->children().begin(); adjs != sections->children().end(); ++adjs) { const bool add = moptions.baBehav[adjs->get_value(behavColumns.addsetid)]; - adjs->set_value (behavColumns.badd, add); - adjs->set_value (behavColumns.bset, !add); + adjs->set_value(behavColumns.badd, add); + adjs->set_value(behavColumns.bset, !add); } } cropGuidesCombo->set_active(moptions.cropGuides); cropAutoFitCB->set_active(moptions.cropAutoFit); - addc.block (false); - setc.block (false); - cpfconn.block (false); - fconn.block (false); - tconn.block (false); - sconn.block (false); - dfconn.block (false); - ffconn.block (false); - rpconn.block (true); - ipconn.block (true); - bpconn.block (false); + addc.block(false); + setc.block(false); + cpfconn.block(false); + fconn.block(false); + tconn.block(false); + sconn.block(false); + dfconn.block(false); + ffconn.block(false); + rpconn.block(true); + ipconn.block(true); + bpconn.block(false); - chOverwriteOutputFile->set_active (moptions.overwriteOutputFile); + chOverwriteOutputFile->set_active(moptions.overwriteOutputFile); // Sounds only on Windows and Linux #if defined(WIN32) || defined(__linux__) - ckbSndEnable->set_active (moptions.sndEnable); - txtSndBatchQueueDone->set_text (moptions.sndBatchQueueDone); - txtSndLngEditProcDone->set_text (moptions.sndLngEditProcDone); - spbSndLngEditProcDoneSecs->set_value (moptions.sndLngEditProcDoneSecs); + ckbSndEnable->set_active(moptions.sndEnable); + txtSndBatchQueueDone->set_text(moptions.sndBatchQueueDone); + txtSndLngEditProcDone->set_text(moptions.sndLngEditProcDone); + spbSndLngEditProcDoneSecs->set_value(moptions.sndLngEditProcDoneSecs); #endif } @@ -2089,9 +2109,9 @@ void Preferences::savePressed () { } */ -void Preferences::autoMonProfileToggled () +void Preferences::autoMonProfileToggled() { - monProfile->set_sensitive (!cbAutoMonProfile->get_active()); + monProfile->set_sensitive(!cbAutoMonProfile->get_active()); } /* @@ -2100,43 +2120,43 @@ void Preferences::autocielabToggled () { } */ -void Preferences::sndEnableToggled () +void Preferences::sndEnableToggled() { - txtSndBatchQueueDone->set_sensitive (ckbSndEnable->get_active()); - txtSndLngEditProcDone->set_sensitive (ckbSndEnable->get_active()); - spbSndLngEditProcDoneSecs->set_sensitive (ckbSndEnable->get_active()); + txtSndBatchQueueDone->set_sensitive(ckbSndEnable->get_active()); + txtSndLngEditProcDone->set_sensitive(ckbSndEnable->get_active()); + spbSndLngEditProcDoneSecs->set_sensitive(ckbSndEnable->get_active()); } -void Preferences::langAutoDetectToggled () +void Preferences::langAutoDetectToggled() { - languages->set_sensitive (!ckbLangAutoDetect->get_active()); + languages->set_sensitive(!ckbLangAutoDetect->get_active()); } -void Preferences::okPressed () +void Preferences::okPressed() { - storePreferences (); + storePreferences(); workflowUpdate(); - options.copyFrom (&moptions); + options.copyFrom(&moptions); options.filterOutParsedExtensions(); try { - Options::save (); + Options::save(); } catch (Options::Error &e) { - Gtk::MessageDialog msgd (getToplevelWindow (this), e.get_msg(), true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true); + Gtk::MessageDialog msgd(getToplevelWindow(this), e.get_msg(), true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_CLOSE, true); msgd.run(); } dynProfilePanel->save(); - hide (); + hide(); } -void Preferences::cancelPressed () +void Preferences::cancelPressed() { // set the initial theme back if (themeFNames.at (themeCBT->get_active_row_number ()).longFName != options.theme) { RTImage::updateImages(); - switchThemeTo (options.theme); + switchThemeTo(options.theme); } // set the initial font back @@ -2144,59 +2164,59 @@ void Preferences::cancelPressed () if (fd.get_family() != options.fontFamily && (fd.get_size() / Pango::SCALE) != options.fontSize) { if (options.fontFamily == "default") { - switchFontTo (initialFontFamily, initialFontSize); + switchFontTo(initialFontFamily, initialFontSize); } else { - switchFontTo (options.fontFamily, options.fontSize); + switchFontTo(options.fontFamily, options.fontSize); } } // update the profileStore - if (useBundledProfiles->get_active () != options.useBundledProfiles) { + if (useBundledProfiles->get_active() != options.useBundledProfiles) { // we have to rescan with the old value - bpconn.block (true); - useBundledProfiles->set_active (false); + bpconn.block(true); + useBundledProfiles->set_active(false); bundledProfilesChanged(); - bpconn.block (false); + bpconn.block(false); } - hide (); + hide(); } -void Preferences::selectStartupDir () +void Preferences::selectStartupDir() { - Gtk::FileChooserDialog dialog (getToplevelWindow (this), M ("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + Gtk::FileChooserDialog dialog(getToplevelWindow(this), M("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); //dialog.set_transient_for(*this); //Add response buttons to the dialog: - dialog.add_button (M ("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); - dialog.add_button (M ("GENERAL_OPEN"), Gtk::RESPONSE_OK); + dialog.add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); + dialog.add_button(M("GENERAL_OPEN"), Gtk::RESPONSE_OK); int result = dialog.run(); if (result == Gtk::RESPONSE_OK) { - startupdir->set_text (dialog.get_filename()); + startupdir->set_text(dialog.get_filename()); } } -void Preferences::aboutPressed () +void Preferences::aboutPressed() { - splash = new Splash (*this); - splash->set_transient_for (*this); - splash->signal_delete_event().connect ( sigc::mem_fun (*this, &Preferences::splashClosed) ); - splash->show (); + splash = new Splash(*this); + splash->set_transient_for(*this); + splash->signal_delete_event().connect(sigc::mem_fun(*this, &Preferences::splashClosed)); + splash->show(); } -void Preferences::themeChanged () +void Preferences::themeChanged() { moptions.theme = themeFNames.at (themeCBT->get_active_row_number ()).longFName; RTImage::updateImages(); - switchThemeTo (moptions.theme); + switchThemeTo(moptions.theme); } -void Preferences::forRAWComboChanged () +void Preferences::forRAWComboChanged() { if (!rprofiles) { return; @@ -2209,17 +2229,17 @@ void Preferences::forRAWComboChanged () } if (selectedEntry->type == PSET_FOLDER) { - rpconn.block (true); - rprofiles->set_active (currRawRow); - rpconn.block (false); + rpconn.block(true); + rprofiles->set_active(currRawRow); + rpconn.block(false); } else { currRawRow = rprofiles->get_active(); } - rprofiles->set_tooltip_text (selectedEntry->label); + rprofiles->set_tooltip_text(selectedEntry->label); } -void Preferences::forImageComboChanged () +void Preferences::forImageComboChanged() { if (!iprofiles) { return; @@ -2232,29 +2252,29 @@ void Preferences::forImageComboChanged () } if (selectedEntry->type == PSET_FOLDER) { - ipconn.block (true); - iprofiles->set_active (currImgRow); - ipconn.block (false); + ipconn.block(true); + iprofiles->set_active(currImgRow); + ipconn.block(false); } else { currImgRow = rprofiles->get_active(); } - iprofiles->set_tooltip_text (iprofiles->getSelectedEntry()->label); + iprofiles->set_tooltip_text(iprofiles->getSelectedEntry()->label); } -void Preferences::layoutComboChanged () +void Preferences::layoutComboChanged() { - editorLayout->set_tooltip_text (editorLayout->get_active_text()); + editorLayout->set_tooltip_text(editorLayout->get_active_text()); } -void Preferences::bundledProfilesChanged () +void Preferences::bundledProfilesChanged() { - rpconn.block (true); - ipconn.block (true); + rpconn.block(true); + ipconn.block(true); // parseProfiles does use options.useBundledProfiles, so we temporarily change its value bool currValue = options.useBundledProfiles; - options.useBundledProfiles = useBundledProfiles->get_active (); + options.useBundledProfiles = useBundledProfiles->get_active(); // rescan the file's tree ProfileStore::getInstance()->parseProfiles(); // This will call Preferences::updateProfileList in return @@ -2262,24 +2282,24 @@ void Preferences::bundledProfilesChanged () // restoring back the old value options.useBundledProfiles = currValue; - ipconn.block (false); - rpconn.block (false); + ipconn.block(false); + rpconn.block(false); } -void Preferences::iccDirChanged () +void Preferences::iccDirChanged() { - const auto currentSelection = monProfile->get_active_text (); - const auto profiles = rtengine::ICCStore::getInstance ()->getProfilesFromDir (iccDir->get_filename ()); + const auto currentSelection = monProfile->get_active_text(); + const auto profiles = rtengine::ICCStore::getInstance()->getProfilesFromDir(iccDir->get_filename()); monProfile->remove_all(); - monProfile->append (M ("PREFERENCES_PROFILE_NONE")); + monProfile->append(M("PREFERENCES_PROFILE_NONE")); for (const auto& profile : profiles) { - monProfile->append (profile); + monProfile->append(profile); } - setActiveTextOrIndex (*monProfile, currentSelection, 0); + setActiveTextOrIndex(*monProfile, currentSelection, 0); } void Preferences::storeCurrentValue() @@ -2294,26 +2314,26 @@ void Preferences::updateProfileList() rprofiles->updateProfileList(); iprofiles->updateProfileList(); const ProfileStoreEntry* dynpse = ProfileStore::getInstance()->getInternalDynamicPSE(); - rprofiles->addRow (dynpse); - iprofiles->addRow (dynpse); + rprofiles->addRow(dynpse); + iprofiles->addRow(dynpse); } void Preferences::restoreValue() { - if (!rprofiles->setActiveRowFromFullPath (storedValueRaw)) { + if (!rprofiles->setActiveRowFromFullPath(storedValueRaw)) { moptions.defProfRaw = DEFPROFILE_INTERNAL; - rpconn.block (true); + rpconn.block(true); rprofiles->setInternalEntry(); - rpconn.block (false); + rpconn.block(false); } currRawRow = rprofiles->get_active(); - if (!iprofiles->setActiveRowFromFullPath (storedValueImg)) { + if (!iprofiles->setActiveRowFromFullPath(storedValueImg)) { moptions.defProfImg = DEFPROFILE_INTERNAL; - ipconn.block (true); + ipconn.block(true); iprofiles->setInternalEntry(); - ipconn.block (false); + ipconn.block(false); } currImgRow = iprofiles->get_active(); @@ -2322,48 +2342,47 @@ void Preferences::restoreValue() storedValueImg = ""; } -void Preferences::switchThemeTo (Glib::ustring newTheme) +void Preferences::switchThemeTo(Glib::ustring newTheme) { - Glib::ustring filename (Glib::build_filename (argv0, "themes", newTheme + ".css")); + Glib::ustring filename(Glib::build_filename(argv0, "themes", newTheme + ".css")); if (!themecss) { themecss = Gtk::CssProvider::create(); Glib::RefPtr screen = Gdk::Screen::get_default(); - Gtk::StyleContext::add_provider_for_screen (screen, themecss, GTK_STYLE_PROVIDER_PRIORITY_USER); + Gtk::StyleContext::add_provider_for_screen(screen, themecss, GTK_STYLE_PROVIDER_PRIORITY_USER); } try { - themecss->load_from_path (filename); + themecss->load_from_path(filename); } catch (Glib::Error &err) { - printf ("Error: Can't load css file \"%s\"\nMessage: %s\n", filename.c_str(), err.what().c_str()); + printf("Error: Can't load css file \"%s\"\nMessage: %s\n", filename.c_str(), err.what().c_str()); } catch (...) { - printf ("Error: Can't load css file \"%s\"\n", filename.c_str()); + printf("Error: Can't load css file \"%s\"\n", filename.c_str()); } } -void Preferences::fontChanged () +void Preferences::fontChanged() { - newFont = true; Pango::FontDescription fd (mainFontFB->get_font_name()); - switchFontTo (fd.get_family(), fd.get_size() / Pango::SCALE); + switchFontTo(fd.get_family(), fd.get_size() / Pango::SCALE); } -void Preferences::cpFontChanged () +void Preferences::cpFontChanged() { newCPFont = true; } -void Preferences::switchFontTo (const Glib::ustring &newFontFamily, const int newFontSize) +void Preferences::switchFontTo(const Glib::ustring &newFontFamily, const int newFontSize) { if (newFontFamily != "default") { if (!fontcss) { fontcss = Gtk::CssProvider::create(); Glib::RefPtr screen = Gdk::Screen::get_default(); - Gtk::StyleContext::add_provider_for_screen (screen, fontcss, GTK_STYLE_PROVIDER_PRIORITY_USER); + Gtk::StyleContext::add_provider_for_screen(screen, fontcss, GTK_STYLE_PROVIDER_PRIORITY_USER); } try { @@ -2375,47 +2394,52 @@ void Preferences::switchFontTo (const Glib::ustring &newFontFamily, const int ne //#endif //GTK318 } catch (Glib::Error &err) { - printf ("Error: \"%s\"\n", err.what().c_str()); + printf("Error: \"%s\"\n", err.what().c_str()); } catch (...) { - printf ("Error: Can't find the font named \"%s\"\n", newFontFamily.c_str()); + printf("Error: Can't find the font named \"%s\"\n", newFontFamily.c_str()); } } else { if (fontcss) { fontcss = Gtk::CssProvider::create(); Glib::RefPtr screen = Gdk::Screen::get_default(); - Gtk::StyleContext::remove_provider_for_screen (screen, fontcss); + Gtk::StyleContext::remove_provider_for_screen(screen, fontcss); } } } -void Preferences::workflowUpdate () +void Preferences::workflowUpdate() { if (moptions.tabbedUI != options.tabbedUI) { - parent->setEditorMode (moptions.tabbedUI); + parent->setEditorMode(moptions.tabbedUI); } if (moptions.hideTPVScrollbar != options.hideTPVScrollbar) { // Update the tool panels - parent->updateTPVScrollbar (moptions.hideTPVScrollbar); + parent->updateTPVScrollbar(moptions.hideTPVScrollbar); } if (moptions.FileBrowserToolbarSingleRow != options.FileBrowserToolbarSingleRow) { // Update the position of the Query toolbar - parent->updateFBQueryTB (moptions.FileBrowserToolbarSingleRow); + parent->updateFBQueryTB(moptions.FileBrowserToolbarSingleRow); } if (moptions.showFilmStripToolBar != options.showFilmStripToolBar) { // Update the visibility of FB toolbar - parent->updateFBToolBarVisibility (moptions.showFilmStripToolBar); + parent->updateFBToolBarVisibility(moptions.showFilmStripToolBar); + } + + if (moptions.showtooltip != options.showtooltip) { + // Update the visibility of tooltip + parent->updateShowtooltipVisibility(moptions.showtooltip); } if (moptions.histogramPosition != options.histogramPosition) { // Update the position of the Histogram - parent->updateHistogramPosition (options.histogramPosition, moptions.histogramPosition); + parent->updateHistogramPosition(options.histogramPosition, moptions.histogramPosition); } - if ( moptions.rtSettings.printerProfile != options.rtSettings.printerProfile + if (moptions.rtSettings.printerProfile != options.rtSettings.printerProfile || moptions.rtSettings.printerBPC != options.rtSettings.printerBPC || moptions.rtSettings.printerIntent != options.rtSettings.printerIntent) { // Update the position of the Histogram @@ -2424,56 +2448,56 @@ void Preferences::workflowUpdate () } -void Preferences::addExtPressed () +void Preferences::addExtPressed() { - Gtk::TreeNodeChildren c = extensionModel->children (); + Gtk::TreeNodeChildren c = extensionModel->children(); for (size_t i = 0; i < c.size(); i++) - if (c[i][extensionColumns.ext] == extension->get_text ()) { + if (c[i][extensionColumns.ext] == extension->get_text()) { return; } Gtk::TreeRow row = * (extensionModel->append()); row[extensionColumns.enabled] = true; - row[extensionColumns.ext] = extension->get_text (); + row[extensionColumns.ext] = extension->get_text(); } -void Preferences::delExtPressed () +void Preferences::delExtPressed() { - extensionModel->erase (extensions->get_selection()->get_selected ()); + extensionModel->erase(extensions->get_selection()->get_selected()); } -void Preferences::moveExtUpPressed () +void Preferences::moveExtUpPressed() { - const Glib::RefPtr selection = extensions->get_selection (); + const Glib::RefPtr selection = extensions->get_selection(); if (!selection) { return; } - const Gtk::TreeModel::iterator selected = selection->get_selected (); + const Gtk::TreeModel::iterator selected = selection->get_selected(); - if (!selected || selected == extensionModel->children ().begin ()) { + if (!selected || selected == extensionModel->children().begin()) { return; } Gtk::TreeModel::iterator previous = selected; --previous; - extensionModel->iter_swap (selected, previous); + extensionModel->iter_swap(selected, previous); } -void Preferences::moveExtDownPressed () +void Preferences::moveExtDownPressed() { - const Glib::RefPtr selection = extensions->get_selection (); + const Glib::RefPtr selection = extensions->get_selection(); if (!selection) { return; } - const Gtk::TreeModel::iterator selected = selection->get_selected (); + const Gtk::TreeModel::iterator selected = selection->get_selected(); if (!selected) { return; @@ -2482,44 +2506,45 @@ void Preferences::moveExtDownPressed () Gtk::TreeModel::iterator next = selected; if (++next) { - extensionModel->iter_swap (selected, next); + extensionModel->iter_swap(selected, next); } } -void Preferences::clearProfilesPressed () +void Preferences::clearProfilesPressed() { - cacheMgr->clearProfiles (); + cacheMgr->clearProfiles(); } -void Preferences::clearThumbImagesPressed () + +void Preferences::clearThumbImagesPressed() { - cacheMgr->clearImages (); + cacheMgr->clearImages(); } -void Preferences::clearAllPressed () +void Preferences::clearAllPressed() { - cacheMgr->clearAll (); + cacheMgr->clearAll(); } -void Preferences::darkFrameChanged () +void Preferences::darkFrameChanged() { //Glib::ustring s(darkFrameDir->get_filename()); - Glib::ustring s (darkFrameDir->get_current_folder()); + Glib::ustring s(darkFrameDir->get_current_folder()); //if( s.compare( rtengine::dfm.getPathname()) !=0 ){ - rtengine::dfm.init ( s ); + rtengine::dfm.init(s); updateDFinfos(); //} } -void Preferences::flatFieldChanged () +void Preferences::flatFieldChanged() { //Glib::ustring s(flatFieldDir->get_filename()); - Glib::ustring s (flatFieldDir->get_current_folder()); + Glib::ustring s(flatFieldDir->get_current_folder()); //if( s.compare( rtengine::ffm.getPathname()) !=0 ){ - rtengine::ffm.init ( s ); + rtengine::ffm.init(s); updateFFinfos(); //} } @@ -2527,29 +2552,30 @@ void Preferences::flatFieldChanged () void Preferences::updateDFinfos() { int t1, t2; - rtengine::dfm.getStat (t1, t2); - Glib::ustring s = Glib::ustring::compose ("%1: %2 %3, %4 %5", M ("PREFERENCES_DARKFRAMEFOUND"), t1, M ("PREFERENCES_DARKFRAMESHOTS"), t2, M ("PREFERENCES_DARKFRAMETEMPLATES")); - dfLabel->set_text (s); + rtengine::dfm.getStat(t1, t2); + Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_DARKFRAMEFOUND"), t1, M("PREFERENCES_DARKFRAMESHOTS"), t2, M("PREFERENCES_DARKFRAMETEMPLATES")); + dfLabel->set_text(s); } void Preferences::updateFFinfos() { int t1, t2; - rtengine::ffm.getStat (t1, t2); - Glib::ustring s = Glib::ustring::compose ("%1: %2 %3, %4 %5", M ("PREFERENCES_FLATFIELDFOUND"), t1, M ("PREFERENCES_FLATFIELDSHOTS"), t2, M ("PREFERENCES_FLATFIELDTEMPLATES")); - ffLabel->set_text (s); + rtengine::ffm.getStat(t1, t2); + Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_FLATFIELDFOUND"), t1, M("PREFERENCES_FLATFIELDSHOTS"), t2, M("PREFERENCES_FLATFIELDTEMPLATES")); + ffLabel->set_text(s); } -bool Preferences::splashClosed (GdkEventAny* event) +bool Preferences::splashClosed(GdkEventAny* event) { delete splash; splash = nullptr; return true; } -void Preferences::behAddSetAllPressed (bool add) +void Preferences::behAddSetAllPressed(bool add) { moptions.baBehav.assign(ADDSET_PARAM_NUM, add); + for (Gtk::TreeIter sections = behModel->children().begin(); sections != behModel->children().end(); ++sections) { for (Gtk::TreeIter adjs = sections->children().begin(); adjs != sections->children().end(); ++adjs) { adjs->set_value(behavColumns.badd, add); @@ -2558,12 +2584,12 @@ void Preferences::behAddSetAllPressed (bool add) } } -void Preferences::behAddAllPressed () +void Preferences::behAddAllPressed() { behAddSetAllPressed(true); } -void Preferences::behSetAllPressed () +void Preferences::behSetAllPressed() { behAddSetAllPressed(false); } diff --git a/rtgui/preferences.h b/rtgui/preferences.h index a6cbe7939..3cf6b2043 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -146,6 +146,8 @@ class Preferences final : Gtk::CheckButton* ctiffserialize; Gtk::ComboBoxText* curveBBoxPosC; + Gtk::ComboBoxText* complexitylocal; + Gtk::ComboBoxText* themeCBT; Gtk::FontButton* mainFontFB; Gtk::FontButton* colorPickerFontFB; @@ -208,6 +210,7 @@ class Preferences final : Gtk::CheckButton* ckbFileBrowserToolbarSingleRow; Gtk::CheckButton* ckbShowFilmStripToolBar; Gtk::CheckButton* ckbHideTPVScrollbar; + Gtk::CheckButton* ckbshowtooltiplocallab; Gtk::CheckButton* ckbAutoSaveTpOpen; Gtk::Button* btnSaveTpOpenNow; diff --git a/rtgui/preprocesswb.cc b/rtgui/preprocesswb.cc new file mode 100644 index 000000000..170371318 --- /dev/null +++ b/rtgui/preprocesswb.cc @@ -0,0 +1,97 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2020 Alberto Romei + * + * 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 + +#include "preprocesswb.h" +#include "eventmapper.h" + +#include "guiutils.h" +#include "options.h" + +#include "../rtengine/procparams.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +PreprocessWB::PreprocessWB() : + FoldableToolPanel(this, "preprocesswb", M("TP_PREPROCWB_LABEL")), + evPreprocessWBMode(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_PREPROCWB_MODE")), + mode(Gtk::manage(new MyComboBoxText())) +{ + Gtk::HBox *hb = Gtk::manage(new Gtk::HBox()); + hb->pack_start(*Gtk::manage(new Gtk::Label(M("TP_PREPROCWB_MODE") + ": ")), Gtk::PACK_SHRINK, 0); + + mode->append(M("TP_PREPROCWB_MODE_CAMERA")); + mode->append(M("TP_PREPROCWB_MODE_AUTO")); + + hb->pack_start(*mode); + + mode->set_active(0); + mode->signal_changed().connect(sigc::mem_fun(*this, &PreprocessWB::modeChanged)); + + mode->show(); + + pack_start(*hb, Gtk::PACK_SHRINK, 4); +} + +void PreprocessWB::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener(); + + mode->set_active(int(pp->raw.preprocessWB.mode)); + + enableListener(); +} + +void PreprocessWB::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + if (mode->get_active_row_number() != 2) { + pp->raw.preprocessWB.mode = RAWParams::PreprocessWB::Mode(mode->get_active_row_number()); + } + + if (pedited) { + pedited->raw.preprocessWB.mode = mode->get_active_row_number() != 2; // UNCHANGED entry, see setBatchMode + } + +} + +void PreprocessWB::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode(batchMode); + + if (batchMode) { + mode->append(M("GENERAL_UNCHANGED")); + mode->set_active_text(M("GENERAL_UNCHANGED")); + } +} + +void PreprocessWB::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ +} + +void PreprocessWB::trimValues(rtengine::procparams::ProcParams* pp) +{ +} + +void PreprocessWB::modeChanged() +{ + if (listener) { + listener->panelChanged(evPreprocessWBMode, mode->get_active_text()); + } +} diff --git a/rtgui/preprocesswb.h b/rtgui/preprocesswb.h new file mode 100644 index 000000000..343d2e9e9 --- /dev/null +++ b/rtgui/preprocesswb.h @@ -0,0 +1,47 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2020 Alberto Romei + * + * 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 . + */ +#pragma once + +#include + +#include "adjuster.h" +#include "toolpanel.h" + +class PreprocessWB final: + public ToolParamBlock, + public FoldableToolPanel +{ + +private: + const rtengine::ProcEvent evPreprocessWBMode; + + MyComboBoxText* mode; + +public: + + PreprocessWB(); + + void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; + void setBatchMode(bool batchMode) override; + void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; + void setAdjusterBehavior(bool add); + void trimValues(rtengine::procparams::ProcParams* pp) override; + void modeChanged(); +}; diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index 4c8e30e44..c7e889b3f 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -273,11 +273,21 @@ void ProfilePanel::restoreValue () void ProfilePanel::save_clicked (GdkEventButton* event) { - if (event->button != 1) { return; } + const PartialProfile* toSave; + + if (isCustomSelected()) { + toSave = custom; + } else if (isLastSavedSelected()) { + toSave = lastsaved; + } else { + const auto entry = profiles->getSelectedEntry(); + toSave = entry ? ProfileStore::getInstance()->getProfile(entry) : nullptr; + } + // If it's a partial profile, it's more intuitive to first allow the user // to choose which parameters to save before showing the Save As dialog // #5491 @@ -288,6 +298,7 @@ void ProfilePanel::save_clicked (GdkEventButton* event) } partialProfileDlg->set_title(M("PROFILEPANEL_SAVEPPASTE")); + partialProfileDlg->updateSpotWidget(toSave->pparams); const auto response = partialProfileDlg->run(); partialProfileDlg->hide(); @@ -342,19 +353,9 @@ void ProfilePanel::save_clicked (GdkEventButton* event) lastFilename = Glib::path_get_basename(fname); - const PartialProfile* toSave; - - if (isCustomSelected()) { - toSave = custom; - } else if (isLastSavedSelected()) { - toSave = lastsaved; - } else { - const auto entry = profiles->getSelectedEntry(); - toSave = entry ? ProfileStore::getInstance()->getProfile(entry) : nullptr; - } - if (toSave) { int retCode; + if (isPartial) { // Build partial profile PartialProfile ppTemp(true); @@ -410,6 +411,7 @@ void ProfilePanel::copy_clicked (GdkEventButton* event) partialProfileDlg = new PartialPasteDlg (Glib::ustring (), parent); } partialProfileDlg->set_title(M("PROFILEPANEL_COPYPPASTE")); + partialProfileDlg->updateSpotWidget(toSave->pparams); int i = partialProfileDlg->run(); partialProfileDlg->hide(); @@ -473,20 +475,7 @@ void ProfilePanel::load_clicked (GdkEventButton* event) if (result == Gtk::RESPONSE_OK) { Glib::ustring fname = dialog.get_filename(); - - if (event->state & Gdk::CONTROL_MASK) { - // opening the partial paste dialog window - if(!partialProfileDlg) { - partialProfileDlg = new PartialPasteDlg (Glib::ustring (), parent); - } - partialProfileDlg->set_title(M("PROFILEPANEL_LOADPPASTE")); - int i = partialProfileDlg->run(); - partialProfileDlg->hide(); - - if (i != Gtk::RESPONSE_OK) { - return; - } - } + printf("fname=%s\n", fname.c_str()); bool customCreated = false; @@ -502,6 +491,9 @@ void ProfilePanel::load_clicked (GdkEventButton* event) if (!err) { if (!customCreated && fillMode->get_active()) { custom->pparams->setDefaults(); + + // Clearing all LocallabSpotEdited to be compliant with default pparams + custom->pedited->locallab.spots.clear(); } custom->set(true); @@ -521,6 +513,17 @@ void ProfilePanel::load_clicked (GdkEventButton* event) if(!partialProfileDlg) { partialProfileDlg = new PartialPasteDlg (Glib::ustring (), parent); } + + // opening the partial paste dialog window + partialProfileDlg->set_title(M("PROFILEPANEL_LOADPPASTE")); + partialProfileDlg->updateSpotWidget(&pp); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + + if (i != Gtk::RESPONSE_OK) { + return; + } + partialProfileDlg->applyPaste (custom->pparams, !fillMode->get_active() ? custom->pedited : nullptr, &pp, &pe); } else { // custom.pparams = loadedFile.pparams filtered by ( loadedFile.pedited ) @@ -557,32 +560,27 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) return; } - if (event->state & Gdk::CONTROL_MASK) { - if(!partialProfileDlg) { - partialProfileDlg = new PartialPasteDlg (Glib::ustring (), parent); - } - partialProfileDlg->set_title(M("PROFILEPANEL_PASTEPPASTE")); - int i = partialProfileDlg->run(); - partialProfileDlg->hide(); - - if (i != Gtk::RESPONSE_OK) { - return; - } - } - bool prevState = changeconn.block(true); if (!custom) { - custom = new PartialProfile (true); + custom = new PartialProfile (true); // custom pedited is initialized to false if (isLastSavedSelected()) { *custom->pparams = *lastsaved->pparams; + + // Setting LocallabSpotEdited number coherent with spots number in lastsaved->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(false)); } else { const ProfileStoreEntry* entry = profiles->getSelectedEntry(); if (entry) { const PartialProfile* partProfile = ProfileStore::getInstance()->getProfile (entry); *custom->pparams = *partProfile->pparams; + + // Setting LocallabSpotEdited number coherent with spots number in partProfile->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(false)); } } @@ -591,15 +589,26 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) } else { if (fillMode->get_active()) { custom->pparams->setDefaults(); + + // Clear all LocallabSpotEdited to be compliant with default pparams + custom->pedited->locallab.spots.clear(); } else if (!isCustomSelected ()) { if (isLastSavedSelected()) { *custom->pparams = *lastsaved->pparams; + + // Setting LocallabSpotEdited number coherent with spots number in lastsaved->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); } else { const ProfileStoreEntry* entry = profiles->getSelectedEntry(); if (entry) { const PartialProfile* partProfile = ProfileStore::getInstance()->getProfile (entry); *custom->pparams = *partProfile->pparams; + + // Setting LocallabSpotEdited number coherent with spots number in partProfile->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); } } } @@ -626,6 +635,16 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) if(!partialProfileDlg) { partialProfileDlg = new PartialPasteDlg (Glib::ustring (), parent); } + + partialProfileDlg->set_title(M("PROFILEPANEL_PASTEPPASTE")); + partialProfileDlg->updateSpotWidget(&pp); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + + if (i != Gtk::RESPONSE_OK) { + return; + } + partialProfileDlg->applyPaste (custom->pparams, !fillMode->get_active() ? custom->pedited : nullptr, &pp, &pe); } else { // custom.pparams = clipboard.pparams filtered by ( clipboard.pedited ) @@ -633,6 +652,10 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) if (!fillMode->get_active()) { *custom->pedited = pe; + } else { + // Setting LocallabSpotEdited number coherent with spots number in custom->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); } } } else { @@ -642,10 +665,28 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) if(!partialProfileDlg) { partialProfileDlg = new PartialPasteDlg (Glib::ustring (), parent); } + + partialProfileDlg->set_title(M("PROFILEPANEL_PASTEPPASTE")); + partialProfileDlg->updateSpotWidget(&pp); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + + if (i != Gtk::RESPONSE_OK) { + return; + } + partialProfileDlg->applyPaste (custom->pparams, nullptr, &pp, nullptr); + + // Setting LocallabSpotEdited number coherent with spots number in custom->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); } else { // custom.pparams = clipboard.pparams non filtered *custom->pparams = pp; + + // Setting LocallabSpotEdited number coherent with spots number in custom->pparams + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); } } @@ -693,6 +734,10 @@ void ProfilePanel::selection_changed () if (s) { if (fillMode->get_active() && s->pedited) { ParamsEdited pe(true); + + // Setting LocallabSpotEdited number coherent with spots number in s->pparams + pe.locallab.spots.resize(s->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + PartialProfile s2(s->pparams, &pe, false); changeTo (&s2, pse->label + "+"); } else { @@ -731,6 +776,10 @@ void ProfilePanel::procParamsChanged( } *custom->pparams = *p; + + // Setting LocallabSpotEdited number coherent with spots number in p + custom->pedited->locallab.spots.clear(); + custom->pedited->locallab.spots.resize(p->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); } void ProfilePanel::clearParamChanges() @@ -766,6 +815,8 @@ void ProfilePanel::initProfile (const Glib::ustring& profileFullPath, ProcParams if (lastSaved) { ParamsEdited* pe = new ParamsEdited(true); + // Setting LocallabSpotEdited number coherent with lastSaved->locallab spots number (initialized at true such as pe) + pe->locallab.spots.resize(lastSaved->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); // copying the provided last saved profile to ProfilePanel::lastsaved lastsaved = new PartialProfile(lastSaved, pe); } diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index fc315e1b7..e1d8c1f84 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -280,23 +280,6 @@ RTWindow::RTWindow () set_default_size (options.windowWidth, options.windowHeight); set_modal (false); - Gdk::Rectangle lMonitorRect; - get_screen()->get_monitor_geometry (std::min (options.windowMonitor, Gdk::Screen::get_default()->get_n_monitors() - 1), lMonitorRect); - - if (options.windowMaximized) { - move (lMonitorRect.get_x(), lMonitorRect.get_y()); - maximize(); - } else { - unmaximize(); - resize (options.windowWidth, options.windowHeight); - - if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height()) { - move (options.windowX, options.windowY); - } else { - move (lMonitorRect.get_x(), lMonitorRect.get_y()); - } - } - on_delete_has_run = false; is_fullscreen = false; property_destroy_with_parent().set_value (false); @@ -1081,6 +1064,17 @@ void RTWindow::updateFBToolBarVisibility (bool showFilmStripToolBar) fpanel->fileCatalog->updateFBToolBarVisibility (showFilmStripToolBar); } +void RTWindow::updateShowtooltipVisibility (bool showtooltip) +{ + if (epanel) { + epanel->updateShowtooltipVisibility (showtooltip); + } + + for (auto panel : epanels) { + panel.second->updateShowtooltipVisibility (showtooltip); + } +} + void RTWindow::updateHistogramPosition (int oldPosition, int newPosition) { if (epanel) { @@ -1100,6 +1094,44 @@ bool RTWindow::splashClosed (GdkEventAny* event) return true; } +void RTWindow::setWindowSize () +{ + Gdk::Rectangle lMonitorRect; + get_screen()->get_monitor_geometry (std::min (options.windowMonitor, Gdk::Screen::get_default()->get_n_monitors() - 1), lMonitorRect); + +#ifdef __APPLE__ + // Get macOS menu bar height + const Gdk::Rectangle lWorkAreaRect = get_screen()->get_monitor_workarea (std::min (options.windowMonitor, Gdk::Screen::get_default()->get_n_monitors() - 1)); + const int macMenuBarHeight = lWorkAreaRect.get_y(); +#endif + + if (options.windowMaximized) { +#ifdef __APPLE__ + move (lMonitorRect.get_x(), lMonitorRect.get_y() + macMenuBarHeight); +#else + move (lMonitorRect.get_x(), lMonitorRect.get_y()); +#endif + maximize(); + } else { + unmaximize(); + resize (options.windowWidth, options.windowHeight); + +#ifdef __APPLE__ + if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height() - macMenuBarHeight) { + move (options.windowX, options.windowY + macMenuBarHeight); + } else { + move (lMonitorRect.get_x(), lMonitorRect.get_y() + macMenuBarHeight); + } +#else + if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height()) { + move (options.windowX, options.windowY); + } else { + move (lMonitorRect.get_x(), lMonitorRect.get_y()); + } +#endif + } +} + void RTWindow::set_title_decorated (Glib::ustring fname) { Glib::ustring subtitle; diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index c493c2db4..e5e180747 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -119,10 +119,12 @@ public: void updateHistogramPosition (int oldPosition, int newPosition); void updateFBQueryTB (bool singleRow); void updateFBToolBarVisibility (bool showFilmStripToolBar); + void updateShowtooltipVisibility (bool showtooltip); bool getIsFullscreen() { return is_fullscreen; } + void setWindowSize (); void set_title_decorated (Glib::ustring fname); void closeOpenEditors(); void setEditorMode (bool tabbedUI); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 7452c9d72..c1884edeb 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -39,6 +39,7 @@ #include "guiutils.h" #include "batchqueue.h" #include "extprog.h" +#include "md5helper.h" #include "pathutils.h" #include "paramsedited.h" #include "procparamchangers.h" @@ -450,6 +451,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh const bool needsReprocessing = resetToDefault || pparams->toneCurve != pp.toneCurve + || pparams->locallab != pp.locallab || pparams->labCurve != pp.labCurve || pparams->localContrast != pp.localContrast || pparams->rgbCurves != pp.rgbCurves @@ -873,7 +875,7 @@ void Thumbnail::_loadThumbnail(bool firstTrial) if (!succ && firstTrial) { _generateThumbnailImage (); - if (cfs.supported && firstTrial) { + if (cfs.supported) { _loadThumbnail (false); } @@ -993,7 +995,7 @@ void Thumbnail::setFileName (const Glib::ustring &fn) { fname = fn; - cfs.md5 = cachemgr->getMD5 (fname); + cfs.md5 = ::getMD5 (fname); } int Thumbnail::getRank () const diff --git a/rtgui/toolbar.cc b/rtgui/toolbar.cc index 99c4196c6..e642ae51b 100644 --- a/rtgui/toolbar.cc +++ b/rtgui/toolbar.cc @@ -109,7 +109,7 @@ void ToolBar::setTool (ToolMode tool) ConnectionBlocker cropBlocker(cropConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); - stopEdit = tool == TMHand && handTool->get_active() && editingMode; + stopEdit = tool == TMHand && handTool->get_active() && editingMode && !blockEdit; handTool->set_active (false); @@ -206,7 +206,7 @@ void ToolBar::hand_pressed () ConnectionBlocker cropBlocker(cropConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); - if (editingMode) { + if (editingMode && !blockEdit) { stopEditMode(); if (listener) { listener->editModeSwitchedOff (); @@ -291,7 +291,7 @@ void ToolBar::colPicker_pressed (GdkEventButton* event) if (current != TMColorPicker) { // Disabling all other tools, enabling the Picker tool and entering the "visible pickers" mode - if (editingMode) { + if (editingMode && !blockEdit) { stopEditMode(); if (listener) { listener->editModeSwitchedOff (); diff --git a/rtgui/toolbar.h b/rtgui/toolbar.h index 8ec6bb615..a4525019f 100644 --- a/rtgui/toolbar.h +++ b/rtgui/toolbar.h @@ -65,6 +65,7 @@ protected: ToolMode current; bool allowNoTool; bool editingMode; // true if the cursor is being used to remotely edit tool's values + bool blockEdit; // true if edit tool shouldn't be disabled when pressing hand button or h/H key sigc::connection handConn; sigc::connection wbConn; sigc::connection cpConn; @@ -99,4 +100,9 @@ public: bool handleShortcutKey (GdkEventKey* event); void setBatchMode(); + + void blockEditDeactivation(bool cond = true) + { + blockEdit = cond; + } }; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index d02dd0237..857a4c57b 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -32,7 +32,7 @@ using namespace rtengine::procparams; -ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), editDataProvider (nullptr) +ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), editDataProvider (nullptr), photoLoadedOnce(false) { favoritePanel = Gtk::manage (new ToolVBox ()); @@ -42,6 +42,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit transformPanel = Gtk::manage (new ToolVBox ()); rawPanel = Gtk::manage (new ToolVBox ()); advancedPanel = Gtk::manage (new ToolVBox ()); + locallabPanel = Gtk::manage(new ToolVBox()); coarse = Gtk::manage (new CoarsePanel ()); toneCurve = Gtk::manage (new ToneCurve ()); @@ -52,50 +53,52 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit epd = Gtk::manage (new EdgePreservingDecompositionUI ()); sharpening = Gtk::manage (new Sharpening ()); localContrast = Gtk::manage(new LocalContrast()); - sharpenEdge = Gtk::manage (new SharpenEdge ()); - sharpenMicro = Gtk::manage (new SharpenMicro ()); - lcurve = Gtk::manage (new LCurve ()); - rgbcurves = Gtk::manage (new RGBCurves ()); - colortoning = Gtk::manage (new ColorToning ()); - lensgeom = Gtk::manage (new LensGeometry ()); - lensProf = Gtk::manage (new LensProfilePanel ()); - distortion = Gtk::manage (new Distortion ()); - rotate = Gtk::manage (new Rotate ()); - vibrance = Gtk::manage (new Vibrance ()); - colorappearance = Gtk::manage (new ColorAppearance ()); - whitebalance = Gtk::manage (new WhiteBalance ()); - vignetting = Gtk::manage (new Vignetting ()); - retinex = Gtk::manage (new Retinex ()); - gradient = Gtk::manage (new Gradient ()); - pcvignette = Gtk::manage (new PCVignette ()); - perspective = Gtk::manage (new PerspCorrection ()); - cacorrection = Gtk::manage (new CACorrection ()); - chmixer = Gtk::manage (new ChMixer ()); - blackwhite = Gtk::manage (new BlackWhite ()); - resize = Gtk::manage (new Resize ()); - prsharpening = Gtk::manage (new PrSharpening()); - crop = Gtk::manage (new Crop ()); - icm = Gtk::manage (new ICMPanel ()); + sharpenEdge = Gtk::manage(new SharpenEdge()); + sharpenMicro = Gtk::manage(new SharpenMicro()); + lcurve = Gtk::manage(new LCurve()); + rgbcurves = Gtk::manage(new RGBCurves()); + colortoning = Gtk::manage(new ColorToning()); + lensgeom = Gtk::manage(new LensGeometry()); + lensProf = Gtk::manage(new LensProfilePanel()); + distortion = Gtk::manage(new Distortion()); + rotate = Gtk::manage(new Rotate()); + vibrance = Gtk::manage(new Vibrance()); + colorappearance = Gtk::manage(new ColorAppearance()); + whitebalance = Gtk::manage(new WhiteBalance()); + vignetting = Gtk::manage(new Vignetting()); + retinex = Gtk::manage(new Retinex()); + gradient = Gtk::manage(new Gradient()); + locallab = Gtk::manage(new Locallab()); + pcvignette = Gtk::manage(new PCVignette()); + perspective = Gtk::manage(new PerspCorrection()); + cacorrection = Gtk::manage(new CACorrection()); + chmixer = Gtk::manage(new ChMixer()); + blackwhite = Gtk::manage(new BlackWhite()); + resize = Gtk::manage(new Resize()); + prsharpening = Gtk::manage(new PrSharpening()); + crop = Gtk::manage(new Crop()); + icm = Gtk::manage(new ICMPanel()); metadata = Gtk::manage(new MetaDataPanel()); - wavelet = Gtk::manage (new Wavelet ()); - dirpyrequalizer = Gtk::manage (new DirPyrEqualizer ()); - hsvequalizer = Gtk::manage (new HSVEqualizer ()); - filmSimulation = Gtk::manage (new FilmSimulation ()); + wavelet = Gtk::manage(new Wavelet()); + dirpyrequalizer = Gtk::manage(new DirPyrEqualizer()); + hsvequalizer = Gtk::manage(new HSVEqualizer()); + filmSimulation = Gtk::manage(new FilmSimulation()); softlight = Gtk::manage(new SoftLight()); dehaze = Gtk::manage(new Dehaze()); - sensorbayer = Gtk::manage (new SensorBayer ()); - sensorxtrans = Gtk::manage (new SensorXTrans ()); - bayerprocess = Gtk::manage (new BayerProcess ()); - xtransprocess = Gtk::manage (new XTransProcess ()); - bayerpreprocess = Gtk::manage (new BayerPreProcess ()); - preprocess = Gtk::manage (new PreProcess ()); - darkframe = Gtk::manage (new DarkFrame ()); - flatfield = Gtk::manage (new FlatField ()); - rawcacorrection = Gtk::manage (new RAWCACorr ()); - rawexposure = Gtk::manage (new RAWExposure ()); - bayerrawexposure = Gtk::manage (new BayerRAWExposure ()); - xtransrawexposure = Gtk::manage (new XTransRAWExposure ()); - fattal = Gtk::manage (new FattalToneMapping ()); + sensorbayer = Gtk::manage(new SensorBayer()); + sensorxtrans = Gtk::manage(new SensorXTrans()); + bayerprocess = Gtk::manage(new BayerProcess()); + xtransprocess = Gtk::manage(new XTransProcess()); + bayerpreprocess = Gtk::manage(new BayerPreProcess()); + preprocess = Gtk::manage(new PreProcess()); + darkframe = Gtk::manage(new DarkFrame()); + flatfield = Gtk::manage(new FlatField()); + rawcacorrection = Gtk::manage(new RAWCACorr()); + rawexposure = Gtk::manage(new RAWExposure()); + preprocessWB = Gtk::manage (new PreprocessWB ()); + bayerrawexposure = Gtk::manage(new BayerRAWExposure()); + xtransrawexposure = Gtk::manage(new XTransRAWExposure()); + fattal = Gtk::manage(new FattalToneMapping()); filmNegative = Gtk::manage (new FilmNegative ()); pdSharpening = Gtk::manage (new PdSharpening()); // So Demosaic, Line noise filter, Green Equilibration, Ca-Correction (garder le nom de section identique!) and Black-Level will be moved in a "Bayer sensor" tool, @@ -136,6 +139,8 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (detailsPanel, dirpyrequalizer); addfavoritePanel (detailsPanel, dehaze); addfavoritePanel (advancedPanel, wavelet); + addfavoritePanel(locallabPanel, locallab); + addfavoritePanel (transformPanel, crop); addfavoritePanel (transformPanel, resize); addPanel (resize->getPackBox(), prsharpening, 2); @@ -156,6 +161,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (sensorxtrans->getPackBox(), xtransprocess, 2); addfavoritePanel (sensorxtrans->getPackBox(), xtransrawexposure, 2); addfavoritePanel (rawPanel, rawexposure); + addfavoritePanel (rawPanel, preprocessWB); addfavoritePanel (rawPanel, preprocess); addfavoritePanel (rawPanel, darkframe); addfavoritePanel (rawPanel, flatfield); @@ -173,25 +179,24 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanels.push_back (coarse); toolPanels.push_back(metadata); - toolPanelNotebook = new Gtk::Notebook (); - toolPanelNotebook->set_name ("ToolPanelNotebook"); - + toolPanelNotebook = new Gtk::Notebook(); + toolPanelNotebook->set_name("ToolPanelNotebook"); exposurePanelSW = Gtk::manage (new MyScrolledWindow ()); detailsPanelSW = Gtk::manage (new MyScrolledWindow ()); colorPanelSW = Gtk::manage (new MyScrolledWindow ()); transformPanelSW = Gtk::manage (new MyScrolledWindow ()); rawPanelSW = Gtk::manage (new MyScrolledWindow ()); advancedPanelSW = Gtk::manage (new MyScrolledWindow ()); + locallabPanelSW = Gtk::manage(new MyScrolledWindow()); // load panel endings - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 8; i++) { vbPanelEnd[i] = Gtk::manage (new Gtk::VBox ()); imgPanelEnd[i] = Gtk::manage (new RTImage ("ornament1.png")); - imgPanelEnd[i]->show (); - vbPanelEnd[i]->pack_start (*imgPanelEnd[i], Gtk::PACK_SHRINK); + imgPanelEnd[i]->show(); + vbPanelEnd[i]->pack_start(*imgPanelEnd[i], Gtk::PACK_SHRINK); vbPanelEnd[i]->show_all(); } - if(favoriteCount > 0) { favoritePanelSW = Gtk::manage(new MyScrolledWindow()); favoritePanelSW->add(*favoritePanel); @@ -216,6 +221,10 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit advancedPanel->pack_start (*Gtk::manage (new Gtk::HSeparator), Gtk::PACK_SHRINK, 0); advancedPanel->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK, 0); + locallabPanelSW->add(*locallabPanel); + locallabPanel->pack_start(*Gtk::manage(new Gtk::HSeparator), Gtk::PACK_SHRINK, 0); + locallabPanel->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK, 4); + transformPanelSW->add (*transformPanel); transformPanel->pack_start (*Gtk::manage (new Gtk::HSeparator), Gtk::PACK_SHRINK, 0); transformPanel->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK, 4); @@ -229,10 +238,11 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toiD = Gtk::manage (new TextOrIcon ("detail.png", M ("MAIN_TAB_DETAIL"), M ("MAIN_TAB_DETAIL_TOOLTIP"))); toiC = Gtk::manage (new TextOrIcon ("color-circles.png", M ("MAIN_TAB_COLOR"), M ("MAIN_TAB_COLOR_TOOLTIP"))); toiW = Gtk::manage (new TextOrIcon ("atom.png", M ("MAIN_TAB_ADVANCED"), M ("MAIN_TAB_ADVANCED_TOOLTIP"))); + toiL = Gtk::manage(new TextOrIcon("hand-open.png", M("MAIN_TAB_LOCALLAB"), M("MAIN_TAB_LOCALLAB_TOOLTIP"))); + toiT = Gtk::manage (new TextOrIcon ("transform.png", M ("MAIN_TAB_TRANSFORM"), M ("MAIN_TAB_TRANSFORM_TOOLTIP"))); toiR = Gtk::manage (new TextOrIcon ("bayer.png", M ("MAIN_TAB_RAW"), M ("MAIN_TAB_RAW_TOOLTIP"))); toiM = Gtk::manage (new TextOrIcon ("metadata.png", M ("MAIN_TAB_METADATA"), M ("MAIN_TAB_METADATA_TOOLTIP"))); - if (favoritePanelSW) { toolPanelNotebook->append_page (*favoritePanelSW, *toiF); } @@ -240,46 +250,78 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanelNotebook->append_page (*detailsPanelSW, *toiD); toolPanelNotebook->append_page (*colorPanelSW, *toiC); toolPanelNotebook->append_page (*advancedPanelSW, *toiW); + + // Locallab notebook is hidden in batch mode + if (!batch) { + toolPanelNotebook->append_page(*locallabPanelSW, *toiL); + } + toolPanelNotebook->append_page (*transformPanelSW, *toiT); toolPanelNotebook->append_page (*rawPanelSW, *toiR); toolPanelNotebook->append_page (*metadata, *toiM); - toolPanelNotebook->set_current_page (0); + toolPanelNotebook->set_scrollable(); + toolPanelNotebook->show_all(); - toolPanelNotebook->set_scrollable (); - toolPanelNotebook->show_all (); + notebookconn = toolPanelNotebook->signal_switch_page().connect( + sigc::mem_fun(*this, &ToolPanelCoordinator::notebookPageChanged)); - for (auto toolPanel : toolPanels) { - toolPanel->setListener (this); + // In batch mode, notebookPageChanged method is blocked because it's useless to display spots + if (batch) { + notebookconn.block(true); } - whitebalance->setWBProvider (this); - whitebalance->setSpotWBListener (this); - darkframe->setDFProvider (this); - flatfield->setFFProvider (this); - lensgeom->setLensGeomListener (this); - rotate->setLensGeomListener (this); - perspective->setLensGeomListener (this); - distortion->setLensGeomListener (this); - crop->setCropPanelListener (this); - icm->setICMPanelListener (this); + for (auto toolPanel : toolPanels) { + toolPanel->setListener(this); + } + + whitebalance->setWBProvider(this); + whitebalance->setSpotWBListener(this); + darkframe->setDFProvider(this); + flatfield->setFFProvider(this); + lensgeom->setLensGeomListener(this); + rotate->setLensGeomListener(this); + perspective->setLensGeomListener(this); + distortion->setLensGeomListener(this); + crop->setCropPanelListener(this); + icm->setICMPanelListener(this); filmNegative->setFilmNegProvider (this); - toolBar = new ToolBar (); - toolBar->setToolBarListener (this); + toolBar = new ToolBar(); + toolBar->setToolBarListener(this); + + prevPage = toolPanelNotebook->get_nth_page(0); } -void ToolPanelCoordinator::addPanel (Gtk::Box* where, FoldableToolPanel* panel, int level) +void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num) +{ + // Locallab spot curves are set visible if at least one photo has been loaded (to avoid + // segfault) and locallab panel is active + if (photoLoadedOnce) { + if (page == locallabPanelSW) { + toolBar->blockEditDeactivation(); // Avoid edit tool deactivation when Locallab page is active (except if pressing other tools button) + locallab->subscribe(); + } + + if (prevPage == locallabPanelSW) { // To deactivate Locallab only when switching from Locallab page + toolBar->blockEditDeactivation(false); + locallab->unsubscribe(); + } + + prevPage = page; + } +} + +void ToolPanelCoordinator::addPanel(Gtk::Box* where, FoldableToolPanel* panel, int level) { - panel->setParent (where); - panel->setLevel (level); + panel->setParent(where); + panel->setLevel(level); - expList.push_back (panel->getExpander()); - where->pack_start (*panel->getExpander(), false, false); - toolPanels.push_back (panel); + expList.push_back(panel->getExpander()); + where->pack_start(*panel->getExpander(), false, false); + toolPanels.push_back(panel); } - void ToolPanelCoordinator::addfavoritePanel (Gtk::Box* where, FoldableToolPanel* panel, int level) { auto name = panel->getToolName(); @@ -296,13 +338,17 @@ ToolPanelCoordinator::~ToolPanelCoordinator () { idle_register.destroy(); - closeImage (); + closeImage(); + + // When deleting toolPanelNotebook, pages removal activates notebookPageChanged function + // which is responsible of segfault if listener isn't deactivated before + notebookconn.block(true); delete toolPanelNotebook; delete toolBar; } -void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono) +void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool isMono) { if (isRaw) { if (isBayer) { @@ -325,8 +371,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt return false; } ); - } - else if (isXtrans) { + } else if (isXtrans) { idle_register.add( [this]() -> bool { @@ -346,8 +391,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt return false; } ); - } - else if (isMono) { + } else if (isMono) { idle_register.add( [this]() -> bool { @@ -359,6 +403,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt sensorxtrans->FoldableToolPanel::hide(); xtransprocess->FoldableToolPanel::hide(); xtransrawexposure->FoldableToolPanel::hide(); + preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::show(); filmNegative->FoldableToolPanel::hide(); @@ -379,6 +424,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt sensorxtrans->FoldableToolPanel::hide(); xtransprocess->FoldableToolPanel::hide(); xtransrawexposure->FoldableToolPanel::hide(); + preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::hide(); filmNegative->FoldableToolPanel::hide(); @@ -400,6 +446,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt sensorxtrans->FoldableToolPanel::hide(); xtransprocess->FoldableToolPanel::hide(); xtransrawexposure->FoldableToolPanel::hide(); + preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::hide(); filmNegative->FoldableToolPanel::hide(); @@ -421,18 +468,18 @@ void ToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, const int changeFlags = rtengine::RefreshMapper::getInstance()->getAction(event); - ProcParams* params = ipc->beginUpdateParams (); + ProcParams* params = ipc->beginUpdateParams(); for (auto toolPanel : toolPanels) { - toolPanel->write (params); + toolPanel->write(params); } // Compensate rotation on flip if (event == rtengine::EvCTHFlip || event == rtengine::EvCTVFlip) { - if (fabs (params->rotate.degree) > 0.001) { + if (fabs(params->rotate.degree) > 0.001) { params->rotate.degree *= -1; changeFlags |= rtengine::RefreshMapper::getInstance()->getAction(rtengine::EvROTDegree); - rotate->read (params); + rotate->read(params); } } @@ -450,34 +497,78 @@ void ToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, const if (event == rtengine::EvPhotoLoaded || event == rtengine::EvProfileChanged || event == rtengine::EvHistoryBrowsed || event == rtengine::EvCTRotate) { // updating the "on preview" geometry int fw, fh; - ipc->getInitialImage()->getImageSource()->getFullSize (fw, fh, tr); - gradient->updateGeometry (params->gradient.centerX, params->gradient.centerY, params->gradient.feather, params->gradient.degree, fw, fh); + ipc->getInitialImage()->getImageSource()->getFullSize(fw, fh, tr); + gradient->updateGeometry(params->gradient.centerX, params->gradient.centerY, params->gradient.feather, params->gradient.degree, fw, fh); } // some transformations make the crop change for convenience if (event == rtengine::EvCTHFlip) { - crop->hFlipCrop (); - crop->write (params); + crop->hFlipCrop(); + crop->write(params); } else if (event == rtengine::EvCTVFlip) { - crop->vFlipCrop (); - crop->write (params); + crop->vFlipCrop(); + crop->write(params); } else if (event == rtengine::EvCTRotate) { - crop->rotateCrop (params->coarse.rotate, params->coarse.hflip, params->coarse.vflip); - crop->write (params); - resize->update (params->crop.enabled, params->crop.w, params->crop.h, ipc->getFullWidth(), ipc->getFullHeight()); - resize->write (params); + crop->rotateCrop(params->coarse.rotate, params->coarse.hflip, params->coarse.vflip); + crop->write(params); + resize->update(params->crop.enabled, params->crop.w, params->crop.h, ipc->getFullWidth(), ipc->getFullHeight()); + resize->write(params); } else if (event == rtengine::EvCrop) { - resize->update (params->crop.enabled, params->crop.w, params->crop.h); - resize->write (params); + resize->update(params->crop.enabled, params->crop.w, params->crop.h); + resize->write(params); } - ipc->endUpdateParams (changeFlags); // starts the IPC processing + /* + * Manage Locallab mask visibility: + * - Mask preview is updated when choosing a mask preview method + * - Mask preview is also updated when modifying (to avoid hiding a potentially visible mask combobox): + * - Color&Light invers + * - Exposure inversex + * - Shadow Highlight inverssh + * - Soft Light softMethod + * - Mask preview is stopped when creating, deleting or selecting a spot + * - Mask preview is also stopped when removing a spot or resetting all mask visibility + */ + if (event == rtengine::EvlocallabshowmaskMethod) { + const Locallab::llMaskVisibility maskStruc = locallab->getMaskVisibility(); + ipc->setLocallabMaskVisibility(maskStruc.previewDeltaE, maskStruc.colorMask, maskStruc.colorMaskinv, maskStruc.expMask, maskStruc.expMaskinv, + maskStruc.SHMask, maskStruc.SHMaskinv, maskStruc.vibMask, maskStruc.softMask, + maskStruc.blMask, maskStruc.tmMask, maskStruc.retiMask, maskStruc.sharMask, + maskStruc.lcMask, maskStruc.cbMask); + } else if (event == rtengine::EvLocallabSpotCreated || event == rtengine::EvLocallabSpotSelectedWithMask || + event == rtengine::EvLocallabSpotDeleted || event == rtengine::Evlocallabshowreset || + event == rtengine::EvlocallabToolRemovedWithRefresh) { + locallab->resetMaskVisibility(); + ipc->setLocallabMaskVisibility(false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + ipc->endUpdateParams(changeFlags); // starts the IPC processing hasChanged = true; for (auto paramcListener : paramcListeners) { - paramcListener->procParamsChanged (params, event, descr); + paramcListener->procParamsChanged(params, event, descr); } + + // Locallab spot curves are set visible if at least one photo has been loaded (to avoid + // segfault) and locallab panel is active + // When a new photo is loaded, Locallab spot curves need to be set visible again +const auto func = + [this]() -> bool + { + if (photoLoadedOnce && (toolPanelNotebook->get_nth_page(toolPanelNotebook->get_current_page()) == locallabPanelSW)) { + locallab->subscribe(); + } + + return false; + }; + +if (event == rtengine::EvPhotoLoaded) { + idle_register.add(func); +} + + photoLoadedOnce = true; + } void ToolPanelCoordinator::profileChange( @@ -494,7 +585,7 @@ void ToolPanelCoordinator::profileChange( return; } - ProcParams *params = ipc->beginUpdateParams (); + ProcParams *params = ipc->beginUpdateParams(); ProcParams *mergedParams = new ProcParams(); // Copy the current params as default values for the fusion @@ -507,17 +598,17 @@ void ToolPanelCoordinator::profileChange( } // And apply the partial profile nparams to mergedParams - nparams->applyTo (mergedParams, fromLastSave); + nparams->applyTo(mergedParams, fromLastSave); // Derive the effective changes, if it's a profile change, to prevent slow RAW rerendering if not necessary bool filterRawRefresh = false; if (event != rtengine::EvPhotoLoaded) { - ParamsEdited pe (true); - std::vector lParams (2); + ParamsEdited pe(true); + std::vector lParams(2); lParams[0] = *params; lParams[1] = *mergedParams; - pe.initFrom (lParams); + pe.initFrom(lParams); filterRawRefresh = pe.raw.isUnchanged() && pe.lensProf.isUnchanged() && pe.retinex.isUnchanged() && pe.filmNegative.isUnchanged() && pe.pdsharpening.isUnchanged(); } @@ -536,35 +627,61 @@ void ToolPanelCoordinator::profileChange( } // trimming overflowing cropped area - ipc->getInitialImage()->getImageSource()->getFullSize (fw, fh, tr); - crop->trim (params, fw, fh); + ipc->getInitialImage()->getImageSource()->getFullSize(fw, fh, tr); + crop->trim(params, fw, fh); // updating the GUI with updated values for (auto toolPanel : toolPanels) { - toolPanel->read (params); + toolPanel->read(params); if (event == rtengine::EvPhotoLoaded || event == rtengine::EvProfileChanged) { toolPanel->autoOpenCurve(); + + // For Locallab, reset tool expanders visibility only when a photo or profile is loaded + locallab->openAllTools(); } } if (event == rtengine::EvPhotoLoaded || event == rtengine::EvProfileChanged || event == rtengine::EvHistoryBrowsed || event == rtengine::EvCTRotate) { // updating the "on preview" geometry - gradient->updateGeometry (params->gradient.centerX, params->gradient.centerY, params->gradient.feather, params->gradient.degree, fw, fh); + gradient->updateGeometry(params->gradient.centerX, params->gradient.centerY, params->gradient.feather, params->gradient.degree, fw, fh); } + // Reset Locallab mask visibility + locallab->resetMaskVisibility(); + ipc->setLocallabMaskVisibility(false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + // start the IPC processing if (filterRawRefresh) { - ipc->endUpdateParams ( rtengine::RefreshMapper::getInstance()->getAction(event) & ALLNORAW ); + ipc->endUpdateParams(rtengine::RefreshMapper::getInstance()->getAction(event) & ALLNORAW); } else { - ipc->endUpdateParams (event); + ipc->endUpdateParams(event); } hasChanged = event != rtengine::EvProfileChangeNotification; for (auto paramcListener : paramcListeners) { - paramcListener->procParamsChanged (params, event, descr); + paramcListener->procParamsChanged(params, event, descr); } + + // Locallab spot curves are set visible if at least one photo has been loaded (to avoid + // segfault) and locallab panel is active + // When a new photo is loaded, Locallab spot curves need to be set visible again +const auto func = + [this]() -> bool + { + if (photoLoadedOnce && (toolPanelNotebook->get_nth_page(toolPanelNotebook->get_current_page()) == locallabPanelSW)) { + locallab->subscribe(); + } + + return false; + }; + +if (event == rtengine::EvPhotoLoaded) { + idle_register.add(func); +} + + photoLoadedOnce = true; } void ToolPanelCoordinator::setDefaults(const ProcParams* defparams) @@ -576,60 +693,61 @@ void ToolPanelCoordinator::setDefaults(const ProcParams* defparams) } } -CropGUIListener* ToolPanelCoordinator::getCropGUIListener () +CropGUIListener* ToolPanelCoordinator::getCropGUIListener() { return crop; } -void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool raw) +void ToolPanelCoordinator::initImage(rtengine::StagedImageProcessor* ipc_, bool raw) { ipc = ipc_; - toneCurve->disableListener (); - toneCurve->enableAll (); - toneCurve->enableListener (); + toneCurve->disableListener(); + toneCurve->enableAll(); + toneCurve->enableListener(); if (ipc) { const rtengine::FramesMetaData* pMetaData = ipc->getInitialImage()->getMetaData(); metadata->setImageData(pMetaData); - ipc->setAutoExpListener (toneCurve); - ipc->setAutoCamListener (colorappearance); - ipc->setAutoBWListener (blackwhite); - ipc->setFrameCountListener (bayerprocess); + ipc->setAutoExpListener(toneCurve); + ipc->setAutoCamListener(colorappearance); + ipc->setAutoBWListener(blackwhite); + ipc->setFrameCountListener(bayerprocess); ipc->setFlatFieldAutoClipListener (flatfield); ipc->setBayerAutoContrastListener (bayerprocess); ipc->setXtransAutoContrastListener (xtransprocess); ipc->setpdSharpenAutoContrastListener (pdSharpening); ipc->setpdSharpenAutoRadiusListener (pdSharpening); - ipc->setAutoWBListener (whitebalance); - ipc->setAutoColorTonListener (colortoning); - ipc->setAutoChromaListener (dirpyrdenoise); - ipc->setWaveletListener (wavelet); - ipc->setRetinexListener (retinex); - ipc->setSizeListener (crop); - ipc->setSizeListener (resize); - ipc->setImageTypeListener (this); + ipc->setAutoWBListener(whitebalance); + ipc->setAutoColorTonListener(colortoning); + ipc->setAutoChromaListener(dirpyrdenoise); + ipc->setWaveletListener(wavelet); + ipc->setRetinexListener(retinex); + ipc->setSizeListener(crop); + ipc->setSizeListener(resize); + ipc->setLocallabListener(locallab); + ipc->setImageTypeListener(this); ipc->setFilmNegListener (filmNegative); - flatfield->setShortcutPath (Glib::path_get_dirname (ipc->getInitialImage()->getFileName())); + flatfield->setShortcutPath(Glib::path_get_dirname(ipc->getInitialImage()->getFileName())); - icm->setRawMeta (raw, (const rtengine::FramesData*)pMetaData); - lensProf->setRawMeta (raw, pMetaData); - perspective->setMetadata (pMetaData); + icm->setRawMeta(raw, (const rtengine::FramesData*)pMetaData); + lensProf->setRawMeta(raw, pMetaData); + perspective->setMetadata(pMetaData); } - toneCurve->setRaw (raw); + toneCurve->setRaw(raw); hasChanged = true; } -void ToolPanelCoordinator::closeImage () +void ToolPanelCoordinator::closeImage() { if (ipc) { - ipc->stopProcessing (); + ipc->stopProcessing(); ipc = nullptr; } } @@ -685,33 +803,40 @@ void ToolPanelCoordinator::updateToolState() } } -void ToolPanelCoordinator::readOptions () +void ToolPanelCoordinator::readOptions() { - crop->readOptions (); + crop->readOptions(); } -void ToolPanelCoordinator::writeOptions () +void ToolPanelCoordinator::writeOptions() { - crop->writeOptions (); + crop->writeOptions(); if (options.autoSaveTpOpen) { - writeToolExpandedStatus (options.tpOpen); + writeToolExpandedStatus(options.tpOpen); } } -void ToolPanelCoordinator::writeToolExpandedStatus (std::vector &tpOpen) +void ToolPanelCoordinator::writeToolExpandedStatus(std::vector &tpOpen) { - tpOpen.clear (); + tpOpen.clear(); for (size_t i = 0; i < expList.size(); i++) { - tpOpen.push_back (expList.at (i)->get_expanded ()); + tpOpen.push_back(expList.at(i)->get_expanded()); } - wavelet->writeOptions (tpOpen); - retinex->writeOptions (tpOpen); + wavelet->writeOptions(tpOpen); + retinex->writeOptions(tpOpen); + +} + + +void ToolPanelCoordinator::updateShowtooltipVisibility (bool showtooltip) +{ + locallab->updateShowtooltipVisibility(showtooltip); } @@ -722,15 +847,15 @@ void ToolPanelCoordinator::spotWBselected(int x, int y, Thumbnail* thm) } // toolBar->setTool (TOOL_HAND); - int rect = whitebalance->getSize (); + int rect = whitebalance->getSize(); int ww = ipc->getFullWidth(); int hh = ipc->getFullHeight(); if (x - rect > 0 && y - rect > 0 && x + rect < ww && y + rect < hh) { double temp; double green; - ipc->getSpotWB (x, y, rect, temp, green); - whitebalance->setWB (temp, green); + ipc->getSpotWB(x, y, rect, temp, green); + whitebalance->setWB(temp, green); } } @@ -739,7 +864,8 @@ void ToolPanelCoordinator::sharpMaskSelected(bool sharpMask) if (!ipc) { return; } - ipc->beginUpdateParams (); + + ipc->beginUpdateParams(); ipc->endUpdateParams (ipc->setSharpMask(sharpMask)); } @@ -780,7 +906,7 @@ CropGUIListener* ToolPanelCoordinator::startCropEditing(Thumbnail* thm) return crop; } -void ToolPanelCoordinator::autoCropRequested () +void ToolPanelCoordinator::autoCropRequested() { if (!ipc) { @@ -788,12 +914,12 @@ void ToolPanelCoordinator::autoCropRequested () } int x1, y1, x2, y2, w, h; - ipc->getAutoCrop (crop->getRatio(), x1, y1, w, h); + ipc->getAutoCrop(crop->getRatio(), x1, y1, w, h); x2 = x1 + w - 1; y2 = y1 + h - 1; - crop->cropInit (x1, y1, w, h); - crop->cropResized (x1, y1, x2, y2); - crop->cropManipReady (); + crop->cropInit(x1, y1, w, h); + crop->cropResized(x1, y1, x2, y2); + crop->cropManipReady(); } rtengine::RawImage* ToolPanelCoordinator::getDF() @@ -807,11 +933,11 @@ rtengine::RawImage* ToolPanelCoordinator::getDF() if (imd) { int iso = imd->getISOSpeed(); double shutter = imd->getShutterSpeed(); - std::string maker ( imd->getMake() ); - std::string model ( imd->getModel() ); + std::string maker(imd->getMake()); + std::string model(imd->getModel()); time_t timestamp = imd->getDateTimeAsTS(); - return rtengine::dfm.searchDarkFrame ( maker, model, iso, shutter, timestamp); + return rtengine::dfm.searchDarkFrame(maker, model, iso, shutter, timestamp); } return nullptr; @@ -830,12 +956,12 @@ rtengine::RawImage* ToolPanelCoordinator::getFF() // double shutter = imd->getShutterSpeed(); temporarily removed because unused double aperture = imd->getFNumber(); double focallength = imd->getFocalLen(); - std::string maker ( imd->getMake() ); - std::string model ( imd->getModel() ); - std::string lens ( imd->getLens() ); + std::string maker(imd->getMake()); + std::string model(imd->getModel()); + std::string lens(imd->getLens()); time_t timestamp = imd->getDateTimeAsTS(); - return rtengine::ffm.searchFlatField ( maker, model, lens, focallength, aperture, timestamp); + return rtengine::ffm.searchFlatField(maker, model, lens, focallength, aperture, timestamp); } return nullptr; @@ -850,14 +976,14 @@ Glib::ustring ToolPanelCoordinator::GetCurrentImageFilePath() return ipc->getInitialImage()->getFileName(); } -void ToolPanelCoordinator::straightenRequested () +void ToolPanelCoordinator::straightenRequested() { if (!ipc) { return; } - toolBar->setTool (TMStraighten); + toolBar->setTool(TMStraighten); } void ToolPanelCoordinator::autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const rtengine::ControlLine *lines, size_t line_count) @@ -880,13 +1006,13 @@ void ToolPanelCoordinator::autoPerspRequested (bool corr_pitch, bool corr_yaw, d yaw = res.yaw; } -double ToolPanelCoordinator::autoDistorRequested () +double ToolPanelCoordinator::autoDistorRequested() { if (!ipc) { return 0.0; } - return rtengine::ImProcFunctions::getAutoDistor (ipc->getInitialImage()->getFileName(), 400); + return rtengine::ImProcFunctions::getAutoDistor(ipc->getInitialImage()->getFileName(), 400); } void ToolPanelCoordinator::updateTransformPreviewRequested(rtengine::ProcEvent event, bool render_perspective) @@ -899,30 +1025,30 @@ void ToolPanelCoordinator::updateTransformPreviewRequested(rtengine::ProcEvent e ipc->endUpdateParams(event); } -void ToolPanelCoordinator::spotWBRequested (int size) +void ToolPanelCoordinator::spotWBRequested(int size) { if (!ipc) { return; } - toolBar->setTool (TMSpotWB); + toolBar->setTool(TMSpotWB); } -void ToolPanelCoordinator::cropSelectRequested () +void ToolPanelCoordinator::cropSelectRequested() { if (!ipc) { return; } - toolBar->setTool (TMCropSelect); + toolBar->setTool(TMCropSelect); } void ToolPanelCoordinator::saveInputICCReference(const Glib::ustring& fname, bool apply_wb) { if (ipc) { - ipc->saveInputICCReference (fname, apply_wb); + ipc->saveInputICCReference(fname, apply_wb); } } @@ -946,7 +1072,7 @@ void ToolPanelCoordinator::updateCurveBackgroundHistogram( retinex->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); } -void ToolPanelCoordinator::foldAllButOne (Gtk::Box* parent, FoldableToolPanel* openedSection) +void ToolPanelCoordinator::foldAllButOne(Gtk::Box* parent, FoldableToolPanel* openedSection) { for (auto toolPanel : toolPanels) { @@ -956,10 +1082,10 @@ void ToolPanelCoordinator::foldAllButOne (Gtk::Box* parent, FoldableToolPanel* o if (currentTP->getParent() == parent) { // Section in the same tab, we unfold it if it's not the one that has been clicked if (currentTP != openedSection) { - currentTP->setExpanded (false); + currentTP->setExpanded(false); } else { if (!currentTP->getExpanded()) { - currentTP->setExpanded (true); + currentTP->setExpanded(true); } } } @@ -967,7 +1093,7 @@ void ToolPanelCoordinator::foldAllButOne (Gtk::Box* parent, FoldableToolPanel* o } } -bool ToolPanelCoordinator::handleShortcutKey (GdkEventKey* event) +bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event) { //bool ctrl = event->state & GDK_CONTROL_MASK; temporarily removed because unused @@ -983,31 +1109,35 @@ bool ToolPanelCoordinator::handleShortcutKey (GdkEventKey* event) return true; case GDK_KEY_e: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*exposurePanelSW)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*exposurePanelSW)); return true; case GDK_KEY_d: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*detailsPanelSW)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*detailsPanelSW)); return true; case GDK_KEY_c: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*colorPanelSW)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*colorPanelSW)); return true; case GDK_KEY_t: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*transformPanelSW)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*transformPanelSW)); return true; case GDK_KEY_r: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*rawPanelSW)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*rawPanelSW)); return true; case GDK_KEY_a: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*advancedPanelSW)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*advancedPanelSW)); + return true; + + case GDK_KEY_o: + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*locallabPanelSW)); return true; case GDK_KEY_m: - toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*metadata)); + toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*metadata)); return true; } } @@ -1015,7 +1145,7 @@ bool ToolPanelCoordinator::handleShortcutKey (GdkEventKey* event) return false; } -void ToolPanelCoordinator::updateVScrollbars (bool hide) +void ToolPanelCoordinator::updateVScrollbars(bool hide) { GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected Gtk::PolicyType policy = hide ? Gtk::POLICY_NEVER : Gtk::POLICY_AUTOMATIC; @@ -1028,20 +1158,24 @@ void ToolPanelCoordinator::updateVScrollbars (bool hide) transformPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); rawPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); advancedPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); + locallabPanelSW->set_policy(Gtk::POLICY_AUTOMATIC, policy); + for (auto currExp : expList) { - currExp->updateVScrollbars (hide); + currExp->updateVScrollbars(hide); } } -void ToolPanelCoordinator::updateTPVScrollbar (bool hide) + +void ToolPanelCoordinator::updateTPVScrollbar(bool hide) { - updateVScrollbars (hide); + updateVScrollbars(hide); } -void ToolPanelCoordinator::toolSelected (ToolMode tool) +void ToolPanelCoordinator::toolSelected(ToolMode tool) { GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + notebookconn.block(true); // "signal_switch_page" event is blocked to avoid unsubscribing Locallab (allows a correct behavior when switching to another tool using toolbar) auto checkFavorite = [this](FoldableToolPanel* tool) { for (auto fav : favorites) { @@ -1054,18 +1188,23 @@ void ToolPanelCoordinator::toolSelected (ToolMode tool) switch (tool) { case TMCropSelect: { + toolBar->blockEditDeactivation(false); // To allow deactivating Locallab when switching to another tool using toolbar crop->setExpanded(true); toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(checkFavorite(crop) ? *favoritePanelSW : *transformPanelSW)); + prevPage = toolPanelNotebook->get_nth_page(toolPanelNotebook->get_current_page()); // Updating prevPage as "signal_switch_page" event break; } case TMSpotWB: { + toolBar->blockEditDeactivation(false); // To allow deactivating Locallab when switching to another tool using toolbar whitebalance->setExpanded(true); toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(checkFavorite(whitebalance) ? *favoritePanelSW : *colorPanelSW)); + prevPage = toolPanelNotebook->get_nth_page(toolPanelNotebook->get_current_page()); // Updating prevPage as "signal_switch_page" event break; } case TMStraighten: { + toolBar->blockEditDeactivation(false); // To allow deactivating Locallab when switching to another tool using toolbar rotate->setExpanded(true); bool isFavorite = checkFavorite(rotate); if (!isFavorite) { @@ -1073,33 +1212,36 @@ void ToolPanelCoordinator::toolSelected (ToolMode tool) lensgeom->setExpanded(true); } toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(isFavorite ? *favoritePanelSW : *transformPanelSW)); + prevPage = toolPanelNotebook->get_nth_page(toolPanelNotebook->get_current_page()); // Updating prevPage as "signal_switch_page" event break; } default: break; } + + notebookconn.block(false); } -void ToolPanelCoordinator::editModeSwitchedOff () +void ToolPanelCoordinator::editModeSwitchedOff() { if (editDataProvider) { editDataProvider->switchOffEditMode(); } } -void ToolPanelCoordinator::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) +void ToolPanelCoordinator::dirSelected(const Glib::ustring& dirname, const Glib::ustring& openfile) { - flatfield->setShortcutPath (dirname); + flatfield->setShortcutPath(dirname); } -void ToolPanelCoordinator::setEditProvider (EditDataProvider *provider) +void ToolPanelCoordinator::setEditProvider(EditDataProvider *provider) { editDataProvider = provider; for (size_t i = 0; i < toolPanels.size(); i++) { - toolPanels.at (i)->setEditProvider (provider); + toolPanels.at(i)->setEditProvider(provider); } } diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index fe65a0745..7ab17018b 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -54,11 +54,13 @@ #include "lensgeomlistener.h" #include "lensprofile.h" #include "localcontrast.h" +#include "locallab.h" #include "pcvignette.h" #include "pdsharpening.h" #include "perspective.h" #include "pparamschangelistener.h" #include "preprocess.h" +#include "preprocesswb.h" #include "profilechangelistener.h" #include "prsharpening.h" #include "rawcacorrection.h" @@ -110,6 +112,7 @@ protected: WhiteBalance* whitebalance; Vignetting* vignetting; Gradient* gradient; + Locallab* locallab; Retinex* retinex; PCVignette* pcvignette; LensGeometry* lensgeom; @@ -155,6 +158,7 @@ protected: FlatField* flatfield; RAWCACorr* rawcacorrection; RAWExposure* rawexposure; + PreprocessWB* preprocessWB; BayerRAWExposure* bayerrawexposure; XTransRAWExposure* xtransrawexposure; FattalToneMapping *fattal; @@ -174,6 +178,7 @@ protected: ToolVBox* transformPanel; ToolVBox* rawPanel; ToolVBox* advancedPanel; + ToolVBox* locallabPanel; ToolBar* toolBar; TextOrIcon* toiF; @@ -184,9 +189,10 @@ protected: TextOrIcon* toiR; TextOrIcon* toiM; TextOrIcon* toiW; + TextOrIcon* toiL; - Gtk::Image* imgPanelEnd[7]; - Gtk::VBox* vbPanelEnd[7]; + Gtk::Image* imgPanelEnd[8]; + Gtk::VBox* vbPanelEnd[8]; Gtk::ScrolledWindow* favoritePanelSW; Gtk::ScrolledWindow* exposurePanelSW; @@ -195,27 +201,32 @@ protected: Gtk::ScrolledWindow* transformPanelSW; Gtk::ScrolledWindow* rawPanelSW; Gtk::ScrolledWindow* advancedPanelSW; + Gtk::ScrolledWindow* locallabPanelSW; std::vector expList; bool hasChanged; - void addPanel (Gtk::Box* where, FoldableToolPanel* panel, int level = 1); - void foldThemAll (GdkEventButton* event); - void updateVScrollbars (bool hide); + void addPanel(Gtk::Box* where, FoldableToolPanel* panel, int level = 1); + void foldThemAll(GdkEventButton* event); + void updateVScrollbars(bool hide); void addfavoritePanel (Gtk::Box* where, FoldableToolPanel* panel, int level = 1); + void notebookPageChanged(Gtk::Widget* page, guint page_num); private: EditDataProvider *editDataProvider; + sigc::connection notebookconn; + bool photoLoadedOnce; // Used to indicated that a photo has been loaded yet + Gtk::Widget* prevPage; public: CoarsePanel* coarse; Gtk::Notebook* toolPanelNotebook; - ToolPanelCoordinator (bool batch = false); + ToolPanelCoordinator(bool batch = false); ~ToolPanelCoordinator () override; - bool getChangedState () + bool getChangedState() { return hasChanged; } @@ -231,12 +242,12 @@ public: const LUTu& histLuma, const LUTu& histLRETI ); - void foldAllButOne (Gtk::Box* parent, FoldableToolPanel* openedSection); + void foldAllButOne(Gtk::Box* parent, FoldableToolPanel* openedSection); // multiple listeners can be added that are notified on changes (typical: profile panel and the history) - void addPParamsChangeListener (PParamsChangeListener* pp) + void addPParamsChangeListener(PParamsChangeListener* pp) { - paramcListeners.push_back (pp); + paramcListeners.push_back(pp); } // toolpanellistener interface @@ -255,36 +266,36 @@ public: void setDefaults(const rtengine::procparams::ProcParams* defparams) override; // DirSelectionListener interface - void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile); + void dirSelected(const Glib::ustring& dirname, const Glib::ustring& openfile); // to support the GUI: - CropGUIListener* getCropGUIListener (); // through the CropGUIListener the editor area can notify the "crop" ToolPanel when the crop selection changes + CropGUIListener* getCropGUIListener(); // through the CropGUIListener the editor area can notify the "crop" ToolPanel when the crop selection changes // init the toolpanelcoordinator with an image & close it - void initImage (rtengine::StagedImageProcessor* ipc_, bool israw); - void closeImage (); + void initImage(rtengine::StagedImageProcessor* ipc_, bool israw); + void closeImage(); // update the "expanded" state of the Tools - void updateToolState (); - void openAllTools (); - void closeAllTools (); + void updateToolState(); + void openAllTools(); + void closeAllTools(); // read/write the "expanded" state of the expanders & read/write the crop panel settings (ratio, guide type, etc.) - void readOptions (); - void writeOptions (); - void writeToolExpandedStatus (std::vector &tpOpen); - + void readOptions(); + void writeOptions(); + void writeToolExpandedStatus(std::vector &tpOpen); + void updateShowtooltipVisibility (bool showtooltip); // wbprovider interface void getAutoWB (double& temp, double& green, double equal, double tempBias) override { if (ipc) { - ipc->getAutoWB (temp, green, equal, tempBias); + ipc->getAutoWB(temp, green, equal, tempBias); } } void getCamWB (double& temp, double& green) override { if (ipc) { - ipc->getCamWB (temp, green); + ipc->getCamWB(temp, green); } } @@ -324,14 +335,14 @@ public: ToolBar* getToolBar() const final; CropGUIListener* startCropEditing(Thumbnail* thm = nullptr) override; - void updateTPVScrollbar (bool hide); - bool handleShortcutKey (GdkEventKey* event); + void updateTPVScrollbar(bool hide); + bool handleShortcutKey(GdkEventKey* event); // ToolBarListener interface void toolSelected (ToolMode tool) override; void editModeSwitchedOff () final; - void setEditProvider (EditDataProvider *provider); + void setEditProvider(EditDataProvider *provider); private: IdleRegister idle_register; diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index af159d480..ac8c6100b 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -27,6 +27,7 @@ #include "rtimage.h" #include "options.h" #include "eventmapper.h" +#include "labgrid.h" #include "../rtengine/color.h" using namespace rtengine; @@ -62,6 +63,7 @@ std::vector makeWholeHueRange() Wavelet::Wavelet() : FoldableToolPanel(this, "wavelet", M("TP_WAVELET_LABEL"), true, true), curveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CONTEDIT"))), + curveEditorC(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CONTRASTEDIT"))), CCWcurveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CCURVE"))), curveEditorbl(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_BLCURVE"))), curveEditorRES(new CurveEditorGroup(options.lastWaveletCurvesDir)), @@ -112,6 +114,12 @@ Wavelet::Wavelet() : strength(Gtk::manage(new Adjuster(M("TP_WAVELET_STRENGTH"), 0, 100, 1, 100))), balance(Gtk::manage(new Adjuster(M("TP_WAVELET_BALANCE"), -30, 100, 1, 0))), iter(Gtk::manage(new Adjuster(M("TP_WAVELET_ITER"), -3, 3, 1, 0))), + sigmafin(Gtk::manage(new Adjuster(M("TP_WAVELET_SIGMAFIN"), 0.025, 2.5, 0.01, 1.))), + sigmaton(Gtk::manage(new Adjuster(M("TP_WAVELET_SIGMAFIN"), 0.025, 2.5, 0.01, 1.))), + sigmacol(Gtk::manage(new Adjuster(M("TP_WAVELET_SIGMAFIN"), 0.025, 2.5, 0.01, 1.))), + sigmadir(Gtk::manage(new Adjuster(M("TP_WAVELET_SIGMAFIN"), 0.025, 2.5, 0.01, 1.))), + rangeab(Gtk::manage(new Adjuster(M("TP_WAVELET_RANGEAB"), 0., 100., 0.1, 20.))), + protab(Gtk::manage(new Adjuster(M("TP_WAVELET_PROTAB"), 0., 100., 0.5, 0.))), hueskin(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_HUESKIN"), -314., 314., -5., 25., 170., 120., 0, false))), hueskin2(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_HUESKY"), -314., 314., -260., -250, -130., -140., 0, false))), hllev(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_HIGHLIGHT"), 0., 100., 50., 75., 100., 98., 0, false))), @@ -123,18 +131,19 @@ Wavelet::Wavelet() : level1noise(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_LEVONE"), -30., 100., 0., M("TP_WAVELET_STREN"), 1., 0., 100., 0., M("TP_WAVELET_NOIS"), 1., nullptr, false))), level2noise(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_LEVTWO"), -30., 100., 0., M("TP_WAVELET_STREN"), 1., 0., 100., 0., M("TP_WAVELET_NOIS"), 1., nullptr, false))), level3noise(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_LEVTHRE"), -30., 100., 0., M("TP_WAVELET_STREN"), 1., 0., 100., 0., M("TP_WAVELET_NOIS"), 1., nullptr, false))), - threshold(Gtk::manage(new Adjuster(M("TP_WAVELET_THRESHOLD"), 1, 9, 1, 5))), - threshold2(Gtk::manage(new Adjuster(M("TP_WAVELET_THRESHOLD2"), 1, 9, 1, 4))), + threshold(Gtk::manage(new Adjuster(M("TP_WAVELET_THRESHOLD"), 1, 9, 1, 4))), + // threshold2(Gtk::manage(new Adjuster(M("TP_WAVELET_THRESHOLD2"), 1, 9, 1, 4))), + threshold2(Gtk::manage(new Adjuster(M("TP_WAVELET_THRESHOLD2"), 3, 9, 1, 5))), edgedetect(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEDETECT"), 0, 100, 1, 90))), edgedetectthr(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEDETECTTHR"), 0, 100, 1, 20))), edgedetectthr2(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEDETECTTHR2"), -10, 100, 1, 0))), edgesensi(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGESENSI"), 0, 100, 1, 60))), edgeampli(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGEAMPLI"), 0, 100, 1, 10))), ballum(Gtk::manage(new Adjuster(M("TP_WAVELET_BALLUM"), -2., 10., 0.5, 7., Gtk::manage(new RTImage("circle-white-small.png")), Gtk::manage(new RTImage("circle-black-small.png"))))), - balchrom(Gtk::manage(new Adjuster(M("TP_WAVELET_BALCHROM"), -100., 100., 1., 0., Gtk::manage(new RTImage("circle-blue-small.png")), Gtk::manage(new RTImage("circle-red-small.png"))))), + balchrom(Gtk::manage(new Adjuster(M("TP_WAVELET_BALCHROM"), -100., 100., 1., 0., Gtk::manage(new RTImage("circle-blue-yellow-small.png")), Gtk::manage(new RTImage("circle-red-green-small.png"))))), chromfi(Gtk::manage(new Adjuster(M("TP_WAVELET_CHROMFI"), 0.0, 150., 0.01, 0.))), chromco(Gtk::manage(new Adjuster(M("TP_WAVELET_CHROMCO"), 0, 100., 0.01, 0.))), - mergeL(Gtk::manage(new Adjuster(M("TP_WAVELET_MERGEL"), -50, 100, 1, 40))), + mergeL(Gtk::manage(new Adjuster(M("TP_WAVELET_MERGEL"), -50, 100, 1, 20))), mergeC(Gtk::manage(new Adjuster(M("TP_WAVELET_MERGEC"), -50, 100, 1, 20))), softrad(Gtk::manage(new Adjuster(M("TP_WAVELET_SOFTRAD"), 0.0, 100., 0.5, 0.))), softradend(Gtk::manage(new Adjuster(M("TP_WAVELET_SOFTRAD"), 0.0, 100., 0.5, 0.))), @@ -162,6 +171,9 @@ Wavelet::Wavelet() : blurFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_BLURFRAME")))), chromaFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_CHROMAFRAME")))), chroFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_CHROFRAME")))), + fincFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_FINCFRAME")))), + dirFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_DIRFRAME")))), + tonFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_TONFRAME")))), wavLabels(Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER))), labmC(Gtk::manage(new Gtk::Label(M("TP_WAVELET_CTYPE") + ":"))), labmNP(Gtk::manage(new Gtk::Label(M("TP_WAVELET_NPTYPE") + ":"))), @@ -207,6 +219,17 @@ Wavelet::Wavelet() : EvWavresblur = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_BLURWAV"); EvWavresblurc = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_BLURCWAV"); EvWavedgeffect = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_EDGEFFECT"); + EvWavsigmafin = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_SIGMAFIN"); + EvWavsigmaton = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_SIGMATON"); + EvWavsigmacol = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_SIGMACOL"); + EvWavsigmadir = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_SIGMADIR"); + EvWavLabGridValue = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVLABGRID_VALUE"); + EvWavrangeab = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_RANGEAB"); + EvWavprotab = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_PROTAB"); + EvWavlevelshc = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_LEVELSHC"); + + labgrid = Gtk::manage(new LabGrid(EvWavLabGridValue, M("TP_WAVELET_LABGRID_VALUES"))); + expsettings->signal_button_release_event().connect_notify(sigc::bind(sigc::mem_fun(this, &Wavelet::foldAllButMe), expsettings)); expcontrast->signal_button_release_event().connect_notify(sigc::bind(sigc::mem_fun(this, &Wavelet::foldAllButMe), expcontrast)); @@ -402,11 +425,25 @@ Wavelet::Wavelet() : threshold2->setAdjusterListener(this); threshold2->set_tooltip_text(M("TP_WAVELET_THRESHOLD2_TOOLTIP")); + const WaveletParams default_params; + + curveEditorC->setCurveListener(this); + curveEditorC->set_tooltip_text(M("TP_WAVELET_FINCOAR_TOOLTIP")); + + + opacityShapeSH = static_cast(curveEditorC->addCurve(CT_Flat, "", nullptr, false, false)); + opacityShapeSH->setIdentityValue(0.); + opacityShapeSH->setResetCurve(FlatCurveType(default_params.opacityCurveSH.at(0)), default_params.opacityCurveSH); + + curveEditorC->curveListComplete(); + curveEditorC->show(); + contrastSHVBox->pack_start(*HSmethod); contrastSHVBox->pack_start(*hllev); contrastSHVBox->pack_start(*threshold); contrastSHVBox->pack_start(*bllev); contrastSHVBox->pack_start(*threshold2); + // contrastSHVBox->pack_start(*curveEditorC); Gtk::Frame* const contrastSHFrame = Gtk::manage(new Gtk::Frame(M("TP_WAVELET_APPLYTO"))); contrastSHFrame->add(*contrastSHVBox); levBox->pack_start(*contrastSHFrame); @@ -450,8 +487,10 @@ Wavelet::Wavelet() : chBox->pack_start(*satlev); chro->set_tooltip_text(M("TP_WAVELET_CHR_TOOLTIP")); - chBox->pack_start(*chro); chro->setAdjusterListener(this); + sigmacol->setAdjusterListener(this); + chBox->pack_start(*chro); + chBox->pack_start(*sigmacol); Gtk::HBox* const buttonchBox = Gtk::manage(new Gtk::HBox(true, 10)); neutralchPressedConn = neutralchButton->signal_pressed().connect(sigc::mem_fun(*this, &Wavelet::neutralchPressed)); @@ -483,17 +522,35 @@ Wavelet::Wavelet() : // Toning ToolParamBlock* const tonBox = Gtk::manage(new ToolParamBlock()); + sigmaton->setAdjusterListener(this); + rangeab->setAdjusterListener(this); + protab->setAdjusterListener(this); opaCurveEditorG->setCurveListener(this); - const WaveletParams default_params; +// const WaveletParams default_params; opacityShapeRG = static_cast(opaCurveEditorG->addCurve(CT_Flat, "", nullptr, false, false)); opacityShapeRG->setIdentityValue(0.); opacityShapeRG->setResetCurve(FlatCurveType(default_params.opacityCurveRG.at(0)), default_params.opacityCurveRG); + //from green to magenta + std::vector mileston = { + GradientMilestone(0., 0., 1., 0.), + GradientMilestone(1., 1., 0., 1.) + }; + opacityShapeRG->setLeftBarBgGradient(mileston); opaCurveEditorG->curveListComplete(); opaCurveEditorG->show(); + tonBox->pack_start(*sigmaton); + + tonFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const ton2Box = Gtk::manage(new ToolParamBlock()); + ton2Box->pack_start(*labgrid, Gtk::PACK_EXPAND_WIDGET, 2); + ton2Box->pack_start(*rangeab); + ton2Box->pack_start(*protab); + tonFrame->add(*ton2Box); + tonBox->pack_start(*tonFrame); tonBox->pack_start(*opaCurveEditorG, Gtk::PACK_SHRINK, 2); @@ -502,6 +559,12 @@ Wavelet::Wavelet() : opacityShapeBY = static_cast(opacityCurveEditorG->addCurve(CT_Flat, "", nullptr, false, false)); opacityShapeBY->setIdentityValue(0.); opacityShapeBY->setResetCurve(FlatCurveType(default_params.opacityCurveBY.at(0)), default_params.opacityCurveBY); + //from blue to yellow + mileston = { + GradientMilestone(0., 0., 0., 1.), + GradientMilestone(1., 1., 1., 0.) + }; + opacityShapeBY->setLeftBarBgGradient(mileston); opacityCurveEditorG->curveListComplete(); opacityCurveEditorG->show(); @@ -511,7 +574,7 @@ Wavelet::Wavelet() : // Denoise and Refine ToolParamBlock* const noiseBox = Gtk::manage(new ToolParamBlock()); - linkedg->set_active(true); + linkedg->set_active(false); linkedgConn = linkedg->signal_toggled().connect(sigc::mem_fun(*this, &Wavelet::linkedgToggled)); noiseBox->pack_start(*linkedg); @@ -545,6 +608,7 @@ Wavelet::Wavelet() : chroBox->pack_start(*chromco); chroFrame->add(*chroBox); noiseBox->pack_start(*chroFrame); + noiseBox->set_tooltip_text(M("TP_WAVELET_NOISE_TOOLTIP")); //Clarity @@ -571,13 +635,13 @@ Wavelet::Wavelet() : // Edge Sharpness ToolParamBlock* const edgBox = Gtk::manage(new ToolParamBlock()); - edgeffect->setAdjusterListener(this); - edgBox->pack_start(*edgeffect); - edgeffect->set_tooltip_markup(M("TP_WAVELET_EDEFFECT_TOOLTIP")); edgval->setAdjusterListener(this); edgBox->pack_start(*edgval); + edgeffect->setAdjusterListener(this); + edgBox->pack_start(*edgeffect); + edgeffect->set_tooltip_markup(M("TP_WAVELET_EDEFFECT_TOOLTIP")); edgrad->setAdjusterListener(this); edgBox->pack_start(*edgrad); @@ -694,7 +758,7 @@ Wavelet::Wavelet() : blshape->setIdentityValue(0.); blshape->setResetCurve(FlatCurveType(default_params.blcurve.at(0)), default_params.blcurve); - blshape->setTooltip(M("TP_WAVELET_CURVEEDITOR_CC_TOOLTIP")); + blshape->setTooltip(M("TP_WAVELET_CURVEEDITOR_BL_TOOLTIP")); curveEditorbl->curveListComplete(); curveEditorbl->show(); @@ -800,6 +864,8 @@ Wavelet::Wavelet() : blurBox->pack_start(*resblur); blurBox->pack_start(*resblurc); blurFrame->add(*blurBox); + resblur->set_tooltip_text(M("TP_WAVELET_RESBLUR_TOOLTIP")); + resblurc->set_tooltip_text(M("TP_WAVELET_RESBLUR_TOOLTIP")); chromaFrame->set_label_align(0.025, 0.5); ToolParamBlock* const chromaBox = Gtk::manage(new ToolParamBlock()); @@ -975,8 +1041,9 @@ Wavelet::Wavelet() : iter->setAdjusterListener(this); iter->set_tooltip_text(M("TP_WAVELET_ITER_TOOLTIP")); + sigmadir->setAdjusterListener(this); - Gtk::HSeparator* const separatorbalend = Gtk::manage(new Gtk::HSeparator()); +// Gtk::HSeparator* const separatorbalend = Gtk::manage(new Gtk::HSeparator()); opacityCurveEditorWL->setCurveListener(this); @@ -984,6 +1051,8 @@ Wavelet::Wavelet() : opacityShapeWL->setIdentityValue(0.); opacityShapeWL->setResetCurve(FlatCurveType(default_params.opacityCurveWL.at(0)), default_params.opacityCurveWL); opacityShapeWL->setTooltip(M("TP_WAVELET_OPACITYWL_TOOLTIP")); + opacityShapeWL->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + sigmafin->setAdjusterListener(this); // This will add the reset button at the end of the curveType buttons opacityCurveEditorWL->curveListComplete(); @@ -1002,19 +1071,26 @@ Wavelet::Wavelet() : tmr->set_tooltip_text(M("TP_WAVELET_BALCHRO_TOOLTIP")); tmrConn = tmr->signal_toggled().connect(sigc::mem_fun(*this, &Wavelet::tmrToggled)); + fincFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const fincBox = Gtk::manage(new ToolParamBlock()); + fincBox->pack_start(*opacityCurveEditorWL, Gtk::PACK_SHRINK, 2); + fincBox->pack_start(*sigmafin); + fincFrame->add(*fincBox); + + dirFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const dirBox = Gtk::manage(new ToolParamBlock()); + dirBox->pack_start(*ctboxBA); + dirBox->pack_start(*balance); + dirBox->pack_start(*opacityCurveEditorW, Gtk::PACK_SHRINK, 2); + dirBox->pack_start(*iter); + dirBox->pack_start(*sigmadir); + dirBox->pack_start(*tmr); + dirFrame->add(*dirBox); + ToolParamBlock* const finalBox = Gtk::manage(new ToolParamBlock()); + finalBox->pack_start(*dirFrame); - finalBox->pack_start(*ctboxBA); - finalBox->pack_start(*balance); - - finalBox->pack_start(*opacityCurveEditorW, Gtk::PACK_SHRINK, 2); - - finalBox->pack_start(*iter); - - finalBox->pack_start(*tmr); - finalBox->pack_start(*separatorbalend, Gtk::PACK_SHRINK, 2); - finalBox->pack_start(*opacityCurveEditorWL, Gtk::PACK_SHRINK, 2); - + finalBox->pack_start(*fincFrame); finalBox->pack_start(*curveEditorG, Gtk::PACK_SHRINK, 4); finalBox->pack_start(*softradend); @@ -1073,6 +1149,7 @@ Wavelet::~Wavelet() idle_register.destroy(); delete opaCurveEditorG; + delete curveEditorC; delete opacityCurveEditorG; delete curveEditorbl; delete CCWcurveEditorG; @@ -1084,6 +1161,24 @@ Wavelet::~Wavelet() } +void Wavelet::updateGUI() +{ + const int temp2 = threshold2->getValue(); + const int temp = threshold->getValue(); + const int maxlev = thres->getValue(); + threshold2->setLimits(temp + 1, maxlev, 1, maxlev + 1); + threshold2 ->setValue(temp2); +} + +void Wavelet::updateGUImaxlev() +{ + const int temp4 = threshold->getValue(); + const int temp3 = thres->getValue(); + threshold->setLimits(1, temp3, 1, temp3); + threshold ->setValue(temp4); +} + + void Wavelet::wavChanged(double nlevel) { if (!batchMode) { @@ -1120,6 +1215,13 @@ void Wavelet::neutral_pressed() } } +void Wavelet::setListener(ToolPanelListener *tpl) +{ + ToolPanel::setListener(tpl); + labgrid->setListener(tpl); +} + + void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) { @@ -1295,6 +1397,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) ccshape->setCurve(pp->wavelet.ccwcurve); blshape->setCurve(pp->wavelet.blcurve); opacityShapeRG->setCurve(pp->wavelet.opacityCurveRG); + opacityShapeSH->setCurve(pp->wavelet.opacityCurveSH); opacityShapeBY->setCurve(pp->wavelet.opacityCurveBY); opacityShape->setCurve(pp->wavelet.opacityCurveW); opacityShapeWL->setCurve(pp->wavelet.opacityCurveWL); @@ -1381,7 +1484,9 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) skinprotect->setValue(pp->wavelet.skinprotect); hueskin->setValue(pp->wavelet.hueskin); hueskin2->setValue(pp->wavelet.hueskin2); + updateGUImaxlev(); threshold->setValue(pp->wavelet.threshold); + updateGUI(); threshold2->setValue(pp->wavelet.threshold2); edgedetect->setValue(pp->wavelet.edgedetect); edgedetectthr->setValue(pp->wavelet.edgedetectthr); @@ -1406,6 +1511,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) mergeC->setValue(pp->wavelet.mergeC); softrad->setValue(pp->wavelet.softrad); softradend->setValue(pp->wavelet.softradend); + labgrid->setParams(pp->wavelet.labgridALow / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridBLow / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridAHigh / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridBHigh / WaveletParams::LABGRID_CORR_MAX, false); ballum->setValue(pp->wavelet.ballum); balchrom->setValue(pp->wavelet.balchrom); @@ -1418,6 +1524,12 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) strength->setValue(pp->wavelet.strength); balance->setValue(pp->wavelet.balance); iter->setValue(pp->wavelet.iter); + sigmafin->setValue(pp->wavelet.sigmafin); + sigmaton->setValue(pp->wavelet.sigmaton); + sigmacol->setValue(pp->wavelet.sigmacol); + sigmadir->setValue(pp->wavelet.sigmadir); + rangeab->setValue(pp->wavelet.rangeab); + protab->setValue(pp->wavelet.protab); for (int i = 0; i < 9; i++) { correction[i]->setValue(pp->wavelet.c[i]); @@ -1493,6 +1605,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) if (!pedited->wavelet.ushamethod) { ushamethod->set_active_text(M("GENERAL_UNCHANGED")); } + labgrid->setEdited(pedited->wavelet.labgridALow || pedited->wavelet.labgridBLow || pedited->wavelet.labgridAHigh || pedited->wavelet.labgridBHigh); set_inconsistent(multiImage && !pedited->wavelet.enabled); ccshape->setUnChanged(!pedited->wavelet.ccwcurve); @@ -1507,6 +1620,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) exptoning->set_inconsistent(!pedited->wavelet.exptoning); expnoise->set_inconsistent(!pedited->wavelet.expnoise); opacityShapeRG->setCurve(pp->wavelet.opacityCurveRG); + opacityShapeSH->setCurve(pp->wavelet.opacityCurveSH); opacityShapeBY->setCurve(pp->wavelet.opacityCurveBY); opacityShape->setCurve(pp->wavelet.opacityCurveW); opacityShapeWL->setCurve(pp->wavelet.opacityCurveWL); @@ -1535,6 +1649,12 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) thres->setEditedState(pedited->wavelet.thres ? Edited : UnEdited); balance->setEditedState(pedited->wavelet.balance ? Edited : UnEdited); iter->setEditedState(pedited->wavelet.iter ? Edited : UnEdited); + sigmafin->setEditedState(pedited->wavelet.sigmafin ? Edited : UnEdited); + sigmaton->setEditedState(pedited->wavelet.sigmaton ? Edited : UnEdited); + sigmacol->setEditedState(pedited->wavelet.sigmacol ? Edited : UnEdited); + sigmadir->setEditedState(pedited->wavelet.sigmadir ? Edited : UnEdited); + rangeab->setEditedState(pedited->wavelet.rangeab ? Edited : UnEdited); + protab->setEditedState(pedited->wavelet.protab ? Edited : UnEdited); threshold->setEditedState(pedited->wavelet.threshold ? Edited : UnEdited); threshold2->setEditedState(pedited->wavelet.threshold2 ? Edited : UnEdited); edgedetect->setEditedState(pedited->wavelet.edgedetect ? Edited : UnEdited); @@ -1693,6 +1813,7 @@ void Wavelet::setEditProvider(EditDataProvider *provider) ccshape->setEditProvider(provider); blshape->setEditProvider(provider); opacityShapeRG->setEditProvider(provider); + opacityShapeSH->setEditProvider(provider); opacityShapeBY->setEditProvider(provider); opacityShape->setEditProvider(provider); opacityShapeWL->setEditProvider(provider); @@ -1770,6 +1891,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.ccwcurve = ccshape->getCurve(); pp->wavelet.blcurve = blshape->getCurve(); pp->wavelet.opacityCurveRG = opacityShapeRG->getCurve(); + pp->wavelet.opacityCurveSH = opacityShapeSH->getCurve(); pp->wavelet.opacityCurveBY = opacityShapeBY->getCurve(); pp->wavelet.opacityCurveW = opacityShape->getCurve(); pp->wavelet.opacityCurveWL = opacityShapeWL->getCurve(); @@ -1783,6 +1905,11 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.ballum = ballum->getValue(); pp->wavelet.chromfi = chromfi->getValue(); pp->wavelet.chromco = chromco->getValue(); + labgrid->getParams(pp->wavelet.labgridALow, pp->wavelet.labgridBLow, pp->wavelet.labgridAHigh, pp->wavelet.labgridBHigh); + pp->wavelet.labgridALow *= WaveletParams::LABGRID_CORR_MAX; + pp->wavelet.labgridAHigh *= WaveletParams::LABGRID_CORR_MAX; + pp->wavelet.labgridBLow *= WaveletParams::LABGRID_CORR_MAX; + pp->wavelet.labgridBHigh *= WaveletParams::LABGRID_CORR_MAX; pp->wavelet.greenlow = greenlow->getValue(); pp->wavelet.bluelow = bluelow->getValue(); @@ -1806,6 +1933,12 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.iter = (int) iter->getValue(); pp->wavelet.wavclCurve = clshape->getCurve(); + pp->wavelet.sigmafin = sigmafin->getValue(); + pp->wavelet.sigmaton = sigmaton->getValue(); + pp->wavelet.sigmacol = sigmacol->getValue(); + pp->wavelet.sigmadir = sigmadir->getValue(); + pp->wavelet.rangeab = rangeab->getValue(); + pp->wavelet.protab = protab->getValue(); for (int i = 0; i < 9; i++) { pp->wavelet.c[i] = (int) correction[i]->getValue(); @@ -1887,6 +2020,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.level2noise = level2noise->getEditedState(); pedited->wavelet.level3noise = level3noise->getEditedState(); pedited->wavelet.opacityCurveRG = !opacityShapeRG->isUnChanged(); + pedited->wavelet.opacityCurveSH = !opacityShapeSH->isUnChanged(); pedited->wavelet.opacityCurveBY = !opacityShapeBY->isUnChanged(); pedited->wavelet.opacityCurveW = !opacityShape->isUnChanged(); pedited->wavelet.opacityCurveWL = !opacityShapeWL->isUnChanged(); @@ -1912,6 +2046,12 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.softradend = softradend->getEditedState(); pedited->wavelet.balance = balance->getEditedState(); pedited->wavelet.iter = iter->getEditedState(); + pedited->wavelet.sigmafin = sigmafin->getEditedState(); + pedited->wavelet.sigmaton = sigmaton->getEditedState(); + pedited->wavelet.sigmacol = sigmacol->getEditedState(); + pedited->wavelet.sigmadir = sigmadir->getEditedState(); + pedited->wavelet.rangeab = rangeab->getEditedState(); + pedited->wavelet.protab = protab->getEditedState(); pedited->wavelet.wavclCurve = !clshape->isUnChanged(); pedited->wavelet.expcontrast = !expcontrast->get_inconsistent(); pedited->wavelet.expchroma = !expchroma->get_inconsistent(); @@ -1922,6 +2062,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.exptoning = !exptoning->get_inconsistent(); pedited->wavelet.expnoise = !expnoise->get_inconsistent(); pedited->wavelet.expclari = !expclari->get_inconsistent(); + pedited->wavelet.labgridALow = pedited->wavelet.labgridBLow = pedited->wavelet.labgridAHigh = pedited->wavelet.labgridBHigh = labgrid->getEdited(); for (int i = 0; i < 9; i++) { pedited->wavelet.c[i] = correction[i]->getEditedState(); @@ -2062,6 +2203,8 @@ void Wavelet::curveChanged(CurveEditor* ce) listener->panelChanged(EvWavblshape, M("HISTORY_CUSTOMCURVE")); } else if (ce == opacityShapeRG) { listener->panelChanged(EvWavColor, M("HISTORY_CUSTOMCURVE")); + } else if (ce == opacityShapeSH) { + listener->panelChanged(EvWavlevelshc, M("HISTORY_CUSTOMCURVE")); } else if (ce == opacityShapeBY) { listener->panelChanged(EvWavOpac, M("HISTORY_CUSTOMCURVE")); } else if (ce == opacityShape) { @@ -2092,7 +2235,13 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit strength->setDefault(defParams->wavelet.strength); balance->setDefault(defParams->wavelet.balance); iter->setDefault(defParams->wavelet.iter); + sigmafin->setDefault(defParams->wavelet.sigmafin); + sigmaton->setDefault(defParams->wavelet.sigmaton); + sigmacol->setDefault(defParams->wavelet.sigmacol); + sigmadir->setDefault(defParams->wavelet.sigmadir); sigma->setDefault(defParams->wavelet.sigma); + rangeab->setDefault(defParams->wavelet.rangeab); + protab->setDefault(defParams->wavelet.protab); offset->setDefault(defParams->wavelet.offset); lowthr->setDefault(defParams->wavelet.lowthr); rescon->setDefault(defParams->wavelet.rescon); @@ -2141,6 +2290,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit balchrom->setDefault(defParams->wavelet.balchrom); chromfi->setDefault(defParams->wavelet.chromfi); chromco->setDefault(defParams->wavelet.chromco); + labgrid->setDefault(defParams->wavelet.labgridALow / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridBLow / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridAHigh / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridBHigh / WaveletParams::LABGRID_CORR_MAX); greenlow->setDefault(defParams->wavelet.greenlow); bluelow->setDefault(defParams->wavelet.bluelow); @@ -2168,6 +2318,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit balchrom->setDefaultEditedState(pedited->wavelet.balchrom ? Edited : UnEdited); chromfi->setDefaultEditedState(pedited->wavelet.chromfi ? Edited : UnEdited); chromco->setDefaultEditedState(pedited->wavelet.chromco ? Edited : UnEdited); + labgrid->setEdited((pedited->wavelet.labgridALow || pedited->wavelet.labgridBLow || pedited->wavelet.labgridAHigh || pedited->wavelet.labgridBHigh) ? Edited : UnEdited); sigma->setDefault(defParams->wavelet.sigma); offset->setDefault(defParams->wavelet.offset); @@ -2214,6 +2365,12 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit strength->setDefaultEditedState(pedited->wavelet.strength ? Edited : UnEdited); balance->setDefaultEditedState(pedited->wavelet.balance ? Edited : UnEdited); iter->setDefaultEditedState(pedited->wavelet.iter ? Edited : UnEdited); + sigmafin->setDefaultEditedState(pedited->wavelet.sigmafin ? Edited : UnEdited); + sigmaton->setDefaultEditedState(pedited->wavelet.sigmaton ? Edited : UnEdited); + sigmacol->setDefaultEditedState(pedited->wavelet.sigmacol ? Edited : UnEdited); + sigmadir->setDefaultEditedState(pedited->wavelet.sigmadir ? Edited : UnEdited); + rangeab->setDefaultEditedState(pedited->wavelet.rangeab ? Edited : UnEdited); + protab->setDefaultEditedState(pedited->wavelet.protab ? Edited : UnEdited); level0noise->setDefaultEditedState(pedited->wavelet.level0noise ? Edited : UnEdited); level1noise->setDefaultEditedState(pedited->wavelet.level1noise ? Edited : UnEdited); level2noise->setDefaultEditedState(pedited->wavelet.level2noise ? Edited : UnEdited); @@ -2276,6 +2433,13 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit strength->setDefaultEditedState(Irrelevant); balance->setDefaultEditedState(Irrelevant); iter->setDefaultEditedState(Irrelevant); + sigmafin->setDefaultEditedState(Irrelevant); + sigmaton->setDefaultEditedState(Irrelevant); + sigmacol->setDefaultEditedState(Irrelevant); + sigmadir->setDefaultEditedState(Irrelevant); + rangeab->setDefaultEditedState(Irrelevant); + protab->setDefaultEditedState(Irrelevant); + labgrid->setEdited(Edited); for (int i = 0; i < 9; i++) { correction[i]->setDefaultEditedState(Irrelevant); @@ -2348,11 +2512,13 @@ void Wavelet::HSmethodUpdateUI() bllev->hide(); threshold->hide(); threshold2->hide(); + curveEditorC->hide(); } else { //with hllev->show(); bllev->show(); threshold->show(); threshold2->show(); + curveEditorC->show(); } } } @@ -2371,6 +2537,7 @@ void Wavelet::CHmethodUpdateUI() if (!batchMode) { if (CHmethod->get_active_row_number() == 0) { CHSLmethod->show(); + // sigmacol->show(); pastlev->hide(); satlev->hide(); chroma->hide(); @@ -2390,6 +2557,7 @@ void Wavelet::CHmethodUpdateUI() } } else if (CHmethod->get_active_row_number() == 1) { CHSLmethod->show(); + // sigmacol->show(); pastlev->show(); satlev->show(); chroma->show(); @@ -2409,6 +2577,7 @@ void Wavelet::CHmethodUpdateUI() } } else { chro->show(); + // sigmacol->hide(); pastlev->hide(); satlev->hide(); chroma->hide(); @@ -2510,15 +2679,18 @@ void Wavelet::BAmethodUpdateUI() balance->hide(); opacityCurveEditorW->hide(); iter->hide(); + tmr->hide(); } else if (BAmethod->get_active_row_number() == 1) { //sli opacityCurveEditorW->hide(); balance->show(); iter->show(); + tmr->show(); } else if (BAmethod->get_active_row_number() == 2) { //CU opacityCurveEditorW->show(); balance->hide(); iter->show(); + tmr->show(); } } } @@ -2757,6 +2929,7 @@ void Wavelet::setBatchMode(bool batchMode) Dirmethod->append(M("GENERAL_UNCHANGED")); CCWcurveEditorG->setBatchMode(batchMode); opaCurveEditorG->setBatchMode(batchMode); + curveEditorC->setBatchMode(batchMode); opacityCurveEditorG->setBatchMode(batchMode); opacityCurveEditorW->setBatchMode(batchMode); opacityCurveEditorWL->setBatchMode(batchMode); @@ -2808,6 +2981,12 @@ void Wavelet::setBatchMode(bool batchMode) strength->showEditedCB(); balance->showEditedCB(); iter->showEditedCB(); + sigmafin->showEditedCB(); + sigmaton->showEditedCB(); + sigmacol->showEditedCB(); + sigmadir->showEditedCB(); + rangeab->showEditedCB(); + protab->showEditedCB(); level0noise->showEditedCB(); level1noise->showEditedCB(); level2noise->showEditedCB(); @@ -2904,6 +3083,9 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvWavradius, radius->getTextValue()); } else if (a == threshold) { listener->panelChanged(EvWavThreshold, threshold->getTextValue()); + updateGUI(); + updateGUImaxlev(); + } else if (a == threshold2) { listener->panelChanged(EvWavThreshold2, threshold2->getTextValue()); } else if (a == edgedetect) { @@ -2949,6 +3131,8 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) } listener->panelChanged(EvWavthres, thres->getTextValue()); + updateGUImaxlev(); + updateGUI(); } else if (a == skinprotect) { listener->panelChanged(EvWavSkin, skinprotect->getTextValue()); } else if (a == strength) { @@ -2957,6 +3141,18 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvWavbalance, balance->getTextValue()); } else if (a == iter) { listener->panelChanged(EvWaviter, iter->getTextValue()); + } else if (a == sigmafin) { + listener->panelChanged(EvWavsigmafin, sigmafin->getTextValue()); + } else if (a == sigmaton) { + listener->panelChanged(EvWavsigmaton, sigmaton->getTextValue()); + } else if (a == rangeab) { + listener->panelChanged(EvWavrangeab, rangeab->getTextValue()); + } else if (a == protab) { + listener->panelChanged(EvWavprotab, protab->getTextValue()); + } else if (a == sigmacol) { + listener->panelChanged(EvWavsigmacol, sigmacol->getTextValue()); + } else if (a == sigmadir) { + listener->panelChanged(EvWavsigmadir, sigmadir->getTextValue()); } else if (a == greenhigh) { listener->panelChanged(EvWavgreenhigh, greenhigh->getTextValue()); } else if (a == bluehigh) { @@ -3500,6 +3696,8 @@ void Wavelet::neutralPressed() correction[i]->setValue(0); adjusterChanged(correction[i], 0); } + sup->setValue(0); + adjusterChanged(sup, 0); } void Wavelet::neutralchPressed() diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h index d1b4bb7c3..6daabcd67 100644 --- a/rtgui/wavelet.h +++ b/rtgui/wavelet.h @@ -33,6 +33,7 @@ class CurveEditorGroup; class DiagonalCurveEditor; class EditDataProvider; class FlatCurveEditor; +class LabGrid; class Wavelet final : public ToolParamBlock, @@ -93,8 +94,19 @@ private: rtengine::ProcEvent EvWavresblur; rtengine::ProcEvent EvWavresblurc; rtengine::ProcEvent EvWavedgeffect; + rtengine::ProcEvent EvWavsigmafin; + rtengine::ProcEvent EvWavsigmaton; + rtengine::ProcEvent EvWavsigmacol; + rtengine::ProcEvent EvWavsigmadir; + rtengine::ProcEvent EvWavLabGridValue; + rtengine::ProcEvent EvWavrangeab; + rtengine::ProcEvent EvWavprotab; + rtengine::ProcEvent EvWavlevelshc; + + LabGrid *labgrid; void foldAllButMe(GdkEventButton* event, MyExpander *expander); + void setListener(ToolPanelListener *tpl) override; void colorForValue(double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) override; void BAmethodChanged(); @@ -129,6 +141,8 @@ private: void updatewavLabel (); void wavChanged(double nlevel) override; void ushamethodChanged(); + void updateGUI(); + void updateGUImaxlev(); void HSmethodUpdateUI(); void CHmethodUpdateUI(); @@ -153,6 +167,8 @@ private: void enableToggled(MyExpander* expander); CurveEditorGroup* const curveEditorG; + CurveEditorGroup* const curveEditorC; + FlatCurveEditor* opacityShapeSH; CurveEditorGroup* const CCWcurveEditorG; CurveEditorGroup* const curveEditorbl; @@ -218,7 +234,13 @@ private: Adjuster* const strength; Adjuster* const balance; Adjuster* const iter; - + Adjuster* const sigmafin; + Adjuster* const sigmaton; + Adjuster* const sigmacol; + Adjuster* const sigmadir; + Adjuster* const rangeab; + Adjuster* const protab; + Adjuster* greenlow; Adjuster* bluelow; Adjuster* greenmed; @@ -294,6 +316,9 @@ private: Gtk::Frame* const blurFrame; Gtk::Frame* const chromaFrame; Gtk::Frame* const chroFrame; + Gtk::Frame* const fincFrame; + Gtk::Frame* const dirFrame; + Gtk::Frame* const tonFrame; Gtk::Label* const wavLabels; Gtk::Label* const labmC; diff --git a/tools/INSTALL.readme b/tools/INSTALL.readme new file mode 100644 index 000000000..a4f19ec3c --- /dev/null +++ b/tools/INSTALL.readme @@ -0,0 +1,3 @@ +To install the RawTherapee application, open the .dmg and drag the RawTherapee app onto the /Applications folder. + +To use the optional rawtherapee-cli command line interface, move rawtherapee-cli into a folder in your $PATH and install the RawTherapee app as above. diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 9258810c0..e3dc61857 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -106,7 +106,7 @@ __EOS__ minimum_macos_version=${MINIMUM_SYSTEM_VERSION} -# Retreive cached values from cmake +# Retrieve cached values from cmake #In: LOCAL_PREFIX:STRING=/opt #Out: /opt @@ -236,6 +236,11 @@ ditto {"${LOCAL_PREFIX}/local","${RESOURCES}"}/share/icons/Adwaita/index.theme "${LOCAL_PREFIX}/local/bin/gtk-update-icon-cache" "${RESOURCES}/share/icons/Adwaita" ditto "${LOCAL_PREFIX}/local/share/icons/hicolor" "${RESOURCES}/share/icons/hicolor" +# fix libfreetype install name +for lib in "${LIB}"/*; do + install_name_tool -change libfreetype.6.dylib "${LIB}"/libfreetype.6.dylib "${lib}" +done + # pixbuf loaders & immodules msg "Build GTK3 databases:" "${LOCAL_PREFIX}"/local/bin/gdk-pixbuf-query-loaders "${LIB}"/libpix*.so > "${ETC}"/gtk-3.0/gdk-pixbuf.loaders @@ -259,11 +264,11 @@ ditto "${PROJECT_SOURCE_DIR}/rtdata/fonts" "${ETC}/fonts" ditto "${PROJECT_SOURCE_DATA_DIR}/"{rawtherapee,profile}.icns "${RESOURCES}" ditto "${PROJECT_SOURCE_DATA_DIR}/PkgInfo" "${CONTENTS}" install -m 0644 "${PROJECT_SOURCE_DATA_DIR}/Info.plist.in" "${CONTENTS}/Info.plist" +install -m 0644 "${PROJECT_SOURCE_DATA_DIR}/cliInfo.plist.in" "${LIB}/Info.plist" sed -i "" -e "s|@version@|${PROJECT_FULL_VERSION}| s|@shortVersion@|${PROJECT_VERSION}| s|@arch@|${arch}|" \ "${CONTENTS}/Info.plist" -plutil -convert binary1 "${CONTENTS}/Info.plist" update-mime-database -V "${RESOURCES}/share/mime" msg "Build glib database:" @@ -279,23 +284,25 @@ ModifyInstallNames # fix @rpath in Frameworks msg "Registering @rpath in Frameworks folder." -for frameworklibs in "${LIB}"/*{dylib,so}; do +for frameworklibs in "${LIB}"/*{dylib,so,cli}; do install_name_tool -delete_rpath ${LOCAL_PREFIX}/local/lib "${frameworklibs}" install_name_tool -add_rpath /Applications/"${LIB}" "${frameworklibs}" done install_name_tool -delete_rpath RawTherapee.app/Contents/Frameworks "${EXECUTABLE}"-cli -install_name_tool -add_rpath @executable_path "${EXECUTABLE}"-cli +install_name_tool -add_rpath /Applications/"${LIB}" "${EXECUTABLE}"-cli +ditto "${EXECUTABLE}"-cli "${APP}"/.. # Codesign the app if [[ -n $CODESIGNID ]]; then msg "Codesigning Application." - install -m 0644 "${PROJECT_SOURCE_DATA_DIR}"/rt.entitlements "${CMAKE_BUILD_TYPE}"/rt.entitlements - plutil -convert binary1 "${CMAKE_BUILD_TYPE}"/rt.entitlements + iconv -f UTF-8 -t ASCII "${PROJECT_SOURCE_DATA_DIR}"/rt.entitlements > "${CMAKE_BUILD_TYPE}"/rt.entitlements + iconv -f UTF-8 -t ASCII "${PROJECT_SOURCE_DATA_DIR}"/rt-cli.entitlements > "${CMAKE_BUILD_TYPE}"/rt-cli.entitlements mv "${EXECUTABLE}"-cli "${LIB}" - for frameworklibs in "${LIB}"/*; do - codesign -v -s "${CODESIGNID}" -i com.rawtherapee.RawTherapee --force --verbose -o runtime --timestamp "${frameworklibs}" + for frameworklibs in "${LIB}"/*{dylib,so}; do + codesign -v -s "${CODESIGNID}" -i com.rawtherapee.RawTherapee --force --verbose -o runtime --timestamp --entitlements "${CMAKE_BUILD_TYPE}"/rt.entitlements "${frameworklibs}" done - codesign --timestamp --strict -v -s "${CODESIGNID}" -i com.rawtherapee.RawTherapee -o runtime --entitlements "${CMAKE_BUILD_TYPE}"/rt.entitlements "${APP}" + codesign --force -v -s "${CODESIGNID}" -i com.rawtherapee.RawTherapee -o runtime --entitlements "${CMAKE_BUILD_TYPE}"/rt-cli.entitlements "${LIB}"/rawtherapee-cli + codesign --deep --timestamp --strict -v -s "${CODESIGNID}" -i com.rawtherapee.RawTherapee -o runtime --entitlements "${CMAKE_BUILD_TYPE}"/rt.entitlements "${APP}" spctl -a -vvvv "${APP}" fi @@ -345,7 +352,7 @@ function CreateDmg { CreateWebloc 'Report Bug' 'https://github.com/Beep6581/RawTherapee/issues/new' # Disk image name - dmg_name="${PROJECT_NAME// /_}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}" + dmg_name="${PROJECT_NAME}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}" lower_build_type="$(tr '[:upper:]' '[:lower:]' <<< "$CMAKE_BUILD_TYPE")" if [[ $lower_build_type != release ]]; then dmg_name="${dmg_name}_${lower_build_type}" @@ -390,6 +397,7 @@ function CreateDmg { xcrun stapler staple "${dmg_name}.dmg" # staple the ticket xcrun stapler validate -v "${dmg_name}.dmg" echo "dmg Notarization success" + rm *dmg.zip break elif [[ $status1 = "in" ]]; then echo "dmg Notarization still in progress, sleeping for 15 seconds and trying again" @@ -404,10 +412,12 @@ function CreateDmg { # Zip disk image for redistribution msg "Zipping disk image for redistribution:" - zip "${dmg_name}.zip" "${dmg_name}.dmg" - rm "${dmg_name}.dmg" - msg "Removing disk image caches:" - rm -rf "${srcDir}" + mkdir "${PROJECT_NAME}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}_folder" + ditto {"${PROJECT_NAME}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}.dmg","rawtherapee-cli","${PROJECT_SOURCE_DATA_DIR}/INSTALL.readme.rtf"} "${PROJECT_NAME}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}_folder" + zip -r "${PROJECT_NAME}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_OSX_${MINIMUM_SYSTEM_VERSION}_${PROC_BIT_DEPTH}_${PROJECT_FULL_VERSION}_folder/" + # rm "${dmg_name}.dmg" + # msg "Removing disk image caches:" + # rm -rf "${srcDir}" } CreateDmg msg "Finishing build:" diff --git a/tools/osx/rt.entitlements b/tools/osx/rt.entitlements index c571f1f41..8fc97c7da 100644 --- a/tools/osx/rt.entitlements +++ b/tools/osx/rt.entitlements @@ -1,19 +1,16 @@ + - - application-identifier - com.rawtherapee.RawTherapee - com.apple.security.temporary-exception.files.absolute-path.read-write - - / - - com.apple.security.cs.allow-dyld-environment-variables - - com.apple.security.files.user-selected.read-write - - com.apple.security.app-sandbox - - com.apple.security.files.downloads.read-write - - - \ No newline at end of file + + com.apple.application-identifier + com.rawtherapee.RawTherapee + com.apple.security.app-sandbox + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.temporary-exception.files.absolute-path.read-write + + / + + +