diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e483ace01..4fa09ee98 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,16 +14,16 @@ on: - created jobs: build: - runs-on: macos-10.15 + runs-on: macos-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Install dependencies run: | date -u mkdir build date +%s > build/stamp brew uninstall --ignore-dependencies libtiff - brew install libtiff gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++ little-cms2 libiptcdata fftw lensfun expat pkgconfig libomp shared-mime-info | tee -a depslog + brew install libtiff gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++@2 little-cms2 libiptcdata fftw lensfun expat pkgconfig libomp shared-mime-info | tee -a depslog date -u echo "----====Pourage====----" cat depslog | grep Pouring @@ -82,11 +82,11 @@ jobs: echo "=== artifact: ${ARTIFACT}" # defining environment variables for next step as per # https://github.com/actions/starter-workflows/issues/68 - echo "::set-env name=ARTIFACT_PATH::${GITHUB_WORKSPACE}/build/${ARTIFACT}" - echo "::set-env name=ARTIFACT_FILE::${ARTIFACT}" + echo "ARTIFACT_PATH=${GITHUB_WORKSPACE}/build/${ARTIFACT}" >> $GITHUB_ENV + echo "ARTIFACT_FILE=${ARTIFACT}" >> $GITHUB_ENV zsh -c 'echo "Bundled in $(printf "%0.2f" $(($[$(date +%s)-$(cat bundlestamp)]/$((60.))))) minutes"' exit - - uses: actions/upload-artifact@v1 + - uses: actions/upload-artifact@v2 with: name: ${{env.ARTIFACT_FILE}} path: ${{env.ARTIFACT_PATH}} diff --git a/AUTHORS.txt b/AUTHORS.txt index 227390faa..ec40f75e1 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 @@ -14,12 +15,14 @@ Development contributors, in last name alphabetical order: Maciek Dworak Michael Ezra Flössie + Rüdiger Franke Jean-Christophe Frisch Ilias Giarimis Alberto Griggio Steve Herrell Philippe Hupé Wolfgang Kuehnel + Lawrence Lee Guokai Ma Emil Martinec Wyatt Olson @@ -36,8 +39,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 @@ -56,12 +60,14 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati Oscar de Lama Lebarhon Karl Loncarek + Patrick Lopatto Jie Luo Paul Matthijsse Wim ter Meer Alberto Righetto Kostia (Kildor) Romanov Kalle Söderman + Wayne Sutton Johan Thor Vitalis Tiknius TooWaBoo diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d66109e0..cc5c2b09b 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_EQUAL "10.1") + 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: @@ -444,13 +456,13 @@ if(GTK_VERSION VERSION_GREATER "3.24.1" AND GTK_VERSION VERSION_LESS "3.24.7") ) endif() -pkg_check_modules(GLIB2 REQUIRED glib-2.0>=2.44) -pkg_check_modules(GLIBMM REQUIRED glibmm-2.4>=2.44) +pkg_check_modules(GLIB2 REQUIRED glib-2.0>=2.48) +pkg_check_modules(GLIBMM REQUIRED glibmm-2.4>=2.48) pkg_check_modules(CAIROMM REQUIRED cairomm-1.0) -pkg_check_modules(GIO REQUIRED gio-2.0>=2.44) -pkg_check_modules(GIOMM REQUIRED giomm-2.4>=2.44) -pkg_check_modules(GTHREAD REQUIRED gthread-2.0>=2.44) -pkg_check_modules(GOBJECT REQUIRED gobject-2.0>=2.44) +pkg_check_modules(GIO REQUIRED gio-2.0>=2.48) +pkg_check_modules(GIOMM REQUIRED giomm-2.4>=2.48) +pkg_check_modules(GTHREAD REQUIRED gthread-2.0>=2.48) +pkg_check_modules(GOBJECT REQUIRED gobject-2.0>=2.48) pkg_check_modules(SIGC REQUIRED sigc++-2.0>=2.3.1) pkg_check_modules(LENSFUN REQUIRED lensfun>=0.2) pkg_check_modules(RSVG REQUIRED librsvg-2.0>=2.40) @@ -481,7 +493,11 @@ endif() # Check for libcanberra-gtk3 (sound events on Linux): if(UNIX AND (NOT APPLE)) - pkg_check_modules(CANBERRA-GTK REQUIRED libcanberra-gtk3) + option(USE_LIBCANBERRA "Build with libcanberra" ON) + if(USE_LIBCANBERRA) + pkg_check_modules(CANBERRA-GTK REQUIRED libcanberra-gtk3) + add_definitions(-DUSE_CANBERRA) + endif() endif() if(WITH_MYFILE_MMAP) @@ -625,14 +641,8 @@ else() endif() # Get compiler name and version. - get_filename_component(COMPILER_INFO ${CMAKE_C_COMPILER} NAME_WE) - set(COMPILER_INFO "${COMPILER_INFO} ${CMAKE_C_COMPILER_VERSION}") -if(NOT APPLE) - execute_process( - COMMAND gcc -dumpversion - OUTPUT_VARIABLE GCC_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - set(COMPILER_INFO "gcc ${GCC_VERSION}") -endif() +get_filename_component(COMPILER_INFO ${CMAKE_C_COMPILER} NAME_WE) +set(COMPILER_INFO "${COMPILER_INFO} ${CMAKE_C_COMPILER_VERSION}") # Get C++ and linker flags for rtengine (the GUI's C++ flags may have fewer # flags): diff --git a/rtdata/dcpprofiles/CANON EOS 5D MARK IV.dcp b/rtdata/dcpprofiles/Canon EOS 5D Mark IV.dcp similarity index 100% rename from rtdata/dcpprofiles/CANON EOS 5D MARK IV.dcp rename to rtdata/dcpprofiles/Canon EOS 5D Mark IV.dcp diff --git a/rtdata/dcpprofiles/Canon EOS 90D.dcp b/rtdata/dcpprofiles/Canon EOS 90D.dcp new file mode 100644 index 000000000..e50e677b1 Binary files /dev/null and b/rtdata/dcpprofiles/Canon EOS 90D.dcp differ diff --git a/rtdata/dcpprofiles/CANON EOS M6 MARK II.dcp b/rtdata/dcpprofiles/Canon EOS M6 Mark II.dcp similarity index 100% rename from rtdata/dcpprofiles/CANON EOS M6 MARK II.dcp rename to rtdata/dcpprofiles/Canon EOS M6 Mark II.dcp diff --git a/rtdata/dcpprofiles/CANON EOS R.dcp b/rtdata/dcpprofiles/Canon EOS R.dcp similarity index 100% rename from rtdata/dcpprofiles/CANON EOS R.dcp rename to rtdata/dcpprofiles/Canon EOS R.dcp diff --git a/rtdata/dcpprofiles/Canon EOS R5.dcp b/rtdata/dcpprofiles/Canon EOS R5.dcp new file mode 100644 index 000000000..88f94620d Binary files /dev/null and b/rtdata/dcpprofiles/Canon EOS R5.dcp differ diff --git a/rtdata/dcpprofiles/Canon EOS R6.dcp b/rtdata/dcpprofiles/Canon EOS R6.dcp new file mode 100644 index 000000000..7aaa04ab2 Binary files /dev/null and b/rtdata/dcpprofiles/Canon EOS R6.dcp differ diff --git a/rtdata/dcpprofiles/CANON POWERSHOT G1 X MARK II.dcp b/rtdata/dcpprofiles/Canon PowerShot G1 X Mark II.dcp similarity index 100% rename from rtdata/dcpprofiles/CANON POWERSHOT G1 X MARK II.dcp rename to rtdata/dcpprofiles/Canon PowerShot G1 X Mark II.dcp diff --git a/rtdata/dcpprofiles/FUJIFILM X-PRO3.dcp b/rtdata/dcpprofiles/FUJIFILM X-Pro3.dcp similarity index 100% rename from rtdata/dcpprofiles/FUJIFILM X-PRO3.dcp rename to rtdata/dcpprofiles/FUJIFILM X-Pro3.dcp diff --git a/rtdata/dcpprofiles/OLYMPUS E-M5MARKII.dcp b/rtdata/dcpprofiles/OLYMPUS E-M5MarkII.dcp similarity index 100% rename from rtdata/dcpprofiles/OLYMPUS E-M5MARKII.dcp rename to rtdata/dcpprofiles/OLYMPUS E-M5MarkII.dcp diff --git a/rtdata/dcpprofiles/Panasonic DC-S5.dcp b/rtdata/dcpprofiles/Panasonic DC-S5.dcp new file mode 100644 index 000000000..fd01c1225 Binary files /dev/null and b/rtdata/dcpprofiles/Panasonic DC-S5.dcp differ diff --git a/rtdata/iccprofiles/output/RTv2_Medium.icc b/rtdata/iccprofiles/output/RTv2_Medium.icc index ebaf4d133..930f38a71 100644 Binary files a/rtdata/iccprofiles/output/RTv2_Medium.icc and b/rtdata/iccprofiles/output/RTv2_Medium.icc differ diff --git a/rtdata/images/svg/bidirectional-arrow-horizontal-hicontrast.svg b/rtdata/images/svg/bidirectional-arrow-horizontal-hicontrast.svg new file mode 100644 index 000000000..f2712cee9 --- /dev/null +++ b/rtdata/images/svg/bidirectional-arrow-horizontal-hicontrast.svg @@ -0,0 +1,127 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/bidirectional-arrow-horizontal-prelight.svg b/rtdata/images/svg/bidirectional-arrow-horizontal-prelight.svg new file mode 100644 index 000000000..6382cc546 --- /dev/null +++ b/rtdata/images/svg/bidirectional-arrow-horizontal-prelight.svg @@ -0,0 +1,127 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/bidirectional-arrow-vertical-hicontrast.svg b/rtdata/images/svg/bidirectional-arrow-vertical-hicontrast.svg new file mode 100644 index 000000000..93cb21a43 --- /dev/null +++ b/rtdata/images/svg/bidirectional-arrow-vertical-hicontrast.svg @@ -0,0 +1,127 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/bidirectional-arrow-vertical-prelight.svg b/rtdata/images/svg/bidirectional-arrow-vertical-prelight.svg new file mode 100644 index 000000000..76f4312cb --- /dev/null +++ b/rtdata/images/svg/bidirectional-arrow-vertical-prelight.svg @@ -0,0 +1,127 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/draw.svg b/rtdata/images/svg/draw.svg new file mode 100644 index 000000000..30ea04ea4 --- /dev/null +++ b/rtdata/images/svg/draw.svg @@ -0,0 +1,108 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-ellipsis-small.svg b/rtdata/images/svg/histogram-ellipsis-small.svg new file mode 100644 index 000000000..4fdb17907 --- /dev/null +++ b/rtdata/images/svg/histogram-ellipsis-small.svg @@ -0,0 +1,135 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-bayer-on-small.svg b/rtdata/images/svg/histogram-type-histogram-raw-small.svg similarity index 100% rename from rtdata/images/svg/histogram-bayer-on-small.svg rename to rtdata/images/svg/histogram-type-histogram-raw-small.svg diff --git a/rtdata/images/svg/histogram-bayer-off-small.svg b/rtdata/images/svg/histogram-type-histogram-small.svg similarity index 59% rename from rtdata/images/svg/histogram-bayer-off-small.svg rename to rtdata/images/svg/histogram-type-histogram-small.svg index 5d6c439fb..1d2f6547e 100644 --- a/rtdata/images/svg/histogram-bayer-off-small.svg +++ b/rtdata/images/svg/histogram-type-histogram-small.svg @@ -1,6 +1,4 @@ - - + inkscape:version="1.0 (4035a4fb49, 2020-05-01)" + sodipodi:docname="histogram-type-histogram-small.svg"> + inkscape:snap-bbox-midpoints="false" + inkscape:document-rotation="0"> image/svg+xml - + - Maciej Dworak + Lawrence Lee @@ -100,40 +99,24 @@ inkscape:groupmode="layer" inkscape:label="Layer 1" transform="translate(0,-8)"> + + y="10" + x="2" + height="12" + width="12" + id="rect1467" + style="opacity:0.3;fill:#2a7fff;stroke-linecap:square;fill-opacity:1" /> - - - + style="opacity:1;fill:none;fill-opacity:0.3;stroke:#000000;stroke-width:0.999999;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect849" + width="13" + height="13.000001" + x="1.5" + y="9.5" /> diff --git a/rtdata/images/svg/histogram-type-parade-small.svg b/rtdata/images/svg/histogram-type-parade-small.svg new file mode 100644 index 000000000..f299f8ab2 --- /dev/null +++ b/rtdata/images/svg/histogram-type-parade-small.svg @@ -0,0 +1,132 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-vectorscope-hc-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hc-small.svg new file mode 100644 index 000000000..ef2e8b51f --- /dev/null +++ b/rtdata/images/svg/histogram-type-vectorscope-hc-small.svg @@ -0,0 +1,131 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-vectorscope-hs-small.svg b/rtdata/images/svg/histogram-type-vectorscope-hs-small.svg new file mode 100644 index 000000000..62bbf9586 --- /dev/null +++ b/rtdata/images/svg/histogram-type-vectorscope-hs-small.svg @@ -0,0 +1,135 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/histogram-type-waveform-small.svg b/rtdata/images/svg/histogram-type-waveform-small.svg new file mode 100644 index 000000000..5147ab2fc --- /dev/null +++ b/rtdata/images/svg/histogram-type-waveform-small.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + + + + Lawrence Lee + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + + diff --git a/rtdata/images/svg/perspective-horizontal-vertical.svg b/rtdata/images/svg/perspective-horizontal-vertical.svg new file mode 100644 index 000000000..0c5046879 --- /dev/null +++ b/rtdata/images/svg/perspective-horizontal-vertical.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + image/svg+xml + + + + + Maciej Dworak + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + + + + diff --git a/rtdata/languages/Chinese (Simplified) b/rtdata/languages/Chinese (Simplified) index 61cbd58ac..a2181050a 100644 --- a/rtdata/languages/Chinese (Simplified) +++ b/rtdata/languages/Chinese (Simplified) @@ -4,21 +4,29 @@ #03 2013-10-20 Jiero #04 2014-10-24 Jie Luo #05 2017-09-18 Chongnuo Ji +#06 2020-08-11 十一元人民币 ABOUT_TAB_BUILD;版本 -ABOUT_TAB_CREDITS;感谢 +ABOUT_TAB_CREDITS;致谢名单 ABOUT_TAB_LICENSE;授权协议 ABOUT_TAB_RELEASENOTES;发布说明 ABOUT_TAB_SPLASH;启动页 +ADJUSTER_RESET_TO_DEFAULT;单击-恢复默认值\nCtrl+单击-恢复初始值 BATCH_PROCESSING;批量处理 +CURVEEDITOR_AXIS_IN;I: +CURVEEDITOR_AXIS_LEFT_TAN;LT: +CURVEEDITOR_AXIS_OUT;O: +CURVEEDITOR_AXIS_RIGHT_TAN;RT: +CURVEEDITOR_CATMULLROM;灵活 CURVEEDITOR_CURVE;曲线 CURVEEDITOR_CURVES;曲线 CURVEEDITOR_CUSTOM;自定义 CURVEEDITOR_DARKS;暗 -CURVEEDITOR_HIGHLIGHTS;高亮 +CURVEEDITOR_EDITPOINT_HINT;启用对于节点进/出值的编辑\n\n右击节点以选中\n右击空白处以取消选中节点 +CURVEEDITOR_HIGHLIGHTS;高光 CURVEEDITOR_LIGHTS;光 CURVEEDITOR_LINEAR;线性 -CURVEEDITOR_LOADDLGLABEL;正读取曲线... +CURVEEDITOR_LOADDLGLABEL;加载曲线... CURVEEDITOR_MINMAXCPOINTS;均衡器 CURVEEDITOR_NURBS;控制点 CURVEEDITOR_PARAMETRIC;参数 @@ -35,18 +43,25 @@ DONT_SHOW_AGAIN;不再显示该信息 DYNPROFILEEDITOR_DELETE;删除 DYNPROFILEEDITOR_EDIT;编辑 DYNPROFILEEDITOR_EDIT_RULE;编辑动态配置规则 -DYNPROFILEEDITOR_ENTRY_TOOLTIP;该项匹配不区分大小写 \n使用 "re:" 前缀来输入 \na 正则式 +DYNPROFILEEDITOR_ENTRY_TOOLTIP;该项匹配不区分大小写 \n使用 "re:" 前缀来输入\na 正则式 +DYNPROFILEEDITOR_IMGTYPE_ANY;Any +DYNPROFILEEDITOR_IMGTYPE_HDR;HDR +DYNPROFILEEDITOR_IMGTYPE_PS;像素偏移 +DYNPROFILEEDITOR_IMGTYPE_STD;标准 DYNPROFILEEDITOR_MOVE_DOWN;下移 DYNPROFILEEDITOR_MOVE_UP;上移 DYNPROFILEEDITOR_NEW;新建 DYNPROFILEEDITOR_NEW_RULE;新建动态配置规则 DYNPROFILEEDITOR_PROFILE;处理配置规则 EDITWINDOW_TITLE;图片修改 +EDIT_OBJECT_TOOLTIP;在预览窗口中展示一个允许你调整本工具的widget窗口。 +EDIT_PIPETTE_TOOLTIP;要向曲线添加调整点,点击此按钮,按住Ctrl键并用鼠标左键点击图像预览中你想要的点。\n要调整点的位置,按住Ctrl键并用鼠标左键点击图像预览中的对应位置,然后松开Ctrl(除非你希望精调)同时按住鼠标左键,将鼠标向上/下移动以上下移动曲线中的点。 EXIFFILTER_APERTURE;光圈 EXIFFILTER_CAMERA;相机 EXIFFILTER_EXPOSURECOMPENSATION;曝光补偿值 (EV) EXIFFILTER_FILETYPE;文件类型 EXIFFILTER_FOCALLEN;焦距 +EXIFFILTER_IMAGETYPE;图像类型 EXIFFILTER_ISO;感光度 EXIFFILTER_LENS;镜头 EXIFFILTER_METADATAFILTER;启用元数据过滤器 @@ -64,101 +79,133 @@ EXIFPANEL_RESET;重置 EXIFPANEL_RESETALL;全部重置 EXIFPANEL_RESETALLHINT;重置所有标签内容 EXIFPANEL_RESETHINT;重置所选标签内容 +EXIFPANEL_SHOWALL;显示所有 EXIFPANEL_SUBDIRECTORY;子文件夹 -EXPORT_BYPASS_ALL;(取消)选择全部 -EXPORT_BYPASS_DEFRINGE;不应用去边处理 -EXPORT_BYPASS_DIRPYRDENOISE;不应用降噪处理 -EXPORT_BYPASS_DIRPYREQUALIZER;不应用分频反差调整 -EXPORT_BYPASS_EQUALIZER;不应用小波变换级别处理 -EXPORT_BYPASS_RAW_CA;不应用 [raw] 色差矫正 -EXPORT_BYPASS_RAW_CCSTEPS;不应用 [raw] 摩尔纹控制 -EXPORT_BYPASS_RAW_DF;不应用 [raw] 暗场处理 -EXPORT_BYPASS_RAW_FF;不应用 [raw] 平场 -EXPORT_BYPASS_RAW_GREENTHRESH;不应用 [raw] 绿色偏纠正 -EXPORT_BYPASS_RAW_LINENOISE;不应用 [raw] 线噪过滤 -EXPORT_BYPASS_SHARPENEDGE;不应用边缘锐化 -EXPORT_BYPASS_SHARPENING;不应用锐化 -EXPORT_BYPASS_SHARPENMICRO;不应用微反差调节 +EXPORT_BYPASS;要跳过的处理步骤 +EXPORT_BYPASS_ALL;选择/取消选择全部选项 +EXPORT_BYPASS_DEFRINGE;跳过去边处理 +EXPORT_BYPASS_DIRPYRDENOISE;跳过降噪处理 +EXPORT_BYPASS_DIRPYREQUALIZER;跳过分频反差调整 +EXPORT_BYPASS_EQUALIZER;跳过小波层级处理 +EXPORT_BYPASS_RAW_CA;跳过 [raw] 色差矫正 +EXPORT_BYPASS_RAW_CCSTEPS;跳过 [raw] 伪色抑制 +EXPORT_BYPASS_RAW_DCB_ENHANCE;跳过 [raw] DCB优化步长 +EXPORT_BYPASS_RAW_DCB_ITERATIONS;跳过 [raw] DCB迭代 +EXPORT_BYPASS_RAW_DF;跳过 [raw] 暗场处理 +EXPORT_BYPASS_RAW_FF;跳过 [raw] 平场 +EXPORT_BYPASS_RAW_GREENTHRESH;跳过 [raw] 绿平衡 +EXPORT_BYPASS_RAW_LINENOISE;跳过 [raw] 线状噪点过滤 +EXPORT_BYPASS_RAW_LMMSE_ITERATIONS;跳过 [raw] LMMSE优化步长 +EXPORT_BYPASS_SHARPENEDGE;跳过边缘锐化 +EXPORT_BYPASS_SHARPENING;跳过锐化 +EXPORT_BYPASS_SHARPENMICRO;跳过微反差调节 EXPORT_FASTEXPORTOPTIONS;快速导出选项 -EXPORT_MAXHEIGHT;最大高度 -EXPORT_MAXWIDTH;最大宽度 -EXPORT_PUTTOQUEUEFAST; 放入快速导出序列 -EXPORT_RAW_DMETHOD;反拜尔算法 +EXPORT_INSTRUCTIONS;快速导出选项提供跳过占用资源和时间的处理步骤的选项,并使用快速导出设定来进行队列处理。\n此方法推荐在优先追求速度,生成低分辨率图片时使用,或是调整尺寸的输出大小适合你想输出的图片,你又不想修改这些照片的后期处理设定时使用。 +EXPORT_MAXHEIGHT;最大高度: +EXPORT_MAXWIDTH;最大宽度: +EXPORT_PIPELINE;输出流水线 +EXPORT_PUTTOQUEUEFAST; 放入快速导出队列 +EXPORT_RAW_DMETHOD;去马赛克算法 +EXPORT_USE_FAST_PIPELINE;专门(对缩放大小的图片应用全部处理) +EXPORT_USE_FAST_PIPELINE_TIP;使用专门的处理流水线来对图片进行处理,以牺牲质量来换取速度。对图片的缩放会尽早进行,而非在正常流水线中那样在最后进行。这能够大幅提升速度,但是用户可能会在输出的图片中看到杂点和较低的总体质量。 +EXPORT_USE_NORMAL_PIPELINE;标准(跳过某些步骤,并在最后缩放图片) EXTPROGTARGET_1;raw EXTPROGTARGET_2;队列已处理 FILEBROWSER_APPLYPROFILE;应用配置 -FILEBROWSER_APPLYPROFILE_PARTIAL;应用 - 局部 +FILEBROWSER_APPLYPROFILE_PARTIAL;部分应用配置 FILEBROWSER_AUTODARKFRAME;自动暗场 FILEBROWSER_AUTOFLATFIELD;自动平场 +FILEBROWSER_BROWSEPATHHINT;输入你想前往的路径。\n\n快捷键:\nCtrl-o 让文本框获得焦点\nEnter / Ctrl-Enter 前往输入的目录\nEsc 清除改动\nShift-Esc 让文本框失去焦点\n\n路径快捷键:\n~ - 用户的home/文档路径\n! - 用户的图片路径 FILEBROWSER_CACHE;缓存 -FILEBROWSER_CLEARPROFILE;清空配置 -FILEBROWSER_COPYPROFILE;复制配置 +FILEBROWSER_CACHECLEARFROMFULL;清除全部,包括缓存文件 +FILEBROWSER_CACHECLEARFROMPARTIAL;清除全部,不包括缓存文件 +FILEBROWSER_CLEARPROFILE;清空 +FILEBROWSER_COLORLABEL_TOOLTIP;颜色标记,\n\n使用下拉菜单或快捷键:\nShift-Ctrl-0 无颜色\nShift-Ctrl-1 红\nShift-Ctrl-2 黄\nShift-Ctrl-3 绿\nShift-Ctrl-4 蓝\nShift-Ctrl-5 紫 +FILEBROWSER_COPYPROFILE;复制 FILEBROWSER_CURRENT_NAME;当前名称: FILEBROWSER_DARKFRAME;暗场 -FILEBROWSER_DELETEDIALOG_HEADER;确认删除 +FILEBROWSER_DELETEDIALOG_ALL;你确定要永久删除%1个垃圾桶中的文件吗? +FILEBROWSER_DELETEDIALOG_HEADER;删除确认 +FILEBROWSER_DELETEDIALOG_SELECTED;你希望永久删除%1个被选中的文件吗? +FILEBROWSER_DELETEDIALOG_SELECTEDINCLPROC;你希望永久删除%1个被选中的文件, 包括已进行过队列处理的版本吗? FILEBROWSER_EMPTYTRASH;清空垃圾箱 -FILEBROWSER_EXTPROGMENU;调用程序... +FILEBROWSER_EMPTYTRASHHINT;永久删除垃圾桶的所有文件 +FILEBROWSER_EXTPROGMENU;打开方式 FILEBROWSER_FLATFIELD;平场 FILEBROWSER_MOVETODARKFDIR;移动到暗场路径 FILEBROWSER_MOVETOFLATFIELDDIR;移动到平场路径 FILEBROWSER_NEW_NAME;新名称: -FILEBROWSER_OPENDEFAULTVIEWER;Windows 默认阅览工具 (序列) +FILEBROWSER_OPENDEFAULTVIEWER;Windows 默认阅览工具 (队列) FILEBROWSER_PARTIALPASTEPROFILE;选择性粘贴 -FILEBROWSER_PASTEPROFILE;粘贴配置 +FILEBROWSER_PASTEPROFILE;粘贴 FILEBROWSER_POPUPCANCELJOB;取消任务 -FILEBROWSER_POPUPCOLORLABEL;彩色标帖 -FILEBROWSER_POPUPCOLORLABEL0;Label: 无 -FILEBROWSER_POPUPCOLORLABEL1;Label: 红 -FILEBROWSER_POPUPCOLORLABEL2;Label: 黄 -FILEBROWSER_POPUPCOLORLABEL3;Label: 绿 -FILEBROWSER_POPUPCOLORLABEL4;Label: 蓝 -FILEBROWSER_POPUPCOLORLABEL5;Label: 紫 +FILEBROWSER_POPUPCOLORLABEL;色彩标签 +FILEBROWSER_POPUPCOLORLABEL0;标签:无 +FILEBROWSER_POPUPCOLORLABEL1;标签:红 +FILEBROWSER_POPUPCOLORLABEL2;标签:黄 +FILEBROWSER_POPUPCOLORLABEL3;标签:绿 +FILEBROWSER_POPUPCOLORLABEL4;标签:蓝 +FILEBROWSER_POPUPCOLORLABEL5;标签:紫 FILEBROWSER_POPUPCOPYTO;复制至... FILEBROWSER_POPUPFILEOPERATIONS;文件操作 FILEBROWSER_POPUPMOVEEND;移动到队列尾部 FILEBROWSER_POPUPMOVEHEAD;移动到队列头部 FILEBROWSER_POPUPMOVETO;移动至... FILEBROWSER_POPUPOPEN;打开 -FILEBROWSER_POPUPOPENINEDITOR;打开在编辑器 +FILEBROWSER_POPUPOPENINEDITOR;在编辑器中打开 FILEBROWSER_POPUPPROCESS;放入队列 -FILEBROWSER_POPUPPROCESSFAST;放入序列(快速导出) -FILEBROWSER_POPUPPROFILEOPERATIONS;处理色彩档案 -FILEBROWSER_POPUPRANK;评分 -FILEBROWSER_POPUPRANK0;去评分 -FILEBROWSER_POPUPRANK1;评 1 星 -FILEBROWSER_POPUPRANK2;评 2 星 -FILEBROWSER_POPUPRANK3;评 3 星 -FILEBROWSER_POPUPRANK4;评 4 星 -FILEBROWSER_POPUPRANK5;评 5 星 +FILEBROWSER_POPUPPROCESSFAST;放入队列(快速导出) +FILEBROWSER_POPUPPROFILEOPERATIONS;后期档案操作 +FILEBROWSER_POPUPRANK;评级 +FILEBROWSER_POPUPRANK0;取消评级 +FILEBROWSER_POPUPRANK1;评1星 +FILEBROWSER_POPUPRANK2;评2星 +FILEBROWSER_POPUPRANK3;评3星 +FILEBROWSER_POPUPRANK4;评4星 +FILEBROWSER_POPUPRANK5;评5星 +FILEBROWSER_POPUPREMOVE;永久删除 +FILEBROWSER_POPUPREMOVEINCLPROC;永久删除,包括队列处理的版本 FILEBROWSER_POPUPRENAME;重命名 FILEBROWSER_POPUPSELECTALL;全部选中 FILEBROWSER_POPUPTRASH;移动到垃圾箱 FILEBROWSER_POPUPUNRANK;取消星级 FILEBROWSER_POPUPUNTRASH;从垃圾箱中移除 -FILEBROWSER_QUERYBUTTONHINT;清除搜索序列 +FILEBROWSER_QUERYBUTTONHINT;清除搜索队列 +FILEBROWSER_QUERYHINT;输入文件名进行搜索。支持不完整文件名。使用英文逗号分割关键词,例:\n1001,1004,1199\n\n在关键词前面加入!=以排除此关键词,例:\n!=1001,1004,1199\n\n快捷键:\nCtrl-f-让搜索框获得焦点,\nEnter-搜索,\nEsc-清空搜索框,\nShift-Esc-让搜索框失去焦点。 FILEBROWSER_QUERYLABEL; 查找: -FILEBROWSER_RANK1_TOOLTIP;评分 1 *\n快捷键:Shift-1 -FILEBROWSER_RANK2_TOOLTIP;评分 2 *\n快捷键:Shift-2 -FILEBROWSER_RANK3_TOOLTIP;评分 3 *\n快捷键:Shift-3 -FILEBROWSER_RANK4_TOOLTIP;评分 4 *\n快捷键:Shift-4 -FILEBROWSER_RANK5_TOOLTIP;评分 5 *\n快捷键:Shift-5 +FILEBROWSER_RANK1_TOOLTIP;评1星\n快捷键:Shift-1 +FILEBROWSER_RANK2_TOOLTIP;评2星\n快捷键:Shift-2 +FILEBROWSER_RANK3_TOOLTIP;评3星\n快捷键:Shift-3 +FILEBROWSER_RANK4_TOOLTIP;评4星\n快捷键:Shift-4 +FILEBROWSER_RANK5_TOOLTIP;评5星\n快捷键:Shift-5 FILEBROWSER_RENAMEDLGLABEL;文件重命名 FILEBROWSER_RESETDEFAULTPROFILE;还原到默认 -FILEBROWSER_SELECTDARKFRAME;选择暗场... -FILEBROWSER_SELECTFLATFIELD;选择平场…… +FILEBROWSER_SELECTDARKFRAME;选择暗场… +FILEBROWSER_SELECTFLATFIELD;选择平场… +FILEBROWSER_SHOWCOLORLABEL1HINT;显示被标记为红色的照片\n快捷键:Alt-1 +FILEBROWSER_SHOWCOLORLABEL2HINT;显示被标记为黄色的照片\n快捷键:Alt-2 +FILEBROWSER_SHOWCOLORLABEL3HINT;显示被标记为绿色的照片\n快捷键:Alt-3 +FILEBROWSER_SHOWCOLORLABEL4HINT;显示被标记为蓝色的照片\n快捷键:Alt-4 +FILEBROWSER_SHOWCOLORLABEL5HINT;显示被标记为紫色的照片\n快捷键:Alt-5 FILEBROWSER_SHOWDIRHINT;显示文件夹中所有图片 -FILEBROWSER_SHOWEXIFINFO;显示Exif 信息\n\n快捷:\ni - 多编辑标签页模式, \nAlt-i - 单编辑标签模式 +FILEBROWSER_SHOWEDITEDHINT;显示已编辑的照片\n快捷键:7 +FILEBROWSER_SHOWEDITEDNOTHINT;显示未编辑的照片\n快捷键:6 +FILEBROWSER_SHOWEXIFINFO;显示Exif信息\n\n快捷键:\ni - 多编辑标签页模式, \nAlt-i - 单编辑标签模式 +FILEBROWSER_SHOWNOTTRASHHINT;仅显示未进入垃圾箱的照片 FILEBROWSER_SHOWRANK1HINT;显示1星图片 FILEBROWSER_SHOWRANK2HINT;显示2星图片 FILEBROWSER_SHOWRANK3HINT;显示3星图片 FILEBROWSER_SHOWRANK4HINT;显示4星图片 FILEBROWSER_SHOWRANK5HINT;显示5星图片 -FILEBROWSER_SHOWRECENTLYSAVEDHINT;显示保存的图片\n快捷: Alt-7 +FILEBROWSER_SHOWRECENTLYSAVEDHINT;显示保存的图片\n快捷键: Alt-7 +FILEBROWSER_SHOWRECENTLYSAVEDNOTHINT;显示未保存的图片\n快捷键:Alt-6 FILEBROWSER_SHOWTRASHHINT;显示垃圾箱内容 +FILEBROWSER_SHOWUNCOLORHINT;显示没有颜色标记的照片\n快捷键:Alt-0 FILEBROWSER_SHOWUNRANKHINT;显示未评星图片 FILEBROWSER_THUMBSIZE;缩略图大小 +FILEBROWSER_UNRANK_TOOLTIP;未评级\n快捷键:Shift-0 FILEBROWSER_ZOOMINHINT;增大缩略图 -FILEBROWSER_ZOOMOUTHINT;减小缩略图 +FILEBROWSER_ZOOMOUTHINT;缩小缩略图 FILECHOOSER_FILTER_ANY;所有文件 FILECHOOSER_FILTER_COLPROF;色彩配置文件 FILECHOOSER_FILTER_CURVE;曲线文件 @@ -167,18 +214,20 @@ FILECHOOSER_FILTER_PP;处理预设文件 FILECHOOSER_FILTER_SAME;与当前照片格式相同 FILECHOOSER_FILTER_TIFF;TIFF 文件 GENERAL_ABOUT;关于 -GENERAL_AFTER;之后 +GENERAL_AFTER;处理后 GENERAL_APPLY;应用 GENERAL_ASIMAGE;跟随图像 GENERAL_AUTO;自动 -GENERAL_BEFORE;之前 +GENERAL_BEFORE;处理前 GENERAL_CANCEL;取消 GENERAL_CLOSE;关闭 +GENERAL_CURRENT;当前 GENERAL_DISABLE;禁用 GENERAL_DISABLED;禁用 GENERAL_ENABLE;启用 GENERAL_ENABLED;开启 GENERAL_FILE;文件 +GENERAL_HELP;帮助 GENERAL_LANDSCAPE;横向 GENERAL_NA;不适用 GENERAL_NO;否 @@ -186,137 +235,291 @@ GENERAL_NONE;无 GENERAL_OK;确定 GENERAL_OPEN;打开 GENERAL_PORTRAIT;纵向 +GENERAL_RESET;重置 GENERAL_SAVE;保存 -GENERAL_UNCHANGED;(未改变) +GENERAL_SLIDER;滑条 +GENERAL_UNCHANGED;(不改变) GENERAL_WARNING;警告 +GIMP_PLUGIN_INFO;欢迎使用RawTherapee的GIMP插件!\n当你完成编辑后,关闭RawTherapee主窗口,图片就会被自动导入到GIMP中。 HISTOGRAM_TOOLTIP_B;显示/隐藏 蓝色直方图 +HISTOGRAM_TOOLTIP_BAR;显示/隐藏RGB指示条。 +HISTOGRAM_TOOLTIP_CHRO;显示/隐藏色度直方图。 HISTOGRAM_TOOLTIP_G;显示/隐藏 绿色直方图 HISTOGRAM_TOOLTIP_L;显示/隐藏 CIELAB 亮度直方图 HISTOGRAM_TOOLTIP_R;显示/隐藏 红色直方图 +HISTOGRAM_TOOLTIP_RAW;显示/隐藏Raw直方图。 HISTORY_CHANGED;已更改 HISTORY_CUSTOMCURVE;自定义曲线 HISTORY_FROMCLIPBOARD;从剪贴板 HISTORY_LABEL;历史 -HISTORY_MSG_1;图片加载完 -HISTORY_MSG_2;配置加载完 +HISTORY_MSG_1;图片加载完成 +HISTORY_MSG_2;配置加载完成 HISTORY_MSG_3;配置改变 HISTORY_MSG_4;历史浏览 -HISTORY_MSG_5;亮度 -HISTORY_MSG_6;对比度 -HISTORY_MSG_7;黑点 -HISTORY_MSG_8;曝光补偿 -HISTORY_MSG_9;高光压缩 -HISTORY_MSG_10;阴影压缩 -HISTORY_MSG_11;影调曲线 -HISTORY_MSG_12;自动曝光 -HISTORY_MSG_13;曝光溢出 -HISTORY_MSG_14;亮度亮度 -HISTORY_MSG_15;亮度对比度 -HISTORY_MSG_16;亮度黑 +HISTORY_MSG_5;曝光-光亮度 +HISTORY_MSG_6;曝光-对比度 +HISTORY_MSG_7;曝光-暗部 +HISTORY_MSG_8;曝光-曝光补偿 +HISTORY_MSG_9;曝光-高光压缩 +HISTORY_MSG_10;曝光-阴影压缩 +HISTORY_MSG_11;曝光-色调曲线1 +HISTORY_MSG_12;曝光-自动曝光 +HISTORY_MSG_13;曝光-溢出 +HISTORY_MSG_14;L*a*b*-明度 +HISTORY_MSG_15;L*a*b*-对比度 +HISTORY_MSG_16;L*a*b*-黑 HISTORY_MSG_17;亮度高光压缩 HISTORY_MSG_18;亮度阴影压缩 -HISTORY_MSG_19;亮度曲线 +HISTORY_MSG_19;L*a*b*-L*曲线 HISTORY_MSG_20;锐化 -HISTORY_MSG_21;锐化半径 -HISTORY_MSG_22;锐化程度 -HISTORY_MSG_23;锐化阈值 -HISTORY_MSG_24;仅锐化边缘 -HISTORY_MSG_25;锐化边缘半径 -HISTORY_MSG_26;锐化边缘容差 -HISTORY_MSG_27;锐化光晕控制 -HISTORY_MSG_28;光晕控制量 -HISTORY_MSG_29;锐化方式 -HISTORY_MSG_30;重叠半径 -HISTORY_MSG_31;重叠程度 -HISTORY_MSG_32;重叠衰减 -HISTORY_MSG_33;重叠次数 -HISTORY_MSG_34;避免色彩溢出 -HISTORY_MSG_35;饱和度限制器 -HISTORY_MSG_36;饱和度限制 -HISTORY_MSG_37;色彩增强 -HISTORY_MSG_38;拍平衡方式 -HISTORY_MSG_39;色温 -HISTORY_MSG_40;白平衡微调 -HISTORY_MSG_41;色彩偏移 "A" -HISTORY_MSG_42;色彩偏移 "B" -HISTORY_MSG_43;亮度降噪 -HISTORY_MSG_44;亮度降噪半径 -HISTORY_MSG_45;亮度降噪边缘容差 -HISTORY_MSG_46;色彩降噪 -HISTORY_MSG_47;色彩降噪半径 -HISTORY_MSG_48;色彩降噪边缘容差 -HISTORY_MSG_49;色彩降噪边缘敏感度 +HISTORY_MSG_21;USM锐化-半径 +HISTORY_MSG_22;USM锐化-数量 +HISTORY_MSG_23;USM锐化-阈值 +HISTORY_MSG_24;USM锐化-仅锐化边缘 +HISTORY_MSG_25;USM锐化-边缘检测半径 +HISTORY_MSG_26;USM锐化-边缘容差 +HISTORY_MSG_27;USM锐化-光晕控制 +HISTORY_MSG_28;USM锐化-光晕控制数量 +HISTORY_MSG_29;锐化-方式 +HISTORY_MSG_30;RLD-半径 +HISTORY_MSG_31;RLD-数量 +HISTORY_MSG_32;RLD-衰减 +HISTORY_MSG_33;RLD-迭代 +HISTORY_MSG_34;镜头矫正-畸变 +HISTORY_MSG_35;镜头矫正-暗角 +HISTORY_MSG_36;镜头矫正-色差 +HISTORY_MSG_37;曝光-自动曝光 +HISTORY_MSG_38;白平衡-方式 +HISTORY_MSG_39;白平衡-色温 +HISTORY_MSG_40;白平衡-色相 +HISTORY_MSG_41;曝光-色调曲线1模式 +HISTORY_MSG_42;曝光-色调曲线2 +HISTORY_MSG_43;曝光-色调曲线2模式 +HISTORY_MSG_44;亮度噪点降低 半径 +HISTORY_MSG_45;亮度噪点降低 边缘容差 +HISTORY_MSG_46;色度降噪 +HISTORY_MSG_47;色度降噪半径 +HISTORY_MSG_48;色度降噪边缘容差 +HISTORY_MSG_49;色度降噪边缘敏感度 HISTORY_MSG_50;阴影/高光工具 -HISTORY_MSG_51;高光增强 -HISTORY_MSG_52;阴影增强 -HISTORY_MSG_53;高光色度范围 -HISTORY_MSG_54;阴影色度范围 -HISTORY_MSG_55;局部对比度 -HISTORY_MSG_56;阴影/高光半径 +HISTORY_MSG_51;阴影/高光-高光增强 +HISTORY_MSG_52;阴影/高光-阴影增强 +HISTORY_MSG_53;阴影/高光-高光色调宽度 +HISTORY_MSG_54;阴影/高光-阴影色调宽度 +HISTORY_MSG_55;阴影/高光-局部对比度 +HISTORY_MSG_56;阴影/高光-半径 HISTORY_MSG_57;粗略旋转 HISTORY_MSG_58;水平翻转 -HISTORY_MSG_59;竖直翻转 +HISTORY_MSG_59;垂直翻转 HISTORY_MSG_60;旋转 -HISTORY_MSG_61;旋转 -HISTORY_MSG_62;镜头失真矫正 -HISTORY_MSG_63;设置书签 -HISTORY_MSG_64;剪切图片 -HISTORY_MSG_65;色散矫正 -HISTORY_MSG_66;高光还原 -HISTORY_MSG_67;高光还原程度 -HISTORY_MSG_68;高光还原方式 +HISTORY_MSG_61;自动填充 +HISTORY_MSG_62;镜头畸变矫正 +HISTORY_MSG_63;选择快照 +HISTORY_MSG_64;裁切 +HISTORY_MSG_65;色差矫正 +HISTORY_MSG_66;曝光-高光还原 +HISTORY_MSG_67;曝光-高光还原数量 +HISTORY_MSG_68;曝光-高光还原方式 HISTORY_MSG_69;工作色彩空间 HISTORY_MSG_70;输出色彩空间 HISTORY_MSG_71;输入色彩空间 HISTORY_MSG_72;暗角矫正 HISTORY_MSG_73;通道混合器 -HISTORY_MSG_74;调整大小比例 -HISTORY_MSG_75;调整大小方式 +HISTORY_MSG_74;调整大小-比例 +HISTORY_MSG_75;调整大小-方式 HISTORY_MSG_76;Exif元数据 HISTORY_MSG_77;IPTC元数据 HISTORY_MSG_78;调整大小数据 -HISTORY_MSG_79;调整宽度 -HISTORY_MSG_80;调整高度 -HISTORY_MSG_81;调整尺寸开启 -HISTORY_MSG_83;S/H - 锐度蒙板 +HISTORY_MSG_79;调整大小-宽度 +HISTORY_MSG_80;调整大小-高度 +HISTORY_MSG_81;调整大小 +HISTORY_MSG_82;档案修改 +HISTORY_MSG_83;阴影/高光-锐度蒙板 HISTORY_MSG_84;视角矫正 -HISTORY_MSG_85;LCP +HISTORY_MSG_85;镜头矫正-LCP档案 +HISTORY_MSG_86;RGB曲线-色度模式 +HISTORY_MSG_87;脉冲噪声降低 +HISTORY_MSG_88;脉冲降噪阈值 HISTORY_MSG_89;降噪 -HISTORY_MSG_90;降噪 - 亮度 -HISTORY_MSG_92;降噪 - 伽马 -HISTORY_MSG_103;HSV - 数值 -HISTORY_MSG_111;Lab - 避免色彩偏移 -HISTORY_MSG_113;Lab - 保护 +HISTORY_MSG_90;降噪-亮度 +HISTORY_MSG_92;降噪-伽马 +HISTORY_MSG_95;L*a*b*-色度 +HISTORY_MSG_96;L*a*b*-a* 曲线 +HISTORY_MSG_97;L*a*b*-b* 曲线 +HISTORY_MSG_98;去马赛克方法 +HISTORY_MSG_99;热像素过滤器 +HISTORY_MSG_100;曝光-饱和度 +HISTORY_MSG_101;HSV-色度(Hue) +HISTORY_MSG_102;HSV-饱和度(Saturation) +HISTORY_MSG_103;HSV-数值 +HISTORY_MSG_104;HSV均衡器 +HISTORY_MSG_105;去色彩边缘 +HISTORY_MSG_106;去边-半径 +HISTORY_MSG_107;去边-阈值 +HISTORY_MSG_109;调整大小-边界限制方块 +HISTORY_MSG_110;调整大小-应用到 +HISTORY_MSG_111;Lab-避免色彩偏移 +HISTORY_MSG_113;Lab-保护 HISTORY_MSG_114;DCB 迭代 -HISTORY_MSG_119;线性消噪 -HISTORY_MSG_122;自动暗幅 -HISTORY_MSG_123;暗幅文件 +HISTORY_MSG_115;伪色抑制 +HISTORY_MSG_116;DCB增强 +HISTORY_MSG_117;Raw色差修正-红 +HISTORY_MSG_118;Raw色差修正-蓝 +HISTORY_MSG_119;线状噪点过滤器 +HISTORY_MSG_120;绿平衡 +HISTORY_MSG_121;Raw色差修正-自动 +HISTORY_MSG_122;自动暗场 +HISTORY_MSG_123;暗场文件 HISTORY_MSG_124;线性曝光修正 HISTORY_MSG_126;平场文件 HISTORY_MSG_127;平场自动选择 HISTORY_MSG_128;平场模糊半径 HISTORY_MSG_129;平场模糊类型 HISTORY_MSG_130;自动扭曲纠正 +HISTORY_MSG_131;降噪-亮度 +HISTORY_MSG_132;降噪-色度 +HISTORY_MSG_144;微反差-数量 +HISTORY_MSG_145;微反差-均匀度 HISTORY_MSG_146;边缘锐化 -HISTORY_MSG_147;边缘锐化 - 单纯亮度 -HISTORY_MSG_155;Vib - 避免色彩偏移 +HISTORY_MSG_147;边缘锐化-单纯亮度 +HISTORY_MSG_148;微反差 +HISTORY_MSG_149;微反差-3×3阵列 +HISTORY_MSG_155;Vib-避免色彩偏移 HISTORY_MSG_158;力度 HISTORY_MSG_159;边缘停止 HISTORY_MSG_160;拉伸 HISTORY_MSG_162;色调映射 +HISTORY_MSG_163;RGB曲线-红 +HISTORY_MSG_164;RGB曲线-绿 +HISTORY_MSG_165;RGB曲线-蓝 +HISTORY_MSG_166;曝光-重置 +HISTORY_MSG_167;去马赛克方法 +HISTORY_MSG_168;L*a*b*-CC曲线 +HISTORY_MSG_169;L*a*b*-CH曲线 +HISTORY_MSG_171;L*a*b*-LC曲线 +HISTORY_MSG_172;L*a*b*-限制LC +HISTORY_MSG_173;降噪-细节恢复 HISTORY_MSG_174;CIECAM02 -HISTORY_MSG_183;CAM02 - 对比度 (J) -HISTORY_MSG_210;渐变 - 角度 +HISTORY_MSG_180;CAM02-亮度 (J) +HISTORY_MSG_181;CAM02-色度 (C) +HISTORY_MSG_183;CAM02-对比度 (J) +HISTORY_MSG_186;CAM02-算法 +HISTORY_MSG_187;CAM02-红色/肤色保护 +HISTORY_MSG_188;CAM02-亮度 (Q) +HISTORY_MSG_189;CAM02-对比度 (Q) +HISTORY_MSG_190;CAM02-饱和度 (S) +HISTORY_MSG_191;CAM02-色彩丰富度 (M) +HISTORY_MSG_192;CAM02-色度 (h) +HISTORY_MSG_193;CAM02-色调曲线1 +HISTORY_MSG_194;CAM02-色调曲线2 +HISTORY_MSG_195;CAM02-色调曲线1 +HISTORY_MSG_196;CAM02-色调曲线2 +HISTORY_MSG_200;CAM02-色调映射 +HISTORY_MSG_203;降噪-色彩空间 +HISTORY_MSG_204;LMMSE优化步长 +HISTORY_MSG_205;CAM02-热像素/坏点过滤器 +HISTORY_MSG_207;去边-色度曲线 +HISTORY_MSG_210;渐变-角度 HISTORY_MSG_211;渐变滤镜 -HISTORY_MSG_212;暗角 - 力度 +HISTORY_MSG_212;暗角-力度 HISTORY_MSG_213;暗角滤镜 -HISTORY_MSG_239;GF - 力度 -HISTORY_MSG_244;VC - 力度 -HISTORY_MSG_245;VC - 中心 +HISTORY_MSG_239;GF-力度 +HISTORY_MSG_244;暗角矫正-力度 +HISTORY_MSG_245;暗角矫正-中心 +HISTORY_MSG_246;L*a*b*-CL曲线 +HISTORY_MSG_247;L*a*b*-LH曲线 +HISTORY_MSG_248;L*a*b*-HH曲线 +HISTORY_MSG_255;降噪-中值滤波器 +HISTORY_MSG_256;降噪-中值滤波器-方法 +HISTORY_MSG_285;降噪-中值滤波-方法 +HISTORY_MSG_286;降噪-中值滤波-类型 +HISTORY_MSG_287;降噪-中值滤波-迭代 +HISTORY_MSG_288;平场-溢出控制 +HISTORY_MSG_289;平场-溢出控制-自动 +HISTORY_MSG_293;胶片模拟 +HISTORY_MSG_294;胶片模拟-力度 +HISTORY_MSG_295;胶片模拟-胶片 +HISTORY_MSG_296;降噪-亮度曲线 +HISTORY_MSG_297;降噪-模式 +HISTORY_MSG_298;坏点过滤器 +HISTORY_MSG_299;降噪-色度曲线 +HISTORY_MSG_305;小波层级 +HISTORY_MSG_371;调整大小后加锐(PRS) +HISTORY_MSG_372;PRS USM-半径 +HISTORY_MSG_373;PRS USM-数量 +HISTORY_MSG_374;PRS USM-阈值 +HISTORY_MSG_375;PRS USM-仅加锐边缘 +HISTORY_MSG_376;PRS USM-边缘检测半径 +HISTORY_MSG_377;PRS USM-Edge tolerance +HISTORY_MSG_378;PRS USM-光晕控制 +HISTORY_MSG_379;PRS USM-光晕控制数量 +HISTORY_MSG_380;PRS-方法 +HISTORY_MSG_381;PRS RLD-半径 +HISTORY_MSG_382;PRS RLD-数量 +HISTORY_MSG_383;PRS RLD-衰减 +HISTORY_MSG_384;PRS RLD-迭代 +HISTORY_MSG_445;Raw子图像 +HISTORY_MSG_449;像素偏移-ISO适应 +HISTORY_MSG_452;像素偏移-显示动体 +HISTORY_MSG_453;像素偏移-仅显示动体蒙版 +HISTORY_MSG_457;像素偏移-检测红/蓝 +HISTORY_MSG_462;像素偏移-检测绿 +HISTORY_MSG_464;像素偏移-动体蒙版模糊 +HISTORY_MSG_465;像素偏移-模糊半径 +HISTORY_MSG_468;像素偏移-填洞 +HISTORY_MSG_469;像素偏移-中值 +HISTORY_MSG_471;像素偏移-动体补正 +HISTORY_MSG_472;像素偏移-顺滑过渡 +HISTORY_MSG_473;像素偏移-使用LMMSE +HISTORY_MSG_474;像素偏移-亮度均等 +HISTORY_MSG_475;像素偏移-均等各通道 +HISTORY_MSG_485;镜头矫正 +HISTORY_MSG_486;镜头矫正-相机 +HISTORY_MSG_487;镜头矫正-镜头 +HISTORY_MSG_488;动态范围压缩(DRC) +HISTORY_MSG_491;白平衡 +HISTORY_MSG_492;RGB曲线 +HISTORY_MSG_493;L*a*b*调整 +HISTORY_MSG_494;捕图锐化 +HISTORY_MSG_DEHAZE_ENABLED;去雾 +HISTORY_MSG_DEHAZE_STRENGTH;去雾-力度 +HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;双重去马赛克-自动阈值 +HISTORY_MSG_DUALDEMOSAIC_CONTRAST;双重去马赛克-对比度阈值 +HISTORY_MSG_FILMNEGATIVE_ENABLED;胶片负片 +HISTORY_MSG_HISTMATCHING;自适应色调曲线 +HISTORY_MSG_LOCALCONTRAST_AMOUNT;局部反差-数量 +HISTORY_MSG_LOCALCONTRAST_DARKNESS;局部反差-黑处 +HISTORY_MSG_LOCALCONTRAST_ENABLED;局部反差 +HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;局部反差-亮处 +HISTORY_MSG_LOCALCONTRAST_RADIUS;局部反差-半径 +HISTORY_MSG_METADATA_MODE;元数据复制模式 +HISTORY_MSG_MICROCONTRAST_CONTRAST;微反差-反差阈值 +HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;捕图锐化-自动阈值 +HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;捕图锐化-自动半径 +HISTORY_MSG_PDSHARPEN_CHECKITER;捕图锐化-自动限制迭代 +HISTORY_MSG_PDSHARPEN_CONTRAST;捕图锐化-反差阈值 +HISTORY_MSG_PDSHARPEN_ITERATIONS;捕图锐化-迭代 +HISTORY_MSG_PDSHARPEN_RADIUS;捕图锐化-半径 +HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;捕图锐化-边缘半径值提升 +HISTORY_MSG_PIXELSHIFT_DEMOSAIC;像素偏移-动体部分去马赛克算法 +HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;线状噪点过滤方向 +HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAF条纹过滤 +HISTORY_MSG_PRSHARPEN_CONTRAST;PRS-反差阈值 +HISTORY_MSG_RAWCACORR_AUTOIT;Raw色差矫正-迭代 +HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw色差矫正-避免色偏 +HISTORY_MSG_RAW_BORDER;Raw边界 +HISTORY_MSG_RESIZE_ALLOWUPSCALING;调整大小-允许升采样 +HISTORY_MSG_SHARPENING_BLUR;加锐-模糊半径 +HISTORY_MSG_SHARPENING_CONTRAST;加锐-反差阈值 +HISTORY_MSG_SH_COLORSPACE;阴影/高光-色彩空间 HISTORY_NEWSNAPSHOT;新建快照 HISTORY_NEWSNAPSHOT_TOOLTIP;快捷键:Alt-s HISTORY_SNAPSHOT;快照 -HISTORY_SNAPSHOTS;系列快照 +HISTORY_SNAPSHOTS;快照 +ICCPROFCREATOR_COPYRIGHT;版权: +ICCPROFCREATOR_CUSTOM;自定义 +ICCPROFCREATOR_DESCRIPTION;描述: +ICCPROFCREATOR_SAVEDIALOG_TITLE;将ICC档案保存为…… IPTCPANEL_CATEGORY;类别 IPTCPANEL_CITY;城市 IPTCPANEL_COPYHINT;将IPTC设置复制到剪贴板 @@ -334,9 +537,9 @@ IPTCPANEL_RESET;重置 IPTCPANEL_RESETHINT;重置为默认配置 IPTCPANEL_SOURCE;来源 IPTCPANEL_TITLE;标题 -MAIN_BUTTON_FULLSCREEN;全屏幕 +MAIN_BUTTON_FULLSCREEN;全屏 MAIN_BUTTON_PREFERENCES;参数设置 -MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;将当前图片放入处理序列中\n快捷键: Ctrl+b +MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;将当前图片放入处理队列中\n快捷键: Ctrl+b MAIN_BUTTON_SAVE;保存图片 MAIN_BUTTON_SAVE_TOOLTIP;保存当前图像 \n快捷键:Ctrl+S MAIN_BUTTON_SENDTOEDITOR;发送到编辑器 @@ -345,22 +548,25 @@ MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP;显示/隐藏全部侧边栏\n快捷键: MAIN_BUTTON_UNFULLSCREEN;退出全屏 MAIN_FRAME_EDITOR;编辑器 MAIN_FRAME_EDITOR_TOOLTIP;编辑器.\n快捷键: Ctrl-F4 -MAIN_FRAME_FILEBROWSER;文件浏览 -MAIN_FRAME_FILEBROWSER_TOOLTIP;文件浏览\n快捷键: Ctrl-F2 +MAIN_FRAME_FILEBROWSER;文件浏览器 +MAIN_FRAME_FILEBROWSER_TOOLTIP;文件浏览器\n快捷键: Ctrl-F2 MAIN_FRAME_PLACES;位置 MAIN_FRAME_PLACES_ADD;添加 +MAIN_FRAME_PLACES_DEL;移除 MAIN_FRAME_QUEUE;批处理队列 -MAIN_FRAME_QUEUE_TOOLTIP;处理序列\n快捷键: Ctrl-F3 +MAIN_FRAME_QUEUE_TOOLTIP;处理队列\n快捷键: Ctrl-F3 MAIN_FRAME_RECENT;最近使用的文件夹 MAIN_MSG_ALREADYEXISTS;该文件已存在 MAIN_MSG_CANNOTLOAD;无法加载图片 MAIN_MSG_CANNOTSAVE;文件保存中出错 MAIN_MSG_CANNOTSTARTEDITOR;无法启动编辑器 -MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;请在“首选项“对话框设置正确的路径 +MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY;请在“参数设置“中设置正确的路径 MAIN_MSG_EMPTYFILENAME;未指定文件名! -MAIN_MSG_NAVIGATOR;浏览器 +MAIN_MSG_NAVIGATOR;导航器 MAIN_MSG_OPERATIONCANCELLED;取消 MAIN_MSG_QOVERWRITE;是否覆盖? +MAIN_TAB_ADVANCED;高级 +MAIN_TAB_ADVANCED_TOOLTIP;快捷键:Alt-a MAIN_TAB_COLOR;色彩 MAIN_TAB_COLOR_TOOLTIP;快捷键:Alt-c MAIN_TAB_DETAIL;细节 @@ -370,6 +576,7 @@ MAIN_TAB_EXIF;Exif MAIN_TAB_EXPORT; 快速导出 MAIN_TAB_EXPOSURE;曝光 MAIN_TAB_EXPOSURE_TOOLTIP;快捷键:Alt-e +MAIN_TAB_FAVORITES_TOOLTIP;快捷键: Alt-u MAIN_TAB_FILTER;过滤器 MAIN_TAB_INSPECT; 检阅 MAIN_TAB_IPTC;IPTC @@ -382,13 +589,19 @@ MAIN_TAB_TRANSFORM_TOOLTIP;快捷键:Alt-t MAIN_TOOLTIP_HIDEHP;显示/隐藏左面板 (包含历史, 快捷键: H) MAIN_TOOLTIP_INDCLIPPEDH;高光溢出提示 MAIN_TOOLTIP_INDCLIPPEDS;阴影不足提示 -MAIN_TOOLTIP_PREVIEWR;预览 红色通道.\n快捷键: r +MAIN_TOOLTIP_PREVIEWB;预览蓝色通道\n快捷键:b +MAIN_TOOLTIP_PREVIEWFOCUSMASK;预览合焦蒙版\n快捷键:Shift-f\n\n在浅景深,噪点少,放大得大的图片中更加精准\n在噪点多的图像中,把图片缩放到10%-30%以提升检测精准度。 +MAIN_TOOLTIP_PREVIEWG;预览绿色通道\n快捷键:g +MAIN_TOOLTIP_PREVIEWL;预览亮度\n快捷键:v\n\n0.299*R + 0.587*G + 0.114*B +MAIN_TOOLTIP_PREVIEWR;预览红色通道\n快捷键: r +MAIN_TOOLTIP_PREVIEWSHARPMASK;预览加锐反差蒙版\n快捷键:p MAIN_TOOLTIP_QINFO;图片快捷信息 MAIN_TOOLTIP_SHOWHIDELP1;显示/隐藏左面板\n快捷键: l MAIN_TOOLTIP_SHOWHIDERP1;显示/隐藏右面板\n快捷键: Alt-l MAIN_TOOLTIP_SHOWHIDETP1;显示/隐藏上面板\n快捷键: Shift-L MAIN_TOOLTIP_THRESHOLD;阈值 -MAIN_TOOLTIP_TOGGLE;切换 /视图\n快捷键: Shift-b +MAIN_TOOLTIP_TOGGLE;切换 处理前/处理后视图\n快捷键: Shift-b +MONITOR_PROFILE_SYSTEM;系统默认 NAVIGATOR_B;B: NAVIGATOR_G;G: NAVIGATOR_H;H: @@ -401,11 +614,12 @@ NAVIGATOR_S;S: NAVIGATOR_V;V: NAVIGATOR_XY_FULL;宽 = %1, 高 = %2 NAVIGATOR_XY_NA;x = n/a, y = n/a +PARTIALPASTE_ADVANCEDGROUP;高级设置 PARTIALPASTE_BASICGROUP;基本设置 PARTIALPASTE_CACORRECTION;色彩矫正 PARTIALPASTE_CHANNELMIXER;通道混合器 PARTIALPASTE_CHANNELMIXERBW;黑白 -PARTIALPASTE_COARSETRANS;90度旋转/翻转 +PARTIALPASTE_COARSETRANS;90°旋转/翻转 PARTIALPASTE_COLORAPP;CIECAM02 PARTIALPASTE_COLORGROUP;色彩相关设定 PARTIALPASTE_COLORTONING;色调 @@ -415,77 +629,98 @@ PARTIALPASTE_CROP;剪裁 PARTIALPASTE_DARKFRAMEAUTOSELECT;暗场自动选择 PARTIALPASTE_DARKFRAMEFILE;暗场文件 PARTIALPASTE_DEFRINGE;去边 +PARTIALPASTE_DEHAZE;去雾 PARTIALPASTE_DETAILGROUP;细节设置 PARTIALPASTE_DIALOGLABEL;选择性粘贴配置 PARTIALPASTE_DIRPYRDENOISE;降噪 PARTIALPASTE_DIRPYREQUALIZER;分频反差调整 PARTIALPASTE_DISTORTION;畸变矫正 PARTIALPASTE_EPD;色调映射 -PARTIALPASTE_EQUALIZER;小波变换等级 +PARTIALPASTE_EQUALIZER;小波变换层级 PARTIALPASTE_EVERYTHING;全部 PARTIALPASTE_EXIFCHANGES;对exif所做的修改 PARTIALPASTE_EXPOSURE;曝光 +PARTIALPASTE_FILMNEGATIVE;胶片负片 PARTIALPASTE_FILMSIMULATION;胶片模拟 PARTIALPASTE_FLATFIELDAUTOSELECT;平场自动选择 PARTIALPASTE_FLATFIELDBLURRADIUS;平场模糊半径 PARTIALPASTE_FLATFIELDBLURTYPE;平场模糊类型 PARTIALPASTE_FLATFIELDCLIPCONTROL;平场剪切控制 PARTIALPASTE_FLATFIELDFILE;平场文件夹 -PARTIALPASTE_GRADIENT;渐变过滤 -PARTIALPASTE_HSVEQUALIZER;HSV均衡 -PARTIALPASTE_ICMSETTINGS;ICM 设置 +PARTIALPASTE_GRADIENT;渐变滤镜 +PARTIALPASTE_HSVEQUALIZER;HSV均衡器 +PARTIALPASTE_ICMSETTINGS;ICM设置 PARTIALPASTE_IMPULSEDENOISE;脉冲噪声降低 PARTIALPASTE_IPTCINFO;IPTC 信息 PARTIALPASTE_LABCURVE;Lab调整 PARTIALPASTE_LENSGROUP;镜头相关设置 PARTIALPASTE_LENSPROFILE;镜片修正档案 +PARTIALPASTE_LOCALCONTRAST;局部反差 PARTIALPASTE_METAGROUP;元数据 PARTIALPASTE_PCVIGNETTE;暗角滤镜 PARTIALPASTE_PERSPECTIVE;视角 PARTIALPASTE_PREPROCESS_DEADPIXFILT;坏点过滤器 PARTIALPASTE_PREPROCESS_GREENEQUIL;绿平衡 PARTIALPASTE_PREPROCESS_HOTPIXFILT;热噪过滤器 -PARTIALPASTE_PREPROCESS_LINEDENOISE;线条噪点过滤 +PARTIALPASTE_PREPROCESS_LINEDENOISE;线状噪点过滤 +PARTIALPASTE_PREPROCESS_PDAFLINESFILTER;PDAF条带过滤器 PARTIALPASTE_PRSHARPENING;调整大小后锐化 -PARTIALPASTE_RAWCACORR_AUTO;CA自动更正 -PARTIALPASTE_RAWCACORR_CAREDBLUE;红蓝色散 +PARTIALPASTE_RAWCACORR_AUTO;色差自动矫正 +PARTIALPASTE_RAWCACORR_CAREDBLUE;红蓝色差 PARTIALPASTE_RAWEXPOS_BLACK;黑色等级 PARTIALPASTE_RAWEXPOS_LINEAR;白点纠正 PARTIALPASTE_RAWGROUP;Raw设置 -PARTIALPASTE_RAW_DCBENHANCE;DCB 增强 -PARTIALPASTE_RAW_DCBITERATIONS;DCB 反复 -PARTIALPASTE_RAW_DMETHOD;解马赛克方法 +PARTIALPASTE_RAW_BORDER;Raw边界 +PARTIALPASTE_RAW_DCBENHANCE;DCB增强 +PARTIALPASTE_RAW_DCBITERATIONS;DCB迭代 +PARTIALPASTE_RAW_DMETHOD;去马赛克方法 PARTIALPASTE_RAW_FALSECOLOR;摩尔纹抑制 PARTIALPASTE_RAW_IMAGENUM;子图像 -PARTIALPASTE_RAW_LMMSEITERATIONS;LMMSE 增强级数 -PARTIALPASTE_RAW_PIXELSHIFT;像素位移 -PARTIALPASTE_RESIZE;缩放 -PARTIALPASTE_RETINEX;Retinex增强算法 +PARTIALPASTE_RAW_LMMSEITERATIONS;LMMSE优化步长 +PARTIALPASTE_RAW_PIXELSHIFT;像素偏移 +PARTIALPASTE_RESIZE;调整大小 +PARTIALPASTE_RETINEX;Retinex PARTIALPASTE_RGBCURVES;RGB曲线 PARTIALPASTE_ROTATION;旋转 PARTIALPASTE_SHADOWSHIGHLIGHTS;阴影/高光 PARTIALPASTE_SHARPENEDGE;边缘 PARTIALPASTE_SHARPENING;锐化 -PARTIALPASTE_SHARPENMICRO;微处对比 +PARTIALPASTE_SHARPENMICRO;微对比度 +PARTIALPASTE_TM_FATTAL;动态范围压缩 PARTIALPASTE_VIBRANCE;鲜艳度 -PARTIALPASTE_VIGNETTING;暗角修正 +PARTIALPASTE_VIGNETTING;暗角矫正 PARTIALPASTE_WHITEBALANCE;白平衡 PREFERENCES_ADD;添加 -PREFERENCES_APPEARANCE_NAVGUIDECOLOR;导航器引导颜色 +PREFERENCES_APPEARANCE;外观 +PREFERENCES_APPEARANCE_CROPMASKCOLOR;裁剪蒙版颜色 +PREFERENCES_APPEARANCE_MAINFONT;主字体 +PREFERENCES_APPEARANCE_NAVGUIDECOLOR;导航器图框颜色 +PREFERENCES_APPEARANCE_PSEUDOHIDPI;伪-高DPI模式 +PREFERENCES_APPEARANCE_THEME;主题 PREFERENCES_APPLNEXTSTARTUP;下次启动生效 PREFERENCES_AUTOMONPROFILE;使用操作系统主显示器的色彩档案 +PREFERENCES_AUTOSAVE_TP_OPEN;在退出时保存工具的展开/折叠状态 PREFERENCES_BATCH_PROCESSING;批处理 -PREFERENCES_BEHADDALL;全 '添加' +PREFERENCES_BEHADDALL;全 “添加” PREFERENCES_BEHAVIOR;行为 -PREFERENCES_BEHSETALL;全 '设定' +PREFERENCES_BEHSETALL;全“ 设定” +PREFERENCES_BEHSETALLHINT;将所有选项设为设定模式\n批处理栏的处理参数将是a绝对值,数值会被显示。 +PREFERENCES_CACHECLEAR;清空 +PREFERENCES_CACHECLEAR_ALL;清空所有缓存文件: PREFERENCES_CACHEMAXENTRIES;最大缓存数量 PREFERENCES_CACHEOPTS;缓存选项 PREFERENCES_CACHETHUMBHEIGHT;最大缩略图高度 +PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE去马赛克 +PREFERENCES_CHUNKSIZE_RAW_CA;Raw色差矫正 +PREFERENCES_CHUNKSIZE_RAW_RCD;RCD去马赛克 +PREFERENCES_CHUNKSIZE_RGB;RGB处理 PREFERENCES_CLIPPINGIND;高光溢出提示 -PREFERENCES_CLUTSCACHE;HaldCLUT 缓存 -PREFERENCES_CLUTSCACHE_LABEL;CLUTs 最大缓存数 -PREFERENCES_CLUTSDIR;HaldCLUT 路径 +PREFERENCES_CLUTSCACHE;HaldCLUT缓存 +PREFERENCES_CLUTSCACHE_LABEL;CLUT最大缓存数 +PREFERENCES_CLUTSDIR;HaldCLUT路径 PREFERENCES_CMMBPC;黑场补偿 +PREFERENCES_CROP;裁切编辑 +PREFERENCES_CROP_AUTO_FIT;自动放大以适应裁剪 PREFERENCES_CURVEBBOXPOS;曲线复制/粘贴按钮位置 PREFERENCES_CURVEBBOXPOS_ABOVE;上 PREFERENCES_CURVEBBOXPOS_BELOW;下 @@ -502,14 +737,16 @@ PREFERENCES_DARKFRAMETEMPLATES;模板 PREFERENCES_DATEFORMAT;日期格式 PREFERENCES_DATEFORMATHINT;可以使用下列控制符:\n%y : 年\n%m : 月h\n%d : 日\n\n例如, 中文日期格式:\n%y/%m/%d PREFERENCES_DIRDARKFRAMES;暗场图像路径 +PREFERENCES_DIRECTORIES;目录 PREFERENCES_DIRHOME;用户文件路径 PREFERENCES_DIRLAST;上次访问路径 PREFERENCES_DIROTHER;其他 PREFERENCES_DIRSELECTDLG;启动时选择图片路径... PREFERENCES_DIRSOFTWARE;软件安装路径 +PREFERENCES_EDITORCMDLINE;自定义命令行 PREFERENCES_EDITORLAYOUT;编辑器布局 PREFERENCES_EXTERNALEDITOR;外部编辑器 -PREFERENCES_FBROWSEROPTS;文件浏览选项 +PREFERENCES_FBROWSEROPTS;文件浏览器选项 PREFERENCES_FLATFIELDFOUND;找到 PREFERENCES_FLATFIELDSDIR;平场图像路径 PREFERENCES_FLATFIELDSHOTS;张 @@ -519,12 +756,12 @@ PREFERENCES_FORRAW;用于Raw文件 PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT;Same thumbnail height between the Filmstrip and the File Browser PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT_HINT;Having separate thumbnail size will require more processing time each time you'll switch between the single Editor tab and the File Browser. PREFERENCES_GIMPPATH;GIMP安装文件夹 -PREFERENCES_HISTOGRAMPOSITIONLEFT;直方图放置在左面板 -PREFERENCES_HISTOGRAM_TOOLTIP;If enabled, the working profile is used for rendering the main histogram and the Navigator panel, otherwise the gamma-corrected output profile is used. +PREFERENCES_HISTOGRAMPOSITIONLEFT;将直方图放置在左面板 +PREFERENCES_HISTOGRAM_TOOLTIP;启用后,当前使用的后期配置档案将被用于渲染主直方图和导航栏,不启用则将使用伽马矫正的输出档案进行渲染。 PREFERENCES_HLTHRESHOLD;高光溢出阈值 PREFERENCES_ICCDIR;ICC配置路径 PREFERENCES_IMPROCPARAMS;默认图片处理参数 -PREFERENCES_INSPECT_LABEL;检阅 +PREFERENCES_INSPECT_LABEL;查看 PREFERENCES_INSPECT_MAXBUFFERS_LABEL;最大缓存图片数 PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP;Set the maximum number of images stored in cache when hovering over them in the File Browser; systems with little RAM (2GB) should keep this value set to 1 or 2. PREFERENCES_INTENT_ABSOLUTE;绝对比色 @@ -535,72 +772,77 @@ PREFERENCES_INTERNALTHUMBIFUNTOUCHED;如果RAW文件没有修改, 显示内嵌JP PREFERENCES_LANG;语言 PREFERENCES_LANGAUTODETECT;使用系统语言 PREFERENCES_MAXRECENTFOLDERS;最近访问路径历史记录数 -PREFERENCES_MENUGROUPEXTPROGS;Group "Open with" -PREFERENCES_MENUGROUPFILEOPERATIONS;Group "File operations" -PREFERENCES_MENUGROUPLABEL;Group "Color label" -PREFERENCES_MENUGROUPPROFILEOPERATIONS;Group "Processing profile operations" -PREFERENCES_MENUGROUPRANK;组 "评价" -PREFERENCES_MENUOPTIONS;子菜单选项 +PREFERENCES_MENUGROUPEXTPROGS;组合"打开方式" +PREFERENCES_MENUGROUPFILEOPERATIONS;组合"文件操作" +PREFERENCES_MENUGROUPLABEL;组合"色彩标签" +PREFERENCES_MENUGROUPPROFILEOPERATIONS;组合"后期档案操作" +PREFERENCES_MENUGROUPRANK;组合 "评级" +PREFERENCES_MENUOPTIONS;右键子菜单选项 PREFERENCES_MONINTENT;默认渲染意图 PREFERENCES_MONITOR;显示器 PREFERENCES_MONPROFILE;默认色彩配置文件 PREFERENCES_MONPROFILE_WARNOSX;受MacOS限制, 仅支持sRGB PREFERENCES_MULTITAB;多编辑器标签模式 -PREFERENCES_MULTITABDUALMON;多编辑器标签独立模式 +PREFERENCES_MULTITABDUALMON;多编辑器,编辑器标签独立模式 PREFERENCES_NAVIGATIONFRAME;导航器 PREFERENCES_OVERLAY_FILENAMES;Overlay filenames on thumbnails in the file browser PREFERENCES_OVERLAY_FILENAMES_FILMSTRIP;Overlay filenames on thumbnails in the editor pannel PREFERENCES_OVERWRITEOUTPUTFILE;Overwrite existing output files -PREFERENCES_PANFACTORLABEL;Pan rate amplification +PREFERENCES_PANFACTORLABEL;拖移速率增幅 PREFERENCES_PARSEDEXT;已知扩展名 PREFERENCES_PARSEDEXTADD;添加扩展名 PREFERENCES_PARSEDEXTADDHINT;输入扩展名并按此按钮将其添加至列表 PREFERENCES_PARSEDEXTDELHINT;从列表中删除选中的扩展名 -PREFERENCES_PARSEDEXTDOWNHINT;Move selected extension down in the list. -PREFERENCES_PARSEDEXTUPHINT;Move selected extension up in the list. -PREFERENCES_PREVDEMO;预览解马赛克方法 +PREFERENCES_PARSEDEXTDOWNHINT;让选中的插件在列表中的位置下降。 +PREFERENCES_PARSEDEXTUPHINT;让选中的插件在列表中的位置上升。 +PREFERENCES_PERFORMANCE_THREADS;线程 +PREFERENCES_PERFORMANCE_THREADS_LABEL;用于降噪和小波层级的最大线程数(0=自动) +PREFERENCES_PREVDEMO;预览去马赛克方法 PREFERENCES_PREVDEMO_FAST;快速 -PREFERENCES_PREVDEMO_LABEL;小于100%缩放查看时使用的解马赛克算法: +PREFERENCES_PREVDEMO_LABEL;小于100%缩放查看时使用的去马赛克算法: PREFERENCES_PREVDEMO_SIDECAR;与PP3相同 PREFERENCES_PRINTER;打印机 (软打样) PREFERENCES_PROFILEHANDLING;图片处理配置管理 PREFERENCES_PROFILELOADPR;配置文件读取优先级 PREFERENCES_PROFILEPRCACHE;缓存中的配置文件 -PREFERENCES_PROFILEPRFILE;与图片并列存放的配置文件 -PREFERENCES_PROFILESAVEBOTH;Save processing profile both to the cache and next to the input file -PREFERENCES_PROFILESAVECACHE;将配置文件写至缓存 +PREFERENCES_PROFILEPRFILE;图片所在位置的配置文件 +PREFERENCES_PROFILESAVEBOTH;将配置文件存放到缓存和输入图片所在位置 +PREFERENCES_PROFILESAVECACHE;将配置文件存放缓存 PREFERENCES_PROFILESAVEINPUT;将配置文件与图片并列存放 -PREFERENCES_PROFILESAVELOCATION;处理配置文件存储路径 +PREFERENCES_PROFILESAVELOCATION;将配置文件存放到缓存和输入图片所在位置 PREFERENCES_PROFILE_NONE;无 PREFERENCES_PROPERTY;属性 PREFERENCES_PRTINTENT;渲染意图 PREFERENCES_PRTPROFILE;色彩配置文件 PREFERENCES_PSPATH;Adobe Photoshop安装路径 -PREFERENCES_REMEMBERZOOMPAN;记忆缩放和位置 +PREFERENCES_REMEMBERZOOMPAN;记忆图片的缩放和拖动位置 PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Remember the zoom % and pan offset of the current image when opening a new image.\n\nThis option only works in "Single Editor Tab Mode" and when "Demosaicing method used for the preview at <100% zoom" is set to "As in PP3". +PREFERENCES_SAVE_TP_OPEN_NOW;保存工具的展开/折叠状态 PREFERENCES_SELECTLANG;选择语言 PREFERENCES_SERIALIZE_TIFF_READ;TIFF 读取设定 PREFERENCES_SERIALIZE_TIFF_READ_LABEL;连续载入TIFF文件 PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP;开启后可以提高在无压缩TIFF图片文件夹中的缩略图生成速度 -PREFERENCES_SET;设置 +PREFERENCES_SET;设定 PREFERENCES_SHOWBASICEXIF;显示基本Exif信息 PREFERENCES_SHOWDATETIME;显示时间日期 PREFERENCES_SHOWEXPOSURECOMPENSATION;附加曝光补偿 -PREFERENCES_SHOWFILMSTRIPTOOLBAR;显示图像胶片栏 +PREFERENCES_SHOWFILMSTRIPTOOLBAR;显示“数码底片夹”栏 PREFERENCES_SHTHRESHOLD;阴影过暗阈值 -PREFERENCES_SINGLETAB;单编辑器栏模式 -PREFERENCES_SINGLETABVERTAB;单编辑器栏模式, 标签栏垂直 -PREFERENCES_SND_HELP;输入完整路径来指定声音文件, 或者留空表示无声 \nWindows系统声音可以使用 "SystemDefault", "SystemAsterisk" 等 Linux则可以使用 "complete", "window-attention" 等 +PREFERENCES_SINGLETAB;单编辑器模式 +PREFERENCES_SINGLETABVERTAB;单编辑器模式, 标签栏垂直 +PREFERENCES_SND_HELP;输入完整路径来指定声音文件, 或者留空表示无声 \nWindows系统声音可以使用 "SystemDefault", "SystemAsterisk" 等\nLinux则可以使用 "complete", "window-attention" 等 PREFERENCES_SND_LNGEDITPROCDONE;编辑器处理完成 -PREFERENCES_SND_QUEUEDONE;队列处理完成 -PREFERENCES_SND_THRESHOLDSECS;几秒之后 +PREFERENCES_SND_QUEUEDONE;完成队列 +PREFERENCES_SND_THRESHOLDSECS;等待秒数 PREFERENCES_STARTUPIMDIR;启动时路径 PREFERENCES_TAB_BROWSER;文件浏览器 PREFERENCES_TAB_COLORMGR;色彩管理 PREFERENCES_TAB_DYNAMICPROFILE;动态预设规则 -PREFERENCES_TAB_GENERAL;一般 +PREFERENCES_TAB_GENERAL;通用 PREFERENCES_TAB_IMPROC;图片处理 +PREFERENCES_TAB_PERFORMANCE;性能 PREFERENCES_TAB_SOUND;音效 +PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;内嵌JPEG预览 PREFERENCES_TP_LABEL;工具栏 PREFERENCES_TP_VSCROLLBAR;隐藏垂直滚动栏 PREFERENCES_USEBUNDLEDPROFILES;启用内置预设 @@ -616,32 +858,50 @@ PROFILEPANEL_TOOLTIPCOPY;将当前配置复制到剪贴板 PROFILEPANEL_TOOLTIPLOAD;由文件加载配置 PROFILEPANEL_TOOLTIPPASTE;从剪贴板粘贴配置 PROFILEPANEL_TOOLTIPSAVE;保存当前配置 +PROGRESSBAR_GREENEQUIL;绿平衡... +PROGRESSBAR_HLREC;高光还原... +PROGRESSBAR_HOTDEADPIXELFILTER;热像素/坏点过滤器... +PROGRESSBAR_LINEDENOISE;线状噪点过滤器... PROGRESSBAR_LOADING;图片加载中... -PROGRESSBAR_LOADINGTHUMBS;正在读取缩略图…… +PROGRESSBAR_LOADINGTHUMBS;正在读取缩略图... PROGRESSBAR_LOADJPEG;JPEG文件加载中... PROGRESSBAR_LOADPNG;PNG文件加载中... PROGRESSBAR_LOADTIFF;TIFF文件加载中... -PROGRESSBAR_NOIMAGES;没找到图片 +PROGRESSBAR_NOIMAGES;未找到图片 PROGRESSBAR_PROCESSING;图片处理中... +PROGRESSBAR_PROCESSING_PROFILESAVED;处理配置档案已保存 +PROGRESSBAR_RAWCACORR;Raw色差矫正... PROGRESSBAR_READY;就绪 PROGRESSBAR_SAVEJPEG;JPEG文件保存中... PROGRESSBAR_SAVEPNG;PNG文件保存中... PROGRESSBAR_SAVETIFF;TIFF文件保存中... +PROGRESSBAR_SNAPSHOT_ADDED;快照已添加 +QINFO_FRAMECOUNT;%2帧 +QINFO_HDR;HDR / %2帧 QINFO_ISO;ISO QINFO_NOEXIF;Exif数据不可用. +QINFO_PIXELSHIFT;像素偏移/ %2帧 QUEUE_AUTOSTART;自动开始 QUEUE_DESTFILENAME;路径和文件名 QUEUE_FORMAT_TITLE;文件格式 QUEUE_LOCATION_FOLDER;保存至文件夹 QUEUE_LOCATION_TEMPLATE;使用模板 QUEUE_LOCATION_TEMPLATE_TOOLTIP;可以使用下列控制符:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\n这些控制符指向RAW文件所在文件夹及子文件夹 \n\n例如 假如 /home/tom/image/02-09-2006/dsc0012.nef已经打开, 控制符的意义如下:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, p3=/home/tom, ...\n\n如果想将输出文件保存到输入文件所在位置:\n%p1/%f\n\n如果想将输出文件保存至输入文件夹内的'converted'子文件夹:\n%p1/converted/%f\n\n如果想将输出文件保存至 '/home/tom/converted' 并保留按日期所分的子文件夹:\n%p2/converted/%d1/%f +QUEUE_LOCATION_TITLE;输出位置 +SAMPLEFORMAT_0;未知数据格式 +SAMPLEFORMAT_1;8-bit unsigned +SAMPLEFORMAT_2;16-bit unsigned +SAMPLEFORMAT_16;16-bit浮点数 +SAMPLEFORMAT_32;24-bit浮点数 +SAMPLEFORMAT_64;32-bit浮点数 SAVEDLG_AUTOSUFFIX;自动加后缀到已经存在的文件 SAVEDLG_FILEFORMAT;文件格式 +SAVEDLG_FILEFORMAT_FLOAT;浮点数 SAVEDLG_FORCEFORMATOPTS;强制保存选项 SAVEDLG_JPEGQUAL;JPEG质量 SAVEDLG_PUTTOQUEUE;放入队列 -SAVEDLG_PUTTOQUEUEHEAD;放在处理序列首位 -SAVEDLG_PUTTOQUEUETAIL;放在处理序列末位 +SAVEDLG_PUTTOQUEUEHEAD;放在处理队列首位 +SAVEDLG_PUTTOQUEUETAIL;放在处理队列末位 SAVEDLG_SAVEIMMEDIATELY;立即保存 SAVEDLG_SAVESPP;随图片保存处理参数 SAVEDLG_SUBSAMP;二次抽样 @@ -650,10 +910,10 @@ SAVEDLG_SUBSAMP_2;平衡 SAVEDLG_SUBSAMP_3;质量至优 SAVEDLG_TIFFUNCOMPRESSED;未压缩的TIFF SAVEDLG_WARNFILENAME;文件将被命名 -TOOLBAR_TOOLTIP_CROP;剪裁选择 (快捷键: C) -TOOLBAR_TOOLTIP_HAND;手形工具 (快捷键: N) -TOOLBAR_TOOLTIP_STRAIGHTEN;基准线选择 (快捷键: S) -TOOLBAR_TOOLTIP_WB;白平衡采样 (快捷键: W) +TOOLBAR_TOOLTIP_CROP;剪裁选择\n快捷键:c +TOOLBAR_TOOLTIP_HAND;手形工具\n快捷键:n +TOOLBAR_TOOLTIP_STRAIGHTEN;基准线选择\n快捷键:s +TOOLBAR_TOOLTIP_WB;白平衡采样\n快捷键:w TP_BWMIX_ALGO_LI;线性 TP_BWMIX_ALGO_SP;特定效果 TP_BWMIX_AUTOCH;自动 @@ -671,18 +931,22 @@ TP_BWMIX_GAMMA;伽马矫正 TP_BWMIX_GAM_TOOLTIP;矫正红绿蓝三色通道(RGB)伽马 TP_BWMIX_LABEL;黑白 TP_BWMIX_MET;方式 +TP_BWMIX_MET_CHANMIX;通道混合器 TP_BWMIX_MET_DESAT;淡化饱和度 -TP_BWMIX_MET_LUMEQUAL;明亮度平衡工具 +TP_BWMIX_MET_LUMEQUAL;亮度均衡工具 +TP_BWMIX_MIXC;通道混合器 TP_BWMIX_SETTING;预设 -TP_BWMIX_SETTING_TOOLTIP;不同预设 (影片、水平排布等)或手动通道混合工具设置 +TP_BWMIX_SETTING_TOOLTIP;不同预设 (胶片、风光等)或手动的通道混合工具设置 TP_BWMIX_SET_HIGHCONTAST;高对比度 TP_BWMIX_SET_HIGHSENSIT;高灵敏度 TP_BWMIX_SET_INFRARED;红外 TP_BWMIX_SET_LANDSCAPE;水平排布(风景) TP_BWMIX_SET_LOWSENSIT;低灵敏度 -TP_BWMIX_SET_LUMINANCE;光亮度 +TP_BWMIX_SET_LUMINANCE;亮度 TP_BWMIX_SET_PANCHRO;全色的 TP_BWMIX_SET_PORTRAIT;垂直排布(肖像) +TP_BWMIX_SET_RGBABS;绝对RGB +TP_BWMIX_SET_RGBREL;相对RGB TP_BWMIX_TCMODE_FILMLIKE;黑白电影样式 TP_BWMIX_TCMODE_STANDARD;黑白电影标准 TP_BWMIX_VAL;L @@ -697,14 +961,15 @@ TP_COARSETRAF_TOOLTIP_HFLIP;水平翻转 TP_COARSETRAF_TOOLTIP_ROTLEFT;左转 TP_COARSETRAF_TOOLTIP_ROTRIGHT;右转 TP_COARSETRAF_TOOLTIP_VFLIP;竖直翻转 +TP_COLORAPP_BADPIXSL;热像素/坏点过滤器 TP_COLORAPP_LABEL_CAM02;图像调整 -TP_COLORAPP_LIGHT;光度 (J) -TP_COLORAPP_LIGHT_TOOLTIP; CIECAM02、Lab 、RGB中光度意义各不同 +TP_COLORAPP_LIGHT;明度 (J) +TP_COLORAPP_LIGHT_TOOLTIP; CIECAM02、Lab 、RGB中明度意义各不同 TP_COLORAPP_SURROUND_AVER;平均 TP_COLORAPP_SURROUND_DARK;暗 TP_COLORAPP_SURROUND_DIM;暗淡 -TP_COLORAPP_TCMODE_BRIGHTNESS;亮度 -TP_COLORAPP_TCMODE_LIGHTNESS;光度 +TP_COLORAPP_TCMODE_BRIGHTNESS;光亮度 +TP_COLORAPP_TCMODE_LIGHTNESS;明度 TP_COLORAPP_TCMODE_SATUR;色彩饱和度 TP_CROP_FIXRATIO;比例: TP_CROP_GTDIAGONALS;对角线法则 @@ -723,22 +988,63 @@ TP_CROP_W;宽 TP_CROP_X;x TP_CROP_Y;y TP_DARKFRAME_AUTOSELECT;自动选择 -TP_DARKFRAME_LABEL;黑框架 -TP_DEFRINGE_LABEL;去色彩边缘(紫边) +TP_DARKFRAME_LABEL;暗场 +TP_DEFRINGE_LABEL;去边 TP_DEFRINGE_RADIUS;半径 -TP_DIRPYRDENOISE_LUMINANCE_DETAIL;明亮度细节 -TP_DIRPYRDENOISE_LUMINANCE_SMOOTHING;光亮度/发光度 +TP_DEFRINGE_THRESHOLD;阈值 +TP_DEHAZE_LABEL;去雾 +TP_DEHAZE_LUMINANCE;仅亮度 +TP_DEHAZE_STRENGTH;力度 +TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL;全局自动 +TP_DIRPYRDENOISE_CHROMINANCE_BLUEYELLOW;色度—蓝-黄 +TP_DIRPYRDENOISE_CHROMINANCE_CURVE;色度曲线 +TP_DIRPYRDENOISE_CHROMINANCE_FRAME;色度 +TP_DIRPYRDENOISE_CHROMINANCE_MANUAL;手动 +TP_DIRPYRDENOISE_CHROMINANCE_METHOD;方法 +TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_NOISEINFO;当前预览处噪点:中位数=%1 最大=%2 +TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_NOISEINFO_EMPTY;当前预览处噪点:中位数=- 最大= - +TP_DIRPYRDENOISE_CHROMINANCE_REDGREEN;色度—红-绿 +TP_DIRPYRDENOISE_LABEL;降噪 +TP_DIRPYRDENOISE_LUMINANCE_CONTROL;亮度控制 +TP_DIRPYRDENOISE_LUMINANCE_CURVE;亮度曲线 +TP_DIRPYRDENOISE_LUMINANCE_DETAIL;细节恢复 +TP_DIRPYRDENOISE_LUMINANCE_FRAME;亮度 +TP_DIRPYRDENOISE_LUMINANCE_SMOOTHING;亮度 +TP_DIRPYRDENOISE_MAIN_COLORSPACE;色彩空间 TP_DIRPYRDENOISE_MAIN_COLORSPACE_RGB;RGB +TP_DIRPYRDENOISE_MAIN_COLORSPACE_TOOLTIP;对于Raw文件,RGB和L*a*b*均可用\n\n非Raw文件只可用L*a*b*空间,不论用户选择了哪个 +TP_DIRPYRDENOISE_MAIN_MODE;模式 +TP_DIRPYRDENOISE_MAIN_MODE_AGGRESSIVE;激进 +TP_DIRPYRDENOISE_MAIN_MODE_CONSERVATIVE;保守 +TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;“保守”会保留低频的色度纹路,而“激进”会消除它们 +TP_DIRPYRDENOISE_MEDIAN_METHOD;中值法 +TP_DIRPYRDENOISE_MEDIAN_METHOD_CHROMINANCE;仅色度 +TP_DIRPYRDENOISE_MEDIAN_METHOD_LAB;L*a*b* +TP_DIRPYRDENOISE_MEDIAN_METHOD_LABEL;中值滤波器 +TP_DIRPYRDENOISE_MEDIAN_METHOD_LUMINANCE;仅亮度 +TP_DIRPYRDENOISE_MEDIAN_METHOD_RGB;RGB +TP_DIRPYRDENOISE_MEDIAN_METHOD_TOOLTIP;当使用“仅亮度”和“L*a*b*”法时,在降噪流水线中,\n中值滤波会在小波被应用后进行。\n当使用“RGB”模式时,它会在降噪流水线的最后被进行 +TP_DIRPYRDENOISE_MEDIAN_METHOD_WEIGHTED;权重L* (小) + a*b* (正常) +TP_DIRPYRDENOISE_MEDIAN_PASSES;中值迭代 +TP_DIRPYRDENOISE_MEDIAN_PASSES_TOOLTIP;使用3x3大小窗口并进行三次中值迭代通常比使用7x7窗口并进行一次迭代的效果更好 +TP_DIRPYRDENOISE_MEDIAN_TYPE;中值类型 +TP_DIRPYRDENOISE_MEDIAN_TYPE_TOOLTIP;使用你想要的窗口大小的中值滤波器。窗口大小越大,处理用时越长。\n3×3柔和:处理3x3窗口中的5个像素。\n\n处理3x3像素大小的窗口里面的9个像素。\n\n5x5柔和:处理5x5像素大小的窗口里面的13个像素。\n\n5x5:处理5x5像素大小的窗口里面的25个像素。\n\n7x7:处理7x7像素大小的窗口里面的49个像素。\n\n9x9:处理9x9像素大小的窗口里面的81个像素。\n\n有时使用小窗口进行多次迭代的效果会优于使用大窗口进行一次迭代的效果 +TP_DIRPYRDENOISE_TYPE_3X3;3×3 +TP_DIRPYRDENOISE_TYPE_3X3SOFT;3×3柔和 +TP_DIRPYRDENOISE_TYPE_5X5;5×5 +TP_DIRPYRDENOISE_TYPE_5X5SOFT;5×5柔和 +TP_DIRPYRDENOISE_TYPE_7X7;7×7 +TP_DIRPYRDENOISE_TYPE_9X9;9×9 TP_DIRPYREQUALIZER_ALGO;皮肤色彩范围 TP_DIRPYREQUALIZER_ARTIF;减少杂色 TP_DIRPYREQUALIZER_HUESKIN;皮肤色相 TP_DIRPYREQUALIZER_LABEL;分频反差调整 -TP_DIRPYREQUALIZER_LUMACOARSEST;最粗 +TP_DIRPYREQUALIZER_LUMACOARSEST;最粗糙 TP_DIRPYREQUALIZER_LUMACONTRAST_MINUS;反差 - TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS;反差 + -TP_DIRPYREQUALIZER_LUMAFINEST;最细 +TP_DIRPYREQUALIZER_LUMAFINEST;最精细 TP_DIRPYREQUALIZER_LUMANEUTRAL;自然 -TP_DIRPYREQUALIZER_SKIN;皮肤色彩 针对/保护 +TP_DIRPYREQUALIZER_SKIN;肤色针对/保护 TP_DIRPYREQUALIZER_THRESHOLD;阈值 TP_DISTORTION_AMOUNT;数量 TP_DISTORTION_LABEL;畸变 @@ -747,7 +1053,7 @@ TP_EPD_SCALE;拉伸 TP_EPD_STRENGTH;力度 TP_EXPOSURE_AUTOLEVELS;自动色阶 TP_EXPOSURE_BLACKLEVEL;黑点 -TP_EXPOSURE_BRIGHTNESS;亮度 +TP_EXPOSURE_BRIGHTNESS;光亮度 TP_EXPOSURE_CLIP;高光溢出 TP_EXPOSURE_COMPRHIGHLIGHTS;高光压缩 TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD;高光压缩阈值 @@ -758,40 +1064,55 @@ TP_EXPOSURE_CURVEEDITOR1;色调曲线 1 TP_EXPOSURE_CURVEEDITOR2;色调曲线 2 TP_EXPOSURE_CURVEEDITOR2_TOOLTIP;请从 RawPedia 网站中 Exposure > Tone Curve 文章中了解如何使用双色调曲线 TP_EXPOSURE_EXPCOMP;曝光补偿 +TP_EXPOSURE_HISTMATCHING;自适应色调曲线 +TP_EXPOSURE_HISTMATCHING_TOOLTIP;自动调整滑条和曲线(不包括曝光补偿)以使图片贴近于内嵌于Raw的JPEG预览图。 TP_EXPOSURE_LABEL;曝光 TP_EXPOSURE_SATURATION;色彩饱和度 TP_EXPOSURE_TCMODE_FILMLIKE;仿胶片式 TP_EXPOSURE_TCMODE_LABEL1;曲线模式1 TP_EXPOSURE_TCMODE_LABEL2;曲线模式2 -TP_EXPOSURE_TCMODE_SATANDVALBLENDING;饱和度和混合值 +TP_EXPOSURE_TCMODE_LUMINANCE;亮度 +TP_EXPOSURE_TCMODE_PERCEPTUAL;感知性 +TP_EXPOSURE_TCMODE_SATANDVALBLENDING;饱和度-亮度混合 TP_EXPOSURE_TCMODE_STANDARD;标准 -TP_EXPOSURE_TCMODE_WEIGHTEDSTD;倾向于标准 +TP_EXPOSURE_TCMODE_WEIGHTEDSTD;加权标准 +TP_FILMNEGATIVE_LABEL;胶片负片 +TP_FILMSIMULATION_LABEL;胶片模拟 +TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee默认会寻找用于胶片模拟工具的Hald CLUT图像,图像所在的文件夹加载时间比较长。\n前往参数设置-图片处理-Hald CLUT路径\n以寻找被使用的文件夹是哪个。你应该把这个文件夹指向一个只有Hald CLUT图像而没有其他图片的文件夹,而如果你不想用胶片模拟功能,就把它指向一个空文件夹。\n\n阅读RawPedia上的Film Simulation词条以获取更多信息。\n\n你现在想取消扫描吗? +TP_FILMSIMULATION_STRENGTH;力度 +TP_FILMSIMULATION_ZEROCLUTSFOUND;在参数设置中设定HaldCLUT目录 TP_FLATFIELD_AUTOSELECT;自动选择 TP_FLATFIELD_BLURRADIUS;模糊半径 TP_FLATFIELD_BLURTYPE;模糊种类 TP_FLATFIELD_BT_AREA;区域 TP_FLATFIELD_BT_HORIZONTAL;水平 -TP_FLATFIELD_BT_VERTHORIZ;垂直 + 水平 +TP_FLATFIELD_BT_VERTHORIZ;垂直+水平 TP_FLATFIELD_BT_VERTICAL;垂直 +TP_FLATFIELD_CLIPCONTROL;溢出控制 +TP_FLATFIELD_CLIPCONTROL_TOOLTIP;溢出控制能够避免由于平场的应用而导致的高光溢出。如果在应用平场之前就有溢出的高光,数值就会为0 TP_FLATFIELD_LABEL;平场 +TP_GENERAL_11SCALE_TOOLTIP;此工具的效果仅在以1:1大小预览时才可见/准确 TP_GRADIENT_CENTER;中心 TP_GRADIENT_CENTER_X;中心 X +TP_GRADIENT_CENTER_X_TOOLTIP;将渐变滤镜向左(负值)或向右(正值)移动 TP_GRADIENT_CENTER_Y;中心 Y +TP_GRADIENT_CENTER_Y_TOOLTIP;将渐变滤镜向上(负值)或向下(正值)移动 TP_GRADIENT_DEGREE;角度 -TP_GRADIENT_DEGREE_TOOLTIP;转动角度数 +TP_GRADIENT_DEGREE_TOOLTIP;转动的角度数 TP_GRADIENT_FEATHER;羽化 -TP_GRADIENT_FEATHER_TOOLTIP;图像对角比例表示渐变宽度 -TP_GRADIENT_LABEL;渐变过滤 +TP_GRADIENT_FEATHER_TOOLTIP;以图像对角线的长度为100,设定渐变的宽度 +TP_GRADIENT_LABEL;渐变滤镜 TP_GRADIENT_STRENGTH;延展 +TP_GRADIENT_STRENGTH_TOOLTIP;滤镜的强度(档数) TP_HLREC_BLEND;混合 TP_HLREC_CIELAB;CIELab模式混合 TP_HLREC_COLOR;色彩延伸 TP_HLREC_LABEL;高光还原 TP_HLREC_LUMINANCE;亮度还原 TP_HLREC_METHOD;方法: -TP_HSVEQUALIZER_CHANNEL;频道 +TP_HSVEQUALIZER_CHANNEL;通道 TP_HSVEQUALIZER_HUE;H -TP_HSVEQUALIZER_LABEL;HSV 平衡 +TP_HSVEQUALIZER_LABEL;HSV均衡器 TP_HSVEQUALIZER_SAT;S TP_HSVEQUALIZER_VAL;V TP_ICM_INPUTCAMERA;相机缺省 @@ -807,83 +1128,205 @@ TP_ICM_NOICM;No ICM: sRGB配置 TP_ICM_OUTPUTPROFILE;输出配置 TP_ICM_TONECURVE;使用 DCP 色调曲线 TP_ICM_WORKINGPROFILE;当前配置 -TP_IMPULSEDENOISE_LABEL;降低脉冲噪声 +TP_IMPULSEDENOISE_LABEL;脉冲噪声降低 TP_IMPULSEDENOISE_THRESH;阈值 TP_LABCURVE_AVOIDCOLORSHIFT;避免色彩偏移 TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP;使色彩适应当前色彩空间范围, 并使用Munsell色矫正 -TP_LABCURVE_BRIGHTNESS;光度 +TP_LABCURVE_BRIGHTNESS;光强度 TP_LABCURVE_CHROMATICITY;色度 CIE +TP_LABCURVE_CHROMA_TOOLTIP;若要应用黑白色调,将色度值降低为-100 TP_LABCURVE_CONTRAST;对比度 -TP_LABCURVE_CURVEEDITOR;明亮度曲线 +TP_LABCURVE_CURVEEDITOR;亮度曲线 TP_LABCURVE_LABEL;Lab调整 TP_LENSGEOM_AUTOCROP;自动剪切 TP_LENSGEOM_FILL;自动填充 TP_LENSGEOM_LABEL;镜头 / 几何 +TP_LENSGEOM_LIN;线性 +TP_LENSGEOM_LOG;对数 +TP_LENSPROFILE_CORRECTION_AUTOMATCH;自动选择 +TP_LENSPROFILE_CORRECTION_LCPFILE;LCP文件 +TP_LENSPROFILE_CORRECTION_MANUAL;手动选择 TP_LENSPROFILE_LABEL;镜头矫正档案 +TP_LENSPROFILE_MODE_HEADER;镜头档案 +TP_LENSPROFILE_USE_CA;色差 +TP_LENSPROFILE_USE_GEOMETRIC;几何畸变 +TP_LENSPROFILE_USE_HEADER;矫正 +TP_LENSPROFILE_USE_VIGNETTING;暗角 +TP_LOCALCONTRAST_AMOUNT;数量 +TP_LOCALCONTRAST_DARKNESS;黑处等级 +TP_LOCALCONTRAST_LABEL;局部反差 +TP_LOCALCONTRAST_LIGHTNESS;亮处等级 +TP_LOCALCONTRAST_RADIUS;半径 +TP_METADATA_EDIT;应用修改 +TP_METADATA_MODE;元数据复制模式: +TP_METADATA_STRIP;移除所有元数据 TP_PCVIGNETTE_FEATHER;羽化 +TP_PCVIGNETTE_FEATHER_TOOLTIP;羽化:\n0 = 仅边角,\n50 = 到达一半的位置,\n100 = 到达中心 TP_PCVIGNETTE_LABEL;暗角滤镜 TP_PCVIGNETTE_ROUNDNESS;圆度 +TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;圆度:\n0 = 矩形,\n50 = 适于图像的椭圆\n100 = 圆形 TP_PCVIGNETTE_STRENGTH;力度 -TP_PCVIGNETTE_STRENGTH_TOOLTIP;滤镜的力度刻度 (到达角落) +TP_PCVIGNETTE_STRENGTH_TOOLTIP;滤镜的曝光补偿力度 (到达边角) +TP_PDSHARPENING_LABEL;捕图加锐 TP_PERSPECTIVE_HORIZONTAL;水平 TP_PERSPECTIVE_LABEL;视角 TP_PERSPECTIVE_VERTICAL;垂直 -TP_PREPROCESS_LABEL;处理中 -TP_PREPROCESS_LINEDENOISE;线性噪点过滤 +TP_PREPROCESS_DEADPIXFILT;坏点过滤器 +TP_PREPROCESS_DEADPIXFILT_TOOLTIP;尝试过滤坏点。 +TP_PREPROCESS_GREENEQUIL;绿平衡 +TP_PREPROCESS_HOTPIXFILT;热像素过滤器 +TP_PREPROCESS_HOTPIXFILT_TOOLTIP;尝试过滤热像素。 +TP_PREPROCESS_LABEL;预处理 +TP_PREPROCESS_LINEDENOISE;线状噪点过滤 +TP_PREPROCESS_LINEDENOISE_DIRECTION;方向 +TP_PREPROCESS_LINEDENOISE_DIRECTION_BOTH;双向 +TP_PREPROCESS_LINEDENOISE_DIRECTION_HORIZONTAL;横向 +TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;横向,只在PDAF点所在的行上 +TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;纵向 TP_PREPROCESS_NO_FOUND;没发现 +TP_PREPROCESS_PDAFLINESFILTER;PDAF条纹过滤器 +TP_PRSHARPENING_LABEL;调整大小后加锐 +TP_PRSHARPENING_TOOLTIP;在调整图片大小后加锐图像。仅在选择"Lanczos"算法时可用。本工具的效果无法预览。见RawPedia的文章以了解本工具的使用教程 TP_RAWCACORR_AUTO;自动修正 +TP_RAWCACORR_AUTOIT;迭代 +TP_RAWCACORR_AUTOIT_TOOLTIP;若“自动矫正”被勾选,此设置便可用。\n自动矫正是保守的,也就是说它经常不会去除所有色差。\n要移除全部色差,你可以使用至多迭代五次的色差矫正迭代。\n每次迭代会纠正上个迭代未能修正的色差,代价是需要花费额外的处理时间。 +TP_RAWCACORR_AVOIDCOLORSHIFT;避免偏色 TP_RAWCACORR_CABLUE;蓝 TP_RAWCACORR_CARED;红 -TP_RESIZE_CROPPEDAREA;切出的部分 -TP_RESIZE_FITBOX;Bounding Box -TP_RESIZE_FULLIMAGE;全图 +TP_RAWCACORR_LABEL;色差矫正 +TP_RAWEXPOS_RGB;红,绿,蓝 +TP_RAW_AHD;AHD +TP_RAW_AMAZE;AMaZE +TP_RAW_AMAZEVNG4;AMaZE+VNG4 +TP_RAW_BORDER;边界 +TP_RAW_DCB;DCB +TP_RAW_DCBENHANCE;DCB优化 +TP_RAW_DCBITERATIONS;DCB迭代数 +TP_RAW_DCBVNG4;DCB+VNG4 +TP_RAW_DMETHOD;方法 +TP_RAW_DMETHOD_PROGRESSBAR;%1 去马赛克中... +TP_RAW_DMETHOD_PROGRESSBAR_REFINE;去马赛克精细化... +TP_RAW_DMETHOD_TOOLTIP;注:IGV和LMMSE是专门用于配合降噪工具,在为高ISO图片降噪时不产生迷宫状噪点,色调分离或是褪色所用的。\n像素偏移是为宾得/索尼的像素偏移文件所用的。此算法使用AMaZE算法来处理非像素偏移文件。 +TP_RAW_DUALDEMOSAICAUTOCONTRAST;自动阈值 +TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;如果勾选框被打勾(推荐如此做),RawTherapee会根据图片中的平缓区域自动计算一个最优值。\n如果图像中没有平缓的区域,或是图片噪点太多,该数值会被设为0\n若想手动调整此数值,首先要将勾选框取消勾选(合适的值取决于具体图像的情况)。 +TP_RAW_DUALDEMOSAICCONTRAST;反差阈值 +TP_RAW_EAHD;EAHD +TP_RAW_FALSECOLOR;伪色抑制步长 +TP_RAW_FAST;Fast +TP_RAW_HD;阈值 +TP_RAW_HD_TOOLTIP;更低的数值会使热像素/坏点的检测更加激进,但是“宁错杀,不放过”的激进程度可能会导致杂点的产生。在启用本功能后,如果你发现了新出现的杂点,就逐渐提高阈值,直至杂点消失。 +TP_RAW_HPHD;HPHD +TP_RAW_IGV;IGV +TP_RAW_IMAGENUM;子图像 +TP_RAW_IMAGENUM_SN;SN模式 +TP_RAW_IMAGENUM_TOOLTIP;某些Raw文件包含多张子图像(宾得/索尼的像素偏移,宾得的3张合并HDR,佳能的双像素,富士的EXR)。\n\n当使用除像素偏移外的任意一个去马赛克算法时,本栏用来选择哪帧子图像被处理。\n\n当在像素偏移的Raw文件上使用像素偏移去马赛克算法时,所有子图像都会被应用,此时本栏用来选择哪帧子图像被用来处理动体。 +TP_RAW_LABEL;去马赛克 +TP_RAW_LMMSEITERATIONS;LMMSE优化步长 +TP_RAW_LMMSE_TOOLTIP;添加gamma(步长1),中位数(步长2-4)和精细化(步长5-6)以减少杂点并提升信噪比。 +TP_RAW_MONO;黑白 +TP_RAW_NONE;无(显示传感器阵列) +TP_RAW_PIXELSHIFT;像素偏移 +TP_RAW_PIXELSHIFTBLUR;动体蒙版模糊 +TP_RAW_PIXELSHIFTDMETHOD;动体区域的去马赛克算法 +TP_RAW_PIXELSHIFTEPERISO;敏感度 +TP_RAW_PIXELSHIFTEPERISO_TOOLTIP;默认值0在原生ISO下应该具有不错的效果。\n更大的数值会增强动体检测的敏感度。\n以微小的步长调整此值,同时观察动体蒙版的变化。\n对于欠曝/高ISO的照片,应提高此值。 +TP_RAW_PIXELSHIFTEQUALBRIGHT;将不同照片的亮度均等化 +TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL;将各个通道分别均等化 +TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL_TOOLTIP;启用:对RGB通道分别进行均等化。\n禁用:使用同一个均等化系数对所有通道进行均等化。 +TP_RAW_PIXELSHIFTEQUALBRIGHT_TOOLTIP;以当前被选中的一帧图像为基准,均等化各帧图像的亮度。\n如果各帧中有过曝的区域,应选择最亮的一帧以避免过曝区域出现紫色,也可启用动体补正来解决该问题。 +TP_RAW_PIXELSHIFTGREEN;检查绿色通道以检测动体 +TP_RAW_PIXELSHIFTHOLEFILL;填补动体蒙版的洞 +TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;填补动体蒙版中间所存在的洞 +TP_RAW_PIXELSHIFTMEDIAN;对动体区域使用中值 +TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;对于运动的部分,使用所有图片的中值,而不是用户选择的某一帧图片。\n移除在所有图片中位置都不同的物体。\n在移动慢(重叠)的物体上会产生动体效果。 +TP_RAW_PIXELSHIFTMM_AUTO;自动 +TP_RAW_PIXELSHIFTMM_CUSTOM;自定义 +TP_RAW_PIXELSHIFTMM_OFF;关闭 +TP_RAW_PIXELSHIFTMOTIONMETHOD;动体补正 +TP_RAW_PIXELSHIFTNONGREENCROSS;检查红/蓝色通道以检测动体 +TP_RAW_PIXELSHIFTSHOWMOTION;显示动体蒙版 +TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;仅显示动体蒙版 +TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;显示没有照片的动体蒙版。 +TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;在图像上用绿色蒙版显示动体区域。 +TP_RAW_PIXELSHIFTSIGMA;模糊半径 +TP_RAW_PIXELSHIFTSIGMA_TOOLTIP;默认半径值1.0一般对于原生ISO来说足够好。\n对于高ISO照片,提高此值,5.0是不错的起始点。\n在改变此值的同时关注动体蒙版。 +TP_RAW_PIXELSHIFTSMOOTH;顺滑过渡 +TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;让存在动体的区域与没有动体之间的区域之间顺滑地过渡。\n将此值设置为0以禁用顺滑过渡\n将此值设置为1以使用AMaZE/LMMSE算法(这取决于你是否选择了“使用LMMSE”)所解出的你所选择的那一帧图像,如果你选择了“使用中值”,那么就会根据通过所有图像计算出的中值解出图像。 +TP_RAW_RCD;RCD +TP_RAW_RCDVNG4;RCD+VNG4 +TP_RAW_SENSOR_BAYER_LABEL;拜耳阵列传感器 +TP_RESIZE_ALLOW_UPSCALING;允许升采样 +TP_RESIZE_APPLIESTO;应用到: +TP_RESIZE_CROPPEDAREA;裁剪区域 +TP_RESIZE_FITBOX;矩形区域 +TP_RESIZE_FULLIMAGE;整张图 TP_RESIZE_H;高: TP_RESIZE_HEIGHT;高度 TP_RESIZE_LABEL;调整大小 TP_RESIZE_LANCZOS;Lanczos算法 TP_RESIZE_METHOD;方式: TP_RESIZE_NEAREST;最近点 -TP_RESIZE_SCALE;比例 -TP_RESIZE_SPECIFY;指定: +TP_RESIZE_SCALE;缩放倍数 +TP_RESIZE_SPECIFY;调整: TP_RESIZE_W;宽: TP_RESIZE_WIDTH;宽度 +TP_RETINEX_CONTEDIT_HSL;HSL直方图 +TP_RETINEX_CONTEDIT_LAB;L*a*b*直方图 +TP_RETINEX_CONTEDIT_LH;色调 +TP_RETINEX_CONTEDIT_MAP;均衡器 +TP_RETINEX_EQUAL;均衡器 +TP_RETINEX_VIEW_UNSHARP;USM锐化 TP_RGBCURVES_BLUE;B -TP_RGBCURVES_CHANNEL;频道 +TP_RGBCURVES_CHANNEL;通道 TP_RGBCURVES_GREEN;G TP_RGBCURVES_LABEL;RGB曲线 -TP_RGBCURVES_LUMAMODE;光度模式 -TP_RGBCURVES_LUMAMODE_TOOLTIP;光度模式 允许改变R、G、B三种通道光量但不影响色彩 +TP_RGBCURVES_LUMAMODE;亮度模式 +TP_RGBCURVES_LUMAMODE_TOOLTIP;亮度模式 允许改变R、G、B三种通道光量但不影响色彩 TP_RGBCURVES_RED;R TP_ROTATE_DEGREE;角度 TP_ROTATE_LABEL;旋转 -TP_ROTATE_SELECTLINE; 选择基准线 +TP_ROTATE_SELECTLINE;选择基准线 TP_SAVEDIALOG_OK_TIP;快捷键: Ctrl-Enter TP_SHADOWSHLIGHTS_HIGHLIGHTS;高光 -TP_SHADOWSHLIGHTS_HLTONALW;影调范围 +TP_SHADOWSHLIGHTS_HLTONALW;色调范围 TP_SHADOWSHLIGHTS_LABEL;阴影/高光 TP_SHADOWSHLIGHTS_RADIUS;半径 TP_SHADOWSHLIGHTS_SHADOWS;阴影 -TP_SHADOWSHLIGHTS_SHTONALW;影调范围 +TP_SHADOWSHLIGHTS_SHTONALW;色调范围 TP_SHARPENEDGE_AMOUNT;数量 TP_SHARPENEDGE_LABEL;边缘 -TP_SHARPENEDGE_PASSES;迭代次数 -TP_SHARPENEDGE_THREE;仅光度 +TP_SHARPENEDGE_PASSES;迭代 +TP_SHARPENEDGE_THREE;仅亮度 TP_SHARPENING_AMOUNT;数量 +TP_SHARPENING_BLUR;模糊半径 +TP_SHARPENING_CONTRAST;反差阈值 TP_SHARPENING_EDRADIUS;半径 TP_SHARPENING_EDTOLERANCE;边缘容差 TP_SHARPENING_HALOCONTROL;光晕控制 TP_SHARPENING_HCAMOUNT;数量 +TP_SHARPENING_ITERCHECK;自动限制迭代 TP_SHARPENING_LABEL;锐化 TP_SHARPENING_METHOD;方式 TP_SHARPENING_ONLYEDGES;仅锐化边缘 TP_SHARPENING_RADIUS;半径 -TP_SHARPENING_RLD;理查森-露西反卷积法 +TP_SHARPENING_RADIUS_BOOST;边缘半径值提升 +TP_SHARPENING_RLD;理查森-露西反卷积法(RLD) TP_SHARPENING_RLD_AMOUNT;数量 TP_SHARPENING_RLD_DAMPING;衰减 TP_SHARPENING_RLD_ITERATIONS;迭代 TP_SHARPENING_THRESHOLD;阈值 TP_SHARPENING_USM;USM锐化 TP_SHARPENMICRO_AMOUNT;数量 +TP_SHARPENMICRO_CONTRAST;反差阈值 +TP_SHARPENMICRO_LABEL;微反差 +TP_SHARPENMICRO_MATRIX;使用3×3阵列而非5×5阵列 +TP_SHARPENMICRO_UNIFORMITY;均匀度 +TP_TM_FATTAL_AMOUNT;数量 +TP_TM_FATTAL_ANCHOR;锚点 +TP_TM_FATTAL_LABEL;动态范围压缩 +TP_TM_FATTAL_THRESHOLD;细节 +TP_VIBRANCE_AVOIDCOLORSHIFT;避免偏色 +TP_VIBRANCE_PROTECTSKINS;保护肤色 TP_VIGNETTING_AMOUNT;数量 TP_VIGNETTING_CENTER;中心 TP_VIGNETTING_CENTER_X;中心 X @@ -891,6 +1334,66 @@ TP_VIGNETTING_CENTER_Y;中心 Y TP_VIGNETTING_LABEL;暗角矫正 TP_VIGNETTING_RADIUS;半径 TP_VIGNETTING_STRENGTH;力度 +TP_WAVELET_1;第1级 +TP_WAVELET_2;第2级 +TP_WAVELET_3;第3级 +TP_WAVELET_4;第4级 +TP_WAVELET_5;第5级 +TP_WAVELET_6;第6级 +TP_WAVELET_7;第7级 +TP_WAVELET_8;第8级 +TP_WAVELET_9;第9级 +TP_WAVELET_APPLYTO;应用到 +TP_WAVELET_AVOID;避免偏色 +TP_WAVELET_B0;黑色 +TP_WAVELET_B1;灰色 +TP_WAVELET_BACKGROUND;背景 +TP_WAVELET_BACUR;曲线 +TP_WAVELET_BASLI;滑条 +TP_WAVELET_CCURVE;局部反差 +TP_WAVELET_CH3;与反差等级挂钩 +TP_WAVELET_CHCU;曲线 +TP_WAVELET_CHR;色度-反差挂钩力度 +TP_WAVELET_CHSL;滑条 +TP_WAVELET_COMPCONT;反差 +TP_WAVELET_CONTRA;反差 +TP_WAVELET_CONTRAST_MINUS;反差 - +TP_WAVELET_CONTRAST_PLUS;反差 + +TP_WAVELET_CONTRA_TOOLTIP;改变余像的反差。 +TP_WAVELET_CTYPE;色度控制 +TP_WAVELET_DALL;所有方向 +TP_WAVELET_DAUB;Edge performance +TP_WAVELET_DAUB2;D2-低 +TP_WAVELET_DAUB4;D4-标准 +TP_WAVELET_DAUB6;D6-标准增强 +TP_WAVELET_DAUB10;D10-中等 +TP_WAVELET_DAUB14;D14-高 +TP_WAVELET_DONE;纵向 +TP_WAVELET_DTHR;斜向 +TP_WAVELET_DTWO;横向 +TP_WAVELET_EDCU;曲线 +TP_WAVELET_EDGCONT;局部反差 +TP_WAVELET_EDSL;阈值滑条 +TP_WAVELET_EDVAL;力度 +TP_WAVELET_LABEL;小波层级 +TP_WAVELET_LARGEST;最粗糙 +TP_WAVELET_LEVDIR_ALL;所有方向的全部层级 +TP_WAVELET_LEVDIR_INF;小于等于此层级 +TP_WAVELET_LEVDIR_ONE;一个层级 +TP_WAVELET_LEVDIR_SUP;高于此层级 +TP_WAVELET_LEVELS;小波层级 +TP_WAVELET_LEVELS_TOOLTIP;选择将图像分解为几个层级的细节。更多的层级需要使用更多的内存和更长的处理时间。 +TP_WAVELET_LEVONE;第2级 +TP_WAVELET_LEVTHRE;第4级 +TP_WAVELET_LEVTWO;第3级 +TP_WAVELET_LEVZERO;第1级 +TP_WAVELET_MEDGREINF;第一层级 +TP_WAVELET_MEDI;减少蓝天中的杂点 +TP_WAVELET_NOIS;去噪 +TP_WAVELET_NOISE;去噪和精细化 +TP_WAVELET_SETTINGS;小波设定 +TP_WAVELET_STREN;力度 +TP_WAVELET_STRENGTH;力度 TP_WBALANCE_AUTO;自动 TP_WBALANCE_CAMERA;相机 TP_WBALANCE_CLOUDY;阴天 @@ -898,6 +1401,8 @@ TP_WBALANCE_CUSTOM;自定义 TP_WBALANCE_DAYLIGHT;晴天 TP_WBALANCE_EQBLUERED;蓝红平衡 TP_WBALANCE_FLASH55;徕卡 +TP_WBALANCE_FLASH60;标准,佳能,宾得,奥林巴斯 +TP_WBALANCE_FLASH65;尼康,松下,索尼,美能达 TP_WBALANCE_FLASH_HEADER;闪光 TP_WBALANCE_GREEN;色度 TP_WBALANCE_LABEL;白平衡 @@ -913,1403 +1418,9 @@ TP_WBALANCE_WATER1;水下 1 TP_WBALANCE_WATER2;水下 2 TP_WBALANCE_WATER_HEADER;水下 ZOOMPANEL_100;(100%) -ZOOMPANEL_NEWCROPWINDOW;开启(新)细节窗口 +ZOOMPANEL_NEWCROPWINDOW;开启(新的)细节窗口 ZOOMPANEL_ZOOM100;缩放到100%\n快捷键: z ZOOMPANEL_ZOOMFITCROPSCREEN;适应边缘到屏幕\n快捷键:f ZOOMPANEL_ZOOMFITSCREEN;适应屏幕\n快捷键: Alt-f ZOOMPANEL_ZOOMIN;缩放拉近\n快捷键: + ZOOMPANEL_ZOOMOUT;缩放拉远\n快捷键: - - -!!!!!!!!!!!!!!!!!!!!!!!!! -! 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_AXIS_IN;I: -!CURVEEDITOR_AXIS_LEFT_TAN;LT: -!CURVEEDITOR_AXIS_OUT;O: -!CURVEEDITOR_AXIS_RIGHT_TAN;RT: -!CURVEEDITOR_CATMULLROM;Flexible -!CURVEEDITOR_EDITPOINT_HINT;Enable edition of node in/out values.\n\nRight-click on a node to select it.\nRight-click on empty space to de-select the node. -!DYNPROFILEEDITOR_IMGTYPE_ANY;Any -!DYNPROFILEEDITOR_IMGTYPE_HDR;HDR -!DYNPROFILEEDITOR_IMGTYPE_PS;Pixel Shift -!DYNPROFILEEDITOR_IMGTYPE_STD;Standard -!EDIT_OBJECT_TOOLTIP;Displays a widget on the preview window which lets you adjust this tool. -!EDIT_PIPETTE_TOOLTIP;To add an adjustment point to the curve, hold the Ctrl key while left-clicking the desired spot in the image preview.\nTo adjust the point, hold the Ctrl key while left-clicking the corresponding area in the preview, then let go of Ctrl (unless you desire fine control) and while still holding the left mouse button move the mouse up or down to move that point up or down in the curve. -!EXIFFILTER_IMAGETYPE;Image type -!EXIFPANEL_SHOWALL;Show all -!EXPORT_BYPASS;Processing steps to bypass -!EXPORT_BYPASS_RAW_DCB_ENHANCE;Bypass [raw] DCB Enhancement Steps -!EXPORT_BYPASS_RAW_DCB_ITERATIONS;Bypass [raw] DCB Iterations -!EXPORT_BYPASS_RAW_LMMSE_ITERATIONS;Bypass [raw] LMMSE Enhancement Steps -!EXPORT_INSTRUCTIONS;Fast Export options provide overrides to bypass time and resource consuming development settings and to run queue processing using the fast export settings instead. This method is recommended for quicker generation of lower resolution images when speed is a priority or when resized output is desired for one or many images without making modifications to their saved development parameters. -!EXPORT_PIPELINE;Processing pipeline -!EXPORT_USE_FAST_PIPELINE;Dedicated (full processing on resized image) -!EXPORT_USE_FAST_PIPELINE_TIP;Use a dedicated processing pipeline for images in Fast Export mode, that trades speed for quality. Resizing of the image is done as early as possible, instead of doing it at the end like in the normal pipeline. The speedup can be significant, but be prepared to see artifacts and a general degradation of output quality. -!EXPORT_USE_NORMAL_PIPELINE;Standard (bypass some steps, resize at the end) -!FILEBROWSER_BROWSEPATHBUTTONHINT;Click to open specified path, reload folder and apply "find" keywords. -!FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory -!FILEBROWSER_CACHECLEARFROMFULL;Clear all including cached profiles -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear all except cached profiles -!FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple -!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_QUERYHINT;Type filenames to search for. Supports partial filenames. Separate the search terms using commas, e.g.\n1001,1004,1199\n\nExclude search terms by prefixing them with !=\ne.g.\n!=1001,1004,1199\n\nShortcuts:\nCtrl-f - focus the Find box,\nEnter - search,\nEsc - clear the Find box,\nShift-Esc - defocus the Find box. -!FILEBROWSER_SHOWCOLORLABEL1HINT;Show images labeled Red.\nShortcut: Alt-1 -!FILEBROWSER_SHOWCOLORLABEL2HINT;Show images labeled Yellow.\nShortcut: Alt-2 -!FILEBROWSER_SHOWCOLORLABEL3HINT;Show images labeled Green.\nShortcut: Alt-3 -!FILEBROWSER_SHOWCOLORLABEL4HINT;Show images labeled Blue.\nShortcut: Alt-4 -!FILEBROWSER_SHOWCOLORLABEL5HINT;Show images labeled Purple.\nShortcut: Alt-5 -!FILEBROWSER_SHOWEDITEDHINT;Show edited images.\nShortcut: 7 -!FILEBROWSER_SHOWEDITEDNOTHINT;Show not edited images.\nShortcut: 6 -!FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. -!FILEBROWSER_SHOWORIGINALHINT;Show only original images.\n\nWhen several images exist with the same filename but different extensions, the one considered original is the one whose extension is nearest the top of the parsed extensions list in Preferences > File Browser > Parsed Extensions. -!FILEBROWSER_SHOWRECENTLYSAVEDNOTHINT;Show unsaved images.\nShortcut: Alt-6 -!FILEBROWSER_SHOWUNCOLORHINT;Show images without a color label.\nShortcut: Alt-0 -!FILEBROWSER_UNRANK_TOOLTIP;Unrank.\nShortcut: Shift-0 -!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_BAR;Show/Hide RGB indicator bar. -!HISTOGRAM_TOOLTIP_CHRO;Show/Hide chromaticity histogram. -!HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram. -!HISTOGRAM_TOOLTIP_RAW;Show/Hide raw histogram. -!HISTORY_MSG_82;Profile changed -!HISTORY_MSG_86;RGB Curves - Luminosity mode -!HISTORY_MSG_87;Impulse Noise Reduction -!HISTORY_MSG_88;Impulse NR threshold -!HISTORY_MSG_91;NR - Chrominance master -!HISTORY_MSG_93;CbDL - Value -!HISTORY_MSG_94;Contrast by Detail Levels -!HISTORY_MSG_95;L*a*b* - Chromaticity -!HISTORY_MSG_96;L*a*b* - a* curve -!HISTORY_MSG_97;L*a*b* - b* curve -!HISTORY_MSG_98;Demosaicing method -!HISTORY_MSG_99;Hot pixel filter -!HISTORY_MSG_100;Exposure - Saturation -!HISTORY_MSG_101;HSV - Hue -!HISTORY_MSG_102;HSV - Saturation -!HISTORY_MSG_104;HSV Equalizer -!HISTORY_MSG_105;Defringe -!HISTORY_MSG_106;Defringe - Radius -!HISTORY_MSG_107;Defringe - Threshold -!HISTORY_MSG_108;Exposure - HLC threshold -!HISTORY_MSG_109;Resize - Bounding box -!HISTORY_MSG_110;Resize - Applies to -!HISTORY_MSG_112;--unused-- -!HISTORY_MSG_115;False color suppression -!HISTORY_MSG_116;DCB enhancement -!HISTORY_MSG_117;Raw CA correction - Red -!HISTORY_MSG_118;Raw CA correction - Blue -!HISTORY_MSG_120;Green equilibration -!HISTORY_MSG_121;Raw CA Correction - Auto -!HISTORY_MSG_131;NR - Luma -!HISTORY_MSG_132;NR - Chroma -!HISTORY_MSG_133;Output gamma -!HISTORY_MSG_134;Free gamma -!HISTORY_MSG_135;Free gamma -!HISTORY_MSG_136;Free gamma slope -!HISTORY_MSG_137;Black level - Green 1 -!HISTORY_MSG_138;Black level - Red -!HISTORY_MSG_139;Black level - Blue -!HISTORY_MSG_140;Black level - Green 2 -!HISTORY_MSG_141;Black level - Link greens -!HISTORY_MSG_142;ES - Iterations -!HISTORY_MSG_143;ES - Quantity -!HISTORY_MSG_144;Microcontrast - Quantity -!HISTORY_MSG_145;Microcontrast - Uniformity -!HISTORY_MSG_148;Microcontrast -!HISTORY_MSG_149;Microcontrast - 3×3 matrix -!HISTORY_MSG_150;Post-demosaic artifact/noise red. -!HISTORY_MSG_151;Vibrance -!HISTORY_MSG_152;Vib - Pastel tones -!HISTORY_MSG_153;Vib - Saturated tones -!HISTORY_MSG_154;Vib - Protect skin-tones -!HISTORY_MSG_156;Vib - Link pastel/saturated -!HISTORY_MSG_157;Vib - P/S threshold -!HISTORY_MSG_161;TM - Reweighting iterates -!HISTORY_MSG_163;RGB Curves - Red -!HISTORY_MSG_164;RGB Curves - Green -!HISTORY_MSG_165;RGB Curves - Blue -!HISTORY_MSG_166;Exposure - Reset -!HISTORY_MSG_167;Demosaicing method -!HISTORY_MSG_168;L*a*b* - CC curve -!HISTORY_MSG_169;L*a*b* - CH curve -!HISTORY_MSG_170;Vibrance - HH curve -!HISTORY_MSG_171;L*a*b* - LC curve -!HISTORY_MSG_172;L*a*b* - Restrict LC -!HISTORY_MSG_173;NR - Detail recovery -!HISTORY_MSG_175;CAM02 - CAT02 adaptation -!HISTORY_MSG_176;CAM02 - Viewing surround -!HISTORY_MSG_177;CAM02 - Scene luminosity -!HISTORY_MSG_178;CAM02 - Viewing luminosity -!HISTORY_MSG_179;CAM02 - White-point model -!HISTORY_MSG_180;CAM02 - Lightness (J) -!HISTORY_MSG_181;CAM02 - Chroma (C) -!HISTORY_MSG_182;CAM02 - Automatic CAT02 -!HISTORY_MSG_184;CAM02 - Scene surround -!HISTORY_MSG_185;CAM02 - Gamut control -!HISTORY_MSG_186;CAM02 - Algorithm -!HISTORY_MSG_187;CAM02 - Red/skin prot. -!HISTORY_MSG_188;CAM02 - Brightness (Q) -!HISTORY_MSG_189;CAM02 - Contrast (Q) -!HISTORY_MSG_190;CAM02 - Saturation (S) -!HISTORY_MSG_191;CAM02 - Colorfulness (M) -!HISTORY_MSG_192;CAM02 - Hue (h) -!HISTORY_MSG_193;CAM02 - Tone curve 1 -!HISTORY_MSG_194;CAM02 - Tone curve 2 -!HISTORY_MSG_195;CAM02 - Tone curve 1 -!HISTORY_MSG_196;CAM02 - Tone curve 2 -!HISTORY_MSG_197;CAM02 - Color curve -!HISTORY_MSG_198;CAM02 - Color curve -!HISTORY_MSG_199;CAM02 - Output histograms -!HISTORY_MSG_200;CAM02 - Tone mapping -!HISTORY_MSG_201;NR - Chrominance - R&G -!HISTORY_MSG_202;NR - Chrominance - B&Y -!HISTORY_MSG_203;NR - Color space -!HISTORY_MSG_204;LMMSE enhancement steps -!HISTORY_MSG_205;CAM02 - Hot/bad pixel filter -!HISTORY_MSG_206;CAT02 - Auto scene luminosity -!HISTORY_MSG_207;Defringe - Hue curve -!HISTORY_MSG_208;WB - B/R equalizer -!HISTORY_MSG_214;Black-and-White -!HISTORY_MSG_215;B&W - CM - Red -!HISTORY_MSG_216;B&W - CM - Green -!HISTORY_MSG_217;B&W - CM - Blue -!HISTORY_MSG_218;B&W - Gamma - Red -!HISTORY_MSG_219;B&W - Gamma - Green -!HISTORY_MSG_220;B&W - Gamma - Blue -!HISTORY_MSG_221;B&W - Color filter -!HISTORY_MSG_222;B&W - Presets -!HISTORY_MSG_223;B&W - CM - Orange -!HISTORY_MSG_224;B&W - CM - Yellow -!HISTORY_MSG_225;B&W - CM - Cyan -!HISTORY_MSG_226;B&W - CM - Magenta -!HISTORY_MSG_227;B&W - CM - Purple -!HISTORY_MSG_228;B&W - Luminance equalizer -!HISTORY_MSG_229;B&W - Luminance equalizer -!HISTORY_MSG_230;B&W - Mode -!HISTORY_MSG_231;B&W - 'Before' curve -!HISTORY_MSG_232;B&W - 'Before' curve type -!HISTORY_MSG_233;B&W - 'After' curve -!HISTORY_MSG_234;B&W - 'After' curve type -!HISTORY_MSG_235;B&W - CM - Auto -!HISTORY_MSG_236;--unused-- -!HISTORY_MSG_237;B&W - CM -!HISTORY_MSG_238;GF - Feather -!HISTORY_MSG_240;GF - Center -!HISTORY_MSG_241;VF - Feather -!HISTORY_MSG_242;VF - Roundness -!HISTORY_MSG_243;VC - Radius -!HISTORY_MSG_246;L*a*b* - CL curve -!HISTORY_MSG_247;L*a*b* - LH curve -!HISTORY_MSG_248;L*a*b* - HH curve -!HISTORY_MSG_249;CbDL - Threshold -!HISTORY_MSG_250;NR - Enhanced -!HISTORY_MSG_251;B&W - Algorithm -!HISTORY_MSG_252;CbDL - Skin tar/prot -!HISTORY_MSG_253;CbDL - Reduce artifacts -!HISTORY_MSG_254;CbDL - Skin hue -!HISTORY_MSG_255;NR - Median filter -!HISTORY_MSG_256;NR - Median - Type -!HISTORY_MSG_257;Color Toning -!HISTORY_MSG_258;CT - Color curve -!HISTORY_MSG_259;CT - Opacity curve -!HISTORY_MSG_260;CT - a*[b*] opacity -!HISTORY_MSG_261;CT - Method -!HISTORY_MSG_262;CT - b* opacity -!HISTORY_MSG_263;CT - Shadows - Red -!HISTORY_MSG_264;CT - Shadows - Green -!HISTORY_MSG_265;CT - Shadows - Blue -!HISTORY_MSG_266;CT - Mid - Red -!HISTORY_MSG_267;CT - Mid - Green -!HISTORY_MSG_268;CT - Mid - Blue -!HISTORY_MSG_269;CT - High - Red -!HISTORY_MSG_270;CT - High - Green -!HISTORY_MSG_271;CT - High - Blue -!HISTORY_MSG_272;CT - Balance -!HISTORY_MSG_273;CT - Color Balance SMH -!HISTORY_MSG_274;CT - Sat. Shadows -!HISTORY_MSG_275;CT - Sat. Highlights -!HISTORY_MSG_276;CT - Opacity -!HISTORY_MSG_277;--unused-- -!HISTORY_MSG_278;CT - Preserve luminance -!HISTORY_MSG_279;CT - Shadows -!HISTORY_MSG_280;CT - Highlights -!HISTORY_MSG_281;CT - Sat. strength -!HISTORY_MSG_282;CT - Sat. threshold -!HISTORY_MSG_283;CT - Strength -!HISTORY_MSG_284;CT - Auto sat. protection -!HISTORY_MSG_285;NR - Median - Method -!HISTORY_MSG_286;NR - Median - Type -!HISTORY_MSG_287;NR - Median - Iterations -!HISTORY_MSG_288;Flat-Field - Clip control -!HISTORY_MSG_289;Flat-Field - Clip control - Auto -!HISTORY_MSG_290;Black Level - Red -!HISTORY_MSG_291;Black Level - Green -!HISTORY_MSG_292;Black Level - Blue -!HISTORY_MSG_293;Film Simulation -!HISTORY_MSG_294;Film Simulation - Strength -!HISTORY_MSG_295;Film Simulation - Film -!HISTORY_MSG_296;NR - Luminance curve -!HISTORY_MSG_297;NR - Mode -!HISTORY_MSG_298;Dead pixel filter -!HISTORY_MSG_299;NR - Chrominance curve -!HISTORY_MSG_300;- -!HISTORY_MSG_301;NR - Luma control -!HISTORY_MSG_302;NR - Chroma method -!HISTORY_MSG_303;NR - Chroma method -!HISTORY_MSG_304;W - Contrast levels -!HISTORY_MSG_305;Wavelet Levels -!HISTORY_MSG_306;W - Process -!HISTORY_MSG_307;W - Process -!HISTORY_MSG_308;W - Process direction -!HISTORY_MSG_309;W - ES - Detail -!HISTORY_MSG_310;W - Residual - Sky tar/prot -!HISTORY_MSG_311;W - Wavelet levels -!HISTORY_MSG_312;W - Residual - Shadows threshold -!HISTORY_MSG_313;W - Chroma - Sat/past -!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_322;W - Gamut - Avoid color shift -!HISTORY_MSG_323;W - ES - Local contrast -!HISTORY_MSG_324;W - Chroma - Pastel -!HISTORY_MSG_325;W - Chroma - Saturated -!HISTORY_MSG_326;W - Chroma - Method -!HISTORY_MSG_327;W - Contrast - Apply to -!HISTORY_MSG_328;W - Chroma - Link strength -!HISTORY_MSG_329;W - Toning - Opacity RG -!HISTORY_MSG_330;W - Toning - Opacity BY -!HISTORY_MSG_331;W - Contrast levels - Extra -!HISTORY_MSG_332;W - Tiling method -!HISTORY_MSG_333;W - Residual - Shadows -!HISTORY_MSG_334;W - Residual - Chroma -!HISTORY_MSG_335;W - Residual - Highlights -!HISTORY_MSG_336;W - Residual - Highlights threshold -!HISTORY_MSG_337;W - Residual - Sky hue -!HISTORY_MSG_338;W - ES - Radius -!HISTORY_MSG_339;W - ES - Strength -!HISTORY_MSG_340;W - Strength -!HISTORY_MSG_341;W - Edge performance -!HISTORY_MSG_342;W - ES - First level -!HISTORY_MSG_343;W - Chroma levels -!HISTORY_MSG_344;W - Meth chroma sl/cur -!HISTORY_MSG_345;W - ES - Local contrast -!HISTORY_MSG_346;W - ES - Local contrast method -!HISTORY_MSG_347;W - Denoise - Level 1 -!HISTORY_MSG_348;W - Denoise - Level 2 -!HISTORY_MSG_349;W - Denoise - Level 3 -!HISTORY_MSG_350;W - ES - Edge detection -!HISTORY_MSG_351;W - Residual - HH curve -!HISTORY_MSG_352;W - Background -!HISTORY_MSG_353;W - ES - Gradient sensitivity -!HISTORY_MSG_354;W - ES - Enhanced -!HISTORY_MSG_355;W - ES - Threshold low -!HISTORY_MSG_356;W - ES - Threshold high -!HISTORY_MSG_357;W - Denoise - Link with ES -!HISTORY_MSG_358;W - Gamut - CH -!HISTORY_MSG_359;Hot/Dead - Threshold -!HISTORY_MSG_360;TM - Gamma -!HISTORY_MSG_361;W - Final - Chroma balance -!HISTORY_MSG_362;W - Residual - Compression method -!HISTORY_MSG_363;W - Residual - Compression strength -!HISTORY_MSG_364;W - Final - Contrast balance -!HISTORY_MSG_365;W - Final - Delta balance -!HISTORY_MSG_366;W - Residual - Compression gamma -!HISTORY_MSG_367;W - Final - 'After' contrast curve -!HISTORY_MSG_368;W - Final - Contrast balance -!HISTORY_MSG_369;W - Final - Balance method -!HISTORY_MSG_370;W - Final - Local contrast curve -!HISTORY_MSG_371;Post-Resize Sharpening -!HISTORY_MSG_372;PRS USM - Radius -!HISTORY_MSG_373;PRS USM - Amount -!HISTORY_MSG_374;PRS USM - Threshold -!HISTORY_MSG_375;PRS USM - Sharpen only edges -!HISTORY_MSG_376;PRS USM - Edge detection radius -!HISTORY_MSG_377;PRS USM - Edge tolerance -!HISTORY_MSG_378;PRS USM - Halo control -!HISTORY_MSG_379;PRS USM - Halo control amount -!HISTORY_MSG_380;PRS - Method -!HISTORY_MSG_381;PRS RLD - Radius -!HISTORY_MSG_382;PRS RLD - Amount -!HISTORY_MSG_383;PRS RLD - Damping -!HISTORY_MSG_384;PRS RLD - Iterations -!HISTORY_MSG_385;W - Residual - Color Balance -!HISTORY_MSG_386;W - Residual - CB green high -!HISTORY_MSG_387;W - Residual - CB blue high -!HISTORY_MSG_388;W - Residual - CB green mid -!HISTORY_MSG_389;W - Residual - CB blue mid -!HISTORY_MSG_390;W - Residual - CB green low -!HISTORY_MSG_391;W - Residual - CB blue low -!HISTORY_MSG_392;W - Residual - Color Balance -!HISTORY_MSG_393;DCP - Look table -!HISTORY_MSG_394;DCP - Baseline exposure -!HISTORY_MSG_395;DCP - Base table -!HISTORY_MSG_396;W - Contrast sub-tool -!HISTORY_MSG_397;W - Chroma sub-tool -!HISTORY_MSG_398;W - ES sub-tool -!HISTORY_MSG_399;W - Residual sub-tool -!HISTORY_MSG_400;W - Final sub-tool -!HISTORY_MSG_401;W - Toning sub-tool -!HISTORY_MSG_402;W - Denoise sub-tool -!HISTORY_MSG_403;W - ES - Edge sensitivity -!HISTORY_MSG_404;W - ES - Base amplification -!HISTORY_MSG_405;W - Denoise - Level 4 -!HISTORY_MSG_406;W - ES - Neighboring pixels -!HISTORY_MSG_407;Retinex - Method -!HISTORY_MSG_408;Retinex - Radius -!HISTORY_MSG_409;Retinex - Contrast -!HISTORY_MSG_410;Retinex - Offset -!HISTORY_MSG_411;Retinex - Strength -!HISTORY_MSG_412;Retinex - Gaussian gradient -!HISTORY_MSG_413;Retinex - Contrast -!HISTORY_MSG_414;Retinex - Histogram - Lab -!HISTORY_MSG_415;Retinex - Transmission -!HISTORY_MSG_416;Retinex -!HISTORY_MSG_417;Retinex - Transmission median -!HISTORY_MSG_418;Retinex - Threshold -!HISTORY_MSG_419;Retinex - Color space -!HISTORY_MSG_420;Retinex - Histogram - HSL -!HISTORY_MSG_421;Retinex - Gamma -!HISTORY_MSG_422;Retinex - Gamma -!HISTORY_MSG_423;Retinex - Gamma slope -!HISTORY_MSG_424;Retinex - HL threshold -!HISTORY_MSG_425;Retinex - Log base -!HISTORY_MSG_426;Retinex - Hue equalizer -!HISTORY_MSG_427;Output rendering intent -!HISTORY_MSG_428;Monitor rendering intent -!HISTORY_MSG_429;Retinex - Iterations -!HISTORY_MSG_430;Retinex - Transmission gradient -!HISTORY_MSG_431;Retinex - Strength gradient -!HISTORY_MSG_432;Retinex - M - Highlights -!HISTORY_MSG_433;Retinex - M - Highlights TW -!HISTORY_MSG_434;Retinex - M - Shadows -!HISTORY_MSG_435;Retinex - M - Shadows TW -!HISTORY_MSG_436;Retinex - M - Radius -!HISTORY_MSG_437;Retinex - M - Method -!HISTORY_MSG_438;Retinex - M - Equalizer -!HISTORY_MSG_439;Retinex - Process -!HISTORY_MSG_440;CbDL - Method -!HISTORY_MSG_441;Retinex - Gain transmission -!HISTORY_MSG_442;Retinex - Scale -!HISTORY_MSG_443;Output black point compensation -!HISTORY_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_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: -!IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider. -!IPTCPANEL_CITYHINT;Enter the name of the city pictured in this image. -!IPTCPANEL_COPYRIGHT;Copyright notice -!IPTCPANEL_COPYRIGHTHINT;Enter a Notice on the current owner of the Copyright for this image, such as ©2008 Jane Doe. -!IPTCPANEL_COUNTRYHINT;Enter the name of the country pictured in this image. -!IPTCPANEL_CREATOR;Creator -!IPTCPANEL_CREATORHINT;Enter the name of the person that created this image. -!IPTCPANEL_CREATORJOBTITLE;Creator's job title -!IPTCPANEL_CREATORJOBTITLEHINT;Enter the Job Title of the person listed in the Creator field. -!IPTCPANEL_DATECREATEDHINT;Enter the Date the image was taken. -!IPTCPANEL_DESCRIPTION;Description -!IPTCPANEL_DESCRIPTIONHINT;Enter a "caption" describing the who, what, and why of what is happening in this image, this might include names of people, and/or their role in the action that is taking place within the image. -!IPTCPANEL_DESCRIPTIONWRITER;Description writer -!IPTCPANEL_DESCRIPTIONWRITERHINT;Enter the name of the person involved in writing, editing or correcting the description of the image. -!IPTCPANEL_HEADLINEHINT;Enter a brief publishable synopsis or summary of the contents of the image. -!IPTCPANEL_INSTRUCTIONSHINT;Enter information about embargoes, or other restrictions not covered by the Copyright field. -!IPTCPANEL_KEYWORDSHINT;Enter any number of keywords, terms or phrases used to express the subject matter in the image. -!IPTCPANEL_PROVINCE;Province or state -!IPTCPANEL_PROVINCEHINT;Enter the name of the province or state pictured in this image. -!IPTCPANEL_SOURCEHINT;Enter or edit the name of a person or party who has a role in the content supply chain, such as a person or entity from whom you received this image from. -!IPTCPANEL_SUPPCATEGORIES;Supplemental categories -!IPTCPANEL_SUPPCATEGORIESHINT;Further refines the subject of the image. -!IPTCPANEL_TITLEHINT;Enter a short verbal and human readable name for the image, this may be the file name. -!IPTCPANEL_TRANSREFERENCE;Job ID -!IPTCPANEL_TRANSREFERENCEHINT;Enter a number or identifier needed for workflow control or tracking. -!MAIN_BUTTON_ICCPROFCREATOR;ICC Profile Creator -!MAIN_BUTTON_NAVNEXT_TOOLTIP;Navigate to the next image relative to image opened in the Editor.\nShortcut: Shift-F4\n\nTo navigate to the next image relative to the currently selected thumbnail in the File Browser or Filmstrip:\nShortcut: F4 -!MAIN_BUTTON_NAVPREV_TOOLTIP;Navigate to the previous image relative to image opened in the Editor.\nShortcut: Shift-F3\n\nTo navigate to the previous image relative to the currently selected thumbnail in the File Browser or Filmstrip:\nShortcut: F3 -!MAIN_BUTTON_NAVSYNC_TOOLTIP;Synchronize the File Browser or Filmstrip with the Editor to reveal the thumbnail of the currently opened image, and clear any active filters.\nShortcut: x\n\nAs above, but without clearing active filters:\nShortcut: y\n(Note that the thumbnail of the opened image will not be shown if filtered out). -!MAIN_FRAME_PLACES_DEL;Remove -!MAIN_MSG_IMAGEUNPROCESSED;This command requires all selected images to be queue-processed first. -!MAIN_MSG_PATHDOESNTEXIST;The path\n\n%1\n\ndoes not exist. Please set a correct path in Preferences. -!MAIN_MSG_SETPATHFIRST;You first have to set a target path in Preferences in order to use this function! -!MAIN_MSG_TOOMANYOPENEDITORS;Too many open editors.\nPlease close an editor to continue. -!MAIN_MSG_WRITEFAILED;Failed to write\n"%1"\n\nMake sure that the folder exists and that you have write permission to it. -!MAIN_TAB_ADVANCED;Advanced -!MAIN_TAB_ADVANCED_TOOLTIP;Shortcut: Alt-a -!MAIN_TAB_FAVORITES;Favorites -!MAIN_TAB_FAVORITES_TOOLTIP;Shortcut: Alt-u -!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_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_PREVIEWB;Preview the blue channel.\nShortcut: b -!MAIN_TOOLTIP_PREVIEWFOCUSMASK;Preview the focus mask.\nShortcut: Shift-f\n\nMore accurate on images with shallow depth of field, low noise and at higher zoom levels.\nZoom out to 10-30% to improve detection accuracy on noisy images. -!MAIN_TOOLTIP_PREVIEWG;Preview the green channel.\nShortcut: g -!MAIN_TOOLTIP_PREVIEWL;Preview the luminosity.\nShortcut: v\n\n0.299*R + 0.587*G + 0.114*B -!MAIN_TOOLTIP_PREVIEWSHARPMASK;Preview the sharpening contrast mask.\nShortcut: p\n\nOnly works when sharpening is enabled and zoom >= 100%. -!MONITOR_PROFILE_SYSTEM;System default -!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_BEHADDALLHINT;Set all parameters to the Add mode.\nAdjustments of parameters in the batch tool panel will be deltas to the stored values. -!PREFERENCES_BEHSETALLHINT;Set all parameters to the Set mode.\nAdjustments of parameters in the batch tool panel will be absolute, the actual values will be displayed. -!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_CUSTPROFBUILDHINT;Executable (or script) file called when a new initial processing profile should be generated for an image.\n\nThe path of the communication file (*.ini style, a.k.a. "Keyfile") is added as a command line parameter. It contains various parameters required for the scripts and image Exif to allow a rules-based processing profile generation.\n\nWARNING: You are responsible for using double quotes where necessary if you're using paths containing spaces. -!PREFERENCES_DIRECTORIES;Directories -!PREFERENCES_EDITORCMDLINE;Custom command line -!PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser -!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_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 -!PROFILEPANEL_COPYPPASTE;Parameters to copy -!PROFILEPANEL_GLOBALPROFILES;Bundled profiles -!PROFILEPANEL_LOADPPASTE;Parameters to load -!PROFILEPANEL_MODE_TIP;Processing profile fill mode.\n\nButton pressed: partial profiles will be converted to full profiles; the missing values will be replaced with hard-coded defaults.\n\nButton released: profiles will be applied as they are, altering only those values which they contain. -!PROFILEPANEL_PASTEPPASTE;Parameters to paste -!PROFILEPANEL_PDYNAMIC;Dynamic -!PROFILEPANEL_PINTERNAL;Neutral -!PROFILEPANEL_SAVEPPASTE;Parameters to save -!PROGRESSBAR_DECODING;Decoding... -!PROGRESSBAR_GREENEQUIL;Green equilibration... -!PROGRESSBAR_HLREC;Highlight reconstruction... -!PROGRESSBAR_HOTDEADPIXELFILTER;Hot/dead pixel filter... -!PROGRESSBAR_LINEDENOISE;Line noise filter... -!PROGRESSBAR_PROCESSING_PROFILESAVED;Processing profile saved -!PROGRESSBAR_RAWCACORR;Raw CA correction... -!PROGRESSBAR_SNAPSHOT_ADDED;Snapshot added -!PROGRESSDLG_PROFILECHANGEDINBROWSER;Processing profile changed in browser -!QINFO_FRAMECOUNT;%2 frames -!QINFO_HDR;HDR / %2 frame(s) -!QINFO_PIXELSHIFT;Pixel Shift / %2 frame(s) -!QUEUE_AUTOSTART_TOOLTIP;Start processing automatically when a new job arrives. -!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 -!SAVEDLG_SUBSAMP_TOOLTIP;Best compression:\nJ:a:b 4:2:0\nh/v 2/2\nChroma halved horizontally and vertically.\n\nBalanced:\nJ:a:b 4:2:2\nh/v 2/1\nChroma halved horizontally.\n\nBest quality:\nJ:a:b 4:4:4\nh/v 1/1\nNo chroma subsampling. -!SHCSELECTOR_TOOLTIP;Click right mouse button to reset the position of those 3 sliders. -!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. -!THRESHOLDSELECTOR_B;Bottom -!THRESHOLDSELECTOR_BL;Bottom-left -!THRESHOLDSELECTOR_BR;Bottom-right -!THRESHOLDSELECTOR_HINT;Hold the Shift key to move individual control points. -!THRESHOLDSELECTOR_T;Top -!THRESHOLDSELECTOR_TL;Top-left -!THRESHOLDSELECTOR_TR;Top-right -!TOOLBAR_TOOLTIP_COLORPICKER;Lockable Color Picker\n\nWhen the tool is active:\n- Add a picker: left-click.\n- Drag a picker: left-click and drag.\n- Delete a picker: right-click.\n- Delete all pickers: Ctrl+Shift+right-click.\n- Revert to hand tool: right-click outside any picker. -!TP_BWMIX_ALGO;Algorithm OYCPM -!TP_BWMIX_ALGO_TOOLTIP;Linear: will produce a normal linear response.\nSpecial effects: will produce special effects by mixing channels non-linearly. -!TP_BWMIX_CC_ENABLED;Adjust complementary color -!TP_BWMIX_CC_TOOLTIP;Enable to allow automatic adjustment of complementary colors in ROYGCBPM mode. -!TP_BWMIX_CHANNEL;Luminance equalizer -!TP_BWMIX_CURVEEDITOR1;'Before' curve -!TP_BWMIX_CURVEEDITOR2;'After' curve -!TP_BWMIX_CURVEEDITOR_AFTER_TOOLTIP;Tone curve, after B&W conversion, at the end of treatment. -!TP_BWMIX_CURVEEDITOR_BEFORE_TOOLTIP;Tone curve, just before B&W conversion.\nMay take into account the color components. -!TP_BWMIX_CURVEEDITOR_LH_TOOLTIP;Luminance according to hue L=f(H).\nPay attention to extreme values as they may cause artifacts. -!TP_BWMIX_FILTER_TOOLTIP;The color filter simulates shots taken with a colored filter placed in front of the lens. Colored filters reduce the transmission of specific color ranges and therefore affect their lightness. E.g. a red filter darkens blue skies. -!TP_BWMIX_MET_CHANMIX;Channel Mixer -!TP_BWMIX_MIXC;Channel Mixer -!TP_BWMIX_NEUTRAL;Reset -!TP_BWMIX_RGBLABEL;R: %1%% G: %2%% B: %3%% Total: %4%% -!TP_BWMIX_RGBLABEL_HINT;Final RGB factors that take care of all the mixer options.\n"Total" displays the sum of the RGB values:\n- always 100% in relative mode\n- higher (lighter) or lower (darker) than 100% in absolute mode. -!TP_BWMIX_RGB_TOOLTIP;Mix the RGB channels. Use presets for guidance.\nPay attention to negative values that may cause artifacts or erratic behavior. -!TP_BWMIX_SET_HYPERPANCHRO;Hyper Panchromatic -!TP_BWMIX_SET_NORMCONTAST;Normal Contrast -!TP_BWMIX_SET_ORTHOCHRO;Orthochromatic -!TP_BWMIX_SET_RGBABS;Absolute RGB -!TP_BWMIX_SET_RGBREL;Relative RGB -!TP_BWMIX_SET_ROYGCBPMABS;Absolute ROYGCBPM -!TP_BWMIX_SET_ROYGCBPMREL;Relative ROYGCBPM -!TP_BWMIX_TCMODE_SATANDVALBLENDING;B&W Saturation and Value Blending -!TP_BWMIX_TCMODE_WEIGHTEDSTD;B&W Weighted Standard -!TP_CBDL_AFT;After Black-and-White -!TP_CBDL_BEF;Before Black-and-White -!TP_CBDL_METHOD;Process located -!TP_CBDL_METHOD_TOOLTIP;Choose whether the Contrast by Detail Levels tool is to be positioned after the Black-and-White tool, which makes it work in L*a*b* space, or before it, which makes it work in RGB space. -!TP_COLORAPP_ABSOLUTELUMINANCE;Absolute luminance -!TP_COLORAPP_ALGO;Algorithm -!TP_COLORAPP_ALGO_ALL;All -!TP_COLORAPP_ALGO_JC;Lightness + Chroma (JC) -!TP_COLORAPP_ALGO_JS;Lightness + Saturation (JS) -!TP_COLORAPP_ALGO_QM;Brightness + Colorfulness (QM) -!TP_COLORAPP_ALGO_TOOLTIP;Lets you choose between parameter subsets or all parameters. -!TP_COLORAPP_BADPIXSL;Hot/bad pixel filter -!TP_COLORAPP_BADPIXSL_TOOLTIP;Suppression of hot/bad (brightly colored) pixels.\n0 = No effect\n1 = Median\n2 = Gaussian.\nAlternatively, adjust the image to avoid very dark shadows.\n\nThese artifacts are due to limitations of CIECAM02. -!TP_COLORAPP_BRIGHT;Brightness (Q) -!TP_COLORAPP_BRIGHT_TOOLTIP;Brightness in CIECAM02 takes into account the white's luminosity and differs from L*a*b* and RGB brightness. -!TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;When setting manually, values above 65 are recommended. -!TP_COLORAPP_CHROMA;Chroma (C) -!TP_COLORAPP_CHROMA_M;Colorfulness (M) -!TP_COLORAPP_CHROMA_M_TOOLTIP;Colorfulness in CIECAM02 differs from L*a*b* and RGB colorfulness. -!TP_COLORAPP_CHROMA_S;Saturation (S) -!TP_COLORAPP_CHROMA_S_TOOLTIP;Saturation in CIECAM02 differs from L*a*b* and RGB saturation. -!TP_COLORAPP_CHROMA_TOOLTIP;Chroma in CIECAM02 differs from L*a*b* and RGB chroma. -!TP_COLORAPP_CIECAT_DEGREE;CAT02 adaptation -!TP_COLORAPP_CONTRAST;Contrast (J) -!TP_COLORAPP_CONTRAST_Q;Contrast (Q) -!TP_COLORAPP_CONTRAST_Q_TOOLTIP;Differs from L*a*b* and RGB contrast. -!TP_COLORAPP_CONTRAST_TOOLTIP;Differs from L*a*b* and RGB contrast. -!TP_COLORAPP_CURVEEDITOR1;Tone curve 1 -!TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Shows the histogram of L* (L*a*b*) before CIECAM02.\nIf the "Show CIECAM02 output histograms in curves" checkbox is enabled, shows the histogram of J or Q after CIECAM02.\n\nJ and Q are not shown in the main histogram panel.\n\nFor final output refer to the main histogram panel. -!TP_COLORAPP_CURVEEDITOR2;Tone curve 2 -!TP_COLORAPP_CURVEEDITOR2_TOOLTIP;Same usage as with the second exposure tone curve. -!TP_COLORAPP_CURVEEDITOR3;Color curve -!TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Adjust either chroma, saturation or colorfulness.\n\nShows the histogram of chromaticity (L*a*b*) before CIECAM02.\nIf the "Show CIECAM02 output histograms in curves" checkbox is enabled, shows the histogram of C, s or M after CIECAM02.\n\nC, s and M are not shown in the main histogram panel.\nFor final output refer to the main histogram panel. -!TP_COLORAPP_DATACIE;CIECAM02 output histograms in curves -!TP_COLORAPP_DATACIE_TOOLTIP;When enabled, histograms in CIECAM02 curves show approximate values/ranges for J or Q, and C, s or M after the CIECAM02 adjustments.\nThis selection does not impact the main histogram panel.\n\nWhen disabled, histograms in CIECAM02 curves show L*a*b* values before CIECAM02 adjustments. -!TP_COLORAPP_FREE;Free temp+green + CAT02 + [output] -!TP_COLORAPP_GAMUT;Gamut control (L*a*b*) -!TP_COLORAPP_GAMUT_TOOLTIP;Allow gamut control in L*a*b* mode. -!TP_COLORAPP_HUE;Hue (h) -!TP_COLORAPP_HUE_TOOLTIP;Hue (h) - angle between 0° and 360°. -!TP_COLORAPP_LABEL;CIE Color Appearance Model 2002 -!TP_COLORAPP_LABEL_SCENE;Scene Conditions -!TP_COLORAPP_LABEL_VIEWING;Viewing Conditions -!TP_COLORAPP_MEANLUMINANCE;Mean luminance (Yb%) -!TP_COLORAPP_MODEL;WP Model -!TP_COLORAPP_MODEL_TOOLTIP;White-Point Model.\n\nWB [RT] + [output]: RT's white balance is used for the scene, CIECAM02 is set to D50, and the output device's white balance is set in Viewing Conditions.\n\nWB [RT+CAT02] + [output]: RT's white balance settings are used by CAT02 and the output device's white balance is set in Viewing Conditions.\n\nFree temp+green + CAT02 + [output]: temp and green are selected by the user, the output device's white balance is set in Viewing Conditions. -!TP_COLORAPP_NEUTRAL;Reset -!TP_COLORAPP_NEUTRAL_TIP;Reset all sliders checkbox and curves to their default values -!TP_COLORAPP_RSTPRO;Red & skin-tones protection -!TP_COLORAPP_RSTPRO_TOOLTIP;Red & skin-tones protection affects both sliders and curves. -!TP_COLORAPP_SURROUND;Surround -!TP_COLORAPP_SURROUND_EXDARK;Extremly Dark (Cutsheet) -!TP_COLORAPP_SURROUND_TOOLTIP;Changes tones and colors to take into account the viewing conditions of the output device.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment (TV). The image will become slightly dark.\n\nDark: Dark environment (projector). The image will become more dark.\n\nExtremly Dark: Extremly dark environment (cutsheet). The image will become very dark. -!TP_COLORAPP_TCMODE_CHROMA;Chroma -!TP_COLORAPP_TCMODE_COLORF;Colorfulness -!TP_COLORAPP_TCMODE_LABEL1;Curve mode 1 -!TP_COLORAPP_TCMODE_LABEL2;Curve mode 2 -!TP_COLORAPP_TCMODE_LABEL3;Curve chroma mode -!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_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²). -!TP_COLORAPP_WBCAM;WB [RT+CAT02] + [output] -!TP_COLORAPP_WBRT;WB [RT] + [output] -!TP_COLORTONING_AB;o C/L -!TP_COLORTONING_AUTOSAT;Automatic -!TP_COLORTONING_BALANCE;Balance -!TP_COLORTONING_BY;o C/L -!TP_COLORTONING_CHROMAC;Opacity -!TP_COLORTONING_COLOR;Color -!TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP;Chroma opacity as a function of luminance oC=f(L) -!TP_COLORTONING_HIGHLIGHT;Highlights -!TP_COLORTONING_HUE;Hue -!TP_COLORTONING_LAB;L*a*b* blending -!TP_COLORTONING_LABEL;Color Toning -!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_COLORTONING_LUMA;Luminance -!TP_COLORTONING_LUMAMODE;Preserve luminance -!TP_COLORTONING_LUMAMODE_TOOLTIP;If enabled, when you change color (red, green, cyan, blue, etc.) the luminance of each pixel is preserved. -!TP_COLORTONING_METHOD;Method -!TP_COLORTONING_METHOD_TOOLTIP;"L*a*b* blending", "RGB sliders" and "RGB curves" use interpolated color blending.\n"Color balance (Shadows/Midtones/Highlights)" and "Saturation 2 colors" use direct colors.\n\nThe Black-and-White tool can be enabled when using any color toning method, which allows for color toning. -!TP_COLORTONING_MIDTONES;Midtones -!TP_COLORTONING_NEUTRAL;Reset sliders -!TP_COLORTONING_NEUTRAL_TIP;Reset all values (Shadows, Midtones, Highlights) to default. -!TP_COLORTONING_OPACITY;Opacity -!TP_COLORTONING_RGBCURVES;RGB - Curves -!TP_COLORTONING_RGBSLIDERS;RGB - Sliders -!TP_COLORTONING_SA;Saturation Protection -!TP_COLORTONING_SATURATEDOPACITY;Strength -!TP_COLORTONING_SATURATIONTHRESHOLD;Threshold -!TP_COLORTONING_SHADOWS;Shadows -!TP_COLORTONING_SPLITCO;Shadows/Midtones/Highlights -!TP_COLORTONING_SPLITCOCO;Color Balance Shadows/Midtones/Highlights -!TP_COLORTONING_SPLITLR;Saturation 2 colors -!TP_COLORTONING_STR;Strength -!TP_COLORTONING_STRENGTH;Strength -!TP_COLORTONING_TWO2;Special chroma '2 colors' -!TP_COLORTONING_TWOALL;Special chroma -!TP_COLORTONING_TWOBY;Special a* and b* -!TP_COLORTONING_TWOCOLOR_TOOLTIP;Standard chroma:\nLinear response, a* = b*.\n\nSpecial chroma:\nLinear response, a* = b*, but unbound - try under the diagonal.\n\nSpecial a* and b*:\nLinear response unbound with separate curves for a* and b*. Intended for special effects.\n\nSpecial chroma 2 colors:\nMore predictable. -!TP_COLORTONING_TWOSTD;Standard chroma -!TP_CROP_PPI;PPI -!TP_CROP_RESETCROP;Reset -!TP_CROP_SELECTCROP;Select -!TP_DEFRINGE_THRESHOLD;Threshold -!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_AMZ;Auto multi-zones -!TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL;Automatic global -!TP_DIRPYRDENOISE_CHROMINANCE_BLUEYELLOW;Chrominance - Blue-Yellow -!TP_DIRPYRDENOISE_CHROMINANCE_CURVE;Chrominance curve -!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_CHROMINANCE_FRAME;Chrominance -!TP_DIRPYRDENOISE_CHROMINANCE_MANUAL;Manual -!TP_DIRPYRDENOISE_CHROMINANCE_MASTER;Chrominance - Master -!TP_DIRPYRDENOISE_CHROMINANCE_METHOD;Method -!TP_DIRPYRDENOISE_CHROMINANCE_METHODADVANCED_TOOLTIP;Manual\nActs on the full image.\nYou control the noise reduction settings manually.\n\nAutomatic global\nActs on the full image.\n9 zones are used to calculate a global chrominance noise reduction setting.\n\nPreview\nActs on the whole image.\nThe part of the image visible in the preview is used to calculate global chrominance noise reduction settings. -!TP_DIRPYRDENOISE_CHROMINANCE_METHOD_TOOLTIP;Manual\nActs on the full image.\nYou control the noise reduction settings manually.\n\nAutomatic global\nActs on the full image.\n9 zones are used to calculate a global chrominance noise reduction setting.\n\nAutomatic multi-zones\nNo preview - works only during saving, but using the "Preview" method by matching the tile size and center to the preview size and center you can get an idea of the expected results.\nThe image is divided into tiles (about 10 to 70 depending on image size) and each tile receives its own chrominance noise reduction settings.\n\nPreview\nActs on the whole image.\nThe part of the image visible in the preview is used to calculate global chrominance noise reduction settings. -!TP_DIRPYRDENOISE_CHROMINANCE_PMZ;Preview multi-zones -!TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW;Preview -!TP_DIRPYRDENOISE_CHROMINANCE_PREVIEWRESIDUAL_INFO_TOOLTIP;Displays the remaining noise levels of the part of the image visible in the preview after wavelet.\n\n>300 Very noisy\n100-300 Noisy\n50-100 A little noisy\n<50 Very low noise\n\nBeware, the values will differ between RGB and L*a*b* mode. The RGB values are less accurate because the RGB mode does not completely separate luminance and chrominance. -!TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_INFO;Preview size=%1, Center: Px=%2 Py=%3 -!TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_NOISEINFO;Preview noise: Mean=%1 High=%2 -!TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_NOISEINFO_EMPTY;Preview noise: Mean= - High= - -!TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_TILEINFO;Tile size=%1, Center: Tx=%2 Ty=%3 -!TP_DIRPYRDENOISE_CHROMINANCE_REDGREEN;Chrominance - Red-Green -!TP_DIRPYRDENOISE_LABEL;Noise Reduction -!TP_DIRPYRDENOISE_LUMINANCE_CONTROL;Luminance control -!TP_DIRPYRDENOISE_LUMINANCE_CURVE;Luminance curve -!TP_DIRPYRDENOISE_LUMINANCE_FRAME;Luminance -!TP_DIRPYRDENOISE_MAIN_COLORSPACE;Color space -!TP_DIRPYRDENOISE_MAIN_COLORSPACE_LAB;L*a*b* -!TP_DIRPYRDENOISE_MAIN_COLORSPACE_TOOLTIP;For raw images either RGB or L*a*b* methods can be used.\n\nFor non-raw images the L*a*b* method will be used, regardless of the selection. -!TP_DIRPYRDENOISE_MAIN_GAMMA;Gamma -!TP_DIRPYRDENOISE_MAIN_GAMMA_TOOLTIP;Gamma varies noise reduction strength across the range of tones. Smaller values will target shadows, while larger values will stretch the effect to the brighter tones. -!TP_DIRPYRDENOISE_MAIN_MODE;Mode -!TP_DIRPYRDENOISE_MAIN_MODE_AGGRESSIVE;Aggressive -!TP_DIRPYRDENOISE_MAIN_MODE_CONSERVATIVE;Conservative -!TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;"Conservative" preserves low frequency chroma patterns, while "aggressive" obliterates them. -!TP_DIRPYRDENOISE_MEDIAN_METHOD;Median method -!TP_DIRPYRDENOISE_MEDIAN_METHOD_CHROMINANCE;Chroma only -!TP_DIRPYRDENOISE_MEDIAN_METHOD_LAB;L*a*b* -!TP_DIRPYRDENOISE_MEDIAN_METHOD_LABEL;Median Filter -!TP_DIRPYRDENOISE_MEDIAN_METHOD_LUMINANCE;Luminance only -!TP_DIRPYRDENOISE_MEDIAN_METHOD_RGB;RGB -!TP_DIRPYRDENOISE_MEDIAN_METHOD_TOOLTIP;When using the "Luminance only" and "L*a*b*" methods, median filtering will be performed just after the wavelet step in the noise reduction pipeline.\nWhen using the "RGB" mode, it will be performed at the very end of the noise reduction pipeline. -!TP_DIRPYRDENOISE_MEDIAN_METHOD_WEIGHTED;Weighted L* (little) + a*b* (normal) -!TP_DIRPYRDENOISE_MEDIAN_PASSES;Median iterations -!TP_DIRPYRDENOISE_MEDIAN_PASSES_TOOLTIP;Applying three median filter iterations with a 3×3 window size often leads to better results than using one median filter iteration with a 7×7 window size. -!TP_DIRPYRDENOISE_MEDIAN_TYPE;Median type -!TP_DIRPYRDENOISE_MEDIAN_TYPE_TOOLTIP;Apply a median filter of the desired window size. The larger the window's size, the longer it takes.\n\n3×3 soft: treats 5 pixels in a 3×3 pixel window.\n3×3: treats 9 pixels in a 3×3 pixel window.\n5×5 soft: treats 13 pixels in a 5×5 pixel window.\n5×5: treats 25 pixels in a 5×5 pixel window.\n7×7: treats 49 pixels in a 7×7 pixel window.\n9×9: treats 81 pixels in a 9×9 pixel window.\n\nSometimes it is possible to achieve higher quality running several iterations with a smaller window size than one iteration with a larger one. -!TP_DIRPYRDENOISE_TYPE_3X3;3×3 -!TP_DIRPYRDENOISE_TYPE_3X3SOFT;3×3 soft -!TP_DIRPYRDENOISE_TYPE_5X5;5×5 -!TP_DIRPYRDENOISE_TYPE_5X5SOFT;5×5 soft -!TP_DIRPYRDENOISE_TYPE_7X7;7×7 -!TP_DIRPYRDENOISE_TYPE_9X9;9×9 -!TP_DIRPYREQUALIZER_ALGO_TOOLTIP;Fine: closer to the colors of the skin, minimizing the action on other colors\nLarge: avoid more artifacts. -!TP_DIRPYREQUALIZER_HUESKIN_TOOLTIP;This pyramid is for the upper part, so far as the algorithm at its maximum efficiency.\nTo the lower part, the transition zones.\nIf you need to move the area significantly to the left or right - or if there are artifacts: the white balance is incorrect\nYou can slightly reduce the zone to prevent the rest of the image is affected. -!TP_DIRPYREQUALIZER_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_DIRPYREQUALIZER_TOOLTIP;Attempts to reduce artifacts in the transitions between skin colors (hue, chroma, luma) and the rest of the image. -!TP_DISTORTION_AUTO_TIP;Automatically corrects lens distortion in raw files by matching it against the embedded JPEG image if one exists and has had its lens disortion auto-corrected by the camera. -!TP_EPD_EDGESTOPPING;Edge stopping -!TP_EPD_GAMMA;Gamma -!TP_EPD_REWEIGHTINGITERATES;Reweighting iterates -!TP_EXPOSURE_AUTOLEVELS_TIP;Toggles execution of Auto Levels to automatically set Exposure slider values based on an image analysis.\nEnables Highlight Reconstruction if necessary. -!TP_EXPOSURE_CLAMPOOG;Clip out-of-gamut colors -!TP_EXPOSURE_CLIP_TIP;The fraction of pixels to be clipped in Auto Levels operation. -!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_EXPOSURE_TCMODE_LUMINANCE;Luminance -!TP_EXPOSURE_TCMODE_PERCEPTUAL;Perceptual -!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points -!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points -!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_FILMSIMULATION_LABEL;Film Simulation -!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now? -!TP_FILMSIMULATION_STRENGTH;Strength -!TP_FILMSIMULATION_ZEROCLUTSFOUND;Set HaldCLUT directory in Preferences -!TP_FLATFIELD_CLIPCONTROL;Clip control -!TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Clip control avoids clipped highlights caused by applying the flat field. If there are already clipped highlights before applying the flat field, value 0 is used. -!TP_GENERAL_11SCALE_TOOLTIP;The effects of this tool are only visible or only accurate at a preview scale of 1:1. -!TP_GRADIENT_CENTER_X_TOOLTIP;Shift gradient to the left (negative values) or right (positive values). -!TP_GRADIENT_CENTER_Y_TOOLTIP;Shift gradient up (negative values) or down (positive values). -!TP_GRADIENT_STRENGTH_TOOLTIP;Filter strength in stops. -!TP_HLREC_ENA_TOOLTIP;Could be activated by Auto Levels. -!TP_ICM_APPLYBASELINEEXPOSUREOFFSET;Baseline exposure -!TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP;Employ the embedded DCP baseline exposure offset. The setting is only available if the selected DCP has one. -!TP_ICM_APPLYHUESATMAP;Base table -!TP_ICM_APPLYHUESATMAP_TOOLTIP;Employ the embedded DCP base table (HueSatMap). The setting is only available if the selected DCP has one. -!TP_ICM_APPLYLOOKTABLE;Look table -!TP_ICM_APPLYLOOKTABLE_TOOLTIP;Employ the embedded DCP look table. The setting is only available if the selected DCP has one. -!TP_ICM_BPC;Black Point Compensation -!TP_ICM_DCPILLUMINANT;Illuminant -!TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolated -!TP_ICM_DCPILLUMINANT_TOOLTIP;Select which embedded DCP illuminant to employ. Default is "interpolated" which is a mix between the two based on white balance. The setting is only available if a dual-illuminant DCP with interpolation support is selected. -!TP_ICM_INPUTCAMERAICC;Auto-matched camera profile -!TP_ICM_INPUTCAMERAICC_TOOLTIP;Use RawTherapee's camera-specific DCP or ICC input color profiles. These profiles are more precise than simpler matrix ones. They are not available for all cameras. These profiles are stored in the /iccprofiles/input and /dcpprofiles folders and are automatically retrieved based on a file name matching to the exact model name of the camera. -!TP_ICM_INPUTCAMERA_TOOLTIP;Use a simple color matrix from dcraw, an enhanced RawTherapee version (whichever is available based on camera model) or one embedded in the DNG. -!TP_ICM_INPUTNONE_TOOLTIP;Use no input color profile at all.\nUse only in special cases. -!TP_ICM_PROFILEINTENT;Rendering Intent -!TP_ICM_SAVEREFERENCE;Save Reference Image -!TP_ICM_SAVEREFERENCE_APPLYWB;Apply white balance -!TP_ICM_SAVEREFERENCE_APPLYWB_TOOLTIP;Generally, apply the white balance when saving images to create ICC profiles, and do not apply the white balance to create DCP profiles. -!TP_ICM_SAVEREFERENCE_TOOLTIP;Save the linear TIFF image before the input profile is applied. The result can be used for calibration purposes and generation of a camera profile. -!TP_ICM_TONECURVE_TOOLTIP;Employ the embedded DCP tone curve. The setting is only available if the selected DCP has a tone curve. -!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_LABCURVE_CHROMA_TOOLTIP;To apply B&W toning, set Chromaticity to -100. -!TP_LABCURVE_CURVEEDITOR_A_RANGE1;Green Saturated -!TP_LABCURVE_CURVEEDITOR_A_RANGE2;Green Pastel -!TP_LABCURVE_CURVEEDITOR_A_RANGE3;Red Pastel -!TP_LABCURVE_CURVEEDITOR_A_RANGE4;Red Saturated -!TP_LABCURVE_CURVEEDITOR_B_RANGE1;Blue Saturated -!TP_LABCURVE_CURVEEDITOR_B_RANGE2;Blue Pastel -!TP_LABCURVE_CURVEEDITOR_B_RANGE3;Yellow Pastel -!TP_LABCURVE_CURVEEDITOR_B_RANGE4;Yellow Saturated -!TP_LABCURVE_CURVEEDITOR_CC;CC -!TP_LABCURVE_CURVEEDITOR_CC_RANGE1;Neutral -!TP_LABCURVE_CURVEEDITOR_CC_RANGE2;Dull -!TP_LABCURVE_CURVEEDITOR_CC_RANGE3;Pastel -!TP_LABCURVE_CURVEEDITOR_CC_RANGE4;Saturated -!TP_LABCURVE_CURVEEDITOR_CC_TOOLTIP;Chromaticity according to chromaticity C=f(C) -!TP_LABCURVE_CURVEEDITOR_CH;CH -!TP_LABCURVE_CURVEEDITOR_CH_TOOLTIP;Chromaticity according to hue C=f(H) -!TP_LABCURVE_CURVEEDITOR_CL;CL -!TP_LABCURVE_CURVEEDITOR_CL_TOOLTIP;Chromaticity according to luminance C=f(L) -!TP_LABCURVE_CURVEEDITOR_HH;HH -!TP_LABCURVE_CURVEEDITOR_HH_TOOLTIP;Hue according to hue H=f(H) -!TP_LABCURVE_CURVEEDITOR_LC;LC -!TP_LABCURVE_CURVEEDITOR_LC_TOOLTIP;Luminance according to chromaticity L=f(C) -!TP_LABCURVE_CURVEEDITOR_LH;LH -!TP_LABCURVE_CURVEEDITOR_LH_TOOLTIP;Luminance according to hue L=f(H) -!TP_LABCURVE_CURVEEDITOR_LL_TOOLTIP;Luminance according to luminance L=f(L) -!TP_LABCURVE_LCREDSK;Restrict LC to red and skin-tones -!TP_LABCURVE_LCREDSK_TIP;If enabled, the LC Curve affects only red and skin-tones.\nIf disabled, it applies to all tones. -!TP_LABCURVE_RSTPROTECTION;Red and skin-tones protection -!TP_LABCURVE_RSTPRO_TOOLTIP;Works on the Chromaticity slider and the CC curve. -!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_NEUTRAL;Reset -!TP_NEUTRAL_TIP;Resets exposure sliders to neutral values.\nApplies to the same controls that Auto Levels applies to, regardless of whether you used Auto Levels or not. -!TP_PCVIGNETTE_FEATHER_TOOLTIP;Feathering:\n0 = corners only,\n50 = halfway to center,\n100 = to center. -!TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Roundness:\n0 = rectangle,\n50 = fitted ellipse,\n100 = circle. -!TP_PDSHARPENING_LABEL;Capture Sharpening -!TP_PFCURVE_CURVEEDITOR_CH;Hue -!TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Controls defringe strength by color.\nHigher = more,\nLower = less. -!TP_PREPROCESS_DEADPIXFILT;Dead pixel filter -!TP_PREPROCESS_DEADPIXFILT_TOOLTIP;Tries to suppress dead pixels. -!TP_PREPROCESS_GREENEQUIL;Green equilibration -!TP_PREPROCESS_HOTPIXFILT;Hot pixel filter -!TP_PREPROCESS_HOTPIXFILT_TOOLTIP;Tries to suppress hot pixels. -!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_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_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_RAWCACORR_LABEL;Chromatic Aberration Correction -!TP_RAWEXPOS_BLACK_0;Green 1 (lead) -!TP_RAWEXPOS_BLACK_1;Red -!TP_RAWEXPOS_BLACK_2;Blue -!TP_RAWEXPOS_BLACK_3;Green 2 -!TP_RAWEXPOS_BLACK_BLUE;Blue -!TP_RAWEXPOS_BLACK_GREEN;Green -!TP_RAWEXPOS_BLACK_RED;Red -!TP_RAWEXPOS_LINEAR;White-point correction -!TP_RAWEXPOS_RGB;Red, Green, Blue -!TP_RAWEXPOS_TWOGREEN;Link greens -!TP_RAW_1PASSMEDIUM;1-pass (Markesteijn) -!TP_RAW_2PASS;1-pass+fast -!TP_RAW_3PASSBEST;3-pass (Markesteijn) -!TP_RAW_4PASS;3-pass+fast -!TP_RAW_AHD;AHD -!TP_RAW_AMAZE;AMaZE -!TP_RAW_AMAZEVNG4;AMaZE+VNG4 -!TP_RAW_BORDER;Border -!TP_RAW_DCB;DCB -!TP_RAW_DCBENHANCE;DCB enhancement -!TP_RAW_DCBITERATIONS;Number of DCB iterations -!TP_RAW_DCBVNG4;DCB+VNG4 -!TP_RAW_DMETHOD;Method -!TP_RAW_DMETHOD_PROGRESSBAR;%1 demosaicing... -!TP_RAW_DMETHOD_PROGRESSBAR_REFINE;Demosaicing refinement... -!TP_RAW_DMETHOD_TOOLTIP;Note: IGV and LMMSE are dedicated to high ISO images to aid in noise reduction without leading to maze patterns, posterization or a washed-out look.\nPixel Shift is for Pentax/Sony Pixel Shift files. It falls back to AMaZE for non-Pixel Shift files. -!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_EAHD;EAHD -!TP_RAW_FALSECOLOR;False color suppression steps -!TP_RAW_FAST;Fast -!TP_RAW_HD;Threshold -!TP_RAW_HD_TOOLTIP;Lower values make hot/dead pixel detection more aggressive, but false positives may lead to artifacts. If you notice any artifacts appearing when enabling the Hot/Dead Pixel Filters, gradually increase the threshold value until they disappear. -!TP_RAW_HPHD;HPHD -!TP_RAW_IGV;IGV -!TP_RAW_IMAGENUM;Sub-image -!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_LABEL;Demosaicing -!TP_RAW_LMMSE;LMMSE -!TP_RAW_LMMSEITERATIONS;LMMSE enhancement steps -!TP_RAW_LMMSE_TOOLTIP;Adds gamma (step 1), median (steps 2-4) and refinement (steps 5-6) to reduce artifacts and improve the signal-to-noise ratio. -!TP_RAW_MONO;Mono -!TP_RAW_NONE;None (Shows sensor pattern) -!TP_RAW_PIXELSHIFT;Pixel Shift -!TP_RAW_PIXELSHIFTBLUR;Blur motion mask -!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_PIXELSHIFTEQUALBRIGHT;Equalize brightness of frames -!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_PIXELSHIFTEQUALBRIGHT_TOOLTIP;Equalize the brightness of the frames to the brightness of the selected frame.\nIf there are overexposed areas in the frames select the brightest frame to avoid magenta color cast in overexposed areas or enable motion correction. -!TP_RAW_PIXELSHIFTGREEN;Check green channel for motion -!TP_RAW_PIXELSHIFTHOLEFILL;Fill holes in motion mask -!TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;Fill holes in motion mask -!TP_RAW_PIXELSHIFTMEDIAN;Use median for moving parts -!TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;Use median of all frames instead of selected frame for regions with motion.\nRemoves objects which are at different places in all frames.\nGives motion effect on slow moving (overlapping) objects. -!TP_RAW_PIXELSHIFTMM_AUTO;Automatic -!TP_RAW_PIXELSHIFTMM_CUSTOM;Custom -!TP_RAW_PIXELSHIFTMM_OFF;Off -!TP_RAW_PIXELSHIFTMOTIONMETHOD;Motion Correction -!TP_RAW_PIXELSHIFTNONGREENCROSS;Check red/blue channels for motion -!TP_RAW_PIXELSHIFTSHOWMOTION;Show motion mask -!TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;Show only motion mask -!TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;Shows the motion mask without the image. -!TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;Overlays the image with a green mask showing the regions with motion. -!TP_RAW_PIXELSHIFTSIGMA;Blur radius -!TP_RAW_PIXELSHIFTSIGMA_TOOLTIP;The default radius of 1.0 usually fits well for base ISO.\nIncrease the value for high ISO shots, 5.0 is a good starting point.\nWatch the motion mask while changing the value. -!TP_RAW_PIXELSHIFTSMOOTH;Smooth transitions -!TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions between areas with motion and areas without.\nSet to 0 to disable transition smoothing.\nSet to 1 to either get the AMaZE/LMMSE result of the selected frame (depending on whether "Use LMMSE" is selected), or the median of all four frames if "Use median" is selected. -!TP_RAW_RCD;RCD -!TP_RAW_RCDVNG4;RCD+VNG4 -!TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix -!TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster.\n+fast gives less artifacts in flat areas -!TP_RAW_SENSOR_XTRANS_LABEL;Sensor with X-Trans Matrix -!TP_RAW_VNG4;VNG4 -!TP_RAW_XTRANS;X-Trans -!TP_RAW_XTRANSFAST;Fast X-Trans -!TP_RESIZE_ALLOW_UPSCALING;Allow Upscaling -!TP_RESIZE_APPLIESTO;Applies to: -!TP_RETINEX_CONTEDIT_HSL;HSL histogram -!TP_RETINEX_CONTEDIT_LAB;L*a*b* histogram -!TP_RETINEX_CONTEDIT_LH;Hue -!TP_RETINEX_CONTEDIT_MAP;Equalizer -!TP_RETINEX_CURVEEDITOR_CD;L=f(L) -!TP_RETINEX_CURVEEDITOR_CD_TOOLTIP;Luminance according to luminance L=f(L)\nCorrect raw data to reduce halos and artifacts. -!TP_RETINEX_CURVEEDITOR_LH;Strength=f(H) -!TP_RETINEX_CURVEEDITOR_LH_TOOLTIP;Strength according to hue Strength=f(H)\nThis curve also acts on chroma when using the "Highlight" retinex method. -!TP_RETINEX_CURVEEDITOR_MAP;L=f(L) -!TP_RETINEX_CURVEEDITOR_MAP_TOOLTIP;This curve can be applied alone or with a Gaussian mask or wavelet mask.\nBeware of artifacts! -!TP_RETINEX_EQUAL;Equalizer -!TP_RETINEX_FREEGAMMA;Free gamma -!TP_RETINEX_GAIN;Gain -!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_GAMMA;Gamma -!TP_RETINEX_GAMMA_FREE;Free -!TP_RETINEX_GAMMA_HIGH;High -!TP_RETINEX_GAMMA_LOW;Low -!TP_RETINEX_GAMMA_MID;Middle -!TP_RETINEX_GAMMA_NONE;None -!TP_RETINEX_GAMMA_TOOLTIP;Restore tones by applying gamma before and after Retinex. Different from Retinex curves or others curves (Lab, Exposure, etc.). -!TP_RETINEX_GRAD;Transmission gradient -!TP_RETINEX_GRADS;Strength gradient -!TP_RETINEX_GRADS_TOOLTIP;If slider at 0, all iterations are identical.\nIf > 0 Strength is reduced when iterations increase, and conversely. -!TP_RETINEX_GRAD_TOOLTIP;If slider at 0, all iterations are identical.\nIf > 0 Variance and Threshold are reduced when iterations increase, and conversely. -!TP_RETINEX_HIGH;High -!TP_RETINEX_HIGHLIG;Highlight -!TP_RETINEX_HIGHLIGHT;Highlight threshold -!TP_RETINEX_HIGHLIGHT_TOOLTIP;Increase action of High algorithm.\nMay require you to re-adjust "Neighboring pixels" and to increase the "White-point correction" in the Raw tab -> Raw White Points tool. -!TP_RETINEX_HSLSPACE_LIN;HSL-Linear -!TP_RETINEX_HSLSPACE_LOG;HSL-Logarithmic -!TP_RETINEX_ITER;Iterations (Tone-mapping) -!TP_RETINEX_ITERF;Tone mapping -!TP_RETINEX_ITER_TOOLTIP;Simulate a tone-mapping operator.\nHigh values increase the processing time. -!TP_RETINEX_LABEL;Retinex -!TP_RETINEX_LABEL_MASK;Mask -!TP_RETINEX_LABSPACE;L*a*b* -!TP_RETINEX_LOW;Low -!TP_RETINEX_MAP;Method -!TP_RETINEX_MAP_GAUS;Gaussian mask -!TP_RETINEX_MAP_MAPP;Sharp mask (wavelet partial) -!TP_RETINEX_MAP_MAPT;Sharp mask (wavelet total) -!TP_RETINEX_MAP_METHOD_TOOLTIP;Use the mask generated by the Gaussian function above (Radius, Method) to reduce halos and artifacts.\n\nCurve only: apply a diagonal contrast curve on the mask.\nBeware of artifacts!\n\nGaussian mask: generate and use a Gaussian blur of the original mask.\nQuick.\n\nSharp mask: generate and use a wavelet on the original mask.\nSlow. -!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_NEIGHBOR;Radius -!TP_RETINEX_NEUTRAL;Reset -!TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. -!TP_RETINEX_OFFSET;Offset (brightness) -!TP_RETINEX_SCALES;Gaussian gradient -!TP_RETINEX_SCALES_TOOLTIP;If slider at 0, all iterations are identical.\nIf > 0 Scale and radius are reduced when iterations increase, and conversely. -!TP_RETINEX_SETTINGS;Settings -!TP_RETINEX_SKAL;Scale -!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_TRANF;Transmission -!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 -!TP_RETINEX_VARIANCE_TOOLTIP;Low variance increase local contrast and saturation, but can lead to artifacts. -!TP_RETINEX_VIEW;Process -!TP_RETINEX_VIEW_MASK;Mask -!TP_RETINEX_VIEW_METHOD_TOOLTIP;Standard - Normal display.\nMask - Displays the mask.\nUnsharp mask - Displays the image with a high radius unsharp mask.\nTransmission - Auto/Fixed - Displays the file transmission-map, before any action on contrast and brightness.\n\nAttention: the mask does not correspond to reality, but is amplified to make it more visible. -!TP_RETINEX_VIEW_NONE;Standard -!TP_RETINEX_VIEW_TRAN;Transmission - Auto -!TP_RETINEX_VIEW_TRAN2;Transmission - Fixed -!TP_RETINEX_VIEW_UNSHARP;Unsharp mask -!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_SHARPENMICRO_LABEL;Microcontrast -!TP_SHARPENMICRO_MATRIX;3×3 matrix instead of 5×5 -!TP_SHARPENMICRO_UNIFORMITY;Uniformity -!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_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift -!TP_VIBRANCE_CURVEEDITOR_SKINTONES;HH -!TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL;Skin-tones -!TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE1;Red/Purple -!TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE2;Red -!TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE3;Red/Yellow -!TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE4;Yellow -!TP_VIBRANCE_CURVEEDITOR_SKINTONES_TOOLTIP;Hue according to hue H=f(H) -!TP_VIBRANCE_LABEL;Vibrance -!TP_VIBRANCE_PASTELS;Pastel Tones -!TP_VIBRANCE_PASTSATTOG;Link pastel and saturated tones -!TP_VIBRANCE_PROTECTSKINS;Protect skin-tones -!TP_VIBRANCE_PSTHRESHOLD;Pastel/saturated tones threshold -!TP_VIBRANCE_PSTHRESHOLD_SATTHRESH;Saturation threshold -!TP_VIBRANCE_PSTHRESHOLD_TOOLTIP;The vertical axis represents pastel tones at the bottom and saturated tones at the top.\nThe horizontal axis represents the saturation range. -!TP_VIBRANCE_PSTHRESHOLD_WEIGTHING;Pastel/saturated transition's weighting -!TP_VIBRANCE_SATURATED;Saturated Tones -!TP_WAVELET_1;Level 1 -!TP_WAVELET_2;Level 2 -!TP_WAVELET_3;Level 3 -!TP_WAVELET_4;Level 4 -!TP_WAVELET_5;Level 5 -!TP_WAVELET_6;Level 6 -!TP_WAVELET_7;Level 7 -!TP_WAVELET_8;Level 8 -!TP_WAVELET_9;Level 9 -!TP_WAVELET_APPLYTO;Apply To -!TP_WAVELET_AVOID;Avoid color shift -!TP_WAVELET_B0;Black -!TP_WAVELET_B1;Grey -!TP_WAVELET_B2;Residual -!TP_WAVELET_BACKGROUND;Background -!TP_WAVELET_BACUR;Curve -!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;Chroma balance -!TP_WAVELET_BALCHRO_TOOLTIP;If enabled, the 'Contrast balance' curve or slider also modifies chroma balance. -!TP_WAVELET_BANONE;None -!TP_WAVELET_BASLI;Slider -!TP_WAVELET_BATYPE;Contrast balance method -!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 -!TP_WAVELET_CH1;Whole chroma range -!TP_WAVELET_CH2;Saturated/pastel -!TP_WAVELET_CH3;Link contrast levels -!TP_WAVELET_CHCU;Curve -!TP_WAVELET_CHR;Chroma-contrast link strength -!TP_WAVELET_CHRO;Saturated/pastel threshold -!TP_WAVELET_CHRO_TOOLTIP;Sets the wavelet level which will be the threshold between saturated and pastel colors.\n1-x: saturated\nx-9: pastel\n\nIf the value exceeds the amount of wavelet levels you are using then it will be ignored. -!TP_WAVELET_CHR_TOOLTIP;Adjusts chroma as a function of "contrast levels" and "chroma-contrast link strength" -!TP_WAVELET_CHSL;Sliders -!TP_WAVELET_CHTYPE;Chrominance method -!TP_WAVELET_COLORT;Opacity Red-Green -!TP_WAVELET_COMPCONT;Contrast -!TP_WAVELET_COMPGAMMA;Compression gamma -!TP_WAVELET_COMPGAMMA_TOOLTIP;Adjusting the gamma of the residual image allows you to equilibrate the data and histogram. -!TP_WAVELET_COMPTM;Tone mapping -!TP_WAVELET_CONTEDIT;'After' contrast curve -!TP_WAVELET_CONTR;Gamut -!TP_WAVELET_CONTRA;Contrast -!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_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. -!TP_WAVELET_CURVEEDITOR_CL;L -!TP_WAVELET_CURVEEDITOR_CL_TOOLTIP;Applies a final contrast luminance curve at the end of the wavelet treatment. -!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_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_DONE;Vertical -!TP_WAVELET_DTHR;Diagonal -!TP_WAVELET_DTWO;Horizontal -!TP_WAVELET_EDCU;Curve -!TP_WAVELET_EDGCONT;Local contrast -!TP_WAVELET_EDGCONT_TOOLTIP;Adjusting the points to the left decreases contrast, and to the right increases it.\nBottom-left, top-left, top-right and bottom-right represent respectively local contrast for low values, mean, mean+stdev and maxima. -!TP_WAVELET_EDGE;Edge Sharpness -!TP_WAVELET_EDGEAMPLI;Base amplification -!TP_WAVELET_EDGEDETECT;Gradient sensitivity -!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_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. -!TP_WAVELET_EDGTHRESH;Detail -!TP_WAVELET_EDGTHRESH_TOOLTIP;Change the repartition between the first levels and the others. The higher the threshold the more the action is centered on the first levels. Be careful with negative values, they increase the action of high levels and can introduce artifacts. -!TP_WAVELET_EDRAD;Radius -!TP_WAVELET_EDRAD_TOOLTIP;This radius adjustment is very different from those in other sharpening tools. Its value is compared to each level through a complex function. In this sense, a value of zero still has an effect. -!TP_WAVELET_EDSL;Threshold Sliders -!TP_WAVELET_EDTYPE;Local contrast method -!TP_WAVELET_EDVAL;Strength -!TP_WAVELET_FINAL;Final Touchup -!TP_WAVELET_FINEST;Finest -!TP_WAVELET_HIGHLIGHT;Highlight luminance range -!TP_WAVELET_HS1;Whole luminance range -!TP_WAVELET_HS2;Shadows/Highlights -!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 -!TP_WAVELET_HUESKY_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_ITER;Delta balance levels -!TP_WAVELET_ITER_TOOLTIP;Left: increase low levels and reduce high levels,\nRight: reduce low levels and increase high levels. -!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_ONE;One level -!TP_WAVELET_LEVDIR_SUP;Above the 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 -!TP_WAVELET_LEVLABEL;Preview maximum possible levels = %1 -!TP_WAVELET_LEVONE;Level 2 -!TP_WAVELET_LEVTHRE;Level 4 -!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_MEDGREINF;First level -!TP_WAVELET_MEDI;Reduce artifacts in blue sky -!TP_WAVELET_MEDILEV;Edge detection -!TP_WAVELET_MEDILEV_TOOLTIP;When you enable Edge Detection, it is recommanded:\n- to disabled low contrast levels to avoid artifacts,\n- to use high values of gradient sensitivity.\n\nYou can modulate the strength with 'refine' from Denoise and Refine. -!TP_WAVELET_NEUTRAL;Neutral -!TP_WAVELET_NOIS;Denoise -!TP_WAVELET_NOISE;Denoise and Refine -!TP_WAVELET_NPHIGH;High -!TP_WAVELET_NPLOW;Low -!TP_WAVELET_NPNONE;None -!TP_WAVELET_NPTYPE;Neighboring pixels -!TP_WAVELET_NPTYPE_TOOLTIP;This algorithm uses the proximity of a pixel and eight of its neighbors. If less difference, edges are reinforced. -!TP_WAVELET_OPACITY;Opacity Blue-Yellow -!TP_WAVELET_OPACITYW;Contrast balance d/v-h curve -!TP_WAVELET_OPACITYWL;Final 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_RE1;Reinforced -!TP_WAVELET_RE2;Unchanged -!TP_WAVELET_RE3;Reduced -!TP_WAVELET_RESCHRO;Chroma -!TP_WAVELET_RESCON;Shadows -!TP_WAVELET_RESCONH;Highlights -!TP_WAVELET_RESID;Residual Image -!TP_WAVELET_SAT;Saturated chroma -!TP_WAVELET_SETTINGS;Wavelet Settings -!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 -!TP_WAVELET_SKY_TOOLTIP;At -100 sky-tones are targetted.\nAt 0 all tones are treated equally.\nAt +100 sky-tones are protected while all other tones are affected. -!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_THRH;Highlights threshold -!TP_WAVELET_TILESBIG;Big tiles -!TP_WAVELET_TILESFULL;Full image -!TP_WAVELET_TILESIZE;Tiling method -!TP_WAVELET_TILESLIT;Little tiles -!TP_WAVELET_TILES_TOOLTIP;Processing the full image leads to better quality and is the recommended option, while using tiles is a fall-back solution for users with little RAM. Refer to RawPedia for memory requirements. -!TP_WAVELET_TMSTRENGTH;Compression strength -!TP_WAVELET_TMSTRENGTH_TOOLTIP;Control the strength of tone mapping or contrast compression of the residual image. When the value is different from 0, the Strength and Gamma sliders of the Tone Mapping tool in the Exposure tab will become grayed out. -!TP_WAVELET_TMTYPE;Compression method -!TP_WAVELET_TON;Toning -!TP_WBALANCE_EQBLUERED_TOOLTIP;Allows to deviate from the normal behavior of "white balance" by modulating the blue/red balance.\nThis can be useful when shooting conditions:\na) are far from the standard illuminant (e.g. underwater),\nb) are far from conditions where calibrations were performed,\nc) where the matrices or ICC profiles are unsuitable. -!TP_WBALANCE_FLASH60;Standard, Canon, Pentax, Olympus -!TP_WBALANCE_FLASH65;Nikon, Panasonic, Sony, Minolta -!TP_WBALANCE_FLUO1;F1 - Daylight -!TP_WBALANCE_FLUO2;F2 - Cool White -!TP_WBALANCE_FLUO3;F3 - White -!TP_WBALANCE_FLUO4;F4 - Warm White -!TP_WBALANCE_FLUO5;F5 - Daylight -!TP_WBALANCE_FLUO6;F6 - Lite White -!TP_WBALANCE_FLUO7;F7 - D65 Daylight Simulator -!TP_WBALANCE_FLUO8;F8 - D50 / Sylvania F40 Design -!TP_WBALANCE_FLUO9;F9 - Cool White Deluxe -!TP_WBALANCE_FLUO10;F10 - Philips TL85 -!TP_WBALANCE_FLUO11;F11 - Philips TL84 -!TP_WBALANCE_FLUO12;F12 - Philips TL83 -!TP_WBALANCE_FLUO_HEADER;Fluorescent -!TP_WBALANCE_GTI;GTI -!TP_WBALANCE_HMI;HMI -!TP_WBALANCE_JUDGEIII;JudgeIII -!TP_WBALANCE_LAMP_HEADER;Lamp -!TP_WBALANCE_LED_CRS;CRS SP12 WWMR16 -!TP_WBALANCE_LED_LSI;LSI Lumelex 2040 -!TP_WBALANCE_PICKER;Pick -!TP_WBALANCE_SOLUX47;Solux 4700K (vendor) -!TP_WBALANCE_SOLUX47_NG;Solux 4700K (Nat. Gallery) -!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_TUNGSTEN;Tungsten 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/Francais b/rtdata/languages/Francais index 55824ba44..1c8b5fee4 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -906,6 +906,8 @@ MAIN_TAB_FAVORITES_TOOLTIP;Raccourci: Alt-u MAIN_TAB_FILTER; Filtrer MAIN_TAB_INSPECT; Inspecter MAIN_TAB_IPTC;IPTC +MAIN_TAB_LOCALLAB;Local +MAIN_TAB_LOCALLAB_TOOLTIP;Raccourci: Alt-o MAIN_TAB_METADATA;Métadonnées MAIN_TAB_METADATA_TOOLTIP;Raccourci:Alt-m MAIN_TAB_RAW;RAW @@ -989,6 +991,8 @@ PARTIALPASTE_LABCURVE;Courbes Lab PARTIALPASTE_LENSGROUP;Réglages de l'objectif PARTIALPASTE_LENSPROFILE;Profil de correction d'Objectif PARTIALPASTE_LOCALCONTRAST;Contraste local +PARTIALPASTE_LOCALLAB;Ajustements locauc +PARTIALPASTE_LOCALLABGROUP;Réglages Ajustements locaux PARTIALPASTE_METADATA;Mode des Metadonnées PARTIALPASTE_METAGROUP;Réglages des Métadonnées PARTIALPASTE_PCVIGNETTE;Filtre Vignettage @@ -1750,6 +1754,644 @@ TP_LOCALCONTRAST_DARKNESS;Niveau des ombres TP_LOCALCONTRAST_LABEL;Contraste Local TP_LOCALCONTRAST_LIGHTNESS;Niveau des hautes-lumières TP_LOCALCONTRAST_RADIUS;Rayon +TP_LOCALLAB_ACTIV;Luminosité seulement +TP_LOCALLAB_ACTIVSPOT;Activer le Spot +TP_LOCALLAB_ADJ;Egalisateur Bleu-jaune Rouge-vert +TP_LOCALLAB_ALL;Toutes les rubriques +TP_LOCALLAB_AMOUNT;Quantité +TP_LOCALLAB_ARTIF;Détection de forme +TP_LOCALLAB_ARTIF_TOOLTIP;Le seuil deltaE étendue accroit la plage of étendue-deltaE - les valeurs élévées sont pour les images à gamut élévé.\nAugmenter l'affaiblissement deltaE améliore la détection de forme, mais peu réduire la capacité de détection. +TP_LOCALLAB_AUTOGRAY;Automatique +TP_LOCALLAB_AVOID;Evite les dérives de couleurs +TP_LOCALLAB_BALAN;Balance ΔE ab-L +TP_LOCALLAB_BALANEXP;Balance Laplacien +TP_LOCALLAB_BALANH;Balance ΔE C-H +TP_LOCALLAB_BALAN_TOOLTIP;Change l'algorithme des paramètres ΔE.\nPlus ou moins ab-L, plus ou moins C-H.\nPas pour le Debruitage +TP_LOCALLAB_BASELOG;Base Logarithme +TP_LOCALLAB_BILATERAL;Filtre Bilateral +TP_LOCALLAB_BLACK_EV;Noir Ev +TP_LOCALLAB_BLCO;Chrominance seulement +TP_LOCALLAB_BLENDMASKCOL;Mélange - fusion +TP_LOCALLAB_BLENDMASKMASK;Ajout / soustrait le masque Luminance +TP_LOCALLAB_BLENDMASKMASKAB;Ajout / soustrait le masque Chrominance +TP_LOCALLAB_BLENDMASK_TOOLTIP;Si fusion = 0 seule la détection de forme est améliorée.\nSi fusion > 0 le masque est ajouté à l'image. Si fusion < 0 le masque est soustrait à l'image +TP_LOCALLAB_BLENDMASKMASK_TOOLTIP;Si ce curseur = 0 pas d'action.\nAjoute ou soustrait le masque de l'image originale +TP_LOCALLAB_BLGUID;Filtre guidé +TP_LOCALLAB_BLINV;Inverse +TP_LOCALLAB_BLLC;Luminance & Chrominance +TP_LOCALLAB_BLLO;Luminance seulement +TP_LOCALLAB_BLMED;Median +TP_LOCALLAB_BLMETHOD_TOOLTIP;Normal - direct floute et bruite avec tous les réglages.\nInverse floute et bruite avec tous les réglages. Soyez prudents certains resultats peuvent être curieux +TP_LOCALLAB_BLNOI_EXP;Flouter & Bruit +TP_LOCALLAB_BLNORM;Normal +TP_LOCALLAB_BLSYM;Symétrique +TP_LOCALLAB_BLURCOLDE_TOOLTIP;L'image pour calculer dE est légèrement floutéeafin d'éviter de prendre en compte des pixels isolés. +TP_LOCALLAB_BLUFR;Flouter - Grain - Debruiter +TP_LOCALLAB_BLUMETHOD_TOOLTIP;Pour flouter l'arrère plan et isoler le premier plan:\n*Flouter l'arrière plan avec un RT-spot couvrant totalement l'image (valeurs élevées Etendue et transition) - normal ou inverse.\n*Isoler le premier plan avec un ou plusieurs RT-spot Exclusion avec l'outils que vous voulez (accroître Etendue).\n\nCe module peut être utilisé en réduction de bruit additionnelle,incluant un "median" et un "Filtre Guidé" +TP_LOCALLAB_BLUR;Flou Gaussien - Bruit - Grain +TP_LOCALLAB_BLURCBDL;Flouter niveaux 0-1-2-3-4 +TP_LOCALLAB_BLURCOL;Rayon floutage +TP_LOCALLAB_BLURDE;Flouter la détection de forme +TP_LOCALLAB_BLURLC;Luminance seulement +TP_LOCALLAB_BLURLEVELFRA;Flouter niveaux +TP_LOCALLAB_BLURMASK_TOOLTIP;Génère un masque flou, prend en compte la structure avec le curseur de seuil de contraste du Masque flou. +TP_LOCALLAB_BLURRMASK_TOOLTIP;Vous permet de faire varier "rayon" du flou Gaussien (0 to 1000) +TP_LOCALLAB_BLURRESIDFRA;Flouter image Résiduelle +TP_LOCALLAB_BLUR_TOOLNAME;Flouter/Grain & Réduction du Bruit - 1 +TP_LOCALLAB_BLWH;Tous les changements forcés en noir et blanc +TP_LOCALLAB_BLWH_TOOLTIP;Force le changement de la composante "a" et "b" à zéro.\nUtile quand l'utilisateur choisit un processus noir et blanc, ou un film. +TP_LOCALLAB_BUTTON_ADD;Ajouter +TP_LOCALLAB_BUTTON_DEL;Effacer +TP_LOCALLAB_BUTTON_DUPL;Dupliquer +TP_LOCALLAB_BUTTON_REN;Renommer +TP_LOCALLAB_BUTTON_VIS;Montrer/Cacher +TP_LOCALLAB_CBDL;Contraste par niveaux de détail +TP_LOCALLAB_CBDLCLARI_TOOLTIP;Ajuste les tons moyens et les réhausse. +TP_LOCALLAB_CBDL_ADJ_TOOLTIP;Agit comme un outil ondelettes.\nLe premier niveau (0) agit sur des détails de 2x2.\nLe dernier niveau (5) agit sur des détails de 64x64. +TP_LOCALLAB_CBDL_THRES_TOOLTIP;Empêche d'augmenter le bruit +TP_LOCALLAB_CBDL_TOOLNAME;Contraste par niveaux de détail - 2 +TP_LOCALLAB_CENTER_X;Centre X +TP_LOCALLAB_CENTER_Y;Centre Y +TP_LOCALLAB_CH;Courbes CL - LC +TP_LOCALLAB_CHROMA;Chrominance +TP_LOCALLAB_CHROMABLU;Niveaux Chroma +TP_LOCALLAB_CHROMABLU_TOOLTIP;Agit comme un amplificateur-reducteur d'action en comparant aux réglages de luma.\nEn dessous de 1 reduit, au dessus de 1 amplifie +TP_LOCALLAB_CHROMACBDL;Chroma +TP_LOCALLAB_CHROMACB_TOOLTIP;Agit comme un amplificateur-reducteur d'action en comparant aux curseurs de luminance.\nEn dessous de 100 reduit, au dessus de 100 amplifie +TP_LOCALLAB_CHROMALEV;Niveaux de Chroma +TP_LOCALLAB_CHROMASKCOL;Chroma +TP_LOCALLAB_CHROMASK_TOOLTIP;Vous pouvez utiliser ce curseur pour désaturer l'arrière plan (inverse masque - courbe proche de 0).\nEgalement pour atténier ou accroître l'action du masque sur la chroma +TP_LOCALLAB_CHRRT;Chroma +TP_LOCALLAB_CIRCRADIUS;Taille Spot +TP_LOCALLAB_CIRCRAD_TOOLTIP;Contient les références du RT-spot, utile pour la détection de forme (couleur, luma, chroma, Sobel).\nLes faibles valeurs peuvent être utiles pour les feuillages.\nLes valeurs élevées peuvent être utile pour la peau +TP_LOCALLAB_CLARICRES;Fusion Chroma +TP_LOCALLAB_CLARIFRA;Clarté & Masque de netteté - Fusion & adoucir images +TP_LOCALLAB_CLARILRES;Fusion Luma +TP_LOCALLAB_CLARISOFT;Rayon adoucir +TP_LOCALLAB_CLARISOFT_TOOLTIP;Actif pour Clarté et Masque de netteté si différent de zéro.\n\nActif pour toutes les pyramides ondelettes.\nInactif si rayon = 0 +TP_LOCALLAB_CLARITYML;Clarté +TP_LOCALLAB_CLARI_TOOLTIP;En dessous ou égal à 4, 'Masque netteté' est actif.\nAu dessus du niveau ondelettes 5 'Clarté' est actif.\nUtilesu=i vous utilisez 'Compression dynamique des niveaux' +TP_LOCALLAB_CLIPTM;Clip Recupère données (gain) +TP_LOCALLAB_COFR;Couleur & Lumière +TP_LOCALLAB_COLORDE;Couleur prévisualisation sélection ΔE - Intensité +TP_LOCALLAB_COLORDEPREV_TOOLTIP;Bouton Prévisualisation ΔE a besoin qu'un seul outil soit activé (expander).\nPour pouvoir avoir une Prévisualisation ΔE avec plusieurs outils activés utiliser Masque et modifications - Prévisualisation ΔE +TP_LOCALLAB_COLORDE_TOOLTIP;Affiche la prévisualisation ΔE en bleu si négatif et en vert si positif.\n\nMasque et modifications (montre modifications sans masque): montre les modifications réelles si positf, montre les modifications améliorées (luminance seule) en bleu et jaune si négatif. +TP_LOCALLAB_COLORSCOPE;Etendue Outils Couleur +TP_LOCALLAB_COLORSCOPE_TOOLTIP;Utilise une étendue commune pour Couleur et lumière, Ombres Lumières, Vibrance.\nLes autres outils ont leur étendue spécifique. +TP_LOCALLAB_COLOR_TOOLNAME;Couleur & Lumière - 11 +TP_LOCALLAB_COL_NAME;Nom +TP_LOCALLAB_COL_VIS;Statut +TP_LOCALLAB_COMPFRA;Niveaux Contraste directionnel +TP_LOCALLAB_COMPFRAME_TOOLTIP;Autorise des effets spéciaux. Vous pouvez réduire les artéfacts avec 'Clarté & Masque netteté - Fusion & Images douces".\nUtilise des ressources +TP_LOCALLAB_COMPLEX_METHOD;Complexitée logicielle +TP_LOCALLAB_COMPLEX_TOOLTIP; Autorise l'utilisateur à sélectionner des rubriques Ajustements locaux. +TP_LOCALLAB_COMPREFRA;Niveaux de (de)compression dynamique +TP_LOCALLAB_COMPRESS_TOOLTIP;Utilisesi nécessaire le module 'Clarté & Masque de netteté - Fusion & Images douces' en ajustant 'Rayon doux' pour réduire les artéfacts. +TP_LOCALLAB_CONTCOL;Seuil de Contraste Masque flou +TP_LOCALLAB_CONTFRA;Contraste par niveau +TP_LOCALLAB_CONTRAST;Contraste +TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP;Contrôle de contraste du masque. +TP_LOCALLAB_CONTRESID;Contraste +TP_LOCALLAB_CONTTHMASK_TOOLTIP;Vous permet de déterminer quelles parties de l'image seront concernées par la texture. +TP_LOCALLAB_CONTTHR;Seuil contraste +TP_LOCALLAB_CONTWFRA;Contrast Local +TP_LOCALLAB_CSTHRESHOLD;Ψ Ondelettes niveaux +TP_LOCALLAB_CSTHRESHOLDBLUR;Ψ Masque Ondelettes niveau +TP_LOCALLAB_CURV;Luminosité - Contraste - Chrominance "Super" +TP_LOCALLAB_CURVCURR;Normal +TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP;Si la courbe est au sommet, le masque est compétement noir aucune transformation n'est réalisée par le masque sur l'image.\nQuand vous descendez la courbe, progressivement le masque va se colorer et s'éclaicir, l'image change de plus en plus.\n\nIl est recommendé (pas obligatoire) de positionner le sommet des courbes curves sur la ligne de transition grise qui représnte les références (chroma, luma, couleur). +TP_LOCALLAB_CURVEEDITORM_CC_TOOLTIP;Si la courbe est au sommet,le masque est compétement noir aucune transformation n'est réalisée par le masque sur l'image.\nQuand vous descendez la courbe, progressivement le masque va se colorer et s'éclaicir, l'image change de plus en plus.\nVous pouvez choisir ou non de positionner le sommet de la courbe sur la transition. +TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP;Pour être actif, vous devez activer la combobox 'Curves type' +TP_LOCALLAB_CURVEEDITOR_TONES_LABEL;Courbe tonale +TP_LOCALLAB_CURVEEDITOR_TONES_TOOLTIP;L=f(L), peut être utilisée avec L(H) dans Couleur et lumière +TP_LOCALLAB_CURVEMETHOD_TOOLTIP;'Normal', la courbe L=f(L) a le même algorithme que le curseur luminosité.\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;Désactive courbes +TP_LOCALLAB_DARKRETI;Obscuirité +TP_LOCALLAB_DEHAFRA;Elimination de la brume +TP_LOCALLAB_DEHAZFRAME_TOOLTIP;Élimine la brume atmosphérique. Augmente généralement la saturation et les détails. \ N Peut supprimer les dominantes de couleur, mais peut également introduire une dominante bleue qui peut être corrigée à l'aide d'autres outils. +TP_LOCALLAB_DEHAZ;Force +TP_LOCALLAB_DEHAZ_TOOLTIP;Valeurs Négatives ajoute de la brume +TP_LOCALLAB_DELTAD;Delta balance +TP_LOCALLAB_DELTAEC;Masque ΔE Image +TP_LOCALLAB_DENOIS;Ψ Réduction du bruit +TP_LOCALLAB_DENOI_EXP;Réduction du bruit +TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservatif préserve les fréquences basses, alors que agressif tend à les effacer +TP_LOCALLAB_DENOIEQUAL_TOOLTIP;Equilibre l'action de denoise luminance entre les ombres et les lumières +TP_LOCALLAB_DENOI_TOOLTIP;Ce module peut être utilisé seul (à la fin du processus), ou en complément de Réduction du bruit (au début).\nEtendue(deltaE)permet de différencier l'action.\nVous pouvez compléter avec "median" ou "Filtre guidé" (Adoucir Flou...).\nVous pouvez compléter l'action avec "Flou niveaux" "Ondelette pyramide" +TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;Permet de récupérer les détails de luminance par mise en oeuvre progressive de la transformée de Fourier (DCT) +TP_LOCALLAB_DENOICHROF_TOOLTIP;Agit sur les fins détails du bruit de chrominance +TP_LOCALLAB_DENOICHROC_TOOLTIP;Agit sur les paquets et amas de bruit de chrominance +TP_LOCALLAB_DENOICHRODET_TOOLTIP;Permet de récupérer les détails de chrominance par mise en oeuvre progressive de la transformée de Fourier (DCT) +TP_LOCALLAB_DENOITHR_TOOLTIP;Règle l'effet de bord pour privilégier l'action sur les aplats +TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP;Equilibre l'action de denoise chrominance entre les bleus-jaunes et les rouges-verts +TP_LOCALLAB_DENOIBILAT_TOOLTIP;Traite le bruit d'impulsion (poivre et sel) +TP_LOCALLAB_DEPTH;Profondeur +TP_LOCALLAB_DETAIL;Contrast local +TP_LOCALLAB_DETAILSH;Details +TP_LOCALLAB_DETAILTHR;Seuil Detail Luminance Chroma (DCT ƒ) +TP_LOCALLAB_DUPLSPOTNAME;Copier +TP_LOCALLAB_EDGFRA;Netteté des bords +TP_LOCALLAB_EDGSHOW;Montre tous les outils +TP_LOCALLAB_ELI;Ellipse +TP_LOCALLAB_ENABLE_AFTER_MASK;Utilise Tone Mapping +TP_LOCALLAB_ENABLE_MASK;Active masque +TP_LOCALLAB_ENABLE_MASKAFT;Utilise tous les algorithmes Exposition +TP_LOCALLAB_ENARETIMASKTMAP_TOOLTIP;Si activé, le Masque utilise les données recupérées après 'Transmission Map' au lieu des données originales +TP_LOCALLAB_ENH;Amélioré +TP_LOCALLAB_ENHDEN;Amélioré + chroma réduction bruit +TP_LOCALLAB_EPSBL;Detail +TP_LOCALLAB_EQUIL;Normalise Luminance +TP_LOCALLAB_EQUILTM_TOOLTIP;Reconstruit la luminance de telle manière que la moyenne et la variance de l'image traitée soient identiques à celle d'origine +TP_LOCALLAB_ESTOP;Arrêt des bords +TP_LOCALLAB_EV_DUPL;Copier vers +TP_LOCALLAB_EV_NVIS;Cacher +TP_LOCALLAB_EV_NVIS_ALL;Cacher tout +TP_LOCALLAB_EV_VIS;Montrer +TP_LOCALLAB_EV_VIS_ALL;Montrer tout +TP_LOCALLAB_EXCLUF;Exclure +TP_LOCALLAB_EXCLUF_TOOLTIP;Peut être utilsé pour exclure une partie des données - agir sur Etendue pour prendre en compte plus de couleurs.\n Vous pouvez utiliser tous les réglages pour ce type de RT-spot. +TP_LOCALLAB_EXCLUTYPE;Spot méthode +TP_LOCALLAB_EXCLUTYPE_TOOLTIP;Spot Normal utilise les données récursives.\n\nSpot exclusion réinitialise les données d'origine.\nPeut être utilsé pour annuler totalement ou partiellement une action précédente ou pour réaliser un mode inverse +TP_LOCALLAB_EXECLU;Spot Exclusion +TP_LOCALLAB_EXNORM;Spot Normal +TP_LOCALLAB_EXPCBDL_TOOLTIP;Peut être utilisé pour retirer les marques sur le capteur ou la lentille. +TP_LOCALLAB_EXPCHROMA;Chroma compensation +TP_LOCALLAB_EXPCHROMA_TOOLTIP;Seulement en association avec compensation d'exposition et PDE Ipol.\nEvite la desaturation des couleurs +TP_LOCALLAB_EXPCOLOR_TOOLTIP;Ajuste les couleurs, la luminosité, le contrast et corrige les petits défauts tels que teux-rouges, poussières sur le capteur, etc. +TP_LOCALLAB_EXPCOMP;Compensation d'exposition ƒ +TP_LOCALLAB_EXPCOMPINV;Compensation d'exposition +TP_LOCALLAB_EXPCOMP_TOOLTIP;Pour les portraits et les images à faible gradient, vous pouvez changer "Détection de forme" dans "Réglages":\n\nAugmentez 'Seuil ΔE Etendue'\nRéduire 'ΔE affaiblissement'\nAugmenter 'Balance ΔE ab-L' +TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;Voir la documentation de ondelettes niveaux.\nCependant il y a des différences: plus d'outils et plus proches des détails .\nEx: Tone mapping pour ondelettes. +TP_LOCALLAB_EXPCONTRAST_TOOLTIP;Evitez les spots trop petits(< 32x32 pixels).\nUtilisez de faibles valeurs de transition et de hautes valeurs de transition affaiblissement et d'Etendue pour simuler un petit RT-spot et s'adapter aux défauts.\nUtimiser si nécessaire le module 'Clarté & Maqsue netteté' et 'Fusion d'images' en ajustant 'Rayon adoucir' pour réduire les artéfacts. +TP_LOCALLAB_EXPCURV;Courbes +TP_LOCALLAB_EXPGRAD;Filtre gradué +TP_LOCALLAB_EXPGRADCOL_TOOLTIP;Un filtre gardué est disponible dans Couleur et lumière (luminance, chrominance & teinte gradients, et "Fusion fichier") Exposure (luminance grad.), Exposition Masque(luminance grad.), Ombres/lumières (luminance grad.), Vibrance (luminance, chrominance & teinte gradients), Local contrast & ondelettes pyramide (local contrast grad.).\nAdoucissement de gradient est dans "Réglages". +TP_LOCALLAB_EXPLAPBAL_TOOLTIP;Balance l'action entre l'iamge originale image et la transformée de Laplace. +TP_LOCALLAB_EXPLAPGAMM_TOOLTIP;Applique un gamma avant et après la transformée de Laplace +TP_LOCALLAB_EXPLAPLIN_TOOLTIP;Ajoute une exposition linéaire avant l'application de la transformée de Laplace +TP_LOCALLAB_EXPLAP_TOOLTIP;Plus vous agissez sur ce curseur de seuil, plus grande sera l'action de reduire le contraste. +TP_LOCALLAB_EXPMERGEFILE_TOOLTIP;Autorise de nombreuses possibilités de fusionner les images (comme les calques dans Photosshop) : difference, multiply, soft light, overlay...avec opacité...\nOriginale Image : fusionne le RT-spot en cours avec Originale.\nSpot Précédent : fusionne le RT-spot en cours avec le précédent - si il n'y a qu'un spot précédent = original.\nArrière plan : fusionne le RT-spot en cours avec la couleur et la luminance de l'arrière plan (moins de possibilités) +TP_LOCALLAB_EXPMETHOD_TOOLTIP;Standard : utilise un algorithme similaire à Exposure principal mais en L*a*b* et en prenant en compte le deltaE.\n\nCompression dynamique et atténuateur de contraste : utilise un autre algorithme aussi avec deltaE et avec l'équation de Poisson pour résoudre le Laplacien dans l'espace de Fourier.\nAtténuateur, Compression dynamqiue et Standard peuvent être combinés.\nFFTW La transformée de Fourier est optimisée en taille pour réduire les temps de traitement.\nRéduit les artéfacts et le bruit. +TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP;Applique un median avant la transformée de Laplace pour éviter les artéfacts (bruit).\nVous pouvez aussi utiliser l'outil "Réduction du bruit". +TP_LOCALLAB_EXPOSE;Compression dynamique & Exposition +TP_LOCALLAB_EXPOSURE_TOOLTIP;Modifie l'exposition dans l'espace L*a*b* en utilisant un Laplacien et les algorithmes PDE en prenant en compte dE, minimise les artéfacts. +TP_LOCALLAB_EXPRETITOOLS;Outils Retinex avancés +TP_LOCALLAB_EXPSHARP_TOOLTIP;RT-Spot minimum 39*39.\nUtiliser de basses valeurs de transition et de hautes valeurs de transition affaiblissement et Etendue pour simuler un petit RT-spot. +TP_LOCALLAB_EXPTOOL;Outils exposition +TP_LOCALLAB_EXPTRC;Courbe de réponse Tonale - TRC +TP_LOCALLAB_EXP_TOOLNAME;Compression Dynamique & Exposition- 10 +TP_LOCALLAB_FATAMOUNT;Quantité +TP_LOCALLAB_FATANCHOR;Ancre +TP_LOCALLAB_FATANCHORA;Décalage +TP_LOCALLAB_FATDETAIL;Detail +TP_LOCALLAB_FATFRA;Compression Dynamique ƒ +TP_LOCALLAB_FATFRAME_TOOLTIP;PDE Fattal - utilise Fattal Tone mapping algorithme. +TP_LOCALLAB_FATLEVEL;Sigma +TP_LOCALLAB_FATRES;Quantité de Residual Image +TP_LOCALLAB_FATSHFRA;Compression Dynamique Masque ƒ +TP_LOCALLAB_FEATH_TOOLTIP;Largeur du Gradient en porcentage de la diagonale du Spot\nUtilisé par tous les Filtres Gradués dans tous les outils.\nPas d'action si les filtres gradués ne sont pas utilisés. +TP_LOCALLAB_FEATVALUE;Adoucissement gradient (Filtres Gradués) +TP_LOCALLAB_FFTCOL_MASK;FFTW ƒ +TP_LOCALLAB_FFTMASK_TOOLTIP;Utilise une transformée de Fourier pour une meilleure qualité (accroit le temps de traitement et le besoin en mémoire) +TP_LOCALLAB_FFTW;ƒ - Utilise Fast Fourier Transform +TP_LOCALLAB_FFTW2;ƒ - Utilise Fast Fourier Transform (TIF, JPG,..) +TP_LOCALLAB_FFTWBLUR;ƒ - Utilise toujours Fast Fourier Transform +TP_LOCALLAB_FULLIMAGE;Calcule les valeurs Noir Ev - Blanc Ev - sur l'image entière +TP_LOCALLAB_FULLIMAGELOG_TOOLTIP;Calcule les valeurs Ev sur l'image entière. +TP_LOCALLAB_GAM;Gamma +TP_LOCALLAB_GAMFRA;Courbe Réponse Tonale (TRC) +TP_LOCALLAB_GAMM;Gamma +TP_LOCALLAB_GAMMASKCOL;Gamma +TP_LOCALLAB_GAMMASK_TOOLTIP;Gamma et Pente (Slope) autorise une transformation du masque en douceur et sans artefacts en modifiant progressivement "L" pour éviter les discontinuité. +TP_LOCALLAB_GAMSH;Gamma +TP_LOCALLAB_GRADANG;Angle du Gradient +TP_LOCALLAB_GRADANG_TOOLTIP;Angle de Rotation en degrés : -180 0 +180 +TP_LOCALLAB_GRADFRA;Filtre gradué Masque +TP_LOCALLAB_GRADGEN_TOOLTIP;Filtre Gradué est fourni avec Couleur et Lumière & Fusion fichier, Exposition & masque, Shadows Highlight, Vibrance, Encoding log.\n\nVibrance, Couleur et Lumière & Fusion fichier, sont fournis avec GF luminance, chrominance, teinte.\nAdoucissement est situé dans "réglages". +TP_LOCALLAB_GRADLOGFRA;Filtre Gradué Luminance +TP_LOCALLAB_GRADSTR;Force du Gradient +TP_LOCALLAB_GRADSTRAB_TOOLTIP;Filtre chroma force +TP_LOCALLAB_GRADSTRCHRO;Force Gradient Chrominance +TP_LOCALLAB_GRADSTRHUE;Force Gradient Teinte +TP_LOCALLAB_GRADSTRHUE2;Force Gradient Teinte +TP_LOCALLAB_GRADSTRHUE_TOOLTIP;Filttre Teinte force +TP_LOCALLAB_GRADSTRLUM;Force Gradient Luminance +TP_LOCALLAB_GRADSTR_TOOLTIP;Force Filtre en Ev +TP_LOCALLAB_GRAINFRA;Film Grain 1:1 +TP_LOCALLAB_GRAIN_TOOLTIP;Ajoute du grain pour simuler un film +TP_LOCALLAB_GRALWFRA;Filtre Gradué Local contraste +TP_LOCALLAB_GRIDFRAME_TOOLTIP;Vous pouvez utiliser cet outil comme une brosse. Utiliser un petit Spot et adaptez transition et transition affaiblissement\nSeulement en mode NORMAL et éventuellement Teinte, Saturation, Couleur, Luminosité sont concernés par Fusion arrire plan (ΔE) +TP_LOCALLAB_GRIDONE;Virage partiel +TP_LOCALLAB_GRIDTWO;Direct +TP_LOCALLAB_GRIDMETH_TOOLTIP;Virage partiel: la luminance est prise en compte quand varie la chroma -Equivalent de H=f(H) si le "point blanc" sur la grille the grid est à zéro et vous faites varier le "point noir" -Equivalent de "Virage partiel" si vous faites varier les 2 points.\n\nDirect: agit directement sur la chroma +TP_LOCALLAB_GUIDBL;Rayon adoucir +TP_LOCALLAB_GUIDFILTER;Rayon Filtre Guidé +TP_LOCALLAB_GUIDFILTER_TOOLTIP;Adapter cette valeur en fonction des images - peut réduire ou accroître les artéfacts. +TP_LOCALLAB_GUIDBL_TOOLTIP;Applique un filtre guidé avec un rayon donné, pour réduire les artefacts ou flouter l'image +TP_LOCALLAB_GUIDSTRBL_TOOLTIP;Force du filtre guidé +TP_LOCALLAB_GUIDEPSBL_TOOLTIP;Détail - agit sur la répartition du filtre guidé, les valeurs négatives simulent un flou gaussien +TP_LOCALLAB_HHMASK_TOOLTIP;Ajustements fin de la teinte par exemple pour la peau. +TP_LOCALLAB_HIGHMASKCOL;Hautes lumières masque +TP_LOCALLAB_HLH;Courbes H +TP_LOCALLAB_IND;Independant (souris) +TP_LOCALLAB_INDSL;Independant (souris + curseurs) +TP_LOCALLAB_INVERS;Inverse +TP_LOCALLAB_INVERS_TOOLTIP;Si sélectionné (inverse) moins de possibilités.\n\nAlternative\nPremier Spot:\n image entière - delimiteurs en dehors de la prévisualisation\n RT-spot forme sélection : rectangle. Transition 100\n\nDeuxième spot : Spot Exclusion +TP_LOCALLAB_INVBL_TOOLTIP;Alternative\nPremier Spot:\n image entière - delimiteurs en dehors de la prévisualisation\n RT-spot forme sélection : rectangle. Transition 100\n\nDeuxième spot : Spot Exclusion +TP_LOCALLAB_ISOGR;Plus gros (ISO) +TP_LOCALLAB_LABBLURM;Masque Flouter +TP_LOCALLAB_LABEL;Ajustements Locaux +TP_LOCALLAB_LABGRID;Grille correction couleurs +TP_LOCALLAB_LABGRIDMERG;Arrière plan +TP_LOCALLAB_LABGRID_VALUES;Haut(a)=%1 Haut(b)=%2\nBas(a)=%3 Bas(b)=%4 +TP_LOCALLAB_LABSTRUM;Masque Structure +TP_LOCALLAB_LAPLACC;ΔØ Masque Laplacien résoud PDE +TP_LOCALLAB_LAPLACE;Laplacien seuil ΔE +TP_LOCALLAB_LAPLACEXP;Laplacien seuil +TP_LOCALLAB_LAPMASKCOL;Laplacien seuil +TP_LOCALLAB_LAPRAD_TOOLTIP;Eviter d'utiliser Radius and Laplace Seuil en même temps.\nLaplacien seuil reduit le contraste, artéfacts, adoucit le résultat. +TP_LOCALLAB_LAPRAD1_TOOLTIP;Eviter d'utiliser Radius and Laplace Seuil en même temps.\nTransforme le masque pour éliminer les valeurs inférieures au seuil.\nReduit les artefacts et le bruit, et permet une modification du contraste local. +TP_LOCALLAB_LAP_MASK_TOOLTIP;Résoud PDE (Equation aux dérivées partielles) pour tous les masques Laplacien.\nSi activé Laplacien masque seuil reduit les artéfacts et adoucit les résultats.\nSi désactivé réponse linaire. +TP_LOCALLAB_LC_FFTW_TOOLTIP;FFT améliore la qualité et autorise de grands rayons, mais accroît les temps de traitement.\nCe temps dépends de la surface devant être traitée.\nA utiliser de préférences pour de grands rayons.\n\nLes Dimensions peuvent être réduites de quelques pixels pour optimiser FFTW.\nCette optimisation peut réduire le temps de traitement d'un facteur de 1.5 à 10.\n +TP_LOCALLAB_LC_TOOLNAME;Constraste Local & Ondelettes - 7 +TP_LOCALLAB_LEVELBLUR;Maximum Flouter +TP_LOCALLAB_LEVELLOCCONTRAST_TOOLTIP;En abscisse le contraste local (proche du concept de luminance). En ordonnée, amplification ou reduction du contraste local. +TP_LOCALLAB_LEVELWAV;Ψ Ondelettes Niveaux +TP_LOCALLAB_LEVELWAV_TOOLTIP;Le niveau est automatiquement adapté à la taille du spot et de la prévisualisation.\nDu niveau 9 taille max 512 jusqu'au niveau 1 taille max = 4 +TP_LOCALLAB_LEVFRA;Niveaux +TP_LOCALLAB_LIGHTNESS;Luminosité +TP_LOCALLAB_LIGHTN_TOOLTIP;En mode inverse: selection = -100 force la luminance à zero +TP_LOCALLAB_LIGHTRETI;Luminosité +TP_LOCALLAB_LINEAR;Linéarité +TP_LOCALLAB_LIST_NAME;Ajoute un outil au spot courant... +TP_LOCALLAB_LIST_TOOLTIP;Vous pouvez choisir 3 niveaux de complexité pour chaque outil: Basic, Normal & Avancé.\nLe réglage par défaut est Basic mais il peut être changé dans Préférences.\nVous pouvez aussi changer ce niveau pour chaque outil en cours. +TP_LOCALLAB_LMASK_LEVEL_TOOLTIP;Donne priorité à l'action sur les tons moyens et hautes lumières en choisissant les niveaux concernés d'ondelettes +TP_LOCALLAB_LMASK_LL_TOOLTIP;Vous permet de modifier librement le contraste du masque. Peut amener de artefacts. +TP_LOCALLAB_LOCCONT;Masque Flou +TP_LOCALLAB_LOC_CONTRAST;Contraste Local & Ondelettes +TP_LOCALLAB_LOC_CONTRASTPYR;Ψ Pyramide 1: +TP_LOCALLAB_LOC_CONTRASTPYR2;Ψ Pyramide 2: +TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contr. par niveaux- Tone Mapping - Cont.Dir. +TP_LOCALLAB_LOC_CONTRASTPYRLAB; Filtre Gradué - Netteté bords - Flouter +TP_LOCALLAB_LOC_RESIDPYR;Image Residuelle +TP_LOCALLAB_LOG;Codage log +TP_LOCALLAB_LOGAUTO;Automatique +TP_LOCALLAB_LOGAUTO_TOOLTIP;Presser ce bouton va amner une évaluation an evaluation de l'amplitude dynamique et du point gris "source" (Si "Automatique" Source gris activé).\nPour être autorisé à retoucher les valeurs automatiques, presser le bouton à nouveau +TP_LOCALLAB_LOGBASE_TOOLTIP;Défaut = 2.\nValeurs inférieures à 2 réduisent l'action de l'algorithme, les ombres sont plus sombres, les hautes lumières plus brillantes.\nValeurs supérieures à 2 changent l'action de l'algorithme, les ombres sont plus grises, les hautes lumières lavées +TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP;Valeurs estimées de la plage Dynamique - Noir Ev et Blanc Ev +TP_LOCALLAB_LOGENCOD_TOOLTIP;Autorise 'Tone Mapping' avec codage Logarithmique (ACES).\nUtile pour images ous-exposées, ou avec une plage dynamique élévée.\n\nDeux étapes dans le processus : 1) Calculer Plage Dynamique 2) Adaptation par utilisateur +TP_LOCALLAB_LOGFRA;Point gris source +TP_LOCALLAB_LOGFRAME_TOOLTIP;Calcule ou utilise le niveau d'Exposition de l'image tôt dans le processus:\n Noir Ev, Blanc Ev et Point gris source.\n Prend en compte la compensation d'exposition principale. +TP_LOCALLAB_LOGLIN;Logarithme mode +TP_LOCALLAB_LOGPFRA;Niveaux d'Exposition relatif +TP_LOCALLAB_LOGSRCGREY_TOOLTIP;Estime la valeur du point gris de l'image, tôt dans le processus +TP_LOCALLAB_LOGTARGGREY_TOOLTIP;Vous pouvez changer cette valeur pour l'adapter à votre goût. +TP_LOCALLAB_LOG_TOOLNAME;Codage log - 0 +TP_LOCALLAB_LUM;Courbes LL - CC +TP_LOCALLAB_LUMADARKEST;Plus Sombre +TP_LOCALLAB_LUMASK;Maqsue Luminance arrière plan +TP_LOCALLAB_LUMASK_TOOLTIP;Ajuste le gris de l'arrière plan du masque dans Montrer Masque (Masque et modifications) +TP_LOCALLAB_LUMAWHITESEST;Plus clair +TP_LOCALLAB_LUMONLY;Luminance seulement +TP_LOCALLAB_MASKCOM;Masque couleur Commun +TP_LOCALLAB_MASKCOM_TOOLTIP;Ces masques travaillent comme les autres outils, ils prennet en compte Etendue.\nIls sont différents des autres masques qui complètent un outil (Couleur et Lumière, Exposition...) +TP_LOCALLAB_MASFRAME;Masque et Fusion +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_MASK;Masque +TP_LOCALLAB_MASK2;Courbe de Contraste +TP_LOCALLAB_MASKCOL;Masque Courbes +TP_LOCALLAB_MASKCURVE_TOOLTIP;Si la courbe est au sommet, le masque est compétement noir aucune transformation n'est réalisée par le masque sur l'image.\nQuand vous descendez la courbe, progressivement le masque va se colorer et s'éclaicir, l'image change de plus en plus.\n\nIl est recommendé (pas obligatoire) de positionner le sommet des courbes curves sur la ligne de transition grise qui représnte les références (chroma, luma, couleur). +TP_LOCALLAB_MASKH;Courbe teinte +TP_LOCALLAB_MASK_TOOLTIP;Vous pouvez activer plusieurs masques pour un simple outil, ceci nécessite d'activer un autre outil (mais sans utilser l'outil : curseurs à 0,...)où est le masque que vous souhaitez activer.\n\nVous pouvez aussi dupliquer le RT-spot et le placer juste à côté de l'autre,les variations de références autorisent un travail fin sur les images. +TP_LOCALLAB_MED;Medium +TP_LOCALLAB_MEDIAN;Median Bas +TP_LOCALLAB_MEDIAN_TOOLTIP;Choisir un median 3x3 à 9x9: plus les valeurs sont élévées, plus la réduction du bruit ou le flou seront marqués +TP_LOCALLAB_MEDIANITER_TOOLTIP;Nombre d'applications successives du median +TP_LOCALLAB_MEDNONE;Rien +TP_LOCALLAB_MERCOL;Couleur +TP_LOCALLAB_MERDCOL;Fusion arrière plan (ΔE) +TP_LOCALLAB_MERELE;Eclaicit seulement +TP_LOCALLAB_MERFIV;Addition +TP_LOCALLAB_MERFOR;Couleur esquiver +TP_LOCALLAB_MERFOU;Multiplier +TP_LOCALLAB_MERGE1COLFRA;Fusion avec Original ou Précédent ou arrière plan +TP_LOCALLAB_MERGECOLFRA;Masque: LCH & Structure +TP_LOCALLAB_MERGECOLFRMASK_TOOLTIP;Vous permet de créer des masques basés sur les 3 courbes LCH et/ou un algorithm de détection de structure +TP_LOCALLAB_MERGEFIV;Previous Spot(Mask 7) + Mask LCH +TP_LOCALLAB_MERGEFOU;Previous Spot(Mask 7) +TP_LOCALLAB_MERGEMER_TOOLTIP;Prend en compte ΔE pour fusionner les fichiers (équivalent de Etendue pour cet usage) +TP_LOCALLAB_MERGENONE;Rien +TP_LOCALLAB_MERGEONE;Short Curves 'L' Mask +TP_LOCALLAB_MERGEOPA_TOOLTIP;Opacité fusion % Spot courant avec original ou Spot précédent.\nContraste seuil : ajuste le résulat en fonction du contraste original +TP_LOCALLAB_MERGETHR;Original(Mask 7) + Mask LCH +TP_LOCALLAB_MERGETWO;Original(Mask 7) +TP_LOCALLAB_MERGETYPE;Fusion image et masque +TP_LOCALLAB_MERGETYPE_TOOLTIP;Rien, 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_MERHEI;Overlay +TP_LOCALLAB_MERHUE;Teite +TP_LOCALLAB_MERLUCOL;Luminance +TP_LOCALLAB_MERLUM;Luminosité +TP_LOCALLAB_MERNIN;Ecran +TP_LOCALLAB_MERONE;Normal +TP_LOCALLAB_MERSAT;Saturation +TP_LOCALLAB_MERSEV;Soft Light (legacy) +TP_LOCALLAB_MERSEV0;Soft Light Illusion +TP_LOCALLAB_MERSEV1;Soft Light W3C +TP_LOCALLAB_MERSEV2;Lumière dure +TP_LOCALLAB_MERSIX;Divise +TP_LOCALLAB_MERTEN;Assombrit seulement +TP_LOCALLAB_MERTHI;Couleur Brûlé +TP_LOCALLAB_MERTHR;Difference +TP_LOCALLAB_MERTWE;Exclusion +TP_LOCALLAB_MERTWO;Soustrait +TP_LOCALLAB_METHOD_TOOLTIP;'Enhanced + chroma denoise' significantly increases processing times.\nBut reduce artifacts. +TP_LOCALLAB_MLABEL;Récupère les données Min=%1 Max=%2 (Clip - décalage) +TP_LOCALLAB_MLABEL_TOOLTIP;'Doit être' près de min=0 max=32768 (log mode) mais d'autres valeurs sont possibles.\nVous pouvez agir sur les données récupérées (CLIP) et décalage pour normaliser.\n\nRécupère les données image sans mélange. +TP_LOCALLAB_MODE_EXPERT;Avancé +TP_LOCALLAB_MODE_NORMAL;Standard +TP_LOCALLAB_MRFIV;Arrière plan +TP_LOCALLAB_MRFOU;Spot précédent +TP_LOCALLAB_MRONE;Rien +TP_LOCALLAB_MRTHR;Image Originale +TP_LOCALLAB_MRTWO;Short Curves 'L' Mask +TP_LOCALLAB_MULTIPL_TOOLTIP;Autorise la retouche des tons sur une large plage : -18EV +4EV. Le remier curseur agit sur -18EV and -6EV. Le dernier curseur agit sur les tons au-dessus de 4EV +TP_LOCALLAB_NEIGH;Rayon +TP_LOCALLAB_NOISE_TOOLTIP;Ajoute du bruit de luminance +TP_LOCALLAB_NOISECHROCOARSE;Chroma gros (Ond) +TP_LOCALLAB_NOISECHROC_TOOLTIP;Si supérieur à zéro, algorithme haute qualité est activé.\nGros est sélectionné si curseur >=0.2 +TP_LOCALLAB_NOISECHRODETAIL;Récupération des détails Chroma (DCT ƒ) +TP_LOCALLAB_NOISECHROFINE;Chroma fin (Ond) +TP_LOCALLAB_NOISEDETAIL_TOOLTIP;Désactivé si curseur = 100 +TP_LOCALLAB_NOISELEQUAL;Egalisateurs balnc-noir +TP_LOCALLAB_NOISELUMCOARSE;Luminance gros (ond) +TP_LOCALLAB_NOISELUMDETAIL;Récupération Luminance fin(DCT ƒ) +TP_LOCALLAB_NOISELUMFINE;Luminance fin 1 (ond) +TP_LOCALLAB_NOISELUMFINETWO;Luminance fin 2 (ond) +TP_LOCALLAB_NOISELUMFINEZERO;Luminance fin 0 (ond) +TP_LOCALLAB_NOISEMETH;Réduction du bruit +TP_LOCALLAB_NONENOISE;Rien +TP_LOCALLAB_OFFS;Décalage +TP_LOCALLAB_OFFSETWAV;Décalage +TP_LOCALLAB_OPACOL;Opacité +TP_LOCALLAB_ORIGLC;Fusion seulement avec image originale +TP_LOCALLAB_ORRETILAP_TOOLTIP;Agit sur un deuxième seuil Laplacien, pour prendre en compte ΔE pour différencier l'action nottament avec l'arrière plan (différent de Etendue) +TP_LOCALLAB_ORRETISTREN_TOOLTIP;Aagit sur un seuil Laplacien, plus grande est l'action, plus les différences de contraste seront réduites +TP_LOCALLAB_PASTELS2;Vibrance +TP_LOCALLAB_PDE;Atténuation de Contraste - Compression dynamique +TP_LOCALLAB_PDEFRA;Contraste atténuation ƒ +TP_LOCALLAB_PDEFRAME_TOOLTIP;PDE IPOL - algorithme personnel adapté de IPOL à Rawtherapee: conduit à des résultats très variés et a besoin de différents réglages que Standard (Noir négatif, gamma < 1,...)\nPeut être utils pour des iamges sous-exposées ou avec une étendue dynamique importante.\n +TP_LOCALLAB_PREVIEW;Prévisualisation ΔE +TP_LOCALLAB_PREVHIDE;Cacher tous les réglages +TP_LOCALLAB_PREVSHOW;Montrer tous les réglages +TP_LOCALLAB_PROXI;ΔE Affaiblissement +TP_LOCALLAB_QUALCURV_METHOD;Types de Courbes +TP_LOCALLAB_QUAL_METHOD;Qualité globale +TP_LOCALLAB_RADIUS;Rayon +TP_LOCALLAB_RADIUS_TOOLTIP;Above Radius 30 Use Fast Fourier Transform +TP_LOCALLAB_RADMASKCOL;Rayon adoucir +TP_LOCALLAB_RECT;Rectangle +TP_LOCALLAB_RECURS;Réferences Récursives +TP_LOCALLAB_RECURS_TOOLTIP;Recalcule les références pour teinte, luma, chroma après chaque module et après chaque RT-spot.\nAussi utile pour le travail avec les masques. +TP_LOCALLAB_REFLABEL;Ref. (0..1) Chroma=%1 Luma=%2 teinte=%3 +TP_LOCALLAB_REN_DIALOG_LAB;Entrer le nouveau nom de Spot +TP_LOCALLAB_REN_DIALOG_NAME;Renomme le Controle Spot +TP_LOCALLAB_RESETSHOW;Annuler Montrer Toutes les Modifications +TP_LOCALLAB_RESID;Image Résiduelle +TP_LOCALLAB_RESIDBLUR;Flouter Image Résiduelle +TP_LOCALLAB_RESIDCHRO;Image Résiduelle Chroma +TP_LOCALLAB_RESIDCOMP;Image Résiduelle Compression +TP_LOCALLAB_RESIDCONT;Image Résiduelle Contraste +TP_LOCALLAB_RESIDHI;Hautes lumières +TP_LOCALLAB_RESIDHITHR;Hautes lumières seuil +TP_LOCALLAB_RESIDSHA;Ombres +TP_LOCALLAB_RESIDSHATHR;Ombres seuil +TP_LOCALLAB_RETI;De-brume - Retinex Fort contraste +TP_LOCALLAB_RETIFRA;Retinex +TP_LOCALLAB_RETIM;Original Retinex +TP_LOCALLAB_RETITOOLFRA;Retinex Outils +TP_LOCALLAB_RETIFRAME_TOOLTIP; L'utilisation de Retinex peut être bénéfique pour le traitement des images: \ nqui sont floues, brumeuses ou ayant un voile de brouillard (en complément de Dehaz). \ Navec d'importants écarts de luminance. \ N où l'utilisateur recherche des effets spéciaux (cartographie des tons…) +TP_LOCALLAB_RETI_FFTW_TOOLTIP;FFT améliore la qualité et autorise de grands rayons, mais accroît les temps de traitement.\nCe temps dépends de la surface traitée\nLe temps de traitements dépend de "scale" (échelle) (soyez prudent avec les hautes valeurs ).\nA utiliser de préférence avec de grand rayons.\n\nLes Dimensions peuvent être réduites de quelques pixels pour optimiser FFTW.\nCette optimisation peut réduire le temps de traitement d'un facteur de 1.5 à 10.\nOptimisation pas utilsée en prévisualisation +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_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_LOGLIN_TOOLTIP;Logarithm allows differenciation for haze or normal.\nLogarithm brings more contrast but will generate more halo. +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_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_RET_TOOLNAME;De-brume & Retinex - 9 +TP_LOCALLAB_REWEI;Repondération iterations +TP_LOCALLAB_RGB;RGB Courbe de tonalité +TP_LOCALLAB_ROW_NVIS;Pas visible +TP_LOCALLAB_ROW_VIS;Visible +TP_LOCALLAB_SATUR;Saturation +TP_LOCALLAB_SAVREST;Sauve - Récupère Image Courante +TP_LOCALLAB_SCALEGR;Echelle +TP_LOCALLAB_SCALERETI;Echelle +TP_LOCALLAB_SCALTM;Echelle +TP_LOCALLAB_SCOPEMASK;Etendue Masque ΔE Image +TP_LOCALLAB_SCOPEMASK_TOOLTIP;Actif si Masque DeltaE Image est activé.\nLes faibles valeurs évitent de retoucher l'aire sélectionnée +TP_LOCALLAB_SENSI;Etendue +TP_LOCALLAB_SENSIBN;Etendue +TP_LOCALLAB_SENSICB;Etendue +TP_LOCALLAB_SENSIDEN;Etendue +TP_LOCALLAB_SENSIEXCLU;Etendue +TP_LOCALLAB_SENSIEXCLU_TOOLTIP;Ajuste les couleurs pour les inclure dans exclusion! +TP_LOCALLAB_SENSIH;Etendue +TP_LOCALLAB_SENSIH_TOOLTIP;Ajuste Etendue de l'action:\nLes petites valeurs limitent l'action aux couleurs très similaires à celles sous le centre du spot.\nHautes valeurs laissent l'outil agir sur une large plage de couleurs. +TP_LOCALLAB_SENSILOG;Etendue +TP_LOCALLAB_SENSIS;Etendue +TP_LOCALLAB_SENSI_TOOLTIP;Ajuste Etendue de l'action:\nLes petites valeurs limitent l'action aux couleurs très similaires à celles sous le centre du spot.\nHautes valeurs laissent l'outil agir sur une large plage de couleurs. +TP_LOCALLAB_SENSIMASK_TOOLTIP;Ajuste Etendue pour ce masque commun.\nAgit sur l'écart entre l'image originale et le masque.\nLes références (luma, chroma, teinte) sont celles du centre du RT-spot\n\nVous pouvez aussi agir sur le deltaE interne au masque avec 'Etendue Masque deltaE image' dans 'Réglages' +TP_LOCALLAB_SETTINGS;Réglages +TP_LOCALLAB_SH1;Ombres Lumières +TP_LOCALLAB_SH2;Egaliseur +TP_LOCALLAB_SHADEX;Ombres +TP_LOCALLAB_SHADEXCOMP;Compression ombres & profondeur tonale +TP_LOCALLAB_SHADHIGH;Ombres/Lumières - Egaliseur tonal +TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP;Peut être utilisé - ou en complement - du module Exposition dans les cas difficiles.\nUtiliser réduction du bruit Denoise peut être nécessaire : éclaicir les ombres.\n\nPeut être utilisé comme un filtre gradué (augmenter Etendue) +TP_LOCALLAB_SHAMASKCOL;Ombres +TP_LOCALLAB_SHADMASK_TOOLTIP;Relève les ombres du masque de la même manière que l'algorithme "ombres/lumières" +TP_LOCALLAB_SHADHMASK_TOOLTIP;Abaisse les hautes lumières du masque de la même manière que l'algorithme "ombres/lumières" +TP_LOCALLAB_SHAPETYPE;Forme aire RT-spot +TP_LOCALLAB_SHAPE_TOOLTIP;Ellipse est le mode normal.\nRectangle peut être utilé dans certains cas, par exemple pour travailler en image complète en conjonction avec les délimiteurs en dehors de la prévisualisation, transition = 100.\n\nPolygone - Beziers sont en attente de GUI... +TP_LOCALLAB_SHARAMOUNT;Quantité +TP_LOCALLAB_SHARBLUR;Rayon flouter +TP_LOCALLAB_SHARDAMPING;Amortissement +TP_LOCALLAB_SHARFRAME;Modifications +TP_LOCALLAB_SHARITER;Iterations +TP_LOCALLAB_SHARP;Netteté +TP_LOCALLAB_SHARP_TOOLNAME;Netteté - 8 +TP_LOCALLAB_SHARRADIUS;Rayon +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_SHOWC;Masque et modifications +TP_LOCALLAB_SHOWC1;Fusion fichier +TP_LOCALLAB_SHOWCB;Masque et modifications +TP_LOCALLAB_SHOWDCT;Montrer processus Fourier ƒ +TP_LOCALLAB_SHOWE;Masque et modifications +TP_LOCALLAB_SHOWFOURIER;Fourier ƒ(dct) +TP_LOCALLAB_SHOWLAPLACE;∆ Laplacien (premier) +TP_LOCALLAB_SHOWLC;Masque et modifications +TP_LOCALLAB_SHOWMASK;Montrer masque +TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;Affiche masque modifications.\nAttention, vous ne pouvez voir qu'un seul masque à la fois.\n\nNote: Utilisation du Masque est avant l'algorihtme de détection de forme. +TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;Montre le processus Fourier:\nMontre les différentes étapes du processus.\nLaplace - construit la dérivée seconde the second dérivée associée au seuil (Premiére étape).\nFourier -montre la transformée de Laplace avec DCT.\nPoisson - montre la solution de Poisson DCE.\nNormalise - montre le résultat sans normalisation de la luminance. +TP_LOCALLAB_SHOWMASKTYP1;Flouter & Bruit +TP_LOCALLAB_SHOWMASKTYP2;Réduction du bruit +TP_LOCALLAB_SHOWMASKTYP3;Flouter & Bruit + De-bruite +TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;Masque et modifications peuvent être choisis.\nFlouter et bruit: dans ce cas il n'est pas utilisé pour 'Réduction du bruit'.\nRéduction du bruit : dans ce cas il n'est pas utilisé pour 'flouter et bruit'.\n\nFlouter et bruit + Réduction du bruit : le masque est partagé, faire attention à 'montrer modifications' et 'Etendue' +TP_LOCALLAB_SHOWMNONE;Montrer image modifiée +TP_LOCALLAB_SHOWMODIF;Montrer modifications sans masque +TP_LOCALLAB_SHOWMODIFMASK;Montrer modifications avec masque +TP_LOCALLAB_SHOWNORMAL;Normalise luminance (non) +TP_LOCALLAB_SHOWPLUS;Masque et modifications - Adoucir-flouter & De-bruite +TP_LOCALLAB_SHOWPOISSON;Poisson (pde ƒ) +TP_LOCALLAB_SHOWR;Masque et modifications +TP_LOCALLAB_SHOWREF;Prévisualisation ΔE +TP_LOCALLAB_SHOWS;Masque et modifications +TP_LOCALLAB_SHOWSTRUC;Montrer Spot structure (avancé) +TP_LOCALLAB_SHOWSTRUCEX;Montrer Spot structure (avancé) +TP_LOCALLAB_SHOWT;Masque et modifications +TP_LOCALLAB_SHOWVI;Masque et modifications +TP_LOCALLAB_SHRESFRA;Ombres/Lumières +TP_LOCALLAB_SHTRC_TOOLTIP;Modifie les tons de l'image en agissant sur la TRC (Tone Response Curve).\nGamma agit principalement sur les tons lumineux.\nSlope (pente) agit principalement sur les tons sombres. +TP_LOCALLAB_SH_TOOLNAME;Ombres/lumières & Egaliseur tonal - 5 +TP_LOCALLAB_SIGMAWAV;Atténuation Réponse +TP_LOCALLAB_SIM;Simple +TP_LOCALLAB_SLOMASKCOL;Pente (slope) +TP_LOCALLAB_SLOMASK_TOOLTIP;Gamma et Pente (Slope) autorise une transformation du masque en douceur et sans artefacts en modifiant progressivement "L" pour éviter les discontinuité. +TP_LOCALLAB_SLOSH;Pente +TP_LOCALLAB_SOFT;Lumière douce - Original Retinex +TP_LOCALLAB_SOFTM;Lumière douce (soft light) +TP_LOCALLAB_SOFTMETHOD_TOOLTIP;Applique un mélange Lumière douce. Effectue une émulation de "dodge and burn" en utilisant l'algorithme original de retinex. +TP_LOCALLAB_SOFTRADIUSCOL;Rayon adoucir +TP_LOCALLAB_SOFTRADIUSCOL_TOOLTIP;Applique un filtre guidé à l'image de sortie pour réduire les éventuels artefacts. +TP_LOCALLAB_SOFTRETI;Reduire artefact ΔE +TP_LOCALLAB_SOFTRETI_TOOLTIP;Prend en compte ΔE pour améliorer Transmission map +TP_LOCALLAB_SOFT_TOOLNAME;Lumière douce & Original Retinex - 6 +TP_LOCALLAB_SOURCE_GRAY;Valeur +TP_LOCALLAB_SPECCASE; Cas spécifiques +TP_LOCALLAB_SPECIAL;Usage Special des courbes RGB +TP_LOCALLAB_SPECIAL_TOOLTIP;Seulement pour cette courbe RGB, désactive (ou réduit les effecs) de Etendue, masque...par exemple, si vous voulez rendre un effet "négatif". +TP_LOCALLAB_SPOTNAME;Nouveau Spot +TP_LOCALLAB_STD;Standard +TP_LOCALLAB_STR;Force +TP_LOCALLAB_STRBL;Force +TP_LOCALLAB_STREN;Compression Force +TP_LOCALLAB_STRENG;Force +TP_LOCALLAB_STRENGRID_TOOLTIP;Vous pouvez ajuster l'effet désiré avec "force", mais vous pouvez aussi utiliser la fonction "Etendue" qui permet de délimiter l'action (par exemple, pour isoler une couleur particulière). +TP_LOCALLAB_STRENGR;Force +TP_LOCALLAB_STRENGTH;Bruit +TP_LOCALLAB_STRGRID;Force +TP_LOCALLAB_STRRETI_TOOLTIP;Si force Retinex < 0.2 seul Dehaze est activé.\nSi force Retinex >= 0.1 Dehaze est en mode luminance. +TP_LOCALLAB_STRUC;Structure +TP_LOCALLAB_STRUCCOL;Structure +TP_LOCALLAB_STRUCCOL1;Spot structure +TP_LOCALLAB_STRUCT_TOOLTIP;Utilise l'algorithme de Sobel pour prendre en compte la structure dans la détection de forme.\nvous pouvez prévisualiser avec "masque et modifications - Montrer structure spot".\n\nPeut être utilisé avec masques (avancé) structure, flouter, ondelettes pour améliorer la détection de bords.\n\nA besoin de réglages sans-masque pour êtrre activé (luminosité, exposition...) +TP_LOCALLAB_STRUMASKCOL;Structure force +TP_LOCALLAB_STRUMASK_TOOLTIP;Génère un masque structure qui va différencier les aplats et reliefs.\nSi structure masque comme outil est activé, ce masque est untilisé en plus des autres outils (gamma, slope, courbe contraste ...) +TP_LOCALLAB_STRUSTRMASK_TOOLTIP;Un usage modéré de ce curseur est recommandé! +TP_LOCALLAB_STYPE;Forme méthode +TP_LOCALLAB_STYPE_TOOLTIP;Vous pouvez choisir entre:\nSymétrique - gauche et droite sont liés, haut et bas sont liés.\nIndépendent - toutes les saisies sont indépendantes. +TP_LOCALLAB_SYM;Symétrique (souris) +TP_LOCALLAB_SYMSL;Symétrique (souris + curseurs) +TP_LOCALLAB_TARGET_GRAY;Point Gris Cible +TP_LOCALLAB_THRES;Seuil structure +TP_LOCALLAB_THRESDELTAE;Seuil ΔE-Etendue +TP_LOCALLAB_THRESRETI;Seuil +TP_LOCALLAB_THRESWAV;Balance Seuil +TP_LOCALLAB_TLABEL;TM Datas Min=%1 Max=%2 Mean=%3 Sigma=%4 (Seuil) +TP_LOCALLAB_TLABEL2;TM Effectif Tm=%1 TM=%2 +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;Compression tonale - Texture +TP_LOCALLAB_TM_MASK;Utilise transmission map +TP_LOCALLAB_TONEMAPESTOP_TOOLTIP;Ce paramètre affecte la sensibilité aux bords.\n Plus grand il est, plus la luminosité change peut être considéré comme un bord.\n Si réglé à zéro 'compression tonale' va avoir un effet similaire à masque flou. +TP_LOCALLAB_TONEMAPGAM_TOOLTIP;Gamma déplace l'action de 'compression tonale' des ombres vers les lumières. +TP_LOCALLAB_TONEMAPREWEI_TOOLTIP;Dans certains 'compression tonal' peut amener des effets de perspective, et dans de rares cas des halos peuvent apparaître.\n Accroître le nombre d'itérations peut aider à résoudre ces problèmes. +TP_LOCALLAB_TONEMAP_TOOLTIP;Compression tonal - menu principal doit être désactivé +TP_LOCALLAB_TONEMASCALE_TOOLTIP;Ce contrôle donne le pouvoir de différencier le contraste "local" et "global".\nPlus il est important, plus un détail sera accentué. +TP_LOCALLAB_TONE_TOOLNAME;Compression tonale - 4 +TP_LOCALLAB_TOOLCOL;Masque Structure comme outil +TP_LOCALLAB_TOOLCOLFRMASK_TOOLTIP;Autorise de modifier le masque s'il a été créé +TP_LOCALLAB_TOOLMASK;Outils du masque +TP_LOCALLAB_TOOLMASK_TOOLTIP;Génère un masque structure qui va différencier les aplats et reliefs.\nSi structure masque comme outil est activé, ce masque est untilisé en plus des autres outils (gamma, slope, courbe contraste ...) +TP_LOCALLAB_TRANSIT;Transition - Gradient +TP_LOCALLAB_TRANSITGRAD;Transition différentiation XY +TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Change la transition des abscisses vers les ordonnées +TP_LOCALLAB_TRANSITVALUE;Transition valeur +TP_LOCALLAB_TRANSITWEAK;Transition affaiblissement (linéaire-log) +TP_LOCALLAB_TRANSITWEAK_TOOLTIP;Ajuste l'affaiblissement de la transition : change le processus d'affaiblissement - 1 linéaire - 2 parabolique - 3 cubique - ^25.\nPeut être utilisé en conjonction avec de très faibles valeurs de transition pour traiter/réduire les défauts (CBDL, Ondelettes, Couleur et lumière) +TP_LOCALLAB_TRANSIT_TOOLTIP;Ajuste la progressions de la transition enttre les zones affectées ou non affectées, comme un pourcentage du "rayon" +TP_LOCALLAB_TRANSMISSIONGAIN;Transmission gain +TP_LOCALLAB_TRANSMISSIONMAP;Transmission map +TP_LOCALLAB_TRANSMISSION_TOOLTIP;Transmission en accord à transmission.\nAbscisse: transmission pour les valeurs négatives (min), mean, et les valeurs positives (max).\nOrdonnée: amplification ou réduction.\nVous pouvez agir sur cette courbe pour chnager la Transmission et réduire les artefacts +TP_LOCALLAB_USEMASK;Utiliser masque +TP_LOCALLAB_VART;Variance (contraste) +TP_LOCALLAB_VIBRANCE;Vibrance - Chaud & Froid +TP_LOCALLAB_VIBRA_TOOLTIP;Ajuste vibrance (Globalement identique à Couleur ajustement).\nAmène l'équivalent d'une balance des blancs en utilisant l'algorithme CIECAM. +TP_LOCALLAB_VIB_TOOLNAME;Vibrance - Chaud & Froid - 3 +TP_LOCALLAB_SOFT_TOOLNAME;Lumière douce & Original Retinex - 6 +TP_LOCALLAB_BLUR_TOOLNAME;Flouter/Grain & Réduction du bruit - 1 +TP_LOCALLAB_TONE_TOOLNAME;Compression tonale - 4 +TP_LOCALLAB_RET_TOOLNAME;De-brume & Retinex - 9 +TP_LOCALLAB_SHARP_TOOLNAME;Netteté - 8 +TP_LOCALLAB_LC_TOOLNAME;Constraste local & Ondelettes (Défauts) - 7 +TP_LOCALLAB_CBDL_TOOLNAME;Contraste par Niveau détail - 2 +TP_LOCALLAB_LOG_TOOLNAME;Codage log - 0 +TP_LOCALLAB_MASKCOM_TOOLNAME;Masque Commun Couleur - 13 +TP_LOCALLAB_VIS_TOOLTIP;Click pour montrer/cacher le Spot sélectionné.\nCtrl+click pour montrer/cacher tous les Spot. +TP_LOCALLAB_WAMASKCOL;Ψ Niveau Ondelettes +TP_LOCALLAB_WARM;Chaud - Froid & Artefacts de couleur +TP_LOCALLAB_WARM_TOOLTIP;Ce curseur utilise l'algorithme Ciecam et agit comme une Balance des blancs, il prut réchauffer ou refroidir cool la zone concernée.\nIl peut aussi dans certains réduire les artefacts colorés. +TP_LOCALLAB_WASDEN_TOOLTIP;De-bruite luminance pour les 3 premiers niveaux (fin).\nLa limite droite de la courbe correspond à gros : niveau 3 et au delà. +TP_LOCALLAB_WAT_WAVSHAPE_TOOLTIP;Contraste faible à élevé de gauche à droite en abscisse\nAugmente ou réduit le contraste en ordonnée. +TP_LOCALLAB_WAT_LEVELLOCCONTRAST_TOOLTIP;Contraste faible à élevé de gauche à droite en abscisse\nAugmente ou réduit le contraste en ordonnée. +TP_LOCALLAB_WAT_SIGMALC_TOOLTIP;L'effet sur le contraste local est maximum pour les valeurs moyennes, et affaibli pour les valeurs faibles ou élevées.\n Le curseur contrôle comment s'effectue les changements pour ces valeurs extêmse.\n Plus la valeur du curseur est élevée, plus grande sera l'étendue qui recevra le maximum d'ajustements, ainsi que le risque de voir apparaître des artefacts.\n .Plus faible sera cette valeur, plus les différences de contraste seront atténuées +TP_LOCALLAB_WAT_BLURLC_TOOLTIP;Par défaut les 3 dimensions de L*a*b* luminance et couleur sont concernées par le floutage.\nCase cochée - luminance seulement +TP_LOCALLAB_WAT_THRESHOLDWAV_TOOLTIP;Etendue des niveaux d’ondelettes utilisée dans l’ensemble du module “wavelets” +TP_LOCALLAB_WAT_EXPRESID_TOOLTIP;Image résiduelle, a le même comportement que l'image principale +TP_LOCALLAB_WAT_CLARIL_TOOLTIP;"Fusion luma" est utilisée pour selectionner l'intensité de l'effet désiré sur la luminance. +TP_LOCALLAB_WAT_CLARIC_TOOLTIP;"Fusion chroma" est utilisée pour selectionner l'intensité de l'effet désiré sur la luminance. +TP_LOCALLAB_WAT_ORIGLC_TOOLTIP;"Fusion seulement avec image originale", empêche les actions "Wavelet Pyramid" d'interférer avec "Claté" and "Masque netteté" +TP_LOCALLAB_WAT_STRWAV_TOOLTIP;Permet au contraste local de varier en fonction d'un gradient et d'un angle. La variation du signal de la luminance signal est prise en compte et non pas la luminance. +TP_LOCALLAB_WAT_CONTOFFSET_TOOLTIP;Décalage modifie la balance entre faible contraste et contraste élévé.\nLes hautes valeurs amplifient les changements de contraste pour les détails à contraste élévé, alors que les faibles valeurs vont amplifier les détails à contraste faible .\nEn selectionant des valeurs faibles vous pouvez ainsi sélectionner les zones de contrastes qui seront accentuées. +TP_LOCALLAB_WAT_CONTCHROMALEV_TOOLTIP;"Niveaux de Chroma": ajuste les valeurs "a" et "b" des composantes L*a*b* comme une proportion de la luminance. +TP_LOCALLAB_WAT_WAVCBDL_TOOLTIP;Similaira à Contraste par niveaux de détail. Des détails fins au gros details de gauche à droite en abscisse. +TP_LOCALLAB_WAT_STRENGTHW_TOOLTIP;Intensité de la détection d'effet de bord +TP_LOCALLAB_WAT_LOCCONTRASTEDG_TOOLTIP;Vous pouvez agir sur la répartition du contraste local selon l'intensité initiale du contraste par niveaux d'ondelettes.\nCeci aura comme conséquences de modifier l'effet de perspective et de relief de l'image, et/ou réduire les contrastes pour les très faibles niveaux de contraste initial +TP_LOCALLAB_WAT_GRADW_TOOLTIP;Plus vous déplacez le curseur à droite, plus l'algorithme de détection sera efficace, moins les effets du contraste local seront sensibles +TP_LOCALLAB_WAT_WAVESHOW_TOOLTIP;Montre l'ensemble des outils "Netteté bords".\nLa lecture de la documentation wavelet est recommandée +TP_LOCALLAB_WAT_WAVLEVELBLUR_TOOLTIP;Permet d'ajuster l'effet maximum de floutage des niveaux +TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP;Vous permet de flouter chaque niveau de décomposition.\nEn abscisse de gauche à droite, les niveaux de décomposition du plus fin au plus gros +TP_LOCALLAB_WAT_RESIDBLUR_TOOLTIP;Floute l'image résiduelle, indépendamment des niveaux +TP_LOCALLAB_WAT_WAVTM_TOOLTIP;La partie inférieure (négative) compresse chaque niveau de décomposition créant un effet tone mapping.\nLa partie supérieure (positive) atténue le contraste par niveau.\nEn abscisse de gauche à droite, les niveaux de décomposition du plus fin au plus gros +TP_LOCALLAB_WAT_BALTHRES_TOOLTIP;Equilibre l'action à l'intérieur de chaque niveau +TP_LOCALLAB_WAT_RESIDCOMP_TOOLTIP;Commpresse l'image résiduelle afin d'accentuer ou réduire les contrastes +TP_LOCALLAB_WAT_DELTABAL_TOOLTIP;En déplaçant le curseur à gauche, les bas niveaux sont accentués, et vers la droite ce sont les bas niveaux qui sont réduits et les hauts niveaux accentués +TP_LOCALLAB_WAT_WAVDELTABAL_TOOLTIP;Agit sur la balance des trois directions horizontale - verticale - diagonale - en fonction de la luminance de l'image.\nPar défaut les parties sombres ou hautes lumières sont réduites afin d'éviter les artefacts +TP_LOCALLAB_WAV;Contrast local niveau +TP_LOCALLAB_WAVBLUR_TOOLTIP;Réalise un flou pour chaque niveau de décomposition, également pour l'image résiduelle. +TP_LOCALLAB_WAVCOMP;Compression par niveau +TP_LOCALLAB_WAVCOMPRE;Compression par niveau +TP_LOCALLAB_WAVCOMPRE_TOOLTIP;Réalise un 'Tone-mapping' ou une réduction du contraste local par niveau.\nEn abscisse: niveaux +TP_LOCALLAB_WAVCOMP_TOOLTIP;Réalise un contrast local en fonction de la direction de la décomposition en ondelettes : horizontal, vertical, diagonal +TP_LOCALLAB_WAVCON;Contraste par niveau +TP_LOCALLAB_WAVCONTF_TOOLTIP;Similaire à Contrast By Detail Levels : en abscisse niveaux. +TP_LOCALLAB_WAVDEN;de-bruite luminance par niveau (0 1 2 + 3 et plus) +TP_LOCALLAB_WAVE;Ψ Ondelette +TP_LOCALLAB_WAVEDG;Contrast Local +TP_LOCALLAB_WAVEEDG_TOOLTIP;Améliore la netteté prenant en compte la notion de "ondelettes bords".\nNécessite au moins que les 4 premiers niveaux sont utilisables +TP_LOCALLAB_WAVGRAD_TOOLTIP;Filtre gradué pour Contraste local "luminance" +TP_LOCALLAB_WAVHIGH;Ψ Ondelette haut +TP_LOCALLAB_WAVLEV;Flouter par niveau +TP_LOCALLAB_WAVLOW;Ψ Ondelette bas +TP_LOCALLAB_WAVMASK;Ψ Niveau contraste local +TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP;Amplitude des niveaux d'ondelettes utilisés par “Local contrast” +TP_LOCALLAB_WAVMASK_TOOLTIP;Autorise un travail fin sur les masques niveaux de contraste (structure) +TP_LOCALLAB_WAVMED;Ψ Ondelette normal +TP_LOCALLAB_WEDIANHI;Median Haut +TP_LOCALLAB_WHITE_EV;Blanc Ev TP_METADATA_EDIT;Appliquer les modifications TP_METADATA_MODE;Mode de copie des métadonnées TP_METADATA_STRIP;Retirer toutes les métadonnées @@ -2078,6 +2720,8 @@ TP_WAVELET_CHR_TOOLTIP;Ajuste le chroma en fonction des "niveaux de contraste" e TP_WAVELET_CHSL;Curseurs TP_WAVELET_CHTYPE;Méthode de chrominance TP_WAVELET_COLORT;Opacité Rouge-Vert +TP_WAVELET_COMPLEX_TOOLTIP;Standard: l’application dispose du nécessaire pour assurer les opérations courantes, l’interface graphique est simplifiée.\nAvancé: toutes les fonctionnalités sont présentes, certaines nécessitent un apprentissage important +TP_WAVELET_COMPEXPERT;Avancé TP_WAVELET_COMPCONT;Contraste TP_WAVELET_COMPGAMMA;Compression gamma TP_WAVELET_COMPGAMMA_TOOLTIP;Ajuster le gamma de l'image résiduelle vous permet d'équiilibrer les données de l'histogramme. diff --git a/rtdata/languages/Japanese b/rtdata/languages/Japanese index b7c0b7e22..22dc027ea 100644 --- a/rtdata/languages/Japanese +++ b/rtdata/languages/Japanese @@ -8,6 +8,7 @@ #08 2012-12-22 a3novy #09 2013-04-01 a3novy #10 2013-04-19 a3novy +#11 2020-06-24 Yz2house ABOUT_TAB_BUILD;バージョン ABOUT_TAB_CREDITS;クレジット @@ -25,7 +26,7 @@ CURVEEDITOR_CURVE;カーブ CURVEEDITOR_CURVES;カーブ CURVEEDITOR_CUSTOM;カスタム CURVEEDITOR_DARKS;ダーク -CURVEEDITOR_EDITPOINT_HINT;ボタンを押すと数値で入出力を編集出来ます\n\n編集したいカーブ上のポイントを右クリックします\n編集を無効にする場合はポイント以外の部分で右クリックします +CURVEEDITOR_EDITPOINT_HINT;ボタンを押すと数値で入出力値を変えられるようになります\n\nカーブ上で目標ポイントを右クリックし、カーブ下に表示されるI(入力値)或いはO(出力値)\n編集するポイントを変更する場合はポイント以外の部分で右クリックします CURVEEDITOR_HIGHLIGHTS;ハイライト CURVEEDITOR_LIGHTS;ライト CURVEEDITOR_LINEAR;リニア @@ -103,14 +104,14 @@ EXPORT_BYPASS_SHARPENEDGE;エッジ・シャープニングを迂回 EXPORT_BYPASS_SHARPENING;シャープニングを迂回 EXPORT_BYPASS_SHARPENMICRO;マイクロコントラストを迂回 EXPORT_FASTEXPORTOPTIONS;高速書き出しオプション -EXPORT_INSTRUCTIONS;現像の設定に要する時間と手間を省くために、高速書き出しを優先させるオプションです。処理速度が優先される場合や、既定の現像パラメータを変えずに何枚ものリサイズ画像が要求される場合に奨められる方法で、低解像度画像を迅速に生成します。 +EXPORT_INSTRUCTIONS;出力設定に要する時間と手間を省くために、高速書き出しを優先させるオプションです。処理速度が優先される場合や、既定の出力パラメータを変えずに何枚ものリサイズ画像が要求される場合に奨められる方法で、低解像度画像を迅速に生成します。 EXPORT_MAXHEIGHT;最大高: EXPORT_MAXWIDTH;最大幅: EXPORT_PIPELINE;高速書き出しの方法 EXPORT_PUTTOQUEUEFAST; 高速書き出しのキューに追加 EXPORT_RAW_DMETHOD;デモザイクの方式 EXPORT_USE_FAST_PIPELINE;処理速度優先(リサイズした画像に調整を全て行う) -EXPORT_USE_FAST_PIPELINE_TIP;処理速度を優先すると、処理は速くなりますが、画像の質は落ちます。通常、画像のリサイズは全現像処理工程の最後で行われますが、ここでは処理工程の初めの方でリサイズが行われます。処理速度は著しく上がりますが、現像処理された画像にアーティファクトが発生したり、全体的な質が低下したりします。 +EXPORT_USE_FAST_PIPELINE_TIP;処理速度を優先すると、処理は速くなりますが、画像の質は落ちます。通常、画像のリサイズは全処理工程の最後で行われますが、ここでは処理工程の初めの方でリサイズが行われます。処理速度は著しく上がりますが、処理された画像にアーティファクトが発生したり、全体的な質が低下したりします。 EXPORT_USE_NORMAL_PIPELINE;標準(リサイズ処理は最後、幾つかの処理を迂回) EXTPROGTARGET_1;raw EXTPROGTARGET_2;キュー処理 @@ -232,6 +233,7 @@ GENERAL_DISABLED;無効 GENERAL_ENABLE;有効 GENERAL_ENABLED;有効 GENERAL_FILE;ファイル +GENERAL_HELP;ヘルプ GENERAL_LANDSCAPE;横 GENERAL_NA;n/a GENERAL_NO;No @@ -262,7 +264,7 @@ HISTORY_MSG_1;写真を読み込みました HISTORY_MSG_2;PP3を読み込みました HISTORY_MSG_3;PP3を変更しました HISTORY_MSG_4;履歴ブラウジング -HISTORY_MSG_5;明度 +HISTORY_MSG_5;明るさ HISTORY_MSG_6;コントラスト HISTORY_MSG_7;黒 HISTORY_MSG_8;露光量補正 @@ -431,16 +433,16 @@ HISTORY_MSG_171;L*a*b* LC カーブ HISTORY_MSG_172;LCの適用をレッドと肌色トーンだけに制限 HISTORY_MSG_173;ノイズ低減 - 細部の復元 HISTORY_MSG_174;CIE色の見えモデル2002 -HISTORY_MSG_175;CAM02 - 色順応量 -HISTORY_MSG_176;CAM02 - 観視の暗い周囲環境 -HISTORY_MSG_177;CAM02 - 撮影環境の順応輝度 -HISTORY_MSG_178;CAM02 - 観視の順応輝度 -HISTORY_MSG_179;CAM02 - モデル +HISTORY_MSG_175;CAM02 - CAT02 +HISTORY_MSG_176;CAM02 - 観視環境 +HISTORY_MSG_177;CAM02 - 画像の輝度 +HISTORY_MSG_178;CAM02 - 観視の輝度 +HISTORY_MSG_179;CAM02 - ホワイトポイントモデル HISTORY_MSG_180;CAM02 - 明度 (J) HISTORY_MSG_181;CAM02 - 色度 (C) HISTORY_MSG_182;CAM02 - 自動 CAT02 HISTORY_MSG_183;CAM02 - コントラスト (J) -HISTORY_MSG_184;CAM02 - 暗い周囲環境を伴う撮影環境 +HISTORY_MSG_184;CAM02 - 画像の周辺環境 HISTORY_MSG_185;CAM02 - 色域制御 HISTORY_MSG_186;CAM02 - アルゴリズム HISTORY_MSG_187;CAM02 - レッドと肌色トーンを保護 @@ -455,8 +457,8 @@ HISTORY_MSG_195;CAM02 - トーンカーブ 1 HISTORY_MSG_196;CAM02 - トーンカーブ 2 HISTORY_MSG_197;CAM02 - カラー・カーブ HISTORY_MSG_198;CAM02 - カラー・カーブ -HISTORY_MSG_199;CAM02 - カーブでCIECAM02出力のヒストグラムを表示 -HISTORY_MSG_200;CAM02 - CIECAM02 Q でトーンマッピング +HISTORY_MSG_199;CAM02 - 出力のヒストグラムを表示 +HISTORY_MSG_200;CAM02 - トーンマッピング HISTORY_MSG_201;色差 レッド/グリーン HISTORY_MSG_202;色差 ブルー/イエロー HISTORY_MSG_203;ノイズ低減 - 方式 @@ -592,7 +594,7 @@ HISTORY_MSG_333;W- 残差 シャドウ HISTORY_MSG_334;W- 残差 色度 HISTORY_MSG_335;W- 残差 ハイライト HISTORY_MSG_336;W- 残差 ハイライトのしきい値 -HISTORY_MSG_337;W- 残差 青空の色相 +HISTORY_MSG_337;W- 残差 色相の目標/保護 HISTORY_MSG_338;W- ES 半径 HISTORY_MSG_339;W- ES 強さ HISTORY_MSG_340;W- 強さ @@ -667,7 +669,7 @@ HISTORY_MSG_408;レティネックス - 半径 HISTORY_MSG_409;レティネックス - コントラスト HISTORY_MSG_410;レティネックス - 明るさ HISTORY_MSG_411;レティネックス - 強さ -HISTORY_MSG_412;レティネックス - ガウス暈しのグラデーション +HISTORY_MSG_412;レティネックス - ガウスフィルタの勾配 HISTORY_MSG_413;レティネックス - 差異 HISTORY_MSG_414;レティネックス - ヒストグラム - Lab HISTORY_MSG_415;レティネックス - 透過 @@ -685,8 +687,8 @@ HISTORY_MSG_426;レティネックス - 色相イコライザ HISTORY_MSG_427;出力レンダリングの意図 HISTORY_MSG_428;モニターレンダリングの意図 HISTORY_MSG_429;レティネックス - 繰り返し -HISTORY_MSG_430;レティネックス - 透過のグラデーション -HISTORY_MSG_431;レティネックス - 強さのグラデーション +HISTORY_MSG_430;レティネックス - 透過マップの勾配 +HISTORY_MSG_431;レティネックス - 強さの勾配 HISTORY_MSG_432;レティネックス - M - ハイライト HISTORY_MSG_433;レティネックス - M - ハイライト TW HISTORY_MSG_434;レティネックス - M - シャドウ @@ -695,21 +697,37 @@ HISTORY_MSG_436;レティネックス - M - 半径 HISTORY_MSG_437;レティネックス - M - 方式 HISTORY_MSG_438;レティネックス - M - イコライザ HISTORY_MSG_439;レティネックス - プロセス -HISTORY_MSG_440;詳細レベルコントラスト - 適用 +HISTORY_MSG_440;詳細レベルコントラスト - 処理の順番 HISTORY_MSG_441;レティネックス - 透過率の増加 HISTORY_MSG_442;レティネックス - スケール HISTORY_MSG_443;出力のブラックポイント補正 HISTORY_MSG_444;WB - 色温度のバイアス HISTORY_MSG_445;Raw サブイメージ +HISTORY_MSG_446;EvPixelShiftMotion +HISTORY_MSG_447;EvPixelShiftMotionCorrection +HISTORY_MSG_448;EvPixelShiftStddevFactorGreen HISTORY_MSG_449;PS - ISOへの適合 +HISTORY_MSG_450;EvPixelShiftNreadIso +HISTORY_MSG_451;EvPixelShiftPrnu HISTORY_MSG_452;PS - モーションを表示 HISTORY_MSG_453;PS - マスクだけを表示 +HISTORY_MSG_454;EvPixelShiftAutomatic +HISTORY_MSG_455;EvPixelShiftNonGreenHorizontal +HISTORY_MSG_456;EvPixelShiftNonGreenVertical HISTORY_MSG_457;PS - レッド/ブルーを確認 +HISTORY_MSG_458;EvPixelShiftStddevFactorRed +HISTORY_MSG_459;EvPixelShiftStddevFactorBlue +HISTORY_MSG_460;EvPixelShiftGreenAmaze +HISTORY_MSG_461;EvPixelShiftNonGreenAmaze HISTORY_MSG_462;PS - グリーンを確認 +HISTORY_MSG_463;EvPixelShiftRedBlueWeight HISTORY_MSG_464;PS - モーションマスクをぼかす HISTORY_MSG_465;PS - ぼかしの半径 +HISTORY_MSG_466;EvPixelShiftSum +HISTORY_MSG_467;EvPixelShiftExp0 HISTORY_MSG_468;PS - 穴を埋める HISTORY_MSG_469;PS - メディアン +HISTORY_MSG_470;EvPixelShiftMedian3 HISTORY_MSG_471;PS - 振れの補正 HISTORY_MSG_472;PS - 境界を滑らかにする HISTORY_MSG_473;PS - LMMSEを使う @@ -732,8 +750,434 @@ HISTORY_MSG_489;DRC - CbDL HISTORY_MSG_490;DRC - 量 HISTORY_MSG_491;ホワイトバランス HISTORY_MSG_492;RGBカーブ -HISTORY_MSG_493;L*a*b*調整 +HISTORY_MSG_493;ローカル調整 HISTORY_MSG_494;キャプチャーシャープニング +HISTORY_MSG_496;ローカル スポット 削除 +HISTORY_MSG_497;ローカル スポット 選択 +HISTORY_MSG_498;ローカル スポット 名前 +HISTORY_MSG_499;ローカル スポット 表示 +HISTORY_MSG_500;ローカル スポット 形状 +HISTORY_MSG_501;ローカル スポット 方法 +HISTORY_MSG_502;ローカル スポット 形状の方式 +HISTORY_MSG_503;ローカル スポット 右の垂直線 +HISTORY_MSG_504;ローカル スポット 左の垂直線 +HISTORY_MSG_505;ローカル スポット 下の水平線 +HISTORY_MSG_506;ローカル スポット 上の水平線 +HISTORY_MSG_507;ローカル スポット 中心 +HISTORY_MSG_508;ローカル スポット 大きさ +HISTORY_MSG_509;ローカル スポット 質の種類 +HISTORY_MSG_510;ローカル スポット 境界 +HISTORY_MSG_511;ローカル スポット しきい値 +HISTORY_MSG_512;ローカル スポット ΔEの減衰 +HISTORY_MSG_513;ローカル スポット スコープ +HISTORY_MSG_514;ローカル スポット 構造 +HISTORY_MSG_515;ローカル調整 +HISTORY_MSG_516;ローカル - 色と明るさ +HISTORY_MSG_517;ローカル - 強力を有効にする +HISTORY_MSG_518;ローカル - 明るさ +HISTORY_MSG_519;ローカル - コントラスト +HISTORY_MSG_520;ローカル - 色度 +HISTORY_MSG_521;ローカル - スコープ +HISTORY_MSG_522;ローカル - カーブの方式 +HISTORY_MSG_523;ローカル - LL カーブ +HISTORY_MSG_524;ローカル - CC カーブ +HISTORY_MSG_525;ローカル - LH カーブ +HISTORY_MSG_526;ローカル - H カーブ +HISTORY_MSG_527;ローカル - 反対色 +HISTORY_MSG_528;ローカル - 露光補正 +HISTORY_MSG_529;ローカル - Exp 露光量補正 +HISTORY_MSG_530;ローカル - Exp ハイライト圧縮 +HISTORY_MSG_531;ローカル - Exp ハイライト圧縮のしきい値 +HISTORY_MSG_532;ローカル - Exp 黒レベル +HISTORY_MSG_533;ローカル - Exp 黒レベルの圧縮 +HISTORY_MSG_534;ローカル - ウォームとクール +HISTORY_MSG_535;ローカル - Exp スコープ +HISTORY_MSG_536;ローカル - Exp コントラストカーブ +HISTORY_MSG_537;ローカル - 自然な彩度 +HISTORY_MSG_538;ローカル - Vib 純色 +HISTORY_MSG_539;ローカル - Vib パステル +HISTORY_MSG_540;ローカル - Vib しきい値 +HISTORY_MSG_541;ローカル - Vib 肌色の保護 +HISTORY_MSG_542;ローカル - Vib 色ずれの回避 +HISTORY_MSG_543;ローカル - Vib リンク +HISTORY_MSG_544;ローカル - Vib スコープ +HISTORY_MSG_545;ローカル - Vib H カーブ +HISTORY_MSG_546;ローカル - ぼかしとノイズ +HISTORY_MSG_547;ローカル - 半径 +HISTORY_MSG_548;ローカル - ノイズ +HISTORY_MSG_549;ローカル - ぼかしのスコープ +HISTORY_MSG_550;ローカル - ぼかしの方式 +HISTORY_MSG_551;ローカル - ぼかし 輝度だけ +HISTORY_MSG_552;ローカル - トーンマッピング +HISTORY_MSG_553;ローカル - TM 強さ +HISTORY_MSG_554;ローカル - TM ガンマ +HISTORY_MSG_555;ローカル - TM エッジ停止 +HISTORY_MSG_556;ローカル - TM スケール +HISTORY_MSG_557;ローカル - TM 再加重 +HISTORY_MSG_558;ローカル - TM スコープ +HISTORY_MSG_559;ローカル - レティネックス +HISTORY_MSG_560;ローカル - レティネックス 方式 +HISTORY_MSG_561;ローカル - レティネックス 強さ +HISTORY_MSG_562;ローカル - レティネックス 色度 +HISTORY_MSG_563;ローカル - レティネックス 半径 +HISTORY_MSG_564;ローカル - レティネックス コントラスト +HISTORY_MSG_565;ローカル - スコープ +HISTORY_MSG_566;ローカル - レティネックス ゲインのカーブ +HISTORY_MSG_567;ローカル - レティネックス 反対処理 +HISTORY_MSG_568;ローカル - シャープニング +HISTORY_MSG_569;ローカル - Sh 半径 +HISTORY_MSG_570;ローカル - Sh 量 +HISTORY_MSG_571;ローカル - Sh 減衰 +HISTORY_MSG_572;ローカル - Sh 繰り返し +HISTORY_MSG_573;ローカル - Sh スコープ +HISTORY_MSG_574;ローカル - Sh 反対処理 +HISTORY_MSG_575;ローカル - 詳細レベルによるコントラスト調整 +HISTORY_MSG_576;ローカル - CbDL 複数のレベル +HISTORY_MSG_577;ローカル - CbDL 色度 +HISTORY_MSG_578;ローカル - CbDL しきい値 +HISTORY_MSG_579;ローカル - CbDL スコープ +HISTORY_MSG_580;ローカル - ノイズ除去 +HISTORY_MSG_581;ローカル - ノイズ除去 輝度 細かい1 +HISTORY_MSG_582;ローカル - ノイズ除去 輝度 祖い +HISTORY_MSG_583;ローカル - ノイズ除去 細部の回復 +HISTORY_MSG_584;ローカル - ノイズ除去 イコライザ 白黒 +HISTORY_MSG_585;ローカル - ノイズ除去 色度 細かい +HISTORY_MSG_586;ローカル - ノイズ除去 色度 粗い +HISTORY_MSG_587;ローカル - ノイズ除去 色度の回復 +HISTORY_MSG_588;ローカル - ノイズ除去 イコライザ ブルー-レッド +HISTORY_MSG_589;ローカル - ノイズ除去 平滑化フィルタ +HISTORY_MSG_590;ローカル - ノイズ除去 スコープ +HISTORY_MSG_591;ローカル - 色ずれの回避 +HISTORY_MSG_592;ローカル - Sh コントラスト +HISTORY_MSG_593;ローカル - ローカルコントラスト +HISTORY_MSG_594;ローカル - ローカルコントラスト 半径 +HISTORY_MSG_595;ローカル - ローカルコントラスト 量 +HISTORY_MSG_596;ローカル - ローカルコントラスト 暗さ +HISTORY_MSG_597;ローカル - ローカルコントラスト 明るさ +HISTORY_MSG_598;ローカル - ローカルコントラスト スコープ +HISTORY_MSG_599;ローカル - レティネックス 霞除去 +HISTORY_MSG_600;ローカル - ソフトライト 有効 +HISTORY_MSG_601;ローカル - ソフトライト 強さ +HISTORY_MSG_602;ローカル - ソフトライト スコープ +HISTORY_MSG_603;ローカル - Sh ぼかしの半径 +HISTORY_MSG_605;ローカル - 色と明るさの変更 +HISTORY_MSG_606;ローカル - 露光の変更 +HISTORY_MSG_607;ローカル - 色と明るさ マスク C +HISTORY_MSG_608;ローカル - 色と明るさ マスク L +HISTORY_MSG_609;ローカル - 露光補正 マスク C +HISTORY_MSG_610;ローカル - 露光補正 マスク L +HISTORY_MSG_611;ローカル - 色と明るさ マスク H +HISTORY_MSG_612;ローカル - 色と明るさ 構造 +HISTORY_MSG_613;ローカル - 露光補正 構造 +HISTORY_MSG_614;ローカル - 露光補正 マスク H +HISTORY_MSG_615;ローカル - 色と明るさ ブレンド +HISTORY_MSG_616;ローカル - 露光補正 ブレンド +HISTORY_MSG_617;ローカル - 露光補正 ぼかし +HISTORY_MSG_618;ローカル - 色と明るさ マスクを使う +HISTORY_MSG_619;ローカル - 露光補正 マスクを使う +HISTORY_MSG_620;ローカル - 色と明るさ ぼかし +HISTORY_MSG_621;ローカル - 露光補正 反対処理 +HISTORY_MSG_622;ローカル - 構造の除外 +HISTORY_MSG_623;ローカル - 露光補正 色の補間 +HISTORY_MSG_624;ローカル - 色と明るさ 補正グリッド +HISTORY_MSG_625;ローカル - 色と明るさ 補正の強さ +HISTORY_MSG_626;ローカル - 色と明るさ 補正の方式 +HISTORY_MSG_627;ローカル - シャドウ/ハイライト +HISTORY_MSG_628;ローカル - SH ハイライト +HISTORY_MSG_629;ローカル - SH ハイライトトーンの幅 +HISTORY_MSG_630;ローカル - SH シャドウ +HISTORY_MSG_631;ローカル - SH シャドウトーンの幅 +HISTORY_MSG_632;ローカル - SH 半径 +HISTORY_MSG_633;ローカル - SH スコープ +HISTORY_MSG_634;ローカル - 色と明るさ 半径 +HISTORY_MSG_635;ローカル - 露光補正 半径 +HISTORY_MSG_636;ローカル - 追加された機能 +HISTORY_MSG_637;ローカル - SH マスク C +HISTORY_MSG_638;ローカル - SH マスク L +HISTORY_MSG_639;ローカル - SH マスク H +HISTORY_MSG_640;ローカル - SH ブレンド +HISTORY_MSG_641;ローカル - SH マスクを使用 +HISTORY_MSG_642;ローカル - SH 半径 +HISTORY_MSG_643;ローカル - SH ぼかし +HISTORY_MSG_644;ローカル - SH 反対処理 +HISTORY_MSG_645;ローカル - 色差のバランス ab-L +HISTORY_MSG_646;ローカル - 露光補正 色度のマスク +HISTORY_MSG_647;ローカル - 露光補正 ガンマのマスク +HISTORY_MSG_648;ローカル - 露光補正 スロープのマスク +HISTORY_MSG_649;ローカル - 露光補正 ソフトな半径 +HISTORY_MSG_650;ローカル - 色と明るさ 色度のマスク +HISTORY_MSG_651;ローカル - 色と明るさ ガンマのマスク +HISTORY_MSG_652;ローカル - 色と明るさ スロープのマスク +HISTORY_MSG_653;ローカル - SH 色度のマスク +HISTORY_MSG_654;ローカル - SH ガンマのマスク +HISTORY_MSG_655;ローカル - SH スロープのマスク +HISTORY_MSG_656;ローカル - 色と明るさ ソフトな半径 +HISTORY_MSG_657;ローカル - レティネックス アーティファクトの軽減 +HISTORY_MSG_658;ローカル - CbDL ソフトな半径 +HISTORY_MSG_659;ローカル スポット 境界値の減衰 +HISTORY_MSG_660;ローカル - CbDL 明瞭 +HISTORY_MSG_661;ローカル - CbDL 残差のコントラスト +HISTORY_MSG_662;ローカル - deNoise 輝度 細かい0 +HISTORY_MSG_663;ローカル - deNoise 輝度 細かい2 +HISTORY_MSG_664;ローカル - CbDL ぼかし +HISTORY_MSG_665;ローカル - CbDL ブレンドのマスク +HISTORY_MSG_666;ローカル - CbDL 半径のマスク +HISTORY_MSG_667;ローカル - CbDL 色度のマスク +HISTORY_MSG_668;ローカル - CbDL ガンマのマスク +HISTORY_MSG_669;ローカル - CbDL スロープのマスク +HISTORY_MSG_670;ローカル - CbDL マスク C +HISTORY_MSG_671;ローカル - CbDL マスク L +HISTORY_MSG_672;ローカル - CbDL マスク CL +HISTORY_MSG_673;ローカル - CbDL マスクを使う +HISTORY_MSG_674;ローカル - 削除された機能 +HISTORY_MSG_675;ローカル - TM ソフトな半径 +HISTORY_MSG_676;ローカル スポット 境界の差異 +HISTORY_MSG_677;ローカル - TM 量 +HISTORY_MSG_678;ローカル - TM 彩度 +HISTORY_MSG_679;ローカル - レティネックス マスク C +HISTORY_MSG_680;ローカル - レティネックス マスク L +HISTORY_MSG_681;ローカル - レティネックス マスク CL +HISTORY_MSG_682;ローカル - レティネックス マスク +HISTORY_MSG_683;ローカル - レティネックス ブレンドのマスク +HISTORY_MSG_684;ローカル - レティネックス 半径のマスク +HISTORY_MSG_685;ローカル - レティネックス 色度のマスク +HISTORY_MSG_686;ローカル - レティネックス ガンマのマスク +HISTORY_MSG_687;ローカル - レティネックス スロープのマスク +HISTORY_MSG_688;ローカル - 削除された機能 +HISTORY_MSG_689;ローカル - レティネックス 透過マップのマスク +HISTORY_MSG_690;ローカル - レティネックス スケール +HISTORY_MSG_691;ローカル - レティネックス 暗さ +HISTORY_MSG_692;ローカル - レティネックス 明るさ +HISTORY_MSG_693;ローカル - レティネックス しきい値 +HISTORY_MSG_694;ローカル - レティネックス ラプラシアンのしきい値 +HISTORY_MSG_695;ローカル - ソフトの方式 +HISTORY_MSG_696;ローカル - レティネックス 標準化 +HISTORY_MSG_697;ローカル - TM 標準化 +HISTORY_MSG_698;ローカル - ローカルコントラスト 高速フーリエ変換 +HISTORY_MSG_699;ローカル - レティネックス 高速フーリエ変換 +HISTORY_MSG_701;ローカル - Exp シャドウ +HISTORY_MSG_702;ローカル - Exp 方式 +HISTORY_MSG_703;ローカル - Exp ラプラシアンのしきい値 +HISTORY_MSG_704;ローカル - Exp PDEのバランス +HISTORY_MSG_705;ローカル - Exp 線形 +HISTORY_MSG_706;ローカル - TM マスク C +HISTORY_MSG_707;ローカル - TM マスク L +HISTORY_MSG_708;ローカル - TM マスク CL +HISTORY_MSG_709;ローカル - TM マスク マスク +HISTORY_MSG_710;ローカル - TM ブレンドのマスク +HISTORY_MSG_711;ローカル - TM 半径のマスク +HISTORY_MSG_712;ローカル - TM 色度のマスク +HISTORY_MSG_713;ローカル - TM ガンマのマスク +HISTORY_MSG_714;ローカル - TM スロープのマスク +HISTORY_MSG_716;ローカル - ローカル 方式 +HISTORY_MSG_717;ローカル - ローカルコントラスト +HISTORY_MSG_718;ローカル - ローカルコントラストのレベル +HISTORY_MSG_719;ローカル - ローカルコントラスト 残差L +HISTORY_MSG_720;ローカル - ぼかし マスク C +HISTORY_MSG_721;ローカル - ぼかし マスク L +HISTORY_MSG_722;ローカル - ぼかし マスク CL +HISTORY_MSG_723;ローカル - ぼかし マスクを使う +HISTORY_MSG_725;ローカル - ぼかし ブレンドのマスク +HISTORY_MSG_726;ローカル - ぼかし 半径のマスク +HISTORY_MSG_727;ローカル - ぼかし 色度のマスク +HISTORY_MSG_728;ローカル - ぼかし ガンマのマスク +HISTORY_MSG_729;ローカル - ぼかし スロープのマスク +HISTORY_MSG_730;ローカル - ぼかしの方式 +HISTORY_MSG_731;ローカル - メディアンの方式 +HISTORY_MSG_732;ローカル - メディアン 繰り返し +HISTORY_MSG_733;ローカル - ソフトな半径 +HISTORY_MSG_734;ローカル - ディテール +HISTORY_MSG_738;ローカル - ローカルコントラスト Lを統合 +HISTORY_MSG_739;ローカル - ローカルコントラスト ソフトな半径 +HISTORY_MSG_740;ローカル - ローカルコントラスト Cを統合 +HISTORY_MSG_741;ローカル - ローカルコントラスト 残差C +HISTORY_MSG_742;ローカル - Exp ラプラシアンのガンマ +HISTORY_MSG_743;ローカル - Exp Fattal 量 +HISTORY_MSG_744;ローカル - Exp Fattal ディテール +HISTORY_MSG_745;ローカル - Exp Fattal オフセット +HISTORY_MSG_746;ローカル - Exp Fattal シグマ +HISTORY_MSG_747;ローカル 作成されたスポット +HISTORY_MSG_748;ローカル - Exp ノイズ除去 +HISTORY_MSG_749;ローカル - Reti 深度 +HISTORY_MSG_750;ローカル - Reti モード 対数 - 線形 +HISTORY_MSG_751;ローカル - Reti 霞除去 輝度だけ +HISTORY_MSG_752;ローカル - Reti オフセット +HISTORY_MSG_753;ローカル - Reti 透過マップ +HISTORY_MSG_754;ローカル - Reti クリップ +HISTORY_MSG_755;ローカル - TM マスクを使う +HISTORY_MSG_756;ローカル - Exp 露光補正マスクのアルゴリズムを使う +HISTORY_MSG_757;ローカル - Exp ラプラシアンマスク +HISTORY_MSG_758;ローカル - Reti ラプラシアンマスク +HISTORY_MSG_759;ローカル - Exp ラプラシアンマスク +HISTORY_MSG_760;ローカル - Color ラプラシアンマスク +HISTORY_MSG_761;ローカル - SH ラプラシアンマスク +HISTORY_MSG_762;ローカル - cbdl ラプラシアンマスク +HISTORY_MSG_763;ローカル - Blur ラプラシアンマスク +HISTORY_MSG_764;ローカル - Solve PDE ラプラシアンマスク +HISTORY_MSG_765;ローカル - deNoise ディテールのしきい値 +HISTORY_MSG_766;ローカル - Blur 高速フーリエ変換 +HISTORY_MSG_767;ローカル - Grain ISO +HISTORY_MSG_768;ローカル - Grain 強さ +HISTORY_MSG_769;ローカル - Grain スケール +HISTORY_MSG_770;ローカル - Color コントラストカーブのマスク +HISTORY_MSG_771;ローカル - Exp コントラストカーブのマスク +HISTORY_MSG_772;ローカル - SH コントラストカーブのマスク +HISTORY_MSG_773;ローカル - TM コントラストカーブのマスク +HISTORY_MSG_774;ローカル - Reti コントラストカーブのマスク +HISTORY_MSG_775;ローカル - CBDL コントラストカーブのマスク +HISTORY_MSG_776;ローカル - Blur Denoise コントラストカーブのマスク +HISTORY_MSG_777;ローカル - Blur ローカルコントラストカーブのマスク +HISTORY_MSG_778;ローカル - ハイライトのマスク +HISTORY_MSG_779;ローカル - 色と明るさ ローカルコントラストカーブのマスク +HISTORY_MSG_780;ローカル - 色と明るさ シャドウのマスク +HISTORY_MSG_781;ローカル - コントラスト ウェーブレットのレベルのマスク +HISTORY_MSG_782;ローカル - Blur Denoise ウェーブレットのレベルのマスク +HISTORY_MSG_783;ローカル - 色と明るさ ウェーブレットのレベル +HISTORY_MSG_784;ローカル - ΔEのマスク +HISTORY_MSG_785;ローカル - ΔEのスコープのマスク +HISTORY_MSG_786;ローカル - SH 方式 +HISTORY_MSG_787;ローカル - イコライザの乗数 +HISTORY_MSG_788;ローカル - イコライザのディテール +HISTORY_MSG_789;ローカル - SH マスクの量 +HISTORY_MSG_790;ローカル - SH マスクのアンカー +HISTORY_MSG_791;ローカル - マスク ショートLカーブ +HISTORY_MSG_792;ローカル - マスク 背景輝度 +HISTORY_MSG_793;ローカル - SH TRCのガンマ +HISTORY_MSG_794;ローカル - SH TRCのスロープ +HISTORY_MSG_795;ローカル - マスク 復元したイメージの保存 +HISTORY_MSG_796;ローカル - 参考値の繰り返し +HISTORY_MSG_797;ローカル - オリジナルとの融合方式 +HISTORY_MSG_798;ローカル - 不透明度 +HISTORY_MSG_799;ローカル - Color RGB トーンカーブ +HISTORY_MSG_800;ローカル - Color トーンカーブの方式 +HISTORY_MSG_801;ローカル - Color 特殊なトーンカーブ +HISTORY_MSG_802;ローカル - コントラストしきい値 +HISTORY_MSG_803;ローカル - 色と明るさ 融合 +HISTORY_MSG_804;ローカル - 色と明るさ マスクの構造 +HISTORY_MSG_805;ローカル - ぼかしとノイズ マスクの構造 +HISTORY_MSG_806;ローカル - 色と明るさ 機能としてのマスクの構造 +HISTORY_MSG_807;ローカル - ぼかしとノイズ 機能としてのマスクの構造 +HISTORY_MSG_808;ローカル - 色と明るさ マスクカーブ H(H) +HISTORY_MSG_809;ローカル - Vib カーブのマスク C(C) +HISTORY_MSG_810;ローカル - Vib カーブのマスク L(L) +HISTORY_MSG_811;ローカル - Vib カーブのマスク LC(H) +HISTORY_MSG_813;ローカル - 自然な彩度 マスクを使う +HISTORY_MSG_814;ローカル - Vib ブレンドのマスク +HISTORY_MSG_815;ローカル - Vib 半径のマスク +HISTORY_MSG_816;ローカル - Vib 色度のマスク +HISTORY_MSG_817;ローカル - Vib ガンマのマスク +HISTORY_MSG_818;ローカル - Vib 勾配のマスク +HISTORY_MSG_819;ローカル - Vib ラプラシアンのマスク +HISTORY_MSG_820;ローカル - Vib コントラストカーブのマスク +HISTORY_MSG_821;ローカル - 色と明るさ 背景のグリッド +HISTORY_MSG_822;ローカル - 色と明るさ 背景の融合 +HISTORY_MSG_823;ローカル - 色と明るさ 背景の融合 輝度だけ +HISTORY_MSG_824;ローカル - Exp 減光マスクの強さ +HISTORY_MSG_825;ローカル - Exp 減光マスクの角度 +HISTORY_MSG_826;ローカル - Exp 減光の強さ +HISTORY_MSG_827;ローカル - Exp 減光の角度 +HISTORY_MSG_828;ローカル - SH 階調 強さ +HISTORY_MSG_829;ローカル - SH 階調 角度 +HISTORY_MSG_830;ローカル - 色と明るさ 階調 Lの強さ +HISTORY_MSG_831;ローカル - 色と明るさ 階調 角度 +HISTORY_MSG_832;ローカル - 色と明るさ 階調 Cの強さ +HISTORY_MSG_833;ローカル - 減光のフェザー処理 +HISTORY_MSG_834;ローカル - 色と明るさ 減光の強さ H +HISTORY_MSG_835;ローカル - Vib 諧調 Lの強さ +HISTORY_MSG_836;ローカル - Vib 階調 角度 +HISTORY_MSG_837;ローカル - Vib 階調 Cの強さ +HISTORY_MSG_838;ローカル - Vib 階調 Hの強さ +HISTORY_MSG_839;ローカル - ソフトウェアの難易度 +HISTORY_MSG_840;ローカル - CL カーブ +HISTORY_MSG_841;ローカル - LC カーブ +HISTORY_MSG_842;ローカル - マスクぼかしのコントラストしきい値 +HISTORY_MSG_843;ローカル - マスクぼかしの半径 +HISTORY_MSG_844;ローカル - 色と明るさ マスク FTTW +HISTORY_MSG_845;ローカル - 対数符号化 +HISTORY_MSG_846;ローカル - 符号化 自動 +HISTORY_MSG_847;ローカル - グレーポイントの源泉 +HISTORY_MSG_848;ローカル - グレーポイントの源泉 自動 +HISTORY_MSG_849;ローカル - グレーポイントの自動選択 +HISTORY_MSG_850;ローカル - ブラックEv +HISTORY_MSG_851;ローカル - ホワイトEv +HISTORY_MSG_852;ローカル - グレーポイントの目標 +HISTORY_MSG_853;ローカル - ローカルコントラスト +HISTORY_MSG_854;ローカル - 対数符号化のスコープ +HISTORY_MSG_855;ローカル - 画像全体 +HISTORY_MSG_856;ローカル - 対数の基数 +HISTORY_MSG_857;ローカル - Contrast 残差のぼかし +HISTORY_MSG_858;ローカル - Contrast 輝度だけ +HISTORY_MSG_859;ローカル - Contrast 最大値 ぼかしレベル +HISTORY_MSG_860;ローカル - Contrast カーブ ぼかすレベル +HISTORY_MSG_861;ローカル - Contrast カーブ コントラストレベル +HISTORY_MSG_862;ローカル - Contrast シグマ 輝度 +HISTORY_MSG_863;ローカル - Contrast 元画像との融合 +HISTORY_MSG_864;ローカル - Contrast ディテール +HISTORY_MSG_865;ローカル - Contrast アンカー +HISTORY_MSG_866;ローカル - Contrast カーブの圧縮 +HISTORY_MSG_867;ローカル - Contrast 残差の量 +HISTORY_MSG_868;ローカル - ΔEのバランス C-H +HISTORY_MSG_869;ローカル - ノイズ除去カーブ 輝度 +HISTORY_MSG_870;ローカル - LC カーブのマスク LC(H) +HISTORY_MSG_871;ローカル - LC カーブのマスク C(C) +HISTORY_MSG_872;ローカル - LC カーブのマスク L(L) +HISTORY_MSG_873;ローカル - LC マスク 有効 +HISTORY_MSG_875;ローカル - LC マスク ブレンド +HISTORY_MSG_876;ローカル - LC マスク 半径 +HISTORY_MSG_877;ローカル - LC マスク 色度 +HISTORY_MSG_878;ローカル - LC カーブのマスク コントラスト +HISTORY_MSG_879;ローカル - LC 色度 レベル +HISTORY_MSG_880;ローカル - LC 色度のぼかし レベル +HISTORY_MSG_881;ローカル - Contrast オフセット 輝度 +HISTORY_MSG_882;ローカル - Contrast ぼかし +HISTORY_MSG_883;ローカル - Contrast レベルごと +HISTORY_MSG_884;ローカル - Contrast ダイナミックレンジ ラプラシアン +HISTORY_MSG_885;ローカル - Contrast ダイナミックレンジ ウェーブレット +HISTORY_MSG_886;ローカル - Contrast ウェーブレット カーブの圧縮 +HISTORY_MSG_887;ローカル - Contrast ウェーブレット 残差の圧縮 +HISTORY_MSG_888;ローカル - Contrast ウェーブレット バランスのしきい値 +HISTORY_MSG_889;ローカル - Contrast ウェーブレット 階調の強さ +HISTORY_MSG_890;ローカル - Contrast ウェーブレット 階調の角度 +HISTORY_MSG_891;ローカル - Contrast ウェーブレット 階調フィルタ +HISTORY_MSG_892;ローカル - 対数符号化 階調の強さ +HISTORY_MSG_893;ローカル - 対数符号化 階調の角度 +HISTORY_MSG_894;ローカル - 色と明るさ 色差のプレビュー +HISTORY_MSG_897;ローカル - Contrast ウェーブレット ES 強さ +HISTORY_MSG_898;ローカル - Contrast ウェーブレット ES 半径 +HISTORY_MSG_899;ローカル - Contrast ウェーブレット ES ディテール +HISTORY_MSG_900;ローカル - Contrast ウェーブレット ES 勾配 +HISTORY_MSG_901;ローカル - Contrast ウェーブレット ES しきい値 低 +HISTORY_MSG_902;ローカル - Contrast ウェーブレット ES しきい値 高 +HISTORY_MSG_903;ローカル - Contrast ウェーブレット ES ローカルコントラスト +HISTORY_MSG_904;ローカル - Contrast ウェーブレット ES 最初のレベル +HISTORY_MSG_905;ローカル - Contrast ウェーブレット エッジシャープネス +HISTORY_MSG_906;ローカル - Contrast ウェーブレット ES 感度 +HISTORY_MSG_907;ローカル - Contrast ウェーブレット ES 増幅 +HISTORY_MSG_908;ローカル - Contrast ウェーブレット ES 隣接 +HISTORY_MSG_909;ローカル - Contrast ウェーブレット ES 表示 +HISTORY_MSG_910;ローカル - ウェーブレット エッジ検出の効果 +HISTORY_MSG_911;ローカル - ぼかし 色度 輝度 +HISTORY_MSG_912;ローカル - ガイド付きフィルターの強さのぼかし +HISTORY_MSG_913;ローカル - Contrast Wavelet Sigma DR +HISTORY_MSG_914;ローカル - ウェーブレットのぼかし シグマ BL +HISTORY_MSG_915;ローカル - ウェーブレットのエッジ シグマ ED +HISTORY_MSG_916;ローカル - ウェーブレットの残差画像 シャドウ +HISTORY_MSG_917;ローカル - ウェーブレットの残差画像 シャドウのしきい値 +HISTORY_MSG_918;ローカル - ウェーブレットの残差画像 ハイライト +HISTORY_MSG_919;ローカル - ウェーブレットの残差画像 ハイライトのしきい値 +HISTORY_MSG_920;ローカル - ウェーブレット シグマ LC +HISTORY_MSG_921;ローカル - ウェーブレット 階調のシグマ LC2 +HISTORY_MSG_922;ローカル - 白黒での変更 +HISTORY_MSG_923;ローカル - 機能の複雑度モード +HISTORY_MSG_924;ローカル - 機能の複雑度モード +HISTORY_MSG_925;Local - カラー機能のスコープ +HISTORY_MSG_926;Local - マスクのタイプを表示 +HISTORY_MSG_927;Local - シャドウマスク +HISTORY_MSG_BLSHAPE;詳細レベルによるぼかし +HISTORY_MSG_BLURCWAV;色度のぼかし +HISTORY_MSG_BLURWAV;輝度のぼかし +HISTORY_MSG_BLUWAV;減衰応答 +HISTORY_MSG_CAT02PRESET;Cat02 自動プリセット HISTORY_MSG_CLAMPOOG;色域外の色を切り取る HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - カラー補正 HISTORY_MSG_COLORTONING_LABREGION_AB;CT - 色の補正 @@ -756,7 +1200,9 @@ HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;霞除去 - 深度マップの表示 HISTORY_MSG_DEHAZE_STRENGTH;霞除去 - 強さ HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;デュアルデモザイク - 自動しきい値 HISTORY_MSG_DUALDEMOSAIC_CONTRAST;AMaZE+VNG4 - コントラストのしきい値 +HISTORY_MSG_EDGEFFECT;エッジの効果調整 HISTORY_MSG_FILMNEGATIVE_ENABLED;ネガフィルム +HISTORY_MSG_FILMNEGATIVE_FILMBASE;フィルムのベースカラー HISTORY_MSG_FILMNEGATIVE_VALUES;ネガフィルムの値 HISTORY_MSG_HISTMATCHING;トーンカーブの自動調節 HISTORY_MSG_ICM_OUTPUT_PRIMARIES;出力 - プライマリ @@ -765,6 +1211,7 @@ HISTORY_MSG_ICM_OUTPUT_TYPE;出力 - タイプ HISTORY_MSG_ICM_WORKING_GAMMA;作業色空間 - ガンマ HISTORY_MSG_ICM_WORKING_SLOPE;作業色空間 - 勾配 HISTORY_MSG_ICM_WORKING_TRC_METHOD;作業色空間 - TRCの方式 +HISTORY_MSG_ILLUM;輝度 HISTORY_MSG_LOCALCONTRAST_AMOUNT;ローカルコントラスト - 量 HISTORY_MSG_LOCALCONTRAST_DARKNESS;ローカルコントラスト - 暗い部分 HISTORY_MSG_LOCALCONTRAST_ENABLED;ローカルコントラスト @@ -779,10 +1226,20 @@ HISTORY_MSG_PDSHARPEN_CONTRAST;CS - コントラストのしきい値 HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - 繰り返し HISTORY_MSG_PDSHARPEN_RADIUS;CS - シグマ HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - 周辺のシグマを増やす +HISTORY_MSG_PERSP_CAM_ANGLE;パースペクティブ - カメラ +HISTORY_MSG_PERSP_CAM_FL;パースペクティブ - カメラ +HISTORY_MSG_PERSP_CAM_SHIFT;パースペクティブ - カメラ +HISTORY_MSG_PERSP_METHOD;パースペクティブ - 方法 +HISTORY_MSG_PERSP_PROJ_ANGLE;パースペクティブ - 回復 +HISTORY_MSG_PERSP_PROJ_ROTATE;パースペクティブ - PCA 回転 +HISTORY_MSG_PERSP_PROJ_SHIFT;パースペクティブ - PCA HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - 振れに対するデモザイクの方式 HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;ラインノイズフィルタの方向 HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAFラインフィルタ +HISTORY_MSG_PREPROCWB_MODE;ホワイトバランスモードの前処理 +HISTORY_MSG_PROTAB;保護 HISTORY_MSG_PRSHARPEN_CONTRAST;PRS - コントラストのしきい値 +HISTORY_MSG_RANGEAB;abの範囲 HISTORY_MSG_RAWCACORR_AUTOIT;Rawの色収差補正 - 繰り返し HISTORY_MSG_RAWCACORR_COLORSHIFT;Rawの色収差補正 - 色ずれを回避 HISTORY_MSG_RAW_BORDER;Rawの境界 @@ -790,9 +1247,35 @@ HISTORY_MSG_RESIZE_ALLOWUPSCALING;リサイズ - アップスケーリングを HISTORY_MSG_SHARPENING_BLUR;シャープニング - ぼかしの半径 HISTORY_MSG_SHARPENING_CONTRAST;シャープニング - コントラストのしきい値 HISTORY_MSG_SH_COLORSPACE;S/H - 色空間 +HISTORY_MSG_SIGMACOL;色度の効果調整 +HISTORY_MSG_SIGMADIR;Dirの効果調整 +HISTORY_MSG_SIGMAFIN;最終的なコントラストの効果調整 +HISTORY_MSG_SIGMATON;トーンの効果調整 HISTORY_MSG_SOFTLIGHT_ENABLED;ソフトライト HISTORY_MSG_SOFTLIGHT_STRENGTH;ソフトライト - 強さ +HISTORY_MSG_TEMPOUT;CAM02 自動色温度設定 +HISTORY_MSG_THRESWAV;バランスのしきい値 HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - アンカー +HISTORY_MSG_TRANS_Method;ジオメトリ - 方式 +HISTORY_MSG_WAVBALCHROM;イコライザ 色度 +HISTORY_MSG_WAVBALLUM;イコライザ 輝度 +HISTORY_MSG_WAVBL;レベルのぼかし +HISTORY_MSG_WAVCHROMCO;粗い部分の色度 +HISTORY_MSG_WAVCHROMFI;細部の色度 +HISTORY_MSG_WAVCLARI;明瞭 +HISTORY_MSG_WAVEDGS;エッジ停止 +HISTORY_MSG_WAVLOWTHR;最小コントラストのしきい値 +HISTORY_MSG_WAVMERGEC;色度の融合 +HISTORY_MSG_WAVMERGEL;輝度の融合 +HISTORY_MSG_WAVOFFSET;オフセット +HISTORY_MSG_WAVOLDSH;古いアルゴリズムを使う +HISTORY_MSG_WAVRADIUS;シャドウ/ハイライトの半径 +HISTORY_MSG_WAVSCALE;スケール +HISTORY_MSG_WAVSHOWMASK;ウェーブレットのマスクを表示 +HISTORY_MSG_WAVSIGMA;シグマ +HISTORY_MSG_WAVSOFTRAD;明瞭のソフトな半径 +HISTORY_MSG_WAVSOFTRADEND;最終画像のソフトな半径 +HISTORY_MSG_WAVUSHAMET;明瞭の方式 HISTORY_NEWSNAPSHOT;追加 HISTORY_NEWSNAPSHOT_TOOLTIP;ショートカット: Alt-s HISTORY_SNAPSHOT;スナップショット @@ -880,7 +1363,6 @@ IPTCPANEL_TITLE;タイトル IPTCPANEL_TITLEHINT;画像を短く表す言葉や撮影者名、或いは画像のタイトルでもよい IPTCPANEL_TRANSREFERENCE;作業のID IPTCPANEL_TRANSREFERENCEHINT;作業工程の管理やトラッキングのための画像の数字或いは識別 -LENSPROFILE_LENS_WARNING;注意:レンズプロファイルに関する切り抜きの因数がカメラの因数より大きいと、誤った結果になるかもしれません MAIN_BUTTON_FULLSCREEN;フルスクリーン MAIN_BUTTON_ICCPROFCREATOR;ICCプロファイルクリエーター MAIN_BUTTON_NAVNEXT_TOOLTIP;エディタで開いている画像に対応する次の画像に移動します\nショートカット: Shift-F4\n\nファイルブラウザで選択したサムネイルに対応する次の画像に移動するには\nショートカット: F4 @@ -921,7 +1403,7 @@ MAIN_TAB_ADVANCED;高度な機能 MAIN_TAB_ADVANCED_TOOLTIP;ショートカット: Alt-a MAIN_TAB_COLOR;カラー MAIN_TAB_COLOR_TOOLTIP;ショートカット: Alt-c -MAIN_TAB_DETAIL;CbDL +MAIN_TAB_DETAIL;ディテール MAIN_TAB_DETAIL_TOOLTIP;ショートカット: Alt-d MAIN_TAB_DEVELOP;一括編集 MAIN_TAB_EXIF;Exif @@ -933,6 +1415,8 @@ MAIN_TAB_FAVORITES_TOOLTIP;ショートカット: Alt-u MAIN_TAB_FILTER;絞り込み MAIN_TAB_INSPECT;カメラ出しJPEG MAIN_TAB_IPTC;IPTC +MAIN_TAB_LOCALLAB;ローカル調整 +MAIN_TAB_LOCALLAB_TOOLTIP;ショートカット Alt-o MAIN_TAB_METADATA;メタデータ MAIN_TAB_METADATA_TOOLTIP;ショートカット: Alt-m MAIN_TAB_RAW;raw @@ -1012,20 +1496,24 @@ PARTIALPASTE_GRADIENT;減光フィルター PARTIALPASTE_HSVEQUALIZER;HSV イコライザ PARTIALPASTE_ICMSETTINGS;ICM 設定 PARTIALPASTE_IMPULSEDENOISE;インパルス・ノイズ低減 -PARTIALPASTE_IPTCINFO;IPTC 情報 +PARTIALPASTE_IPTCINFO;IPTC PARTIALPASTE_LABCURVE;L*a*b* 調整 -PARTIALPASTE_LENSGROUP;レンズ設定 +PARTIALPASTE_LENSGROUP;レンズ関係の設定 PARTIALPASTE_LENSPROFILE;レンズ補正プロファイル PARTIALPASTE_LOCALCONTRAST;ローカルコントラスト +PARTIALPASTE_LOCALLAB;ローカル調整 +PARTIALPASTE_LOCALLABGROUP;ローカル調整の設定 +PARTIALPASTE_LOCGROUP;ローカル PARTIALPASTE_METADATA;メタデータモード PARTIALPASTE_METAGROUP;メタデータ PARTIALPASTE_PCVIGNETTE;ビネットフィルター PARTIALPASTE_PERSPECTIVE;パースペクティブの補正 PARTIALPASTE_PREPROCESS_DEADPIXFILT;デッドピクセルフィルターを適用 PARTIALPASTE_PREPROCESS_GREENEQUIL;グリーン 平衡化 -PARTIALPASTE_PREPROCESS_HOTPIXFILT;ホットピクセルフィルターを適用 +PARTIALPASTE_PREPROCESS_HOTPIXFILT;ホットピクセルフィルター PARTIALPASTE_PREPROCESS_LINEDENOISE;ラインノイズ フィルタ PARTIALPASTE_PREPROCESS_PDAFLINESFILTER;PDAF ラインフィルタ +PARTIALPASTE_PREPROCWB;ホワイトバランスの前処理 PARTIALPASTE_PRSHARPENING;リサイズ後のシャープニング PARTIALPASTE_RAWCACORR_AUTO;自動色収差補正 PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT;CA 色ずれを回避 @@ -1049,7 +1537,7 @@ PARTIALPASTE_SHADOWSHIGHLIGHTS;シャドウ/ハイライト PARTIALPASTE_SHARPENEDGE;エッジ PARTIALPASTE_SHARPENING;シャープニング (USM/RL) PARTIALPASTE_SHARPENMICRO;マイクロコントラスト -PARTIALPASTE_SOFTLIGHT;ソフトな明るさ +PARTIALPASTE_SOFTLIGHT;ソフトライト PARTIALPASTE_TM_FATTAL;ダイナミックレンジ圧縮 PARTIALPASTE_VIBRANCE;自然な彩度 PARTIALPASTE_VIGNETTING;周辺光量補正 @@ -1090,6 +1578,9 @@ PREFERENCES_CLUTSCACHE;HaldCLUT cache PREFERENCES_CLUTSCACHE_LABEL;cacheに入れるHaldCLUTの最大数 PREFERENCES_CLUTSDIR;HaldCLUTのディレクトリー PREFERENCES_CMMBPC;ブラックポイントの補正 +PREFERENCES_COMPLEXITYLOC;ローカル調整のデフォルトの複雑度 +PREFERENCES_COMPLEXITY_EXP;エキスパート +PREFERENCES_COMPLEXITY_NORM;通常 PREFERENCES_CROP;切り抜き画像の編集 PREFERENCES_CROP_AUTO_FIT;切り抜き画像を自動的に拡大します PREFERENCES_CROP_GUIDES;切り抜き画像が編集されていない時はガイドを表示します @@ -1155,7 +1646,7 @@ PREFERENCES_MENUGROUPLABEL;"カラーラベル"のグループ PREFERENCES_MENUGROUPPROFILEOPERATIONS;"処理プロファイル操作"のグループ PREFERENCES_MENUGROUPRANK;"ランキング"のグループ PREFERENCES_MENUOPTIONS;メニューオプションの状況 -PREFERENCES_MONINTENT;デフォルトのモニターインテント +PREFERENCES_MONINTENT;デフォルトのレンダリングの目標 PREFERENCES_MONITOR;モニター PREFERENCES_MONPROFILE;デフォルトのモニタープロファイル PREFERENCES_MONPROFILE_WARNOSX;MacのOSの制約により、サポート出来るのはsRGBだけです @@ -1206,6 +1697,7 @@ PREFERENCES_SHOWBASICEXIF;基本Exif情報を表示 PREFERENCES_SHOWDATETIME;日付表示 PREFERENCES_SHOWEXPOSURECOMPENSATION;露光補正追加 PREFERENCES_SHOWFILMSTRIPTOOLBAR;画像スライドにツールバーを表示する +PREFERENCES_SHOWTOOLTIP;ローカル調整の機能のヒントを表示 PREFERENCES_SHTHRESHOLD;シャドウ・クリッピング領域のしきい値 PREFERENCES_SINGLETAB;シングルタブモードモード PREFERENCES_SINGLETABVERTAB;シングル編集タブモード, 垂直タブ @@ -1413,7 +1905,7 @@ TP_COLORAPP_CHROMA_M_TOOLTIP;CIECAM02の鮮やかさは L*a*b*やRGBの鮮やか TP_COLORAPP_CHROMA_S;彩度 (S) TP_COLORAPP_CHROMA_S_TOOLTIP;CIECAM02の彩度は L*a*b*やRGBの彩度とは異なります TP_COLORAPP_CHROMA_TOOLTIP;CIECAM02の色度は L*a*b*やRGBの色度とは異なります -TP_COLORAPP_CIECAT_DEGREE;CAT02に適応 +TP_COLORAPP_CIECAT_DEGREE;CAT02 TP_COLORAPP_CONTRAST;コントラスト (J) TP_COLORAPP_CONTRAST_Q;コントラスト (Q) TP_COLORAPP_CONTRAST_Q_TOOLTIP;CIECAM02のコントラスト(明るさQ)スライダーは L*a*b*やRGBとは異なります @@ -1424,17 +1916,27 @@ TP_COLORAPP_CURVEEDITOR2;トーンカーブ2 TP_COLORAPP_CURVEEDITOR2_TOOLTIP;2番目の露光トーンカーブも同じ使い方です TP_COLORAPP_CURVEEDITOR3;カラーカーブ TP_COLORAPP_CURVEEDITOR3_TOOLTIP;色度、彩度、鮮やかさのいずれかを調整します\n\nCIECAM02調整前の色度(L*a*b*)のヒストグラムを表示します\nチェックボックスの"カーブにCIECAM02出力のヒストグラムを表示" が有効の場合、CIECAM02調整後のC,sまたはMのヒストグラムを表示します\n\nC, sとMは、メインのヒストグラム・パネルには表示されません\n最終出力は、メインのヒストグラム・パネルを参照してください -TP_COLORAPP_DATACIE;カーブにCIECAM02出力のヒストグラムを表示 +TP_COLORAPP_DATACIE;カーブでCIECAM02出力のヒストグラムを表示 TP_COLORAPP_DATACIE_TOOLTIP;有効の場合、CIECAM02カーブのヒストグラムは、JかQ、CIECAM02調整後のCかs、またはMの値/範囲の近似値を表示します\nこの選択はメイン・ヒストグラムパネルには影響を与えません\n\n無効の場合、CIECAM02カーブのヒストグラムは、CIECAM調整前のL*a*b*値を表示します -TP_COLORAPP_FREE;任意の色温度+グリーン + CAT02 + [出力] +TP_COLORAPP_FREE;任意の色温度と色偏差 + CAT02 + [出力] TP_COLORAPP_GAMUT;色域制御 (L*a*b*) -TP_COLORAPP_GAMUT_TOOLTIP;L*a*b*モードの色域制御を許可 +TP_COLORAPP_GAMUT_TOOLTIP;L*a*b*モードの色域制御を可能にします TP_COLORAPP_HUE;色相 (h) TP_COLORAPP_HUE_TOOLTIP;色相 (h) - 0° から 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;白熱灯標準A 2856K +TP_COLORAPP_ILFREE;フリー +TP_COLORAPP_ILLUM;光源 +TP_COLORAPP_ILLUM_TOOLTIP;撮影条件に最も近い条件を選択します\n一般的にはD50 ですが、時間と緯度に応じて変えます TP_COLORAPP_LABEL;CIE色の見えモデル2002 TP_COLORAPP_LABEL_CAM02;画像の調整 -TP_COLORAPP_LABEL_SCENE;撮影環境条件 -TP_COLORAPP_LABEL_VIEWING;観視条件 +TP_COLORAPP_LABEL_SCENE;撮影環境 +TP_COLORAPP_LABEL_VIEWING;観視環境 TP_COLORAPP_LIGHT;明度 (J) TP_COLORAPP_LIGHT_TOOLTIP;CIECAM02の明度は L*a*b*やRGBの明度とは異なります TP_COLORAPP_MEANLUMINANCE;中間輝度 (Yb%) @@ -1442,6 +1944,8 @@ TP_COLORAPP_MODEL;ホワイトポイント・モデル TP_COLORAPP_MODEL_TOOLTIP;WB [RT] + [出力]:\nRTのホワイトバランスは、撮影環境に使用されます。CIECAM02はD50の設定, 出力デバイスのホワイトバランスは「環境設定」の「カラーマネジメント」の設定\n\nWB [RT+CAT02] + [出力]:\nRTのホワイトバランス設定は、CAT02で使用され、出力デバイスのホワイトバランスは環境設定の値を使用します TP_COLORAPP_NEUTRAL;リセット TP_COLORAPP_NEUTRAL_TIP;全てのスライダーチェックボックスとカーブをデフォルトにリセットします +TP_COLORAPP_PRESETCAT02;cat02の自動プリセット +TP_COLORAPP_PRESETCAT02_TIP;これを有効にすると、スライダー、色温度、色偏差がCAT02自動に合わせて設定されます\n撮影環境の輝度は変えることが出来ます\n必要であれば、CAT02の観視環境を変更します\n必要に応じて観視環境の色温度、色偏差、を変更します TP_COLORAPP_RSTPRO;レッドと肌色トーンを保護 TP_COLORAPP_RSTPRO_TOOLTIP;レッドと肌色トーンを保護はスライダーとカーブの両方に影響します TP_COLORAPP_SURROUND;周囲環境 @@ -1458,6 +1962,8 @@ TP_COLORAPP_TCMODE_LABEL2;カーブ・モード2 TP_COLORAPP_TCMODE_LABEL3;カーブ・色度モード TP_COLORAPP_TCMODE_LIGHTNESS;明度 TP_COLORAPP_TCMODE_SATUR;彩度 +TP_COLORAPP_TEMP2_TOOLTIP;シンメトリカルモードの場合は色温度 = White balance.\n色偏差は常に1.0\n\nA光源 色温度=2856\nD41 色温度=4100\nD50 色温度=5003\nD55 色温度=5503\nD60 色温度=6000\nD65 色温度=6504\nD75 色温度=7504 +TP_COLORAPP_TEMPOUT_TOOLTIP;色温度と色偏差を変えるために無効にします TP_COLORAPP_TEMP_TOOLTIP;選択した光源に関し色偏差は常に1が使われます\n\n色温度=2856\nD50 色温度=5003\nD55 色温度=5503\nD65 色温度=6504\nD75 色温度=7504 TP_COLORAPP_TONECIE;CIECAM02 明るさ(Q)を使用してトーンマッピング TP_COLORAPP_TONECIE_TOOLTIP;このオプションが無効になっている場合、トーンマッピングはL*a*b*空間を使用します\nこのオプションが有効になっている場合、トーンマッピングは、CIECAM02を使用します\nトーンマッピング(L*a*b*/CIECAM02)ツールを有効にするには、この設定を有効にする必要があります @@ -1538,8 +2044,8 @@ TP_CROP_PPI;PPI TP_CROP_RESETCROP;リセット TP_CROP_SELECTCROP;セレクト TP_CROP_W;W 幅 -TP_CROP_X;X -TP_CROP_Y;Y +TP_CROP_X;左 +TP_CROP_Y;上部 TP_DARKFRAME_AUTOSELECT;自動選択 TP_DARKFRAME_LABEL;ダークフレーム TP_DEFRINGE_LABEL;フリンジ低減 @@ -1552,7 +2058,7 @@ TP_DEHAZE_SHOW_DEPTH_MAP;深度マップの表示 TP_DEHAZE_STRENGTH;強さ TP_DIRPYRDENOISE_CHROMINANCE_AMZ;自動(多分割方式) TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL;自動(分割方式) -TP_DIRPYRDENOISE_CHROMINANCE_BLUEYELLOW;色差 ブルー/イエロー +TP_DIRPYRDENOISE_CHROMINANCE_BLUEYELLOW;ブルー/イエロー TP_DIRPYRDENOISE_CHROMINANCE_CURVE;色ノイズ低減のカーブ TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;クロミナンススライダー全ての値を増幅します\n色度をベースにこのカーブで色ノイズ低減の強さを加減します。例えば彩度の低い部分で作用を強める、或いは色度の高い部分で作用を弱めるように使います TP_DIRPYRDENOISE_CHROMINANCE_FRAME;色ノイズ @@ -1568,7 +2074,7 @@ TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_INFO;プレビュー画像のサイズ=%1, TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_NOISEINFO;プレビュー画像のノイズ: 平均値=%1 最大値=%2 TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_NOISEINFO_EMPTY;プレビュー画像のノイズ: 平均値= - 最大値= - TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_TILEINFO;タイルのサイズ=%1, 中心位置: X座標=%2 Y座標=%3 -TP_DIRPYRDENOISE_CHROMINANCE_REDGREEN;色差 レッド/グリーン +TP_DIRPYRDENOISE_CHROMINANCE_REDGREEN;レッド/グリーン TP_DIRPYRDENOISE_LABEL;ノイズ低減 TP_DIRPYRDENOISE_LUMINANCE_CONTROL;輝度ノイズの調整法 TP_DIRPYRDENOISE_LUMINANCE_CURVE;輝度カーブ @@ -1585,7 +2091,7 @@ TP_DIRPYRDENOISE_MAIN_MODE;モード TP_DIRPYRDENOISE_MAIN_MODE_AGGRESSIVE;積極的 TP_DIRPYRDENOISE_MAIN_MODE_CONSERVATIVE;控えめ TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;”控えめ”モードは低周波の色度パターンが維持されますが、”積極的”モードではそれらも取り除かれます -TP_DIRPYRDENOISE_MEDIAN_METHOD;方式 +TP_DIRPYRDENOISE_MEDIAN_METHOD;メディアンの方式 TP_DIRPYRDENOISE_MEDIAN_METHOD_CHROMINANCE;色ノイズだけ TP_DIRPYRDENOISE_MEDIAN_METHOD_LAB;L*a*b* TP_DIRPYRDENOISE_MEDIAN_METHOD_LABEL;メディアンフィルター @@ -1609,7 +2115,7 @@ TP_DIRPYREQUALIZER_ARTIF;アーティファクトを軽減 TP_DIRPYREQUALIZER_HUESKIN;肌色の色相 TP_DIRPYREQUALIZER_HUESKIN_TOOLTIP;このカーブは上部ほど、アルゴリズムが効率良く働くことを示しています。\n下部ほど、色相の遷移が見られる部分です。\nコントロールポイントを左右に大きく動かす必要が生じたり、アーティファクトが生じたりする場合は、ホワイトバランスが妥当ではない時です。\n他の色への影響を避けるには、調整範囲を少し減らします TP_DIRPYREQUALIZER_LABEL;詳細レベルによるコントラスト調整 -TP_DIRPYREQUALIZER_LUMACOARSEST;粗い +TP_DIRPYREQUALIZER_LUMACOARSEST;大まか TP_DIRPYREQUALIZER_LUMACONTRAST_MINUS;コントラスト- TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS;コントラスト+ TP_DIRPYREQUALIZER_LUMAFINEST;細かい @@ -1628,12 +2134,12 @@ TP_EPD_REWEIGHTINGITERATES;再加重反復 TP_EPD_SCALE;スケール TP_EPD_STRENGTH;強さ TP_EXPOSURE_AUTOLEVELS;自動露光補正 -TP_EXPOSURE_AUTOLEVELS_TIP;画像を解析し露光補正を自動で設定します +TP_EXPOSURE_AUTOLEVELS_TIP;画像を解析し、露光補正を自動で行います\n必要に応じてハイライト復元を有効にします TP_EXPOSURE_BLACKLEVEL;黒レベル -TP_EXPOSURE_BRIGHTNESS;明度 +TP_EXPOSURE_BRIGHTNESS;明るさ TP_EXPOSURE_CLAMPOOG;色域から外れた色を切り取る TP_EXPOSURE_CLIP;クリップ % -TP_EXPOSURE_CLIP_TIP;自動露光補正によるハイライトとシャドウ部分での飽和ピクセルの割合制限 +TP_EXPOSURE_CLIP_TIP;自動露光補正で使う飽和ピクセルの割合 TP_EXPOSURE_COMPRHIGHLIGHTS;ハイライト圧縮 TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD;ハイライト圧縮 しきい値 TP_EXPOSURE_COMPRSHADOWS;シャドウ圧縮 @@ -1657,6 +2163,9 @@ TP_EXPOSURE_TCMODE_WEIGHTEDSTD;加重平均 TP_EXPOS_BLACKPOINT_LABEL;raw ブラック・ポイント TP_EXPOS_WHITEPOINT_LABEL;raw ホワイト・ポイント TP_FILMNEGATIVE_BLUE;ブルーの比率 +TP_FILMNEGATIVE_FILMBASE_PICK;フィルのベースカラーをピック +TP_FILMNEGATIVE_FILMBASE_TOOLTIP;実際のフィルムのベースカラーを取得して、処理プロファイルに保存するために未露光のスポットをピック(例 フレームの境)\nこの方が、同じフィルムロールからの複数の画像をバッチ処理する際に、一貫性のあるカラーバランスを取り易いです\n変換する画像が極端に暗い、明るい、色のバランスが悪い場合に使えます。 +TP_FILMNEGATIVE_FILMBASE_VALUES;フィルムをベースにしたRGB: TP_FILMNEGATIVE_GREEN;参考指数(コントラスト) TP_FILMNEGATIVE_GUESS_TOOLTIP;原画像の中で色相がニュートラルな部分2か所をピックすることでレッドとブルーの比率を自動で設定します。明るさが異なる2か所をピックします。その後、ホワイトバランスを設定します。 TP_FILMNEGATIVE_LABEL;ネガフィルム @@ -1734,7 +2243,7 @@ TP_ICM_SAVEREFERENCE_TOOLTIP;入力プロファイルが適用される前のリ TP_ICM_TONECURVE;DCPトーンカーブ使用 TP_ICM_TONECURVE_TOOLTIP;DCPのプロファイルに含まれているトーンカーブを使用することができます TP_ICM_WORKINGPROFILE;作業プロファイル -TP_ICM_WORKING_TRC;トーン再現カーブ: +TP_ICM_WORKING_TRC;TRC: TP_ICM_WORKING_TRC_CUSTOM;カスタム TP_ICM_WORKING_TRC_GAMMA;ガンマ TP_ICM_WORKING_TRC_NONE;なし @@ -1782,6 +2291,8 @@ TP_LABCURVE_RSTPRO_TOOLTIP;色度スライダーとCCカーブを使用するこ TP_LENSGEOM_AUTOCROP;自動的に切り抜き選択 TP_LENSGEOM_FILL;オートフィル TP_LENSGEOM_LABEL;レンズ / ジオメトリ +TP_LENSGEOM_LIN;線形 +TP_LENSGEOM_LOG;対数 TP_LENSPROFILE_CORRECTION_AUTOMATCH;自動で選択 TP_LENSPROFILE_CORRECTION_LCPFILE;LCPファイル TP_LENSPROFILE_CORRECTION_MANUAL;手動で選択 @@ -1797,6 +2308,561 @@ TP_LOCALCONTRAST_DARKNESS;暗い部分のレベル TP_LOCALCONTRAST_LABEL;ローカルコントラスト TP_LOCALCONTRAST_LIGHTNESS;明るい部分のレベル TP_LOCALCONTRAST_RADIUS;半径 +TP_LOCALLAB_ACTIV;輝度だけ +TP_LOCALLAB_ADJ;イコライザ ブルー/イエロー レッド/グリーン +TP_LOCALLAB_ALL;全ての種類 +TP_LOCALLAB_AMOUNT;量 +TP_LOCALLAB_ARTIF;形状検出 +TP_LOCALLAB_ARTIF_TOOLTIP;色差の軽減を強めることで形状検出を向上させますが、形状の検出の範囲が狭まることがあります\n画像の形状のしきい値が画像のベタな部分のレベルを考慮します +TP_LOCALLAB_AUTOGRAY;自動 +TP_LOCALLAB_AVOID;色ずれの回避 +TP_LOCALLAB_BALAN;ΔEのバランス ab-L +TP_LOCALLAB_BALANEXP;ΔØ PDE バランス +TP_LOCALLAB_BALANH;ΔEのバランス C-H +TP_LOCALLAB_BALAN_TOOLTIP;色差のアルゴリズムのパラメータを変えます。\nab-L、C - Hを増減させます\nノイズ除去は変わりません +TP_LOCALLAB_BASELOG;対数の基数 +TP_LOCALLAB_BILATERAL;平滑化フィルタ +TP_LOCALLAB_BLACK_EV;ブラックEv +TP_LOCALLAB_BLCO;色度だけ +TP_LOCALLAB_BLENDMASKCOL;ブレンド +TP_LOCALLAB_BLENDMASK_TOOLTIP;ブレンド=0の場合は、形状検出だけが改善します\nブレンドが0より大きい場合は、画像にマスクが追加されます。 ブレンドが0より小さい場合は、画像からマスクが除かれます。 +TP_LOCALLAB_BLGUID;ガイド付きフィルタ +TP_LOCALLAB_BLINV;インバース +TP_LOCALLAB_BLLC;輝度と色度 +TP_LOCALLAB_BLLO;輝度だけ +TP_LOCALLAB_BLMED;メディアン +TP_LOCALLAB_BLMETHOD_TOOLTIP;通常-全ての設定に対し、直接的なぼかしとノイズ\n反対‐スコープと拡張アルゴリズムを除いた設定で、ぼかしとノイズの反対処理\nシンメトリック‐全ての設定でぼかしとノイズの反対処理(予期せぬ結果になることが有り) +TP_LOCALLAB_BLNOI_EXP;ぼかし & ノイズ +TP_LOCALLAB_BLNORM;通常 +TP_LOCALLAB_BLSYM;シンメトリック +TP_LOCALLAB_BLUFR;平滑化 - ぼかし - 質感 - ノイズ除去 +TP_LOCALLAB_BLUMETHOD_TOOLTIP;背景をぼかし、前景を分離するために:\n*RT-スポットが画像全体をカバーできるようにして(スコープと境界を高くする)背景をぼかします-通常或いはリバースモード\n*使用したい機能で一つ以上の除外RT-スポットを追加し(スコープを大きくします)、前景を分離します、マスクを使うことで効果を増幅出来ます +TP_LOCALLAB_BLUR;ガウスぼかし - ノイズ - ノイズ除去 +TP_LOCALLAB_BLURCBDL;ぼかしのレベル 0-1-2-3-4 +TP_LOCALLAB_BLURCOL;マスクぼかしの半径 +TP_LOCALLAB_BLURDE;形状検出のぼかし +TP_LOCALLAB_BLURLC;輝度だけ +TP_LOCALLAB_BLURLEVELFRA;レベルのぼかし +TP_LOCALLAB_BLURMASK_TOOLTIP;コントラストのしきい値と構造を考慮したマスクぼかしのスライダーでぼかしマスクを生成します。 +TP_LOCALLAB_BLURRESIDFRA;残差のぼかし +TP_LOCALLAB_BLUR_TOOLNAME;平滑化ぼかし 質感 & ノイズ除去 - 1 +TP_LOCALLAB_BLWH;全ての変更を強制的に白黒にする +TP_LOCALLAB_BLWH_TOOLTIP;色の構成要素、"a"と"b"の値を強制的にゼロにします +TP_LOCALLAB_BUTTON_ADD;追加 +TP_LOCALLAB_BUTTON_DEL;削除 +TP_LOCALLAB_BUTTON_DUPL;複製 +TP_LOCALLAB_BUTTON_REN;名前の変更 +TP_LOCALLAB_BUTTON_VIS;表示/非表示 +TP_LOCALLAB_CBDL;詳細レベルによるコントラスト調整 - 不良の補正 +TP_LOCALLAB_CBDLCLARI_TOOLTIP;中間トーンを強化します +TP_LOCALLAB_CBDL_ADJ_TOOLTIP;ウェーブレット機能のように作用します\n最初のレベル(0)は2x2ピクセルで解析します\n最後のレベル(5)は64x64ピクセルで解析します +TP_LOCALLAB_CBDL_THRES_TOOLTIP;ノイズが先鋭化するのを避けます +TP_LOCALLAB_CBDL_TOOLNAME;詳細レベルによるコントラスト調整 (不良部分の補正) - 2 +TP_LOCALLAB_CENTER_X;センターX +TP_LOCALLAB_CENTER_Y;センターY +TP_LOCALLAB_CH;カーブ CL - LC +TP_LOCALLAB_CHROMA;色度 +TP_LOCALLAB_CHROMABLU;色度のレベル +TP_LOCALLAB_CHROMABLU_TOOLTIP;輝度のスライダーと比べて増幅と減衰の作用の働きをします\n1以下で減衰、1以上で増幅の作用となります +TP_LOCALLAB_CHROMACBDL;色度 +TP_LOCALLAB_CHROMACB_TOOLTIP;輝度のスライダーと比べて増幅と減衰の作用の働きをします\n100以下で減衰、100以上で増幅の作用となります +TP_LOCALLAB_CHROMALEV;色度のレベル +TP_LOCALLAB_CHROMASKCOL;色度のマスク +TP_LOCALLAB_CHROMASK_TOOLTIP;このスライダーを使って背景の彩度を下げることが出来ます(インバースマスクで言う0に近いカーブ).\n色度に対するマスクの作用を強めることも出来ます。 +TP_LOCALLAB_CHRRT;色度 +TP_LOCALLAB_CIRCRADIUS;スポットサイズ +TP_LOCALLAB_CIRCRAD_TOOLTIP;RT-スポットの参考値を含んでいるので、形状検出(色相、輝度、色度、Sobel)に有利です\n小さい値は花びらの補正などに便利です\n大きな値は肌などの補正に便利です +TP_LOCALLAB_CLARICRES;色度を融合 +TP_LOCALLAB_CLARIFRA;明瞭とシャープマスク - ブレンド & ソフトイメージ +TP_LOCALLAB_CLARILRES;輝度の融合 +TP_LOCALLAB_CLARISOFT;ソフトな半径 +TP_LOCALLAB_CLARISOFT_TOOLTIP;輝度の融合が0以外の場合に明瞭とシャープマスクが有効となります。\n\nウェーブレットピラミッドモジュールの全てが有効となります\nソフトな半径が0の場合は無効となります +TP_LOCALLAB_CLARITYML;明瞭 +TP_LOCALLAB_CLARI_TOOLTIP;ウェーブレットのレベルが4以下の場合は、’シャープマスク’が有効となります。\n5以上のレベルでは’明瞭化’が有効となります。 +TP_LOCALLAB_CLIPTM;復元されたデータの切り取り(ゲイン) +TP_LOCALLAB_COFR;色と明るさ - 小さな不良 +TP_LOCALLAB_COLORDE;プレビューのカラー選択 ΔE - 強さ +TP_LOCALLAB_COLORDEPREV_TOOLTIP;有効になっている機能が1つだけの時は、設定のパネル(拡張する)のΔEのプレビューボタンを使います。\n複数の機能が有効になっている時は、各機能に備わっているマスクと調節の中のΔEのプレビューを使います。 +TP_LOCALLAB_COLORDE_TOOLTIP;設定値がマイナスの場合は色差(ΔE)のプレビューの色をブルーで表示、プラスの場合はグリーンで表示\n\nマスクと調節(マスクなしで調節を表示):プラスであれば、実際の変更を表示、マイナスであれば、強化した調節(輝度のみ)をブルーとイエローで表示 +TP_LOCALLAB_COLORSCOPE;カラー機能のスコープ +TP_LOCALLAB_COLORSCOPE_TOOLTIP;色と明るさ、露光補正(標準)、シャドウ/ハイライト、自然な彩度は共通したスコープを使います。\n他の機能に関しては、それぞれ特定のスコープを使います。 +TP_LOCALLAB_COLOR_TOOLNAME;色&&明るさ (不良部分の補正) - 11 +TP_LOCALLAB_COL_NAME;名前 +TP_LOCALLAB_COL_VIS;ステータス +TP_LOCALLAB_COMPFRA;詳細レベルの方向によるコントラスト +TP_LOCALLAB_COMPFRAME_TOOLTIP;特殊な効果を付けるために使います。アーティファクトを軽減するためには'明瞭 & シャープマスク、ブレンド & ソフトイメージ'を使います\n処理時間が大きく増えます +TP_LOCALLAB_COMPLEX_METHOD;ソフトウェアの複雑度 +TP_LOCALLAB_COMPLEX_TOOLTIP; ローカル調整の扱いの複雑度を選択出来ます +TP_LOCALLAB_COMPREFRA;ウェーブレットを使ったレベルのダイナミックレンジ(非)圧縮 +TP_LOCALLAB_COMPRESS_TOOLTIP;アーティファクトを軽減するため必要に応じて'明瞭 & シャープマスク、ブレンド & ソフトイメージ'の'ソフトな半径'使います +TP_LOCALLAB_CONTCOL;マスクぼかしのコントラストしきい値 +TP_LOCALLAB_CONTFRA;レベルによるコントラスト調整 +TP_LOCALLAB_CONTRAST;コントラスト +TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP;メインのマスクのコントラストをコントロール +TP_LOCALLAB_CONTRESID;コントラスト +TP_LOCALLAB_CONTTHR;コントラストのしきい値 +TP_LOCALLAB_CSTHRESHOLD;Ψ ウェーブレットのレベル +TP_LOCALLAB_CSTHRESHOLDBLUR;Ψ ウェーブレットレベルのマスク +TP_LOCALLAB_CURV;明るさ - コントラスト - 色度 "強力" +TP_LOCALLAB_CURVCURR;通常 +TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP;カーブが最上部に位置している時は、マスクが完全に黒く表示され、マスクの作用がない状態\nカーブを下に下げるにつれ、マスクの色が変わり、合わせて画像の状態も変わる +TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP;使うためには'カーブを有効にする'に✔を入れる +TP_LOCALLAB_CURVEEDITOR_TONES_LABEL;トーンカーブ +TP_LOCALLAB_CURVEEDITOR_TONES_TOOLTIP;L=f(L), 色と明るさでL(H)との併用可 +TP_LOCALLAB_CURVEMETHOD_TOOLTIP;'通常', L=f(L)カーブはスライダーと同じアルゴリズムを使っています\n'強力' L=f(L)カーブで作用を強めた新しいアルゴリズムを使っていますが、場合によってアーティファクトが出ることがあります +TP_LOCALLAB_CURVENCONTRAST;強力+コントラストのしきい値(試験的) +TP_LOCALLAB_CURVENH;強力 +TP_LOCALLAB_CURVENHSU;色相と色度の組み合わせ(試験的) +TP_LOCALLAB_CURVENSOB2;色相と色度の組み合わせ+コントラストのしきい値(試験的) +TP_LOCALLAB_CURVNONE;カーブを無効 +TP_LOCALLAB_DARKRETI;暗さ +TP_LOCALLAB_DEHAFRA;霞除去 +TP_LOCALLAB_DEHAZ;強さ +TP_LOCALLAB_DEHAZ_TOOLTIP;マイナス値にすると霞が増えます +TP_LOCALLAB_DELTAD;色差のバランス +TP_LOCALLAB_DELTAEC;ΔE画像のマスク +TP_LOCALLAB_DENOIS;Ψ ノイズ除去 +TP_LOCALLAB_DENOI_EXP;ノイズ除去 +TP_LOCALLAB_DENOI_TOOLTIP;このモジュール(処理工程の後の方に位置)だけで使うことも、メインのノイズ低減(処理工程の最初の方に位置)と併用することも出来ます\nスコープは色(ΔE)に応じてノイズ除去の作用に違いを持たせます。\n”メディアン”と”ガイド付きフィルタ”(平滑化ぼかし)も使えば、ノイズ除去のパフォーマンスが良くなります。\n”レベルのぼかし”や”ウェーブレットピラミッド”の併用で更にノイズ除去のパフォーマンスが上がります。 +TP_LOCALLAB_DEPTH;深度 +TP_LOCALLAB_DETAIL;ローカルコントラスト +TP_LOCALLAB_DETAILSH;ディテール +TP_LOCALLAB_DETAILTHR;細部の色の明るさのしきい値 (DCT) +TP_LOCALLAB_DUPLSPOTNAME;コピー +TP_LOCALLAB_EDGFRA;エッジシャープネス +TP_LOCALLAB_EDGSHOW;全ての機能を表示 +TP_LOCALLAB_ELI;楕円 +TP_LOCALLAB_ENABLE_AFTER_MASK;トーンマッピングを使う +TP_LOCALLAB_ENABLE_MASK;マスクを有効にする +TP_LOCALLAB_ENABLE_MASKAFT;露光補正の全てのアルゴリズムを使う +TP_LOCALLAB_ENARETIMASKTMAP_TOOLTIP;元のデータの代わりに透過マップを使った後は、有効にしたマスクは保持されているデータを使います。 +TP_LOCALLAB_ENH;強化 +TP_LOCALLAB_ENHDEN;強化 + 色ノイズの軽減 +TP_LOCALLAB_EPSBL;ディテール +TP_LOCALLAB_EQUIL;輝度の標準化 +TP_LOCALLAB_EQUILTM_TOOLTIP;出力画像の輝度の平均と分散が元画像のそれらと同じになるように輝度を回復するオプションです +TP_LOCALLAB_ESTOP;エッジ停止 +TP_LOCALLAB_EV_DUPL;のコピー +TP_LOCALLAB_EV_NVIS;非表示 +TP_LOCALLAB_EV_NVIS_ALL;全て非表示 +TP_LOCALLAB_EV_VIS;表示 +TP_LOCALLAB_EV_VIS_ALL;全て表示 +TP_LOCALLAB_EXCLUF;除外 +TP_LOCALLAB_EXCLUF_TOOLTIP;スコープを動かして色を拡張するような場合、データの一部を除外する場合に使います\nRT-スポットに対する全ての設定で適用できます。 +TP_LOCALLAB_EXCLUTYPE;スポットのタイプ +TP_LOCALLAB_EXCLUTYPE_TOOLTIP;通常方式は、スポットのデータを繰り返して使います\n例外方式は元のデータに戻して使う方式です +TP_LOCALLAB_EXECLU;除外スポット +TP_LOCALLAB_EXNORM;通常スポット +TP_LOCALLAB_EXPCBDL_TOOLTIP;センサーの汚れに起因する不良で、それらが画像の大切な部分にある、或いは複数個所にそれらある場合\n\na) RT-スポットをその部分に作成(必要であれば大きさを調節); b) または複数個所をカバーするスポットを作成; c) 比較的大きな境界の調整を設定; d) レベル3と4のスライダー、場合によっては2の値も100以下にします。必要に応じて色度のスライダーも使います。 +TP_LOCALLAB_EXPCHROMA;色度の補間 +TP_LOCALLAB_EXPCHROMA_TOOLTIP;この機能は露光量補正とPDE IPOLだけに関わります\n色が褪せるのを避けます +TP_LOCALLAB_EXPCOLOR_TOOLTIP;不良個所か小さい場合:\n\n赤目 : 中心円を赤い部分に合わせ、RT-スポットの範囲を眼の大きさ程度にします。スコープの値を小さくし、"明るさ" -100, "色" -100にします\n\n赤外線センサーのスポット:中心円を不良個所に合わせます、 RT-スポットの範囲はデフォルトに近い大きさで構いません - "色"を減らし、場合によっては"スコープ"を使って作用の及ぶ範囲を調節します\n\nセンサーの汚れ(小):中心円を不良部分に合わせます(スポットサイズも調整します)、RT-スポットの範囲が不良個所にあまり近づかないようにします(境界部分が目立たないようにする) a) "境界の調節"は小さくします; b) "輝度"、場合によっては"色" を使って不良個所のレンダリングを正常な部分のレンダリングに近づけます; c) "スコープ"を適度に使って作用の及ぶ範囲を調節します +TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;ウェーブレットのレベル或いはノイズ除去の説明を参照して下さい。\n但し、幾つか変更されている部分もあります:より多くの機能がノイズ除去に関する詳細が多くなっています。\nウェーブレットのレベルのトーンマッピング +TP_LOCALLAB_EXPCONTRAST_TOOLTIP;大きさが50x50ピクセルより小さいスポットを使うのは避けます\n代わりに、境界値を低く、境界の減衰値とスコープ値を高く設定して小さなRT-スポットを真似ます\nアーティストを軽減するために、必要であれば’ソフトな半径’を調整しながら’明瞭 & シャープマスクとイメージのブレンド’モジュールを使います +TP_LOCALLAB_EXPCURV;カーブ +TP_LOCALLAB_EXPGRAD;階調フィルタ +TP_LOCALLAB_EXPLAPBAL_TOOLTIP;元画像とラプラス変換の間のバランスをとります +TP_LOCALLAB_EXPLAPGAMM_TOOLTIP;ラプラス変換の適用前後でガンマを適用します +TP_LOCALLAB_EXPLAPLIN_TOOLTIP;ラプラス変換の適用前に、露光補正の線形要素を追加します +TP_LOCALLAB_EXPLAP_TOOLTIP;しきい値のスライダーを増やすほど、コントラストの減衰作用が強くなります +TP_LOCALLAB_EXPMERGEFILE_TOOLTIP;画像を融合するために複数の機能が使えます(Photoshopのレイヤーのように):差分、積算、ソフトライト、オーバーレイ+不透明度。。。\n元画像 : 現在のRT-スポットを元画像と融合.\n前のスポット : 現在のRT-スポットを前のRT-スポットと融合 – スポットが一つだけの場合は元画像との融合になります\n背景:現在のRT-スポットを背景の色と輝度と融合します +TP_LOCALLAB_EXPMETHOD_TOOLTIP;標準:メインの露光補正と類似したアルゴリズムを使いますが、 L*a*b*で作業するため色差を考慮します\n\nラプラスとポアソン方程式:色差を考慮する別なアルゴリズムですが、フーリエ空間でのラプラスの欠点を解決すためポアソン方程式(PDE)を使います\nPDEを使ったアルゴリズムは結果が大きく異なるため、標準とは異なる設定が必要でしょう\n露出不足の画像に有効かもしれません\nPDEはアーティファクトとノイズを軽減します +TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP;アーティファクト(ノイズ)の発生を避けるため、ラプラス変換の前にメディアンを適用します +TP_LOCALLAB_EXPOSE;露光補正-PDEアルゴリズム +TP_LOCALLAB_EXPOSURE_TOOLTIP;シャドウ部分が強いような場合は、”シャドウ/ハイライト”のモジュールが使えます +TP_LOCALLAB_EXPRETITOOLS;高度なレティネックス機能 +TP_LOCALLAB_EXPSHARP_TOOLTIP;RT-スポットの大きさが最低でも39x39ピクセル必要です\nスポットが小さい場合は、低い境界値、高い減衰値、高いスコープ値を設定します +TP_LOCALLAB_EXPTOOL;露光補正の機能 +TP_LOCALLAB_EXPTRC;トーンリプロダクションカーブ - TRC +TP_LOCALLAB_EXP_TOOLNAME;露光補正 - ダイナミックレンジ圧縮 - 10 +TP_LOCALLAB_FATAMOUNT;量 +TP_LOCALLAB_FATANCHOR;アンカー +TP_LOCALLAB_FATANCHORA;オフセット +TP_LOCALLAB_FATDETAIL;ディテール +TP_LOCALLAB_FATFRA;ダイナミックレンジ圧縮 f +TP_LOCALLAB_FATFRAME_TOOLTIP;ここではFattalトーンマッピングアルゴリズムを使います\nアンカーで画像の露出不足・過多に応じた選択が出来ます\n現在のスポットに近く、マスクを使用する2番目のスポットの輝度を増やすのに便利です +TP_LOCALLAB_FATLEVEL;シグマ +TP_LOCALLAB_FATRES;残差画像の量 +TP_LOCALLAB_FATSHFRA;マスクのダイナミックレンジ圧縮のマスク f +TP_LOCALLAB_FEATH_TOOLTIP;スポットの対角線に対する減光フィルタの幅の割合\n.. +TP_LOCALLAB_FEATVALUE;フェザー処理(階調フィルタ) +TP_LOCALLAB_FFTCOL_MASK;FFTW f +TP_LOCALLAB_FFTW;f 高速フーリエ変換を使う +TP_LOCALLAB_FFTW2;f 高速フーリエ変換を使う(TIF, JPG,..) +TP_LOCALLAB_FFTWBLUR;ƒ - 常に高速フーリエ変換を使う +TP_LOCALLAB_FULLIMAGE;画像全体のブラックEvとホワイトEvを計算 +TP_LOCALLAB_GAM;ガンマ +TP_LOCALLAB_GAMFRA;トーンリプロダクションカーブ(TRC) +TP_LOCALLAB_GAMM;ガンマ +TP_LOCALLAB_GAMMASKCOL;ガンマのマスク +TP_LOCALLAB_GAMSH;ガンマ +TP_LOCALLAB_GRADANG;階調フィルタの角度 +TP_LOCALLAB_GRADANG_TOOLTIP;-180度から+180度の間で角度を調整 +TP_LOCALLAB_GRADFRA;階調フィルタ +TP_LOCALLAB_GRADGEN_TOOLTIP;階調フィルタの機能は”色と明るさ”と、”露光”、”シャドウ/ハイライト”、”自然な彩度”に備わっています\n\n自然な彩度、色と明るさには輝度、色調、色相の階調フィルタが使えます\nフェザー処理は設定の中にあります +TP_LOCALLAB_GRADLOGFRA;階調フィルタ 輝度 +TP_LOCALLAB_GRADSTR;階調フィルタ 強さ +TP_LOCALLAB_GRADSTRAB_TOOLTIP;色度の階調の強さを調整します +TP_LOCALLAB_GRADSTRCHRO;色調の階調の強さ +TP_LOCALLAB_GRADSTRHUE;色相の階調の強さ(融合されたファイル) +TP_LOCALLAB_GRADSTRHUE2;色相の階調の強さ +TP_LOCALLAB_GRADSTRHUE_TOOLTIP;色相の階調の強さを調整します +TP_LOCALLAB_GRADSTRLUM;輝度の階調の強さ +TP_LOCALLAB_GRADSTR_TOOLTIP;露出度の階調の強さを調整します +TP_LOCALLAB_GRAINFRA;フィルムの質感 1:1 +TP_LOCALLAB_GRALWFRA;階調フィルタ ローカルコントラスト +TP_LOCALLAB_GRIDFRAME_TOOLTIP;スポットは均一な画像部分にある方が望ましいです\n\n通常モードの場合だけに使えます。融合された背景による色相、彩度、色、輝度が関係します。 +TP_LOCALLAB_GRIDONE;カラートーン調整 +TP_LOCALLAB_GRIDTWO;直接 +TP_LOCALLAB_GUIDBL;ソフトな半径 +TP_LOCALLAB_GUIDFILTER;ガイド付きフィルタの半径 +TP_LOCALLAB_GUIDFILTER_TOOLTIP;画像に応じて値を決めます - 画像が霞んでいなければ値を低く取ります +TP_LOCALLAB_HHMASK_TOOLTIP;例えば肌の微妙な色相調整に使います +TP_LOCALLAB_HIGHMASKCOL;ハイライトマスク +TP_LOCALLAB_HLH;カーブ H +TP_LOCALLAB_IND;独立 (マウス) +TP_LOCALLAB_INDSL;独立 (マウス + スライダー) +TP_LOCALLAB_INVERS;反対 +TP_LOCALLAB_INVERS_TOOLTIP;反対を選択すると調整の多様性が失われます\n\n代わりの方法\n初めのスポット:\n画像全体 –境界線をプレビュー画像の外側にセットします\n スポットの形状は矩形、境界値は100\n\n2番目のスポットを作成し除外スポットにします +TP_LOCALLAB_ISOGR;粗さ (ISO) +TP_LOCALLAB_LABBLURM;マスクぼかし +TP_LOCALLAB_LABEL;ローカル調整 +TP_LOCALLAB_LABGRID;カラー補正グリッド +TP_LOCALLAB_LABGRIDMERG;背景 +TP_LOCALLAB_LABGRID_VALUES;高(a)=%1 高(b)=%2\n低(a)=%3 低(b)=%4 +TP_LOCALLAB_LABSTRUM;マスクの構造 +TP_LOCALLAB_LAPLACC;ΔØ ラプラシアンマスク PDEの境界条件あり +TP_LOCALLAB_LAPLACE;Δ ラプラシアンのしきい値 ΔE +TP_LOCALLAB_LAPLACEXP;Δ ラプラシアンのしきい値 +TP_LOCALLAB_LAPMASKCOL;Δ ラプラシアンのしきい値マスク +TP_LOCALLAB_LAPRAD_TOOLTIP;半径とラプラス変換のしきい値を同時に使うことを避けます。 +TP_LOCALLAB_LAP_MASK_TOOLTIP;全てのラプラシアンマスクのポアソン方程式の解を求めます\nラプラシアンのしきい値マスクを有効にするとアーティファクトが軽減され、スムーズな効果が得られます\n無効の場合は線形的な応答となります +TP_LOCALLAB_LC_FFTW_TOOLTIP;高速フーリエ変換は画像の質を改善し、大きな半径を使えるようにします\n処理する領域の大きさに応じて処理時間が増えます\n大きな半径で使うことを奨めます\n\nFFTWの最適化を図るために領域を数ピクセル削ります +TP_LOCALLAB_LC_TOOLNAME;ローカルコントラスト & ウェーブレット (不良部分の補正) - 7 +TP_LOCALLAB_LEVELBLUR;ぼかしを施すレベルの最大値 +TP_LOCALLAB_LEVELLOCCONTRAST_TOOLTIP;横軸はローカルコントラスト(輝度に近い)を表し、縦軸はローカルコントラストの増減を表します +TP_LOCALLAB_LEVELWAV;Ψ ウェーブレットのレベル +TP_LOCALLAB_LEVELWAV_TOOLTIP;詳細レベルの数はスポットとプレビューのサイズに応じて自動で決まります\n最大512ピクセルで解析するレベル8から最大4ピクセルで解析するレベル1まで +TP_LOCALLAB_LIGHTNESS;明るさ +TP_LOCALLAB_LIGHTN_TOOLTIP;反対モードで明るさを-100にすると輝度が0になります +TP_LOCALLAB_LIGHTRETI;明るさ +TP_LOCALLAB_LINEAR;線形性 +TP_LOCALLAB_LIST_NAME;現在のスポットに機能を追加 +TP_LOCALLAB_LIST_TOOLTIP;機能を選んだ後、その複雑度、”通常”或いは”エキスパート”を選択します\n付随する番号は各RT-スポットの処理の中の機能がある場所をしましています +TP_LOCALLAB_LMASK_LEVEL_TOOLTIP;選択したウェーブレットのレベルによって、中間トーンとハイライトへの作用を優先します +TP_LOCALLAB_LMASK_LL_TOOLTIP;中間トーンとハイライトへの作用を優先します +TP_LOCALLAB_LOCCONT;アンシャープマスク +TP_LOCALLAB_LOC_CONTRAST;ローカルコントラスト-ウェーブレット-欠損/汚れの補正 +TP_LOCALLAB_LOC_CONTRASTPYR;Ψ ピラミッド1: +TP_LOCALLAB_LOC_CONTRASTPYR2;Ψ ピラミッド2: +TP_LOCALLAB_LOC_CONTRASTPYR2LAB;レベルによるコントラスト調整- トーンマッピング(s) +TP_LOCALLAB_LOC_CONTRASTPYRLAB;階調フィルタ - エッジシャープネス - ぼかし +TP_LOCALLAB_LOC_RESIDPYR;残差画像 メイン +TP_LOCALLAB_LOG;対数符号化 +TP_LOCALLAB_LOGAUTO;自動 +TP_LOCALLAB_LOGAUTO_TOOLTIP;このボタンを押すことで、ダイナミックレンジとグレーポイントの源泉の推定値が得られます(グレーポイントの源泉で"自動"が有効になっている場合)\n自動計算による値を仕上げるためには、もう一度ボタンを押します +TP_LOCALLAB_LOGBASE_TOOLTIP;デフォルト値は2です\n2以下にするとアルゴリズムの作用が減少します。シャドウ部分がより暗く、ハイライト部分がより明るくなります\n2以上にするとアルゴリズムの作用が変わります。シャドウ部分は灰色がかり、ハイライト部分の色がさめた印象になります +TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP;ダイナミックレンジの推定値 - ブラックEvとホワイトEv +TP_LOCALLAB_LOGENCOD_TOOLTIP;対数符号化(ACES)を使ってトーンマッピングを行います\n露出不足やハイダイナミックレンジの画像の補正に便利です\n\n処理は : 1) ダイナミックレンジを計算、2) 好みに応じて調節 +TP_LOCALLAB_LOGFRA;グレーポイントの源泉 +TP_LOCALLAB_LOGFRAME_TOOLTIP;処理の初期段階で画像の露光レベルを計算する、或いはそのまま使用します:\n前者はブラックEv, ホワイトEv、グレーポイントの源泉から計算\n後者はメインの露光量補正の値を使います +TP_LOCALLAB_LOGLIN;対数モード +TP_LOCALLAB_LOGPFRA;相対的な露光レベル +TP_LOCALLAB_LOGSRCGREY_TOOLTIP;画像のグレーポイントの推定値、処理行程の前の方 +TP_LOCALLAB_LOGTARGGREY_TOOLTIP;好みに合わせて適用する値を変えられます +TP_LOCALLAB_LOG_TOOLNAME;対数符号化 - 0 +TP_LOCALLAB_LUM;カーブ LL - CC +TP_LOCALLAB_LUMADARKEST;最も暗い部分 +TP_LOCALLAB_LUMASK;マスクの背景輝度 +TP_LOCALLAB_LUMASK_TOOLTIP;マスクの表示(マスクと調節)で、背景のグレーを調節します +TP_LOCALLAB_LUMAWHITESEST;最も明るい部分 +TP_LOCALLAB_LUMONLY;輝度だけ +TP_LOCALLAB_MASFRAME;マスクと融合 +TP_LOCALLAB_MASFRAME_TOOLTIP;全てのマスクに共通する\nガンマ、スロープ、色度、コントラストカーブ、詳細レベルのコントラストカーブのマスクが使われる時は、選択領域のレタッチを避けるために色差イメージを考慮する。 +TP_LOCALLAB_MASK;マスク +TP_LOCALLAB_MASK2;コントラストカーブのマスク +TP_LOCALLAB_MASKCOL;カーブマスク +TP_LOCALLAB_MASKH;色相のカーブマスク +TP_LOCALLAB_MASK_TOOLTIP;使いたい一つの機能で複数のマスクを有効に出来ますが、そのためには別の機能を有効にする必要があります(但し、その機能自体を使う必要はありません、例えば、スライダーが0でも構いません)\nこの特性を有するマスクには’+’のマークがあります\n追加的な機能を持つマスクには’*’のマークが付いています\n数字が示すのはマスクの使用の順番です\n\nインバースマスクがある機能に関するマスクは組み合わせることが可能です\nこの場合、マスクに関連する新しい機能はインバースの中で選択します;その機能を使う際は値を非常に小さくしなければなりません(例えば、露光0.01) +TP_LOCALLAB_MED;中間 +TP_LOCALLAB_MEDIAN;メディアン 低 +TP_LOCALLAB_MEDNONE;なし +TP_LOCALLAB_MERCOL;色 +TP_LOCALLAB_MERDCOL;背景の融合(ΔE) +TP_LOCALLAB_MERELE;明るくするだけ +TP_LOCALLAB_MERFIV;追加 +TP_LOCALLAB_MERFOR;色の覆い焼き +TP_LOCALLAB_MERFOU;乗算 +TP_LOCALLAB_MERGE1COLFRA;オリジナル或いは前のイメージと融合 +TP_LOCALLAB_MERGECOLFRA;マスク: LCHと構造 +TP_LOCALLAB_MERGEFIV;前のスポット(マスク7) + LCHマスク +TP_LOCALLAB_MERGEFOU;前のスポット(マスク7) +TP_LOCALLAB_MERGEMER_TOOLTIP;融合画像に対しΔEを計算に入れます(この方法はスコープの作用と同等です) +TP_LOCALLAB_MERGENONE;なし +TP_LOCALLAB_MERGEONE;ショートカーブ'L'のマスク +TP_LOCALLAB_MERGEOPA_TOOLTIP;オリジナル或いは前のスポットと現在のスポットとの融合する際の不透明度の % \nコントラストのしきい値:オリジナルコントラストの機能の結果を調整 +TP_LOCALLAB_MERGETHR;オリジナル(マスク7) + LCHマスク +TP_LOCALLAB_MERGETWO;オリジナル(マスク7) +TP_LOCALLAB_MERGETYPE;イメージとマスクの融合 +TP_LOCALLAB_MERGETYPE_TOOLTIP;なしの場合、LCHモードの全てのマスクを使います\nショートカーブ 'L'マスクの場合、マスク2、3、4、6、7はスキップします\nオリジナルマスク7の場合、現在のイメージと元のイメージを融合します +TP_LOCALLAB_MERHEI;重ね合わせ +TP_LOCALLAB_MERHUE;色相 +TP_LOCALLAB_MERLUCOL;輝度 +TP_LOCALLAB_MERLUM;光度 +TP_LOCALLAB_MERNIN;スクリーン +TP_LOCALLAB_MERONE;標準 +TP_LOCALLAB_MERSAT;彩度 +TP_LOCALLAB_MERSEV;ソフトライト Photoshop +TP_LOCALLAB_MERSEV0;ソフトライト イリュージョン +TP_LOCALLAB_MERSEV1;ソフトライト W3C +TP_LOCALLAB_MERSEV2;ハードライト +TP_LOCALLAB_MERSIX;分割 +TP_LOCALLAB_MERTEN;暗くするだけ +TP_LOCALLAB_MERTHI;色の焼き込み +TP_LOCALLAB_MERTHR;差異 +TP_LOCALLAB_MERTWE;除外 +TP_LOCALLAB_MERTWO;減算 +TP_LOCALLAB_METHOD_TOOLTIP;'強化 + 色ノイズ低減'を選ぶと処理時間が著しく増加します\nしかし、アーティファクトは軽減されます +TP_LOCALLAB_MLABEL;復元されたデータ 最小値=%1 最大値=%2 (クリップ - オフセット) +TP_LOCALLAB_MLABEL_TOOLTIP;最低値=0、最大値=32768の近くになるよう調整します\n標準化を行うため‘保持されたデータを切り取る’と‘オフセット’を使えます\n\n混成のない画像に戻します +TP_LOCALLAB_MODE_EXPERT;エキスパート +TP_LOCALLAB_MODE_NORMAL;通常 +TP_LOCALLAB_MRFIV;背景 +TP_LOCALLAB_MRFOU;前のスポット +TP_LOCALLAB_MRONE;なし +TP_LOCALLAB_MRTHR;元のイメージ +TP_LOCALLAB_MRTWO;ショートカーブ 'L'マスク +TP_LOCALLAB_MULTIPL_TOOLTIP;非常に広範囲(-18EV~+4EV)でトーンのレタッチが出来ます。初めのスライダーは-18EV~-6EVの非常に暗い部分に作用します。最後のスライダーは4EVまでの明るい部分に作用します +TP_LOCALLAB_NEIGH;半径 +TP_LOCALLAB_NOISECHROCOARSE;色度 粗い (ウェーブレット) +TP_LOCALLAB_NOISECHROC_TOOLTIP;0より大きい値で効果の高いアルゴリズムが働き始めます\n大まかなスライダーの場合は2以上からです +TP_LOCALLAB_NOISECHRODETAIL;色度 細部の回復 (DCT) +TP_LOCALLAB_NOISECHROFINE;色度 細かい (ウェーブレット) +TP_LOCALLAB_NOISEDETAIL_TOOLTIP;スライダー値が100になると無効 +TP_LOCALLAB_NOISELEQUAL;イコライザ 白黒 +TP_LOCALLAB_NOISELUMCOARSE;輝度 大まか(ウェーブレット) +TP_LOCALLAB_NOISELUMDETAIL;輝度 細部の回復 (DCT) +TP_LOCALLAB_NOISELUMFINE;輝度 詳細レベル2(ウェーブレット) +TP_LOCALLAB_NOISELUMFINETWO;輝度 詳細レベル3(ウェーブレット) +TP_LOCALLAB_NOISELUMFINEZERO;輝度 詳細レベル1(ウェーブレット) +TP_LOCALLAB_NOISEMETH;ノイズ低減 +TP_LOCALLAB_NONENOISE;なし +TP_LOCALLAB_OFFS;オフセット +TP_LOCALLAB_OFFSETWAV;オフセット +TP_LOCALLAB_OPACOL;不透明度 +TP_LOCALLAB_ORIGLC;元画像だけと融合 +TP_LOCALLAB_ORRETILAP_TOOLTIP;2次ラプラシアンのしきい値に作用します。作用に差をつけるため、特に背景に対する作用、ΔEを計算に入れます(スコープの作用と異なります) +TP_LOCALLAB_ORRETISTREN_TOOLTIP;1次ラプラシアンのしきい値に作用します。設定値を高くするほど、コントラストの違いが減少します +TP_LOCALLAB_PASTELS2;自然な彩度 +TP_LOCALLAB_PDE;ΔØ ラプラシアン PDE - ダイナミックレンジ圧縮 + 標準 +TP_LOCALLAB_PDEFRA;PDE IPOL - コントラスト減衰 +TP_LOCALLAB_PDEFRAME_TOOLTIP;PDE IPOL - IPOLから取り入れ、独自にRawtherapee用にアレンジしたアルゴリズム:非常に異なる効果が出るので設定を変える必要があります。標準的にはブラックをマイナス値、ガンマを1以下にするなど\n露出の低い画像に便利だと思われます\n +TP_LOCALLAB_PREVIEW;ΔEのプレビュー +TP_LOCALLAB_PROXI;ΔEの減衰 +TP_LOCALLAB_QUALCURV_METHOD;カーブのタイプ +TP_LOCALLAB_QUAL_METHOD;全体の質 +TP_LOCALLAB_RADIUS;半径 +TP_LOCALLAB_RADIUS_TOOLTIP;半径の値が30より大きい場合は、高速フーリエ変換を使います +TP_LOCALLAB_RADMASKCOL;半径のマスクを滑らかにする +TP_LOCALLAB_RECT;長方形 +TP_LOCALLAB_RECURS;参考値の繰り返し +TP_LOCALLAB_RECURS_TOOLTIP;新しいモジュール使用とRT-スポットが作成される度に、色相、輝度、色度の参考値が再計算されます。\nマスクを使った作業に便利です。 +TP_LOCALLAB_REFLABEL;参照 (0..1) 色度=%1 輝度=%2 色相=%3 +TP_LOCALLAB_REN_DIALOG_LAB;新しいコントロールスポットの名前を入力 +TP_LOCALLAB_REN_DIALOG_NAME;コントロールスポットの名前変更 +TP_LOCALLAB_RESETSHOW;全ての表示変更をリセット +TP_LOCALLAB_RESID;残差画像 +TP_LOCALLAB_RESIDBLUR;残差画像をぼかす +TP_LOCALLAB_RESIDCHRO;残差画像の色度 +TP_LOCALLAB_RESIDCOMP;残差画像の圧縮 +TP_LOCALLAB_RESIDCONT;残差画像のコントラスト +TP_LOCALLAB_RESIDHI;ハイライト +TP_LOCALLAB_RESIDHITHR;ハイライトのしきい値 +TP_LOCALLAB_RESIDSHA;シャドウ +TP_LOCALLAB_RESIDSHATHR;シャドウのしきい値 +TP_LOCALLAB_RETI;霞除去 - レティネックス 強いコントラスト +TP_LOCALLAB_RETIFRA;レティネックス +TP_LOCALLAB_RETIM;独自のレティネックス +TP_LOCALLAB_RETITOOLFRA;レティネックスの機能 +TP_LOCALLAB_RETI_FFTW_TOOLTIP;高速フーリエ変換は質を向上させ大きな半径の使用が可能になります\n処理時間は編集する領域の大きさに応じて変わります \n大きな半径を扱う場合に適用するのがいいでしょう\n\n処理領域を数ピクセル減らすことでFFTWの最適化を図ることが出来ます \n但し、RT-スポットの境界線(縦或いは横)が画像からはみ出している場合は最適化を図れません +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_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_LOGLIN_TOOLTIP;Logarithm allows differenciation for haze or normal.\nLogarithm brings more contrast but will generate more halo. +TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP;画像に応じてこれらの値を適用します - 霧のかかった画像の場合で、調整したいのが前景或いは背景なのかに応じて。 +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_RET_TOOLNAME;霞除去 & レティネックス - 9 +TP_LOCALLAB_REWEI;再加重平均の繰り返し +TP_LOCALLAB_RGB;RGB トーンカーブ +TP_LOCALLAB_ROW_NVIS;非表示 +TP_LOCALLAB_ROW_VIS;表示 +TP_LOCALLAB_SATUR;彩度 +TP_LOCALLAB_SAVREST;保存 - 元に戻した現在のイメージ +TP_LOCALLAB_SCALEGR;スケール +TP_LOCALLAB_SCALERETI;スケール +TP_LOCALLAB_SCALTM;スケール +TP_LOCALLAB_SCOPEMASK;ΔE画像のスコープマスク +TP_LOCALLAB_SCOPEMASK_TOOLTIP;色差画像のマスクを有効にすると使えます\n低い値にすると選択した領域の調整が行われません +TP_LOCALLAB_SENSI;スコープ +TP_LOCALLAB_SENSIBN;スコープ +TP_LOCALLAB_SENSICB;スコープ +TP_LOCALLAB_SENSIDEN;スコープ +TP_LOCALLAB_SENSIEXCLU;スコープ +TP_LOCALLAB_SENSIEXCLU_TOOLTIP;除外モードに含まれている色も調整 +TP_LOCALLAB_SENSIH;スコープ +TP_LOCALLAB_SENSIH_TOOLTIP;スコープの作用を調整します:\n小さい値を設定すると調整領域の色の変化は中心円に近いものに制限されます\n高い値を設定すると色の変化の範囲が広がります。\n20以下の設定がアルゴリズムの働きにとっていいでしょう +TP_LOCALLAB_SENSILOG;スコープ +TP_LOCALLAB_SENSIS;スコープ +TP_LOCALLAB_SENSIS_TOOLTIP;スコープの作用を調整します:\n小さい値を設定すると調整領域の色の変化は中心円に近いものに制限されます\n高い値を設定すると色の変化の範囲が広がります。\n20以下の設定がアルゴリズムの働きにとっていいでしょう +TP_LOCALLAB_SENSI_TOOLTIP;スコープの作用を調整します:\n小さい値を設定すると調整領域の色の変化は中心円に近いものに制限されます\n高い値を設定すると色の変化の範囲が広がります。\n20以下の設定がアルゴリズムの働きにとっていいでしょう +TP_LOCALLAB_SETTINGS;設定 +TP_LOCALLAB_SH1;シャドウ/ハイライト +TP_LOCALLAB_SH2;イコライザ +TP_LOCALLAB_SHADEX;シャドウ +TP_LOCALLAB_SHADEXCOMP;シャドウの圧縮とトーンの幅 +TP_LOCALLAB_SHADHIGH;シャドウ/ハイライト-階調-トーンイコライザ-TRC +TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP;露光モジュールだけでは処理が困難な場合に、代わりに使う、或いは補間に使います。\nノイズ低減の使用が必要かもしれません:シャドウを明るく +TP_LOCALLAB_SHAMASKCOL;シャドウのマスク +TP_LOCALLAB_SHAPETYPE;RT-スポット領域の形状 +TP_LOCALLAB_SHAPE_TOOLTIP;長方形は通常モードのみ +TP_LOCALLAB_SHARAMOUNT;量 +TP_LOCALLAB_SHARBLUR;半径のぼかし +TP_LOCALLAB_SHARDAMPING;減衰 +TP_LOCALLAB_SHARFRAME;変更 +TP_LOCALLAB_SHARITER;繰り返し +TP_LOCALLAB_SHARP;シャープニング +TP_LOCALLAB_SHARP_TOOLNAME;シャープニング - 8 +TP_LOCALLAB_SHARRADIUS;半径 +TP_LOCALLAB_SHORTC;ショートカーブ'L'マスク +TP_LOCALLAB_SHORTCMASK_TOOLTIP;L(L)とL(H)2つのカーブをつスキップします。\nマスクの作用によって調整された現在のイメージと元イメージを融合します\n但し、これが使えるのは2, 3, 4, 6, 7のマスクです +TP_LOCALLAB_SHOWC;マスクと調節 +TP_LOCALLAB_SHOWC1;ファイルの融合 +TP_LOCALLAB_SHOWCB;マスクと調節 +TP_LOCALLAB_SHOWDCT;フーリエの処理を表示 +TP_LOCALLAB_SHOWE;マスクと調節 +TP_LOCALLAB_SHOWFOURIER;フーリエ (DCT) +TP_LOCALLAB_SHOWLAPLACE;Δ ラプラシアン (最初) +TP_LOCALLAB_SHOWLC;マスクと調節 +TP_LOCALLAB_SHOWMASK;マスクの表示 +TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;調整具合を表示させます\n但し、見られる表示は1度に1種類(色と明るさ、或いは露光のセクション)だけです\n'マスクと調整'のドロップダウンボックスで、'なし' 或いは マスクを表示できるものを選択します\n\nマスクの処理はは形状検出の前に行われます +TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;フーリエによる処理を表示します:\n処理の異なる段階を表示\nラプラス - しきい値に応じた2次微分を行う(最初のステップ)\nフーリエ -変換したラプラスをDCTで表示\nポアソン - ポアソンDCEの解を表示\n標準化 - 輝度の標準化なしに結果を表示 +TP_LOCALLAB_SHOWMASKTYP1;ぼかしとノイズ +TP_LOCALLAB_SHOWMASKTYP2;ノイズ除去 +TP_LOCALLAB_SHOWMASKTYP3;ぼかしとノイズ + ノイズ除去 +TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;マスクと調節を選択出来ます\nぼかしとノイズ:この場合は、'ノイズ除去'は使えません\nノイズ除去:この場合は、'ぼかしとノイズ'は使えません\n\nぼかしとノイズ+ノイズ除去:マスクを共用しますが、'調節を表示'と'スコープ'の扱いには注意が必要です +TP_LOCALLAB_SHOWMNONE;なし +TP_LOCALLAB_SHOWMODIF;マスクなしで変更を表示 +TP_LOCALLAB_SHOWMODIFMASK;マスクと共に変更を表示 +TP_LOCALLAB_SHOWNORMAL;輝度の標準化(なし) +TP_LOCALLAB_SHOWPLUS;マスクと調節- 平滑化によるぼかしとノイズ低減 +TP_LOCALLAB_SHOWPOISSON;ポアソン (pde f) +TP_LOCALLAB_SHOWR;マスクと調節 +TP_LOCALLAB_SHOWREF;ΔEのプレビュー +TP_LOCALLAB_SHOWS;マスクと調節 +TP_LOCALLAB_SHOWSTRUC;構造スポットを表示 +TP_LOCALLAB_SHOWSTRUCEX;構造スポットを表示 - "通常"では不可 +TP_LOCALLAB_SHOWT;マスクと調節 +TP_LOCALLAB_SHOWVI;マスクと調節 +TP_LOCALLAB_SHRESFRA;シャドウ/ハイライト +TP_LOCALLAB_SHTRC_TOOLTIP;TRC(諧調再現カーブ)を使って画像のトーンを調節します。\nガンマは主に明るいトーンに作用します\n勾配は主に暗いトーンに作用します +TP_LOCALLAB_SH_TOOLNAME;シャドウ/ハイライト & トーンイコライザ - 5 +TP_LOCALLAB_SIGMAWAV;減衰応答 +TP_LOCALLAB_SIM;シンプル +TP_LOCALLAB_SLOMASKCOL;スロープのマスク +TP_LOCALLAB_SLOSH;スロープ +TP_LOCALLAB_SOFT;ソフトライトと独自のレティネックス +TP_LOCALLAB_SOFTM;ソフトライト +TP_LOCALLAB_SOFTMETHOD_TOOLTIP;独自のレティネックスは他のレティネックス方式とは大きく異なります\nグレーと輝度のバランスに作用します +TP_LOCALLAB_SOFTRADIUSCOL;ソフトな半径 +TP_LOCALLAB_SOFTRETI;アーティファクトの軽減 ΔE +TP_LOCALLAB_SOFTRETI_TOOLTIP;透過マップを向上させるため色差を考慮します。 +TP_LOCALLAB_SOFT_TOOLNAME;ソフトライト & 独自のレティネックス - 6 +TP_LOCALLAB_SOURCE_GRAY;値 +TP_LOCALLAB_SPECCASE;特定のケース +TP_LOCALLAB_SPECIAL;RGBカーブの特殊な利用 +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_SPOTNAME;新しいスポット +TP_LOCALLAB_STD;標準 +TP_LOCALLAB_STR;強さ +TP_LOCALLAB_STRBL;強さ +TP_LOCALLAB_STREN;圧縮の強さ +TP_LOCALLAB_STRENG;強さ +TP_LOCALLAB_STRENGR;強さ +TP_LOCALLAB_STRENGTH;ノイズ +TP_LOCALLAB_STRGRID;強さ +TP_LOCALLAB_STRRETI_TOOLTIP;レティネックスの強さが0.2より小さい場合は霞除去だけが有効となります。\nレティネックスの強さが0.1以上の場合、霞除去の作用は輝度だけです。 +TP_LOCALLAB_STRUC;構造 +TP_LOCALLAB_STRUCCOL;構造 +TP_LOCALLAB_STRUCCOL1;構造のスポット +TP_LOCALLAB_STRUCT_TOOLTIP;形状検出で構造を計算に入れるため、Sobelアルゴリズムを使います。\n“マスクと調節の構造スポットを表示”を有効にすればプレビューを見ることが出来ます。 +TP_LOCALLAB_STRUMASKCOL;構造マスクの強さ +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;形状の方式 +TP_LOCALLAB_STYPE_TOOLTIP;2つのタイプから選びます:\nシンメトリックは左と右の境界線、上部と底部の境界線がリンクしています\n独立は全ての境界線を独立で動かすことが出来ます +TP_LOCALLAB_SYM;シンメトリック(マウス) +TP_LOCALLAB_SYMSL;シンメトリック(マウス + スライダー) +TP_LOCALLAB_TARGET_GRAY;グレーポイントの目標 +TP_LOCALLAB_THRES;構造のしきい値 +TP_LOCALLAB_THRESDELTAE;ΔE-スコープのしきい値 +TP_LOCALLAB_THRESRETI;しきい値 +TP_LOCALLAB_THRESWAV;バランスのしきい値 +TP_LOCALLAB_TLABEL;TM データ 最小値=%1 最大値=%2 平均値=%3 標準偏差=%4 (しきい値) +TP_LOCALLAB_TLABEL2;TM 効果 Tm=%1 TM=%2 +TP_LOCALLAB_TLABEL_TOOLTIP;これは透過マップの結果を示しています。\n最小値と最大値は分散に使われます。\nTm、TMはそれぞれ透過マップの最小値と最大値です。\nしきい値を調整して標準化できます。 +TP_LOCALLAB_TM;トーンマッピング - 質感 +TP_LOCALLAB_TM_MASK;透過マップを使う +TP_LOCALLAB_TONEMAPESTOP_TOOLTIP;エッジ停止を増やす - 或いは再加重平均の繰り返しを増やすと処理時間も増えます - 但し、その分効果が増します +TP_LOCALLAB_TONEMAPGAM_TOOLTIP;Gamma moves the action of tone-mapping to shadows or highlights. +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_TONEMAP_TOOLTIP;トーンマッピング - メインメニューの同じ機能は必ず無効にする +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_TONE_TOOLNAME;トーンマッピング - 4 +TP_LOCALLAB_TOOLCOL;機能としての構造マスク +TP_LOCALLAB_TOOLMASK;機能 +TP_LOCALLAB_TRANSIT;境界の階調調整 +TP_LOCALLAB_TRANSITGRAD;境界の差異 XY +TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Y軸方向の境界に対するX軸方向の境界の割合を変える +TP_LOCALLAB_TRANSITVALUE;境界値 +TP_LOCALLAB_TRANSITWEAK;境界値の減衰 +TP_LOCALLAB_TRANSITWEAK_TOOLTIP;境界値の減衰を調節 : 処理の滑らかさを変える - 1 線形 - 2 パラボリック - 3 3乗 +TP_LOCALLAB_TRANSIT_TOOLTIP;作用が及ぶ部分と及ばない部分の境界の平滑化を調整します +TP_LOCALLAB_TRANSMISSIONGAIN;透過のゲイン +TP_LOCALLAB_TRANSMISSIONMAP;透過マップ +TP_LOCALLAB_TRANSMISSION_TOOLTIP;透過に応じて透過を決めるカーブです\n横軸はマイナス値(最小)から平均値、プラス値(最大)まであります\n\nこのカーブを使って透過を変え、アーティファクトを軽減できます +TP_LOCALLAB_USEMASK;マスクの使う +TP_LOCALLAB_VART;分散(コントラスト) +TP_LOCALLAB_VIBRANCE;自然な彩度 - ウォーム & クール +TP_LOCALLAB_VIB_TOOLNAME;自然な彩度 - ウォーム & クール - 3 +TP_LOCALLAB_VIS_TOOLTIP;選択したコントロールスポットを表示・非表示するためにはクリックします\n全てのコントロールスポットを表示・非表示するためにはCtrlを押しながらクリックします +TP_LOCALLAB_WAMASKCOL;Ψ ウェーブレットレベルのマスク +TP_LOCALLAB_WARM;ウォーム & -クールと偽色 +TP_LOCALLAB_WARM_TOOLTIP;このスライダーはホワイトバランスのようなCIECAMのアルゴリズムを使っています、選択したエリアの印象を暖かくしたり、冷たくしたりします。\n場合によっては、色のアーティファクトを軽減できます +TP_LOCALLAB_WASDEN_TOOLTIP;最初の3つの細かいレベルのノイズを軽減\n3より粗いレベルのノイズを軽減 +TP_LOCALLAB_WAV;レベルによるローカルコントラスト調整 +TP_LOCALLAB_WAVBLUR_TOOLTIP;残差画像を含め、分解された各詳細レベルに対してぼかしを実行します +TP_LOCALLAB_WAVCOMP;レベルごとの圧縮 +TP_LOCALLAB_WAVCOMPRE;レベルごとの(非)圧縮 +TP_LOCALLAB_WAVCOMPRE_TOOLTIP;トーンマッピング或いはレベルごとのローカルコントラストが軽減出来ます\n横軸がレベルの番手を表しています +TP_LOCALLAB_WAVCOMP_TOOLTIP;ウェーブレットによる分解の方向(水平、垂直、斜め)に応じたローカルコントラストを調整できます +TP_LOCALLAB_WAVCON;レベルによるコントラスト調整 +TP_LOCALLAB_WAVCONTF_TOOLTIP;詳細レベルによるコントラスト調整と似ています:横軸がレベルを表しています +TP_LOCALLAB_WAVDEN;レベルによる輝度ノイズの軽減(0 1 2 + 3、それ以上) +TP_LOCALLAB_WAVE;Ψ ウェーブレット +TP_LOCALLAB_WAVEDG;ローカルコントラスト +TP_LOCALLAB_WAVEEDG_TOOLTIP;少なくとも最初の4つのレベルが使える必要があります +TP_LOCALLAB_WAVGRAD_TOOLTIP;ローカルコントラストの”輝度”に関する諧調調整 +TP_LOCALLAB_WAVHIGH;Ψ ウェーブレット 高 +TP_LOCALLAB_WAVLEV;レベルごとのぼかし +TP_LOCALLAB_WAVLOW;Ψ ウェーブレット 低 +TP_LOCALLAB_WAVMASK;Ψ ローカルコントラストのレベルのマスク +TP_LOCALLAB_WAVMASK_TOOLTIP;Allows fine work on mask levels contrasts (structure) +TP_LOCALLAB_WAVMED;Ψ ウェーブレット 普通 +TP_LOCALLAB_WEDIANHI;メディアン 高 +TP_LOCALLAB_WHITE_EV;ホワイトEv +TP_LOCAL_HEIGHT;ボトム +TP_LOCAL_HEIGHT_T;トップ +TP_LOCAL_WIDTH;右 +TP_LOCAL_WIDTH_L;左 +TP_LOCRETI_METHOD_TOOLTIP;Low = Reinforce low light.\nUniform = Equalize action.\nHigh = Reinforce high light.\n TP_METADATA_EDIT;変更を適用 TP_METADATA_MODE;メタデータ コピーモード TP_METADATA_STRIP;メタデータを全て取り除く @@ -1811,8 +2877,26 @@ TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;形状: 0=長方形、50=楕円形、100=円 TP_PCVIGNETTE_STRENGTH;強さ TP_PCVIGNETTE_STRENGTH_TOOLTIP;終点位置でのフィルターの強さ(四隅) TP_PDSHARPENING_LABEL;キャプチャーシャープニング +TP_PERSPECTIVE_CAMERA_CROP_FACTOR;クロップ・ファクター +TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH;焦点距離 +TP_PERSPECTIVE_CAMERA_FRAME;補正 +TP_PERSPECTIVE_CAMERA_PITCH;垂直 +TP_PERSPECTIVE_CAMERA_ROLL;回転 +TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL;水平移動 +TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL;垂直移動 +TP_PERSPECTIVE_CAMERA_YAW;水平 TP_PERSPECTIVE_HORIZONTAL;水平 TP_PERSPECTIVE_LABEL;パースペクティブ +TP_PERSPECTIVE_METHOD;方式 +TP_PERSPECTIVE_METHOD_CAMERA_BASED;カメラベース +TP_PERSPECTIVE_METHOD_SIMPLE;シンプル +TP_PERSPECTIVE_POST_CORRECTION_ADJUSTMENT_FRAME;補正後の調整 +TP_PERSPECTIVE_PROJECTION_PITCH;垂直 +TP_PERSPECTIVE_PROJECTION_ROTATE;回転 +TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL;水平移動 +TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL;垂直移動 +TP_PERSPECTIVE_PROJECTION_YAW;水平 +TP_PERSPECTIVE_RECOVERY_FRAME;回復 TP_PERSPECTIVE_VERTICAL;垂直 TP_PFCURVE_CURVEEDITOR_CH;色相 TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;デフリンジの強さをコントロールします。値が高いと効果が強まり、低いと弱まります @@ -1830,6 +2914,10 @@ TP_PREPROCESS_LINEDENOISE_DIRECTION_PDAF_LINES;PDAFの場合は水平方向だ TP_PREPROCESS_LINEDENOISE_DIRECTION_VERTICAL;垂直方向 TP_PREPROCESS_NO_FOUND;未検出 TP_PREPROCESS_PDAFLINESFILTER;PDAFラインフィルタ +TP_PREPROCWB_LABEL;ホワイトバランスの前処理 +TP_PREPROCWB_MODE;モード +TP_PREPROCWB_MODE_AUTO;自動 +TP_PREPROCWB_MODE_CAMERA;カメラ TP_PRSHARPENING_LABEL;リサイズ後のシャープニング TP_PRSHARPENING_TOOLTIP;リサイズ後の画像をシャープニングします。但し、リサイズの方式がランチョスの場合に限ります。プレビュー画面でこの機能の効果を見ることは出来ません。使用法に関してはRawPediaを参照して下さい。 TP_RAWCACORR_AUTO;自動補正 @@ -1934,8 +3022,8 @@ TP_RESIZE_SCALE;スケール TP_RESIZE_SPECIFY;条件指定: TP_RESIZE_W;幅: TP_RESIZE_WIDTH;幅 -TP_RETINEX_CONTEDIT_HSL;ヒストグラムイコライザ HSL -TP_RETINEX_CONTEDIT_LAB;ヒストグラムイコライザ L*a*b* +TP_RETINEX_CONTEDIT_HSL;HSLヒストグラム +TP_RETINEX_CONTEDIT_LAB;L*a*b*ヒストグラム TP_RETINEX_CONTEDIT_LH;色相イコライザ TP_RETINEX_CONTEDIT_MAP;イコライザ TP_RETINEX_CURVEEDITOR_CD;輝度=f(輝度) @@ -1947,8 +3035,8 @@ TP_RETINEX_CURVEEDITOR_MAP_TOOLTIP;このカーブは単独で使うことも、 TP_RETINEX_EQUAL;イコライザ TP_RETINEX_FREEGAMMA;フリーガンマ TP_RETINEX_GAIN;ゲイン -TP_RETINEX_GAINOFFS;ゲインとオフセット(明るさ) -TP_RETINEX_GAINTRANSMISSION;ゲインの透過 +TP_RETINEX_GAINOFFS;透過マップのゲインとオフセット +TP_RETINEX_GAINTRANSMISSION;ゲイン TP_RETINEX_GAINTRANSMISSION_TOOLTIP;目標とする輝度を得るために、透過マップ増幅したり減衰させたりします。\n横軸:左から最小、平均、最大となります。\n縦軸:ゲイン TP_RETINEX_GAMMA;ガンマ TP_RETINEX_GAMMA_FREE;フリー @@ -1957,8 +3045,8 @@ TP_RETINEX_GAMMA_LOW;低 TP_RETINEX_GAMMA_MID;中間 TP_RETINEX_GAMMA_NONE;なし TP_RETINEX_GAMMA_TOOLTIP;レティネックス機能の前後のガンマで画像のトーンを修復します。レティネックスのカーブや他のカーブ(Lab調整、露光補正などのカーブ)とは異なるカーブです。 -TP_RETINEX_GRAD;透過のグラデーション -TP_RETINEX_GRADS;強さのグラデーション +TP_RETINEX_GRAD;透過マップの勾配 +TP_RETINEX_GRADS;強さの勾配 TP_RETINEX_GRADS_TOOLTIP;スライダー値が0の場合、全ての繰り返しは同じになります\n0より大きい場合は、繰り返しが増加すると強さが減ります。0より小さい場合はその逆です TP_RETINEX_GRAD_TOOLTIP;スライダー値が0の場合、全ての繰り返しが同じになります\n0より大きい場合は、繰り返しが増加すると差異としきい値が減ります。0より小さい場合はその逆です TP_RETINEX_HIGH;高 @@ -1978,25 +3066,25 @@ TP_RETINEX_MAP;方式 TP_RETINEX_MAP_GAUS;ガウシアンマスク TP_RETINEX_MAP_MAPP;シャープマスク (一部ウェーブレット) TP_RETINEX_MAP_MAPT;シャープマスク (全てウェーブレット) -TP_RETINEX_MAP_METHOD_TOOLTIP;ガウス関数を利用して生成したマスクをハロやアーティファクトを減らすために使う方法です\n\nカーブだけ:マスクにコントラストカーブを適用します\nアーティファクト発生に注意\n\nガウシアンマスク:元画像に対しガウス暈しでマスクを生成し、それを使います\n処理時間短い\n\nシャープマスク:元画像に対しウェーブレットでマスクを生成し、それを使います\n処理時間が長い +TP_RETINEX_MAP_METHOD_TOOLTIP;ガウス関数(半径や方式)で生成されたマスクを利用してハロやアーティファクトを減らします\n\nカーブだけ:マスクにコントラストカーブを適用します\nアーティファクト発生に注意\n\nガウシアンマスク:元画像に対しガウス暈しでマスクを生成し、それを使います\n処理時間短い\n\nシャープマスク:元画像に対しウェーブレットでマスクを生成し、それを使います\n処理時間が長い TP_RETINEX_MAP_NONE;なし TP_RETINEX_MEDIAN;透過のメディアンフィルター TP_RETINEX_METHOD;方法 -TP_RETINEX_METHOD_TOOLTIP;高=明瞭な部分のレンダリングを補正します\n均等=明瞭な部分と不明瞭な部分をバランスよく補正します\n低=不明瞭な部分を重点的に補正します\nハイライト=ハイライト部分のマゼンタ被りを補正します +TP_RETINEX_METHOD_TOOLTIP;高=光度の高い部分のレンダリングを補正します\n均等=光度の高い部分と低い部分を均等に補正します\n低=光度の低い部分を重点的に補正します\nハイライト=ハイライト部分のマゼンタ被りを補正します TP_RETINEX_MLABEL;霞のない画像に修復 最小値=%1 最大値=%2 TP_RETINEX_MLABEL_TOOLTIP;最小値=0 最大値=32768に近づける\nバランスの良い霞のない画像 TP_RETINEX_NEIGHBOR;半径 TP_RETINEX_NEUTRAL;リセット TP_RETINEX_NEUTRAL_TIP;全てのスライダー値とカーブをデフォルトの状態に戻します -TP_RETINEX_OFFSET;オフセット(明るさ) -TP_RETINEX_SCALES;ガウス暈しのグラデーション +TP_RETINEX_OFFSET;オフセット +TP_RETINEX_SCALES;ガウスフィルタの勾配 TP_RETINEX_SCALES_TOOLTIP;スライダー値が0の場合、同一の作業を繰り返します\n0より大きい値を設定すると、繰り返し作業を増やした時に、スケールと隣接するピクセルに対する作用は減ります。0より小さい場合は、その逆です TP_RETINEX_SETTINGS;設定 TP_RETINEX_SKAL;スケール -TP_RETINEX_SLOPE;フリーなガンマの勾配 +TP_RETINEX_SLOPE;フリーガンマの勾配 TP_RETINEX_STRENGTH;強さ TP_RETINEX_THRESHOLD;しきい値 -TP_RETINEX_THRESHOLD_TOOLTIP;インとアウトの制限を意味します\nイン=原画像\nアウト=ガウス暈しを施した原画像 +TP_RETINEX_THRESHOLD_TOOLTIP;インとアウトの制限を意味します\nイン=原画像\nアウト=ガウスフィルタを施した原画像 TP_RETINEX_TLABEL;透過 差異の最小値=%1 最大値=%2 平均=%3 標準偏差=%4 TP_RETINEX_TLABEL2;透過 最小値=%1 最大値=%2 TP_RETINEX_TLABEL_TOOLTIP;透過マップの結果を表示しています\n差異の最小値と最大値です\n平均と標準偏差\n透過マップの最小値と最大値です @@ -2024,11 +3112,11 @@ TP_ROTATE_DEGREE;角度 TP_ROTATE_LABEL;回転 TP_ROTATE_SELECTLINE;直線選択・角度補正ツール TP_SAVEDIALOG_OK_TIP;ショートカット Ctrl-Enter -TP_SHADOWSHLIGHTS_HIGHLIGHTS;ハイライトを暗く +TP_SHADOWSHLIGHTS_HIGHLIGHTS;ハイライト TP_SHADOWSHLIGHTS_HLTONALW;ハイライトトーンの幅 TP_SHADOWSHLIGHTS_LABEL;シャドウ/ハイライト TP_SHADOWSHLIGHTS_RADIUS;半径 -TP_SHADOWSHLIGHTS_SHADOWS;シャドウを明るく +TP_SHADOWSHLIGHTS_SHADOWS;シャドウ TP_SHADOWSHLIGHTS_SHTONALW;シャドウトーンの幅 TP_SHARPENEDGE_AMOUNT;適用量 TP_SHARPENEDGE_LABEL;エッジ @@ -2105,14 +3193,20 @@ TP_WAVELET_B2;残差 TP_WAVELET_BACKGROUND;背景 TP_WAVELET_BACUR;カーブ TP_WAVELET_BALANCE;コントラストバランス 斜め/垂直-水平 -TP_WAVELET_BALANCE_TOOLTIP;ウェーブレットの方向で垂直-水平と斜めのバランスを変えます\nコントラスト、色度、或いは残差画像のトーンマッピングが有効の場合、バランスにより効果が増幅されます +TP_WAVELET_BALANCE_TOOLTIP;ウェーブレットの解析方向の垂直-水平と斜めのバランスを変えます\nコントラスト、色度、或いは残差画像のトーンマッピングが有効の場合、バランスにより効果が増幅されます TP_WAVELET_BALCHRO;色度のバランス +TP_WAVELET_BALCHROM;色ノイズ除去のイコライザ ブルー/イエロー レッド/グリーン TP_WAVELET_BALCHRO_TOOLTIP;有効にすると、’コントラストバランス’のカーブやスライダーも色度のバランスに影響します +TP_WAVELET_BALLUM;輝度ノイズ除去のイコライザ 白黒 TP_WAVELET_BANONE;なし TP_WAVELET_BASLI;スライダー -TP_WAVELET_BATYPE;バランス方式 +TP_WAVELET_BATYPE;コントラストバランス方式 +TP_WAVELET_BL;ぼかしのレベル +TP_WAVELET_BLCURVE;詳細レベルによるぼかし +TP_WAVELET_BLURFRAME;ぼかし +TP_WAVELET_BLUWAV;減衰応答 TP_WAVELET_CBENAB;カラートーンとカラーバランス -TP_WAVELET_CB_TOOLTIP;高い値は、’カラートーン’と併用するか、或いはカラートーンは使わないで単独で使います。\n低い値の場合は前景の色合いを変えずに背景(sky, ...) のホワイトバランスを変えるような効果を得られます。一般的にはコントラストが高くなる印象があります。 +TP_WAVELET_CB_TOOLTIP;高い値は、’カラートーン’と併用するか、或いはカラートーンは使わないで単独で使います。\n低い値の場合は前景の色合いを変えずに背景(空 ...) のホワイトバランスを変えるような効果を得られます。一般的にはコントラストが高くなる印象があります。 TP_WAVELET_CCURVE;ローカルコントラスト TP_WAVELET_CH1;全ての色 TP_WAVELET_CH2;明清色 - 純色 @@ -2120,22 +3214,32 @@ TP_WAVELET_CH3;コントラストのレベルとリンク TP_WAVELET_CHCU;カーブ TP_WAVELET_CHR;色度とコントラストのリンクの強さ TP_WAVELET_CHRO;純色 - 明清色のしきい値 +TP_WAVELET_CHROFRAME;色ノイズの除去 +TP_WAVELET_CHROMAFRAME;色度 +TP_WAVELET_CHROMCO;番手の高いレベルの色度 +TP_WAVELET_CHROMFI;番手の低いレベルの色度 TP_WAVELET_CHRO_TOOLTIP;どのレベルで明清色と純色を調整するか決めます\n1-x:純色を調整するレベルの範囲\nx-9:明清色を調整するレベルの範囲\n\n但し、値がレベルの総数より多い場合は機能が無効となります +TP_WAVELET_CHRWAV;色度のぼかし TP_WAVELET_CHR_TOOLTIP;色度を”コントラストレベル”と”色度とコントラストのリンクの強さ”の相関関係で調整します TP_WAVELET_CHSL;スライダー TP_WAVELET_CHTYPE;調整の方法 +TP_WAVELET_CLA;明瞭 +TP_WAVELET_CLARI;シャープマスクと明瞭 TP_WAVELET_COLORT;レッド/グリーンの不透明度 TP_WAVELET_COMPCONT;コントラスト TP_WAVELET_COMPGAMMA;ガンマの圧縮 TP_WAVELET_COMPGAMMA_TOOLTIP;残差画像のガンマを調整することで、画像データとヒストグラムの均衡を図ります。 TP_WAVELET_COMPTM;トーンマッピング TP_WAVELET_CONTEDIT;'後の' コントラストカーブ +TP_WAVELET_CONTFRAME;コントラスト - 圧縮 TP_WAVELET_CONTR;色域 TP_WAVELET_CONTRA;コントラスト +TP_WAVELET_CONTRASTEDIT;細かい~大まか レベルの指定 TP_WAVELET_CONTRAST_MINUS;コントラスト - TP_WAVELET_CONTRAST_PLUS;コントラスト + TP_WAVELET_CONTRA_TOOLTIP;残差画像のコントラストを変えます TP_WAVELET_CTYPE;色の制御 +TP_WAVELET_CURVEEDITOR_BL_TOOLTIP;拡大率が300%より上になると無効になります TP_WAVELET_CURVEEDITOR_CC_TOOLTIP;元画像のローカルコントラストに応じてローカルコントラストを調節します\n横軸の低い部分は細かいローカルコントラストを表しています(実質値10~20)\n50%はローカルコントラストの平均(実質値100~300)を表しています\n66%はローカルコントラストの標準偏差(実質値300~800)を表しています\n100%はローカルコントラストの最大値を表しています(実質値3000~8000) TP_WAVELET_CURVEEDITOR_CH;コントラストレベル=f(色相) TP_WAVELET_CURVEEDITOR_CH_TOOLTIP;色相に応じて各レベルのコントラストを調節します\n色域抑制のカーブ調整と重複しないように注意します\nウェーブレットのコントラストレベルスライダー値が0の場合は効果はありません @@ -2150,11 +3254,15 @@ TP_WAVELET_DAUB4;D4 - 標準 TP_WAVELET_DAUB6;D6 - 標準プラス TP_WAVELET_DAUB10;D10 - やや高い TP_WAVELET_DAUB14;D14 - 高い +TP_WAVELET_DAUBLOCAL;ウェーブレット エッジ検出の効果 TP_WAVELET_DAUB_TOOLTIP;ドブシー関数の係数を変更します\nD4=標準的なエッジ検出の効果\nD14=通常はエッジ検出の効果が高いが、処理時間が約10%増加\n\n初めのレベルの質だけでなくエッジ検出にも影響します。但し、レベル質は厳格に係数の種類に比例している訳ではありません。画像や使い方にも影響されます。 +TP_WAVELET_DIRFRAME;方向によるコントラスト TP_WAVELET_DONE;垂直 TP_WAVELET_DTHR;対角線 TP_WAVELET_DTWO;水平 TP_WAVELET_EDCU;カーブ +TP_WAVELET_EDEFFECT;減衰応答 +TP_WAVELET_EDEFFECT_TOOLTIP;このスライダーは機能の最大効果を受けるコントラスト値の範囲を調整するものです。最大値(2.5)を設定すると機能の効果が無効となります。 TP_WAVELET_EDGCONT;ローカルコントラスト TP_WAVELET_EDGCONT_TOOLTIP;スライダーを左に動かすとコントラストが減り、右に動かすと増えます\n底部の左、天井部の左、底部の右、天井部の右は、それぞれ低いコントラスト、平均的コントラスト、平均+1標準偏差のコントラスト、最も高いコントラストを示しています TP_WAVELET_EDGE;エッジのシャープネス @@ -2174,10 +3282,11 @@ TP_WAVELET_EDSL;しきい値スライダー TP_WAVELET_EDTYPE;ローカルコントラストの方式 TP_WAVELET_EDVAL;強さ TP_WAVELET_FINAL;最終調整 +TP_WAVELET_FINCFRAME;最終的なローカルコントラスト TP_WAVELET_FINEST;最も細かい -TP_WAVELET_HIGHLIGHT;ハイライトの輝度範囲 +TP_WAVELET_HIGHLIGHT;細かいレベルの輝度調整範囲 TP_WAVELET_HS1;全輝度範囲 -TP_WAVELET_HS2;シャドウ-ハイライト +TP_WAVELET_HS2;指定した輝度範囲 TP_WAVELET_HUESKIN;肌色の色相 TP_WAVELET_HUESKIN_TOOLTIP;底部の2つのポイントは、色相変化が始まる部分に設定されています、天井部の2つのポイントは変化が終わる所で、色相調整の効果が最も高い部分です\n\n設定ポイントを著しく動かす必要がある場合、或いはアーティファクトが発生するようであれば、ホワイトバランスが不適切と考えられます TP_WAVELET_HUESKY;色相の範囲(デフォルト:青空) @@ -2185,7 +3294,7 @@ TP_WAVELET_HUESKY_TOOLTIP;底部の2つのポイントは、色相変化が始 TP_WAVELET_ITER;デルタバランスのレベル TP_WAVELET_ITER_TOOLTIP;スライダーを左に動かすと、低いレベルのデルタが増え、高いレベルのデルタが減ります\n右に動かすとその逆です TP_WAVELET_LABEL;ウェーブレット -TP_WAVELET_LARGEST;最も粗い +TP_WAVELET_LARGEST;最も大まか TP_WAVELET_LEVCH;色度 TP_WAVELET_LEVDIR_ALL;全てのレベルと方向を合わせた画像 TP_WAVELET_LEVDIR_INF;選択したレベル以下を合わせた画像 @@ -2201,57 +3310,89 @@ TP_WAVELET_LEVTWO;レベル3 TP_WAVELET_LEVZERO;レベル1 TP_WAVELET_LINKEDG;エッジのシャープネスの強さとリンク TP_WAVELET_LIPST;高度なアルゴリズム -TP_WAVELET_LOWLIGHT;シャドウの輝度範囲 +TP_WAVELET_LOWLIGHT;大まかなレベルの輝度調整範囲 +TP_WAVELET_LOWTHR_TOOLTIP;詳細とノイズの増幅を避けます TP_WAVELET_MEDGREINF;最初のレベル TP_WAVELET_MEDI;青空のアーティファクトを軽減 TP_WAVELET_MEDILEV;エッジ検出 TP_WAVELET_MEDILEV_TOOLTIP;エッジの検出を有効にした際には、次の操作が奨められます:\n- アーティファクト発生を避けるため低いレベルのコントラストを使わない\n- グラデーション感度では高い値を使う\n\n効果を和らげるには、ノイズ低減とリファインの’リファイン’を下げる +TP_WAVELET_MERGEC;色度を融合 +TP_WAVELET_MERGEL;輝度を融合 TP_WAVELET_NEUTRAL;ニュートラル TP_WAVELET_NOIS;ノイズ低減 TP_WAVELET_NOISE;ノイズ低減とリファイン +TP_WAVELET_NOISE_TOOLTIP;詳細レベル4の輝度ノイズ除去が20以上の時にはアグレッシブモードが使われます\n色ノイズ除去で、大まかなレベルの値が20以上の時は、アグレッシブモードが使われます TP_WAVELET_NPHIGH;高い TP_WAVELET_NPLOW;低い TP_WAVELET_NPNONE;なし TP_WAVELET_NPTYPE;隣接するピクセルに対する効果 TP_WAVELET_NPTYPE_TOOLTIP;このアルゴリズムは近傍する8つのピクセルを使って比較します。違いが少ない場合に、エッジを強化します。 +TP_WAVELET_OFFSET_TOOLTIP;オフセットはシャドウとハイライトのバランスを調整する機能です\n 高い値を設定するとシャドウ部分のコントラスト強化が増幅されます。最小コントラストのしきい値と合わせて使えば、コントラストを高くしたい部分の見極めに役立つでしょう +TP_WAVELET_OLDSH;マイナス値が使えるアルゴリズム TP_WAVELET_OPACITY;ブルー/イエローの不透明度 TP_WAVELET_OPACITYW;コントラストバランス d/v-hカーブ TP_WAVELET_OPACITYWL;最終的なローカルコントラスト TP_WAVELET_OPACITYWL_TOOLTIP;ウェーブレット処理の最後で最終的なローカルコントラストを調整します\n\nイコライザは左から右に向かって、最も細かいローカルコントラストから大きいローカルコントラストを表しています TP_WAVELET_PASTEL;明清色の色度 TP_WAVELET_PROC;プロセス +TP_WAVELET_PROTAB;保護 +TP_WAVELET_RADIUS;シャドウ/ハイライトの半径 +TP_WAVELET_RANGEAB;aとbの範囲 % TP_WAVELET_RE1;強める TP_WAVELET_RE2;変えない TP_WAVELET_RE3;弱める -TP_WAVELET_RESCHRO;色度 +TP_WAVELET_RESBLUR;輝度のぼかし +TP_WAVELET_RESBLURC;色度のぼかし +TP_WAVELET_RESBLUR_TOOLTIP;拡大率が500%以上の場合は作用が無効となります +TP_WAVELET_RESCHRO;強さ TP_WAVELET_RESCON;シャドウ TP_WAVELET_RESCONH;ハイライト TP_WAVELET_RESID;残差画像 TP_WAVELET_SAT;純色の色度 TP_WAVELET_SETTINGS;ウェーブレットの設定 -TP_WAVELET_SKIN;色相-トーン (肌色) の目標/保護 +TP_WAVELET_SHA;シャープマスク +TP_WAVELET_SHFRAME;シャドウ/ハイライト +TP_WAVELET_SHOWMASK;ウェーブレットの'マスク'を表示 +TP_WAVELET_SIGMA;減衰応答 +TP_WAVELET_SIGMAFIN;減衰応答 +TP_WAVELET_SIGMA_TOOLTIP;コントラストスライダーの調整効果は、中間的なマイクロコントラストは強く、低い、或いは高いマイクロコントラストはそうでもありません。\n減衰応答は、この調整作用を極端なコントラスト値に向けて、どれだけ素早く減衰させるかコントロールするスライダーです。\n高い値を設定すると、減衰が強く作用するマイクロコントラストの領域が広がりますが、アーティファクトが発生することがあります。\n低い値を設定すると、減衰が強く作用するマイクロコントラストの領域が狭くなるので、よりピンポイントに効果が表れます。 +TP_WAVELET_SKIN;肌色の目標/保護 TP_WAVELET_SKIN_TOOLTIP;-100にすると肌色のトーンだけが調整の対象になります\n0にすると全てのカラートーンが調整されます\n+100にすると肌色のトーンは保護され、他のカラートーンが調整されます -TP_WAVELET_SKY;色相-トーン(青空)の目標/保護 +TP_WAVELET_SKY;色相の目標/保護 TP_WAVELET_SKY_TOOLTIP;-100にすると青空のトーンだけが調整の対象になります\n0にすると全てのカラートーンが調整されます\n+100にすると青空のトーンは保護され、他のカラートーンが調整されます +TP_WAVELET_SOFTRAD;ソフトな半径 TP_WAVELET_STREN;強さ TP_WAVELET_STRENGTH;強さ TP_WAVELET_SUPE;エキストラ TP_WAVELET_THR;シャドウのしきい値 -TP_WAVELET_THRESHOLD;ハイライトを調整するレベル -TP_WAVELET_THRESHOLD2;シャドウを調整するレベル -TP_WAVELET_THRESHOLD2_TOOLTIP;レベル9と(9-設定値)のレベルの間でシャドウの輝度が調整されます。他のレベルは輝度範囲全体で調整されます。 -TP_WAVELET_THRESHOLD_TOOLTIP;設定値以上のレベルだけが、ハイライトの輝度で調整されます。他のレベルは輝度範囲全体で調整されます。選べる設定値の最大数はシャドウレベルの設定に左右されます。 +TP_WAVELET_THRESHOLD;調整するレベル 細かい +TP_WAVELET_THRESHOLD2;調整するレベル 大まか +TP_WAVELET_THRESHOLD2_TOOLTIP;設定値より上の詳細レベルだけが、大まかなレベルの輝度範囲で設定された条件で調整されます。 +TP_WAVELET_THRESHOLD_TOOLTIP;設定値以下の詳細レベルだけが、細かいレベルの輝度範囲で設定された条件で調整されます。 +TP_WAVELET_THRESWAV;バランスのしきい値 TP_WAVELET_THRH;ハイライトのしきい値 TP_WAVELET_TILESBIG;大きいタイル TP_WAVELET_TILESFULL;画像全体 TP_WAVELET_TILESIZE;タイルのサイズ TP_WAVELET_TILESLIT;小さいタイル TP_WAVELET_TILES_TOOLTIP;画像全体を処理する方が良い結果をもたらすので、推奨される選択です。タイルによる処理はRAMの容量が小さいユーザー向けです。必要なメモリー容量に関してはRawPediaを参照して下さい。 -TP_WAVELET_TMSTRENGTH;残差の効力を圧縮 +TP_WAVELET_TMEDGS;エッジ停止 +TP_WAVELET_TMSCALE;スケール +TP_WAVELET_TMSTRENGTH;圧縮の強さ TP_WAVELET_TMSTRENGTH_TOOLTIP;トーンマッピングの強さや残差画像のコントラストの圧縮を加減します。値が0以外の場合、露光補正パネルのトーンマッピングでは、強さとガンマのスライダー無効となります TP_WAVELET_TMTYPE;圧縮の方法 TP_WAVELET_TON;カラートーン +TP_WAVELET_TONFRAME;除外されたカラー +TP_WAVELET_USH;なし +TP_WAVELET_USHARP;明瞭の方式 +TP_WAVELET_USHARP_TOOLTIP;オリジン : ウェーブレットによる調整を含まないソースファイル\nウェーブレット : ウェーブレットによる調整を含むソースファイル +TP_WAVELET_USH_TOOLTIP;シャープマスクを選択すると、ウェーブレットの設定が次の様に自動的に行われます:\n背景=ブラック、処理=レベル3以下...レベルは1~4の間で変えられます\n\n明瞭を選択すると、ウェーブレットの設定が次の様に自動的に行われます:\n背景=残差画像、処理=レベル7以上 レベルは5~10の間で変えられます +TP_WAVELET_WAVLOWTHR;最小コントラストのしきい値 +TP_WAVELET_WAVOFFSET;オフセット TP_WBALANCE_AUTO;自動補正 +TP_WBALANCE_AUTOITCGREEN;色温度の相関関係を繰り返し解析する +TP_WBALANCE_AUTOOLD;RGBグレーを使う +TP_WBALANCE_AUTO_HEADER;自動 TP_WBALANCE_CAMERA;カメラ TP_WBALANCE_CLOUDY;曇天 TP_WBALANCE_CUSTOM;カスタム @@ -2284,7 +3425,7 @@ TP_WBALANCE_LAMP_HEADER;ランプ TP_WBALANCE_LED_CRS;CRS SP12 WWMR16 TP_WBALANCE_LED_HEADER;LED TP_WBALANCE_LED_LSI;LSI Lumelex 2040 -TP_WBALANCE_METHOD;モード +TP_WBALANCE_METHOD;方式 TP_WBALANCE_PICKER;ピック TP_WBALANCE_SHADE;日陰 TP_WBALANCE_SIZE;サイズ: @@ -2292,7 +3433,9 @@ TP_WBALANCE_SOLUX35;Solux 3500K TP_WBALANCE_SOLUX41;Solux 4100K TP_WBALANCE_SOLUX47;Solux 4700K (vendor) TP_WBALANCE_SOLUX47_NG;Solux 4700K (Nat. Gallery) -TP_WBALANCE_SPOTWB;スポットWB +TP_WBALANCE_SPOTWB;ピペットを使ってプレビュー画像のニュートラルな部分をピックアップ +TP_WBALANCE_STUDLABEL;t検定 Itcwb: %1 +TP_WBALANCE_STUDLABEL_TOOLTIP;t検定の結果を表示\n低い値ほど相関関係が良いことになります\n値が0.002以下はエクセレント\n0.005以下は非常に良い\n0.01以下は良い\n0.05以下は十分\n0.5以上は悪い\n光源が標準的ではない場合は、t検定が良好であってもホワイトバラスが良いことにはなりません\nt検定結果が1000と表示された場合は反復解析が行われなかったことを意味します。良い結果と想定される前の計算結果が使われます TP_WBALANCE_TEMPBIAS;自動ホワイトバランス 色温度のバイアス TP_WBALANCE_TEMPBIAS_TOOLTIP;”自動ホワイトバランスの計算に変更を加えます”\n色温度を変えることで画像の暖かみを増やしたり、冷たさを増やしたりします。\n偏向の度合いは色温度の割合で表示されます\n従って計算値は "算出した色温度 + 算出した色温度 * 偏向"で計算したものです TP_WBALANCE_TEMPERATURE;色温度 @@ -2300,7 +3443,6 @@ TP_WBALANCE_TUNGSTEN;タングステン TP_WBALANCE_WATER1;水中 1 TP_WBALANCE_WATER2;水中 2 TP_WBALANCE_WATER_HEADER;水中 -The last update by firefly 2019-12-21 ZOOMPANEL_100;(100%) ZOOMPANEL_NEWCROPWINDOW;新規ディテール ウィンドウを開く ZOOMPANEL_ZOOM100;100%にズーム\nショートカット: z @@ -2313,7 +3455,4 @@ ZOOMPANEL_ZOOMOUT;ズームアウト\nショートカット: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! -!GENERAL_HELP;Help -!HISTORY_MSG_TRANS_Method;Geometry - Method -!TP_LENSGEOM_LIN;Linear -!TP_LENSGEOM_LOG;Logarithmic +!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 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 db92cc49e..0774e5494 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 @@ -145,6 +145,7 @@ FILEBROWSER_POPUPCOLORLABEL4;Label: Blue FILEBROWSER_POPUPCOLORLABEL5;Label: Purple FILEBROWSER_POPUPCOPYTO;Copy to... FILEBROWSER_POPUPFILEOPERATIONS;File operations +FILEBROWSER_POPUPINSPECT;Inspect FILEBROWSER_POPUPMOVEEND;Move to end of queue FILEBROWSER_POPUPMOVEHEAD;Move to head of queue FILEBROWSER_POPUPMOVETO;Move to... @@ -220,8 +221,10 @@ GENERAL_BEFORE;Before GENERAL_CANCEL;Cancel GENERAL_CLOSE;Close GENERAL_CURRENT;Current +GENERAL_DELETE_ALL;Delete all GENERAL_DISABLE;Disable GENERAL_DISABLED;Disabled +GENERAL_EDIT;Edit GENERAL_ENABLE;Enable GENERAL_ENABLED;Enabled GENERAL_FILE;File @@ -243,11 +246,20 @@ GIMP_PLUGIN_INFO;Welcome to the RawTherapee GIMP plugin!\nOnce you are done edit HISTOGRAM_TOOLTIP_B;Show/Hide blue histogram. HISTOGRAM_TOOLTIP_BAR;Show/Hide RGB indicator bar. HISTOGRAM_TOOLTIP_CHRO;Show/Hide chromaticity histogram. +HISTOGRAM_TOOLTIP_CROSSHAIR;Show/Hide indicator crosshair. HISTOGRAM_TOOLTIP_G;Show/Hide green histogram. HISTOGRAM_TOOLTIP_L;Show/Hide CIELab luminance histogram. HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram. HISTOGRAM_TOOLTIP_R;Show/Hide red histogram. HISTOGRAM_TOOLTIP_RAW;Show/Hide raw histogram. +HISTOGRAM_TOOLTIP_SHOW_OPTIONS;Toggle visibility of the scope option buttons. +HISTOGRAM_TOOLTIP_TRACE_BRIGHTNESS;Adjust scope brightness. +HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM;Histogram +HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW;Raw Histogram +HISTOGRAM_TOOLTIP_TYPE_PARADE;RGB Parade +HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HC;Hue-Chroma Vectorscope +HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HS;Hue-Saturation Vectorscope +HISTOGRAM_TOOLTIP_TYPE_WAVEFORM;Waveform HISTORY_CHANGED;Changed HISTORY_CUSTOMCURVE;Custom curve HISTORY_FROMCLIPBOARD;From clipboard @@ -567,10 +579,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 - 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_318;W - Contrast - Finer levels +HISTORY_MSG_319;W - Contrast - Finer range +HISTORY_MSG_320;W - Contrast - Coarser range +HISTORY_MSG_321;W - Contrast - Coarser levels HISTORY_MSG_322;W - Gamut - Avoid color shift HISTORY_MSG_323;W - ES - Local contrast HISTORY_MSG_324;W - Chroma - Pastel @@ -634,14 +646,14 @@ HISTORY_MSG_381;PRS RLD - Radius HISTORY_MSG_382;PRS RLD - Amount HISTORY_MSG_383;PRS RLD - Damping HISTORY_MSG_384;PRS RLD - Iterations -HISTORY_MSG_385;W - Residual - Color Balance +HISTORY_MSG_385;W - Residual - Color balance HISTORY_MSG_386;W - Residual - CB green high HISTORY_MSG_387;W - Residual - CB blue high HISTORY_MSG_388;W - Residual - CB green mid HISTORY_MSG_389;W - Residual - CB blue mid HISTORY_MSG_390;W - Residual - CB green low HISTORY_MSG_391;W - Residual - CB blue low -HISTORY_MSG_392;W - Residual - Color Balance +HISTORY_MSG_392;W - Residual - Color balance HISTORY_MSG_393;DCP - Look table HISTORY_MSG_394;DCP - Baseline exposure HISTORY_MSG_395;DCP - Base table @@ -694,21 +706,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,9 +754,484 @@ 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 -decay +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-decay +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 saturation +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 +HISTORY_MSG_843;Local - Radius +HISTORY_MSG_845;Local - Log encoding +HISTORY_MSG_846;Local - Log encoding auto +HISTORY_MSG_847;Local - Log encoding Source +HISTORY_MSG_849;Local - Log encoding Source auto +HISTORY_MSG_850;Local - Log encoding B_Ev +HISTORY_MSG_851;Local - Log encoding W_Ev +HISTORY_MSG_852;Local - Log encoding Target +HISTORY_MSG_853;Local - Log encodind loc contrast +HISTORY_MSG_854;Local - Log encodind Scope +HISTORY_MSG_855;Local - Log encoding Whole image +HISTORY_MSG_856;Local - Log encoding Shadows range +HISTORY_MSG_857;Local - Wavelet blur residual +HISTORY_MSG_858;Local - Wavelet blur luminance only +HISTORY_MSG_859;Local - Wavelet max blur +HISTORY_MSG_860;Local - Wavelet blur levels +HISTORY_MSG_861;Local - Wavelet contrast levels +HISTORY_MSG_862;Local - Wavelet contrast attenuation +HISTORY_MSG_863;Local - Wavelet merge original image +HISTORY_MSG_864;Local - Wavelet dir contrast attenuation +HISTORY_MSG_865;Local - Wavelet dir contrast delta +HISTORY_MSG_866;Local - Wavelet dir compression +HISTORY_MSG_869;Local - Denoise by level +HISTORY_MSG_870;Local - Wavelet mask curve H +HISTORY_MSG_871;Local - Wavelet mask curve C +HISTORY_MSG_872;Local - Wavelet mask curve L +HISTORY_MSG_873;Local - Wavelet mask +HISTORY_MSG_875;Local - Wavelet mask blend +HISTORY_MSG_876;Local - Wavelet mask smooth +HISTORY_MSG_877;Local - Wavelet mask chroma +HISTORY_MSG_878;Local - Wavelet mask contrast curve +HISTORY_MSG_879;Local - Wavelet contrast chroma +HISTORY_MSG_880;Local - Wavelet blur chroma +HISTORY_MSG_881;Local - Wavelet contrast offset +HISTORY_MSG_882;Local - Wavelet blur +HISTORY_MSG_883;Local - Wavelet contrast by level +HISTORY_MSG_884;Local - Wavelet dir contrast +HISTORY_MSG_885;Local - Wavelet tone mapping +HISTORY_MSG_886;Local - Wavelet tone mapping compress +HISTORY_MSG_887;Local - Wavelet tone mapping compress 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 - Log Encoding Graduated Strength +HISTORY_MSG_893;Local - Log Encoding 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 +HISTORY_MSG_928;Local - Common color mask +HISTORY_MSG_929;Local - Mask common scope +HISTORY_MSG_930;Local - Mask Common blend luma +HISTORY_MSG_931;Local - Mask Common enable +HISTORY_MSG_932;Local - Mask Common radius soft +HISTORY_MSG_933;Local - Mask Common laplacian +HISTORY_MSG_934;Local - Mask Common chroma +HISTORY_MSG_935;Local - Mask Common gamma +HISTORY_MSG_936;Local - Mask Common slope +HISTORY_MSG_937;Local - Mask Common curve C(C) +HISTORY_MSG_938;Local - Mask Common curve L(L) +HISTORY_MSG_939;Local - Mask Common curve LC(H) +HISTORY_MSG_940;Local - Mask Common structure as tool +HISTORY_MSG_941;Local - Mask Common structure strength +HISTORY_MSG_942;Local - Mask Common H(H) curve +HISTORY_MSG_943;Local - Mask Common FFT +HISTORY_MSG_944;Local - Mask Common Blur radius +HISTORY_MSG_945;Local - Mask Common contrast threshold +HISTORY_MSG_946;Local - Mask Common shadows +HISTORY_MSG_947;Local - Mask Common Contrast curve +HISTORY_MSG_948;Local - Mask Common Wavelet curve +HISTORY_MSG_949;Local - Mask Common Threshold levels +HISTORY_MSG_950;Local - Mask Common GF strength +HISTORY_MSG_951;Local - Mask Common GF angle +HISTORY_MSG_952;Local - Mask Common soft radius +HISTORY_MSG_953;Local - Mask Common blend chroma +HISTORY_MSG_954;Local - Show-hide tools +HISTORY_MSG_955;Local - Enable Spot +HISTORY_MSG_956;Local - CH Curve +HISTORY_MSG_957;Local - Denoise mode +HISTORY_MSG_958;Local - Show/hide settings +HISTORY_MSG_959;Local - Inverse blur +HISTORY_MSG_960;Local - Log encoding - cat02 +HISTORY_MSG_961;Local - Log encoding Ciecam +HISTORY_MSG_962;Local - Log encoding Absolute luminance source +HISTORY_MSG_963;Local - Log encoding Absolute luminance target +HISTORY_MSG_964;Local - Log encoding Surround +HISTORY_MSG_965;Local - Log encoding Saturation s +HISTORY_MSG_966;Local - Log encoding Contrast J +HISTORY_MSG_967;Local - Log encoding Mask curve C +HISTORY_MSG_968;Local - Log encoding Mask curve L +HISTORY_MSG_969;Local - Log encoding Mask curve H +HISTORY_MSG_970;Local - Log encoding Mask enable +HISTORY_MSG_971;Local - Log encoding Mask blend +HISTORY_MSG_972;Local - Log encoding Mask radius +HISTORY_MSG_973;Local - Log encoding Mask chroma +HISTORY_MSG_974;Local - Log encoding Mask contrast +HISTORY_MSG_975;Local - Log encoding Lightness J +HISTORY_MSG_977;Local - Log encoding Contrast Q +HISTORY_MSG_978;Local - Log encoding Sursource +HISTORY_MSG_979;Local - Log encoding Brightness Q +HISTORY_MSG_980;Local - Log encoding Colorfulness M +HISTORY_MSG_981;Local - Log encoding Strength +HISTORY_MSG_BLSHAPE;Blur by level +HISTORY_MSG_BLURCWAV;Blur chroma +HISTORY_MSG_BLURWAV;Blur luminance +HISTORY_MSG_BLUWAV;Attenuation response HISTORY_MSG_CAT02PRESET;Cat02 automatic preset +HISTORY_MSG_CATCOMPLEX;Ciecam complexity HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction HISTORY_MSG_COLORTONING_LABREGION_AB;CT - Color correction @@ -744,15 +1247,20 @@ 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_COMPLEX;Wavelet complexity +HISTORY_MSG_COMPLEXRETI;Retinex complexity HISTORY_MSG_DEHAZE_DEPTH;Dehaze - Depth HISTORY_MSG_DEHAZE_ENABLED;Haze Removal -HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only +HISTORY_MSG_DEHAZE_SATURATION;Dehaze - Saturation 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_EDGEFFECT;Edge Attenuation response +HISTORY_MSG_FILMNEGATIVE_BALANCE;FN - Reference output +HISTORY_MSG_FILMNEGATIVE_COLORSPACE;Film negative color space HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative -HISTORY_MSG_FILMNEGATIVE_FILMBASE;Film base color +HISTORY_MSG_FILMNEGATIVE_REF_SPOT;FN - Reference input HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values HISTORY_MSG_HISTMATCHING;Auto-matched tone curve HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries @@ -776,11 +1284,21 @@ 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_PERSP_CAM_ANGLE;Perspective - Camera +HISTORY_MSG_PERSP_CAM_FL;Perspective - Camera +HISTORY_MSG_PERSP_CAM_SHIFT;Perspective - Camera +HISTORY_MSG_PERSP_CTRL_LINE;Perspective - Control lines +HISTORY_MSG_PERSP_METHOD;Perspective - Method +HISTORY_MSG_PERSP_PROJ_ANGLE;Perspective - Recovery +HISTORY_MSG_PERSP_PROJ_ROTATE;Perspective - PCA rotation +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_PROTAB;Protection HISTORY_MSG_PRSHARPEN_CONTRAST;PRS - Contrast threshold +HISTORY_MSG_RANGEAB;Range ab HISTORY_MSG_RAWCACORR_AUTOIT;Raw CA Correction - Iterations HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw CA Correction - Avoid color shift HISTORY_MSG_RAW_BORDER;Raw border @@ -788,44 +1306,54 @@ 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_SIGMACOL;Chroma Attenuation response +HISTORY_MSG_SIGMADIR;Dir Attenuation response +HISTORY_MSG_SIGMAFIN;Final contrast Attenuation response +HISTORY_MSG_SIGMATON;Toning Attenuation response HISTORY_MSG_SOFTLIGHT_ENABLED;Soft light HISTORY_MSG_SOFTLIGHT_STRENGTH;Soft light - Strength HISTORY_MSG_SPOT;Spot removal HISTORY_MSG_SPOT_ENTRY;Spot removal - Point modif. HISTORY_MSG_TEMPOUT;CAM02 automatic temperature +HISTORY_MSG_THRESWAV;Balance threshold HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor HISTORY_MSG_TRANS_Method;Geometry - Method HISTORY_MSG_WAVBALCHROM;Equalizer chrominance HISTORY_MSG_WAVBALLUM;Equalizer luminance -HISTORY_MSG_WAVCHROMFI;Chroma fine +HISTORY_MSG_WAVBL;Blur levels HISTORY_MSG_WAVCHROMCO;Chroma coarse +HISTORY_MSG_WAVCHROMFI;Chroma fine HISTORY_MSG_WAVCLARI;Clarity +HISTORY_MSG_WAVDENLH;Level 5 +HISTORY_MSG_WAVDENMET;Local equalizer +HISTORY_MSG_WAVDENOISE;Local contrast +HISTORY_MSG_WAVDENOISEH;High levels Local contrast +HISTORY_MSG_WAVDETEND;Details soft HISTORY_MSG_WAVEDGS;Edge stopping +HISTORY_MSG_WAVGUIDH;Local contrast-Hue equalizer +HISTORY_MSG_WAVHUE;Equalizer hue +HISTORY_MSG_WAVLEVDEN;High level local contrast +HISTORY_MSG_WAVLEVSIGM;Radius +HISTORY_MSG_WAVLIMDEN;Interaction 56 14 +HISTORY_MSG_WAVLOWTHR;Threshold low contrast HISTORY_MSG_WAVMERGEC;Merge C HISTORY_MSG_WAVMERGEL;Merge L -HISTORY_MSG_WAVRADIUS;Radius Shadows-Highlight +HISTORY_MSG_WAVMIXMET;Reference local contrast +HISTORY_MSG_WAVOFFSET;Offset +HISTORY_MSG_WAVOLDSH;Old algorithm +HISTORY_MSG_WAVQUAMET;Denoise mode +HISTORY_MSG_WAVRADIUS;Radius shadows-highlights HISTORY_MSG_WAVSCALE;Scale HISTORY_MSG_WAVSHOWMASK;Show wavelet mask -HISTORY_MSG_WAVSIGMA;Damper +HISTORY_MSG_WAVSIGM;Sigma +HISTORY_MSG_WAVSIGMA;Attenuation response +HISTORY_MSG_WAVSLIMET;Method HISTORY_MSG_WAVSOFTRAD;Soft radius clarity HISTORY_MSG_WAVSOFTRADEND;Soft radius final +HISTORY_MSG_WAVSTREND;Strength soft +HISTORY_MSG_WAVTHRDEN;Threshold local contrast +HISTORY_MSG_WAVTHREND;Threshold local contrast HISTORY_MSG_WAVUSHAMET;Clarity method -HISTORY_MSG_THRESWAV;Balance threshold -HISTORY_MSG_BLUWAV;Damper -HISTORY_MSG_WAVOLDSH;Old algorithm -HISTORY_MSG_WAVOFFSET;Offset -HISTORY_MSG_WAVLOWTHR;Threshold low contrast -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_SIGMAFIN;Final contrast Damper -HISTORY_MSG_SIGMATON;Toning Damper -HISTORY_MSG_SIGMACOL;Chroma Damper -HISTORY_MSG_SIGMADIR;Dir Damper -HISTORY_MSG_RANGEAB;Range ab -HISTORY_MSG_PROTAB;Protection HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -847,7 +1375,7 @@ 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_ILL_TOOLTIP;You can set the illuminant for ICC v4 profiles and also for ICC v2 profiles. ICCPROFCREATOR_PRIMARIES;Primaries: ICCPROFCREATOR_PRIM_ACESP0;ACES AP0 ICCPROFCREATOR_PRIM_ACESP1;ACES AP1 @@ -864,7 +1392,7 @@ 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_TOOLTIP;You can set custom primaries for ICC v4 profiles and also for ICC v2 profiles. ICCPROFCREATOR_PRIM_WIDEG;Widegamut ICCPROFCREATOR_PROF_V2;ICC v2 ICCPROFCREATOR_PROF_V4;ICC v4 @@ -965,6 +1493,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 @@ -1033,7 +1563,7 @@ PARTIALPASTE_EQUALIZER;Wavelet levels PARTIALPASTE_EVERYTHING;Everything PARTIALPASTE_EXIFCHANGES;Exif PARTIALPASTE_EXPOSURE;Exposure -PARTIALPASTE_FILMNEGATIVE;Film Negative +PARTIALPASTE_FILMNEGATIVE;Film negative PARTIALPASTE_FILMSIMULATION;Film simulation PARTIALPASTE_FLATFIELDAUTOSELECT;Flat-field auto-selection PARTIALPASTE_FLATFIELDBLURRADIUS;Flat-field blur radius @@ -1049,6 +1579,9 @@ PARTIALPASTE_LABCURVE;L*a*b* adjustments PARTIALPASTE_LENSGROUP;Lens Related Settings PARTIALPASTE_LENSPROFILE;Profiled lens correction PARTIALPASTE_LOCALCONTRAST;Local contrast +PARTIALPASTE_LOCALLAB;Local Adjustments +PARTIALPASTE_LOCALLABGROUP;Local Adjustments Settings +PARTIALPASTE_LOCGROUP;Local PARTIALPASTE_METADATA;Metadata mode PARTIALPASTE_METAGROUP;Metadata settings PARTIALPASTE_PCVIGNETTE;Vignette filter @@ -1124,6 +1657,10 @@ 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;Advanced +PREFERENCES_COMPLEXITY_NORM;Standard +PREFERENCES_COMPLEXITY_SIMP;Basic PREFERENCES_CROP;Crop Editing PREFERENCES_CROP_AUTO_FIT;Automatically zoom to fit the crop PREFERENCES_CROP_GUIDES;Guides shown when not editing the crop @@ -1172,6 +1709,7 @@ PREFERENCES_HISTOGRAM_TOOLTIP;If enabled, the working profile is used for render PREFERENCES_HLTHRESHOLD;Threshold for clipped highlights PREFERENCES_ICCDIR;Directory containing color profiles PREFERENCES_IMPROCPARAMS;Default Processing Profile +PREFERENCES_INSPECTORWINDOW;Open inspector in own window or fullscreen PREFERENCES_INSPECT_LABEL;Inspect PREFERENCES_INSPECT_MAXBUFFERS_LABEL;Maximum number of cached images PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP;Set the maximum number of images stored in cache when hovering over them in the File Browser; systems with little RAM (2GB) should keep this value set to 1 or 2. @@ -1240,6 +1778,7 @@ PREFERENCES_SHOWBASICEXIF;Show basic Exif info PREFERENCES_SHOWDATETIME;Show date and time PREFERENCES_SHOWEXPOSURECOMPENSATION;Append exposure compensation PREFERENCES_SHOWFILMSTRIPTOOLBAR;Show Filmstrip toolbar +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 @@ -1263,6 +1802,7 @@ PREFERENCES_TP_LABEL;Tool panel: PREFERENCES_TP_VSCROLLBAR;Hide vertical scrollbar PREFERENCES_USEBUNDLEDPROFILES;Use bundled profiles PREFERENCES_WORKFLOW;Layout +PREFERENCES_ZOOMONSCROLL;Zoom images by scrolling PROFILEPANEL_COPYPPASTE;Parameters to copy PROFILEPANEL_GLOBALPROFILES;Bundled profiles PROFILEPANEL_LABEL;Processing Profiles @@ -1354,6 +1894,7 @@ THRESHOLDSELECTOR_TR;Top-right TOOLBAR_TOOLTIP_COLORPICKER;Lockable Color Picker\n\nWhen the tool is active:\n- Add a picker: left-click.\n- Drag a picker: left-click and drag.\n- Delete a picker: right-click.\n- Delete all pickers: Ctrl+Shift+right-click.\n- Revert to hand tool: right-click outside any picker. TOOLBAR_TOOLTIP_CROP;Crop selection.\nShortcut: c\nMove the crop using Shift+mouse drag. TOOLBAR_TOOLTIP_HAND;Hand tool.\nShortcut: h +TOOLBAR_TOOLTIP_PERSPECTIVE;Perspective Correction\n\nEdit control lines to correct perspective distortion. Click this button again to apply correction. TOOLBAR_TOOLTIP_STRAIGHTEN;Straighten / fine rotation.\nShortcut: s\n\nIndicate the vertical or horizontal by drawing a guide line over the image preview. Angle of rotation will be shown next to the guide line. Center of rotation is the geometrical center of the image. TOOLBAR_TOOLTIP_WB;Spot white balance.\nShortcut: w TP_BWMIX_ALGO;Algorithm OYCPM @@ -1430,6 +1971,7 @@ TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotate left.\n\nShortcuts:\n[ - Multiple Ed TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotate right.\n\nShortcuts:\n] - Multiple Editor Tabs Mode,\nAlt-] - Single Editor Tab Mode. TP_COARSETRAF_TOOLTIP_VFLIP;Flip vertically. TP_COLORAPP_ABSOLUTELUMINANCE;Absolute luminance +TP_COLORAPP_ADAPSCEN_TOOLTIP;Corresponds to the luminance in candelas per m2 at the time of shooting, calculated automatically from the exif data. TP_COLORAPP_ALGO;Algorithm TP_COLORAPP_ALGO_ALL;All TP_COLORAPP_ALGO_JC;Lightness + Chroma (JC) @@ -1439,63 +1981,70 @@ TP_COLORAPP_ALGO_TOOLTIP;Lets you choose between parameter subsets or all parame TP_COLORAPP_BADPIXSL;Hot/bad pixel filter TP_COLORAPP_BADPIXSL_TOOLTIP;Suppression of hot/bad (brightly colored) pixels.\n0 = No effect\n1 = Median\n2 = Gaussian.\nAlternatively, adjust the image to avoid very dark shadows.\n\nThese artifacts are due to limitations of CIECAM02. TP_COLORAPP_BRIGHT;Brightness (Q) -TP_COLORAPP_BRIGHT_TOOLTIP;Brightness in CIECAM02 takes into account the white's luminosity and differs from L*a*b* and RGB brightness. +TP_COLORAPP_BRIGHT_TOOLTIP;Brightness in CIECAM02 is the amount of perceived light emanating from a stimulus and differs from L*a*b* and RGB brightness. TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;When setting manually, values above 65 are recommended. TP_COLORAPP_CHROMA;Chroma (C) TP_COLORAPP_CHROMA_M;Colorfulness (M) -TP_COLORAPP_CHROMA_M_TOOLTIP;Colorfulness in CIECAM02 differs from L*a*b* and RGB colorfulness. +TP_COLORAPP_CHROMA_M_TOOLTIP;Colorfulness in CIECAM02 is the perceived amount of hue in relation to gray, an indicator that a stimulus appears to be more or less colored. TP_COLORAPP_CHROMA_S;Saturation (S) -TP_COLORAPP_CHROMA_S_TOOLTIP;Saturation in CIECAM02 differs from L*a*b* and RGB saturation. -TP_COLORAPP_CHROMA_TOOLTIP;Chroma in CIECAM02 differs from L*a*b* and RGB chroma. +TP_COLORAPP_CHROMA_S_TOOLTIP;Saturation in CIECAM02 corresponds to the color of a stimulus in relation to its own brightness, differs from L*a*b* and RGB saturation. +TP_COLORAPP_CHROMA_TOOLTIP;Chroma in CIECAM02 corresponds to the color of a stimulus relative to the clarity of a stimulus that appears white under identical conditions, differs from L*a*b* and RGB chroma. TP_COLORAPP_CIECAT_DEGREE;CAT02 adaptation -TP_COLORAPP_CONTRAST;Contrast (J) +TP_COLORAPP_CONTRAST;Contrast (J), TP_COLORAPP_CONTRAST_Q;Contrast (Q) -TP_COLORAPP_CONTRAST_Q_TOOLTIP;Differs from L*a*b* and RGB contrast. -TP_COLORAPP_CONTRAST_TOOLTIP;Differs from L*a*b* and RGB contrast. +TP_COLORAPP_CONTRAST_Q_TOOLTIP;Contrast (Q) based on brightness, differs from L*a*b* and RGB contrast. +TP_COLORAPP_CONTRAST_TOOLTIP;Contrast (J) based on lightness, differs from L*a*b* and RGB contrast. TP_COLORAPP_CURVEEDITOR1;Tone curve 1 -TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Shows the histogram of L* (L*a*b*) before CIECAM02.\nIf the "Show CIECAM02 output histograms in curves" checkbox is enabled, shows the histogram of J or Q after CIECAM02.\n\nJ and Q are not shown in the main histogram panel.\n\nFor final output refer to the main histogram panel. +TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Shows the histogram of L* (L*a*b*) before CIECAM02.\nIf the "CIECAM02 output histograms in curves" checkbox is enabled, shows the histogram of J or Q after CIECAM02.\n\nJ and Q are not shown in the main histogram panel.\n\nFor final output refer to the main histogram panel. TP_COLORAPP_CURVEEDITOR2;Tone curve 2 TP_COLORAPP_CURVEEDITOR2_TOOLTIP;Same usage as with the second exposure tone curve. TP_COLORAPP_CURVEEDITOR3;Color curve -TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Adjust either chroma, saturation or colorfulness.\n\nShows the histogram of chromaticity (L*a*b*) before CIECAM02.\nIf the "Show CIECAM02 output histograms in curves" checkbox is enabled, shows the histogram of C, s or M after CIECAM02.\n\nC, s and M are not shown in the main histogram panel.\nFor final output refer to the main histogram panel. +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Adjust either chroma, saturation or colorfulness.\n\nShows the histogram of chromaticity (L*a*b*) before CIECAM02.\nIf the "CIECAM02 output histograms in curves" checkbox is enabled, shows the histogram of C, S or M after CIECAM02.\n\nC, S and M are not shown in the main histogram panel.\nFor final output refer to the main histogram panel. TP_COLORAPP_DATACIE;CIECAM02 output histograms in curves TP_COLORAPP_DATACIE_TOOLTIP;When enabled, histograms in CIECAM02 curves show approximate values/ranges for J or Q, and C, s or M after the CIECAM02 adjustments.\nThis selection does not impact the main histogram panel.\n\nWhen disabled, histograms in CIECAM02 curves show L*a*b* values before CIECAM02 adjustments. +TP_COLORAPP_DEGREE_TOOLTIP;CAT02 is a chromatic adaptation, it converts the values of an image whose white point is that of a given illuminant (for example D65), into new values whose white point is that of the new illuminant - see WP Model (for example D50 or D55). +TP_COLORAPP_DEGREOUT_TOOLTIP;CAT02 is a chromatic adaptation, it converts the values of an image whose white point is that of a given illuminant (for example D50), into new values whose white point is that of the new illuminant - see WP model (for example D75). TP_COLORAPP_FREE;Free temp+green + CAT02 + [output] TP_COLORAPP_GAMUT;Gamut control (L*a*b*) TP_COLORAPP_GAMUT_TOOLTIP;Allow gamut control in L*a*b* mode. +TP_COLORAPP_GEN;Settings - Preset +TP_COLORAPP_GEN_TOOLTIP;This module is based on the CIECAM02 color appearance model, which was designed to better simulate how human vision perceives colors under different lighting conditions, e.g., against different backgrounds.\nIt takes into account the environment of each color and modifies its appearance to get as close as possible to human perception.\nIt also adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic appearance is preserved across the scene and display environments. TP_COLORAPP_HUE;Hue (h) -TP_COLORAPP_HUE_TOOLTIP;Hue (h) - angle between 0° and 360°. -TP_COLORAPP_ILLUM;Illuminant -TP_COLORAPP_ILLUM_TOOLTIP;Select the illuminant closest to the shooting conditions.\nIn general D50, but it can change depending on the time and lattitude. -TP_COLORAPP_ILA;Incandescent StdA 2856K +TP_COLORAPP_HUE_TOOLTIP;Hue (h) is the degree to which a stimulus can be described as similar to a color described as red, green, blue and yellow. 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;Incandescent StdA 2856K TP_COLORAPP_ILFREE;Free -TP_COLORAPP_LABEL;CIE Color Appearance Model 2002 +TP_COLORAPP_ILLUM;Illuminant +TP_COLORAPP_ILLUM_TOOLTIP;Select the illuminant closest to the shooting conditions.\nIn general D50, but it can change depending on the time and lattitude. +TP_COLORAPP_LABEL;Color Appearance & Lighting (CIECAM02) TP_COLORAPP_LABEL_CAM02;Image Adjustments TP_COLORAPP_LABEL_SCENE;Scene Conditions TP_COLORAPP_LABEL_VIEWING;Viewing Conditions TP_COLORAPP_LIGHT;Lightness (J) -TP_COLORAPP_LIGHT_TOOLTIP;Lightness in CIECAM02 differs from L*a*b* and RGB lightness. +TP_COLORAPP_LIGHT_TOOLTIP;Lightness in CIECAM02 is the clarity of a stimulus relative to the clarity of a stimulus that appears white under similar viewing conditions, differs from L*a*b* and RGB lightness. TP_COLORAPP_MEANLUMINANCE;Mean luminance (Yb%) TP_COLORAPP_MODEL;WP Model TP_COLORAPP_MODEL_TOOLTIP;White-Point Model.\n\nWB [RT] + [output]: RT's white balance is used for the scene, CIECAM02 is set to D50, and the output device's white balance is set in Viewing Conditions.\n\nWB [RT+CAT02] + [output]: RT's white balance settings are used by CAT02 and the output device's white balance is set in Viewing Conditions.\n\nFree temp+green + CAT02 + [output]: temp and green are selected by the user, the output device's white balance is set in Viewing Conditions. TP_COLORAPP_NEUTRAL;Reset TP_COLORAPP_NEUTRAL_TIP;Reset all sliders checkbox and curves to their default values -TP_COLORAPP_PRESETCAT02;Preset cat02 automatic -TP_COLORAPP_PRESETCAT02_TIP;Set combobox, sliders, temp, green so that Cat02 automatic is preset.\nYou can change illuminant shooting conditions.\nYou must change Cat02 adaptation Viewing conditions if need.\nYou can change Temperature and Tint Viewing conditions if need, and other settings if need. +TP_COLORAPP_PRESETCAT02;Preset cat02 automatic - Symetric mode +TP_COLORAPP_PRESETCAT02_TIP;Set combobox, sliders, temp, green so that Cat02 automatic is preset.\nYou can change illuminant shooting conditions.\nYou must change Cat02 adaptation Viewing conditions if needed.\nYou can change Temperature and Tint Viewing conditions if needed, and other settings if needed. TP_COLORAPP_RSTPRO;Red & skin-tones protection TP_COLORAPP_RSTPRO_TOOLTIP;Red & skin-tones protection affects both sliders and curves. +TP_COLORAPP_SOURCEF_TOOLTIP;Corresponds to the shooting conditions and how to bring the conditions and data back to a "normal" area. Normal" means average or standard conditions and data, i.e. without taking into account CIECAM corrections. TP_COLORAPP_SURROUND;Surround +TP_COLORAPP_SURROUNDSRC;Surround - Scene Lighting TP_COLORAPP_SURROUND_AVER;Average TP_COLORAPP_SURROUND_DARK;Dark TP_COLORAPP_SURROUND_DIM;Dim TP_COLORAPP_SURROUND_EXDARK;Extremly Dark (Cutsheet) TP_COLORAPP_SURROUND_TOOLTIP;Changes tones and colors to take into account the viewing conditions of the output device.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment (TV). The image will become slightly dark.\n\nDark: Dark environment (projector). The image will become more dark.\n\nExtremly Dark: Extremly dark environment (cutsheet). The image will become very dark. +TP_COLORAPP_SURSOURCE_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment. The image will become slightly bright.\n\nDark: Dark environment. The image will become more bright.\n\nExtremly Dark: Extremly dark environment. The image will become very bright. TP_COLORAPP_TCMODE_BRIGHTNESS;Brightness TP_COLORAPP_TCMODE_CHROMA;Chroma TP_COLORAPP_TCMODE_COLORF;Colorfulness @@ -1504,14 +2053,17 @@ TP_COLORAPP_TCMODE_LABEL2;Curve mode 2 TP_COLORAPP_TCMODE_LABEL3;Curve chroma mode 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_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_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_VIEWINGF_TOOLTIP;Takes into account the support on which the final image will be viewed (monitor, TV, projector, printer, ...), as well as its environment. This process will take the data coming from process "Image Adjustments" and "bring" it to the support in such a way that the viewing conditions and its environment are taken into account. TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP;Absolute luminance of the viewing environment\n(usually 16 cd/m²). TP_COLORAPP_WBCAM;WB [RT+CAT02] + [output] TP_COLORAPP_WBRT;WB [RT] + [output] +TP_COLORAPP_YBOUT_TOOLTIP;Yb is the relative luminance of the background, expressed in % of gray. A gray at 18% corresponds to a background luminance expressed in CIE L of 50%.\nThis data must take into account the average luminance of the image +TP_COLORAPP_YBSCEN_TOOLTIP;Yb is the relative luminance of the background, expressed in % of gray. A gray at 18% corresponds to a background luminance expressed in CIE L of 50%.\nThis data is calculated from the average luminance of the image TP_COLORTONING_AB;o C/L TP_COLORTONING_AUTOSAT;Automatic TP_COLORTONING_BALANCE;Balance @@ -1595,7 +2147,7 @@ TP_DEFRINGE_RADIUS;Radius TP_DEFRINGE_THRESHOLD;Threshold TP_DEHAZE_DEPTH;Depth TP_DEHAZE_LABEL;Haze Removal -TP_DEHAZE_LUMINANCE;Luminance only +TP_DEHAZE_SATURATION;Saturation TP_DEHAZE_SHOW_DEPTH_MAP;Show depth map TP_DEHAZE_STRENGTH;Strength TP_DIRPYRDENOISE_CHROMINANCE_AMZ;Auto multi-zones @@ -1705,12 +2257,19 @@ TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points TP_EXPOS_WHITEPOINT_LABEL;Raw White Points TP_FILMNEGATIVE_BLUE;Blue ratio -TP_FILMNEGATIVE_FILMBASE_PICK;Pick film base color -TP_FILMNEGATIVE_FILMBASE_TOOLTIP;Pick a spot of unexposed film (eg. the border between frames), to get the actual film base color values, and save them in the processing profile.\nThis makes it easy to get a more consistent color balance when batch-processing multiple pictures from the same roll.\nAlso use this when the converted image is extremely dark, bright, or color-unbalanced. -TP_FILMNEGATIVE_FILMBASE_VALUES;Film base RGB: -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_BLUEBALANCE;Cool/Warm +TP_FILMNEGATIVE_COLORSPACE;Inversion color space: +TP_FILMNEGATIVE_COLORSPACE_INPUT;Input color space +TP_FILMNEGATIVE_COLORSPACE_TOOLTIP;Select the color space used to perform the negative inversion:\nInput color space : perform inversion before the input profile is applied, as in the previous versions of RT.\nWorking color space : perform inversion after input profile, using the currently selected working profile. +TP_FILMNEGATIVE_COLORSPACE_WORKING;Working color space +TP_FILMNEGATIVE_REF_LABEL;Input RGB: %1 +TP_FILMNEGATIVE_REF_PICK;Pick white balance spot +TP_FILMNEGATIVE_REF_TOOLTIP;Pick a gray patch for white-balancing the output, positive image. +TP_FILMNEGATIVE_GREEN;Reference exponent +TP_FILMNEGATIVE_GREENBALANCE;Magenta/Green +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. TP_FILMNEGATIVE_LABEL;Film Negative +TP_FILMNEGATIVE_OUT_LEVEL;Output level TP_FILMNEGATIVE_PICK;Pick neutral spots TP_FILMNEGATIVE_RED;Red ratio TP_FILMSIMULATION_LABEL;Film Simulation @@ -1850,6 +2409,669 @@ TP_LOCALCONTRAST_DARKNESS;Darkness level TP_LOCALCONTRAST_LABEL;Local Contrast TP_LOCALCONTRAST_LIGHTNESS;Lightness level TP_LOCALCONTRAST_RADIUS;Radius +TP_LOCALLAB_ACTIV;Luminance only +TP_LOCALLAB_ACTIVSPOT;Enable Spot +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;ΔE scope threshold increases the range of deltaE scope. High values are for very wide gamut images.\nIncreasing deltaE decay can improve shape detection, but can also reduce the scope. +TP_LOCALLAB_AUTOGRAY;Auto mean luminance (Yb%) +TP_LOCALLAB_AVOID;Avoid color shift +TP_LOCALLAB_BALAN;ab-L balance (ΔE) +TP_LOCALLAB_BALANEXP;Laplacian balance +TP_LOCALLAB_BALANH;C-H balance (ΔE) +TP_LOCALLAB_BALAN_TOOLTIP;Changes the ΔE algorithm parameters.\nTakes into account more or less a*b* or L*, or more or less C or H.\nNot for Denoise +TP_LOCALLAB_BASELOG;Shadows range (logarithm base) +TP_LOCALLAB_BILATERAL;Bilateral filter +TP_LOCALLAB_BLACK_EV;Black Ev +TP_LOCALLAB_BLCO;Chrominance only +TP_LOCALLAB_BLENDMASKCOL;Blend +TP_LOCALLAB_BLENDMASKMASK;Add/subtract luminance mask +TP_LOCALLAB_BLENDMASKMASKAB;Add/subtract chrominance mask +TP_LOCALLAB_BLENDMASKMASK_TOOLTIP;If this slider = 0 no action.\nAdd or subtract the mask from the original image +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_BLLC;Luminance & Chrominance +TP_LOCALLAB_BLLO;Luminance only +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_BLNOI_EXP;Blur & Noise +TP_LOCALLAB_BLNORM;Normal +TP_LOCALLAB_BLSYM;Symmetric +TP_LOCALLAB_BLUFR;Blur/Grain & Denoise +TP_LOCALLAB_BLUMETHOD_TOOLTIP;To blur the background and isolate the foreground:\n-blur the background by completely covering the image with an an RT-spot (high values for scope and transition and ‘Normal’ or ‘Inverse’ in checkbox).\n-Isolate the foreground by using one or more ‘Excluding’ RT-spot(s) and increase the scope.\n\nThis module (including the "median" and "Guided filter") can be used in addition to the main-menu noise reduction. +TP_LOCALLAB_BLUR;Gaussian Blur - Noise - Grain +TP_LOCALLAB_BLURCBDL;Blur levels 0-1-2-3-4 +TP_LOCALLAB_BLURCOL;Radius +TP_LOCALLAB_BLURCOLDE_TOOLTIP;The image used to calculate dE is blurred slightly to avoid taking isolated pixels into account. +TP_LOCALLAB_BLURDE;Blur shape detection +TP_LOCALLAB_BLURLC;Luminance only +TP_LOCALLAB_BLURLEVELFRA;Blur levels +TP_LOCALLAB_BLURMASK_TOOLTIP;Uses a large-radius blur to create a mask that allows you to vary the contrast of the image and/or darken/lighten parts of it. +TP_LOCALLAB_BLURRESIDFRA;Blur Residual +TP_LOCALLAB_BLURRMASK_TOOLTIP;Allows you to vary the "radius" of the Gaussian blur (0 to 1000) +TP_LOCALLAB_BLUR_TOOLNAME;Blur/Grain & Denoise - 1 +TP_LOCALLAB_BLWH;All changes forced in Black-and-White +TP_LOCALLAB_BLWH_TOOLTIP;Force color components "a" and "b" to zero.\nUseful for black and white processing, or film simulation. +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_CATAD;Chromatic adaptation - Cat02 +TP_LOCALLAB_CBDL;Contrast by Detail Levels +TP_LOCALLAB_CBDLCLARI_TOOLTIP;Enhances local contrast of the midtones. +TP_LOCALLAB_CBDL_ADJ_TOOLTIP;Same as wavelets.\nThe first level (0) acts on 2x2 pixel details.\nThe last level (5) acts on 64x64 pixel details. +TP_LOCALLAB_CBDL_THRES_TOOLTIP;Prevents the sharpening of noise +TP_LOCALLAB_CBDL_TOOLNAME;CBDL - 2 +TP_LOCALLAB_CENTER_X;Center X +TP_LOCALLAB_CENTER_Y;Center Y +TP_LOCALLAB_CH;Curves CL - LC +TP_LOCALLAB_CHROMA;Chrominance +TP_LOCALLAB_CHROMABLU;Chroma levels +TP_LOCALLAB_CHROMABLU_TOOLTIP;Increases or reduces the effect depending on the luma settings.\nValues under 1 reduce the effect. Values greater than 1 increase the effect. +TP_LOCALLAB_CHROMACBDL;Chroma +TP_LOCALLAB_CHROMACB_TOOLTIP;Increases or reduces the effect depending on the luma settings.\nValues under 1 reduce the effect. Values greater than 1 increase the effect. +TP_LOCALLAB_CHROMALEV;Chroma levels +TP_LOCALLAB_CHROMASKCOL;Chroma +TP_LOCALLAB_CHROMASK_TOOLTIP;Changes the chroma of the mask if one exists (i.e. C(C) or LC(H) is activated). +TP_LOCALLAB_CHRRT;Chroma +TP_LOCALLAB_CIEC;Use Ciecam environment parameters +TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM02 color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nThe first Ciecam process 'Scene conditions' is carried out by Log encoding, it also uses 'Absolute luminance' at the time of shooting.\nThe second Ciecam process 'Image adjustments' is simplified and uses only 3 variables (local contrast, contrast J, saturation s).\nThe third Ciecam process 'Viewing conditions' adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. +TP_LOCALLAB_CIRCRADIUS;Spot size +TP_LOCALLAB_CIRCRAD_TOOLTIP;Contains the references of the 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 & Soften Images +TP_LOCALLAB_CLARILRES;Merge luma +TP_LOCALLAB_CLARISOFT;Soft radius +TP_LOCALLAB_CLARISOFT_TOOLTIP;The "Soft radius" slider (guided filter algorithm) reduces halos and irregularities for both Clarity and Sharp Mask and for all pyramid wavelet processes. To deactivate, set slider to zero. +TP_LOCALLAB_CLARITYML;Clarity +TP_LOCALLAB_CLARI_TOOLTIP;Levels 0 to 4 (included): ‘Sharp mask’ is enabled\nLevels 5 and above: 'Clarity' is enabled.\nUseful if you use 'Wavelet level tone mapping' +TP_LOCALLAB_CLIPTM;Clip restored data (gain) +TP_LOCALLAB_COFR;Color & Light +TP_LOCALLAB_COLORDE;ΔE preview color - intensity +TP_LOCALLAB_COLORDEPREV_TOOLTIP;Preview ΔE button will only work if you have activated one (and only one) of the tools in "Add tool to current spot" menu.\nTo be able to preview ΔE with several tools enabled, use Mask and modifications - Preview ΔE +TP_LOCALLAB_COLORDE_TOOLTIP;Show a blue color-preview for ΔE selection if negative and green if positive.\n\nMask and modifications (show modified areas without mask): show actual modifications if positive, show enhanced modifications (luminance only) with blue and yellow if negative. +TP_LOCALLAB_COLORSCOPE;Scope (color tools) +TP_LOCALLAB_COLORSCOPE_TOOLTIP;Common Scope slider for Color and Light, Shadows/Highlights, Vibrance.\nOther tools have their own scope controls. +TP_LOCALLAB_COLOR_TOOLNAME;Color & Light - 11 +TP_LOCALLAB_COL_NAME;Name +TP_LOCALLAB_COL_VIS;Status +TP_LOCALLAB_COMPFRA;Directional contrast +TP_LOCALLAB_COMPFRAME_TOOLTIP;Allows special effects. You can reduce artifacts with 'Clarity & Sharp mask - Blend & Soften 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_COMPREFRA;Wavelet level tone mapping +TP_LOCALLAB_COMPRESS_TOOLTIP;Use if necessary the module 'Clarity & Sharp mask and Blend & Soften Images' by adjusting 'Soft radius' to reduce artifacts. +TP_LOCALLAB_CONTCOL;Contrast threshold +TP_LOCALLAB_CONTFRA;Contrast by level +TP_LOCALLAB_CONTL;Contrast (J) +TP_LOCALLAB_CONTRAST;Contrast +TP_LOCALLAB_CONTRASTCURVMASK1_TOOLTIP;Allows you to freely modify the contrast of the mask (gamma & slope), instead of using a continuous & progressive curve. However it can create artifacts that have to be dealt with using the “Smooth radius” or “Laplacian threshold sliders”. +TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP;Allows you to freely change the contrast of the mask. May create artifacts. +TP_LOCALLAB_CONTRESID;Contrast +TP_LOCALLAB_CONTTHMASK_TOOLTIP;Allows you to determine which parts of the image will be impacted based on the texture. +TP_LOCALLAB_CONTTHR;Contrast Threshold +TP_LOCALLAB_CONTWFRA;Local contrast +TP_LOCALLAB_CSTHRESHOLD;Ψ Wavelet levels +TP_LOCALLAB_CSTHRESHOLDBLUR;Ψ Wavelet level selection +TP_LOCALLAB_CURV;Lightness - Contrast - Chrominance "Super" +TP_LOCALLAB_CURVCURR;Normal +TP_LOCALLAB_CURVEEDITORM_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\nThe gray transition line which represents the references (chroma, luma, hue).\nYou can choose or not to position the top of the curves on this transition. +TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP;If curves are at the top, the mask is completely black and no changes are made to the image.\nAs you lower the curve, the mask gradually becomes more colorful and bright, progressively changing the image.\n\nIt is recommended (but not mandatory) to position the top of the curves on the gray boundary line which represents the reference values of chroma, luma, hue for the RT-spot. +TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP;To activate the curves, set the ‘Curve type’ combobox to ‘Normal’ +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) uses the same algorithm as the lightness slider. +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_DEHAZFRAME_TOOLTIP;Removes atmospheric haze. Increases overall saturation and detail.\nCan remove color casts, but may also introduce a blue cast which can be corrected with other tools. +TP_LOCALLAB_DEHAZ_TOOLTIP;Negative values add haze +TP_LOCALLAB_DELTAD;Delta balance +TP_LOCALLAB_DELTAEC;ΔE Image mask +TP_LOCALLAB_DENOIBILAT_TOOLTIP;Allows you to reduce impulse or ‘salt & pepper’ noise. +TP_LOCALLAB_DENOICHROC_TOOLTIP;Allows you to deal with blotches and packets of noise. +TP_LOCALLAB_DENOICHRODET_TOOLTIP;Allows you to recover chrominance detail by progressively applying a Fourier transform (DCT). +TP_LOCALLAB_DENOICHROF_TOOLTIP;Allows you to adjust fine-detail chrominance noise +TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP;Allows you to direct the chroma noise reduction towards either the blue-yellow or red-green colors. +TP_LOCALLAB_DENOIEQUAL_TOOLTIP;Allows you to carry out more or less noise reduction in either the shadows or the highlights. +TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;Allows you to recover luminance detail by progressively applying a Fourier transform (DCT). +TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. “Aggressive” mode removes low frequency detail. +TP_LOCALLAB_DENOIS;Ψ Denoise +TP_LOCALLAB_DENOITHR_TOOLTIP;Adjusts edge detection to help reduce noise in uniform, low-contrast areas. +TP_LOCALLAB_DENOI_EXP;Denoise +TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (deltaE).\n\n You can refine the result with a "Median filter" or a "Guided Filter" (Soft radius). +TP_LOCALLAB_DEPTH;Depth +TP_LOCALLAB_DETAIL;Local contrast +TP_LOCALLAB_DETAILSH;Details +TP_LOCALLAB_DETAILTHR;Luminance & chroma detail threshold (DCT ƒ) +TP_LOCALLAB_DUPLSPOTNAME;Copy +TP_LOCALLAB_EDGFRA;Edge sharpness +TP_LOCALLAB_EDGSHOW;Show all tools +TP_LOCALLAB_ELI;Ellipse +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 so that the mean and variance of the output image are identical to those 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;‘Excluding’ mode prevents adjacent spots from influencing certain parts of the image. Adjusting ‘Scope’ will extend the range of colors.\n You can also add tools to an Excluding spot and use them in the same way as for a normal spot. +TP_LOCALLAB_EXCLUTYPE;Spot method +TP_LOCALLAB_EXCLUTYPE_TOOLTIP;Normal spot uses recursive data.\n\nExcluding spot reinitializes all local adjustment data.\nCan be used to totally or partially cancel a previous action or to carry out operations in Inverse mode +TP_LOCALLAB_EXECLU;Excluding spot +TP_LOCALLAB_EXNORM;Normal spot +TP_LOCALLAB_EXPCBDL_TOOLTIP;Can be used to remove marks on the sensor or lens by reducing the contrast on the appropriate detail level(s). +TP_LOCALLAB_EXPCHROMA;Chroma compensation +TP_LOCALLAB_EXPCHROMA_TOOLTIP;Use in association with ‘Exposure compensation f’ and ‘Contrast Attenuator f’ to avoid desaturating colors. +TP_LOCALLAB_EXPCOLOR_TOOLTIP;Adjust color, lightness, contrast and correct small defects such as red-eye, sensor dust etc. +TP_LOCALLAB_EXPCOMP;Exposure compensation ƒ +TP_LOCALLAB_EXPCOMPINV;Exposure compensation +TP_LOCALLAB_EXPCOMP_TOOLTIP;For portraits or images with a low color gradient. You can change "Shape detection" in "Settings":\n\nIncrease 'ΔE scope threshold'\nReduce 'ΔE decay'\nIncrease 'ab-L balance (ΔE)’ +TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;See the documentation for Wavelet Levels.\nThere are some differences in the Locallab version: more tools and more possibilities for working on individual detail levels.\ne.g. Wavelet-level tone mapping. +TP_LOCALLAB_EXPCONTRAST_TOOLTIP;Avoid spots that are too small ( < 32x32 pixels).\nUse low ‘Transition value’ and high ‘Transition decay’ and ‘Scope’ to simulate small RT-spots and deal wth defects.\nUse 'Clarity & Sharp mask and Blend & Soften Images' if necessary by adjusting 'Soft radius' to reduce artifacts. +TP_LOCALLAB_EXPCURV;Curves +TP_LOCALLAB_EXPGRAD;Graduated Filter +TP_LOCALLAB_EXPGRADCOL_TOOLTIP;A graduated filter is available in Color and Light (luminance, chrominance & hue gradients, and "Merge file") Exposure (luminance grad.), Exposure Mask (luminance grad.), Shadows/Highlights (luminance grad.), Vibrance (luminance, chrominance & hue gradients), Local contrast & wavelet pyramid (local contrast grad.).\nFeather is located in Settings. +TP_LOCALLAB_EXPLAPBAL_TOOLTIP;Changes the transformed/original image blend +TP_LOCALLAB_EXPLAPGAMM_TOOLTIP;Changes the behaviour for images with too much or too little contrast by adding a gamma curve before and after the Laplace transform +TP_LOCALLAB_EXPLAPLIN_TOOLTIP;Changes the behaviour for underexposed images by adding a linear component prior to applying the Laplace transform +TP_LOCALLAB_EXPLAP_TOOLTIP;Moving the slider to the right progressively reduces the contrast. +TP_LOCALLAB_EXPMERGEFILE_TOOLTIP;Allows you to use GIMP or Photoshop (c) layer blend modes i.e. Difference, Multiply, Soft Light, Overlay etc., with opacity control.\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 (fewer possibilties) +TP_LOCALLAB_EXPMETHOD_TOOLTIP;Standard : use an algorithm similar as main Exposure but in L*a*b* and taking account of deltaE.\n\nContrast attenuator : use another algorithm also with deltaE and with Poisson equation to solve Laplacian in Fourier space.\nContrast attenuator, Dynamic range compression and Standard can be combined.\nFFTW Fourier Transform is optimized in size to reduce processing time.\nReduce artifacts and noise. +TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP;Applies a median filter before the Laplace transform to prevent artifacts (noise).\nYou can also use the "Denoise" tool. +TP_LOCALLAB_EXPOSE;Dynamic Range & Exposure +TP_LOCALLAB_EXPOSURE_TOOLTIP;Modify exposure in L*a*b space using Laplacian PDE algorithms to take into account dE and minimize artifacts. +TP_LOCALLAB_EXPRETITOOLS;Advanced Retinex Tools +TP_LOCALLAB_EXPSHARP_TOOLTIP;RT-Spot minimum 39*39.\nUse low transition values and high ‘Transition decay’ and ‘Scope’ values to simulate smaller RT-spots. +TP_LOCALLAB_EXPTOOL;Exposure Tools +TP_LOCALLAB_EXPTRC;Tone Response Curve - TRC +TP_LOCALLAB_EXP_TOOLNAME;Dynamic Range & Exposure - 10 +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 – uses the 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 as a percentage of the Spot diagonal\nUsed by all graduated filters in all tools.\nNo action if a graduated filter hasn’t been activated. +TP_LOCALLAB_FEATVALUE;Feather gradient (Graduated Filters) +TP_LOCALLAB_FFTCOL_MASK;FFTW ƒ +TP_LOCALLAB_FFTMASK_TOOLTIP;Use a Fourier transform for better quality (increased processing time and memory requirements) +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;Dark-Ev & white-Ev for the whole image +TP_LOCALLAB_FULLIMAGELOG_TOOLTIP;Calculates the Ev levels for the whole image. +TP_LOCALLAB_GAM;Gamma +TP_LOCALLAB_GAMFRA;Tone response curve (TRC) +TP_LOCALLAB_GAMM;Gamma +TP_LOCALLAB_GAMMASKCOL;Gamma +TP_LOCALLAB_GAMMASK_TOOLTIP;Gamma and Slope allow a soft and artifact-free transformation of the mask by progressively modifying “L” to avoid any discontinuities. +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;Adjusts luminance gradient strength +TP_LOCALLAB_GRADLOGFRA;Graduated Filter Luminance +TP_LOCALLAB_GRADSTR;Gradient strength +TP_LOCALLAB_GRADSTRAB_TOOLTIP;Adjusts chroma gradient strength +TP_LOCALLAB_GRADSTRCHRO;Chrominance gradient strength +TP_LOCALLAB_GRADSTRHUE;Hue gradient strength +TP_LOCALLAB_GRADSTRHUE2;Hue gradient strength +TP_LOCALLAB_GRADSTRHUE_TOOLTIP;Adjusts hue gradient strength +TP_LOCALLAB_GRADSTRLUM;Luminance gradient strength +TP_LOCALLAB_GRADSTR_TOOLTIP;Filter strength in stops +TP_LOCALLAB_GRAINFRA;Film Grain 1:1 +TP_LOCALLAB_GRAIN_TOOLTIP;Adds film-like grain to the image +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 decay\nOnly mode NORMAL and eventually Hue, Saturation, Color, Luminosity are concerned by Merge background (ΔE) +TP_LOCALLAB_GRIDMETH_TOOLTIP;Color toning: the luminance is taken into account when varying chroma. Equivalent to H=f(H) if the "white dot" on the grid remains at zero and you only vary the "black dot". Equivalent to "Color toning" if you vary the 2 dots.\n\nDirect: acts directly on the chroma +TP_LOCALLAB_GRIDONE;Color Toning +TP_LOCALLAB_GRIDTWO;Direct +TP_LOCALLAB_GUIDBL;Soft radius +TP_LOCALLAB_GUIDBL_TOOLTIP;Applies a guided filter with adjustable radius. Allows you to reduce artifacts or blur the image. +TP_LOCALLAB_GUIDEPSBL_TOOLTIP;Changes the distribution function of the guided filter. Negative values simulate a Gaussian blur. +TP_LOCALLAB_GUIDFILTER;Guided filter radius +TP_LOCALLAB_GUIDFILTER_TOOLTIP;Can reduce or increase artifacts. +TP_LOCALLAB_GUIDSTRBL_TOOLTIP;Intensity of the guided filter +TP_LOCALLAB_HHMASK_TOOLTIP;Fine hue adjustments for example for the skin. +TP_LOCALLAB_HIGHMASKCOL;Highlights +TP_LOCALLAB_HLH;Curves H +TP_LOCALLAB_IND;Independent (mouse) +TP_LOCALLAB_INDSL;Independent (mouse + sliders) +TP_LOCALLAB_INVBL;Inverse +TP_LOCALLAB_INVBL_TOOLTIP;Alternative to ‘Inverse’ mode: use two spots\nFirst Spot:\n full image - delimiter outside preview\n RT-spot shape: rectangle. Transition 100\n\nSecond spot : Excluding spot +TP_LOCALLAB_INVERS;Inverse +TP_LOCALLAB_INVERS_TOOLTIP;Fewer possibilities if selected (Inverse).\n\nAlternative: use two spots\nFirst Spot:\n full image - delimiter outside preview\n RT-spot shape: rectangle. Transition 100\n\nSecond spot: Excluding spot +TP_LOCALLAB_ISOGR;Coarseness (ISO) +TP_LOCALLAB_LABBLURM;Blur Mask +TP_LOCALLAB_LABEL;Local Adjustments +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;Structure Mask +TP_LOCALLAB_LAPLACC;ΔØ Mask Laplacian solve PDE +TP_LOCALLAB_LAPLACE;Laplacian threshold ΔE +TP_LOCALLAB_LAPLACEXP;Laplacian threshold +TP_LOCALLAB_LAPMASKCOL;Laplacian threshold +TP_LOCALLAB_LAPRAD1_TOOLTIP;Avoid using “Smooth radius” and “Laplacian threshold” (advanced) together.\nTransforms the mask to eliminate values lower than the threshold.\nReduces artifacts and noise, and allows local contrast to be modified. +TP_LOCALLAB_LAPRAD2_TOOLTIP;Smooth radius uses a guided filter to decrease artifacts and smooth out the transition +TP_LOCALLAB_LAPRAD_TOOLTIP;Avoid using “Smooth radius” and “Laplacian threshold” (advanced) together.\nSmooth radius uses a guided filter to decrease artifacts and smooth out the transition +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_LC_FFTW_TOOLTIP;FFT improves quality and allows the use of large radii, but increases processing time (depends on the area to be processed). Preferable to use only for large radii. The size of the area can be reduced by a few pixels to optimize the FFTW. This can reduce the processing time by a factor of 1.5 to 10. +TP_LOCALLAB_LC_TOOLNAME;Local Contrast & Wavelets - 7 +TP_LOCALLAB_LEVELBLUR;Maximum blur levels +TP_LOCALLAB_LEVELWAV;Ψ Wavelet 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_LEVFRA;Levels +TP_LOCALLAB_LIGHTNESS;Lightness +TP_LOCALLAB_LIGHTN_TOOLTIP;In inverse mode: selection = -100 forces luminance to zero +TP_LOCALLAB_LIGHTRETI;Lightness +TP_LOCALLAB_LINEAR;Linearity +TP_LOCALLAB_LIST_NAME;Add tool to current spot... +TP_LOCALLAB_LIST_TOOLTIP;You can select 3 levels of complexity for each tool: Basic, Standard & Advanced.\nThe default setting for all tools is Basic but this can be changed in the Preferences window.\nYou can also change the level of complexity on a per-tool basis while you are editing +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;Allows you to freely change the contrast of the mask. May create artifacts. +TP_LOCALLAB_LOCCONT;Unsharp Mask +TP_LOCALLAB_LOC_CONTRAST;Local Contrast & Wavelets +TP_LOCALLAB_LOC_CONTRASTPYR;Ψ Pyramid 1: +TP_LOCALLAB_LOC_CONTRASTPYR2;Ψ Pyramid 2: +TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contrast by level- Tone Mapping - Dir.Contrast +TP_LOCALLAB_LOC_CONTRASTPYRLAB; Graduated Filter - Edge Sharpness - Blur +TP_LOCALLAB_LOC_RESIDPYR;Residual image (Main) +TP_LOCALLAB_LOG;Log Encoding +TP_LOCALLAB_LOG1FRA;Image Adjustments +TP_LOCALLAB_LOG2FRA;Viewing Conditions +TP_LOCALLAB_LOGAUTO;Automatic +TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;Automatically calculates the 'mean luminance' for the scene conditons when the ‘Automatic’ button in Relative Exposure Levels is pressed. +TP_LOCALLAB_LOGAUTO_TOOLTIP;Pressing this button will calculate the 'dynamic range' and 'mean luminance' for the scene conditions if the "Auto mean luminance (Yb%)” is checked).\nAlso calculates the absolute luminance at the time of shooting.\nPress the button again to adjust the automatically calculated values. +TP_LOCALLAB_LOGBASE_TOOLTIP;Default = 2.\nValues less than 2 reduce the action of the algorithm making the shadows darker and the highlights brighter.\nWith values greater than 2, the shadows are grayer and the highlights become more washed out. +TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP;Estimated values of Dynamic Range i.e. Black Ev and White Ev +TP_LOCALLAB_LOGCATAD_TOOLTIP;The chromatic adaptation allows us to interpret a color according to its spatio-temporal environment.\nUseful when the white balance is far from reference D50.\nAdapts colors to the illuminant of the output device. +TP_LOCALLAB_LOGCOLORFL;Colorfulness (M) +TP_LOCALLAB_LOGCOLORF_TOOLTIP;Perceived amount of hue in relation to gray.\nIndicator that a stimulus appears more or less colored. +TP_LOCALLAB_LOGCONQL;Contrast (Q) +TP_LOCALLAB_LOGCONTL;Contrast (J) +TP_LOCALLAB_LOGCONTL_TOOLTIP;Contrast (J) in CIECAM02 takes into account the increase in perceived coloration with luminance. +TP_LOCALLAB_LOGCONTQ_TOOLTIP;Contrast (Q) in CIECAM02 takes into account the increase in perceived coloration with brightness. +TP_LOCALLAB_LOGDETAIL_TOOLTIP;Acts mainly on high frequencies. +TP_LOCALLAB_LOGENCOD_TOOLTIP;Tone Mapping with Logarithmic encoding (ACES).\nUseful for underexposed images or images with high dynamic range.\n\nTwo-step process : 1) Dynamic Range calculation 2) Manual adjustment +TP_LOCALLAB_LOGEXP;All tools +TP_LOCALLAB_LOGFRA;Scene Conditions +TP_LOCALLAB_LOGFRAME_TOOLTIP;Allows you to calculate and adjust the Ev levels and the 'Mean luminance Yb%' (source gray point) for the spot area. The resulting values will be used by all Lab operations and most RGB operations in the pipeline.\nTakes into account exposure compensation in the main-menu Exposure tab.\nAlso calculates the absolute luminance at the time of shooting. +TP_LOCALLAB_LOGIMAGE_TOOLTIP;Takes into account corresponding Ciecam variables (mainly Contrast 'J' and Saturation 's', and also 'advanced' Contrast 'Q' , Brightness 'Q', Lightness (J), Colorfulness (M)). +TP_LOCALLAB_LOGLIGHTL;Lightness (J) +TP_LOCALLAB_LOGLIGHTL_TOOLTIP;Close to lightness (L*a*b*), takes into account the increase in perceived coloration. +TP_LOCALLAB_LOGLIGHTQ;Brightness (Q) +TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;Perceived amount of light emanating from a stimulus.\nIndicator that a stimulus appears to be more or less bright, clear. +TP_LOCALLAB_LOGLIN;Logarithm mode +TP_LOCALLAB_LOGPFRA;Relative Exposure Levels +TP_LOCALLAB_LOGREPART;Strength +TP_LOCALLAB_LOGREPART_TOOLTIP;Allows you to adjust the relative strength of the log-encoded image with respect to the original image.\nDoes not affect the Ciecam component. +TP_LOCALLAB_LOGSATURL_TOOLTIP;Saturation (s) in CIECAM02 corresponds to the color of a stimulus in relation to its own brightness.\nActs mainly on medium and highlights tones +TP_LOCALLAB_LOGSCENE_TOOLTIP;Corresponds to the shooting conditions. +TP_LOCALLAB_LOGSRCGREY_TOOLTIP;Estimated gray point value of the image. +TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment. The image will become slightly bright. +TP_LOCALLAB_LOGTARGGREY_TOOLTIP;You can adjust this value to suit. +TP_LOCALLAB_LOGVIEWING_TOOLTIP;Corresponds to the medium on which the final image will be viewed (monitor, TV, projector, printer,..), as well as its environment. +TP_LOCALLAB_LOG_TOOLNAME;Log Encoding - 0 +TP_LOCALLAB_LUM;Curves LL - CC +TP_LOCALLAB_LUMADARKEST;Darkest +TP_LOCALLAB_LUMASK;Background color for luminance and color masks +TP_LOCALLAB_LUMASK_TOOLTIP;Adjusts the shade of gray or color of the mask background in Show Mask (Mask and modifications) +TP_LOCALLAB_LUMAWHITESEST;Lightest +TP_LOCALLAB_LUMFRA;L*a*b* standard +TP_LOCALLAB_LUMONLY;Luminance only +TP_LOCALLAB_MASFRAME;Mask and Merge +TP_LOCALLAB_MASFRAME_TOOLTIP;For all masks.\nTakes into account the deltaE image to avoid modifying the selection area when the following Mask Tools are used: Gamma , Slope , Chroma, Contrast curve , Local contrast (by wavelet level), Blur Mask and Structure Mask (if enabled ) .\nDisabled when Inverse mode is used +TP_LOCALLAB_MASK;Mask +TP_LOCALLAB_MASK2;Contrast curve +TP_LOCALLAB_MASKCOL;Mask Curves +TP_LOCALLAB_MASKCOM;Common Color Mask +TP_LOCALLAB_MASKCOM_TOOLNAME;Common Color Mask - 13 +TP_LOCALLAB_MASKCOM_TOOLTIP;A tool in its own right.\nCan be used to adjust the image appearance (chrominance, luminance, contrast) and texture as a function of Scope. +TP_LOCALLAB_MASKCURVE_TOOLTIP;The 3 curves are set to 1 (maximum) by default:\nC=f(C) the chroma varies according to the chrominance. You can decrease the chroma to improve the selection. By setting this curve close to zero (with a low value of C to activate the curve) you can desaturate the background in Inverse mode.\nL=f(L) the luminance varies according to the luminance, so you can decrease the brightness to improve the selection.\nL and C = f(H) luminance and chroma vary with hue, so you can decrease luminance and chroma to improve selection +TP_LOCALLAB_MASKH;Hue curve +TP_LOCALLAB_MASK_TOOLTIP;You can enable multiple masks for a tool by activating another tool and using only the mask (set the tool sliders to 0 ).\n\nYou can also duplicate the RT-spot and place it close to the first spot. The small variations in the spot references allows you to make fine adjustments. +TP_LOCALLAB_MED;Medium +TP_LOCALLAB_MEDIAN;Median Low +TP_LOCALLAB_MEDIANITER_TOOLTIP;The number of successive iterations carried out by the median filter. +TP_LOCALLAB_MEDIAN_TOOLTIP;You can choose a median value in the range 3x3 to 9x9 pixels. Higher values increase noise reduction and blur. +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_MERGECOLFRMASK_TOOLTIP;Allows you to create masks based on the 3 LCH curves and/or a structure-detection algorithm +TP_LOCALLAB_MERGEFIV;Previous Spot(Mask 7) + Mask LCH +TP_LOCALLAB_MERGEFOU;Previous Spot(Mask 7) +TP_LOCALLAB_MERGEMER_TOOLTIP;Takes ΔE into account when merging files (equivalent of scope in this case) +TP_LOCALLAB_MERGENONE;None +TP_LOCALLAB_MERGEONE;Short Curves 'L' Mask +TP_LOCALLAB_MERGEOPA_TOOLTIP;Opacity = % of current spot to be merged with original or previous Spot.\nContrast threshold : adjusts result as a function of contrast in original image. +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_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_MERSEV;Soft Light (legacy) +TP_LOCALLAB_MERSEV0;Soft Light Illusion +TP_LOCALLAB_MERSEV1;Soft Light W3C +TP_LOCALLAB_MERSEV2;Hard Light +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;Subtract +TP_LOCALLAB_METHOD_TOOLTIP;'Enhanced + chroma denoise' significantly increases processing times.\nBut reduce artifacts. +TP_LOCALLAB_MLABEL;Restored data Min=%1 Max=%2 (Clip - Offset) +TP_LOCALLAB_MLABEL_TOOLTIP;The values should be close to Min=0 Max=32768 (log mode) but other values are possible.You can adjust ‘Clip restored data (gain)’ and ‘Offset’ to normalize.\nRecovers image data without blending. +TP_LOCALLAB_MODE_EXPERT;Advanced +TP_LOCALLAB_MODE_NORMAL;Standard +TP_LOCALLAB_MODE_SIMPLE;Basic +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;Wide-range tone adjustment: -18EV to +4EV. The first slider acts on very dark tones between -18EV and -6EV. The last slider acts on light tones up to 4EV +TP_LOCALLAB_NEIGH;Radius +TP_LOCALLAB_NOISECHROCOARSE;Coarse chroma (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;Fine chroma (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_NOISE_TOOLTIP;Adds luminance noise +TP_LOCALLAB_NONENOISE;None +TP_LOCALLAB_NUL_TOOLTIP;. +TP_LOCALLAB_OFFS;Offset +TP_LOCALLAB_OFFSETWAV;Offset +TP_LOCALLAB_OPACOL;Opacity +TP_LOCALLAB_ORIGLC;Merge only with original image +TP_LOCALLAB_ORRETILAP_TOOLTIP;Modifies ΔE prior to any changes made by ‘Scope’. This allows you to differentiate the action for different parts of the image (with respect to the background for example). +TP_LOCALLAB_ORRETISTREN_TOOLTIP;Acts on the Laplacian threshold, the greater the action, the more the differences in contrast will be reduced +TP_LOCALLAB_PASTELS2;Vibrance +TP_LOCALLAB_PDE;Contrast Attenuator - Dynamic Range compression +TP_LOCALLAB_PDEFRA;Contrast Attenuator ƒ +TP_LOCALLAB_PDEFRAME_TOOLTIP;PDE IPOL algorithm adapted for Rawtherapee : gives different results and requires different settings compared to main-menu ‘Exposure’.\nMay be useful for under-exposed or high dynamic range images. +TP_LOCALLAB_PREVHIDE;Hide additional settings +TP_LOCALLAB_PREVIEW;Preview ΔE +TP_LOCALLAB_PREVSHOW;Show additional settings +TP_LOCALLAB_PROXI;ΔE decay +TP_LOCALLAB_QUALCURV_METHOD;Curve type +TP_LOCALLAB_QUAL_METHOD;Global quality +TP_LOCALLAB_RADIUS;Radius +TP_LOCALLAB_RADIUS_TOOLTIP;Uses a Fast Fourier Transform for radius > 30 +TP_LOCALLAB_RADMASKCOL;Smooth radius +TP_LOCALLAB_RECT;Rectangle +TP_LOCALLAB_RECURS;Recursive references +TP_LOCALLAB_RECURS_TOOLTIP;Forces the algorithm to recalculate the references after each tool is applied.\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 +TP_LOCALLAB_RETIFRA;Retinex +TP_LOCALLAB_RETIFRAME_TOOLTIP;Retinex can be useful for processing images: \nthat are blurred, foggy or hazy (in addition to Dehaze).\nthat contain large differences in luminance.\nIt can also be used for special effects (tone mapping). +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_LIGHTDARK_TOOLTIP;Has no effect when the value of "Lightness = 1" or "Darkness =2".\nFor other values, the last step of a "Multiple scale Retinex" algorithm (similar to "local contrast") is applied. These 2 cursors, associated with "Strength" allow you to make adjustments upstream of local contrast +TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP;Adjusts the internal parameters to optimize the response.\nPreferable to keep the "Restored data" values close to Min=0 and Max=32768 (log mode), but other values are possible. +TP_LOCALLAB_RETI_LOGLIN_TOOLTIP;Logarithm mode introduces more contrast but will also generate more halos. +TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP;The radius and variance sliders allow you adjust haze and target either the foreground or the background. +TP_LOCALLAB_RETI_SCALE_TOOLTIP;If Scale=1, Retinex behaves like local contrast with additional possibilities.\nIncreasing the value of Scale increases the intensity of the recursive action at the expense of processing time. +TP_LOCALLAB_RET_TOOLNAME;Dehaze & Retinex - 9 +TP_LOCALLAB_REWEI;Reweighting iterates +TP_LOCALLAB_RGB;RGB Tone Curve +TP_LOCALLAB_RGBCURVE_TOOLTIP;In RGB mode you have 4 choices : Standard, Weighted standard, Luminance & Film-like. +TP_LOCALLAB_ROW_NVIS;Not visible +TP_LOCALLAB_ROW_VIS;Visible +TP_LOCALLAB_SATUR;Saturation +TP_LOCALLAB_SATURV;Saturation (s) +TP_LOCALLAB_SAVREST;Save - Restore Current Image +TP_LOCALLAB_SCALEGR;Scale +TP_LOCALLAB_SCALERETI;Scale +TP_LOCALLAB_SCALTM;Scale +TP_LOCALLAB_SCOPEMASK;Scope (ΔE image mask) +TP_LOCALLAB_SCOPEMASK_TOOLTIP;Enabled if DeltaE Image Mask is enabled.\nLow values avoid retouching selected area +TP_LOCALLAB_SENSI;Scope +TP_LOCALLAB_SENSIEXCLU;Scope +TP_LOCALLAB_SENSIEXCLU_TOOLTIP;Adjust the colors to be excluded +TP_LOCALLAB_SENSIMASK_TOOLTIP;Scope adjustment specific to common mask tool.\nActs on the difference between the original image and the mask.\nUses the luma, chroma & hue references from the center of the RT-spot\n\nYou can also adjust the deltaE of the mask itself by using 'Scope (deltaE image mask)' in 'Settings' > ‘Mask & Merge’ +TP_LOCALLAB_SENSI_TOOLTIP;Adjusts the scope of the action:\nSmall values limit the action to colors similar to those in the center of the spot.\nHigh values let the tool act on a wider range of colors +TP_LOCALLAB_SETTINGS;Settings +TP_LOCALLAB_SH1;Shadows Highlights +TP_LOCALLAB_SH2;Equalizer +TP_LOCALLAB_SHADEX;Shadows +TP_LOCALLAB_SHADEXCOMP;Shadow compression & tonal width +TP_LOCALLAB_SHADHIGH;Shadows/Highlights & Tone equalizer +TP_LOCALLAB_SHADHMASK_TOOLTIP;Lowers the highlights of the mask in the same way as the shadows/highlights algorithm +TP_LOCALLAB_SHADMASK_TOOLTIP;Lifts the shadows of the mask in the same way as the shadows/highlights algorithm +TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP;Adjust shadows & highlights either with shadows & highlights sliders or with a tone equalizer.\nCan be used instead of, or in conjunction with the Exposure module.\nCan also be used as a graduated filter. +TP_LOCALLAB_SHAMASKCOL;Shadows +TP_LOCALLAB_SHAPETYPE;RT-spot shape +TP_LOCALLAB_SHAPE_TOOLTIP;”Ellipse” is the normal mode.\n “Rectangle” can be used in certain cases, for example to work in full-image mode by placing the delimiters outside the preview area. In this case, set transition = 100.\n\nFuture developments will include polygon shapes and Bezier curves. +TP_LOCALLAB_SHARAMOUNT;Amount +TP_LOCALLAB_SHARBLUR;Blur radius +TP_LOCALLAB_SHARDAMPING;Damping +TP_LOCALLAB_SHARFRAME;Modifications +TP_LOCALLAB_SHARITER;Iterations +TP_LOCALLAB_SHARP;Sharpening +TP_LOCALLAB_SHARP_TOOLNAME;Sharpening - 8 +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_SHOWC;Mask and modifications +TP_LOCALLAB_SHOWC1;Merge file +TP_LOCALLAB_SHOWCB;Mask and modifications +TP_LOCALLAB_SHOWDCT;Show Fourier (ƒ) process +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;Displays masks and modifications.\nBeware, you can only view one tool mask at a time.\nShow modified image: shows the modified image including the effect of any adjustments and masks.\nShow modified areas without mask: shows the modifications before any masks are applied.\nShow modified areas with mask: shows the modifications after a mask has been applied.\nShow mask: shows the aspect of the mask including the effect of any curves and filters.\nShow spot structure: allows you to see the structure-detection mask when the "Spot structure" cursor is activated (when available).\nNote: The mask is applied before the shape detection algorithm. +TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;Allows you to visualize the different stages of the Fourier process.\n Laplace - calculates the second derivative of the Laplace transform as a function of the threshold.\nFourier - shows the Laplacian transform with DCT.\nPoisson - shows the solution of the Poisson DCE.\nNo luminance normalization - shows result without any luminance normalization. +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;Show modified image +TP_LOCALLAB_SHOWMODIF;Show modified areas without mask +TP_LOCALLAB_SHOWMODIFMASK;Show modified areas with mask +TP_LOCALLAB_SHOWNORMAL;No luminance normalization +TP_LOCALLAB_SHOWPLUS;Mask and modifications (Blur & Denoise) +TP_LOCALLAB_SHOWPOISSON;Poisson (pde ƒ) +TP_LOCALLAB_SHOWR;Mask and modifications +TP_LOCALLAB_SHOWREF;Preview ΔE +TP_LOCALLAB_SHOWS;Mask and modifications +TP_LOCALLAB_SHOWSTRUC;Show spot structure(advanced) +TP_LOCALLAB_SHOWSTRUCEX;Show spot structure(advanced) +TP_LOCALLAB_SHOWT;Mask and modifications +TP_LOCALLAB_SHOWVI;Mask and modifications +TP_LOCALLAB_SHRESFRA;Shadows/Highlights +TP_LOCALLAB_SHTRC_TOOLTIP;Based on 'working profile' (only those provided), 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.\nIt is recommended that the TRC of both devices (monitor and output profile) be sRGB (default). +TP_LOCALLAB_SH_TOOLNAME;Shadows/Highlights & Tone Equalizer - 5 +TP_LOCALLAB_SIGMAWAV;Attenuation response +TP_LOCALLAB_SIM;Simple +TP_LOCALLAB_SLOMASKCOL;Slope +TP_LOCALLAB_SLOMASK_TOOLTIP;Gamma and Slope allow a soft and artifact-free transformation of the mask by progressively modifying “L” to avoid any discontinuities. +TP_LOCALLAB_SLOSH;Slope +TP_LOCALLAB_SOFT;Soft Light & Original Retinex +TP_LOCALLAB_SOFTM;Soft Light +TP_LOCALLAB_SOFTMETHOD_TOOLTIP;Apply a Soft-light blend (identical to the global adjustment). Carry out dodge and burn using the original Retinex algorithm. +TP_LOCALLAB_SOFTRADIUSCOL;Soft radius +TP_LOCALLAB_SOFTRADIUSCOL_TOOLTIP;Applies a guided filter to the output image to reduce possible artifacts. +TP_LOCALLAB_SOFTRETI;Reduce ΔE artifacts +TP_LOCALLAB_SOFTRETI_TOOLTIP;Take into account deltaE to improve Transmission map +TP_LOCALLAB_SOFT_TOOLNAME;Soft Light & Original Retinex - 6 +TP_LOCALLAB_SOURCE_ABS;Absolute luminance +TP_LOCALLAB_SOURCE_GRAY;Mean luminance (Yb%) +TP_LOCALLAB_SPECCASE;Specific cases +TP_LOCALLAB_SPECIAL;Special use of RGB curves +TP_LOCALLAB_SPECIAL_TOOLTIP;The checkbox allows you to remove all other actions i.e. “Scope”, masks, sliders etc., (except for transitions) and use just the effect of the RGB tone-curve. +TP_LOCALLAB_SPOTNAME;New 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_STRENGRID_TOOLTIP;You can adjust the desired effect with "strength", but you can also use the "scope" function which allows you to delimit the action (e.g. to isolate a particular color). +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_STRUCCOL;Spot structure +TP_LOCALLAB_STRUCCOL1;Spot structure +TP_LOCALLAB_STRUCT_TOOLTIP;Uses the Sobel algorithm to take into account structure for shape detection.\nActivate "Mask and modifications” > “Show spot structure" (advanced mode) to see a preview of the mask (without modifications).\n\nCan be used in conjunction with the Structure Mask, Blur Mask and “Local contrast (by wavelet level)” to improve edge detection.\n\nEffects of adjustments using Lightness, Contrast, Chrominance, Exposure or other non-mask-related tools visible using either ‘Show modified image” or “Show modified areas with mask ”. +TP_LOCALLAB_STRUMASKCOL;Structure mask strength +TP_LOCALLAB_STRUMASK_TOOLTIP;Structure mask (slider) with the checkbox "Structure mask as tool" unchecked: In this case a mask showing the structure will be generated even if none of the 3 curves is activated. Structure masks are available for mask 1 (Blur and denoise") and mask 7 (Color & Light). +TP_LOCALLAB_STRUSTRMASK_TOOLTIP;Moderate use of this slider is recommended! +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;Mean luminance (Yb%) +TP_LOCALLAB_THRES;Threshold structure +TP_LOCALLAB_THRESDELTAE;ΔE scope threshold +TP_LOCALLAB_THRESRETI;Threshold +TP_LOCALLAB_THRESWAV;Balance threshold +TP_LOCALLAB_TLABEL;TM Data Min=%1 Max=%2 Mean=%3 Sigma=%4 (Threshold) +TP_LOCALLAB_TLABEL2;TM Effective Tm=%1 TM=%2 +TP_LOCALLAB_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map.\nYou can normalize the results with the threshold slider. +TP_LOCALLAB_TM;Tone Mapping +TP_LOCALLAB_TM_MASK;Use transmission map +TP_LOCALLAB_TONEMAPESTOP_TOOLTIP;This slider affects edge sensitivity.\n The greater the value, the more likely a change in contrast will be interpreted as an "edge".\n If set to zero the tone mapping will have an effect similar to unsharp masking. +TP_LOCALLAB_TONEMAPGAM_TOOLTIP;The Gamma slider shifts the tone-mapping effect towards either the shadows or the highlights. +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_TONEMAP_TOOLTIP;Same as the tone mapping tool in the main menu.\nThe main-menu tool must be deactivated if this tool is used. +TP_LOCALLAB_TONEMASCALE_TOOLTIP;This slider allows you to adjust the transition between "local" and "global" contrast.\nThe greater the value, the larger a detail needs to be for it to be boosted +TP_LOCALLAB_TONE_TOOLNAME;Tone Mapping - 4 +TP_LOCALLAB_TOOLCOL;Structure mask as tool +TP_LOCALLAB_TOOLCOLFRMASK_TOOLTIP;Allows you to modify the mask, if one exists +TP_LOCALLAB_TOOLMASK;Mask Tools +TP_LOCALLAB_TOOLMASK_TOOLTIP;Structure mask (slider) with the checkbox "Structure mask as tool" checked: in this case a mask showing the structure will be generated after one or more of the 2 curves L(L) or LC(H) has been modified.\n Here, the "Structure mask" behaves like the other Mask tools : Gamma, Slope, etc.\n It allows you to vary the action on the mask according to the structure of the image. +TP_LOCALLAB_TRANSIT;Transition Gradient +TP_LOCALLAB_TRANSITGRAD;Transition differentiation XY +TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Allows you to vary the y-axis transition +TP_LOCALLAB_TRANSITVALUE;Transition value +TP_LOCALLAB_TRANSITWEAK;Transition decay (linear-log) +TP_LOCALLAB_TRANSITWEAK_TOOLTIP;Adjust transition decay function: 1 linear , 2 parabolic, 3 cubic up to ^25.\nCan be used in conjunction with very low transition values to reduce defects (CBDL, Wavelets, 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 positive values (max).\nOrdinate: amplification or reduction.\nYou can adjust this curve to change the Transmission and reduce artifacts +TP_LOCALLAB_USEMASK;Use mask +TP_LOCALLAB_VART;Variance (contrast) +TP_LOCALLAB_VIBRANCE;Vibrance & Warm/Cool +TP_LOCALLAB_VIBRA_TOOLTIP;Adjusts vibrance (essentially the same as the global adjustment).\nCarries out the equivalent of a white-balance adjustment using a CIECAM algorithm. +TP_LOCALLAB_VIB_TOOLNAME;Vibrance & Warm/Cool - 3 +TP_LOCALLAB_VIS_TOOLTIP;Click to show/hide selected Control Spot.\nCtrl+click to show/hide all Control Spot. +TP_LOCALLAB_WAMASKCOL;Ψ Mask Wavelet level +TP_LOCALLAB_WARM;Warm/Cool & Color artifacts +TP_LOCALLAB_WARM_TOOLTIP;This slider uses the CIECAM algorithm and acts as a White Balance control to make the color temperature of the selected area warmer or cooler.\nIt can also reduce color artifacts in some cases. +TP_LOCALLAB_WASDEN_TOOLTIP;Luminance noise reduction: the left-hand side of the curve corresponds to the first 3 levels 0,1 &2 (fine detail). The right hand side of the curve corresponds to the coarser details (level 3 and beyond). +TP_LOCALLAB_WAT_BALTHRES_TOOLTIP;Balances the action within each level. +TP_LOCALLAB_WAT_BLURLC_TOOLTIP;The default blur setting affects all 3 L*a* b* components (luminance and colour).\nWhen checked, only luminance is blurred. +TP_LOCALLAB_WAT_CLARIC_TOOLTIP;“Merge chroma” is used to select the intensity of the desired effect on chrominance. +TP_LOCALLAB_WAT_CLARIL_TOOLTIP;“Merge luma” is used to select the intensity of the desired effect on luminance. +TP_LOCALLAB_WAT_CONTCHROMALEV_TOOLTIP;“Chroma levels”: adjusts the “a” and “b” components of Lab* as a proportion of the luminance value. +TP_LOCALLAB_WAT_CONTOFFSET_TOOLTIP;Offset modifies the balance between low-contrast and high-contrast details.\nHigh values will amplify contrast changes to the higher-contrast details, whereas low values will amplify contrast changes to low-contrast details.\nBy using a low “Attenuation response” value you can select which contrast values will be enhanced. +TP_LOCALLAB_WAT_DELTABAL_TOOLTIP;By moving the slider to the left, the lower levels are accentuated. To the right, the lower levels are reduced and the higher levels accentuated. +TP_LOCALLAB_WAT_EXPRESID_TOOLTIP;The residual image behaves in the same way as the main image when making adjustments to contrast, chroma etc. +TP_LOCALLAB_WAT_GRADW_TOOLTIP;The more you move the slider to the right, the more effective the detection algorithm will be and the less noticeable the effects of local contrast. +TP_LOCALLAB_WAT_LEVELLOCCONTRAST_TOOLTIP;Low to high local contrast from left to right on the x-axis.\nIncrease or decrease local contrast on the y-axis. +TP_LOCALLAB_WAT_LOCCONTRASTEDG_TOOLTIP;You can adjust the distribution of local contrast by wavelet level based on the initial intensity of the contrast. This will modify the effects of perspective and relief in the image, and/or reduce the contrast values for very low initial contrast levels. +TP_LOCALLAB_WAT_ORIGLC_TOOLTIP;“Merge only with original image”, prevents the “Wavelet Pyramid” settings from interfering with “Clarity” and “Sharp mask”. +TP_LOCALLAB_WAT_RESIDBLUR_TOOLTIP;Blurs the residual image, independent of the levels. +TP_LOCALLAB_WAT_RESIDCOMP_TOOLTIP;Compresses the residual image to increase or reduce contrast. +TP_LOCALLAB_WAT_SIGMALC_TOOLTIP;The effect of the local contrast adjustment is stronger for medium-contrast details, and weaker for high and low-contrast details.\n This slider controls how quickly the effect dampens towards the extreme contrasts.\nThe higher the value of the slider, the wider the range of contrasts that will receive the full effect of the local contrast adjustment, and the higher the risk of generating artifacts.\nThe lower the value, the more the effect will be pinpointed towards a narrow range of contrast values. +TP_LOCALLAB_WAT_STRENGTHW_TOOLTIP;Intensity of edge-effect detection. +TP_LOCALLAB_WAT_STRWAV_TOOLTIP;Allows the local contrast to be varied according to a chosen gradient and angle. The variation of the luminance signal is taken into account and not the luminance. +TP_LOCALLAB_WAT_THRESHOLDWAV_TOOLTIP;Range of wavelet levels used throughout the "Wavelets" module. +TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP;Allows you to blur each level of decomposition.\nThe finest to coarsest levels of decomposition are from left to right. +TP_LOCALLAB_WAT_WAVCBDL_TOOLTIP;Similar to Contrast By Detail Levels. Fine to coarse detail levels from left to right on the x-axis. +TP_LOCALLAB_WAT_WAVDELTABAL_TOOLTIP;Acts on the balance of the three directions (horizontal, vertical and diagonal) based on the luminance of the image.\nBy default the shadows or highlights are reduced to avoid artifacts. +TP_LOCALLAB_WAT_WAVESHOW_TOOLTIP;Shows all of the "Edge sharpness" tools. It is advisable to read the Wavelet Levels documentation. +TP_LOCALLAB_WAT_WAVLEVELBLUR_TOOLTIP;Allows you to adjust the maximum effect of blurring on the levels. +TP_LOCALLAB_WAT_WAVSHAPE_TOOLTIP;Low to high local contrast from left to right on the x-axis\nIncrease or decrease local contrast on the y-axis. +TP_LOCALLAB_WAT_WAVTM_TOOLTIP;The lower (negative) part compresses each level of decomposition creating a tone mapping effect.\nThe upper (positive) part attenuates the contrast by level.\nThe finest to coarsest levels of decomposition are from left to right on the x-axis. +TP_LOCALLAB_WAV;Local contrast +TP_LOCALLAB_WAVBLUR_TOOLTIP;Allows you to blur each level of the decomposition, as well as the residual image. +TP_LOCALLAB_WAVCOMP;Compression by level +TP_LOCALLAB_WAVCOMPRE;Compression by level +TP_LOCALLAB_WAVCOMPRE_TOOLTIP;Allows you to apply tone mapping or reduce local contrast on individual levels.\nFine to coarse detail levels from left to right on the x-axis. +TP_LOCALLAB_WAVCOMP_TOOLTIP;Allows you to apply local contrast based on the direction of the wavelet decomposition : horizontal, vertical, diagonal +TP_LOCALLAB_WAVCON;Contrast by level +TP_LOCALLAB_WAVCONTF_TOOLTIP;Similar to Contrast By Detail Levels. Fine to coarse detail levels from left to right on the x-axis. +TP_LOCALLAB_WAVDEN;Luminance denoise by level +TP_LOCALLAB_WAVE;Ψ Wavelets +TP_LOCALLAB_WAVEDG;Local contrast +TP_LOCALLAB_WAVEEDG_TOOLTIP;Improves sharpness by targeting the action of local contrast on the edges. It has the same functions as the corresponding module in Wavelet Levels and uses the same settings. +TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP;Range of wavelet levels used in “Local contrast (by wavelet level)” +TP_LOCALLAB_WAVGRAD_TOOLTIP;Allows the local contrast to be varied according to a chosen gradient and angle. The variation of the luminance signal is taken into account and not the luminance. +TP_LOCALLAB_WAVHIGH;Ψ Wavelet high +TP_LOCALLAB_WAVLEV;Blur by level +TP_LOCALLAB_WAVLOW;Ψ Wavelet low +TP_LOCALLAB_WAVMASK;Ψ Local contrast (by wavelet level) +TP_LOCALLAB_WAVMASK_TOOLTIP;Uses wavelets to modify the local contrast of the mask and reinforce or reduce the structure (skin, buildings...) +TP_LOCALLAB_WAVMED;Ψ Wavelet normal +TP_LOCALLAB_WEDIANHI;Median Hi +TP_LOCALLAB_WHITE_EV;White Ev +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 = Evenly distributed.\nHigh = Reinforce strong light.\n TP_METADATA_EDIT;Apply modifications TP_METADATA_MODE;Metadata copy mode TP_METADATA_STRIP;Strip all metadata @@ -1864,8 +3086,28 @@ TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Roundness:\n0 = rectangle,\n50 = fitted ellipse, TP_PCVIGNETTE_STRENGTH;Strength TP_PCVIGNETTE_STRENGTH_TOOLTIP;Filter strength in stops (reached in corners). TP_PDSHARPENING_LABEL;Capture Sharpening +TP_PERSPECTIVE_CAMERA_CROP_FACTOR;Crop factor +TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH;Focal length +TP_PERSPECTIVE_CAMERA_FRAME;Correction +TP_PERSPECTIVE_CAMERA_PITCH;Vertical +TP_PERSPECTIVE_CAMERA_ROLL;Rotation +TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL;Horizontal shift +TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL;Vertical shift +TP_PERSPECTIVE_CAMERA_YAW;Horizontal +TP_PERSPECTIVE_CONTROL_LINES;Control lines +TP_PERSPECTIVE_CONTROL_LINES_TOOLTIP;Ctrl+drag: Draw new line\nRight-click: Delete line TP_PERSPECTIVE_HORIZONTAL;Horizontal TP_PERSPECTIVE_LABEL;Perspective +TP_PERSPECTIVE_METHOD;Method +TP_PERSPECTIVE_METHOD_CAMERA_BASED;Camera-based +TP_PERSPECTIVE_METHOD_SIMPLE;Simple +TP_PERSPECTIVE_POST_CORRECTION_ADJUSTMENT_FRAME;Post-correction adjustment +TP_PERSPECTIVE_PROJECTION_PITCH;Vertical +TP_PERSPECTIVE_PROJECTION_ROTATE;Rotation +TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL;Horizontal shift +TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL;Vertical shift +TP_PERSPECTIVE_PROJECTION_YAW;Horizontal +TP_PERSPECTIVE_RECOVERY_FRAME;Recovery TP_PERSPECTIVE_VERTICAL;Vertical TP_PFCURVE_CURVEEDITOR_CH;Hue TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Controls defringe strength by color.\nHigher = more,\nLower = less. @@ -1912,9 +3154,11 @@ TP_RAW_3PASSBEST;3-pass (Markesteijn) TP_RAW_4PASS;3-pass+fast TP_RAW_AHD;AHD TP_RAW_AMAZE;AMaZE +TP_RAW_AMAZEBILINEAR;AMaZE+Bilinear TP_RAW_AMAZEVNG4;AMaZE+VNG4 TP_RAW_BORDER;Border TP_RAW_DCB;DCB +TP_RAW_DCBBILINEAR;DCB+Bilinear TP_RAW_DCBENHANCE;DCB enhancement TP_RAW_DCBITERATIONS;Number of DCB iterations TP_RAW_DCBVNG4;DCB+VNG4 @@ -1969,6 +3213,7 @@ TP_RAW_PIXELSHIFTSIGMA_TOOLTIP;The default radius of 1.0 usually fits well for b TP_RAW_PIXELSHIFTSMOOTH;Smooth transitions TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;Smooth transitions between areas with motion and areas without.\nSet to 0 to disable transition smoothing.\nSet to 1 to either get the AMaZE/LMMSE result of the selected frame (depending on whether "Use LMMSE" is selected), or the median of all four frames if "Use median" is selected. TP_RAW_RCD;RCD +TP_RAW_RCDBILINEAR;RCD+Bilinear TP_RAW_RCDVNG4;RCD+VNG4 TP_RAW_SENSOR_BAYER_LABEL;Sensor with Bayer Matrix TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;3-pass gives best results (recommended for low ISO images).\n1-pass is almost undistinguishable from 3-pass for high ISO images and is faster.\n+fast gives less artifacts in flat areas @@ -2006,7 +3251,7 @@ TP_RETINEX_FREEGAMMA;Free gamma TP_RETINEX_GAIN;Gain 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_GAINTRANSMISSION_TOOLTIP;Increase or reduce the transmission map to achieve the desired luminance. The x-axis is the transmission. The y-axis is the gain. TP_RETINEX_GAMMA;Gamma TP_RETINEX_GAMMA_FREE;Free TP_RETINEX_GAMMA_HIGH;High @@ -2040,8 +3285,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;The values should be close to Min=0 Max=32768 (log mode) but other values are possible.You can adjust ‘Clip restored data (gain)’ and ‘Offset’ to normalize.\nRecovers image data without blending TP_RETINEX_NEIGHBOR;Radius TP_RETINEX_NEUTRAL;Reset TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. @@ -2054,11 +3299,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;ransmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map.\nYou can normalize the results with the threshold slider. 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 @@ -2134,7 +3379,7 @@ TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE3;Red/Yellow TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE4;Yellow TP_VIBRANCE_CURVEEDITOR_SKINTONES_TOOLTIP;Hue according to hue H=f(H) TP_VIBRANCE_LABEL;Vibrance -TP_VIBRANCE_PASTELS;Pastel Tones +TP_VIBRANCE_PASTELS;Pastel tones TP_VIBRANCE_PASTSATTOG;Link pastel and saturated tones TP_VIBRANCE_PROTECTSKINS;Protect skin-tones TP_VIBRANCE_PSTHRESHOLD;Pastel/saturated tones threshold @@ -2158,27 +3403,28 @@ TP_WAVELET_6;Level 6 TP_WAVELET_7;Level 7 TP_WAVELET_8;Level 8 TP_WAVELET_9;Level 9 -TP_WAVELET_APPLYTO;Apply To +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 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;Chroma balance +TP_WAVELET_BALCHROM;Denoise equalizer Blue-Yellow/Red-Green 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_BALLUM;Denoise Equalizer White-Black +TP_WAVELET_BALLUM;Denoise equalizer White-Black TP_WAVELET_BANONE;None TP_WAVELET_BASLI;Slider TP_WAVELET_BATYPE;Contrast balance method +TP_WAVELET_BL;Blur levels TP_WAVELET_BLCURVE;Blur by levels TP_WAVELET_BLURFRAME;Blur -TP_WAVELET_BLUWAV;Damper -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_BLUWAV;Attenuation response +TP_WAVELET_CBENAB;Toning and Color balance +TP_WAVELET_CB_TOOLTIP;With high values you can create special effects, similar to those achieved with the Chroma Module, but focused on the residual image\nWith moderate values you can manually correct the white balance TP_WAVELET_CCURVE;Local contrast TP_WAVELET_CH1;Whole chroma range TP_WAVELET_CH2;Saturated/pastel @@ -2186,21 +3432,25 @@ TP_WAVELET_CH3;Link contrast levels TP_WAVELET_CHCU;Curve TP_WAVELET_CHR;Chroma-contrast link strength TP_WAVELET_CHRO;Saturated/pastel threshold -TP_WAVELET_CHROFRAME;Denoise Chrominance +TP_WAVELET_CHROFRAME;Denoise chrominance TP_WAVELET_CHROMAFRAME;Chroma TP_WAVELET_CHROMCO;Chrominance Coarse TP_WAVELET_CHROMFI;Chrominance Fine TP_WAVELET_CHRO_TOOLTIP;Sets the wavelet level which will be the threshold between saturated and pastel colors.\n1-x: saturated\nx-9: pastel\n\nIf the value exceeds the amount of wavelet levels you are using then it will be ignored. -TP_WAVELET_CHR_TOOLTIP;Adjusts chroma as a function of "contrast levels" and "chroma-contrast link strength" TP_WAVELET_CHRWAV;Blur chroma +TP_WAVELET_CHR_TOOLTIP;Adjusts chroma as a function of "contrast levels" and "chroma-contrast link strength" TP_WAVELET_CHSL;Sliders TP_WAVELET_CHTYPE;Chrominance method TP_WAVELET_CLA;Clarity TP_WAVELET_CLARI;Sharp-mask and Clarity -TP_WAVELET_COLORT;Opacity Red-Green +TP_WAVELET_COLORT;Opacity red-green TP_WAVELET_COMPCONT;Contrast +TP_WAVELET_COMPEXPERT;Advanced TP_WAVELET_COMPGAMMA;Compression gamma TP_WAVELET_COMPGAMMA_TOOLTIP;Adjusting the gamma of the residual image allows you to equilibrate the data and histogram. +TP_WAVELET_COMPLEXLAB;Complexity +TP_WAVELET_COMPLEX_TOOLTIP;Standard: shows a reduced set of tools suitable for most processing operations.\nAdvanced: shows the complete set of tools for advanced processing operations +TP_WAVELET_COMPNORMAL;Standard TP_WAVELET_COMPTM;Tone mapping TP_WAVELET_CONTEDIT;'After' contrast curve TP_WAVELET_CONTFRAME;Contrast - Compression @@ -2209,16 +3459,16 @@ 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_CONTRA_TOOLTIP;Changes the residual image contrast. 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. TP_WAVELET_CURVEEDITOR_CL;L -TP_WAVELET_CURVEEDITOR_CL_TOOLTIP;Applies a final contrast luminance curve at the end of the wavelet treatment. +TP_WAVELET_CURVEEDITOR_CL_TOOLTIP;Applies a final contrast-luminance curve at the end of the wavelet processing. TP_WAVELET_CURVEEDITOR_HH;HH -TP_WAVELET_CURVEEDITOR_HH_TOOLTIP;Modifies the residual image's hue as a function of hue. +TP_WAVELET_CURVEEDITOR_HH_TOOLTIP;Modifies the residual image hue as a function of hue. TP_WAVELET_DALL;All directions TP_WAVELET_DAUB;Edge performance TP_WAVELET_DAUB2;D2 - low @@ -2226,61 +3476,94 @@ 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_DAUBLOCAL;Wavelet Edge performance +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 first levels. However the quality is not strictly related to this coefficient and can vary depending on image and use. +TP_WAVELET_DEN5THR;Guided threshold +TP_WAVELET_DEN12LOW;1 2 Low +TP_WAVELET_DEN12PLUS;1 2 High +TP_WAVELET_DEN14LOW;1 4 Low +TP_WAVELET_DEN14PLUS;1 4 High +TP_WAVELET_DENCONTRAST;Local contrast Equalizer +TP_WAVELET_DENCURV;Curve +TP_WAVELET_DENEQUAL;1 2 3 4 Equal +TP_WAVELET_DENH;Threshold +TP_WAVELET_DENL;Correction structure +TP_WAVELET_DENLH;Guided threshold by detail levels 1-4 +TP_WAVELET_DENLOCAL_TOOLTIP;Use a curve in order to guide the denoising according to the local contrast.\nThe areas are denoised, the structures are maintained +TP_WAVELET_DENMIX_TOOLTIP;Balances the action of the guide taking into account the original image and the denoised image +TP_WAVELET_DENOISE;Guide curve based on Local contrast +TP_WAVELET_DENOISEGUID;Guided threshold based on hue +TP_WAVELET_DENOISEH;High levels Curve Local contrast +TP_WAVELET_DENOISEHUE;Denoise equalizer Hue +TP_WAVELET_DENQUA;Mode +TP_WAVELET_DENSIGMA_TOOLTIP;Adapts the shape of the guide +TP_WAVELET_DENSLI;Slider +TP_WAVELET_DENSLILAB;Method +TP_WAVELET_DENWAVGUID_TOOLTIP;Uses hue to reduce or increase the action of the guided filter +TP_WAVELET_DENWAVHUE_TOOLTIP;Amplify or reduce denoising depending on the color +TP_WAVELET_DETEND;Details TP_WAVELET_DIRFRAME;Directional contrast TP_WAVELET_DONE;Vertical TP_WAVELET_DTHR;Diagonal TP_WAVELET_DTWO;Horizontal TP_WAVELET_EDCU;Curve +TP_WAVELET_EDEFFECT;Attenuation response +TP_WAVELET_EDEFFECT_TOOLTIP;This slider selects the range of contrast values that will receive the full effect of any adjustment TP_WAVELET_EDGCONT;Local contrast -TP_WAVELET_EDGCONT_TOOLTIP;Adjusting the points to the left decreases contrast, and to the right increases it.\nBottom-left, top-left, top-right and bottom-right represent respectively local contrast for low values, mean, mean+stdev and maxima. -TP_WAVELET_EDGE;Edge Sharpness +TP_WAVELET_EDGCONT_TOOLTIP;Adjusting the points to the left decreases contrast, and to the right increases it.\nBottom-left, top-left, top-right and bottom-right represent respectively local contrast for low values, mean, mean+std. dev. and maxima. +TP_WAVELET_EDGE;Edge sharpness TP_WAVELET_EDGEAMPLI;Base amplification TP_WAVELET_EDGEDETECT;Gradient sensitivity 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_EDGEDETECTTHR2;Edge enhancement +TP_WAVELET_EDGEDETECTTHR_TOOLTIP;This slider sets a threshold below which finer details won't be considered as an edge 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_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. TP_WAVELET_EDGTHRESH;Detail TP_WAVELET_EDGTHRESH_TOOLTIP;Change the repartition between the first levels and the others. The higher the threshold the more the action is centered on the first levels. Be careful with negative values, they increase the action of high levels and can introduce artifacts. TP_WAVELET_EDRAD;Radius -TP_WAVELET_EDRAD_TOOLTIP;This radius adjustment is very different from those in other sharpening tools. Its value is compared to each level through a complex function. In this sense, a value of zero still has an effect. -TP_WAVELET_EDSL;Threshold Sliders +TP_WAVELET_EDRAD_TOOLTIP;This adjustment controls the local enhancement. A value of zero still has an effect +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;Finer levels luminance range +TP_WAVELET_FINCFRAME;Final local contrast 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_FINEST;Finest +TP_WAVELET_FINTHR_TOOLTIP;Uses local contrast to reduce or increase the action of the guided filter +TP_WAVELET_GUIDFRAME;Final smoothing (guided filter) +TP_WAVELET_HIGHLIGHT;Finer levels luminance range TP_WAVELET_HS1;Whole luminance range 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 +TP_WAVELET_HUESKY;Hue range TP_WAVELET_HUESKY_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_ITER;Delta balance levels TP_WAVELET_ITER_TOOLTIP;Left: increase low levels and reduce high levels,\nRight: reduce low levels and increase high levels. -TP_WAVELET_LABEL;Wavelet Levels +TP_WAVELET_LABEL;Wavelet levels TP_WAVELET_LARGEST;Coarsest TP_WAVELET_LEVCH;Chroma +TP_WAVELET_LEVDEN;Level 5-6 denoise TP_WAVELET_LEVDIR_ALL;All levels, in all directions -TP_WAVELET_LEVDIR_INF;Finer details levels, with selected level +TP_WAVELET_LEVDIR_INF;Finer detail levels, including selected level TP_WAVELET_LEVDIR_ONE;One level -TP_WAVELET_LEVDIR_SUP;Coarser details levels, without selected level +TP_WAVELET_LEVDIR_SUP;Coarser detail levels, excluding selected level +TP_WAVELET_LEVELHIGH;Radius 5-6 +TP_WAVELET_LEVELLOW;Radius 1-4 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_LEVELSIGM;Radius +TP_WAVELET_LEVELS_TOOLTIP;Choose the number of wavelet decomposition levels for the image.\nMore levels require more RAM and require a longer processing time. TP_WAVELET_LEVF;Contrast +TP_WAVELET_LEVFOUR;Level 5-6 denoise and guided threshold TP_WAVELET_LEVLABEL;Preview maximum possible levels = %1 TP_WAVELET_LEVONE;Level 2 TP_WAVELET_LEVTHRE;Level 4 TP_WAVELET_LEVTWO;Level 3 TP_WAVELET_LEVZERO;Level 1 -TP_WAVELET_LINKEDG;Link with Edge Sharpness' Strength +TP_WAVELET_LIMDEN;Interaction levels 5-6 on levels 1-4 +TP_WAVELET_LINKEDG;Link to Edge Sharpness Strength TP_WAVELET_LIPST;Enhanced algoritm TP_WAVELET_LOWLIGHT;Coarser levels luminance range TP_WAVELET_LOWTHR_TOOLTIP;Prevents amplification of fine textures and noise @@ -2288,34 +3571,42 @@ TP_WAVELET_MEDGREINF;First level TP_WAVELET_MEDI;Reduce artifacts in blue sky TP_WAVELET_MEDILEV;Edge detection TP_WAVELET_MEDILEV_TOOLTIP;When you enable Edge Detection, it is recommanded:\n- to disabled low contrast levels to avoid artifacts,\n- to use high values of gradient sensitivity.\n\nYou can modulate the strength with 'refine' from Denoise and Refine. -TP_WAVELET_MERGEC;Merge Chroma -TP_WAVELET_MERGEL;Merge Luma +TP_WAVELET_MERGEC;Merge chroma +TP_WAVELET_MERGEL;Merge luma +TP_WAVELET_MIXCONTRAST;Reference local contrast +TP_WAVELET_MIXDENOISE;Denoise +TP_WAVELET_MIXMIX;Mixed 50% noise - 50% denoise +TP_WAVELET_MIXMIX70;Mixed 30% noise - 70% denoise +TP_WAVELET_MIXNOISE;Noise 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_NOISE_TOOLTIP;If level 4 luminance denoise superior to 50, 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 TP_WAVELET_NPTYPE;Neighboring pixels TP_WAVELET_NPTYPE_TOOLTIP;This algorithm uses the proximity of a pixel and eight of its neighbors. If less difference, edges are reinforced. +TP_WAVELET_OFFSET_TOOLTIP;Offset modifies the balance between low contrast and high contrast details.\nHigh values will amplify contrast changes to the higher contrast details, whereas low values will amplify contrast changes to low contrast details.\nBy using a low Attenuation response value you can select which contrast values will be enhanced. TP_WAVELET_OLDSH;Algorithm using negatives values -TP_WAVELET_OPACITY;Opacity Blue-Yellow +TP_WAVELET_OPACITY;Opacity blue-yellow TP_WAVELET_OPACITYW;Contrast balance d/v-h curve 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_QUAAGRES;Agressive +TP_WAVELET_QUACONSER;Conservative +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;Blur luminance +TP_WAVELET_RESBLURC;Blur chroma TP_WAVELET_RESBLUR_TOOLTIP;Disabled if zoom > about 500% -TP_WAVELET_RESCHRO;Intensity +TP_WAVELET_RESCHRO;Strength TP_WAVELET_RESCON;Shadows TP_WAVELET_RESCONH;Highlights TP_WAVELET_RESID;Residual Image @@ -2324,45 +3615,46 @@ 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_SIGMAFIN;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_SIGM;Radius +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 -TP_WAVELET_SKY_TOOLTIP;At -100 sky-tones are targetted.\nAt 0 all tones are treated equally.\nAt +100 sky-tones are protected while all other tones are affected. -TP_WAVELET_SOFTRAD;Soft Radius -TP_WAVELET_STREN;Strength +TP_WAVELET_SKY;Hue targetting/protection +TP_WAVELET_SKY_TOOLTIP;Allows you to target or protect a range of hues.\nAt -100 selected hues are targetted.\nAt 0 all hues are treated equally.\nAt +100 selected hues are protected while all other hues are targetted. +TP_WAVELET_SOFTRAD;Soft radius +TP_WAVELET_STREN;Refine +TP_WAVELET_STREND;Strength TP_WAVELET_STRENGTH;Strength TP_WAVELET_SUPE;Extra TP_WAVELET_THR;Shadows threshold +TP_WAVELET_THRDEN_TOOLTIP;Generates a stepped curve in order to guide the denoising according to the local contrast.\nThe areas are denoised, the structures are maintained +TP_WAVELET_THREND;Local contrast threshold TP_WAVELET_THRESHOLD;Finer levels TP_WAVELET_THRESHOLD2;Coarser levels -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. : All levels from level 1 up to the chosen value will only be affected within the Finer levels luminance range.\nAll other levels will have the whole range of luminances affected, unless the Coarser levels setting limits it.\nThe chosen value in this slider becomes the minimum possible value of the Coarser 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). : Only levels between the chosen value and level 9/Extra will be affected by the Coarser levels luminance range.\nAll other levels will have the whole range of luminances affected, unless the Finer levels setting limits it.\nThe lower level possible that will be considered by the algorithm is limited by the Finer levels value. -TP_WAVELET_THRESWAV;Balance Threshold +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_THRESHOLD_TOOLTIP;Only levels below and including the chosen value will be affected by the Highlight luminance range. +TP_WAVELET_THRESWAV;Balance threshold TP_WAVELET_THRH;Highlights threshold TP_WAVELET_TILESBIG;Tiles TP_WAVELET_TILESFULL;Full image TP_WAVELET_TILESIZE;Tiling method TP_WAVELET_TILESLIT;Little tiles TP_WAVELET_TILES_TOOLTIP;Processing the full image leads to better quality and is the recommended option, while using tiles is a fall-back solution for users with little RAM. Refer to RawPedia for memory requirements. -TP_WAVELET_BL;Blur levels TP_WAVELET_TMEDGS;Edge stopping TP_WAVELET_TMSCALE;Scale 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_TON;Toning +TP_WAVELET_TONFRAME;Excluded colors TP_WAVELET_USH;None TP_WAVELET_USHARP;Clarity method TP_WAVELET_USHARP_TOOLTIP;Origin : the source file is the file before Wavelet.\nWavelet : the source file is the file including wavelet threatment -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_USH_TOOLTIP;If you select Sharp-mask, you can choose any level (in Settings) from 1 to 4 for processing.\nIf you select Clarity, you can choose any level (in Settings) between 5 and Extra. 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_WBALANCE_AUTO;Auto TP_WBALANCE_AUTOITCGREEN;Temperature correlation TP_WBALANCE_AUTOOLD;RGB grey @@ -2424,3 +3716,7 @@ ZOOMPANEL_ZOOMFITCROPSCREEN;Fit crop to screen\nShortcut: f ZOOMPANEL_ZOOMFITSCREEN;Fit whole image to screen\nShortcut: Alt-f ZOOMPANEL_ZOOMIN;Zoom In\nShortcut: + ZOOMPANEL_ZOOMOUT;Zoom Out\nShortcut: - +//TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM02 color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nOnly the third Ciecam process (Viewing conditions - Target) is taken into account, as well as part of the second (contrast J, saturation s) , as well as some data from the first process (Scene conditions - Source) which is used for the Log encoding.\nIt also adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. +//TP_WAVELET_DENH;Low levels (1234)- Finest details +//TP_WAVELET_DENL;High levels - Coarsest details +//TP_WAVELET_DENLH;Guided threshold by detail levels 1-4 diff --git a/rtdata/profiles/Film Negative.pp3 b/rtdata/profiles/Film Negative.pp3 new file mode 100644 index 000000000..c298a6ea9 --- /dev/null +++ b/rtdata/profiles/Film Negative.pp3 @@ -0,0 +1,35 @@ +[Exposure] +Auto=false +Compensation=0 +HistogramMatching=false +CurveFromHistogramMatching=false +ClampOOG=false +CurveMode=Standard +CurveMode2=Standard +Curve=1;0;0;0.88544601940051371;1; +Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419974733677647;1;1; + +[HLRecovery] +Enabled=false +Method=Blend + +[Color Management] +InputProfile=(camera) +ToneCurve=false +ApplyLookTable=false +ApplyHueSatMap=false +WorkingProfile=Rec2020 +WorkingTRC=none + +[RAW Bayer] +Method=rcd + +[Film Negative] +Enabled=true +RedRatio=1.360 +GreenExponent=1.5 +BlueRatio=0.86 +ColorSpace=1 +RefInput=0;0;0; +RefOutput=0;0;0; +BackCompat=0 diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index bdadc00db..f4f9ddb7f 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -720,6 +720,36 @@ flowboxchild:selected { margin: 0; } +/* Vertical version of slider. */ +#histScale { + min-height: 4em; + min-width: 0.4166666666666666em; + margin: 0.5833333333333333em 0 0 0; +} +#histScale trough { + padding: 0.583333333333333333em 0; +} +#histScale trough highlight { + margin: -0.583333333333333333em 0; + padding: 0.1em 0 0 0.1em; +} +#histScale.fine-tune trough highlight { + padding: 0.5em 0 0 0.5em; +} + +/* Copied from button.flat style. */ +button.radio#histButton { + background-image: none; +} + +button.radio#histButton:checked { + background-image: linear-gradient(#343434, #2E2E2E, #292929); +} + +button.radio#histButton:hover { + background-image: linear-gradient(shade(#343434,1.3), shade(#2E2E2E,1.3), shade(#292929,1.3)); +} + /*** end ***************************************************************************************/ #MyExpander { @@ -745,6 +775,7 @@ flowboxchild:selected { background-color: #363636; } +#LocallabToolPanel frame, #ExpanderBox frame, #ExpanderBox2 frame, #ExpanderBox3 frame { @@ -761,18 +792,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 +831,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 +840,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 +854,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 +868,7 @@ flowboxchild:selected { padding: 0.25em; } +#LocallabToolPanel frame frame drawingarea, #ExpanderBox2 frame frame drawingarea { background-color: #474747; } @@ -854,7 +895,7 @@ flowboxchild:selected { color: #D8D8D8; } -#ExpanderBox2 separator, #ExpanderBox3 separator { +#LocallabToolPanel separator, #ExpanderBox2 separator, #ExpanderBox3 separator { color: #292929; } diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index ce4bb8d28..c4300413e 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -454,6 +454,47 @@ filechooser placessidebar list row:selected { margin: 0; } +/* Vertical version of slider. */ +#histScale { + min-height: 4em; + min-width: 1.833333333333333333em; + margin: -0.333333333333333333em 0; +} +#histScale trough { + padding: 0.583333333333333333em 0; +} +#histScale highlight { + background-image: linear-gradient(to right, shade (@accent-color2,1.22), shade(@accent-color2,.88)); + margin: -0.583333333333333333em 0; + padding: 0.333333333333333333em 0 0 0.333333333333333333em; +} +#histScale slider { +} +#histScale.fine-tune highlight { + padding: 0.5em 0 0 0.5em; +} + +/* Copied from button.flat style. */ +button.radio#histButton { + border: 0.083333333333333333em solid transparent; + box-shadow: none; + background-image: none; + background-color: transparent; +} +button.radio#histButton:hover { + border-color: @bg-button-border; + box-shadow: inset 0 0.083333333333333333em rgba(242, 242, 242, 0.1); + background-image: linear-gradient(to bottom, rgba(100,100,100,.3), rgba(30,30,30,.3)); + background-color: @bg-button-hover; +} +button.radio#histButton:active, +button.radio#histButton:checked { + border-color: @bg-button-border; + box-shadow: inset 0 0.1em rgba(242, 242, 242, 0.08); + background-image: linear-gradient(to bottom, rgba(100,100,100,.3), rgba(30,30,30,.3)); + background-color: @bg-button-active; +} + /*** end ***************************************************************************************/ /*** Separator *********************************************************************************/ diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index fa9788af0..c17826623 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -123,7 +123,7 @@ float* RawImageSource::CA_correct_RT( double cared, double cablue, bool avoidColourshift, - const array2D &rawData, + array2D &rawData, double* fitParamsTransfer, bool fitParamsIn, bool fitParamsOut, @@ -1291,7 +1291,7 @@ float* RawImageSource::CA_correct_RT( for (int i = 0; i < H - 2 * cb; ++i) { const int firstCol = fc(cfa, i, 0) & 1; const int colour = fc(cfa, i, firstCol); - const array2D* nonGreen = colour == 0 ? redFactor : blueFactor; + array2D* nonGreen = colour == 0 ? redFactor : blueFactor; int j = firstCol; #ifdef __SSE2__ for (; j < W - 7 - 2 * cb; j += 8) { @@ -1325,7 +1325,7 @@ float* RawImageSource::CA_correct_RT( const int ngRow = 1 - (fc(cfa, 0, 0) & 1); const int ngCol = fc(cfa, ngRow, 0) & 1; const int colour = fc(cfa, ngRow, ngCol); - const array2D* nonGreen = colour == 0 ? redFactor : blueFactor; + array2D* nonGreen = colour == 0 ? redFactor : blueFactor; for (int i = 0; i < (H + 1 - 2 * cb) / 2; ++i) { (*nonGreen)[i][(W - 2 * cb + 1) / 2 - 1] = (*nonGreen)[i][(W - 2* cb + 1) / 2 - 2]; } diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index c687c1cb1..c5b18d2fb 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -64,6 +64,7 @@ set(RTENGINESOURCEFILES ahd_demosaic_RT.cc amaze_demosaic_RT.cc badpixels.cc + bayer_bilinear_demosaic.cc boxblur.cc canon_cr3_decoder.cc CA_correct_RT.cc @@ -94,7 +95,6 @@ set(RTENGINESOURCEFILES fast_demo.cc ffmanager.cc filmnegativeproc.cc - filmnegativethumb.cc flatcurves.cc FTblockDN.cc gamutwarning.cc @@ -118,7 +118,9 @@ set(RTENGINESOURCEFILES impulse_denoise.cc init.cc ipdehaze.cc + ipgrain.cc iplab2rgb.cc + iplocallab.cc iplabregions.cc iplocalcontrast.cc ipresize.cc @@ -141,6 +143,7 @@ set(RTENGINESOURCEFILES myfile.cc panasonic_decoders.cc pdaflinesfilter.cc + perspectivecorrection.cc PF_correct_RT.cc pipettebuffer.cc pixelshift.cc diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 04459e88a..5ae023122 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -4,6 +4,7 @@ #ifdef _OPENMP #include #endif +#include "rt_algo.h" #include "sleef.h" #define DIAGONALS 5 @@ -42,21 +43,13 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl //s is preconditionment of r. Without, direct to r. float *s = r; - double rs = 0.0; // use double precision for large summations if(Preconditioner != nullptr) { s = new float[n]; - Preconditioner(s, r, Pass); } -#ifdef _OPENMP - #pragma omp parallel for reduction(+:rs) // removed schedule(dynamic,10) -#endif - - for(int ii = 0; ii < n; ii++) { - rs += static_cast(r[ii]) * static_cast(s[ii]); - } + double rs = rtengine::accumulateProduct(r, s, n); //Search direction d. float *d = (buffer + n + 32); @@ -77,16 +70,9 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl for(iterate = 0; iterate < MaximumIterates; iterate++) { //Get step size alpha, store ax while at it. - double ab = 0.0; // use double precision for large summations Ax(ax, d, Pass); -#ifdef _OPENMP - #pragma omp parallel for reduction(+:ab) -#endif - - for(int ii = 0; ii < n; ii++) { - ab += static_cast(d[ii]) * static_cast(ax[ii]); - } + double ab = rtengine::accumulateProduct(d, ax, n); if(ab == 0.0) { break; //So unlikely. It means perfectly converged or singular, stop either way. } @@ -118,22 +104,7 @@ float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), fl //Get beta. ab = rs; - rs = 0.0f; - -#ifdef _OPENMP - #pragma omp parallel -#endif - { -#ifdef _OPENMP - #pragma omp for reduction(+:rs) -#endif - - for(int ii = 0; ii < n; ii++) { - rs += static_cast(r[ii]) * static_cast(s[ii]); - } - - } - + rs = rtengine::accumulateProduct(r, s, n); ab = rs / ab; abf = ab; //Update search direction p. @@ -916,7 +887,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 +910,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 89e4c1b8d..66f12b668 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) { @@ -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 @@ -2121,26 +2099,26 @@ float ImProcFunctions::Mad(const float * DataList, const int datalen) } //computes Median Absolute Deviation - //DataList values should mostly have abs val < 256 because we are in Lab mode - int histo[256] ALIGNED64 = {0}; + //DataList values should mostly have abs val < 256 because we are in Lab mode (32768) + int histo[32768] ALIGNED64 = {0}; //calculate histogram of absolute values of wavelet coeffs for (int i = 0; i < datalen; ++i) { - histo[static_cast(rtengine::min(255.f, fabsf(DataList[i])))]++; + histo[static_cast(rtengine::min(32768.f, fabsf(DataList[i])))]++; } //find median of histogram - int median = 0, count = 0; + int lmedian = 0, count = 0; while (count < datalen / 2) { - count += histo[median]; - ++median; + count += histo[lmedian]; + ++lmedian; } - int count_ = count - histo[median - 1]; + int count_ = count - histo[lmedian - 1]; // interpolate - return (((median - 1) + (datalen / 2 - count_) / (static_cast(count - count_))) / 0.6745f); + return ((lmedian - 1) + (datalen / 2 - count_) / (static_cast(count - count_))) / 0.6745f; } float ImProcFunctions::MadRgb(const float * DataList, const int datalen) @@ -2163,18 +2141,18 @@ float ImProcFunctions::MadRgb(const float * DataList, const int datalen) } //find median of histogram - int median = 0, count = 0; + int lmedian = 0, count = 0; while (count < datalen / 2) { - count += histo[median]; - ++median; + count += histo[lmedian]; + ++lmedian; } - int count_ = count - histo[median - 1]; + int count_ = count - histo[lmedian - 1]; // interpolate delete[] histo; - return (((median - 1) + (datalen / 2 - count_) / (static_cast(count - count_))) / 0.6745f); + return ((lmedian - 1) + (datalen / 2 - count_) / (static_cast(count - count_))) / 0.6745f; } @@ -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,7 +2187,7 @@ 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; @@ -2218,6 +2196,10 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &W maxlvl = 4; //for refine denoise edge wavelet } + if (edge == 6) { + maxlvl = 6; //for wavelet denoise + } + if (edge == 2) { maxlvl = 7; //for locallab denoise } @@ -2260,7 +2242,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 +2268,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 || edge == 5) && vari) { + if ((edge == 1 || edge == 2 || edge == 3 || edge == 5 || edge == 6) && 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 +2276,7 @@ bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(const wavelet_decomposition &W } } - if (edge == 2 || edge == 4 || edge == 5) { + if (edge == 2 || edge == 4 || edge == 5 || edge == 6) { for (int i = 0; i < Hlvl_L * Wlvl_L; ++i) { nvl[i] = vari[lvl] * SQR(noisevarlum[i]); } @@ -2392,10 +2374,15 @@ 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(); + printf("Ftblockdn ab bishrink\n"); + + if (local == 1) { + maxlvl = 6; //for local denoise + } + if (local == 2) { maxlvl = 7; //for local denoise @@ -2449,7 +2436,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,10 +2455,11 @@ 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) { + //printf("Shrink ab bis\n"); ShrinkAllAB(WaveletCoeffs_L, WaveletCoeffs_ab, buffer, lvl, dir, noisevarchrom, noisevar_ab, useNoiseCCurve, autoch, denoiseMethodRgb, madL[lvl], nullptr, 0, madab[lvl], true); } else { //simple wavelet shrinkage @@ -2563,7 +2551,7 @@ 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 { @@ -2573,6 +2561,10 @@ bool ImProcFunctions::WaveletDenoiseAllL(const wavelet_decomposition &WaveletCoe maxlvl = 4; //for refine denoise edge wavelet } + if (edge == 6) { + maxlvl = 6; //for wavelet denoise + } + if (edge == 2) { maxlvl = 7; //for locallab denoise } @@ -2588,7 +2580,6 @@ bool ImProcFunctions::WaveletDenoiseAllL(const wavelet_decomposition &WaveletCoe maxHL = WaveletCoeffs_L.level_H(lvl); } } - bool memoryAllocationFailed = false; #ifdef _OPENMP #pragma omp parallel num_threads(denoiseNestedLevels) if (denoiseNestedLevels>1) @@ -2624,13 +2615,17 @@ 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 { - int maxlvl = WaveletCoeffs_L.maxlevel(); + if (local == 1) { + maxlvl = 6; //for local denoise + } + + if (local == 2) { maxlvl = 7; //for local denoise } @@ -2688,7 +2683,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 +2697,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,15 +2708,15 @@ void ImProcFunctions::ShrinkAllL(const wavelet_decomposition &WaveletCoeffs_L, f nvl[i] = 0.f; } - if ((edge == 1 || edge == 2 || edge == 3 || edge == 5) && vari) { + if ((edge == 1 || edge == 2 || edge == 3 || edge == 5 || edge == 6) && 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) { nvl[i] = vari[level]; //* SQR(1.f + 4.f * noisevarchrom[p]); } - } + } - if (edge == 2 || edge == 4 || edge == 5) { + if (edge == 2 || edge == 4 || edge == 5 || edge == 6) { for (int i = 0; i < W_L * H_L; ++i) { nvl[i] = vari[level] * SQR(noisevarlum[i]); } @@ -2779,7 +2774,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 +2793,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 +2913,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 +3043,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/LUT.h b/rtengine/LUT.h index 6ba7d570f..416ae689a 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -58,9 +58,11 @@ #pragma once +#include #include #include #include +#include #ifndef NDEBUG #include @@ -138,6 +140,33 @@ public: clear(); } } + + LUT(const std::vector& input, int flags = LUT_CLIP_BELOW | LUT_CLIP_ABOVE) : + maxs(input.size() - 2), + maxsf(maxs), + data(new T[input.size() + 3]), // Add a few extra elements so [](vfloat) won't access out-of-bounds memory. + clip(flags), + size(input.size()), + upperBound(size - 1), + owner(1), +#ifdef __SSE2__ + maxsv(F2V(maxs)), + sizev(F2V(size - 1)), + sizeiv(_mm_set1_epi32(size - 1)), +#endif + dirty(true) + { +#ifndef NDEBUG + + if (input.empty()) { + printf("s=0!\n"); + } + + assert(!input.empty()); +#endif + std::copy_n(input.begin(), input.size(), data); + } + void operator ()(int s, int flags = LUT_CLIP_BELOW | LUT_CLIP_ABOVE, bool initZero = false) { #ifndef NDEBUG @@ -223,7 +252,7 @@ public: return size > 0 ? upperBound : 0; } - LUT & operator=(const LUT& rhs) + LUT& operator=(const LUT& rhs) { if (this != &rhs) { if (rhs.size > this->size) { @@ -254,7 +283,7 @@ public: } // handy to sum up per thread histograms. #pragma omp simd speeds up the loop by about factor 3 for LUTu (uint32_t). - LUT & operator+=(const LUT& rhs) + LUT& operator+=(const LUT& rhs) { if (rhs.size == this->size) { #ifdef _OPENMP @@ -271,7 +300,7 @@ public: // multiply all elements of LUT with a constant float value template::value>::type> - LUT & operator*=(float factor) + LUT& operator*=(float factor) { #ifdef _OPENMP #pragma omp simd @@ -286,7 +315,7 @@ public: // divide all elements of LUT by a constant float value template::value>::type> - LUT & operator/=(float divisor) + LUT& operator/=(float divisor) { #ifdef _OPENMP #pragma omp simd @@ -456,7 +485,7 @@ public: // Return the value for "index" that is in the [0-1] range. template::value>::type> - T getVal01 (float index) const + T getVal01(float index) const { index *= (float)upperBound; int idx = (int)index; // don't use floor! The difference in negative space is no problems here @@ -481,19 +510,19 @@ public: return (p1 + p2 * diff); } - operator bool (void) const + operator bool() const // FIXME: Should be explicit { return size > 0; } - void clear(void) + void clear() { if (data && size) { memset(data, 0, size * sizeof(T)); } } - void reset(void) + void reset() { if (data) { delete[] data; diff --git a/rtengine/array2D.h b/rtengine/array2D.h index de6381aeb..ca4db3d06 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -27,7 +27,7 @@ * * creates an array which is valid within the normal C/C++ scope "{ ... }" * - * access to elements is a simple as: + * access to elements is as simple as: * * array2D my_array (10,10); // creates 10x10 array of floats * value = my_array[3][5]; @@ -48,275 +48,216 @@ * array2D my_array ; // empty container. * my_array(10,10) ; // resize to 10x10 array * my_array(10,10,ARRAY2D_CLEAR_DATA) ; // resize to 10x10 and clear data - * my_array(10,10,ARRAY2D_CLEAR_DATA|ARRAY2D_LOCK_DATA) ; same but set a lock on changes * - * !! locked arrays cannot be resized and cannot be unlocked again !! */ #pragma once -#include // for raise() #include - -// flags for use -#define ARRAY2D_LOCK_DATA 1 -#define ARRAY2D_CLEAR_DATA 2 -#define ARRAY2D_BYREFERENCE 4 -#define ARRAY2D_VERBOSE 8 - #include -#include - +#include +#include #include "noncopyable.h" +// flags for use +constexpr unsigned int ARRAY2D_CLEAR_DATA = 1; +constexpr unsigned int ARRAY2D_BYREFERENCE = 2; + + template -class array2D : - public rtengine::NonCopyable +class array2D { private: - int x, y, owner; - unsigned int flags; - T ** ptr; - T * data; - bool lock; // useful lock to ensure data is not changed anymore. - void ar_realloc(int w, int h, int offset = 0) + ssize_t width; + std::vector rows; + std::vector buffer; + + void initRows(ssize_t h, int offset = 0) { - if ((ptr) && ((h > y) || (4 * h < y))) { - delete[] ptr; - ptr = nullptr; + rows.resize(h); + T* start = buffer.data() + offset; + for (ssize_t i = 0; i < h; ++i) { + rows[i] = start + width * i; } + } - if ((data) && (((h * w) > (x * y)) || ((h * w) < ((x * y) / 4)))) { - delete[] data; - data = nullptr; - } - - if (ptr == nullptr) { - ptr = new T*[h]; - } - - if (data == nullptr) { - data = new T[h * w + offset]; - } - - x = w; - y = h; - - for (int i = 0; i < h; i++) { - ptr[i] = data + offset + w * i; - } - - owner = 1; + void ar_realloc(ssize_t w, ssize_t h, int offset = 0) + { + width = w; + buffer.resize(h * width + offset); + initRows(h, offset); } public: // use as empty declaration, resize before use! // very useful as a member object - array2D() : - x(0), y(0), owner(0), flags(0), ptr(nullptr), data(nullptr), lock(false) - { - //printf("got empty array2D init\n"); - } + array2D() : width(0) {} // creator type1 - array2D(int w, int h, unsigned int flgs = 0) + array2D(int w, int h, unsigned int flags = 0) : width(w) { - flags = flgs; - lock = flags & ARRAY2D_LOCK_DATA; - data = new T[h * w]; - owner = 1; - x = w; - y = h; - ptr = new T*[h]; - - for (int i = 0; i < h; i++) { - ptr[i] = data + i * w; - } - if (flags & ARRAY2D_CLEAR_DATA) { - memset(data, 0, w * h * sizeof(T)); + buffer.resize(h * width, 0); + } else { + buffer.resize(h * width); } + initRows(h); } // creator type 2 - array2D(int w, int h, T ** source, unsigned int flgs = 0) + array2D(int w, int h, T ** source, unsigned int flags = 0) : width(w) { - flags = flgs; - //if (lock) { printf("array2D attempt to overwrite data\n");raise(SIGSEGV);} - lock = flags & ARRAY2D_LOCK_DATA; - // when by reference - // TODO: improve this code with ar_realloc() - owner = (flags & ARRAY2D_BYREFERENCE) ? 0 : 1; - - if (owner) { - data = new T[h * w]; - } else { - data = nullptr; - } - - x = w; - y = h; - ptr = new T*[h]; - - for (int i = 0; i < h; i++) { - if (owner) { - ptr[i] = data + i * w; - - for (int j = 0; j < w; j++) { - ptr[i][j] = source[i][j]; + rows.resize(h); + if (!(flags & ARRAY2D_BYREFERENCE)) { + buffer.resize(h * width); + T* start = buffer.data(); + for (ssize_t i = 0; i < h; ++i) { + rows[i] = start + i * width; + for (ssize_t j = 0; j < width; ++j) { + rows[i][j] = source[i][j]; } - } else { - ptr[i] = source[i]; + } + } else { + for (ssize_t i = 0; i < h; ++i) { + rows[i] = source[i]; } } } - // destructor - ~array2D() + array2D(const array2D& other) : + width(other.width), + buffer(other.buffer) { + initRows(other.rows.size()); + } - if (flags & ARRAY2D_VERBOSE) { - printf(" deleting array2D size %dx%d \n", x, y); + array2D& operator =(const array2D& other) + { + if (this != &other) { + free(); + width = other.width; + buffer = other.buffer; + initRows(other.rows.size()); } - if ((owner) && (data)) { - delete[] data; - } - - if (ptr) { - delete[] ptr; - } + return *this; } void fill(const T val, bool multiThread = false) { + const ssize_t height = rows.size(); #ifdef _OPENMP #pragma omp parallel for if(multiThread) #endif - for (int i = 0; i < x * y; ++i) { - data[i] = val; + for (ssize_t i = 0; i < width * height; ++i) { + buffer[i] = val; } } void free() { - if ((owner) && (data)) { - delete[] data; - data = nullptr; - } - - if (ptr) { - delete [] ptr; - ptr = nullptr; - } + buffer.clear(); + rows.clear(); + width = 0; } // use with indices - T * operator[](int index) const + T * operator[](int index) { - assert((index >= 0) && (index < y)); - return ptr[index]; + assert((index >= 0) && (index < rows.size())); + return rows[index]; + } + + const T * operator[](int index) const + { + assert((index >= 0) && (index < rows.size())); + return rows[index]; } // use as pointer to T** operator T**() { - return ptr; + return rows.data(); } // use as pointer to T** - operator const T* const *() + operator const T* const *() const { - return ptr; + return rows.data(); } - // use as pointer to data + // use as pointer to buffer operator T*() { // only if owner this will return a valid pointer - return data; + return buffer.data(); + } + + operator const T*() const + { + // only if owner this will return a valid pointer + return buffer.data(); } // useful within init of parent object // or use as resize of 2D array - void operator()(int w, int h, unsigned int flgs = 0, int offset = 0) + void operator()(int w, int h, unsigned int flags = 0, int offset = 0) { - flags = flgs; - - if (flags & ARRAY2D_VERBOSE) { - printf("got init request %dx%d flags=%u\n", w, h, flags); - printf("previous was data %p ptr %p \n", data, ptr); - } - - if (lock) { // our object was locked so don't allow a change. - printf("got init request but object was locked!\n"); - raise( SIGSEGV); - } - - lock = flags & ARRAY2D_LOCK_DATA; - ar_realloc(w, h, offset); if (flags & ARRAY2D_CLEAR_DATA) { - memset(data + offset, 0, static_cast(w) * h * sizeof(T)); + fill(0); } } - // import from flat data - void operator()(int w, int h, T* copy, unsigned int flgs = 0) + array2D& operator+=(const array2D& rhs) { - flags = flgs; + if (rhs.getWidth() == this->getWidth() && rhs.getHeight() == this->getHeight()) { + for (int i = 0; i < getHeight(); ++i) { +#ifdef _OPENMP + #pragma omp simd +#endif - if (flags & ARRAY2D_VERBOSE) { - printf("got init request %dx%d flags=%u\n", w, h, flags); - printf("previous was data %p ptr %p \n", data, ptr); + for (int j = 0; j < getWidth(); ++j) { + rows[i][j] += rhs[i][j]; + } + } } - if (lock) { // our object was locked so don't allow a change. - printf("got init request but object was locked!\n"); - raise( SIGSEGV); - } - - lock = flags & ARRAY2D_LOCK_DATA; - - ar_realloc(w, h); - memcpy(data, copy, w * h * sizeof(T)); + return *this; } - int width() const + + + int getWidth() const { - return x; + return width; } - int height() const + int getHeight() const { - return y; + return rows.size(); } operator bool() { - return (x > 0 && y > 0); + return (width > 0 && !rows.empty()); } }; template -class multi_array2D +class multi_array2D : public rtengine::NonCopyable { private: array2D list[num]; public: - multi_array2D(int x, int y, int flags = 0, int offset = 0) + multi_array2D(int width, int height, int flags = 0, int offset = 0) { - for (size_t i = 0; i < num; i++) { - list[i](x, y, flags, (i + 1) * offset); + for (size_t i = 0; i < num; ++i) { + list[i](width, height, flags, (i + 1) * offset); } } - ~multi_array2D() - { - //printf("trying to delete the list of array2D objects\n"); - } - array2D & operator[](int index) { assert(static_cast(index) < num); diff --git a/rtengine/ashift_dt.c b/rtengine/ashift_dt.c new file mode 100644 index 000000000..ce19b6808 --- /dev/null +++ b/rtengine/ashift_dt.c @@ -0,0 +1,5132 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Alberto Griggio + * + * 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 . + */ + +using namespace std; + +// taken from darktable (src/iop/ashift.c) +/* + This file is part of darktable, + copyright (c) 2016 Ulrich Pegelow. + + 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 . +*/ + +// Inspiration to this module comes from the program ShiftN (http://www.shiftn.de) by +// Marcus Hebel. + +// Thanks to Marcus for his support when implementing part of the ShiftN functionality +// to darktable. + +#define ROTATION_RANGE 10 // allowed min/max default range for rotation parameter +#define ROTATION_RANGE_SOFT 20 // allowed min/max range for rotation parameter with manual adjustment +#define LENSSHIFT_RANGE 0.5 // allowed min/max default range for lensshift parameters +#define LENSSHIFT_RANGE_SOFT 1 // allowed min/max range for lensshift parameters with manual adjustment +#define SHEAR_RANGE 0.2 // allowed min/max range for shear parameter +#define SHEAR_RANGE_SOFT 0.5 // allowed min/max range for shear parameter with manual adjustment +#define CAMERA_ANGLE_RANGE_SOFT 80 +#define MIN_LINE_LENGTH 5 // the minimum length of a line in pixels to be regarded as relevant +#define MAX_TANGENTIAL_DEVIATION 30 // by how many degrees a line may deviate from the +/-180 and +/-90 to be regarded as relevant +#define LSD_SCALE 0.99 // LSD: scaling factor for line detection +#define LSD_SIGMA_SCALE 0.6 // LSD: sigma for Gaussian filter is computed as sigma = sigma_scale/scale +#define LSD_QUANT 2.0 // LSD: bound to the quantization error on the gradient norm +#define LSD_ANG_TH 22.5 // LSD: gradient angle tolerance in degrees +#define LSD_LOG_EPS 0.0 // LSD: detection threshold: -log10(NFA) > log_eps +#define LSD_DENSITY_TH 0.7 // LSD: minimal density of region points in rectangle +#define LSD_N_BINS 1024 // LSD: number of bins in pseudo-ordering of gradient modulus +#define LSD_GAMMA 0.45 // gamma correction to apply on raw images prior to line detection +#define RANSAC_RUNS 400 // how many iterations to run in ransac +#define RANSAC_EPSILON 2 // starting value for ransac epsilon (in -log10 units) +#define RANSAC_EPSILON_STEP 1 // step size of epsilon optimization (log10 units) +#define RANSAC_ELIMINATION_RATIO 60 // percentage of lines we try to eliminate as outliers +#define RANSAC_OPTIMIZATION_STEPS 5 // home many steps to optimize epsilon +#define RANSAC_OPTIMIZATION_DRY_RUNS 50 // how man runs per optimization steps +#define RANSAC_HURDLE 5 // hurdle rate: the number of lines below which we do a complete permutation instead of random sampling +#define MINIMUM_FITLINES 4 // minimum number of lines needed for automatic parameter fit +#define NMS_EPSILON 1e-3 // break criterion for Nelder-Mead simplex +#define NMS_SCALE 1.0 // scaling factor for Nelder-Mead simplex +#define NMS_ITERATIONS 400 // number of iterations for Nelder-Mead simplex +#define NMS_CROP_EPSILON 100.0 // break criterion for Nelder-Mead simplex on crop fitting +#define NMS_CROP_SCALE 0.5 // scaling factor for Nelder-Mead simplex on crop fitting +#define NMS_CROP_ITERATIONS 100 // number of iterations for Nelder-Mead simplex on crop fitting +#define NMS_ALPHA 1.0 // reflection coefficient for Nelder-Mead simplex +#define NMS_BETA 0.5 // contraction coefficient for Nelder-Mead simplex +#define NMS_GAMMA 2.0 // expansion coefficient for Nelder-Mead simplex +#define DEFAULT_F_LENGTH 28.0 // focal length we assume if no exif data are available + +/* // define to get debugging output */ +/* #undef ASHIFT_DEBUG */ + +#define SQR(a) ((a) * (a)) + +// For line detection we use the LSD algorithm as published by Rafael Grompone: +// +// "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, +// Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, +// Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd +// http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd +#include "ashift_lsd.c" + +// For parameter optimization we are using the Nelder-Mead simplex method +// implemented by Michael F. Hutt. +#include "ashift_nmsimplex.c" + +#include "homogeneouscoordinates.h" + + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +DT_MODULE_INTROSPECTION(4, dt_iop_ashift_params_t) + + +const char *name() +{ + return _("perspective correction"); +} + +int flags() +{ + return IOP_FLAGS_ALLOW_TILING | IOP_FLAGS_TILING_FULL_ROI | IOP_FLAGS_ONE_INSTANCE; +} + +int groups() +{ + return dt_iop_get_group("perspective correction", IOP_GROUP_CORRECT); +} + +int operation_tags() +{ + return IOP_TAG_DISTORT; +} + +int operation_tags_filter() +{ + // switch off clipping and decoration, we want to see the full image. + return IOP_TAG_DECORATION | IOP_TAG_CLIPPING; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +typedef enum dt_iop_ashift_homodir_t +{ + ASHIFT_HOMOGRAPH_FORWARD, + ASHIFT_HOMOGRAPH_INVERTED +} dt_iop_ashift_homodir_t; + +//typedef enum dt_iop_ashift_linetype_t +enum +{ + ASHIFT_LINE_IRRELEVANT = 0, // the line is found to be not interesting + // eg. too short, or not horizontal or vertical + ASHIFT_LINE_RELEVANT = 1 << 0, // the line is relevant for us + ASHIFT_LINE_DIRVERT = 1 << 1, // the line is (mostly) vertical, else (mostly) horizontal + ASHIFT_LINE_SELECTED = 1 << 2, // the line is selected for fitting + ASHIFT_LINE_VERTICAL_NOT_SELECTED = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_DIRVERT, + ASHIFT_LINE_HORIZONTAL_NOT_SELECTED = ASHIFT_LINE_RELEVANT, + ASHIFT_LINE_VERTICAL_SELECTED = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_DIRVERT | ASHIFT_LINE_SELECTED, + ASHIFT_LINE_HORIZONTAL_SELECTED = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED, + ASHIFT_LINE_MASK = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_DIRVERT | ASHIFT_LINE_SELECTED +}; //dt_iop_ashift_linetype_t; +typedef unsigned int dt_iop_ashift_linetype_t; + +typedef enum dt_iop_ashift_linecolor_t +{ + ASHIFT_LINECOLOR_GREY = 0, + ASHIFT_LINECOLOR_GREEN = 1, + ASHIFT_LINECOLOR_RED = 2, + ASHIFT_LINECOLOR_BLUE = 3, + ASHIFT_LINECOLOR_YELLOW = 4 +} dt_iop_ashift_linecolor_t; + +//typedef enum dt_iop_ashift_fitaxis_t +enum +{ + ASHIFT_FIT_NONE = 0, // none + ASHIFT_FIT_ROTATION = 1 << 0, // flag indicates to fit rotation angle + ASHIFT_FIT_LENS_VERT = 1 << 1, // flag indicates to fit vertical lens shift + ASHIFT_FIT_LENS_HOR = 1 << 2, // flag indicates to fit horizontal lens shift + ASHIFT_FIT_SHEAR = 1 << 3, // flag indicates to fit shear parameter + ASHIFT_FIT_LINES_VERT = 1 << 4, // use vertical lines for fitting + ASHIFT_FIT_LINES_HOR = 1 << 5, // use horizontal lines for fitting + ASHIFT_FIT_LENS_BOTH = ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LENS_HOR, + ASHIFT_FIT_LINES_BOTH = ASHIFT_FIT_LINES_VERT | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_VERTICALLY = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LINES_VERT, + ASHIFT_FIT_HORIZONTALLY = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LENS_HOR | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_BOTH = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LENS_HOR | + ASHIFT_FIT_LINES_VERT | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_VERTICALLY_NO_ROTATION = ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LINES_VERT, + ASHIFT_FIT_HORIZONTALLY_NO_ROTATION = ASHIFT_FIT_LENS_HOR | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_BOTH_NO_ROTATION = ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LENS_HOR | + ASHIFT_FIT_LINES_VERT | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_BOTH_SHEAR = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LENS_HOR | + ASHIFT_FIT_SHEAR | ASHIFT_FIT_LINES_VERT | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_ROTATION_VERTICAL_LINES = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LINES_VERT, + ASHIFT_FIT_ROTATION_HORIZONTAL_LINES = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_ROTATION_BOTH_LINES = ASHIFT_FIT_ROTATION | ASHIFT_FIT_LINES_VERT | ASHIFT_FIT_LINES_HOR, + ASHIFT_FIT_FLIP = ASHIFT_FIT_LENS_VERT | ASHIFT_FIT_LENS_HOR | ASHIFT_FIT_LINES_VERT | ASHIFT_FIT_LINES_HOR +}; //dt_iop_ashift_fitaxis_t; +typedef unsigned int dt_iop_ashift_fitaxis_t; + +typedef enum dt_iop_ashift_nmsresult_t +{ + NMS_SUCCESS = 0, + NMS_NOT_ENOUGH_LINES = 1, + NMS_DID_NOT_CONVERGE = 2, + NMS_INSANE = 3 +} dt_iop_ashift_nmsresult_t; + +typedef enum dt_iop_ashift_enhance_t +{ + ASHIFT_ENHANCE_NONE = 0, + ASHIFT_ENHANCE_EDGES = 1 << 0, + ASHIFT_ENHANCE_DETAIL = 1 << 1, + ASHIFT_ENHANCE_HORIZONTAL = 0x100, + ASHIFT_ENHANCE_VERTICAL = 0x200 +} dt_iop_ashift_enhance_t; + +typedef enum dt_iop_ashift_mode_t +{ + ASHIFT_MODE_GENERIC = 0, + ASHIFT_MODE_SPECIFIC = 1 +} dt_iop_ashift_mode_t; + +typedef enum dt_iop_ashift_crop_t +{ + ASHIFT_CROP_OFF = 0, + ASHIFT_CROP_LARGEST = 1, + ASHIFT_CROP_ASPECT = 2 +} dt_iop_ashift_crop_t; + +typedef enum dt_iop_ashift_bounding_t +{ + ASHIFT_BOUNDING_OFF = 0, + ASHIFT_BOUNDING_SELECT = 1, + ASHIFT_BOUNDING_DESELECT = 2 +} dt_iop_ashift_bounding_t; + +typedef enum dt_iop_ashift_jobcode_t +{ + ASHIFT_JOBCODE_NONE = 0, + ASHIFT_JOBCODE_GET_STRUCTURE = 1, + ASHIFT_JOBCODE_FIT = 2 +} dt_iop_ashift_jobcode_t; + +typedef struct dt_iop_ashift_params1_t +{ + float rotation; + float lensshift_v; + float lensshift_h; + int toggle; +} dt_iop_ashift_params1_t; + +typedef struct dt_iop_ashift_params2_t +{ + float rotation; + float lensshift_v; + float lensshift_h; + float f_length; + float crop_factor; + float orthocorr; + float aspect; + dt_iop_ashift_mode_t mode; + int toggle; +} dt_iop_ashift_params2_t; + +typedef struct dt_iop_ashift_params3_t +{ + float rotation; + float lensshift_v; + float lensshift_h; + float f_length; + float crop_factor; + float orthocorr; + float aspect; + dt_iop_ashift_mode_t mode; + int toggle; + dt_iop_ashift_crop_t cropmode; + float cl; + float cr; + float ct; + float cb; +} dt_iop_ashift_params3_t; + +typedef struct dt_iop_ashift_params_t +{ + float rotation; + float lensshift_v; + float lensshift_h; + float shear; + float f_length; + float crop_factor; + float orthocorr; + float aspect; + dt_iop_ashift_mode_t mode; + int toggle; + dt_iop_ashift_crop_t cropmode; + float cl; + float cr; + float ct; + float cb; + float camera_pitch; + float camera_yaw; +} dt_iop_ashift_params_t; + +typedef struct dt_iop_ashift_line_t +{ + float p1[3]; + float p2[3]; + float length; + float width; + float weight; + dt_iop_ashift_linetype_t type; + // homogeneous coordinates: + float L[3]; +} dt_iop_ashift_line_t; + +typedef struct dt_iop_ashift_points_idx_t +{ + size_t offset; + int length; + int near; + int bounded; + dt_iop_ashift_linetype_t type; + dt_iop_ashift_linecolor_t color; + // bounding box: + float bbx, bby, bbX, bbY; +} dt_iop_ashift_points_idx_t; + +typedef struct dt_iop_ashift_fit_params_t +{ + int params_count; + dt_iop_ashift_linetype_t linetype; + dt_iop_ashift_linetype_t linemask; + dt_iop_ashift_line_t *lines; + int lines_count; + int width; + int height; + float weight; + float f_length_kb; + float orthocorr; + float aspect; + float rotation; + float lensshift_v; + float lensshift_h; + float shear; + float camera_pitch; + float camera_yaw; + float rotation_range; + float lensshift_v_range; + float lensshift_h_range; + float shear_range; + float camera_pitch_range; + float camera_yaw_range; +} dt_iop_ashift_fit_params_t; + +typedef struct dt_iop_ashift_cropfit_params_t +{ + int width; + int height; + float x; + float y; + float alpha; + float homograph[3][3]; + float edges[4][3]; +} dt_iop_ashift_cropfit_params_t; + +typedef struct dt_iop_ashift_gui_data_t +{ + /* GtkWidget *rotation; */ + /* GtkWidget *lensshift_v; */ + /* GtkWidget *lensshift_h; */ + /* GtkWidget *shear; */ + /* GtkWidget *guide_lines; */ + /* GtkWidget *cropmode; */ + /* GtkWidget *mode; */ + /* GtkWidget *f_length; */ + /* GtkWidget *crop_factor; */ + /* GtkWidget *orthocorr; */ + /* GtkWidget *aspect; */ + /* GtkWidget *fit_v; */ + /* GtkWidget *fit_h; */ + /* GtkWidget *fit_both; */ + /* GtkWidget *structure; */ + /* GtkWidget *clean; */ + /* GtkWidget *eye; */ + int lines_suppressed; + int fitting; + int isflipped; + int show_guides; + int isselecting; + int isdeselecting; + dt_iop_ashift_bounding_t isbounding; + float near_delta; + int selecting_lines_version; + float rotation_range; + float lensshift_v_range; + float lensshift_h_range; + float shear_range; + float camera_pitch_range; + float camera_yaw_range; + dt_iop_ashift_line_t *lines; + int lines_in_width; + int lines_in_height; + int lines_x_off; + int lines_y_off; + int lines_count; + int vertical_count; + int horizontal_count; + int lines_version; + float vertical_weight; + float horizontal_weight; + float *points; + dt_iop_ashift_points_idx_t *points_idx; + int points_lines_count; + int points_version; + float *buf; + int buf_width; + int buf_height; + int buf_x_off; + int buf_y_off; + float buf_scale; + uint64_t lines_hash; + uint64_t grid_hash; + uint64_t buf_hash; + dt_iop_ashift_fitaxis_t lastfit; + float lastx; + float lasty; + float crop_cx; + float crop_cy; + dt_iop_ashift_jobcode_t jobcode; + int jobparams; + /* dt_pthread_mutex_t lock; */ + MyMutex lock; + gboolean adjust_crop; +} dt_iop_ashift_gui_data_t; + +typedef struct dt_iop_ashift_data_t +{ + float rotation; + float lensshift_v; + float lensshift_h; + float shear; + float f_length_kb; + float orthocorr; + float aspect; + float cl; + float cr; + float ct; + float cb; +} dt_iop_ashift_data_t; + +typedef struct dt_iop_ashift_global_data_t +{ + int kernel_ashift_bilinear; + int kernel_ashift_bicubic; + int kernel_ashift_lanczos2; + int kernel_ashift_lanczos3; +} dt_iop_ashift_global_data_t; + +typedef struct dt_iop_module_t +{ + dt_iop_ashift_gui_data_t *gui_data; + int is_raw; +} dt_iop_module_t; + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, + void *new_params, const int new_version) +{ + if(old_version == 1 && new_version == 4) + { + const dt_iop_ashift_params1_t *old = old_params; + dt_iop_ashift_params_t *new = new_params; + new->rotation = old->rotation; + new->lensshift_v = old->lensshift_v; + new->lensshift_h = old->lensshift_h; + new->shear = 0.0f; + new->toggle = old->toggle; + new->f_length = DEFAULT_F_LENGTH; + new->crop_factor = 1.0f; + new->orthocorr = 100.0f; + new->aspect = 1.0f; + new->mode = ASHIFT_MODE_GENERIC; + new->cropmode = ASHIFT_CROP_OFF; + new->cl = 0.0f; + new->cr = 1.0f; + new->ct = 0.0f; + new->cb = 1.0f; + return 0; + } + if(old_version == 2 && new_version == 4) + { + const dt_iop_ashift_params2_t *old = old_params; + dt_iop_ashift_params_t *new = new_params; + new->rotation = old->rotation; + new->lensshift_v = old->lensshift_v; + new->lensshift_h = old->lensshift_h; + new->shear = 0.0f; + new->toggle = old->toggle; + new->f_length = old->f_length; + new->crop_factor = old->crop_factor; + new->orthocorr = old->orthocorr; + new->aspect = old->aspect; + new->mode = old->mode; + new->cropmode = ASHIFT_CROP_OFF; + new->cl = 0.0f; + new->cr = 1.0f; + new->ct = 0.0f; + new->cb = 1.0f; + return 0; + } + if(old_version == 3 && new_version == 4) + { + const dt_iop_ashift_params3_t *old = old_params; + dt_iop_ashift_params_t *new = new_params; + new->rotation = old->rotation; + new->lensshift_v = old->lensshift_v; + new->lensshift_h = old->lensshift_h; + new->shear = 0.0f; + new->toggle = old->toggle; + new->f_length = old->f_length; + new->crop_factor = old->crop_factor; + new->orthocorr = old->orthocorr; + new->aspect = old->aspect; + new->mode = old->mode; + new->cropmode = old->cropmode; + new->cl = old->cl; + new->cr = old->cr; + new->ct = old->ct; + new->cb = old->cb; + return 0; + } + + return 1; +} + +void init_key_accels(dt_iop_module_so_t *self) +{ + dt_accel_register_slider_iop(self, FALSE, NC_("accel", "rotation")); + dt_accel_register_slider_iop(self, FALSE, NC_("accel", "lens shift (v)")); + dt_accel_register_slider_iop(self, FALSE, NC_("accel", "lens shift (h)")); + dt_accel_register_slider_iop(self, FALSE, NC_("accel", "shear")); +} + +void connect_key_accels(dt_iop_module_t *self) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + dt_accel_connect_slider_iop(self, "rotation", GTK_WIDGET(g->rotation)); + dt_accel_connect_slider_iop(self, "lens shift (v)", GTK_WIDGET(g->lensshift_v)); + dt_accel_connect_slider_iop(self, "lens shift (h)", GTK_WIDGET(g->lensshift_h)); + dt_accel_connect_slider_iop(self, "shear", GTK_WIDGET(g->shear)); +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// multiply 3x3 matrix with 3x1 vector +// dst needs to be different from v +static inline void mat3mulv(float *dst, const float *const mat, const float *const v) +{ + for(int k = 0; k < 3; k++) + { + float x = 0.0f; + for(int i = 0; i < 3; i++) x += mat[3 * k + i] * v[i]; + dst[k] = x; + } +} + +// multiply two 3x3 matrices +// dst needs to be different from m1 and m2 +static inline void mat3mul(float *dst, const float *const m1, const float *const m2) +{ + for(int k = 0; k < 3; k++) + { + for(int i = 0; i < 3; i++) + { + float x = 0.0f; + for(int j = 0; j < 3; j++) x += m1[3 * k + j] * m2[3 * j + i]; + dst[3 * k + i] = x; + } + } +} + +// normalized product of two 3x1 vectors +// dst needs to be different from v1 and v2 +static inline void vec3prodn(float *dst, const float *const v1, const float *const v2) +{ + const float l1 = v1[1] * v2[2] - v1[2] * v2[1]; + const float l2 = v1[2] * v2[0] - v1[0] * v2[2]; + const float l3 = v1[0] * v2[1] - v1[1] * v2[0]; + + // normalize so that l1^2 + l2^2 + l3^3 = 1 + const float sq = sqrt(l1 * l1 + l2 * l2 + l3 * l3); + + const float f = sq > 0.0f ? 1.0f / sq : 1.0f; + + dst[0] = l1 * f; + dst[1] = l2 * f; + dst[2] = l3 * f; +} + +// normalize a 3x1 vector so that x^2 + y^2 + z^2 = 1 +// dst and v may be the same +static inline void vec3norm(float *dst, const float *const v) +{ + const float sq = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + + // special handling for an all-zero vector + const float f = sq > 0.0f ? 1.0f / sq : 1.0f; + + dst[0] = v[0] * f; + dst[1] = v[1] * f; + dst[2] = v[2] * f; +} + +// normalize a 3x1 vector so that x^2 + y^2 = 1; a useful normalization for +// lines in homogeneous coordinates +// dst and v may be the same +static inline void vec3lnorm(float *dst, const float *const v) +{ + const float sq = sqrt(v[0] * v[0] + v[1] * v[1]); + + // special handling for a point vector of the image center + const float f = sq > 0.0f ? 1.0f / sq : 1.0f; + + dst[0] = v[0] * f; + dst[1] = v[1] * f; + dst[2] = v[2] * f; +} + + +// scalar product of two 3x1 vectors +static inline float vec3scalar(const float *const v1, const float *const v2) +{ + return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]); +} + +// check if 3x1 vector is (very close to) null +static inline int vec3isnull(const float *const v) +{ + const float eps = 1e-10f; + return (fabs(v[0]) < eps && fabs(v[1]) < eps && fabs(v[2]) < eps); +} + +#ifdef ASHIFT_DEBUG +static void print_roi(const dt_iop_roi_t *roi, const char *label) +{ + printf("{ %5d %5d %5d %5d %.6f } %s\n", roi->x, roi->y, roi->width, roi->height, roi->scale, label); +} +#endif + +#define MAT3SWAP(a, b) { float (*tmp)[3] = (a); (a) = (b); (b) = tmp; } + +/* +static void homography(float *homograph, const float angle, const float shift_v, const float shift_h, + const float shear, const float f_length_kb, const float orthocorr, const float aspect, + const int width, const int height, dt_iop_ashift_homodir_t dir) +*/ +static void homography(float *homograph, const float angle, const float shift_v, + const float shift_h, const float shear, const float camera_pitch, const + float camera_yaw, const float f_length_kb, const float orthocorr, const + float aspect, const int width, const int height, dt_iop_ashift_homodir_t + dir) +{ + // calculate homograph that combines all translations, rotations + // and warping into one single matrix operation. + // this is heavily leaning on ShiftN where the homographic matrix expects + // input in (y : x : 1) format. in the darktable world we want to keep the + // (x : y : 1) convention. therefore we need to flip coordinates first and + // make sure that output is in correct format after corrections are applied. + + const float u = width; + const float v = height; + const float rot = -M_PI * angle / 180.0f; + const float pitch = M_PI * camera_pitch / 180.0f; + const float yaw = M_PI * camera_yaw / 180.0f; + + /* + const float phi = M_PI * angle / 180.0f; + const float cosi = cos(phi); + const float sini = sin(phi); + const float ascale = sqrt(aspect); + + // most of this comes from ShiftN + const float f_global = f_length_kb; + const float horifac = 1.0f - orthocorr / 100.0f; + const float exppa_v = exp(shift_v); + const float fdb_v = f_global / (14.4f + (v / u - 1) * 7.2f); + const float rad_v = fdb_v * (exppa_v - 1.0f) / (exppa_v + 1.0f); + const float alpha_v = CLAMP(atan(rad_v), -1.5f, 1.5f); + const float rt_v = sin(0.5f * alpha_v); + const float r_v = fmax(0.1f, 2.0f * (horifac - 1.0f) * rt_v * rt_v + 1.0f); + + const float vertifac = 1.0f - orthocorr / 100.0f; + const float exppa_h = exp(shift_h); + const float fdb_h = f_global / (14.4f + (u / v - 1) * 7.2f); + const float rad_h = fdb_h * (exppa_h - 1.0f) / (exppa_h + 1.0f); + const float alpha_h = CLAMP(atan(rad_h), -1.5f, 1.5f); + const float rt_h = sin(0.5f * alpha_h); + const float r_h = fmax(0.1f, 2.0f * (vertifac - 1.0f) * rt_h * rt_h + 1.0f); + */ + + const float f = f_length_kb * (sqrt(u*u + v*v) / sqrt(36.0*36.0 + 24.0*24.0)); + + // three intermediate buffers for matrix calculation ... + float m1[3][3]/*, m2[3][3]*/, m3[3][3]; + + // ... and some pointers to handle them more intuitively + float (*mwork)[3] = m1; + //float (*minput)[3] = m2; + float (*moutput)[3] = m3; + + /* + // Step 1: flip x and y coordinates (see above) + memset(minput, 0, 9 * sizeof(float)); + minput[0][1] = 1.0f; + minput[1][0] = 1.0f; + minput[2][2] = 1.0f; + + + // Step 2: rotation of image around its center + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = cosi; + mwork[0][1] = -sini; + mwork[1][0] = sini; + mwork[1][1] = cosi; + mwork[0][2] = -0.5f * v * cosi + 0.5f * u * sini + 0.5f * v; + mwork[1][2] = -0.5f * v * sini - 0.5f * u * cosi + 0.5f * u; + mwork[2][2] = 1.0f; + + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // Step 3: apply shearing + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = 1.0f; + mwork[0][1] = shear; + mwork[1][1] = 1.0f; + mwork[1][0] = shear; + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // Step 4: apply vertical lens shift effect + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = exppa_v; + mwork[1][0] = 0.5f * ((exppa_v - 1.0f) * u) / v; + mwork[1][1] = 2.0f * exppa_v / (exppa_v + 1.0f); + mwork[1][2] = -0.5f * ((exppa_v - 1.0f) * u) / (exppa_v + 1.0f); + mwork[2][0] = (exppa_v - 1.0f) / v; + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // Step 5: horizontal compression + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = 1.0f; + mwork[1][1] = r_v; + mwork[1][2] = 0.5f * u * (1.0f - r_v); + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // Step 6: flip x and y back again + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][1] = 1.0f; + mwork[1][0] = 1.0f; + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // from here output vectors would be in (x : y : 1) format + + // Step 7: now we can apply horizontal lens shift with the same matrix format as above + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = exppa_h; + mwork[1][0] = 0.5f * ((exppa_h - 1.0f) * v) / u; + mwork[1][1] = 2.0f * exppa_h / (exppa_h + 1.0f); + mwork[1][2] = -0.5f * ((exppa_h - 1.0f) * v) / (exppa_h + 1.0f); + mwork[2][0] = (exppa_h - 1.0f) / u; + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // Step 8: vertical compression + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = 1.0f; + mwork[1][1] = r_h; + mwork[1][2] = 0.5f * v * (1.0f - r_h); + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + + + // Step 9: apply aspect ratio scaling + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = 1.0f * ascale; + mwork[1][1] = 1.0f / ascale; + mwork[2][2] = 1.0f; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + */ + + rtengine::homogeneous::Vector center; + center[0] = 0.0f; + center[1] = 0.0f; + center[2] = f; + center[3] = 1.0f; + + using rtengine::operator*; + + // Location of image center after rotations. + const rtengine::homogeneous::Vector camera_center_yaw_pitch = + rtengine::homogeneous::rotationMatrix(pitch, rtengine::homogeneous::Axis::X) * + rtengine::homogeneous::rotationMatrix(yaw, rtengine::homogeneous::Axis::Y) * + center; + + const rtengine::homogeneous::Matrix matrix = + // Perspective correction. + rtengine::homogeneous::projectionMatrix(camera_center_yaw_pitch[2], rtengine::homogeneous::Axis::Z) * + rtengine::homogeneous::rotationMatrix(yaw, rtengine::homogeneous::Axis::Y) * + rtengine::homogeneous::rotationMatrix(pitch, rtengine::homogeneous::Axis::X) * + // Rotation. + rtengine::homogeneous::rotationMatrix(rot, rtengine::homogeneous::Axis::Z) * + // Lens/sensor shift and move to z == camera_focal_length. + rtengine::homogeneous::translationMatrix((0.01f * shift_h - 0.5f) * u, (-0.01f * shift_v - 0.5f) * v, f); + + m3[0][0] = matrix[0][0]; + m3[0][1] = matrix[0][1]; + m3[0][2] = matrix[0][3]; + m3[1][0] = matrix[1][0]; + m3[1][1] = matrix[1][1]; + m3[1][2] = matrix[1][3]; + m3[2][0] = matrix[3][0]; + m3[2][1] = matrix[3][1]; + m3[2][2] = matrix[3][3]; + + /* + // Step 10: find x/y offsets and apply according correction so that + // no negative coordinates occur in output vector + float umin = FLT_MAX, vmin = FLT_MAX; + // visit all four corners + for(int y = 0; y < height; y += height - 1) + for(int x = 0; x < width; x += width - 1) + { + float pi[3], po[3]; + pi[0] = x; + pi[1] = y; + pi[2] = 1.0f; + // moutput expects input in (x:y:1) format and gives output as (x:y:1) + mat3mulv(po, (float *)moutput, pi); + umin = fmin(umin, po[0] / po[2]); + vmin = fmin(vmin, po[1] / po[2]); + } + + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = 1.0f; + mwork[1][1] = 1.0f; + mwork[2][2] = 1.0f; + mwork[0][2] = -umin; + mwork[1][2] = -vmin; + + // moutput (of last calculation) -> minput + MAT3SWAP(minput, moutput); + // multiply mwork * minput -> moutput + mat3mul((float *)moutput, (float *)mwork, (float *)minput); + */ + + + // on request we either keep the final matrix for forward conversions + // or produce an inverted matrix for backward conversions + if(dir == ASHIFT_HOMOGRAPH_FORWARD) + { + // we have what we need -> copy it to the right place + memcpy(homograph, moutput, 9 * sizeof(float)); + } + else + { + // generate inverted homograph (mat3inv function defined in colorspaces.c) + if(mat3inv((float *)homograph, (float *)moutput)) + { + // in case of error we set to unity matrix + memset(mwork, 0, 9 * sizeof(float)); + mwork[0][0] = 1.0f; + mwork[1][1] = 1.0f; + mwork[2][2] = 1.0f; + memcpy(homograph, mwork, 9 * sizeof(float)); + } + } +} +#undef MAT3SWAP + + +// check if module parameters are set to all neutral values in which case the module's +// output is identical to its input +static inline int isneutral(dt_iop_ashift_data_t *data) +{ + // values lower than this have no visible effect + const float eps = 1.0e-4f; + + return(fabs(data->rotation) < eps && + fabs(data->lensshift_v) < eps && + fabs(data->lensshift_h) < eps && + fabs(data->shear) < eps && + fabs(data->aspect - 1.0f) < eps && + data->cl < eps && + 1.0f - data->cr < eps && + data->ct < eps && + 1.0f - data->cb < eps); +} + + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +int distort_transform(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count) +{ + dt_iop_ashift_data_t *data = (dt_iop_ashift_data_t *)piece->data; + + // nothing to be done if parameters are set to neutral values + if(isneutral(data)) return 1; + + float homograph[3][3]; + homography((float *)homograph, data->rotation, data->lensshift_v, data->lensshift_h, data->shear, data->f_length_kb, + data->orthocorr, data->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_FORWARD); + + // clipping offset + const float fullwidth = (float)piece->buf_out.width / (data->cr - data->cl); + const float fullheight = (float)piece->buf_out.height / (data->cb - data->ct); + const float cx = fullwidth * data->cl; + const float cy = fullheight * data->ct; + +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(points, points_count, homograph) +#endif + for(size_t i = 0; i < points_count * 2; i += 2) + { + float pi[3] = { points[i], points[i + 1], 1.0f }; + float po[3]; + mat3mulv(po, (float *)homograph, pi); + points[i] = po[0] / po[2] - cx; + points[i + 1] = po[1] / po[2] - cy; + } + + return 1; +} + + +int distort_backtransform(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, float *points, + size_t points_count) +{ + dt_iop_ashift_data_t *data = (dt_iop_ashift_data_t *)piece->data; + + // nothing to be done if parameters are set to neutral values + if(isneutral(data)) return 1; + + float ihomograph[3][3]; + homography((float *)ihomograph, data->rotation, data->lensshift_v, data->lensshift_h, data->shear, data->f_length_kb, + data->orthocorr, data->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_INVERTED); + + // clipping offset + const float fullwidth = (float)piece->buf_out.width / (data->cr - data->cl); + const float fullheight = (float)piece->buf_out.height / (data->cb - data->ct); + const float cx = fullwidth * data->cl; + const float cy = fullheight * data->ct; + +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(points, points_count, ihomograph) +#endif + for(size_t i = 0; i < points_count * 2; i += 2) + { + float pi[3] = { points[i] + cx, points[i + 1] + cy, 1.0f }; + float po[3]; + mat3mulv(po, (float *)ihomograph, pi); + points[i] = po[0] / po[2]; + points[i + 1] = po[1] / po[2]; + } + + return 1; +} + +void modify_roi_out(struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, + const dt_iop_roi_t *roi_in) +{ + dt_iop_ashift_data_t *data = (dt_iop_ashift_data_t *)piece->data; + *roi_out = *roi_in; + + // nothing more to be done if parameters are set to neutral values + if(isneutral(data)) return; + + float homograph[3][3]; + homography((float *)homograph, data->rotation, data->lensshift_v, data->lensshift_h, data->shear, data->f_length_kb, + data->orthocorr, data->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_FORWARD); + + float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX; + + // go through all four vertices of input roi and convert coordinates to output + for(int y = 0; y < roi_in->height; y += roi_in->height - 1) + { + for(int x = 0; x < roi_in->width; x += roi_in->width - 1) + { + float pin[3], pout[3]; + + // convert from input coordinates to original image coordinates + pin[0] = roi_in->x + x; + pin[1] = roi_in->y + y; + pin[0] /= roi_in->scale; + pin[1] /= roi_in->scale; + pin[2] = 1.0f; + + // apply homograph + mat3mulv(pout, (float *)homograph, pin); + + // convert to output image coordinates + pout[0] /= pout[2]; + pout[1] /= pout[2]; + pout[0] *= roi_out->scale; + pout[1] *= roi_out->scale; + xm = MIN(xm, pout[0]); + xM = MAX(xM, pout[0]); + ym = MIN(ym, pout[1]); + yM = MAX(yM, pout[1]); + } + } + float width = xM - xm + 1; + float height = yM - ym + 1; + + // clipping adjustments + width *= data->cr - data->cl; + height *= data->cb - data->ct; + + roi_out->width = floorf(width); + roi_out->height = floorf(height); + +#ifdef ASHIFT_DEBUG + print_roi(roi_in, "roi_in (going into modify_roi_out)"); + print_roi(roi_out, "roi_out (after modify_roi_out)"); +#endif +} + +void modify_roi_in(struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, + const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in) +{ + dt_iop_ashift_data_t *data = (dt_iop_ashift_data_t *)piece->data; + *roi_in = *roi_out; + + // nothing more to be done if parameters are set to neutral values + if(isneutral(data)) return; + + float ihomograph[3][3]; + homography((float *)ihomograph, data->rotation, data->lensshift_v, data->lensshift_h, data->shear, data->f_length_kb, + data->orthocorr, data->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_INVERTED); + + const float orig_w = roi_in->scale * piece->buf_in.width; + const float orig_h = roi_in->scale * piece->buf_in.height; + + // clipping offset + const float fullwidth = (float)piece->buf_out.width / (data->cr - data->cl); + const float fullheight = (float)piece->buf_out.height / (data->cb - data->ct); + const float cx = roi_out->scale * fullwidth * data->cl; + const float cy = roi_out->scale * fullheight * data->ct; + + float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX; + + // go through all four vertices of output roi and convert coordinates to input + for(int y = 0; y < roi_out->height; y += roi_out->height - 1) + { + for(int x = 0; x < roi_out->width; x += roi_out->width - 1) + { + float pin[3], pout[3]; + + // convert from output image coordinates to original image coordinates + pout[0] = roi_out->x + x + cx; + pout[1] = roi_out->y + y + cy; + pout[0] /= roi_out->scale; + pout[1] /= roi_out->scale; + pout[2] = 1.0f; + + // apply homograph + mat3mulv(pin, (float *)ihomograph, pout); + + // convert to input image coordinates + pin[0] /= pin[2]; + pin[1] /= pin[2]; + pin[0] *= roi_in->scale; + pin[1] *= roi_in->scale; + xm = MIN(xm, pin[0]); + xM = MAX(xM, pin[0]); + ym = MIN(ym, pin[1]); + yM = MAX(yM, pin[1]); + } + } + + const struct dt_interpolation *interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF); + roi_in->x = fmaxf(0.0f, xm - interpolation->width); + roi_in->y = fmaxf(0.0f, ym - interpolation->width); + roi_in->width = fminf(ceilf(orig_w) - roi_in->x, xM - roi_in->x + 1 + interpolation->width); + roi_in->height = fminf(ceilf(orig_h) - roi_in->y, yM - roi_in->y + 1 + interpolation->width); + + // sanity check. + roi_in->x = CLAMP(roi_in->x, 0, (int)floorf(orig_w)); + roi_in->y = CLAMP(roi_in->y, 0, (int)floorf(orig_h)); + roi_in->width = CLAMP(roi_in->width, 1, (int)floorf(orig_w) - roi_in->x); + roi_in->height = CLAMP(roi_in->height, 1, (int)floorf(orig_h) - roi_in->y); +#ifdef ASHIFT_DEBUG + print_roi(roi_out, "roi_out (going into modify_roi_in)"); + print_roi(roi_in, "roi_in (after modify_roi_in)"); +#endif +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// simple conversion of rgb image into greyscale variant suitable for line segment detection +// the lsd routines expect input as *double, roughly in the range [0.0; 256.0] +static void rgb2grey256(const float *in, double *out, const int width, const int height) +{ + const int ch = 4; + +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(in, out) +#endif + for(int j = 0; j < height; j++) + { + const float *inp = in + (size_t)ch * j * width; + double *outp = out + (size_t)j * width; + for(int i = 0; i < width; i++, inp += ch, outp++) + { + *outp = (0.3f * inp[0] + 0.59f * inp[1] + 0.11f * inp[2]) * 256.0; + } + } +} + +// sobel edge enhancement in one direction +static void edge_enhance_1d(const double *in, double *out, const int width, const int height, + dt_iop_ashift_enhance_t dir) +{ + // Sobel kernels for both directions + const double hkernel[3][3] = { { 1.0, 0.0, -1.0 }, { 2.0, 0.0, -2.0 }, { 1.0, 0.0, -1.0 } }; + const double vkernel[3][3] = { { 1.0, 2.0, 1.0 }, { 0.0, 0.0, 0.0 }, { -1.0, -2.0, -1.0 } }; + const int kwidth = 3; + const int khwidth = kwidth / 2; + + // select kernel + const double *kernel = (dir == ASHIFT_ENHANCE_HORIZONTAL) ? (const double *)hkernel : (const double *)vkernel; + +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(in, out, kernel) +#endif + // loop over image pixels and perform sobel convolution + for(int j = khwidth; j < height - khwidth; j++) + { + const double *inp = in + (size_t)j * width + khwidth; + double *outp = out + (size_t)j * width + khwidth; + for(int i = khwidth; i < width - khwidth; i++, inp++, outp++) + { + double sum = 0.0f; + for(int jj = 0; jj < kwidth; jj++) + { + const int k = jj * kwidth; + const int l = (jj - khwidth) * width; + for(int ii = 0; ii < kwidth; ii++) + { + sum += inp[l + ii - khwidth] * kernel[k + ii]; + } + } + *outp = sum; + } + } + +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(out) +#endif + // border fill in output buffer, so we don't get pseudo lines at image frame + for(int j = 0; j < height; j++) + for(int i = 0; i < width; i++) + { + double val = out[j * width + i]; + + if(j < khwidth) + val = out[(khwidth - j) * width + i]; + else if(j >= height - khwidth) + val = out[(j - khwidth) * width + i]; + else if(i < khwidth) + val = out[j * width + (khwidth - i)]; + else if(i >= width - khwidth) + val = out[j * width + (i - khwidth)]; + + out[j * width + i] = val; + + // jump over center of image + if(i == khwidth && j >= khwidth && j < height - khwidth) i = width - khwidth; + } +} + +// edge enhancement in both directions +static int edge_enhance(const double *in, double *out, const int width, const int height) +{ + double *Gx = NULL; + double *Gy = NULL; + + Gx = (double *)malloc((size_t)width * height * sizeof(double)); + if(Gx == NULL) goto error; + + Gy = (double *)malloc((size_t)width * height * sizeof(double)); + if(Gy == NULL) goto error; + + // perform edge enhancement in both directions + edge_enhance_1d(in, Gx, width, height, ASHIFT_ENHANCE_HORIZONTAL); + edge_enhance_1d(in, Gy, width, height, ASHIFT_ENHANCE_VERTICAL); + +// calculate absolute values +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(Gx, Gy, out) +#endif + for(size_t k = 0; k < (size_t)width * height; k++) + { + out[k] = sqrt(Gx[k] * Gx[k] + Gy[k] * Gy[k]); + } + + free(Gx); + free(Gy); + return TRUE; + +error: + if(Gx) free(Gx); + if(Gy) free(Gy); + return FALSE; +} + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +// XYZ -> sRGB matrix +static void XYZ_to_sRGB(const float *XYZ, float *sRGB) +{ + sRGB[0] = 3.1338561f * XYZ[0] - 1.6168667f * XYZ[1] - 0.4906146f * XYZ[2]; + sRGB[1] = -0.9787684f * XYZ[0] + 1.9161415f * XYZ[1] + 0.0334540f * XYZ[2]; + sRGB[2] = 0.0719453f * XYZ[0] - 0.2289914f * XYZ[1] + 1.4052427f * XYZ[2]; +} + +// sRGB -> XYZ matrix +static void sRGB_to_XYZ(const float *sRGB, float *XYZ) +{ + XYZ[0] = 0.4360747f * sRGB[0] + 0.3850649f * sRGB[1] + 0.1430804f * sRGB[2]; + XYZ[1] = 0.2225045f * sRGB[0] + 0.7168786f * sRGB[1] + 0.0606169f * sRGB[2]; + XYZ[2] = 0.0139322f * sRGB[0] + 0.0971045f * sRGB[1] + 0.7141733f * sRGB[2]; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// detail enhancement via bilateral grid (function arguments in and out may represent identical buffers) +static int detail_enhance(const float *in, float *out, const int width, const int height) +{ + return TRUE; +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 + const float sigma_r = 5.0f; + const float sigma_s = fminf(width, height) * 0.02f; + const float detail = 10.0f; + + int success = TRUE; + + // we need to convert from RGB to Lab first; + // as colors don't matter we are safe to assume data to be sRGB + + // convert RGB input to Lab, use output buffer for intermediate storage +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(in, out) +#endif + for(int j = 0; j < height; j++) + { + const float *inp = in + (size_t)4 * j * width; + float *outp = out + (size_t)4 * j * width; + for(int i = 0; i < width; i++, inp += 4, outp += 4) + { + float XYZ[3]; + sRGB_to_XYZ(inp, XYZ); + dt_XYZ_to_Lab(XYZ, outp); + } + } + + // bilateral grid detail enhancement + dt_bilateral_t *b = dt_bilateral_init(width, height, sigma_s, sigma_r); + + if(b != NULL) + { + dt_bilateral_splat(b, out); + dt_bilateral_blur(b); + dt_bilateral_slice_to_output(b, out, out, detail); + dt_bilateral_free(b); + } + else + success = FALSE; + + // convert resulting Lab to RGB output +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(out) +#endif + for(int j = 0; j < height; j++) + { + float *outp = out + (size_t)4 * j * width; + for(int i = 0; i < width; i++, outp += 4) + { + float XYZ[3]; + dt_Lab_to_XYZ(outp, XYZ); + XYZ_to_sRGB(XYZ, outp); + } + } + + return success; +#endif // if 0 +//----------------------------------------------------------------------------- +} + +// apply gamma correction to RGB buffer (function arguments in and out may represent identical buffers) +static void gamma_correct(const float *in, float *out, const int width, const int height) +{ +#ifdef _OPENMP +#pragma omp parallel for schedule(static) shared(in, out) +#endif + for(int j = 0; j < height; j++) + { + const float *inp = in + (size_t)4 * j * width; + float *outp = out + (size_t)4 * j * width; + for(int i = 0; i < width; i++, inp += 4, outp += 4) + { + for(int c = 0; c < 3; c++) + outp[c] = powf(inp[c], LSD_GAMMA); + } + } +} + +// do actual line_detection based on LSD algorithm and return results according +// to this module's conventions +static int line_detect(float *in, const int width, const int height, const int x_off, const int y_off, + const float scale, dt_iop_ashift_line_t **alines, int *lcount, int *vcount, int *hcount, + float *vweight, float *hweight, dt_iop_ashift_enhance_t enhance, const int is_raw) +{ + double *greyscale = NULL; + double *lsd_lines = NULL; + dt_iop_ashift_line_t *ashift_lines = NULL; + + int vertical_count = 0; + int horizontal_count = 0; + float vertical_weight = 0.0f; + float horizontal_weight = 0.0f; + // + int lines_count; + // we count the lines that we really want to use + int lct = 0; + + // apply gamma correction if image is raw + if(is_raw) + { + gamma_correct(in, in, width, height); + } + + // if requested perform an additional detail enhancement step + if(enhance & ASHIFT_ENHANCE_DETAIL) + { + (void)detail_enhance(in, in, width, height); + } + + // allocate intermediate buffers + greyscale = (double *)malloc((size_t)width * height * sizeof(double)); + if(greyscale == NULL) goto error; + + // convert to greyscale image + rgb2grey256(in, greyscale, width, height); + + // if requested perform an additional edge enhancement step + if(enhance & ASHIFT_ENHANCE_EDGES) + { + (void)edge_enhance(greyscale, greyscale, width, height); + } + + // call the line segment detector LSD; + // LSD stores the number of found lines in lines_count. + // it returns structural details as vector 'double lines[7 * lines_count]' + lsd_lines = LineSegmentDetection(&lines_count, greyscale, width, height, + LSD_SCALE, LSD_SIGMA_SCALE, LSD_QUANT, + LSD_ANG_TH, LSD_LOG_EPS, LSD_DENSITY_TH, + LSD_N_BINS, NULL, NULL, NULL); + + if(lines_count > 0) + { + // aggregate lines data into our own structures + ashift_lines = (dt_iop_ashift_line_t *)malloc((size_t)lines_count * sizeof(dt_iop_ashift_line_t)); + if(ashift_lines == NULL) goto error; + + for(int n = 0; n < lines_count; n++) + { + float x1 = lsd_lines[n * 7 + 0]; + float y1 = lsd_lines[n * 7 + 1]; + float x2 = lsd_lines[n * 7 + 2]; + float y2 = lsd_lines[n * 7 + 3]; + + // check for lines running along image borders and skip them. + // these would likely be false-positives which could result + // from any kind of processing artifacts + if((fabs(x1 - x2) < 1 && fmax(x1, x2) < 2) || + (fabs(x1 - x2) < 1 && fmin(x1, x2) > width - 3) || + (fabs(y1 - y2) < 1 && fmax(y1, y2) < 2) || + (fabs(y1 - y2) < 1 && fmin(y1, y2) > height - 3)) + continue; + + // line position in absolute coordinates + float px1 = x_off + x1; + float py1 = y_off + y1; + float px2 = x_off + x2; + float py2 = y_off + y2; + + // scale back to input buffer + px1 /= scale; + py1 /= scale; + px2 /= scale; + py2 /= scale; + + // store as homogeneous coordinates + ashift_lines[lct].p1[0] = px1; + ashift_lines[lct].p1[1] = py1; + ashift_lines[lct].p1[2] = 1.0f; + ashift_lines[lct].p2[0] = px2; + ashift_lines[lct].p2[1] = py2; + ashift_lines[lct].p2[2] = 1.0f; + + // calculate homogeneous coordinates of connecting line (defined by the two points) + vec3prodn(ashift_lines[lct].L, ashift_lines[lct].p1, ashift_lines[lct].p2); + + // normalaze line coordinates so that x^2 + y^2 = 1 + // (this will always succeed as L is a real line connecting two real points) + vec3lnorm(ashift_lines[lct].L, ashift_lines[lct].L); + + // length and width of rectangle (see LSD) + ashift_lines[lct].length = sqrt((px2 - px1) * (px2 - px1) + (py2 - py1) * (py2 - py1)); + ashift_lines[lct].width = lsd_lines[n * 7 + 4] / scale; + + // ... and weight (= angle precision * length * width) + const float weight = lsd_lines[n * 7 + 5] * ashift_lines[lct].length * ashift_lines[lct].width; + ashift_lines[lct].weight = weight; + + + const float angle = atan2(py2 - py1, px2 - px1) / M_PI * 180.0f; + const int vertical = fabs(fabs(angle) - 90.0f) < MAX_TANGENTIAL_DEVIATION ? 1 : 0; + const int horizontal = fabs(fabs(fabs(angle) - 90.0f) - 90.0f) < MAX_TANGENTIAL_DEVIATION ? 1 : 0; + + const int relevant = ashift_lines[lct].length > MIN_LINE_LENGTH ? 1 : 0; + + // register type of line + dt_iop_ashift_linetype_t type = ASHIFT_LINE_IRRELEVANT; + if(vertical && relevant) + { + type = ASHIFT_LINE_VERTICAL_SELECTED; + vertical_count++; + vertical_weight += weight; + } + else if(horizontal && relevant) + { + type = ASHIFT_LINE_HORIZONTAL_SELECTED; + horizontal_count++; + horizontal_weight += weight; + } + ashift_lines[lct].type = type; + + // the next valid line + lct++; + } + } +#ifdef ASHIFT_DEBUG + printf("%d lines (vertical %d, horizontal %d, not relevant %d)\n", lines_count, vertical_count, + horizontal_count, lct - vertical_count - horizontal_count); + float xmin = FLT_MAX, xmax = FLT_MIN, ymin = FLT_MAX, ymax = FLT_MIN; + for(int n = 0; n < lct; n++) + { + xmin = fmin(xmin, fmin(ashift_lines[n].p1[0], ashift_lines[n].p2[0])); + xmax = fmax(xmax, fmax(ashift_lines[n].p1[0], ashift_lines[n].p2[0])); + ymin = fmin(ymin, fmin(ashift_lines[n].p1[1], ashift_lines[n].p2[1])); + ymax = fmax(ymax, fmax(ashift_lines[n].p1[1], ashift_lines[n].p2[1])); + printf("x1 %.0f, y1 %.0f, x2 %.0f, y2 %.0f, length %.0f, width %f, X %f, Y %f, Z %f, type %d, scalars %f %f\n", + ashift_lines[n].p1[0], ashift_lines[n].p1[1], ashift_lines[n].p2[0], ashift_lines[n].p2[1], + ashift_lines[n].length, ashift_lines[n].width, + ashift_lines[n].L[0], ashift_lines[n].L[1], ashift_lines[n].L[2], ashift_lines[n].type, + vec3scalar(ashift_lines[n].p1, ashift_lines[n].L), + vec3scalar(ashift_lines[n].p2, ashift_lines[n].L)); + } + printf("xmin %.0f, xmax %.0f, ymin %.0f, ymax %.0f\n", xmin, xmax, ymin, ymax); +#endif + + // store results in provided locations + *lcount = lct; + *vcount = vertical_count; + *vweight = vertical_weight; + *hcount = horizontal_count; + *hweight = horizontal_weight; + *alines = ashift_lines; + + // free intermediate buffers + free(lsd_lines); + free(greyscale); + return lct > 0 ? TRUE : FALSE; + +error: + free(lsd_lines); + free(greyscale); + return FALSE; +} + +// get image from buffer, analyze for structure and save results +static int get_structure(dt_iop_module_t *module, dt_iop_ashift_enhance_t enhance) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + float *buffer = NULL; + int width = 0; + int height = 0; + int x_off = 0; + int y_off = 0; + float scale = 0.0f; + + { //dt_pthread_mutex_lock(&g->lock); + MyMutex::MyLock lock(g->lock); + + // read buffer data if they are available + if(g->buf != NULL) + { + width = g->buf_width; + height = g->buf_height; + x_off = g->buf_x_off; + y_off = g->buf_y_off; + scale = g->buf_scale; + + // create a temporary buffer to hold image data + buffer = (float *)malloc((size_t)width * height * 4 * sizeof(float)); + if(buffer != NULL) + memcpy(buffer, g->buf, (size_t)width * height * 4 * sizeof(float)); + } + } /* dt_pthread_mutex_unlock(&g->lock); */ + + if(buffer == NULL) goto error; + + // get rid of old structural data + g->lines_count = 0; + g->vertical_count = 0; + g->horizontal_count = 0; + free(g->lines); + g->lines = NULL; + + dt_iop_ashift_line_t *lines; + int lines_count; + int vertical_count; + int horizontal_count; + float vertical_weight; + float horizontal_weight; + + // get new structural data + if(!line_detect(buffer, width, height, x_off, y_off, scale, &lines, &lines_count, + &vertical_count, &horizontal_count, &vertical_weight, &horizontal_weight, + enhance, module->is_raw))//dt_image_is_raw(&module->dev->image_storage))) + goto error; + + // save new structural data + g->lines_in_width = width; + g->lines_in_height = height; + g->lines_x_off = x_off; + g->lines_y_off = y_off; + g->lines_count = lines_count; + g->vertical_count = vertical_count; + g->horizontal_count = horizontal_count; + g->vertical_weight = vertical_weight; + g->horizontal_weight = horizontal_weight; + g->lines_version++; + g->lines_suppressed = 0; + g->lines = lines; + + free(buffer); + return TRUE; + +error: + free(buffer); + return FALSE; +} + + +// swap two integer values +static inline void swap(int *a, int *b) +{ + int tmp = *a; + *a = *b; + *b = tmp; +} + +// do complete permutations +static int quickperm(int *a, int *p, const int N, int *i) +{ + if(*i >= N) return FALSE; + + p[*i]--; + int j = (*i % 2 == 1) ? p[*i] : 0; + swap(&a[j], &a[*i]); + *i = 1; + while(p[*i] == 0) + { + p[*i] = *i; + (*i)++; + } + return TRUE; +} + +// Fisher-Yates shuffle +static void shuffle(int *a, const int N) +{ + for(int i = 0; i < N; i++) + { + int j = i + rand() % (N - i); + swap(&a[j], &a[i]); + } +} + +// factorial function +static int fact(const int n) +{ + return (n == 1 ? 1 : n * fact(n - 1)); +} + +// We use a pseudo-RANSAC algorithm to elminiate ouliers from our set of lines. The +// original RANSAC works on linear optimization problems. Our model is nonlinear. We +// take advantage of the fact that lines interesting for our model are vantage lines +// that meet in one vantage point for each subset of lines (vertical/horizontal). +// Stragegy: we construct a model by (random) sampling within the subset of lines and +// calculate the vantage point. Then we check the "distance" of all other lines to the +// vantage point. The model that gives highest number of lines combined with the highest +// total weight and lowest overall "distance" wins. +// Disadvantage: compared to the original RANSAC we don't get any model parameters that +// we could use for the following NMS fit. +// Self-tuning: we optimize "epsilon", the hurdle rate to reject a line as an outlier, +// by a number of dry runs first. The target average percentage value of lines to eliminate as +// outliers (without judging on the quality of the model) is given by RANSAC_ELIMINATION_RATIO, +// note: the actual percentage of outliers removed in the final run will be lower because we +// will finally look for the best quality model with the optimized epsilon and that quality value also +// encloses the number of good lines +static void ransac(const dt_iop_ashift_line_t *lines, int *index_set, int *inout_set, + const int set_count, const float total_weight, const int xmin, const int xmax, + const int ymin, const int ymax) +{ + if(set_count < 3) return; + + const size_t set_size = set_count * sizeof(int); + int *best_set = (int *)malloc(set_size); + memcpy(best_set, index_set, set_size); + int *best_inout = (int *)calloc(1, set_size); + + float best_quality = 0.0f; + + // hurdle value epsilon for rejecting a line as an outlier will be self-tuning + // in a number of dry runs + float epsilon = pow(10.0f, -RANSAC_EPSILON); + float epsilon_step = RANSAC_EPSILON_STEP; + // some accounting variables for self-tuning + int lines_eliminated = 0; + int valid_runs = 0; + + // number of runs to optimize epsilon + const int optiruns = RANSAC_OPTIMIZATION_STEPS * RANSAC_OPTIMIZATION_DRY_RUNS; + // go for complete permutations on small set sizes, else for random sample consensus + const int riter = (set_count > RANSAC_HURDLE) ? RANSAC_RUNS : fact(set_count); + + // some data needed for quickperm + int *perm = (int *)malloc((set_count + 1) * sizeof(int)); + for(int n = 0; n < set_count + 1; n++) perm[n] = n; + int piter = 1; + + // inout holds good/bad qualification for each line + int *inout = (int *)malloc(set_size); + + for(int r = 0; r < optiruns + riter; r++) + { + // get random or systematic variation of index set + if(set_count > RANSAC_HURDLE || r < optiruns) + shuffle(index_set, set_count); + else + (void)quickperm(index_set, perm, set_count, &piter); + + // summed quality evaluation of this run + float quality = 0.0f; + + // we build a model ouf of the first two lines + const float *L1 = lines[index_set[0]].L; + const float *L2 = lines[index_set[1]].L; + + // get intersection point (ideally a vantage point) + float V[3]; + vec3prodn(V, L1, L2); + + // catch special cases: + // a) L1 and L2 are identical -> V is NULL -> no valid vantage point + // b) vantage point lies inside image frame (no chance to correct for this case) + if(vec3isnull(V) || + (fabs(V[2]) > 0.0f && + V[0]/V[2] >= xmin && + V[1]/V[2] >= ymin && + V[0]/V[2] <= xmax && + V[1]/V[2] <= ymax)) + { + // no valid model + quality = 0.0f; + } + else + { + // valid model + + // normalize V so that x^2 + y^2 + z^2 = 1 + vec3norm(V, V); + + // the two lines constituting the model are part of the set + inout[0] = 1; + inout[1] = 1; + + // go through all remaining lines, check if they are within the model, and + // mark that fact in inout[]. + // summarize a quality parameter for all lines within the model + for(int n = 2; n < set_count; n++) + { + // L is normalized so that x^2 + y^2 = 1 + const float *L3 = lines[index_set[n]].L; + + // we take the absolute value of the dot product of V and L as a measure + // of the "distance" between point and line. Note that this is not the real euclidian + // distance but - with the given normalization - just a pragmatically selected number + // that goes to zero if V lies on L and increases the more V and L are apart + const float d = fabs(vec3scalar(V, L3)); + + // depending on d we either include or exclude the point from the set + inout[n] = (d < epsilon) ? 1 : 0; + + float q; + + if(inout[n] == 1) + { + // a quality parameter that depends 1/3 on the number of lines within the model, + // 1/3 on their weight, and 1/3 on their weighted distance d to the vantage point + q = 0.33f / (float)set_count + + 0.33f * lines[index_set[n]].weight / total_weight + + 0.33f * (1.0f - d / epsilon) * (float)set_count * lines[index_set[n]].weight / total_weight; + } + else + { + q = 0.0f; + lines_eliminated++; + } + + quality += q; + } + valid_runs++; + } + + if(r < optiruns) + { + // on last run of each self-tuning step + if((r % RANSAC_OPTIMIZATION_DRY_RUNS) == (RANSAC_OPTIMIZATION_DRY_RUNS - 1) && (valid_runs > 0)) + { +#ifdef ASHIFT_DEBUG + printf("ransac self-tuning (run %d): epsilon %f", r, epsilon); +#endif + // average ratio of lines that we eliminated with the given epsilon + float ratio = 100.0f * (float)lines_eliminated / ((float)set_count * valid_runs); + // adjust epsilon accordingly + if(ratio < RANSAC_ELIMINATION_RATIO) + epsilon = pow(10.0f, log10(epsilon) - epsilon_step); + else if(ratio > RANSAC_ELIMINATION_RATIO) + epsilon = pow(10.0f, log10(epsilon) + epsilon_step); +#ifdef ASHIFT_DEBUG + printf(" (elimination ratio %f) -> %f\n", ratio, epsilon); +#endif + // reduce step-size for next optimization round + epsilon_step /= 2.0f; + lines_eliminated = 0; + valid_runs = 0; + } + } + else + { + // in the "real" runs check against the best model found so far + if(quality > best_quality) + { + memcpy(best_set, index_set, set_size); + memcpy(best_inout, inout, set_size); + best_quality = quality; + } + } + +#ifdef ASHIFT_DEBUG + // report some statistics + int count = 0, lastcount = 0; + for(int n = 0; n < set_count; n++) count += best_inout[n]; + for(int n = 0; n < set_count; n++) lastcount += inout[n]; + printf("ransac run %d: best qual %.6f, eps %.6f, line count %d of %d (this run: qual %.5f, count %d (%2f%%))\n", r, + best_quality, epsilon, count, set_count, quality, lastcount, 100.0f * lastcount / (float)set_count); +#endif + } + + // store back best set + memcpy(index_set, best_set, set_size); + memcpy(inout_set, best_inout, set_size); + + free(inout); + free(perm); + free(best_inout); + free(best_set); +} + + +// try to clean up structural data by eliminating outliers and thereby increasing +// the chance of a convergent fitting +static int remove_outliers(dt_iop_module_t *module) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + const int width = g->lines_in_width; + const int height = g->lines_in_height; + const int xmin = g->lines_x_off; + const int ymin = g->lines_y_off; + const int xmax = xmin + width; + const int ymax = ymin + height; + + // holds the index set of lines we want to work on + int *lines_set = (int *)malloc(g->lines_count * sizeof(int)); + // holds the result of ransac + int *inout_set = (int *)malloc(g->lines_count * sizeof(int)); + + // some accounting variables + int vnb = 0, vcount = 0; + int hnb = 0, hcount = 0; + + // just to be on the safe side + if(g->lines == NULL) goto error; + + // generate index list for the vertical lines + for(int n = 0; n < g->lines_count; n++) + { + // is this a selected vertical line? + if((g->lines[n].type & ASHIFT_LINE_MASK) != ASHIFT_LINE_VERTICAL_SELECTED) + continue; + + lines_set[vnb] = n; + inout_set[vnb] = 0; + vnb++; + } + + // it only makes sense to call ransac if we have more than two lines + if(vnb > 2) + ransac(g->lines, lines_set, inout_set, vnb, g->vertical_weight, + xmin, xmax, ymin, ymax); + + // adjust line selected flag according to the ransac results + for(int n = 0; n < vnb; n++) + { + const int m = lines_set[n]; + if(inout_set[n] == 1) + { + g->lines[m].type |= ASHIFT_LINE_SELECTED; + vcount++; + } + else + g->lines[m].type &= ~ASHIFT_LINE_SELECTED; + } + // update number of vertical lines + g->vertical_count = vcount; + g->lines_version++; + + // now generate index list for the horizontal lines + for(int n = 0; n < g->lines_count; n++) + { + // is this a selected horizontal line? + if((g->lines[n].type & ASHIFT_LINE_MASK) != ASHIFT_LINE_HORIZONTAL_SELECTED) + continue; + + lines_set[hnb] = n; + inout_set[hnb] = 0; + hnb++; + } + + // it only makes sense to call ransac if we have more than two lines + if(hnb > 2) + ransac(g->lines, lines_set, inout_set, hnb, g->horizontal_weight, + xmin, xmax, ymin, ymax); + + // adjust line selected flag according to the ransac results + for(int n = 0; n < hnb; n++) + { + const int m = lines_set[n]; + if(inout_set[n] == 1) + { + g->lines[m].type |= ASHIFT_LINE_SELECTED; + hcount++; + } + else + g->lines[m].type &= ~ASHIFT_LINE_SELECTED; + } + // update number of horizontal lines + g->horizontal_count = hcount; + g->lines_version++; + + free(inout_set); + free(lines_set); + + return TRUE; + +error: + free(inout_set); + free(lines_set); + return FALSE; +} + +// utility function to map a variable in [min; max] to [-INF; + INF] +static inline double logit(double x, double min, double max) +{ + const double eps = 1.0e-6; + // make sure p does not touch the borders of its definition area, + // not critical for data accuracy as logit() is only used on initial fit parameters + double p = CLAMP((x - min) / (max - min), eps, 1.0 - eps); + + return (2.0 * atanh(2.0 * p - 1.0)); +} + +// inverted function to logit() +static inline double ilogit(double L, double min, double max) +{ + double p = 0.5 * (1.0 + tanh(0.5 * L)); + + return (p * (max - min) + min); +} + +// helper function for simplex() return quality parameter for the given model +// strategy: +// * generate homography matrix out of fixed parameters and fitting parameters +// * apply homography to all end points of affected lines +// * generate new line out of transformed end points +// * calculate scalar product s of line with perpendicular axis +// * sum over weighted s^2 values +static double model_fitness(double *params, void *data) +{ + dt_iop_ashift_fit_params_t *fit = (dt_iop_ashift_fit_params_t *)data; + + // just for convenience: get shorter names + dt_iop_ashift_line_t *lines = fit->lines; + const int lines_count = fit->lines_count; + const int width = fit->width; + const int height = fit->height; + const float f_length_kb = fit->f_length_kb; + const float orthocorr = fit->orthocorr; + const float aspect = fit->aspect; + + float rotation = fit->rotation; + float lensshift_v = fit->lensshift_v; + float lensshift_h = fit->lensshift_h; + float shear = fit->shear; + float camera_pitch = fit->camera_pitch; + float camera_yaw = fit->camera_yaw; + float rotation_range = fit->rotation_range; + /* + float lensshift_v_range = fit->lensshift_v_range; + float lensshift_h_range = fit->lensshift_h_range; + float shear_range = fit->shear_range; + */ + float camera_pitch_range = fit->camera_pitch_range; + float camera_yaw_range = fit->camera_yaw_range; + + int pcount = 0; + + // fill in fit parameters from params[]. Attention: order matters!!! + if(isnan(rotation)) + { + rotation = ilogit(params[pcount], -rotation_range, rotation_range); + pcount++; + } + + /* + if(isnan(lensshift_v)) + { + lensshift_v = ilogit(params[pcount], -lensshift_v_range, lensshift_v_range); + pcount++; + } + + if(isnan(lensshift_h)) + { + lensshift_h = ilogit(params[pcount], -lensshift_h_range, lensshift_h_range); + pcount++; + } + + if(isnan(shear)) + { + shear = ilogit(params[pcount], -shear_range, shear_range); + pcount++; + } + */ + + if(isnan(camera_pitch)) + { + camera_pitch = ilogit(params[pcount], -camera_pitch_range, camera_pitch_range); + pcount++; + } + + if(isnan(camera_yaw)) + { + camera_yaw = ilogit(params[pcount], -camera_yaw_range, camera_yaw_range); + pcount++; + } + + assert(pcount == fit->params_count); + + // the possible reference axes + const float Av[3] = { 1.0f, 0.0f, 0.0f }; + const float Ah[3] = { 0.0f, 1.0f, 0.0f }; + + // generate homograph out of the parameters + float homograph[3][3]; + homography((float *)homograph, rotation, lensshift_v, lensshift_h, shear, camera_pitch, camera_yaw, f_length_kb, + orthocorr, aspect, width, height, ASHIFT_HOMOGRAPH_FORWARD); + + // accounting variables + double sumsq_v = 0.0; + double sumsq_h = 0.0; + double weight_v = 0.0; + double weight_h = 0.0; + int count_v = 0; + int count_h = 0; + int count = 0; + + // iterate over all lines + for(int n = 0; n < lines_count; n++) + { + // check if this is a line which we must skip + if((lines[n].type & fit->linemask) != fit->linetype) + continue; + + // the direction of this line (vertical?) + const int isvertical = lines[n].type & ASHIFT_LINE_DIRVERT; + + // select the perpendicular reference axis + const float *A = isvertical ? Ah : Av; + + // apply homographic transformation to the end points + float P1[3], P2[3]; + mat3mulv(P1, (float *)homograph, lines[n].p1); + mat3mulv(P2, (float *)homograph, lines[n].p2); + + // get line connecting the two points + float L[3]; + vec3prodn(L, P1, P2); + + // normalize L so that x^2 + y^2 = 1; makes sure that + // y^2 = 1 / (1 + m^2) and x^2 = m^2 / (1 + m^2) with m defining the slope of the line + vec3lnorm(L, L); + + // get scalar product of line L with orthogonal axis A -> gives 0 if line is perpendicular + float s = vec3scalar(L, A); + + // sum up weighted s^2 for both directions individually + sumsq_v += isvertical ? (double)s * s * lines[n].weight : 0.0; + weight_v += isvertical ? lines[n].weight : 0.0; + count_v += isvertical ? 1 : 0; + sumsq_h += !isvertical ? (double)s * s * lines[n].weight : 0.0; + weight_h += !isvertical ? lines[n].weight : 0.0; + count_h += !isvertical ? 1 : 0; + count++; + } + + const double v = weight_v > 0.0f && count > 0 ? sumsq_v / weight_v * (float)count_v / count : 0.0; + const double h = weight_h > 0.0f && count > 0 ? sumsq_h / weight_h * (float)count_h / count : 0.0; + + double sum = sqrt(1.0 - (1.0 - v) * (1.0 - h)) * 1.0e6; + //double sum = sqrt(v + h) * 1.0e6; + +#ifdef ASHIFT_DEBUG + /* + printf("fitness with rotation %f, lensshift_v %f, lensshift_h %f, shear %f -> lines %d, quality %10f\n", + rotation, lensshift_v, lensshift_h, shear, count, sum); + */ + printf("fitness with rotation %f, camera_pitch %f, camera_yaw %f -> lines %d, quality %10f\n", + rotation, camera_pitch, camera_yaw, count, sum); +#endif + + return sum; +} + +// setup all data structures for fitting and call NM simplex +static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir, int min_line_count) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + if(!g->lines) return NMS_NOT_ENOUGH_LINES; + if(dir == ASHIFT_FIT_NONE) return NMS_SUCCESS; + + double params[4]; + int pcount = 0; + int enough_lines = TRUE; + + // initialize fit parameters + dt_iop_ashift_fit_params_t fit; + fit.lines = g->lines; + fit.lines_count = g->lines_count; + fit.width = g->lines_in_width; + fit.height = g->lines_in_height; + fit.f_length_kb = (p->mode == ASHIFT_MODE_GENERIC) ? (float)DEFAULT_F_LENGTH : p->f_length * p->crop_factor; + fit.orthocorr = (p->mode == ASHIFT_MODE_GENERIC) ? 0.0f : p->orthocorr; + fit.aspect = (p->mode == ASHIFT_MODE_GENERIC) ? 1.0f : p->aspect; + fit.rotation = p->rotation; + fit.lensshift_v = p->lensshift_v; + fit.lensshift_h = p->lensshift_h; + fit.shear = p->shear; + fit.camera_pitch = p->camera_pitch; + fit.camera_yaw = p->camera_yaw; + fit.rotation_range = g->rotation_range; + fit.lensshift_v_range = g->lensshift_v_range; + fit.lensshift_h_range = g->lensshift_h_range; + fit.shear_range = g->shear_range; + fit.camera_pitch_range = g->camera_pitch_range; + fit.camera_yaw_range = g->camera_yaw_range; + fit.linetype = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED; + fit.linemask = ASHIFT_LINE_MASK; + fit.params_count = 0; + fit.weight = 0.0f; + + // if the image is flipped and if we do not want to fit both lens shift + // directions or none at all, then we need to change direction + dt_iop_ashift_fitaxis_t mdir = dir; + if((mdir & ASHIFT_FIT_LENS_BOTH) != ASHIFT_FIT_LENS_BOTH && + (mdir & ASHIFT_FIT_LENS_BOTH) != 0) + { + // flip all directions + mdir ^= g->isflipped ? ASHIFT_FIT_FLIP : 0; + // special case that needs to be corrected + mdir |= (mdir & ASHIFT_FIT_LINES_BOTH) == 0 ? ASHIFT_FIT_LINES_BOTH : 0; + } + + + // prepare fit structure and starting parameters for simplex fit. + // note: the sequence of parameters in params[] needs to match the + // respective order in dt_iop_ashift_fit_params_t. Parameters which are + // to be fittet are marked with NAN in the fit structure. Non-NAN + // parameters are assumed to be constant. + if(mdir & ASHIFT_FIT_ROTATION) + { + // we fit rotation + fit.params_count++; + params[pcount] = logit(0, -fit.rotation_range, fit.rotation_range); + pcount++; + fit.rotation = NAN; + } + + /* + if(mdir & ASHIFT_FIT_LENS_VERT) + { + // we fit vertical lens shift + fit.params_count++; + params[pcount] = logit(fit.lensshift_v, -fit.lensshift_v_range, fit.lensshift_v_range); + pcount++; + fit.lensshift_v = NAN; + } + + if(mdir & ASHIFT_FIT_LENS_HOR) + { + // we fit horizontal lens shift + fit.params_count++; + params[pcount] = logit(fit.lensshift_h, -fit.lensshift_h_range, fit.lensshift_h_range); + pcount++; + fit.lensshift_h = NAN; + } + + if(mdir & ASHIFT_FIT_SHEAR) + { + // we fit the shear parameter + fit.params_count++; + params[pcount] = logit(fit.shear, -fit.shear_range, fit.shear_range); + pcount++; + fit.shear = NAN; + } + */ + + if(mdir & ASHIFT_FIT_LENS_VERT) + { + // we fit pitch + fit.params_count++; + params[pcount] = logit(0, -fit.camera_pitch_range, fit.camera_pitch_range); + pcount++; + fit.camera_pitch = NAN; + } + + if(mdir & ASHIFT_FIT_LENS_HOR) + { + // we fit yaw + fit.params_count++; + params[pcount] = logit(0, -fit.camera_yaw_range, fit.camera_yaw_range); + pcount++; + fit.camera_yaw = NAN; + } + + if(mdir & ASHIFT_FIT_LINES_VERT) + { + // we use vertical lines for fitting + fit.linetype |= ASHIFT_LINE_DIRVERT; + fit.weight += g->vertical_weight; + enough_lines = enough_lines && (g->vertical_count >= min_line_count); + } + + if(mdir & ASHIFT_FIT_LINES_HOR) + { + // we use horizontal lines for fitting + fit.linetype |= 0; + fit.weight += g->horizontal_weight; + enough_lines = enough_lines && (g->horizontal_count >= min_line_count); + } + + // this needs to come after ASHIFT_FIT_LINES_VERT and ASHIFT_FIT_LINES_HOR + if((mdir & ASHIFT_FIT_LINES_BOTH) == ASHIFT_FIT_LINES_BOTH) + { + // if we use fitting in both directions we need to + // adjust fit.linetype and fit.linemask to match all selected lines + fit.linetype = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED; + fit.linemask = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED; + } + + // error case: we do not run simplex if there are not enough lines + if(!enough_lines) + { +#ifdef ASHIFT_DEBUG + printf("optimization not possible: insufficient number of lines\n"); +#endif + return NMS_NOT_ENOUGH_LINES; + } + + // start the simplex fit + int iter = simplex(model_fitness, params, fit.params_count, NMS_EPSILON, NMS_SCALE, NMS_ITERATIONS, NULL, (void*)&fit); + + // error case: the fit did not converge + if(iter >= NMS_ITERATIONS) + { +#ifdef ASHIFT_DEBUG + printf("optimization not successful: maximum number of iterations reached (%d)\n", iter); +#endif + return NMS_DID_NOT_CONVERGE; + } + + // fit was successful: now consolidate the results (order matters!!!) + pcount = 0; + fit.rotation = isnan(fit.rotation) ? ilogit(params[pcount++], -fit.rotation_range, fit.rotation_range) : fit.rotation; + /* + fit.lensshift_v = isnan(fit.lensshift_v) ? ilogit(params[pcount++], -fit.lensshift_v_range, fit.lensshift_v_range) : fit.lensshift_v; + fit.lensshift_h = isnan(fit.lensshift_h) ? ilogit(params[pcount++], -fit.lensshift_h_range, fit.lensshift_h_range) : fit.lensshift_h; + fit.shear = isnan(fit.shear) ? ilogit(params[pcount++], -fit.shear_range, fit.shear_range) : fit.shear; + */ + fit.camera_pitch = isnan(fit.camera_pitch) ? ilogit(params[pcount++], -fit.camera_pitch_range, fit.camera_pitch_range) : fit.camera_pitch; + fit.camera_yaw = isnan(fit.camera_yaw) ? ilogit(params[pcount++], -fit.camera_yaw_range, fit.camera_yaw_range) : fit.camera_yaw; +#ifdef ASHIFT_DEBUG + /* + printf("params after optimization (%d iterations): rotation %f, lensshift_v %f, lensshift_h %f, shear %f\n", + iter, fit.rotation, fit.lensshift_v, fit.lensshift_h, fit.shear); + */ + printf("params after optimization (%d iterations): rotation %f, camera_pitch %f, camera_yaw %f\n", + iter, fit.rotation, fit.camera_pitch, fit.camera_yaw); +#endif + + /* + // sanity check: in case of extreme values the image gets distorted so strongly that it spans an insanely huge area. we check that + // case and assume values that increase the image area by more than a factor of 4 as being insane. + float homograph[3][3]; + homography((float *)homograph, fit.rotation, fit.lensshift_v, fit.lensshift_h, fit.shear, fit.f_length_kb, + fit.orthocorr, fit.aspect, fit.width, fit.height, ASHIFT_HOMOGRAPH_FORWARD); + + // visit all four corners and find maximum span + float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX; + for(int y = 0; y < fit.height; y += fit.height - 1) + for(int x = 0; x < fit.width; x += fit.width - 1) + { + float pi[3], po[3]; + pi[0] = x; + pi[1] = y; + pi[2] = 1.0f; + mat3mulv(po, (float *)homograph, pi); + po[0] /= po[2]; + po[1] /= po[2]; + xm = fmin(xm, po[0]); + ym = fmin(ym, po[1]); + xM = fmax(xM, po[0]); + yM = fmax(yM, po[1]); + } + + if((xM - xm) * (yM - ym) > 4.0f * fit.width * fit.height) + { +#ifdef ASHIFT_DEBUG + printf("optimization not successful: degenerate case with area growth factor (%f) exceeding limits\n", + (xM - xm) * (yM - ym) / (fit.width * fit.height)); +#endif + return NMS_INSANE; + } + */ + + // now write the results into structure p + p->rotation = fit.rotation; + /* + p->lensshift_v = fit.lensshift_v; + p->lensshift_h = fit.lensshift_h; + p->shear = fit.shear; + */ + p->camera_pitch = fit.camera_pitch; + p->camera_yaw = fit.camera_yaw; + return NMS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +#ifdef ASHIFT_DEBUG +// only used in development phase. call model_fitness() with current parameters and +// print some useful information +static void model_probe(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + if(!g->lines) return; + if(dir == ASHIFT_FIT_NONE) return; + + double params[4]; + int enough_lines = TRUE; + + // initialize fit parameters + dt_iop_ashift_fit_params_t fit; + fit.lines = g->lines; + fit.lines_count = g->lines_count; + fit.width = g->lines_in_width; + fit.height = g->lines_in_height; + fit.f_length_kb = (p->mode == ASHIFT_MODE_GENERIC) ? DEFAULT_F_LENGTH : p->f_length * p->crop_factor; + fit.orthocorr = (p->mode == ASHIFT_MODE_GENERIC) ? 0.0f : p->orthocorr; + fit.aspect = (p->mode == ASHIFT_MODE_GENERIC) ? 1.0f : p->aspect; + fit.rotation = p->rotation; + fit.lensshift_v = p->lensshift_v; + fit.lensshift_h = p->lensshift_h; + fit.shear = p->shear; + fit.linetype = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED; + fit.linemask = ASHIFT_LINE_MASK; + fit.params_count = 0; + fit.weight = 0.0f; + + // if the image is flipped and if we do not want to fit both lens shift + // directions or none at all, then we need to change direction + dt_iop_ashift_fitaxis_t mdir = dir; + if((mdir & ASHIFT_FIT_LENS_BOTH) != ASHIFT_FIT_LENS_BOTH && + (mdir & ASHIFT_FIT_LENS_BOTH) != 0) + { + // flip all directions + mdir ^= g->isflipped ? ASHIFT_FIT_FLIP : 0; + // special case that needs to be corrected + mdir |= (mdir & ASHIFT_FIT_LINES_BOTH) == 0 ? ASHIFT_FIT_LINES_BOTH : 0; + } + + if(mdir & ASHIFT_FIT_LINES_VERT) + { + // we use vertical lines for fitting + fit.linetype |= ASHIFT_LINE_DIRVERT; + fit.weight += g->vertical_weight; + enough_lines = enough_lines && (g->vertical_count >= MINIMUM_FITLINES); + } + + if(mdir & ASHIFT_FIT_LINES_HOR) + { + // we use horizontal lines for fitting + fit.linetype |= 0; + fit.weight += g->horizontal_weight; + enough_lines = enough_lines && (g->horizontal_count >= MINIMUM_FITLINES); + } + + // this needs to come after ASHIFT_FIT_LINES_VERT and ASHIFT_FIT_LINES_HOR + if((mdir & ASHIFT_FIT_LINES_BOTH) == ASHIFT_FIT_LINES_BOTH) + { + // if we use fitting in both directions we need to + // adjust fit.linetype and fit.linemask to match all selected lines + fit.linetype = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED; + fit.linemask = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED; + } + + double quality = model_fitness(params, (void *)&fit); + + printf("model fitness: %.8f (rotation %f, lensshift_v %f, lensshift_h %f, shear %f)\n", + quality, p->rotation, p->lensshift_v, p->lensshift_h, p->shear); +} +#endif +#endif // if 0 +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT (no crop support yet) +//----------------------------------------------------------------------------- +#if 0 +// function to keep crop fitting parameters within constraints +static void crop_constraint(double *params, int pcount) +{ + if(pcount > 0) params[0] = fabs(params[0]); + if(pcount > 1) params[1] = fabs(params[1]); + if(pcount > 2) params[2] = fabs(params[2]); + + if(pcount > 0 && params[0] > 1.0) params[0] = 1.0 - params[0]; + if(pcount > 1 && params[1] > 1.0) params[1] = 1.0 - params[1]; + if(pcount > 2 && params[2] > 0.5*M_PI) params[2] = 0.5*M_PI - params[2]; +} + +// helper function for getting the best fitting crop area; +// returns the negative area of the largest rectangle that fits within the +// defined image with a given rectangle's center and its aspect angle; +// the trick: the rectangle center coordinates are given in the input +// image coordinates so we know for sure that it also lies within the image after +// conversion to the output coordinates +static double crop_fitness(double *params, void *data) +{ + dt_iop_ashift_cropfit_params_t *cropfit = (dt_iop_ashift_cropfit_params_t *)data; + + const float wd = cropfit->width; + const float ht = cropfit->height; + + // get variable and constant parameters, respectively + const float x = isnan(cropfit->x) ? params[0] : cropfit->x; + const float y = isnan(cropfit->y) ? params[1] : cropfit->y; + const float alpha = isnan(cropfit->alpha) ? params[2] : cropfit->alpha; + + // the center of the rectangle in input image coordinates + const float Pc[3] = { x * wd, y * ht, 1.0f }; + + // convert to the output image coordinates and normalize + float P[3]; + mat3mulv(P, (float *)cropfit->homograph, Pc); + P[0] /= P[2]; + P[1] /= P[2]; + P[2] = 1.0f; + + // two auxiliary points (some arbitrary distance away from P) to construct the diagonals + const float Pa[2][3] = { { P[0] + 10.0f * cos(alpha), P[1] + 10.0f * sin(alpha), 1.0f }, + { P[0] + 10.0f * cos(alpha), P[1] - 10.0f * sin(alpha), 1.0f } }; + + // the two diagonals: D = P x Pa + float D[2][3]; + vec3prodn(D[0], P, Pa[0]); + vec3prodn(D[1], P, Pa[1]); + + // find all intersection points of all four edges with both diagonals (I = E x D); + // the shortest distance d2min of the intersection point I to the crop area center P determines + // the size of the crop area that still fits into the image (for the given center and aspect angle) + float d2min = FLT_MAX; + for(int k = 0; k < 4; k++) + for(int l = 0; l < 2; l++) + { + // the intersection point + float I[3]; + vec3prodn(I, cropfit->edges[k], D[l]); + + // special case: I is all null -> E and D are identical -> P lies on E -> d2min = 0 + if(vec3isnull(I)) + { + d2min = 0.0f; + break; + } + + // special case: I[2] is 0.0f -> E and D are parallel and intersect at infinity -> no relevant point + if(I[2] == 0.0f) + continue; + + // the default case -> normalize I + I[0] /= I[2]; + I[1] /= I[2]; + + // calculate distance from I to P + const float d2 = SQR(P[0] - I[0]) + SQR(P[1] - I[1]); + + // the minimum distance over all intersection points + d2min = MIN(d2min, d2); + } + + // calculate the area of the rectangle + const float A = 2.0f * d2min * sin(2.0f * alpha); + +#ifdef ASHIFT_DEBUG + printf("crop fitness with x %f, y %f, angle %f -> distance %f, area %f\n", + x, y, alpha, d2min, A); +#endif + // and return -A to allow Nelder-Mead simplex to search for the minimum + return -A; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +// strategy: for a given center of the crop area and a specific aspect angle +// we calculate the largest crop area that still lies within the output image; +// now we allow a Nelder-Mead simplex to search for the center coordinates +// (and optionally the aspect angle) that delivers the largest overall crop area. +static void do_crop(dt_iop_module_t *module, dt_iop_ashift_params_t *p) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + // skip if fitting is still running + if(g->fitting) return; + + // reset fit margins if auto-cropping is off + if(p->cropmode == ASHIFT_CROP_OFF) + { + p->cl = 0.0f; + p->cr = 1.0f; + p->ct = 0.0f; + p->cb = 1.0f; + return; + } + + g->fitting = 1; + + double params[3]; + int pcount; + + // get parameters for the homograph + const float f_length_kb = (p->mode == ASHIFT_MODE_GENERIC) ? DEFAULT_F_LENGTH : p->f_length * p->crop_factor; + const float orthocorr = (p->mode == ASHIFT_MODE_GENERIC) ? 0.0f : p->orthocorr; + const float aspect = (p->mode == ASHIFT_MODE_GENERIC) ? 1.0f : p->aspect; + const float rotation = p->rotation; + const float lensshift_v = p->lensshift_v; + const float lensshift_h = p->lensshift_h; + const float shear = p->shear; + + // prepare structure of constant parameters + dt_iop_ashift_cropfit_params_t cropfit; + cropfit.width = g->buf_width; + cropfit.height = g->buf_height; + homography((float *)cropfit.homograph, rotation, lensshift_v, lensshift_h, shear, f_length_kb, + orthocorr, aspect, cropfit.width, cropfit.height, ASHIFT_HOMOGRAPH_FORWARD); + + const float wd = cropfit.width; + const float ht = cropfit.height; + + // the four vertices of the image in input image coordinates + const float Vc[4][3] = { { 0.0f, 0.0f, 1.0f }, + { 0.0f, ht, 1.0f }, + { wd, ht, 1.0f }, + { wd, 0.0f, 1.0f } }; + + // convert the vertices to output image coordinates + float V[4][3]; + for(int n = 0; n < 4; n++) + mat3mulv(V[n], (float *)cropfit.homograph, Vc[n]); + + // get width and height of output image for later use + float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN; + for(int n = 0; n < 4; n++) + { + // normalize V + V[n][0] /= V[n][2]; + V[n][1] /= V[n][2]; + V[n][2] = 1.0f; + xmin = MIN(xmin, V[n][0]); + xmax = MAX(xmax, V[n][0]); + ymin = MIN(ymin, V[n][1]); + ymax = MAX(ymax, V[n][1]); + } + const float owd = xmax - xmin; + const float oht = ymax - ymin; + + // calculate the lines defining the four edges of the image area: E = V[n] x V[n+1] + for(int n = 0; n < 4; n++) + vec3prodn(cropfit.edges[n], V[n], V[(n + 1) % 4]); + + // initial fit parameters: crop area is centered and aspect angle is that of the original image + // number of parameters: fit only crop center coordinates with a fixed aspect ratio, or fit all three variables + if(p->cropmode == ASHIFT_CROP_LARGEST) + { + params[0] = 0.5; + params[1] = 0.5; + params[2] = atan2((float)cropfit.height, (float)cropfit.width); + cropfit.x = NAN; + cropfit.y = NAN; + cropfit.alpha = NAN; + pcount = 3; + } + else //(p->cropmode == ASHIFT_CROP_ASPECT) + { + params[0] = 0.5; + params[1] = 0.5; + cropfit.x = NAN; + cropfit.y = NAN; + cropfit.alpha = atan2((float)cropfit.height, (float)cropfit.width); + pcount = 2; + } + + // start the simplex fit + const int iter = simplex(crop_fitness, params, pcount, NMS_CROP_EPSILON, NMS_CROP_SCALE, NMS_CROP_ITERATIONS, + crop_constraint, (void*)&cropfit); + + float A; // RT + float d; // RT + float Pc[3] = { 0.f, 0.f, 1.f }; // RT + + // in case the fit did not converge -> failed + if(iter >= NMS_CROP_ITERATIONS) goto failed; + + // the fit did converge -> get clipping margins out of params: + cropfit.x = isnan(cropfit.x) ? params[0] : cropfit.x; + cropfit.y = isnan(cropfit.y) ? params[1] : cropfit.y; + cropfit.alpha = isnan(cropfit.alpha) ? params[2] : cropfit.alpha; + + // the area of the best fitting rectangle + /*RT const float*/ A = fabs(crop_fitness(params, (void*)&cropfit)); + + // unlikely to happen but we need to catch this case + if(A == 0.0f) goto failed; + + // we need the half diagonal of that rectangle (this is in output image dimensions); + // no need to check for division by zero here as this case implies A == 0.0f, caught above + /*RT const float*/ d = sqrt(A / (2.0f * sin(2.0f * cropfit.alpha))); + + // the rectangle's center in input image (homogeneous) coordinates + // RT const float Pc[3] = { cropfit.x * wd, cropfit.y * ht, 1.0f }; + Pc[0] = cropfit.x * wd; // RT + Pc[1] = cropfit.y * ht; // RT + + // convert rectangle center to output image coordinates and normalize + float P[3]; + mat3mulv(P, (float *)cropfit.homograph, Pc); + P[0] /= P[2]; + P[1] /= P[2]; + + // calculate clipping margins relative to output image dimensions + p->cl = CLAMP((P[0] - d * cos(cropfit.alpha)) / owd, 0.0f, 1.0f); + p->cr = CLAMP((P[0] + d * cos(cropfit.alpha)) / owd, 0.0f, 1.0f); + p->ct = CLAMP((P[1] - d * sin(cropfit.alpha)) / oht, 0.0f, 1.0f); + p->cb = CLAMP((P[1] + d * sin(cropfit.alpha)) / oht, 0.0f, 1.0f); + + // final sanity check + if(p->cr - p->cl <= 0.0f || p->cb - p->ct <= 0.0f) goto failed; + + g->fitting = 0; + +#ifdef ASHIFT_DEBUG + printf("margins after crop fitting: iter %d, x %f, y %f, angle %f, crop area (%f %f %f %f), width %f, height %f\n", + iter, cropfit.x, cropfit.y, cropfit.alpha, p->cl, p->cr, p->ct, p->cb, wd, ht); +#endif +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 + dt_control_queue_redraw_center(); +#endif // if 0 +//----------------------------------------------------------------------------- + + return; + +failed: + // in case of failure: reset clipping margins, set "automatic cropping" parameter + // to "off" state, and display warning message + p->cl = 0.0f; + p->cr = 1.0f; + p->ct = 0.0f; + p->cb = 1.0f; + p->cropmode = ASHIFT_CROP_OFF; +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 + dt_bauhaus_combobox_set(g->cropmode, p->cropmode); +#endif // if 0 +//----------------------------------------------------------------------------- + g->fitting = 0; + dt_control_log(_("automatic cropping failed")); + return; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT (no crop support yet) +//----------------------------------------------------------------------------- +#if 0 +// manually adjust crop area by shifting its center +static void crop_adjust(dt_iop_module_t *module, dt_iop_ashift_params_t *p, const float newx, const float newy) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + // skip if fitting is still running + if(g->fitting) return; + + // get parameters for the homograph + const float f_length_kb = (p->mode == ASHIFT_MODE_GENERIC) ? DEFAULT_F_LENGTH : p->f_length * p->crop_factor; + const float orthocorr = (p->mode == ASHIFT_MODE_GENERIC) ? 0.0f : p->orthocorr; + const float aspect = (p->mode == ASHIFT_MODE_GENERIC) ? 1.0f : p->aspect; + const float rotation = p->rotation; + const float lensshift_v = p->lensshift_v; + const float lensshift_h = p->lensshift_h; + const float shear = p->shear; + + const float wd = g->buf_width; + const float ht = g->buf_height; + + const float alpha = atan2(ht, wd); + + float homograph[3][3]; + homography((float *)homograph, rotation, lensshift_v, lensshift_h, shear, f_length_kb, + orthocorr, aspect, wd, ht, ASHIFT_HOMOGRAPH_FORWARD); + + // the four vertices of the image in input image coordinates + const float Vc[4][3] = { { 0.0f, 0.0f, 1.0f }, + { 0.0f, ht, 1.0f }, + { wd, ht, 1.0f }, + { wd, 0.0f, 1.0f } }; + + // convert the vertices to output image coordinates + float V[4][3]; + for(int n = 0; n < 4; n++) + mat3mulv(V[n], (float *)homograph, Vc[n]); + + // get width and height of output image + float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN; + for(int n = 0; n < 4; n++) + { + // normalize V + V[n][0] /= V[n][2]; + V[n][1] /= V[n][2]; + V[n][2] = 1.0f; + xmin = MIN(xmin, V[n][0]); + xmax = MAX(xmax, V[n][0]); + ymin = MIN(ymin, V[n][1]); + ymax = MAX(ymax, V[n][1]); + } + const float owd = xmax - xmin; + const float oht = ymax - ymin; + + // calculate the lines defining the four edges of the image area: E = V[n] x V[n+1] + float E[4][3]; + for(int n = 0; n < 4; n++) + vec3prodn(E[n], V[n], V[(n + 1) % 4]); + + // the center of the rectangle in output image coordinates + const float P[3] = { newx * owd, newy * oht, 1.0f }; + + // two auxiliary points (some arbitrary distance away from P) to construct the diagonals + const float Pa[2][3] = { { P[0] + 10.0f * cos(alpha), P[1] + 10.0f * sin(alpha), 1.0f }, + { P[0] + 10.0f * cos(alpha), P[1] - 10.0f * sin(alpha), 1.0f } }; + + // the two diagonals: D = P x Pa + float D[2][3]; + vec3prodn(D[0], P, Pa[0]); + vec3prodn(D[1], P, Pa[1]); + + // find all intersection points of all four edges with both diagonals (I = E x D); + // the shortest distance d2min of the intersection point I to the crop area center P determines + // the size of the crop area that still fits into the image (for the given center and aspect angle) + float d2min = FLT_MAX; + for(int k = 0; k < 4; k++) + for(int l = 0; l < 2; l++) + { + // the intersection point + float I[3]; + vec3prodn(I, E[k], D[l]); + + // special case: I is all null -> E and D are identical -> P lies on E -> d2min = 0 + if(vec3isnull(I)) + { + d2min = 0.0f; + break; + } + + // special case: I[2] is 0.0f -> E and D are parallel and intersect at infinity -> no relevant point + if(I[2] == 0.0f) + continue; + + // the default case -> normalize I + I[0] /= I[2]; + I[1] /= I[2]; + + // calculate distance from I to P + const float d2 = SQR(P[0] - I[0]) + SQR(P[1] - I[1]); + + // the minimum distance over all intersection points + d2min = MIN(d2min, d2); + } + + const float d = sqrt(d2min); + + // do not allow crop area to drop below 1% of input image area + const float A = 2.0f * d * d * sin(2.0f * alpha); + if(A < 0.01f * wd * ht) return; + + // calculate clipping margins relative to output image dimensions + p->cl = CLAMP((P[0] - d * cos(alpha)) / owd, 0.0f, 1.0f); + p->cr = CLAMP((P[0] + d * cos(alpha)) / owd, 0.0f, 1.0f); + p->ct = CLAMP((P[1] - d * sin(alpha)) / oht, 0.0f, 1.0f); + p->cb = CLAMP((P[1] + d * sin(alpha)) / oht, 0.0f, 1.0f); + +#ifdef ASHIFT_DEBUG + printf("margins after crop adjustment: x %f, y %f, angle %f, crop area (%f %f %f %f), width %f, height %f\n", + 0.5f * (p->cl + p->cr), 0.5f * (p->ct + p->cb), alpha, p->cl, p->cr, p->ct, p->cb, wd, ht); +#endif + dt_control_queue_redraw_center(); + return; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// helper function to start analysis for structural data and report about errors +static int do_get_structure(dt_iop_module_t *module, dt_iop_ashift_params_t *p, + dt_iop_ashift_enhance_t enhance) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + if(g->fitting) return FALSE; + + g->fitting = 1; + + float *b = NULL; + { + MyMutex::MyLock lock(g->lock); + b = g->buf; + } + /* dt_pthread_mutex_lock(&g->lock); */ + /* float *b = g->buf; */ + /* dt_pthread_mutex_unlock(&g->lock); */ + + if(b == NULL) + { + dt_control_log(_("data pending - please repeat")); + goto error; + } + + if(!get_structure(module, enhance)) + { + dt_control_log(_("could not detect structural data in image")); +#ifdef ASHIFT_DEBUG + // find out more + printf("do_get_structure: buf %p, buf_hash %lu, buf_width %d, buf_height %d, lines %p, lines_count %d\n", + g->buf, g->buf_hash, g->buf_width, g->buf_height, g->lines, g->lines_count); +#endif + goto error; + } + + if(!remove_outliers(module)) + { + dt_control_log(_("could not run outlier removal")); +#ifdef ASHIFT_DEBUG + // find out more + printf("remove_outliers: buf %p, buf_hash %lu, buf_width %d, buf_height %d, lines %p, lines_count %d\n", + g->buf, g->buf_hash, g->buf_width, g->buf_height, g->lines, g->lines_count); +#endif + goto error; + } + + g->fitting = 0; + return TRUE; + +error: + g->fitting = 0; + return FALSE; +} + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +// helper function to clean structural data +static int do_clean_structure(dt_iop_module_t *module, dt_iop_ashift_params_t *p) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + if(g->fitting) return FALSE; + + g->fitting = 1; + g->lines_count = 0; + g->vertical_count = 0; + g->horizontal_count = 0; + free(g->lines); + g->lines = NULL; + g->lines_version++; + g->lines_suppressed = 0; + g->fitting = 0; + return TRUE; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// helper function to start parameter fit and report about errors +static int do_fit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir, int min_line_count = MINIMUM_FITLINES) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + dt_iop_ashift_nmsresult_t res; + + if(g->fitting) return FALSE; + + // if no structure available get it + if(g->lines == NULL) + if(!do_get_structure(module, p, ASHIFT_ENHANCE_NONE)) goto error; + + g->fitting = 1; + + res = nmsfit(module, p, dir, min_line_count); + + switch(res) + { + case NMS_NOT_ENOUGH_LINES: + dt_control_log(_("not enough structure for automatic correction")); + goto error; + break; + case NMS_DID_NOT_CONVERGE: + case NMS_INSANE: + dt_control_log(_("automatic correction failed, please correct manually")); + goto error; + break; + case NMS_SUCCESS: + default: + break; + } + + g->fitting = 0; + + /* + // finally apply cropping + do_crop(module, p); + */ + + return TRUE; + +error: + g->fitting = 0; + return FALSE; +} + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +//----------------------------------------------------------------------------- +void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, + void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) +{ + dt_iop_ashift_data_t *data = (dt_iop_ashift_data_t *)piece->data; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + const int ch = piece->colors; + const int ch_width = ch * roi_in->width; + + // only for preview pipe: collect input buffer data and do some other evaluations + if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW) + { + // we want to find out if the final output image is flipped in relation to this iop + // so we can adjust the gui labels accordingly + + const int width = roi_in->width; + const int height = roi_in->height; + const int x_off = roi_in->x; + const int y_off = roi_in->y; + const float scale = roi_in->scale; + + // origin of image and opposite corner as reference points + float points[4] = { 0.0f, 0.0f, (float)piece->buf_in.width, (float)piece->buf_in.height }; + float ivec[2] = { points[2] - points[0], points[3] - points[1] }; + float ivecl = sqrt(ivec[0] * ivec[0] + ivec[1] * ivec[1]); + + // where do they go? + dt_dev_distort_backtransform_plus(self->dev, self->dev->preview_pipe, self->priority + 1, 9999999, points, + 2); + + float ovec[2] = { points[2] - points[0], points[3] - points[1] }; + float ovecl = sqrt(ovec[0] * ovec[0] + ovec[1] * ovec[1]); + + // angle between input vector and output vector + float alpha = acos(CLAMP((ivec[0] * ovec[0] + ivec[1] * ovec[1]) / (ivecl * ovecl), -1.0f, 1.0f)); + + // we are interested if |alpha| is in the range of 90° +/- 45° -> we assume the image is flipped + int isflipped = fabs(fmod(alpha + M_PI, M_PI) - M_PI / 2.0f) < M_PI / 4.0f ? 1 : 0; + + // did modules prior to this one in pixelpipe have changed? -> check via hash value + uint64_t hash = dt_dev_hash_plus(self->dev, self->dev->preview_pipe, 0, self->priority - 1); + + dt_pthread_mutex_lock(&g->lock); + g->isflipped = isflipped; + + // save a copy of preview input buffer for parameter fitting + if(g->buf == NULL || (size_t)g->buf_width * g->buf_height < (size_t)width * height) + { + // if needed to allocate buffer + free(g->buf); // a no-op if g->buf is NULL + // only get new buffer if no old buffer available or old buffer does not fit in terms of size + g->buf = malloc((size_t)width * height * 4 * sizeof(float)); + } + + if(g->buf /* && hash != g->buf_hash */) + { + // copy data + memcpy(g->buf, ivoid, (size_t)width * height * ch * sizeof(float)); + + g->buf_width = width; + g->buf_height = height; + g->buf_x_off = x_off; + g->buf_y_off = y_off; + g->buf_scale = scale; + g->buf_hash = hash; + } + + dt_pthread_mutex_unlock(&g->lock); + } + + // if module is set to neutral parameters we just copy input->output and are done + if(isneutral(data)) + { + memcpy(ovoid, ivoid, (size_t)roi_out->width * roi_out->height * ch * sizeof(float)); + return; + } + + const struct dt_interpolation *interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF); + + float ihomograph[3][3]; + homography((float *)ihomograph, data->rotation, data->lensshift_v, data->lensshift_h, data->shear, data->f_length_kb, + data->orthocorr, data->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_INVERTED); + + // clipping offset + const float fullwidth = (float)piece->buf_out.width / (data->cr - data->cl); + const float fullheight = (float)piece->buf_out.height / (data->cb - data->ct); + const float cx = roi_out->scale * fullwidth * data->cl; + const float cy = roi_out->scale * fullheight * data->ct; + + +#ifdef _OPENMP +//#pragma omp parallel for schedule(static) shared(ihomograph, interpolation) +#endif + // go over all pixels of output image + for(int j = 0; j < roi_out->height; j++) + { + float *out = ((float *)ovoid) + (size_t)ch * j * roi_out->width; + for(int i = 0; i < roi_out->width; i++, out += ch) + { + float pin[3], pout[3]; + + /* if (j == roi_out->height - 1) { */ + /* printf("HERE\n"); */ + /* } */ + + // convert output pixel coordinates to original image coordinates + pout[0] = roi_out->x + i + cx; + pout[1] = roi_out->y + j + cy; + pout[0] /= roi_out->scale; + pout[1] /= roi_out->scale; + pout[2] = 1.0f; + + // apply homograph + mat3mulv(pin, (float *)ihomograph, pout); + + // convert to input pixel coordinates + pin[0] /= pin[2]; + pin[1] /= pin[2]; + pin[0] *= roi_in->scale; + pin[1] *= roi_in->scale; + + /* if (pin[0] < 0 || pin[1] < 0) { */ + /* printf("NEGATIVE: %f %f -> %f %f\n", pout[0], pout[1], pin[0], pin[1]); */ + /* fflush(stdout); */ + /* } */ + + + pin[0] -= roi_in->x; + pin[1] -= roi_in->y; + + // get output values by interpolation from input image + dt_interpolation_compute_pixel4c(interpolation, (float *)ivoid, out, pin[0], pin[1], roi_in->width, + roi_in->height, ch_width); + } + } +} + +#ifdef HAVE_OPENCL +int process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out, + const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) +{ + dt_iop_ashift_data_t *d = (dt_iop_ashift_data_t *)piece->data; + dt_iop_ashift_global_data_t *gd = (dt_iop_ashift_global_data_t *)self->data; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + const int devid = piece->pipe->devid; + const int iwidth = roi_in->width; + const int iheight = roi_in->height; + const int width = roi_out->width; + const int height = roi_out->height; + + cl_int err = -999; + cl_mem dev_homo = NULL; + + // only for preview pipe: collect input buffer data and do some other evaluations + if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW) + { + // we want to find out if the final output image is flipped in relation to this iop + // so we can adjust the gui labels accordingly + + const int x_off = roi_in->x; + const int y_off = roi_in->y; + const float scale = roi_in->scale; + + // origin of image and opposite corner as reference points + float points[4] = { 0.0f, 0.0f, (float)piece->buf_in.width, (float)piece->buf_in.height }; + float ivec[2] = { points[2] - points[0], points[3] - points[1] }; + float ivecl = sqrt(ivec[0] * ivec[0] + ivec[1] * ivec[1]); + + // where do they go? + dt_dev_distort_backtransform_plus(self->dev, self->dev->preview_pipe, self->priority + 1, 9999999, points, + 2); + + float ovec[2] = { points[2] - points[0], points[3] - points[1] }; + float ovecl = sqrt(ovec[0] * ovec[0] + ovec[1] * ovec[1]); + + // angle between input vector and output vector + float alpha = acos(CLAMP((ivec[0] * ovec[0] + ivec[1] * ovec[1]) / (ivecl * ovecl), -1.0f, 1.0f)); + + // we are interested if |alpha| is in the range of 90° +/- 45° -> we assume the image is flipped + int isflipped = fabs(fmod(alpha + M_PI, M_PI) - M_PI / 2.0f) < M_PI / 4.0f ? 1 : 0; + + // do modules coming before this one in pixelpipe have changed? -> check via hash value + uint64_t hash = dt_dev_hash_plus(self->dev, self->dev->preview_pipe, 0, self->priority - 1); + + dt_pthread_mutex_lock(&g->lock); + g->isflipped = isflipped; + + // save a copy of preview input buffer for parameter fitting + if(g->buf == NULL || (size_t)g->buf_width * g->buf_height < (size_t)iwidth * iheight) + { + // if needed allocate buffer + free(g->buf); // a no-op if g->buf is NULL + // only get new buffer if no old buffer or old buffer does not fit in terms of size + g->buf = malloc((size_t)iwidth * iheight * 4 * sizeof(float)); + } + + if(g->buf /* && hash != g->buf_hash */) + { + // copy data + err = dt_opencl_copy_device_to_host(devid, g->buf, dev_in, iwidth, iheight, 4 * sizeof(float)); + + g->buf_width = iwidth; + g->buf_height = iheight; + g->buf_x_off = x_off; + g->buf_y_off = y_off; + g->buf_scale = scale; + g->buf_hash = hash; + } + dt_pthread_mutex_unlock(&g->lock); + if(err != CL_SUCCESS) goto error; + } + + // if module is set to neutral parameters we just copy input->output and are done + if(isneutral(d)) + { + size_t origin[] = { 0, 0, 0 }; + size_t region[] = { width, height, 1 }; + err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region); + if(err != CL_SUCCESS) goto error; + return TRUE; + } + + float ihomograph[3][3]; + homography((float *)ihomograph, d->rotation, d->lensshift_v, d->lensshift_h, d->shear, d->f_length_kb, d->camera_pitch, d->camera_yaw, + d->orthocorr, d->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_INVERTED); + + // clipping offset + const float fullwidth = (float)piece->buf_out.width / (d->cr - d->cl); + const float fullheight = (float)piece->buf_out.height / (d->cb - d->ct); + const float cx = roi_out->scale * fullwidth * d->cl; + const float cy = roi_out->scale * fullheight * d->ct; + + dev_homo = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * 9, ihomograph); + if(dev_homo == NULL) goto error; + + const int iroi[2] = { roi_in->x, roi_in->y }; + const int oroi[2] = { roi_out->x, roi_out->y }; + const float in_scale = roi_in->scale; + const float out_scale = roi_out->scale; + const float clip[2] = { cx, cy }; + + size_t sizes[] = { ROUNDUPWD(width), ROUNDUPHT(height), 1 }; + + const struct dt_interpolation *interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF); + + int ldkernel = -1; + + switch(interpolation->id) + { + case DT_INTERPOLATION_BILINEAR: + ldkernel = gd->kernel_ashift_bilinear; + break; + case DT_INTERPOLATION_BICUBIC: + ldkernel = gd->kernel_ashift_bicubic; + break; + case DT_INTERPOLATION_LANCZOS2: + ldkernel = gd->kernel_ashift_lanczos2; + break; + case DT_INTERPOLATION_LANCZOS3: + ldkernel = gd->kernel_ashift_lanczos3; + break; + default: + goto error; + } + + dt_opencl_set_kernel_arg(devid, ldkernel, 0, sizeof(cl_mem), (void *)&dev_in); + dt_opencl_set_kernel_arg(devid, ldkernel, 1, sizeof(cl_mem), (void *)&dev_out); + dt_opencl_set_kernel_arg(devid, ldkernel, 2, sizeof(int), (void *)&width); + dt_opencl_set_kernel_arg(devid, ldkernel, 3, sizeof(int), (void *)&height); + dt_opencl_set_kernel_arg(devid, ldkernel, 4, sizeof(int), (void *)&iwidth); + dt_opencl_set_kernel_arg(devid, ldkernel, 5, sizeof(int), (void *)&iheight); + dt_opencl_set_kernel_arg(devid, ldkernel, 6, 2 * sizeof(int), (void *)iroi); + dt_opencl_set_kernel_arg(devid, ldkernel, 7, 2 * sizeof(int), (void *)oroi); + dt_opencl_set_kernel_arg(devid, ldkernel, 8, sizeof(float), (void *)&in_scale); + dt_opencl_set_kernel_arg(devid, ldkernel, 9, sizeof(float), (void *)&out_scale); + dt_opencl_set_kernel_arg(devid, ldkernel, 10, 2 * sizeof(float), (void *)clip); + dt_opencl_set_kernel_arg(devid, ldkernel, 11, sizeof(cl_mem), (void *)&dev_homo); + err = dt_opencl_enqueue_kernel_2d(devid, ldkernel, sizes); + if(err != CL_SUCCESS) goto error; + + dt_opencl_release_mem_object(dev_homo); + return TRUE; + +error: + dt_opencl_release_mem_object(dev_homo); + dt_print(DT_DEBUG_OPENCL, "[opencl_ashift] couldn't enqueue kernel! %d\n", err); + return FALSE; +} +#endif + +// gather information about "near"-ness in g->points_idx +static void get_near(const float *points, dt_iop_ashift_points_idx_t *points_idx, const int lines_count, + float pzx, float pzy, float delta) +{ + const float delta2 = delta * delta; + + for(int n = 0; n < lines_count; n++) + { + points_idx[n].near = 0; + + // skip irrelevant lines + if(points_idx[n].type == ASHIFT_LINE_IRRELEVANT) + continue; + + // first check if the mouse pointer is outside the bounding box of the line -> skip this line + if(pzx < points_idx[n].bbx - delta && + pzx > points_idx[n].bbX + delta && + pzy < points_idx[n].bby - delta && + pzy > points_idx[n].bbY + delta) + continue; + + // pointer is inside bounding box + size_t offset = points_idx[n].offset; + const int length = points_idx[n].length; + + // sanity check (this should not happen) + if(length < 2) continue; + + // check line point by point + for(int l = 0; l < length; l++, offset++) + { + float dx = pzx - points[offset * 2]; + float dy = pzy - points[offset * 2 + 1]; + + if(dx * dx + dy * dy < delta2) + { + points_idx[n].near = 1; + break; + } + } + } +} + +// mark lines which are inside a rectangular area in isbounding mode +static void get_bounded_inside(const float *points, dt_iop_ashift_points_idx_t *points_idx, + const int points_lines_count, float pzx, float pzy, float pzx2, float pzy2, + dt_iop_ashift_bounding_t mode) +{ + // get bounding box coordinates + float ax = pzx; + float ay = pzy; + float bx = pzx2; + float by = pzy2; + if(pzx > pzx2) + { + ax = pzx2; + bx = pzx; + } + if(pzy > pzy2) + { + ay = pzy2; + by = pzy; + } + + // we either look for the selected or the deselected lines + dt_iop_ashift_linetype_t mask = ASHIFT_LINE_SELECTED; + dt_iop_ashift_linetype_t state = (mode == ASHIFT_BOUNDING_DESELECT) ? ASHIFT_LINE_SELECTED : 0; + + for(int n = 0; n < points_lines_count; n++) + { + // mark line as "not near" and "not bounded" + points_idx[n].near = 0; + points_idx[n].bounded = 0; + + // skip irrelevant lines + if(points_idx[n].type == ASHIFT_LINE_IRRELEVANT) + continue; + + // is the line inside the box ? + if(points_idx[n].bbx >= ax && points_idx[n].bbx <= bx && points_idx[n].bbX >= ax + && points_idx[n].bbX <= bx && points_idx[n].bby >= ay && points_idx[n].bby <= by + && points_idx[n].bbY >= ay && points_idx[n].bbY <= by) + { + points_idx[n].bounded = 1; + // only mark "near"-ness of those lines we are interested in + points_idx[n].near = ((points_idx[n].type & mask) != state) ? 0 : 1; + } + } +} + +// generate hash value for lines taking into account only the end point coordinates +static uint64_t get_lines_hash(const dt_iop_ashift_line_t *lines, const int lines_count) +{ + uint64_t hash = 5381; + for(int n = 0; n < lines_count; n++) + { + float v[4] = { lines[n].p1[0], lines[n].p1[1], lines[n].p2[0], lines[n].p2[1] }; + + for(int i = 0; i < 4; i++) + hash = ((hash << 5) + hash) ^ ((uint32_t *)v)[i]; + } + return hash; +} + +// update color information in points_idx if lines have changed in terms of type (but not in terms +// of number or position) +static int update_colors(struct dt_iop_module_t *self, dt_iop_ashift_points_idx_t *points_idx, + int points_lines_count) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + // is the display flipped relative to the original image? + const int isflipped = g->isflipped; + + // go through all lines + for(int n = 0; n < points_lines_count; n++) + { + const dt_iop_ashift_linetype_t type = points_idx[n].type; + + // set line color according to line type/orientation + // note: if the screen display is flipped versus the original image we need + // to respect that fact in the color selection + if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_VERTICAL_SELECTED) + points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_BLUE : ASHIFT_LINECOLOR_GREEN; + else if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_VERTICAL_NOT_SELECTED) + points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_YELLOW : ASHIFT_LINECOLOR_RED; + else if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_HORIZONTAL_SELECTED) + points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_GREEN : ASHIFT_LINECOLOR_BLUE; + else if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_HORIZONTAL_NOT_SELECTED) + points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_RED : ASHIFT_LINECOLOR_YELLOW; + else + points_idx[n].color = ASHIFT_LINECOLOR_GREY; + } + + return TRUE; +} + +// get all the points to display lines in the gui +static int get_points(struct dt_iop_module_t *self, const dt_iop_ashift_line_t *lines, const int lines_count, + const int lines_version, float **points, dt_iop_ashift_points_idx_t **points_idx, + int *points_lines_count) +{ + dt_develop_t *dev = self->dev; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + dt_iop_ashift_points_idx_t *my_points_idx = NULL; + float *my_points = NULL; + + // is the display flipped relative to the original image? + const int isflipped = g->isflipped; + + // allocate new index array + my_points_idx = (dt_iop_ashift_points_idx_t *)malloc(lines_count * sizeof(dt_iop_ashift_points_idx_t)); + if(my_points_idx == NULL) goto error; + + // account for total number of points + size_t total_points = 0; + + // first step: basic initialization of my_points_idx and counting of total_points + for(int n = 0; n < lines_count; n++) + { + const int length = lines[n].length; + + total_points += length; + + my_points_idx[n].length = length; + my_points_idx[n].near = 0; + my_points_idx[n].bounded = 0; + + const dt_iop_ashift_linetype_t type = lines[n].type; + my_points_idx[n].type = type; + + // set line color according to line type/orientation + // note: if the screen display is flipped versus the original image we need + // to respect that fact in the color selection + if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_VERTICAL_SELECTED) + my_points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_BLUE : ASHIFT_LINECOLOR_GREEN; + else if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_VERTICAL_NOT_SELECTED) + my_points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_YELLOW : ASHIFT_LINECOLOR_RED; + else if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_HORIZONTAL_SELECTED) + my_points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_GREEN : ASHIFT_LINECOLOR_BLUE; + else if((type & ASHIFT_LINE_MASK) == ASHIFT_LINE_HORIZONTAL_NOT_SELECTED) + my_points_idx[n].color = isflipped ? ASHIFT_LINECOLOR_RED : ASHIFT_LINECOLOR_YELLOW; + else + my_points_idx[n].color = ASHIFT_LINECOLOR_GREY; + } + + // now allocate new points buffer + my_points = (float *)malloc((size_t)2 * total_points * sizeof(float)); + if(my_points == NULL) goto error; + + // second step: generate points for each line + for(int n = 0, offset = 0; n < lines_count; n++) + { + my_points_idx[n].offset = offset; + + float x = lines[n].p1[0]; + float y = lines[n].p1[1]; + const int length = lines[n].length; + + const float dx = (lines[n].p2[0] - x) / (float)(length - 1); + const float dy = (lines[n].p2[1] - y) / (float)(length - 1); + + for(int l = 0; l < length && offset < total_points; l++, offset++) + { + my_points[2 * offset] = x; + my_points[2 * offset + 1] = y; + + x += dx; + y += dy; + } + } + + // third step: transform all points + if(!dt_dev_distort_transform_plus(dev, dev->preview_pipe, self->priority, 9999999, my_points, total_points)) + goto error; + + // fourth step: get bounding box in final coordinates (used later for checking "near"-ness to mouse pointer) + for(int n = 0; n < lines_count; n++) + { + float xmin = FLT_MAX, xmax = FLT_MIN, ymin = FLT_MAX, ymax = FLT_MIN; + + size_t offset = my_points_idx[n].offset; + int length = my_points_idx[n].length; + + for(int l = 0; l < length; l++) + { + xmin = fmin(xmin, my_points[2 * offset]); + xmax = fmax(xmax, my_points[2 * offset]); + ymin = fmin(ymin, my_points[2 * offset + 1]); + ymax = fmax(ymax, my_points[2 * offset + 1]); + } + + my_points_idx[n].bbx = xmin; + my_points_idx[n].bbX = xmax; + my_points_idx[n].bby = ymin; + my_points_idx[n].bbY = ymax; + } + + // check if lines_version has changed in-between -> too bad: we can forget about all we did :( + if(g->lines_version > lines_version) + goto error; + + *points = my_points; + *points_idx = my_points_idx; + *points_lines_count = lines_count; + + return TRUE; + +error: + if(my_points_idx != NULL) free(my_points_idx); + if(my_points != NULL) free(my_points); + return FALSE; +} + +// does this gui have focus? +static int gui_has_focus(struct dt_iop_module_t *self) +{ + return self->dev->gui_module == self; +} + +void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, + int32_t pointerx, int32_t pointery) +{ + dt_develop_t *dev = self->dev; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + + // the usual rescaling stuff + const float wd = dev->preview_pipe->backbuf_width; + const float ht = dev->preview_pipe->backbuf_height; + if(wd < 1.0 || ht < 1.0) return; + const float zoom_y = dt_control_get_dev_zoom_y(); + const float zoom_x = dt_control_get_dev_zoom_x(); + const dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); + const int closeup = dt_control_get_dev_closeup(); + const float zoom_scale = dt_dev_get_zoom_scale(dev, zoom, 1<buf has been processed + if(g->buf && (p->cropmode != ASHIFT_CROP_OFF) && self->enabled) + { + // roi data of the preview pipe input buffer + const float iwd = g->buf_width; + const float iht = g->buf_height; + const float ixo = g->buf_x_off; + const float iyo = g->buf_y_off; + + // the four corners of the input buffer of this module + const float V[4][2] = { { ixo, iyo }, + { ixo, iyo + iht }, + { ixo + iwd, iyo + iht }, + { ixo + iwd, iyo } }; + + // convert coordinates of corners to coordinates of this module's output + if(!dt_dev_distort_transform_plus(self->dev, self->dev->preview_pipe, self->priority, self->priority + 1, + (float *)V, 4)) + return; + + // get x/y-offset as well as width and height of output buffer + float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN; + for(int n = 0; n < 4; n++) + { + xmin = MIN(xmin, V[n][0]); + xmax = MAX(xmax, V[n][0]); + ymin = MIN(ymin, V[n][1]); + ymax = MAX(ymax, V[n][1]); + } + const float owd = xmax - xmin; + const float oht = ymax - ymin; + + // the four clipping corners + const float C[4][2] = { { xmin + p->cl * owd, ymin + p->ct * oht }, + { xmin + p->cl * owd, ymin + p->cb * oht }, + { xmin + p->cr * owd, ymin + p->cb * oht }, + { xmin + p->cr * owd, ymin + p->ct * oht } }; + + // convert clipping corners to final output image + if(!dt_dev_distort_transform_plus(self->dev, self->dev->preview_pipe, self->priority + 1, 9999999, + (float *)C, 4)) + return; + + cairo_save(cr); + + double dashes = DT_PIXEL_APPLY_DPI(5.0) / zoom_scale; + cairo_set_dash(cr, &dashes, 0, 0); + + cairo_rectangle(cr, 0, 0, width, height); + cairo_clip(cr); + + // mask parts of image outside of clipping area in dark grey + cairo_set_source_rgba(cr, .2, .2, .2, .8); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle(cr, 0, 0, width, height); + cairo_translate(cr, width / 2.0, height / 2.0); + cairo_scale(cr, zoom_scale, zoom_scale); + cairo_translate(cr, -.5f * wd - zoom_x * wd, -.5f * ht - zoom_y * ht); + cairo_move_to(cr, C[0][0], C[0][1]); + cairo_line_to(cr, C[1][0], C[1][1]); + cairo_line_to(cr, C[2][0], C[2][1]); + cairo_line_to(cr, C[3][0], C[3][1]); + cairo_close_path(cr); + cairo_fill(cr); + + // draw white outline around clipping area + cairo_set_source_rgb(cr, .7, .7, .7); + cairo_move_to(cr, C[0][0], C[0][1]); + cairo_line_to(cr, C[1][0], C[1][1]); + cairo_line_to(cr, C[2][0], C[2][1]); + cairo_line_to(cr, C[3][0], C[3][1]); + cairo_close_path(cr); + cairo_stroke(cr); + + // if adjusting crop, draw indicator + if (g->adjust_crop && p->cropmode == ASHIFT_CROP_ASPECT) + { + const double xpos = (C[1][0] + C[2][0]) / 2.0f; + const double ypos = (C[0][1] + C[1][1]) / 2.0f; + const double size_circle = (C[2][0] - C[1][0]) / 30.0f; + const double size_line = (C[2][0] - C[1][0]) / 5.0f; + const double size_arrow = (C[2][0] - C[1][0]) / 25.0f; + + cairo_set_line_width(cr, 2.0 / zoom_scale); + cairo_set_source_rgb(cr, .7, .7, .7); + cairo_arc (cr, xpos, ypos, size_circle, 0, 2.0 * M_PI); + cairo_stroke(cr); + cairo_fill(cr); + + cairo_set_line_width(cr, 2.0 / zoom_scale); + cairo_set_source_rgb(cr, .7, .7, .7); + + // horizontal line + cairo_move_to(cr, xpos - size_line, ypos); + cairo_line_to(cr, xpos + size_line, ypos); + + cairo_move_to(cr, xpos - size_line, ypos); + cairo_rel_line_to(cr, size_arrow, size_arrow); + cairo_move_to(cr, xpos - size_line, ypos); + cairo_rel_line_to(cr, size_arrow, -size_arrow); + + cairo_move_to(cr, xpos + size_line, ypos); + cairo_rel_line_to(cr, -size_arrow, size_arrow); + cairo_move_to(cr, xpos + size_line, ypos); + cairo_rel_line_to(cr, -size_arrow, -size_arrow); + + // vertical line + cairo_move_to(cr, xpos, ypos - size_line); + cairo_line_to(cr, xpos, ypos + size_line); + + cairo_move_to(cr, xpos, ypos - size_line); + cairo_rel_line_to(cr, -size_arrow, size_arrow); + cairo_move_to(cr, xpos, ypos - size_line); + cairo_rel_line_to(cr, size_arrow, size_arrow); + + cairo_move_to(cr, xpos, ypos + size_line); + cairo_rel_line_to(cr, -size_arrow, -size_arrow); + cairo_move_to(cr, xpos, ypos + size_line); + cairo_rel_line_to(cr, size_arrow, -size_arrow); + + cairo_stroke(cr); + } + + cairo_restore(cr); + } + + // show guide lines on request + if(g->show_guides) + { + dt_guides_t *guide = (dt_guides_t *)g_list_nth_data(darktable.guides, 0); + double dashes = DT_PIXEL_APPLY_DPI(5.0); + cairo_save(cr); + cairo_rectangle(cr, 0, 0, width, height); + cairo_clip(cr); + cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); + cairo_set_source_rgb(cr, .8, .8, .8); + cairo_set_dash(cr, &dashes, 1, 0); + guide->draw(cr, 0, 0, width, height, 1.0, guide->user_data); + cairo_stroke_preserve(cr); + cairo_set_dash(cr, &dashes, 0, 0); + cairo_set_source_rgba(cr, 0.3, .3, .3, .8); + cairo_stroke(cr); + cairo_restore(cr); + } + + // structural data are currently being collected or fit procedure is running? -> skip + if(g->fitting) return; + + // no structural data or visibility switched off? -> stop here + if(g->lines == NULL || g->lines_suppressed || !gui_has_focus(self)) return; + + // get hash value that changes if distortions from here to the end of the pixelpipe changed + uint64_t hash = dt_dev_hash_distort(dev); + // get hash value that changes if coordinates of lines have changed + uint64_t lines_hash = get_lines_hash(g->lines, g->lines_count); + + // points data are missing or outdated, or distortion has changed? + if(g->points == NULL || g->points_idx == NULL || hash != g->grid_hash || + (g->lines_version > g->points_version && g->lines_hash != lines_hash)) + { + // we need to reprocess points + free(g->points); + g->points = NULL; + free(g->points_idx); + g->points_idx = NULL; + g->points_lines_count = 0; + + if(!get_points(self, g->lines, g->lines_count, g->lines_version, &g->points, &g->points_idx, + &g->points_lines_count)) + return; + + g->points_version = g->lines_version; + g->grid_hash = hash; + g->lines_hash = lines_hash; + } + else if(g->lines_hash == lines_hash) + { + // update line type information in points_idx + for(int n = 0; n < g->points_lines_count; n++) + g->points_idx[n].type = g->lines[n].type; + + // coordinates of lines are unchanged -> we only need to update colors + if(!update_colors(self, g->points_idx, g->points_lines_count)) + return; + + g->points_version = g->lines_version; + } + + // a final check + if(g->points == NULL || g->points_idx == NULL) return; + + cairo_save(cr); + cairo_rectangle(cr, 0, 0, width, height); + cairo_clip(cr); + cairo_translate(cr, width / 2.0, height / 2.0); + cairo_scale(cr, zoom_scale, zoom_scale); + cairo_translate(cr, -.5f * wd - zoom_x * wd, -.5f * ht - zoom_y * ht); + + // this must match the sequence of enum dt_iop_ashift_linecolor_t! + const float line_colors[5][4] = + { { 0.3f, 0.3f, 0.3f, 0.8f }, // grey (misc. lines) + { 0.0f, 1.0f, 0.0f, 0.8f }, // green (selected vertical lines) + { 0.8f, 0.0f, 0.0f, 0.8f }, // red (de-selected vertical lines) + { 0.0f, 0.0f, 1.0f, 0.8f }, // blue (selected horizontal lines) + { 0.8f, 0.8f, 0.0f, 0.8f } }; // yellow (de-selected horizontal lines) + + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + + // now draw all lines + for(int n = 0; n < g->points_lines_count; n++) + { + // is the near flag set? -> draw line a bit thicker + if(g->points_idx[n].near) + cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(3.0) / zoom_scale); + else + cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.5) / zoom_scale); + + // the color of this line + const float *color = line_colors[g->points_idx[n].color]; + cairo_set_source_rgba(cr, color[0], color[1], color[2], color[3]); + + size_t offset = g->points_idx[n].offset; + const int length = g->points_idx[n].length; + + // sanity check (this should not happen) + if(length < 2) continue; + + // set starting point of multi-segment line + cairo_move_to(cr, g->points[offset * 2], g->points[offset * 2 + 1]); + + offset++; + // draw individual line segments + for(int l = 1; l < length; l++, offset++) + { + cairo_line_to(cr, g->points[offset * 2], g->points[offset * 2 + 1]); + } + + // finally stroke the line + cairo_stroke(cr); + } + + // and we draw the selection box if any + if(g->isbounding != ASHIFT_BOUNDING_OFF) + { + float pzx, pzy; + dt_dev_get_pointer_zoom_pos(dev, pointerx, pointery, &pzx, &pzy); + pzx += 0.5f; + pzy += 0.5f; + + double dashed[] = { 4.0, 4.0 }; + dashed[0] /= zoom_scale; + dashed[1] /= zoom_scale; + int len = sizeof(dashed) / sizeof(dashed[0]); + + cairo_rectangle(cr, g->lastx * wd, g->lasty * ht, (pzx - g->lastx) * wd, (pzy - g->lasty) * ht); + + cairo_set_source_rgba(cr, .3, .3, .3, .8); + cairo_set_line_width(cr, 1.0 / zoom_scale); + cairo_set_dash(cr, dashed, len, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgba(cr, .8, .8, .8, .8); + cairo_set_dash(cr, dashed, len, 4); + cairo_stroke(cr); + } + + // indicate which area is used for "near"-ness detection when selecting/deselecting lines + if(g->near_delta > 0) + { + float pzx, pzy; + dt_dev_get_pointer_zoom_pos(dev, pointerx, pointery, &pzx, &pzy); + pzx += 0.5f; + pzy += 0.5f; + + double dashed[] = { 4.0, 4.0 }; + dashed[0] /= zoom_scale; + dashed[1] /= zoom_scale; + int len = sizeof(dashed) / sizeof(dashed[0]); + + cairo_arc(cr, pzx * wd, pzy * ht, g->near_delta, 0, 2.0 * M_PI); + + cairo_set_source_rgba(cr, .3, .3, .3, .8); + cairo_set_line_width(cr, 1.0 / zoom_scale); + cairo_set_dash(cr, dashed, len, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgba(cr, .8, .8, .8, .8); + cairo_set_dash(cr, dashed, len, 4); + cairo_stroke(cr); + } + + cairo_restore(cr); +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// update the number of selected vertical and horizontal lines +static void update_lines_count(const dt_iop_ashift_line_t *lines, const int lines_count, + int *vertical_count, int *horizontal_count) +{ + int vlines = 0; + int hlines = 0; + + for(int n = 0; n < lines_count; n++) + { + if((lines[n].type & ASHIFT_LINE_MASK) == ASHIFT_LINE_VERTICAL_SELECTED) + vlines++; + else if((lines[n].type & ASHIFT_LINE_MASK) == ASHIFT_LINE_HORIZONTAL_SELECTED) + hlines++; + } + + *vertical_count = vlines; + *horizontal_count = hlines; +} + +//----------------------------------------------------------------------------- +// RT: BEGIN COMMENT +#if 0 +int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + int handled = 0; + + const float wd = self->dev->preview_pipe->backbuf_width; + const float ht = self->dev->preview_pipe->backbuf_height; + if(wd < 1.0 || ht < 1.0) return 1; + + float pzx, pzy; + dt_dev_get_pointer_zoom_pos(self->dev, x, y, &pzx, &pzy); + pzx += 0.5f; + pzy += 0.5f; + + if (g->adjust_crop) + { + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + const float newx = g->crop_cx + pzx - g->lastx; + const float newy = g->crop_cy + pzy - g->lasty; + crop_adjust(self, p, newx, newy); + dt_dev_add_history_item(darktable.develop, self, TRUE); + return TRUE; + } + + // if in rectangle selecting mode adjust "near"-ness of lines according to + // the rectangular selection + if(g->isbounding != ASHIFT_BOUNDING_OFF) + { + if(wd >= 1.0 && ht >= 1.0) + { + // mark lines inside the rectangle + get_bounded_inside(g->points, g->points_idx, g->points_lines_count, pzx * wd, pzy * ht, g->lastx * wd, + g->lasty * ht, g->isbounding); + } + + dt_control_queue_redraw_center(); + return FALSE; + } + + // gather information about "near"-ness in g->points_idx + get_near(g->points, g->points_idx, g->points_lines_count, pzx * wd, pzy * ht, g->near_delta); + + // if we are in sweeping mode iterate over lines as we move the pointer and change "selected" state. + if(g->isdeselecting || g->isselecting) + { + for(int n = 0; g->selecting_lines_version == g->lines_version && n < g->points_lines_count; n++) + { + if(g->points_idx[n].near == 0) + continue; + + if(g->isdeselecting) + g->lines[n].type &= ~ASHIFT_LINE_SELECTED; + else if(g->isselecting) + g->lines[n].type |= ASHIFT_LINE_SELECTED; + + handled = 1; + } + } + + if(handled) + { + update_lines_count(g->lines, g->lines_count, &g->vertical_count, &g->horizontal_count); + g->lines_version++; + g->selecting_lines_version++; + } + + dt_control_queue_redraw_center(); + + // if not in sweeping mode we need to pass the event + return (g->isdeselecting || g->isselecting); +} + +int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, + uint32_t state) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + int handled = 0; + + float pzx, pzy; + dt_dev_get_pointer_zoom_pos(self->dev, x, y, &pzx, &pzy); + pzx += 0.5f; + pzy += 0.5f; + + const float wd = self->dev->preview_pipe->backbuf_width; + const float ht = self->dev->preview_pipe->backbuf_height; + if(wd < 1.0 || ht < 1.0) return 1; + + + // if visibility of lines is switched off or no lines available -> potentially adjust crop area + if(g->lines_suppressed || g->lines == NULL) + { + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + if (p->cropmode == ASHIFT_CROP_ASPECT) + { + dt_control_change_cursor(GDK_HAND1); + g->adjust_crop = TRUE; + g->lastx = pzx; + g->lasty = pzy; + g->crop_cx = 0.5f * (p->cl + p->cr); + g->crop_cy = 0.5f * (p->ct + p->cb); + return TRUE; + } + else + return FALSE; + } + + // remember lines version at this stage so we can continuously monitor if the + // lines have changed in-between + g->selecting_lines_version = g->lines_version; + + // if shift button is pressed go into bounding mode (selecting or deselecting + // in a rectangle area) + if((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) + { + g->lastx = pzx; + g->lasty = pzy; + + g->isbounding = (which == 3) ? ASHIFT_BOUNDING_DESELECT : ASHIFT_BOUNDING_SELECT; + dt_control_change_cursor(GDK_CROSS); + + return TRUE; + } + + dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); + const int closeup = dt_control_get_dev_closeup(); + const float min_scale = dt_dev_get_zoom_scale(self->dev, DT_ZOOM_FIT, 1<dev, zoom, 1<points_lines_count > 0); + + g->near_delta = dt_conf_get_float("plugins/darkroom/ashift/near_delta"); + + // gather information about "near"-ness in g->points_idx + get_near(g->points, g->points_idx, g->points_lines_count, pzx * wd, pzy * ht, g->near_delta); + + // iterate over all lines close to the pointer and change "selected" state. + // left-click selects and right-click deselects the line + for(int n = 0; g->selecting_lines_version == g->lines_version && n < g->points_lines_count; n++) + { + if(g->points_idx[n].near == 0) + continue; + + if(which == 3) + g->lines[n].type &= ~ASHIFT_LINE_SELECTED; + else + g->lines[n].type |= ASHIFT_LINE_SELECTED; + + handled = 1; + } + + // we switch into sweeping mode either if we anyhow take control + // or if cursor was close to a line when button was pressed. in other + // cases we hand over the event (for image panning) + if((take_control || handled) && which == 3) + { + dt_control_change_cursor(GDK_PIRATE); + g->isdeselecting = 1; + } + else if(take_control || handled) + { + dt_control_change_cursor(GDK_PLUS); + g->isselecting = 1; + } + + if(handled) + { + update_lines_count(g->lines, g->lines_count, &g->vertical_count, &g->horizontal_count); + g->lines_version++; + g->selecting_lines_version++; + } + + return (take_control || handled); +} + +int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + // stop adjust crop + g->adjust_crop = FALSE; + dt_control_change_cursor(GDK_LEFT_PTR); + + // finalize the isbounding mode + // if user has released the shift button in-between -> do nothing + if(g->isbounding != ASHIFT_BOUNDING_OFF && (state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) + { + int handled = 0; + + // we compute the rectangle selection + float pzx, pzy; + dt_dev_get_pointer_zoom_pos(self->dev, x, y, &pzx, &pzy); + + pzx += 0.5f; + pzy += 0.5f; + + const float wd = self->dev->preview_pipe->backbuf_width; + const float ht = self->dev->preview_pipe->backbuf_height; + + if(wd >= 1.0 && ht >= 1.0) + { + // mark lines inside the rectangle + get_bounded_inside(g->points, g->points_idx, g->points_lines_count, pzx * wd, pzy * ht, g->lastx * wd, + g->lasty * ht, g->isbounding); + + // select or deselect lines within the rectangle according to isbounding state + for(int n = 0; g->selecting_lines_version == g->lines_version && n < g->points_lines_count; n++) + { + if(g->points_idx[n].bounded == 0) continue; + + if(g->isbounding == ASHIFT_BOUNDING_DESELECT) + g->lines[n].type &= ~ASHIFT_LINE_SELECTED; + else + g->lines[n].type |= ASHIFT_LINE_SELECTED; + + handled = 1; + } + + if(handled) + { + update_lines_count(g->lines, g->lines_count, &g->vertical_count, &g->horizontal_count); + g->lines_version++; + g->selecting_lines_version++; + } + + dt_control_queue_redraw_center(); + } + } + + // end of sweeping/isbounding mode + dt_control_change_cursor(GDK_LEFT_PTR); + g->isselecting = g->isdeselecting = 0; + g->isbounding = ASHIFT_BOUNDING_OFF; + g->near_delta = 0; + g->lastx = g->lasty = -1.0f; + g->crop_cx = g->crop_cy = -1.0f; + + return 0; +} + +int scrolled(struct dt_iop_module_t *self, double x, double y, int up, uint32_t state) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + // do nothing if visibility of lines is switched off or no lines available + if(g->lines_suppressed || g->lines == NULL) + return FALSE; + + if(g->near_delta > 0 && (g->isdeselecting || g->isselecting)) + { + int handled = 0; + + float pzx, pzy; + dt_dev_get_pointer_zoom_pos(self->dev, x, y, &pzx, &pzy); + pzx += 0.5f; + pzy += 0.5f; + + const float wd = self->dev->preview_pipe->backbuf_width; + const float ht = self->dev->preview_pipe->backbuf_height; + + float near_delta = dt_conf_get_float("plugins/darkroom/ashift/near_delta"); + const float amount = up ? 0.8f : 1.25f; + near_delta = MAX(4.0f, MIN(near_delta * amount, 100.0f)); + dt_conf_set_float("plugins/darkroom/ashift/near_delta", near_delta); + g->near_delta = near_delta; + + // gather information about "near"-ness in g->points_idx + get_near(g->points, g->points_idx, g->points_lines_count, pzx * wd, pzy * ht, g->near_delta); + + // iterate over all lines close to the pointer and change "selected" state. + for(int n = 0; g->selecting_lines_version == g->lines_version && n < g->points_lines_count; n++) + { + if(g->points_idx[n].near == 0) + continue; + + if(g->isdeselecting) + g->lines[n].type &= ~ASHIFT_LINE_SELECTED; + else if(g->isselecting) + g->lines[n].type |= ASHIFT_LINE_SELECTED; + + handled = 1; + } + + if(handled) + { + update_lines_count(g->lines, g->lines_count, &g->vertical_count, &g->horizontal_count); + g->lines_version++; + g->selecting_lines_version++; + } + + dt_control_queue_redraw_center(); + return TRUE; + } + + return FALSE; +} + +static void rotation_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->rotation = dt_bauhaus_slider_get(slider); +#ifdef ASHIFT_DEBUG + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + model_probe(self, p, g->lastfit); +#endif + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void lensshift_v_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->lensshift_v = dt_bauhaus_slider_get(slider); +#ifdef ASHIFT_DEBUG + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + model_probe(self, p, g->lastfit); +#endif + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void lensshift_h_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->lensshift_h = dt_bauhaus_slider_get(slider); +#ifdef ASHIFT_DEBUG + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + model_probe(self, p, g->lastfit); +#endif + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void shear_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->shear = dt_bauhaus_slider_get(slider); +#ifdef ASHIFT_DEBUG + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + model_probe(self, p, g->lastfit); +#endif + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void guide_lines_callback(GtkWidget *widget, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + g->show_guides = dt_bauhaus_combobox_get(widget); + dt_iop_request_focus(self); + dt_dev_reprocess_all(self->dev); +} + +static void cropmode_callback(GtkWidget *widget, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + p->cropmode = dt_bauhaus_combobox_get(widget); + if(g->lines != NULL && !g->lines_suppressed) + { + g->lines_suppressed = 1; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->eye), g->lines_suppressed); + } + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void mode_callback(GtkWidget *widget, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + p->mode = dt_bauhaus_combobox_get(widget); + + switch(p->mode) + { + case ASHIFT_MODE_GENERIC: + gtk_widget_hide(g->f_length); + gtk_widget_hide(g->crop_factor); + gtk_widget_hide(g->orthocorr); + gtk_widget_hide(g->aspect); + break; + case ASHIFT_MODE_SPECIFIC: + default: + gtk_widget_show(g->f_length); + gtk_widget_show(g->crop_factor); + gtk_widget_show(g->orthocorr); + gtk_widget_show(g->aspect); + break; + } + + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void f_length_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->f_length = dt_bauhaus_slider_get(slider); + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void crop_factor_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->crop_factor = dt_bauhaus_slider_get(slider); + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void orthocorr_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->orthocorr = dt_bauhaus_slider_get(slider); + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static void aspect_callback(GtkWidget *slider, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(self->dt->gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + p->aspect = dt_bauhaus_slider_get(slider); + do_crop(self, p); + dt_dev_add_history_item(darktable.develop, self, TRUE); +} + +static int fit_v_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(darktable.gui->reset) return FALSE; + + if(event->button == 1) + { + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + const int control = (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK; + const int shift = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK; + + dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; + + if(control) + g->lastfit = fitaxis = ASHIFT_FIT_ROTATION_VERTICAL_LINES; + else if(shift) + g->lastfit = fitaxis = ASHIFT_FIT_VERTICALLY_NO_ROTATION; + else + g->lastfit = fitaxis = ASHIFT_FIT_VERTICALLY; + + dt_iop_request_focus(self); + dt_dev_reprocess_all(self->dev); + + if(self->enabled) + { + // module is enable -> we process directly + if(do_fit(self, p, fitaxis)) + { + darktable.gui->reset = 1; + dt_bauhaus_slider_set_soft(g->rotation, p->rotation); + dt_bauhaus_slider_set_soft(g->lensshift_v, p->lensshift_v); + dt_bauhaus_slider_set_soft(g->lensshift_h, p->lensshift_h); + dt_bauhaus_slider_set_soft(g->shear, p->shear); + darktable.gui->reset = 0; + } + } + else + { + // module is not enabled -> invoke it and queue the job to be processed once + // the preview image is ready + g->jobcode = ASHIFT_JOBCODE_FIT; + g->jobparams = g->lastfit = fitaxis; + p->toggle ^= 1; + } + + dt_dev_add_history_item(darktable.develop, self, TRUE); + return TRUE; + } + return FALSE; +} + +static int fit_h_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(darktable.gui->reset) return FALSE; + + if(event->button == 1) + { + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + const int control = (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK; + const int shift = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK; + + dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; + + if(control) + g->lastfit = fitaxis = ASHIFT_FIT_ROTATION_HORIZONTAL_LINES; + else if(shift) + g->lastfit = fitaxis = ASHIFT_FIT_HORIZONTALLY_NO_ROTATION; + else + g->lastfit = fitaxis = ASHIFT_FIT_HORIZONTALLY; + + dt_iop_request_focus(self); + dt_dev_reprocess_all(self->dev); + + if(self->enabled) + { + // module is enable -> we process directly + if(do_fit(self, p, fitaxis)) + { + darktable.gui->reset = 1; + dt_bauhaus_slider_set_soft(g->rotation, p->rotation); + dt_bauhaus_slider_set_soft(g->lensshift_v, p->lensshift_v); + dt_bauhaus_slider_set_soft(g->lensshift_h, p->lensshift_h); + dt_bauhaus_slider_set_soft(g->shear, p->shear); + darktable.gui->reset = 0; + } + } + else + { + // module is not enabled -> invoke it and queue the job to be processed once + // the preview image is ready + g->jobcode = ASHIFT_JOBCODE_FIT; + g->jobparams = g->lastfit = fitaxis; + p->toggle ^= 1; + } + + dt_dev_add_history_item(darktable.develop, self, TRUE); + return TRUE; + } + return FALSE; +} + +static int fit_both_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(darktable.gui->reset) return FALSE; + + if(event->button == 1) + { + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + const int control = (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK; + const int shift = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK; + + dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; + + if(control && shift) + fitaxis = ASHIFT_FIT_BOTH; + else if(control) + fitaxis = ASHIFT_FIT_ROTATION_BOTH_LINES; + else if(shift) + fitaxis = ASHIFT_FIT_BOTH_NO_ROTATION; + else + fitaxis = ASHIFT_FIT_BOTH_SHEAR; + + dt_iop_request_focus(self); + dt_dev_reprocess_all(self->dev); + + if(self->enabled) + { + // module is enable -> we process directly + if(do_fit(self, p, fitaxis)) + { + darktable.gui->reset = 1; + dt_bauhaus_slider_set_soft(g->rotation, p->rotation); + dt_bauhaus_slider_set_soft(g->lensshift_v, p->lensshift_v); + dt_bauhaus_slider_set_soft(g->lensshift_h, p->lensshift_h); + dt_bauhaus_slider_set_soft(g->shear, p->shear); + darktable.gui->reset = 0; + } + } + else + { + // module is not enabled -> invoke it and queue the job to be processed once + // the preview image is ready + g->jobcode = ASHIFT_JOBCODE_FIT; + g->jobparams = g->lastfit = fitaxis; + p->toggle ^= 1; + } + + dt_dev_add_history_item(darktable.develop, self, TRUE); + return TRUE; + } + return FALSE; +} + +static int structure_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(darktable.gui->reset) return FALSE; + + if(event->button == 1) + { + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + const int control = (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK; + const int shift = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK; + + dt_iop_ashift_enhance_t enhance; + + if(control && shift) + enhance = ASHIFT_ENHANCE_EDGES | ASHIFT_ENHANCE_DETAIL; + else if(shift) + enhance = ASHIFT_ENHANCE_DETAIL; + else if(control) + enhance = ASHIFT_ENHANCE_EDGES; + else + enhance = ASHIFT_ENHANCE_NONE; + + dt_iop_request_focus(self); + dt_dev_reprocess_all(self->dev); + + if(self->enabled) + { + // module is enabled -> process directly + (void)do_get_structure(self, p, enhance); + } + else + { + // module is not enabled -> invoke it and queue the job to be processed once + // the preview image is ready + g->jobcode = ASHIFT_JOBCODE_GET_STRUCTURE; + g->jobparams = enhance; + p->toggle ^= 1; + } + + dt_dev_add_history_item(darktable.develop, self, TRUE); + return TRUE; + } + return FALSE; +} + +static void clean_button_clicked(GtkButton *button, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + if(darktable.gui->reset) return; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + (void)do_clean_structure(self, p); + dt_iop_request_focus(self); + dt_control_queue_redraw_center(); +} + +static void eye_button_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + if(darktable.gui->reset) return; + if(g->lines == NULL) + { + g->lines_suppressed = 0; + gtk_toggle_button_set_active(togglebutton, 0); + } + else + { + g->lines_suppressed = gtk_toggle_button_get_active(togglebutton); + } + dt_iop_request_focus(self); + dt_control_queue_redraw_center(); +} + +// routine that is called after preview image has been processed. we use it +// to perform structure collection or fitting in case those have been triggered while +// the module had not yet been enabled +static void process_after_preview_callback(gpointer instance, gpointer user_data) +{ + dt_iop_module_t *self = (dt_iop_module_t *)user_data; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + + dt_iop_ashift_jobcode_t jobcode = g->jobcode; + int jobparams = g->jobparams; + + // purge + g->jobcode = ASHIFT_JOBCODE_NONE; + g->jobparams = 0; + + if(darktable.gui->reset) return; + + switch(jobcode) + { + case ASHIFT_JOBCODE_GET_STRUCTURE: + (void)do_get_structure(self, p, (dt_iop_ashift_enhance_t)jobparams); + break; + + case ASHIFT_JOBCODE_FIT: + if(do_fit(self, p, (dt_iop_ashift_fitaxis_t)jobparams)) + { + darktable.gui->reset = 1; + dt_bauhaus_slider_set_soft(g->rotation, p->rotation); + dt_bauhaus_slider_set_soft(g->lensshift_v, p->lensshift_v); + dt_bauhaus_slider_set_soft(g->lensshift_h, p->lensshift_h); + dt_bauhaus_slider_set_soft(g->shear, p->shear); + darktable.gui->reset = 0; + } + dt_dev_add_history_item(darktable.develop, self, TRUE); + break; + + case ASHIFT_JOBCODE_NONE: + default: + break; + } + + dt_control_queue_redraw_center(); +} + +void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, + dt_dev_pixelpipe_iop_t *piece) +{ + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)p1; + dt_iop_ashift_data_t *d = (dt_iop_ashift_data_t *)piece->data; + + d->rotation = p->rotation; + d->lensshift_v = p->lensshift_v; + d->lensshift_h = p->lensshift_h; + d->shear = p->shear; + d->f_length_kb = (p->mode == ASHIFT_MODE_GENERIC) ? DEFAULT_F_LENGTH : p->f_length * p->crop_factor; + d->orthocorr = (p->mode == ASHIFT_MODE_GENERIC) ? 0.0f : p->orthocorr; + d->aspect = (p->mode == ASHIFT_MODE_GENERIC) ? 1.0f : p->aspect; + + if(gui_has_focus(self)) + { + // if gui has focus we want to see the full uncropped image + d->cl = 0.0f; + d->cr = 1.0f; + d->ct = 0.0f; + d->cb = 1.0f; + } + else + { + d->cl = p->cl; + d->cr = p->cr; + d->ct = p->ct; + d->cb = p->cb; + } +} + +void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) +{ + dt_iop_ashift_data_t *d = (dt_iop_ashift_data_t *)calloc(1, sizeof(dt_iop_ashift_data_t)); + piece->data = (void *)d; + self->commit_params(self, self->default_params, pipe, piece); +} + +void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) +{ + free(piece->data); + piece->data = NULL; +} + +void gui_update(struct dt_iop_module_t *self) +{ + dt_iop_module_t *module = (dt_iop_module_t *)self; + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)module->params; + dt_bauhaus_slider_set_soft(g->rotation, p->rotation); + dt_bauhaus_slider_set_soft(g->lensshift_v, p->lensshift_v); + dt_bauhaus_slider_set_soft(g->lensshift_h, p->lensshift_h); + dt_bauhaus_slider_set_soft(g->shear, p->shear); + dt_bauhaus_slider_set_soft(g->f_length, p->f_length); + dt_bauhaus_slider_set_soft(g->crop_factor, p->crop_factor); + dt_bauhaus_slider_set(g->orthocorr, p->orthocorr); + dt_bauhaus_slider_set(g->aspect, p->aspect); + dt_bauhaus_combobox_set(g->mode, p->mode); + dt_bauhaus_combobox_set(g->guide_lines, g->show_guides); + dt_bauhaus_combobox_set(g->cropmode, p->cropmode); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->eye), 0); + + switch(p->mode) + { + case ASHIFT_MODE_GENERIC: + gtk_widget_hide(g->f_length); + gtk_widget_hide(g->crop_factor); + gtk_widget_hide(g->orthocorr); + gtk_widget_hide(g->aspect); + break; + case ASHIFT_MODE_SPECIFIC: + default: + gtk_widget_show(g->f_length); + gtk_widget_show(g->crop_factor); + gtk_widget_show(g->orthocorr); + gtk_widget_show(g->aspect); + break; + } +} + +void init(dt_iop_module_t *module) +{ + module->params = calloc(1, sizeof(dt_iop_ashift_params_t)); + module->default_params = calloc(1, sizeof(dt_iop_ashift_params_t)); + module->default_enabled = 0; + module->priority = 214; // module order created by iop_dependencies.py, do not edit! + module->params_size = sizeof(dt_iop_ashift_params_t); + module->gui_data = NULL; + dt_iop_ashift_params_t tmp = (dt_iop_ashift_params_t){ 0.0f, 0.0f, 0.0f, 0.0f, DEFAULT_F_LENGTH, 1.0f, 100.0f, 1.0f, ASHIFT_MODE_GENERIC, 0, + ASHIFT_CROP_OFF, 0.0f, 1.0f, 0.0f, 1.0f }; + memcpy(module->params, &tmp, sizeof(dt_iop_ashift_params_t)); + memcpy(module->default_params, &tmp, sizeof(dt_iop_ashift_params_t)); +} + +void reload_defaults(dt_iop_module_t *module) +{ + // our module is disabled by default + module->default_enabled = 0; + + int isflipped = 0; + float f_length = DEFAULT_F_LENGTH; + float crop_factor = 1.0f; + + // try to get information on orientation, focal length and crop factor from image data + if(module->dev) + { + const dt_image_t *img = &module->dev->image_storage; + // orientation only needed as a-priori information to correctly label some sliders + // before pixelpipe has been set up. later we will get a definite result by + // assessing the pixelpipe + isflipped = (img->orientation == ORIENTATION_ROTATE_CCW_90_DEG + || img->orientation == ORIENTATION_ROTATE_CW_90_DEG) + ? 1 + : 0; + + // focal length should be available in exif data if lens is electronically coupled to the camera + f_length = isfinite(img->exif_focal_length) && img->exif_focal_length > 0.0f ? img->exif_focal_length : f_length; + // crop factor of the camera is often not available and user will need to set it manually in the gui + crop_factor = isfinite(img->exif_crop) && img->exif_crop > 0.0f ? img->exif_crop : crop_factor; + } + + // init defaults: + dt_iop_ashift_params_t tmp = (dt_iop_ashift_params_t){ 0.0f, 0.0f, 0.0f, 0.0f, f_length, crop_factor, 100.0f, 1.0f, ASHIFT_MODE_GENERIC, 0, + ASHIFT_CROP_OFF, 0.0f, 1.0f, 0.0f, 1.0f }; + memcpy(module->params, &tmp, sizeof(dt_iop_ashift_params_t)); + memcpy(module->default_params, &tmp, sizeof(dt_iop_ashift_params_t)); + + // reset gui elements + if(module->gui_data) + { + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)module->gui_data; + + char string_v[256]; + char string_h[256]; + + snprintf(string_v, sizeof(string_v), _("lens shift (%s)"), isflipped ? _("horizontal") : _("vertical")); + snprintf(string_h, sizeof(string_h), _("lens shift (%s)"), isflipped ? _("vertical") : _("horizontal")); + + dt_bauhaus_widget_set_label(g->lensshift_v, NULL, string_v); + dt_bauhaus_widget_set_label(g->lensshift_h, NULL, string_h); + + dt_bauhaus_slider_set_default(g->f_length, tmp.f_length); + dt_bauhaus_slider_set_default(g->crop_factor, tmp.crop_factor); + + dt_pthread_mutex_lock(&g->lock); + free(g->buf); + g->buf = NULL; + g->buf_width = 0; + g->buf_height = 0; + g->buf_x_off = 0; + g->buf_y_off = 0; + g->buf_scale = 1.0f; + g->buf_hash = 0; + g->isflipped = -1; + g->lastfit = ASHIFT_FIT_NONE; + dt_pthread_mutex_unlock(&g->lock); + + g->fitting = 0; + free(g->lines); + g->lines = NULL; + g->lines_count =0; + g->horizontal_count = 0; + g->vertical_count = 0; + g->grid_hash = 0; + g->lines_hash = 0; + g->rotation_range = ROTATION_RANGE_SOFT; + g->lensshift_v_range = LENSSHIFT_RANGE_SOFT; + g->lensshift_h_range = LENSSHIFT_RANGE_SOFT; + g->shear_range = SHEAR_RANGE_SOFT; + g->lines_suppressed = 0; + g->lines_version = 0; + g->show_guides = 0; + g->isselecting = 0; + g->isdeselecting = 0; + g->isbounding = ASHIFT_BOUNDING_OFF; + g->near_delta = 0; + g->selecting_lines_version = 0; + + free(g->points); + g->points = NULL; + free(g->points_idx); + g->points_idx = NULL; + g->points_lines_count = 0; + g->points_version = 0; + + g->jobcode = ASHIFT_JOBCODE_NONE; + g->jobparams = 0; + g->adjust_crop = FALSE; + g->lastx = g->lasty = -1.0f; + g->crop_cx = g->crop_cy = 1.0f; + } +} + + +void init_global(dt_iop_module_so_t *module) +{ + dt_iop_ashift_global_data_t *gd + = (dt_iop_ashift_global_data_t *)malloc(sizeof(dt_iop_ashift_global_data_t)); + module->data = gd; + + const int program = 2; // basic.cl, from programs.conf + gd->kernel_ashift_bilinear = dt_opencl_create_kernel(program, "ashift_bilinear"); + gd->kernel_ashift_bicubic = dt_opencl_create_kernel(program, "ashift_bicubic"); + gd->kernel_ashift_lanczos2 = dt_opencl_create_kernel(program, "ashift_lanczos2"); + gd->kernel_ashift_lanczos3 = dt_opencl_create_kernel(program, "ashift_lanczos3"); +} + +void cleanup(dt_iop_module_t *module) +{ + free(module->params); + module->params = NULL; +} + +void cleanup_global(dt_iop_module_so_t *module) +{ + dt_iop_ashift_global_data_t *gd = (dt_iop_ashift_global_data_t *)module->data; + dt_opencl_free_kernel(gd->kernel_ashift_bilinear); + dt_opencl_free_kernel(gd->kernel_ashift_bicubic); + dt_opencl_free_kernel(gd->kernel_ashift_lanczos2); + dt_opencl_free_kernel(gd->kernel_ashift_lanczos3); + free(module->data); + module->data = NULL; +} + +// adjust labels of lens shift parameters according to flip status of image +static gboolean draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self) +{ + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + if(darktable.gui->reset) return FALSE; + + dt_pthread_mutex_lock(&g->lock); + const int isflipped = g->isflipped; + dt_pthread_mutex_unlock(&g->lock); + + if(isflipped == -1) return FALSE; + + char string_v[256]; + char string_h[256]; + + snprintf(string_v, sizeof(string_v), _("lens shift (%s)"), isflipped ? _("horizontal") : _("vertical")); + snprintf(string_h, sizeof(string_h), _("lens shift (%s)"), isflipped ? _("vertical") : _("horizontal")); + + darktable.gui->reset = 1; + dt_bauhaus_widget_set_label(g->lensshift_v, NULL, string_v); + dt_bauhaus_widget_set_label(g->lensshift_h, NULL, string_h); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->eye), g->lines_suppressed); + darktable.gui->reset = 0; + + return FALSE; +} + +void gui_focus(struct dt_iop_module_t *self, gboolean in) +{ + if(self->enabled) + dt_dev_reprocess_all(self->dev); +} + +static float log10_callback(GtkWidget *self, float inval, dt_bauhaus_callback_t dir) +{ + float outval; + switch(dir) + { + case DT_BAUHAUS_SET: + outval = log10(fmax(inval, 1e-15f)); + break; + case DT_BAUHAUS_GET: + outval = exp(M_LN10 * inval); + break; + default: + outval = inval; + } + return outval; +} + +static float log2_callback(GtkWidget *self, float inval, dt_bauhaus_callback_t dir) +{ + float outval; + switch(dir) + { + case DT_BAUHAUS_SET: + outval = log(fmax(inval, 1e-15f)) / M_LN2; + break; + case DT_BAUHAUS_GET: + outval = exp(M_LN2 * inval); + break; + default: + outval = inval; + } + return outval; +} + +void gui_init(struct dt_iop_module_t *self) +{ + self->gui_data = malloc(sizeof(dt_iop_ashift_gui_data_t)); + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + dt_iop_ashift_params_t *p = (dt_iop_ashift_params_t *)self->params; + + dt_pthread_mutex_init(&g->lock, NULL); + dt_pthread_mutex_lock(&g->lock); + g->buf = NULL; + g->buf_width = 0; + g->buf_height = 0; + g->buf_x_off = 0; + g->buf_y_off = 0; + g->buf_scale = 1.0f; + g->buf_hash = 0; + g->isflipped = -1; + g->lastfit = ASHIFT_FIT_NONE; + dt_pthread_mutex_unlock(&g->lock); + + g->fitting = 0; + g->lines = NULL; + g->lines_count = 0; + g->vertical_count = 0; + g->horizontal_count = 0; + g->lines_version = 0; + g->lines_suppressed = 0; + g->points = NULL; + g->points_idx = NULL; + g->points_lines_count = 0; + g->points_version = 0; + g->grid_hash = 0; + g->lines_hash = 0; + g->rotation_range = ROTATION_RANGE_SOFT; + g->lensshift_v_range = LENSSHIFT_RANGE_SOFT; + g->lensshift_h_range = LENSSHIFT_RANGE_SOFT; + g->shear_range = SHEAR_RANGE_SOFT; + g->show_guides = 0; + g->isselecting = 0; + g->isdeselecting = 0; + g->isbounding = ASHIFT_BOUNDING_OFF; + g->near_delta = 0; + g->selecting_lines_version = 0; + + g->jobcode = ASHIFT_JOBCODE_NONE; + g->jobparams = 0; + g->adjust_crop = FALSE; + g->lastx = g->lasty = -1.0f; + g->crop_cx = g->crop_cy = 1.0f; + + self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE); + dt_gui_add_help_link(self->widget, dt_get_help_url(self->op)); + + g->rotation = dt_bauhaus_slider_new_with_range(self, -ROTATION_RANGE, ROTATION_RANGE, 0.01*ROTATION_RANGE, p->rotation, 2); + dt_bauhaus_widget_set_label(g->rotation, NULL, _("rotation")); + dt_bauhaus_slider_set_format(g->rotation, "%.2f°"); + dt_bauhaus_slider_enable_soft_boundaries(g->rotation, -ROTATION_RANGE_SOFT, ROTATION_RANGE_SOFT); + gtk_box_pack_start(GTK_BOX(self->widget), g->rotation, TRUE, TRUE, 0); + + g->lensshift_v = dt_bauhaus_slider_new_with_range(self, -LENSSHIFT_RANGE, LENSSHIFT_RANGE, 0.01*LENSSHIFT_RANGE, p->lensshift_v, 3); + dt_bauhaus_widget_set_label(g->lensshift_v, NULL, _("lens shift (vertical)")); + dt_bauhaus_slider_enable_soft_boundaries(g->lensshift_v, -LENSSHIFT_RANGE_SOFT, LENSSHIFT_RANGE_SOFT); + gtk_box_pack_start(GTK_BOX(self->widget), g->lensshift_v, TRUE, TRUE, 0); + + g->lensshift_h = dt_bauhaus_slider_new_with_range(self, -LENSSHIFT_RANGE, LENSSHIFT_RANGE, 0.01*LENSSHIFT_RANGE, p->lensshift_h, 3); + dt_bauhaus_widget_set_label(g->lensshift_h, NULL, _("lens shift (horizontal)")); + dt_bauhaus_slider_enable_soft_boundaries(g->lensshift_h, -LENSSHIFT_RANGE_SOFT, LENSSHIFT_RANGE_SOFT); + gtk_box_pack_start(GTK_BOX(self->widget), g->lensshift_h, TRUE, TRUE, 0); + + g->shear = dt_bauhaus_slider_new_with_range(self, -SHEAR_RANGE, SHEAR_RANGE, 0.01*SHEAR_RANGE, p->shear, 3); + dt_bauhaus_widget_set_label(g->shear, NULL, _("shear")); + dt_bauhaus_slider_enable_soft_boundaries(g->shear, -SHEAR_RANGE_SOFT, SHEAR_RANGE_SOFT); + gtk_box_pack_start(GTK_BOX(self->widget), g->shear, TRUE, TRUE, 0); + + g->guide_lines = dt_bauhaus_combobox_new(self); + dt_bauhaus_widget_set_label(g->guide_lines, NULL, _("guides")); + dt_bauhaus_combobox_add(g->guide_lines, _("off")); + dt_bauhaus_combobox_add(g->guide_lines, _("on")); + gtk_box_pack_start(GTK_BOX(self->widget), g->guide_lines, TRUE, TRUE, 0); + + g->cropmode = dt_bauhaus_combobox_new(self); + dt_bauhaus_widget_set_label(g->cropmode, NULL, _("automatic cropping")); + dt_bauhaus_combobox_add(g->cropmode, _("off")); + dt_bauhaus_combobox_add(g->cropmode, _("largest area")); + dt_bauhaus_combobox_add(g->cropmode, _("original format")); + gtk_box_pack_start(GTK_BOX(self->widget), g->cropmode, TRUE, TRUE, 0); + + g->mode = dt_bauhaus_combobox_new(self); + dt_bauhaus_widget_set_label(g->mode, NULL, _("lens model")); + dt_bauhaus_combobox_add(g->mode, _("generic")); + dt_bauhaus_combobox_add(g->mode, _("specific")); + gtk_box_pack_start(GTK_BOX(self->widget), g->mode, TRUE, TRUE, 0); + + g->f_length = dt_bauhaus_slider_new_with_range(self, 1.0f, 3.0f, 0.01f, 1.0f, 2); + dt_bauhaus_widget_set_label(g->f_length, NULL, _("focal length")); + dt_bauhaus_slider_set_callback(g->f_length, log10_callback); + dt_bauhaus_slider_set_format(g->f_length, "%.0fmm"); + dt_bauhaus_slider_set_default(g->f_length, DEFAULT_F_LENGTH); + dt_bauhaus_slider_set(g->f_length, DEFAULT_F_LENGTH); + dt_bauhaus_slider_enable_soft_boundaries(g->f_length, 1.0f, 2000.0f); + gtk_box_pack_start(GTK_BOX(self->widget), g->f_length, TRUE, TRUE, 0); + + g->crop_factor = dt_bauhaus_slider_new_with_range(self, 1.0f, 2.0f, 0.01f, p->crop_factor, 2); + dt_bauhaus_widget_set_label(g->crop_factor, NULL, _("crop factor")); + dt_bauhaus_slider_enable_soft_boundaries(g->crop_factor, 0.5f, 10.0f); + gtk_box_pack_start(GTK_BOX(self->widget), g->crop_factor, TRUE, TRUE, 0); + + g->orthocorr = dt_bauhaus_slider_new_with_range(self, 0.0f, 100.0f, 1.0f, p->orthocorr, 2); + dt_bauhaus_widget_set_label(g->orthocorr, NULL, _("lens dependence")); + dt_bauhaus_slider_set_format(g->orthocorr, "%.0f%%"); +#if 0 + // this parameter could serve to finetune between generic model (0%) and specific model (100%). + // however, users can more easily get the same effect with the aspect adjust parameter so we keep + // this one hidden. + gtk_box_pack_start(GTK_BOX(self->widget), g->orthocorr, TRUE, TRUE, 0); +#endif + + g->aspect = dt_bauhaus_slider_new_with_range(self, -1.0f, 1.0f, 0.01f, 0.0f, 2); + dt_bauhaus_widget_set_label(g->aspect, NULL, _("aspect adjust")); + dt_bauhaus_slider_set_callback(g->aspect, log2_callback); + dt_bauhaus_slider_set_default(g->aspect, 1.0f); + dt_bauhaus_slider_set(g->aspect, 1.0f); + gtk_box_pack_start(GTK_BOX(self->widget), g->aspect, TRUE, TRUE, 0); + + GtkWidget *grid = gtk_grid_new(); + gtk_grid_set_row_spacing(GTK_GRID(grid), 2 * DT_BAUHAUS_SPACE); + gtk_grid_set_column_spacing(GTK_GRID(grid), DT_PIXEL_APPLY_DPI(10)); + + GtkWidget *label1 = gtk_label_new(_("automatic fit")); + gtk_widget_set_halign(label1, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(grid), label1, 0, 0, 1, 1); + + g->fit_v = dtgtk_button_new(dtgtk_cairo_paint_perspective, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | 1, NULL); + gtk_widget_set_hexpand(GTK_WIDGET(g->fit_v), TRUE); + gtk_widget_set_size_request(g->fit_v, -1, DT_PIXEL_APPLY_DPI(24)); + gtk_grid_attach_next_to(GTK_GRID(grid), g->fit_v, label1, GTK_POS_RIGHT, 1, 1); + + g->fit_h = dtgtk_button_new(dtgtk_cairo_paint_perspective, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | 2, NULL); + gtk_widget_set_hexpand(GTK_WIDGET(g->fit_h), TRUE); + gtk_widget_set_size_request(g->fit_h, -1, DT_PIXEL_APPLY_DPI(24)); + gtk_grid_attach_next_to(GTK_GRID(grid), g->fit_h, g->fit_v, GTK_POS_RIGHT, 1, 1); + + g->fit_both = dtgtk_button_new(dtgtk_cairo_paint_perspective, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | 3, NULL); + gtk_widget_set_hexpand(GTK_WIDGET(g->fit_both), TRUE); + gtk_widget_set_size_request(g->fit_both, -1, DT_PIXEL_APPLY_DPI(24)); + gtk_grid_attach_next_to(GTK_GRID(grid), g->fit_both, g->fit_h, GTK_POS_RIGHT, 1, 1); + + GtkWidget *label2 = gtk_label_new(_("get structure")); + gtk_widget_set_halign(label2, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(grid), label2, 0, 1, 1, 1); + + g->structure = dtgtk_button_new(dtgtk_cairo_paint_structure, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER, NULL); + gtk_widget_set_hexpand(GTK_WIDGET(g->structure), TRUE); + gtk_grid_attach_next_to(GTK_GRID(grid), g->structure, label2, GTK_POS_RIGHT, 1, 1); + + g->clean = dtgtk_button_new(dtgtk_cairo_paint_cancel, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER, NULL); + gtk_widget_set_hexpand(GTK_WIDGET(g->clean), TRUE); + gtk_grid_attach_next_to(GTK_GRID(grid), g->clean, g->structure, GTK_POS_RIGHT, 1, 1); + + g->eye = dtgtk_togglebutton_new(dtgtk_cairo_paint_eye_toggle, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER, NULL); + gtk_widget_set_hexpand(GTK_WIDGET(g->eye), TRUE); + gtk_grid_attach_next_to(GTK_GRID(grid), g->eye, g->clean, GTK_POS_RIGHT, 1, 1); + + gtk_box_pack_start(GTK_BOX(self->widget), grid, TRUE, TRUE, 0); + + gtk_widget_show_all(g->f_length); + gtk_widget_set_no_show_all(g->f_length, TRUE); + gtk_widget_show_all(g->crop_factor); + gtk_widget_set_no_show_all(g->crop_factor, TRUE); + gtk_widget_show_all(g->orthocorr); + gtk_widget_set_no_show_all(g->orthocorr, TRUE); + gtk_widget_show_all(g->aspect); + gtk_widget_set_no_show_all(g->aspect, TRUE); + + + switch(p->mode) + { + case ASHIFT_MODE_GENERIC: + gtk_widget_hide(g->f_length); + gtk_widget_hide(g->crop_factor); + gtk_widget_hide(g->orthocorr); + gtk_widget_hide(g->aspect); + break; + case ASHIFT_MODE_SPECIFIC: + default: + gtk_widget_show(g->f_length); + gtk_widget_show(g->crop_factor); + gtk_widget_show(g->orthocorr); + gtk_widget_show(g->aspect); + break; + } + + gtk_widget_set_tooltip_text(g->rotation, _("rotate image")); + gtk_widget_set_tooltip_text(g->lensshift_v, _("apply lens shift correction in one direction")); + gtk_widget_set_tooltip_text(g->lensshift_h, _("apply lens shift correction in one direction")); + gtk_widget_set_tooltip_text(g->shear, _("shear the image along one diagonal")); + gtk_widget_set_tooltip_text(g->guide_lines, _("display guide lines overlay")); + gtk_widget_set_tooltip_text(g->cropmode, _("automatically crop to avoid black edges")); + gtk_widget_set_tooltip_text(g->mode, _("lens model of the perspective correction: " + "generic or according to the focal length")); + gtk_widget_set_tooltip_text(g->f_length, _("focal length of the lens, " + "default value set from exif data if available")); + gtk_widget_set_tooltip_text(g->crop_factor, _("crop factor of the camera sensor, " + "default value set from exif data if available, " + "manual setting is often required")); + gtk_widget_set_tooltip_text(g->orthocorr, _("the level of lens dependent correction, set to maximum for full lens dependency, " + "set to zero for the generic case")); + gtk_widget_set_tooltip_text(g->aspect, _("adjust aspect ratio of image by horizontal and vertical scaling")); + gtk_widget_set_tooltip_text(g->fit_v, _("automatically correct for vertical perspective distortion\n" + "ctrl-click to only fit rotation\n" + "shift-click to only fit lens shift")); + gtk_widget_set_tooltip_text(g->fit_h, _("automatically correct for horizontal perspective distortion\n" + "ctrl-click to only fit rotation\n" + "shift-click to only fit lens shift")); + gtk_widget_set_tooltip_text(g->fit_both, _("automatically correct for vertical and " + "horizontal perspective distortions; fitting rotation," + "lens shift in both directions, and shear\n" + "ctrl-click to only fit rotation\n" + "shift-click to only fit lens shift\n" + "ctrl-shift-click to only fit rotation and lens shift")); + gtk_widget_set_tooltip_text(g->structure, _("analyse line structure in image\n" + "ctrl-click for an additional edge enhancement\n" + "shift-click for an additional detail enhancement\n" + "ctrl-shift-click for a combination of both methods")); + gtk_widget_set_tooltip_text(g->clean, _("remove line structure information")); + gtk_widget_set_tooltip_text(g->eye, _("toggle visibility of structure lines")); + + g_signal_connect(G_OBJECT(g->rotation), "value-changed", G_CALLBACK(rotation_callback), self); + g_signal_connect(G_OBJECT(g->lensshift_v), "value-changed", G_CALLBACK(lensshift_v_callback), self); + g_signal_connect(G_OBJECT(g->lensshift_h), "value-changed", G_CALLBACK(lensshift_h_callback), self); + g_signal_connect(G_OBJECT(g->shear), "value-changed", G_CALLBACK(shear_callback), self); + g_signal_connect(G_OBJECT(g->guide_lines), "value-changed", G_CALLBACK(guide_lines_callback), self); + g_signal_connect(G_OBJECT(g->cropmode), "value-changed", G_CALLBACK(cropmode_callback), self); + g_signal_connect(G_OBJECT(g->mode), "value-changed", G_CALLBACK(mode_callback), self); + g_signal_connect(G_OBJECT(g->f_length), "value-changed", G_CALLBACK(f_length_callback), self); + g_signal_connect(G_OBJECT(g->crop_factor), "value-changed", G_CALLBACK(crop_factor_callback), self); + g_signal_connect(G_OBJECT(g->orthocorr), "value-changed", G_CALLBACK(orthocorr_callback), self); + g_signal_connect(G_OBJECT(g->aspect), "value-changed", G_CALLBACK(aspect_callback), self); + g_signal_connect(G_OBJECT(g->fit_v), "button-press-event", G_CALLBACK(fit_v_button_clicked), (gpointer)self); + g_signal_connect(G_OBJECT(g->fit_h), "button-press-event", G_CALLBACK(fit_h_button_clicked), (gpointer)self); + g_signal_connect(G_OBJECT(g->fit_both), "button-press-event", G_CALLBACK(fit_both_button_clicked), (gpointer)self); + g_signal_connect(G_OBJECT(g->structure), "button-press-event", G_CALLBACK(structure_button_clicked), (gpointer)self); + g_signal_connect(G_OBJECT(g->clean), "clicked", G_CALLBACK(clean_button_clicked), (gpointer)self); + g_signal_connect(G_OBJECT(g->eye), "toggled", G_CALLBACK(eye_button_toggled), (gpointer)self); + g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(draw), self); + + /* add signal handler for preview pipe finish to redraw the overlay */ + dt_control_signal_connect(darktable.signals, DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED, + G_CALLBACK(process_after_preview_callback), self); + +} + +void gui_cleanup(struct dt_iop_module_t *self) +{ + dt_control_signal_disconnect(darktable.signals, G_CALLBACK(process_after_preview_callback), self); + + dt_iop_ashift_gui_data_t *g = (dt_iop_ashift_gui_data_t *)self->gui_data; + dt_pthread_mutex_destroy(&g->lock); + free(g->lines); + free(g->buf); + free(g->points); + free(g->points_idx); + free(self->gui_data); + self->gui_data = NULL; +} +#endif // if 0 +//----------------------------------------------------------------------------- + +// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh +// vim: shiftwidth=2 expandtab tabstop=2 cindent +// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; diff --git a/rtengine/ashift_lsd.c b/rtengine/ashift_lsd.c new file mode 100644 index 000000000..3a0ec5aba --- /dev/null +++ b/rtengine/ashift_lsd.c @@ -0,0 +1,2335 @@ +/* + This file is part of darktable, + copyright (c) 2016 Ulrich Pegelow. + + 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 . +*/ + + +/* For line detection we are using the LSD code as published below. + * Changes versus the original code: + * do not include "lsd.h" (not needed) + * make all interface functions static + * comment out unsused interface functions + * catch (unlikely) division by zero near line 2035 + * rename rad1 and rad2 to radius1 and radius2 in reduce_region_radius() + * to avoid naming conflict in windows build + * + */ + +/* TODO: LSD employs intensive sanity checks of input data and allocation + * results. In case of errors it will terminate the program. On the one side + * this is not optimal for a module within darktable - it should better + * report errors upstream where they should be handled properly. On the other + * hand the kind of error which could be triggered in LSD would make it very unlikely + * that the darktable process could survive anyhow. + */ + +// clang-format off + +/*================================================================================== + * begin LSD code version 1.6. downloaded on January 30, 2016 + *==================================================================================*/ + +/*---------------------------------------------------------------------------- + + LSD - Line Segment Detector on digital images + + This code is part of the following publication and was subject + to peer review: + + "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, + Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, + Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd + http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd + + Copyright (c) 2007-2011 rafael grompone von gioi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + ----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** @file lsd.c + LSD module code + @author rafael grompone von gioi + */ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** @mainpage LSD code documentation + + This is an implementation of the Line Segment Detector described + in the paper: + + "LSD: A Fast Line Segment Detector with a False Detection Control" + by Rafael Grompone von Gioi, Jeremie Jakubowicz, Jean-Michel Morel, + and Gregory Randall, IEEE Transactions on Pattern Analysis and + Machine Intelligence, vol. 32, no. 4, pp. 722-732, April, 2010. + + and in more details in the CMLA Technical Report: + + "LSD: A Line Segment Detector, Technical Report", + by Rafael Grompone von Gioi, Jeremie Jakubowicz, Jean-Michel Morel, + Gregory Randall, CMLA, ENS Cachan, 2010. + + The version implemented here includes some further improvements + described in the following publication, of which this code is part: + + "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, + Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, + Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd + http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd + + The module's main function is lsd(). + + The source code is contained in two files: lsd.h and lsd.c. + + HISTORY: + - version 1.6 - nov 2011: + - changes in the interface, + - max_grad parameter removed, + - the factor 11 was added to the number of test + to consider the different precision values + tested, + - a minor bug corrected in the gradient sorting + code, + - the algorithm now also returns p and log_nfa + for each detection, + - a minor bug was corrected in the image scaling, + - the angle comparison in "isaligned" changed + from < to <=, + - "eps" variable renamed "log_eps", + - "lsd_scale_region" interface was added, + - minor changes to comments. + - version 1.5 - dec 2010: Changes in 'refine', -W option added, + and more comments added. + - version 1.4 - jul 2010: lsd_scale interface added and doxygen doc. + - version 1.3 - feb 2010: Multiple bug correction and improved code. + - version 1.2 - dec 2009: First full Ansi C Language version. + - version 1.1 - sep 2009: Systematic subsampling to scale 0.8 and + correction to partially handle "angle problem". + - version 1.0 - jan 2009: First complete Megawave2 and Ansi C Language + version. + + @author rafael grompone von gioi + */ +/*----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +//#include "lsd.h" + +/** ln(10) */ +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 +#endif /* !M_LN10 */ + +/** PI */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* !M_PI */ + +#ifndef FALSE +#define FALSE 0 +#endif /* !FALSE */ + +#ifndef TRUE +#define TRUE 1 +#endif /* !TRUE */ + +/** Label for pixels with undefined gradient. */ +#define NOTDEF -1024.0 + +/** 3/2 pi */ +#define M_3_2_PI 4.71238898038 + +/** 2 pi */ +#define M_2__PI 6.28318530718 + +/** Label for pixels not used in yet. */ +#define NOTUSED 0 + +/** Label for pixels already used in detection. */ +#define USED 1 + +/*----------------------------------------------------------------------------*/ +/** Chained list of coordinates. + */ +struct coorlist +{ + int x,y; + struct coorlist * next; +}; + +/*----------------------------------------------------------------------------*/ +/** A point (or pixel). + */ +struct point {int x,y;}; + + +/*----------------------------------------------------------------------------*/ +/*------------------------- Miscellaneous functions --------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Fatal error, print a message to standard-error output and exit. + */ +static void error(const char * msg) +{ + fprintf(stderr,"LSD Error: %s\n",msg); + exit(EXIT_FAILURE); +} + +/*----------------------------------------------------------------------------*/ +/** Doubles relative error factor + */ +#define RELATIVE_ERROR_FACTOR 100.0 + +/*----------------------------------------------------------------------------*/ +/** Compare doubles by relative error. + + The resulting rounding error after floating point computations + depend on the specific operations done. The same number computed by + different algorithms could present different rounding errors. For a + useful comparison, an estimation of the relative rounding error + should be considered and compared to a factor times EPS. The factor + should be related to the cumulated rounding error in the chain of + computation. Here, as a simplification, a fixed factor is used. + */ +static int double_equal(double a, double b) +{ + double abs_diff,aa,bb,abs_max; + + /* trivial case */ + if( a == b ) return TRUE; + + abs_diff = fabs(a-b); + aa = fabs(a); + bb = fabs(b); + abs_max = aa > bb ? aa : bb; + + /* DBL_MIN is the smallest normalized number, thus, the smallest + number whose relative error is bounded by DBL_EPSILON. For + smaller numbers, the same quantization steps as for DBL_MIN + are used. Then, for smaller numbers, a meaningful "relative" + error should be computed by dividing the difference by DBL_MIN. */ + if( abs_max < DBL_MIN ) abs_max = DBL_MIN; + + /* equal if relative error <= factor x eps */ + return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON); +} + +/*----------------------------------------------------------------------------*/ +/** Computes Euclidean distance between point (x1,y1) and point (x2,y2). + */ +static double dist(double x1, double y1, double x2, double y2) +{ + return sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ); +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------- 'list of n-tuple' data type ------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** 'list of n-tuple' data type + + The i-th component of the j-th n-tuple of an n-tuple list 'ntl' + is accessed with: + + ntl->values[ i + j * ntl->dim ] + + The dimension of the n-tuple (n) is: + + ntl->dim + + The number of n-tuples in the list is: + + ntl->size + + The maximum number of n-tuples that can be stored in the + list with the allocated memory at a given time is given by: + + ntl->max_size + */ +typedef struct ntuple_list_s +{ + unsigned int size; + unsigned int max_size; + unsigned int dim; + double * values; +} * ntuple_list; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in n-tuple 'in'. + */ +static void free_ntuple_list(ntuple_list in) +{ + if( in == NULL || in->values == NULL ) + error("free_ntuple_list: invalid n-tuple input."); + free( (void *) in->values ); + free( (void *) in ); +} + +/*----------------------------------------------------------------------------*/ +/** Create an n-tuple list and allocate memory for one element. + @param dim the dimension (n) of the n-tuple. + */ +static ntuple_list new_ntuple_list(unsigned int dim) +{ + ntuple_list n_tuple; + + /* check parameters */ + if( dim == 0 ) error("new_ntuple_list: 'dim' must be positive."); + + /* get memory for list structure */ + n_tuple = (ntuple_list) malloc( sizeof(struct ntuple_list_s) ); + if( n_tuple == NULL ) error("not enough memory."); + + /* initialize list */ + n_tuple->size = 0; + n_tuple->max_size = 1; + n_tuple->dim = dim; + + /* get memory for tuples */ + n_tuple->values = (double *) malloc( sizeof(double) * dim*n_tuple->max_size ); + if( n_tuple->values == NULL ) error("not enough memory."); + + return n_tuple; +} + +/*----------------------------------------------------------------------------*/ +/** Enlarge the allocated memory of an n-tuple list. + */ +static void enlarge_ntuple_list(ntuple_list n_tuple) +{ + /* check parameters */ + if( n_tuple == NULL || n_tuple->values == NULL || n_tuple->max_size == 0 ) + error("enlarge_ntuple_list: invalid n-tuple."); + + /* duplicate number of tuples */ + n_tuple->max_size *= 2; + + /* realloc memory */ + n_tuple->values = (double *) realloc( (void *) n_tuple->values, + sizeof(double) * n_tuple->dim * n_tuple->max_size ); + if( n_tuple->values == NULL ) error("not enough memory."); +} + +/*----------------------------------------------------------------------------*/ +/** Add a 7-tuple to an n-tuple list. + */ +static void add_7tuple( ntuple_list out, double v1, double v2, double v3, + double v4, double v5, double v6, double v7 ) +{ + /* check parameters */ + if( out == NULL ) error("add_7tuple: invalid n-tuple input."); + if( out->dim != 7 ) error("add_7tuple: the n-tuple must be a 7-tuple."); + + /* if needed, alloc more tuples to 'out' */ + if( out->size == out->max_size ) enlarge_ntuple_list(out); + if( out->values == NULL ) error("add_7tuple: invalid n-tuple input."); + + /* add new 7-tuple */ + out->values[ out->size * out->dim + 0 ] = v1; + out->values[ out->size * out->dim + 1 ] = v2; + out->values[ out->size * out->dim + 2 ] = v3; + out->values[ out->size * out->dim + 3 ] = v4; + out->values[ out->size * out->dim + 4 ] = v5; + out->values[ out->size * out->dim + 5 ] = v6; + out->values[ out->size * out->dim + 6 ] = v7; + + /* update number of tuples counter */ + out->size++; +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------------- Image Data Types -----------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** char image data type + + The pixel value at (x,y) is accessed by: + + image->data[ x + y * image->xsize ] + + with x and y integer. + */ +typedef struct image_char_s +{ + unsigned char * data; + unsigned int xsize,ysize; +} * image_char; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in image_char 'i'. + */ +static void free_image_char(image_char i) +{ + if( i == NULL || i->data == NULL ) + error("free_image_char: invalid input image."); + free( (void *) i->data ); + free( (void *) i ); +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_char of size 'xsize' times 'ysize'. + */ +static image_char new_image_char(unsigned int xsize, unsigned int ysize) +{ + image_char image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) error("new_image_char: invalid image size."); + + /* get memory */ + image = (image_char) malloc( sizeof(struct image_char_s) ); + if( image == NULL ) error("not enough memory."); + image->data = (unsigned char *) calloc( (size_t) (xsize*ysize), + sizeof(unsigned char) ); + if( image->data == NULL ) error("not enough memory."); + + /* set image size */ + image->xsize = xsize; + image->ysize = ysize; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_char of size 'xsize' times 'ysize', + initialized to the value 'fill_value'. + */ +static image_char new_image_char_ini( unsigned int xsize, unsigned int ysize, + unsigned char fill_value ) +{ + image_char image = new_image_char(xsize,ysize); /* create image */ + unsigned int N = xsize*ysize; + unsigned int i; + + /* check parameters */ + if( image == NULL || image->data == NULL ) + error("new_image_char_ini: invalid image."); + + /* initialize */ + for(i=0; idata[i] = fill_value; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** int image data type + + The pixel value at (x,y) is accessed by: + + image->data[ x + y * image->xsize ] + + with x and y integer. + */ +typedef struct image_int_s +{ + int * data; + unsigned int xsize,ysize; +} * image_int; + +/*----------------------------------------------------------------------------*/ +/** Create a new image_int of size 'xsize' times 'ysize'. + */ +static image_int new_image_int(unsigned int xsize, unsigned int ysize) +{ + image_int image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) error("new_image_int: invalid image size."); + + /* get memory */ + image = (image_int) malloc( sizeof(struct image_int_s) ); + if( image == NULL ) error("not enough memory."); + image->data = (int *) calloc( (size_t) (xsize*ysize), sizeof(int) ); + if( image->data == NULL ) error("not enough memory."); + + /* set image size */ + image->xsize = xsize; + image->ysize = ysize; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_int of size 'xsize' times 'ysize', + initialized to the value 'fill_value'. + */ +static image_int new_image_int_ini( unsigned int xsize, unsigned int ysize, + int fill_value ) +{ + image_int image = new_image_int(xsize,ysize); /* create image */ + unsigned int N = xsize*ysize; + unsigned int i; + + /* initialize */ + for(i=0; idata[i] = fill_value; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** double image data type + + The pixel value at (x,y) is accessed by: + + image->data[ x + y * image->xsize ] + + with x and y integer. + */ +typedef struct image_double_s +{ + double * data; + unsigned int xsize,ysize; +} * image_double; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in image_double 'i'. + */ +static void free_image_double(image_double i) +{ + if( i == NULL || i->data == NULL ) + error("free_image_double: invalid input image."); + free( (void *) i->data ); + free( (void *) i ); +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_double of size 'xsize' times 'ysize'. + */ +static image_double new_image_double(unsigned int xsize, unsigned int ysize) +{ + image_double image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) error("new_image_double: invalid image size."); + + /* get memory */ + image = (image_double) malloc( sizeof(struct image_double_s) ); + if( image == NULL ) error("not enough memory."); + image->data = (double *) calloc( (size_t) (xsize*ysize), sizeof(double) ); + if( image->data == NULL ) error("not enough memory."); + + /* set image size */ + image->xsize = xsize; + image->ysize = ysize; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_double of size 'xsize' times 'ysize' + with the data pointed by 'data'. + */ +static image_double new_image_double_ptr( unsigned int xsize, + unsigned int ysize, double * data ) +{ + image_double image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) + error("new_image_double_ptr: invalid image size."); + if( data == NULL ) error("new_image_double_ptr: NULL data pointer."); + + /* get memory */ + image = (image_double) malloc( sizeof(struct image_double_s) ); + if( image == NULL ) error("not enough memory."); + + /* set image */ + image->xsize = xsize; + image->ysize = ysize; + image->data = data; + + return image; +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------------- Gaussian filter ------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Compute a Gaussian kernel of length 'kernel->dim', + standard deviation 'sigma', and centered at value 'mean'. + + For example, if mean=0.5, the Gaussian will be centered + in the middle point between values 'kernel->values[0]' + and 'kernel->values[1]'. + */ +static void gaussian_kernel(ntuple_list kernel, double sigma, double mean) +{ + double sum = 0.0; + double val; + unsigned int i; + + /* check parameters */ + if( kernel == NULL || kernel->values == NULL ) + error("gaussian_kernel: invalid n-tuple 'kernel'."); + if( sigma <= 0.0 ) error("gaussian_kernel: 'sigma' must be positive."); + + /* compute Gaussian kernel */ + if( kernel->max_size < 1 ) enlarge_ntuple_list(kernel); + kernel->size = 1; + for(i=0;idim;i++) + { + val = ( (double) i - mean ) / sigma; + kernel->values[i] = exp( -0.5 * val * val ); + sum += kernel->values[i]; + } + + /* normalization */ + if( sum >= 0.0 ) for(i=0;idim;i++) kernel->values[i] /= sum; +} + +/*----------------------------------------------------------------------------*/ +/** Scale the input image 'in' by a factor 'scale' by Gaussian sub-sampling. + + For example, scale=0.8 will give a result at 80% of the original size. + + The image is convolved with a Gaussian kernel + @f[ + G(x,y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2+y^2}{2\sigma^2}} + @f] + before the sub-sampling to prevent aliasing. + + The standard deviation sigma given by: + - sigma = sigma_scale / scale, if scale < 1.0 + - sigma = sigma_scale, if scale >= 1.0 + + To be able to sub-sample at non-integer steps, some interpolation + is needed. In this implementation, the interpolation is done by + the Gaussian kernel, so both operations (filtering and sampling) + are done at the same time. The Gaussian kernel is computed + centered on the coordinates of the required sample. In this way, + when applied, it gives directly the result of convolving the image + with the kernel and interpolated to that particular position. + + A fast algorithm is done using the separability of the Gaussian + kernel. Applying the 2D Gaussian kernel is equivalent to applying + first a horizontal 1D Gaussian kernel and then a vertical 1D + Gaussian kernel (or the other way round). The reason is that + @f[ + G(x,y) = G(x) * G(y) + @f] + where + @f[ + G(x) = \frac{1}{\sqrt{2\pi}\sigma} e^{-\frac{x^2}{2\sigma^2}}. + @f] + The algorithm first applies a combined Gaussian kernel and sampling + in the x axis, and then the combined Gaussian kernel and sampling + in the y axis. + */ +static image_double gaussian_sampler( image_double in, double scale, + double sigma_scale ) +{ + image_double aux,out; + ntuple_list kernel; + unsigned int N,M,h,n,x,y,i; + int xc,yc,j,double_x_size,double_y_size; + double sigma,xx,yy,sum,prec; + + /* check parameters */ + if( in == NULL || in->data == NULL || in->xsize == 0 || in->ysize == 0 ) + error("gaussian_sampler: invalid image."); + if( scale <= 0.0 ) error("gaussian_sampler: 'scale' must be positive."); + if( sigma_scale <= 0.0 ) + error("gaussian_sampler: 'sigma_scale' must be positive."); + + /* compute new image size and get memory for images */ + if( in->xsize * scale > (double) UINT_MAX || + in->ysize * scale > (double) UINT_MAX ) + error("gaussian_sampler: the output image size exceeds the handled size."); + N = (unsigned int) ceil( in->xsize * scale ); + M = (unsigned int) ceil( in->ysize * scale ); + aux = new_image_double(N,in->ysize); + out = new_image_double(N,M); + + /* sigma, kernel size and memory for the kernel */ + sigma = scale < 1.0 ? sigma_scale / scale : sigma_scale; + /* + The size of the kernel is selected to guarantee that the + the first discarded term is at least 10^prec times smaller + than the central value. For that, h should be larger than x, with + e^(-x^2/2sigma^2) = 1/10^prec. + Then, + x = sigma * sqrt( 2 * prec * ln(10) ). + */ + prec = 3.0; + h = (unsigned int) ceil( sigma * sqrt( 2.0 * prec * log(10.0) ) ); + n = 1+2*h; /* kernel size */ + kernel = new_ntuple_list(n); + + /* auxiliary double image size variables */ + double_x_size = (int) (2 * in->xsize); + double_y_size = (int) (2 * in->ysize); + + /* First subsampling: x axis */ + for(x=0;xxsize;x++) + { + /* + x is the coordinate in the new image. + xx is the corresponding x-value in the original size image. + xc is the integer value, the pixel coordinate of xx. + */ + xx = (double) x / scale; + /* coordinate (0.0,0.0) is in the center of pixel (0,0), + so the pixel with xc=0 get the values of xx from -0.5 to 0.5 */ + xc = (int) floor( xx + 0.5 ); + gaussian_kernel( kernel, sigma, (double) h + xx - (double) xc ); + /* the kernel must be computed for each x because the fine + offset xx-xc is different in each case */ + + for(y=0;yysize;y++) + { + sum = 0.0; + for(i=0;idim;i++) + { + j = xc - h + i; + + /* symmetry boundary condition */ + while( j < 0 ) j += double_x_size; + while( j >= double_x_size ) j -= double_x_size; + if( j >= (int) in->xsize ) j = double_x_size-1-j; + + sum += in->data[ j + y * in->xsize ] * kernel->values[i]; + } + aux->data[ x + y * aux->xsize ] = sum; + } + } + + /* Second subsampling: y axis */ + for(y=0;yysize;y++) + { + /* + y is the coordinate in the new image. + yy is the corresponding x-value in the original size image. + yc is the integer value, the pixel coordinate of xx. + */ + yy = (double) y / scale; + /* coordinate (0.0,0.0) is in the center of pixel (0,0), + so the pixel with yc=0 get the values of yy from -0.5 to 0.5 */ + yc = (int) floor( yy + 0.5 ); + gaussian_kernel( kernel, sigma, (double) h + yy - (double) yc ); + /* the kernel must be computed for each y because the fine + offset yy-yc is different in each case */ + + for(x=0;xxsize;x++) + { + sum = 0.0; + for(i=0;idim;i++) + { + j = yc - h + i; + + /* symmetry boundary condition */ + while( j < 0 ) j += double_y_size; + while( j >= double_y_size ) j -= double_y_size; + if( j >= (int) in->ysize ) j = double_y_size-1-j; + + sum += aux->data[ x + j * aux->xsize ] * kernel->values[i]; + } + out->data[ x + y * out->xsize ] = sum; + } + } + + /* free memory */ + free_ntuple_list(kernel); + free_image_double(aux); + + return out; +} + + +/*----------------------------------------------------------------------------*/ +/*--------------------------------- Gradient ---------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Computes the direction of the level line of 'in' at each point. + + The result is: + - an image_double with the angle at each pixel, or NOTDEF if not defined. + - the image_double 'modgrad' (a pointer is passed as argument) + with the gradient magnitude at each point. + - a list of pixels 'list_p' roughly ordered by decreasing + gradient magnitude. (The order is made by classifying points + into bins by gradient magnitude. The parameters 'n_bins' and + 'max_grad' specify the number of bins and the gradient modulus + at the highest bin. The pixels in the list would be in + decreasing gradient magnitude, up to a precision of the size of + the bins.) + - a pointer 'mem_p' to the memory used by 'list_p' to be able to + free the memory when it is not used anymore. + */ +static image_double ll_angle( image_double in, double threshold, + struct coorlist ** list_p, void ** mem_p, + image_double * modgrad, unsigned int n_bins ) +{ + image_double g; + unsigned int n,p,x,y,adr,i; + double com1,com2,gx,gy,norm,norm2; + /* the rest of the variables are used for pseudo-ordering + the gradient magnitude values */ + int list_count = 0; + struct coorlist * list; + struct coorlist ** range_l_s; /* array of pointers to start of bin list */ + struct coorlist ** range_l_e; /* array of pointers to end of bin list */ + struct coorlist * start; + struct coorlist * end; + double max_grad = 0.0; + + /* check parameters */ + if( in == NULL || in->data == NULL || in->xsize == 0 || in->ysize == 0 ) + error("ll_angle: invalid image."); + if( threshold < 0.0 ) error("ll_angle: 'threshold' must be positive."); + if( list_p == NULL ) error("ll_angle: NULL pointer 'list_p'."); + if( mem_p == NULL ) error("ll_angle: NULL pointer 'mem_p'."); + if( modgrad == NULL ) error("ll_angle: NULL pointer 'modgrad'."); + if( n_bins == 0 ) error("ll_angle: 'n_bins' must be positive."); + + /* image size shortcuts */ + n = in->ysize; + p = in->xsize; + + /* allocate output image */ + g = new_image_double(in->xsize,in->ysize); + + /* get memory for the image of gradient modulus */ + *modgrad = new_image_double(in->xsize,in->ysize); + + /* get memory for "ordered" list of pixels */ + list = (struct coorlist *) calloc( (size_t) (n*p), sizeof(struct coorlist) ); + *mem_p = (void *) list; + range_l_s = (struct coorlist **) calloc( (size_t) n_bins, + sizeof(struct coorlist *) ); + range_l_e = (struct coorlist **) calloc( (size_t) n_bins, + sizeof(struct coorlist *) ); + if( list == NULL || range_l_s == NULL || range_l_e == NULL ) + error("not enough memory."); + for(i=0;idata[(n-1)*p+x] = NOTDEF; + for(y=0;ydata[p*y+p-1] = NOTDEF; + + /* compute gradient on the remaining pixels */ + for(x=0;xdata[adr+p+1] - in->data[adr]; + com2 = in->data[adr+1] - in->data[adr+p]; + + gx = com1+com2; /* gradient x component */ + gy = com1-com2; /* gradient y component */ + norm2 = gx*gx+gy*gy; + norm = sqrt( norm2 / 4.0 ); /* gradient norm */ + + (*modgrad)->data[adr] = norm; /* store gradient norm */ + + if( norm <= threshold ) /* norm too small, gradient no defined */ + g->data[adr] = NOTDEF; /* gradient angle not defined */ + else + { + /* gradient angle computation */ + g->data[adr] = atan2(gx,-gy); + + /* look for the maximum of the gradient */ + if( norm > max_grad ) max_grad = norm; + } + } + + /* compute histogram of gradient values */ + for(x=0;xdata[y*p+x]; + + /* store the point in the right bin according to its norm */ + i = (unsigned int) (norm * (double) n_bins / max_grad); + if( i >= n_bins ) i = n_bins-1; + if( range_l_e[i] == NULL ) + range_l_s[i] = range_l_e[i] = list+list_count++; + else + { + range_l_e[i]->next = list+list_count; + range_l_e[i] = list+list_count++; + } + range_l_e[i]->x = (int) x; + range_l_e[i]->y = (int) y; + range_l_e[i]->next = NULL; + } + + /* Make the list of pixels (almost) ordered by norm value. + It starts by the larger bin, so the list starts by the + pixels with the highest gradient value. Pixels would be ordered + by norm value, up to a precision given by max_grad/n_bins. + */ + for(i=n_bins-1; i>0 && range_l_s[i]==NULL; i--); + start = range_l_s[i]; + end = range_l_e[i]; + if( start != NULL ) + while(i>0) + { + --i; + if( range_l_s[i] != NULL ) + { + end->next = range_l_s[i]; + end = range_l_e[i]; + } + } + *list_p = start; + + /* free memory */ + free( (void *) range_l_s ); + free( (void *) range_l_e ); + + return g; +} + +/*----------------------------------------------------------------------------*/ +/** Is point (x,y) aligned to angle theta, up to precision 'prec'? + */ +static int isaligned( int x, int y, image_double angles, double theta, + double prec ) +{ + double a; + + /* check parameters */ + if( angles == NULL || angles->data == NULL ) + error("isaligned: invalid image 'angles'."); + if( x < 0 || y < 0 || x >= (int) angles->xsize || y >= (int) angles->ysize ) + error("isaligned: (x,y) out of the image."); + if( prec < 0.0 ) error("isaligned: 'prec' must be positive."); + + /* angle at pixel (x,y) */ + a = angles->data[ x + y * angles->xsize ]; + + /* pixels whose level-line angle is not defined + are considered as NON-aligned */ + if( a == NOTDEF ) return FALSE; /* there is no need to call the function + 'double_equal' here because there is + no risk of problems related to the + comparison doubles, we are only + interested in the exact NOTDEF value */ + + /* it is assumed that 'theta' and 'a' are in the range [-pi,pi] */ + theta -= a; + if( theta < 0.0 ) theta = -theta; + if( theta > M_3_2_PI ) + { + theta -= M_2__PI; + if( theta < 0.0 ) theta = -theta; + } + + return theta <= prec; +} + +/*----------------------------------------------------------------------------*/ +/** Absolute value angle difference. + */ +static double angle_diff(double a, double b) +{ + a -= b; + while( a <= -M_PI ) a += M_2__PI; + while( a > M_PI ) a -= M_2__PI; + if( a < 0.0 ) a = -a; + return a; +} + +/*----------------------------------------------------------------------------*/ +/** Signed angle difference. + */ +static double angle_diff_signed(double a, double b) +{ + a -= b; + while( a <= -M_PI ) a += M_2__PI; + while( a > M_PI ) a -= M_2__PI; + return a; +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------------- NFA computation ------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Computes the natural logarithm of the absolute value of + the gamma function of x using the Lanczos approximation. + See http://www.rskey.org/gamma.htm + + The formula used is + @f[ + \Gamma(x) = \frac{ \sum_{n=0}^{N} q_n x^n }{ \Pi_{n=0}^{N} (x+n) } + (x+5.5)^{x+0.5} e^{-(x+5.5)} + @f] + so + @f[ + \log\Gamma(x) = \log\left( \sum_{n=0}^{N} q_n x^n \right) + + (x+0.5) \log(x+5.5) - (x+5.5) - \sum_{n=0}^{N} \log(x+n) + @f] + and + q0 = 75122.6331530, + q1 = 80916.6278952, + q2 = 36308.2951477, + q3 = 8687.24529705, + q4 = 1168.92649479, + q5 = 83.8676043424, + q6 = 2.50662827511. + */ +static double log_gamma_lanczos(double x) +{ + static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477, + 8687.24529705, 1168.92649479, 83.8676043424, + 2.50662827511 }; + double a = (x+0.5) * log(x+5.5) - (x+5.5); + double b = 0.0; + int n; + + for(n=0;n<7;n++) + { + a -= log( x + (double) n ); + b += q[n] * pow( x, (double) n ); + } + return a + log(b); +} + +/*----------------------------------------------------------------------------*/ +/** Computes the natural logarithm of the absolute value of + the gamma function of x using Windschitl method. + See http://www.rskey.org/gamma.htm + + The formula used is + @f[ + \Gamma(x) = \sqrt{\frac{2\pi}{x}} \left( \frac{x}{e} + \sqrt{ x\sinh(1/x) + \frac{1}{810x^6} } \right)^x + @f] + so + @f[ + \log\Gamma(x) = 0.5\log(2\pi) + (x-0.5)\log(x) - x + + 0.5x\log\left( x\sinh(1/x) + \frac{1}{810x^6} \right). + @f] + This formula is a good approximation when x > 15. + */ +static double log_gamma_windschitl(double x) +{ + return 0.918938533204673 + (x-0.5)*log(x) - x + + 0.5*x*log( x*sinh(1/x) + 1/(810.0*pow(x,6.0)) ); +} + +/*----------------------------------------------------------------------------*/ +/** Computes the natural logarithm of the absolute value of + the gamma function of x. When x>15 use log_gamma_windschitl(), + otherwise use log_gamma_lanczos(). + */ +#define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) + +/*----------------------------------------------------------------------------*/ +/** Size of the table to store already computed inverse values. + */ +#define TABSIZE 100000 + +// clang-format on + +static double *inv = NULL; /* table to keep computed inverse values */ + +__attribute__((constructor)) static void invConstructor() +{ + if(inv) return; + inv = (double *)malloc(sizeof(double) * TABSIZE); +} + +__attribute__((destructor)) static void invDestructor() +{ + free(inv); + inv = NULL; +} + +// clang-format off + +/*----------------------------------------------------------------------------*/ +/** Computes -log10(NFA). + + NFA stands for Number of False Alarms: + @f[ + \mathrm{NFA} = NT \cdot B(n,k,p) + @f] + + - NT - number of tests + - B(n,k,p) - tail of binomial distribution with parameters n,k and p: + @f[ + B(n,k,p) = \sum_{j=k}^n + \left(\begin{array}{c}n\\j\end{array}\right) + p^{j} (1-p)^{n-j} + @f] + + The value -log10(NFA) is equivalent but more intuitive than NFA: + - -1 corresponds to 10 mean false alarms + - 0 corresponds to 1 mean false alarm + - 1 corresponds to 0.1 mean false alarms + - 2 corresponds to 0.01 mean false alarms + - ... + + Used this way, the bigger the value, better the detection, + and a logarithmic scale is used. + + @param n,k,p binomial parameters. + @param logNT logarithm of Number of Tests + + The computation is based in the gamma function by the following + relation: + @f[ + \left(\begin{array}{c}n\\k\end{array}\right) + = \frac{ \Gamma(n+1) }{ \Gamma(k+1) \cdot \Gamma(n-k+1) }. + @f] + We use efficient algorithms to compute the logarithm of + the gamma function. + + To make the computation faster, not all the sum is computed, part + of the terms are neglected based on a bound to the error obtained + (an error of 10% in the result is accepted). + */ +static double nfa(int n, int k, double p, double logNT) +{ + double tolerance = 0.1; /* an error of 10% in the result is accepted */ + double log1term,term,bin_term,mult_term,bin_tail,err,p_term; + int i; + + /* check parameters */ + if( n<0 || k<0 || k>n || p<=0.0 || p>=1.0 ) + error("nfa: wrong n, k or p values."); + + /* trivial cases */ + if( n==0 || k==0 ) return -logNT; + if( n==k ) return -logNT - (double) n * log10(p); + + /* probability term */ + p_term = p / (1.0-p); + + /* compute the first term of the series */ + /* + binomial_tail(n,k,p) = sum_{i=k}^n bincoef(n,i) * p^i * (1-p)^{n-i} + where bincoef(n,i) are the binomial coefficients. + But + bincoef(n,k) = gamma(n+1) / ( gamma(k+1) * gamma(n-k+1) ). + We use this to compute the first term. Actually the log of it. + */ + log1term = log_gamma( (double) n + 1.0 ) - log_gamma( (double) k + 1.0 ) + - log_gamma( (double) (n-k) + 1.0 ) + + (double) k * log(p) + (double) (n-k) * log(1.0-p); + term = exp(log1term); + + /* in some cases no more computations are needed */ + if( double_equal(term,0.0) ) /* the first term is almost zero */ + { + if( (double) k > (double) n * p ) /* at begin or end of the tail? */ + return -log1term / M_LN10 - logNT; /* end: use just the first term */ + else + return -logNT; /* begin: the tail is roughly 1 */ + } + + /* compute more terms if needed */ + bin_tail = term; + for(i=k+1;i<=n;i++) + { + /* + As + term_i = bincoef(n,i) * p^i * (1-p)^(n-i) + and + bincoef(n,i)/bincoef(n,i-1) = n-1+1 / i, + then, + term_i / term_i-1 = (n-i+1)/i * p/(1-p) + and + term_i = term_i-1 * (n-i+1)/i * p/(1-p). + 1/i is stored in a table as they are computed, + because divisions are expensive. + p/(1-p) is computed only once and stored in 'p_term'. + */ + bin_term = (double) (n-i+1) * ( ii. + Then, the error on the binomial tail when truncated at + the i term can be bounded by a geometric series of form + term_i * sum mult_term_i^j. */ + err = term * ( ( 1.0 - pow( mult_term, (double) (n-i+1) ) ) / + (1.0-mult_term) - 1.0 ); + + /* One wants an error at most of tolerance*final_result, or: + tolerance * abs(-log10(bin_tail)-logNT). + Now, the error that can be accepted on bin_tail is + given by tolerance*final_result divided by the derivative + of -log10(x) when x=bin_tail. that is: + tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail) + Finally, we truncate the tail if the error is less than: + tolerance * abs(-log10(bin_tail)-logNT) * bin_tail */ + if( err < tolerance * fabs(-log10(bin_tail)-logNT) * bin_tail ) break; + } + } + return -log10(bin_tail) - logNT; +} + + +/*----------------------------------------------------------------------------*/ +/*--------------------------- Rectangle structure ----------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Rectangle structure: line segment with width. + */ +struct rect +{ + double x1,y1,x2,y2; /* first and second point of the line segment */ + double width; /* rectangle width */ + double x,y; /* center of the rectangle */ + double theta; /* angle */ + double dx,dy; /* (dx,dy) is vector oriented as the line segment */ + double prec; /* tolerance angle */ + double p; /* probability of a point with angle within 'prec' */ +}; + +/*----------------------------------------------------------------------------*/ +/** Copy one rectangle structure to another. + */ +static void rect_copy(struct rect * in, struct rect * out) +{ + /* check parameters */ + if( in == NULL || out == NULL ) error("rect_copy: invalid 'in' or 'out'."); + + /* copy values */ + out->x1 = in->x1; + out->y1 = in->y1; + out->x2 = in->x2; + out->y2 = in->y2; + out->width = in->width; + out->x = in->x; + out->y = in->y; + out->theta = in->theta; + out->dx = in->dx; + out->dy = in->dy; + out->prec = in->prec; + out->p = in->p; +} + +/*----------------------------------------------------------------------------*/ +/** Rectangle points iterator. + + The integer coordinates of pixels inside a rectangle are + iteratively explored. This structure keep track of the process and + functions ri_ini(), ri_inc(), ri_end(), and ri_del() are used in + the process. An example of how to use the iterator is as follows: + \code + + struct rect * rec = XXX; // some rectangle + rect_iter * i; + for( i=ri_ini(rec); !ri_end(i); ri_inc(i) ) + { + // your code, using 'i->x' and 'i->y' as coordinates + } + ri_del(i); // delete iterator + + \endcode + The pixels are explored 'column' by 'column', where we call + 'column' a set of pixels with the same x value that are inside the + rectangle. The following is an schematic representation of a + rectangle, the 'column' being explored is marked by colons, and + the current pixel being explored is 'x,y'. + \verbatim + + vx[1],vy[1] + * * + * * + * * + * ye + * : * + vx[0],vy[0] : * + * : * + * x,y * + * : * + * : vx[2],vy[2] + * : * + y ys * + ^ * * + | * * + | * * + +---> x vx[3],vy[3] + + \endverbatim + The first 'column' to be explored is the one with the smaller x + value. Each 'column' is explored starting from the pixel of the + 'column' (inside the rectangle) with the smallest y value. + + The four corners of the rectangle are stored in order that rotates + around the corners at the arrays 'vx[]' and 'vy[]'. The first + point is always the one with smaller x value. + + 'x' and 'y' are the coordinates of the pixel being explored. 'ys' + and 'ye' are the start and end values of the current column being + explored. So, 'ys' < 'ye'. + */ +typedef struct +{ + double vx[4]; /* rectangle's corner X coordinates in circular order */ + double vy[4]; /* rectangle's corner Y coordinates in circular order */ + double ys,ye; /* start and end Y values of current 'column' */ + int x,y; /* coordinates of currently explored pixel */ +} rect_iter; + +/*----------------------------------------------------------------------------*/ +/** Interpolate y value corresponding to 'x' value given, in + the line 'x1,y1' to 'x2,y2'; if 'x1=x2' return the smaller + of 'y1' and 'y2'. + + The following restrictions are required: + - x1 <= x2 + - x1 <= x + - x <= x2 + */ +static double inter_low(double x, double x1, double y1, double x2, double y2) +{ + /* check parameters */ + if( x1 > x2 || x < x1 || x > x2 ) + error("inter_low: unsuitable input, 'x1>x2' or 'xx2'."); + + /* interpolation */ + if( double_equal(x1,x2) && y1y2 ) return y2; + return y1 + (x-x1) * (y2-y1) / (x2-x1); +} + +/*----------------------------------------------------------------------------*/ +/** Interpolate y value corresponding to 'x' value given, in + the line 'x1,y1' to 'x2,y2'; if 'x1=x2' return the larger + of 'y1' and 'y2'. + + The following restrictions are required: + - x1 <= x2 + - x1 <= x + - x <= x2 + */ +static double inter_hi(double x, double x1, double y1, double x2, double y2) +{ + /* check parameters */ + if( x1 > x2 || x < x1 || x > x2 ) + error("inter_hi: unsuitable input, 'x1>x2' or 'xx2'."); + + /* interpolation */ + if( double_equal(x1,x2) && y1y2 ) return y1; + return y1 + (x-x1) * (y2-y1) / (x2-x1); +} + +/*----------------------------------------------------------------------------*/ +/** Free memory used by a rectangle iterator. + */ +static void ri_del(rect_iter * iter) +{ + if( iter == NULL ) error("ri_del: NULL iterator."); + free( (void *) iter ); +} + +/*----------------------------------------------------------------------------*/ +/** Check if the iterator finished the full iteration. + + See details in \ref rect_iter + */ +static int ri_end(rect_iter * i) +{ + /* check input */ + if( i == NULL ) error("ri_end: NULL iterator."); + + /* if the current x value is larger than the largest + x value in the rectangle (vx[2]), we know the full + exploration of the rectangle is finished. */ + return (double)(i->x) > i->vx[2]; +} + +/*----------------------------------------------------------------------------*/ +/** Increment a rectangle iterator. + + See details in \ref rect_iter + */ +static void ri_inc(rect_iter * i) +{ + /* check input */ + if( i == NULL ) error("ri_inc: NULL iterator."); + + /* if not at end of exploration, + increase y value for next pixel in the 'column' */ + if( !ri_end(i) ) i->y++; + + /* if the end of the current 'column' is reached, + and it is not the end of exploration, + advance to the next 'column' */ + while( (double) (i->y) > i->ye && !ri_end(i) ) + { + /* increase x, next 'column' */ + i->x++; + + /* if end of exploration, return */ + if( ri_end(i) ) return; + + /* update lower y limit (start) for the new 'column'. + + We need to interpolate the y value that corresponds to the + lower side of the rectangle. The first thing is to decide if + the corresponding side is + + vx[0],vy[0] to vx[3],vy[3] or + vx[3],vy[3] to vx[2],vy[2] + + Then, the side is interpolated for the x value of the + 'column'. But, if the side is vertical (as it could happen if + the rectangle is vertical and we are dealing with the first + or last 'columns') then we pick the lower value of the side + by using 'inter_low'. + */ + if( (double) i->x < i->vx[3] ) + i->ys = inter_low((double)i->x,i->vx[0],i->vy[0],i->vx[3],i->vy[3]); + else + i->ys = inter_low((double)i->x,i->vx[3],i->vy[3],i->vx[2],i->vy[2]); + + /* update upper y limit (end) for the new 'column'. + + We need to interpolate the y value that corresponds to the + upper side of the rectangle. The first thing is to decide if + the corresponding side is + + vx[0],vy[0] to vx[1],vy[1] or + vx[1],vy[1] to vx[2],vy[2] + + Then, the side is interpolated for the x value of the + 'column'. But, if the side is vertical (as it could happen if + the rectangle is vertical and we are dealing with the first + or last 'columns') then we pick the lower value of the side + by using 'inter_low'. + */ + if( (double)i->x < i->vx[1] ) + i->ye = inter_hi((double)i->x,i->vx[0],i->vy[0],i->vx[1],i->vy[1]); + else + i->ye = inter_hi((double)i->x,i->vx[1],i->vy[1],i->vx[2],i->vy[2]); + + /* new y */ + i->y = (int) ceil(i->ys); + } +} + +/*----------------------------------------------------------------------------*/ +/** Create and initialize a rectangle iterator. + + See details in \ref rect_iter + */ +static rect_iter * ri_ini(struct rect * r) +{ + double vx[4],vy[4]; + int n,offset; + rect_iter * i; + + /* check parameters */ + if( r == NULL ) error("ri_ini: invalid rectangle."); + + /* get memory */ + i = (rect_iter *) malloc(sizeof(rect_iter)); + if( i == NULL ) error("ri_ini: Not enough memory."); + + /* build list of rectangle corners ordered + in a circular way around the rectangle */ + vx[0] = r->x1 - r->dy * r->width / 2.0; + vy[0] = r->y1 + r->dx * r->width / 2.0; + vx[1] = r->x2 - r->dy * r->width / 2.0; + vy[1] = r->y2 + r->dx * r->width / 2.0; + vx[2] = r->x2 + r->dy * r->width / 2.0; + vy[2] = r->y2 - r->dx * r->width / 2.0; + vx[3] = r->x1 + r->dy * r->width / 2.0; + vy[3] = r->y1 - r->dx * r->width / 2.0; + + /* compute rotation of index of corners needed so that the first + point has the smaller x. + + if one side is vertical, thus two corners have the same smaller x + value, the one with the largest y value is selected as the first. + */ + if( r->x1 < r->x2 && r->y1 <= r->y2 ) offset = 0; + else if( r->x1 >= r->x2 && r->y1 < r->y2 ) offset = 1; + else if( r->x1 > r->x2 && r->y1 >= r->y2 ) offset = 2; + else offset = 3; + + /* apply rotation of index. */ + for(n=0; n<4; n++) + { + i->vx[n] = vx[(offset+n)%4]; + i->vy[n] = vy[(offset+n)%4]; + } + + /* Set an initial condition. + + The values are set to values that will cause 'ri_inc' (that will + be called immediately) to initialize correctly the first 'column' + and compute the limits 'ys' and 'ye'. + + 'y' is set to the integer value of vy[0], the starting corner. + + 'ys' and 'ye' are set to very small values, so 'ri_inc' will + notice that it needs to start a new 'column'. + + The smallest integer coordinate inside of the rectangle is + 'ceil(vx[0])'. The current 'x' value is set to that value minus + one, so 'ri_inc' (that will increase x by one) will advance to + the first 'column'. + */ + i->x = (int) ceil(i->vx[0]) - 1; + i->y = (int) ceil(i->vy[0]); + i->ys = i->ye = -DBL_MAX; + + /* advance to the first pixel */ + ri_inc(i); + + return i; +} + +/*----------------------------------------------------------------------------*/ +/** Compute a rectangle's NFA value. + */ +static double rect_nfa(struct rect * rec, image_double angles, double logNT) +{ + rect_iter * i; + int pts = 0; + int alg = 0; + + /* check parameters */ + if( rec == NULL ) error("rect_nfa: invalid rectangle."); + if( angles == NULL ) error("rect_nfa: invalid 'angles'."); + + /* compute the total number of pixels and of aligned points in 'rec' */ + for(i=ri_ini(rec); !ri_end(i); ri_inc(i)) /* rectangle iterator */ + if( i->x >= 0 && i->y >= 0 && + i->x < (int) angles->xsize && i->y < (int) angles->ysize ) + { + ++pts; /* total number of pixels counter */ + if( isaligned(i->x, i->y, angles, rec->theta, rec->prec) ) + ++alg; /* aligned points counter */ + } + ri_del(i); /* delete iterator */ + + return nfa(pts,alg,rec->p,logNT); /* compute NFA value */ +} + + +/*----------------------------------------------------------------------------*/ +/*---------------------------------- Regions ---------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Compute region's angle as the principal inertia axis of the region. + + The following is the region inertia matrix A: + @f[ + + A = \left(\begin{array}{cc} + Ixx & Ixy \\ + Ixy & Iyy \\ + \end{array}\right) + + @f] + where + + Ixx = sum_i G(i).(y_i - cx)^2 + + Iyy = sum_i G(i).(x_i - cy)^2 + + Ixy = - sum_i G(i).(x_i - cx).(y_i - cy) + + and + - G(i) is the gradient norm at pixel i, used as pixel's weight. + - x_i and y_i are the coordinates of pixel i. + - cx and cy are the coordinates of the center of th region. + + lambda1 and lambda2 are the eigenvalues of matrix A, + with lambda1 >= lambda2. They are found by solving the + characteristic polynomial: + + det( lambda I - A) = 0 + + that gives: + + lambda1 = ( Ixx + Iyy + sqrt( (Ixx-Iyy)^2 + 4.0*Ixy*Ixy) ) / 2 + + lambda2 = ( Ixx + Iyy - sqrt( (Ixx-Iyy)^2 + 4.0*Ixy*Ixy) ) / 2 + + To get the line segment direction we want to get the angle the + eigenvector associated to the smallest eigenvalue. We have + to solve for a,b in: + + a.Ixx + b.Ixy = a.lambda2 + + a.Ixy + b.Iyy = b.lambda2 + + We want the angle theta = atan(b/a). It can be computed with + any of the two equations: + + theta = atan( (lambda2-Ixx) / Ixy ) + + or + + theta = atan( Ixy / (lambda2-Iyy) ) + + When |Ixx| > |Iyy| we use the first, otherwise the second (just to + get better numeric precision). + */ +static double get_theta( struct point * reg, int reg_size, double x, double y, + image_double modgrad, double reg_angle, double prec ) +{ + double lambda,theta,weight; + double Ixx = 0.0; + double Iyy = 0.0; + double Ixy = 0.0; + int i; + + /* check parameters */ + if( reg == NULL ) error("get_theta: invalid region."); + if( reg_size <= 1 ) error("get_theta: region size <= 1."); + if( modgrad == NULL || modgrad->data == NULL ) + error("get_theta: invalid 'modgrad'."); + if( prec < 0.0 ) error("get_theta: 'prec' must be positive."); + + /* compute inertia matrix */ + for(i=0; idata[ reg[i].x + reg[i].y * modgrad->xsize ]; + Ixx += ( (double) reg[i].y - y ) * ( (double) reg[i].y - y ) * weight; + Iyy += ( (double) reg[i].x - x ) * ( (double) reg[i].x - x ) * weight; + Ixy -= ( (double) reg[i].x - x ) * ( (double) reg[i].y - y ) * weight; + } + if( double_equal(Ixx,0.0) && double_equal(Iyy,0.0) && double_equal(Ixy,0.0) ) + error("get_theta: null inertia matrix."); + + /* compute smallest eigenvalue */ + lambda = 0.5 * ( Ixx + Iyy - sqrt( (Ixx-Iyy)*(Ixx-Iyy) + 4.0*Ixy*Ixy ) ); + + /* compute angle */ + theta = fabs(Ixx)>fabs(Iyy) ? atan2(lambda-Ixx,Ixy) : atan2(Ixy,lambda-Iyy); + + /* The previous procedure doesn't cares about orientation, + so it could be wrong by 180 degrees. Here is corrected if necessary. */ + if( angle_diff(theta,reg_angle) > prec ) theta += M_PI; + + return theta; +} + +/*----------------------------------------------------------------------------*/ +/** Computes a rectangle that covers a region of points. + */ +static void region2rect( struct point * reg, int reg_size, + image_double modgrad, double reg_angle, + double prec, double p, struct rect * rec ) +{ + double x,y,dx,dy,l,w,theta,weight,sum,l_min,l_max,w_min,w_max; + int i; + + /* check parameters */ + if( reg == NULL ) error("region2rect: invalid region."); + if( reg_size <= 1 ) error("region2rect: region size <= 1."); + if( modgrad == NULL || modgrad->data == NULL ) + error("region2rect: invalid image 'modgrad'."); + if( rec == NULL ) error("region2rect: invalid 'rec'."); + + /* center of the region: + + It is computed as the weighted sum of the coordinates + of all the pixels in the region. The norm of the gradient + is used as the weight of a pixel. The sum is as follows: + cx = \sum_i G(i).x_i + cy = \sum_i G(i).y_i + where G(i) is the norm of the gradient of pixel i + and x_i,y_i are its coordinates. + */ + x = y = sum = 0.0; + for(i=0; idata[ reg[i].x + reg[i].y * modgrad->xsize ]; + x += (double) reg[i].x * weight; + y += (double) reg[i].y * weight; + sum += weight; + } + if( sum <= 0.0 ) error("region2rect: weights sum equal to zero."); + x /= sum; + y /= sum; + + /* theta */ + theta = get_theta(reg,reg_size,x,y,modgrad,reg_angle,prec); + + /* length and width: + + 'l' and 'w' are computed as the distance from the center of the + region to pixel i, projected along the rectangle axis (dx,dy) and + to the orthogonal axis (-dy,dx), respectively. + + The length of the rectangle goes from l_min to l_max, where l_min + and l_max are the minimum and maximum values of l in the region. + Analogously, the width is selected from w_min to w_max, where + w_min and w_max are the minimum and maximum of w for the pixels + in the region. + */ + dx = cos(theta); + dy = sin(theta); + l_min = l_max = w_min = w_max = 0.0; + for(i=0; i l_max ) l_max = l; + if( l < l_min ) l_min = l; + if( w > w_max ) w_max = w; + if( w < w_min ) w_min = w; + } + + /* store values */ + rec->x1 = x + l_min * dx; + rec->y1 = y + l_min * dy; + rec->x2 = x + l_max * dx; + rec->y2 = y + l_max * dy; + rec->width = w_max - w_min; + rec->x = x; + rec->y = y; + rec->theta = theta; + rec->dx = dx; + rec->dy = dy; + rec->prec = prec; + rec->p = p; + + /* we impose a minimal width of one pixel + + A sharp horizontal or vertical step would produce a perfectly + horizontal or vertical region. The width computed would be + zero. But that corresponds to a one pixels width transition in + the image. + */ + if( rec->width < 1.0 ) rec->width = 1.0; +} + +/*----------------------------------------------------------------------------*/ +/** Build a region of pixels that share the same angle, up to a + tolerance 'prec', starting at point (x,y). + */ +static void region_grow( int x, int y, image_double angles, struct point * reg, + int * reg_size, double * reg_angle, image_char used, + double prec ) +{ + double sumdx,sumdy; + int xx,yy,i; + + /* check parameters */ + if( angles == NULL || angles->data == NULL ) + error("region_grow: invalid image 'angles'."); + if( x < 0 || y < 0 || x >= (int) angles->xsize || y >= (int) angles->ysize ) + error("region_grow: (x,y) out of the image."); + if( reg == NULL ) error("region_grow: invalid 'reg'."); + if( reg_size == NULL ) error("region_grow: invalid pointer 'reg_size'."); + if( reg_angle == NULL ) error("region_grow: invalid pointer 'reg_angle'."); + if( used == NULL || used->data == NULL ) + error("region_grow: invalid image 'used'."); + + /* first point of the region */ + *reg_size = 1; + reg[0].x = x; + reg[0].y = y; + *reg_angle = angles->data[x+y*angles->xsize]; /* region's angle */ + sumdx = cos(*reg_angle); + sumdy = sin(*reg_angle); + used->data[x+y*used->xsize] = USED; + + /* try neighbors as new region points */ + for(i=0; i<*reg_size; i++) + for(xx=reg[i].x-1; xx<=reg[i].x+1; xx++) + for(yy=reg[i].y-1; yy<=reg[i].y+1; yy++) + if( xx>=0 && yy>=0 && xx<(int)used->xsize && yy<(int)used->ysize && + used->data[xx+yy*used->xsize] != USED && + isaligned(xx,yy,angles,*reg_angle,prec) ) + { + /* add point */ + used->data[xx+yy*used->xsize] = USED; + reg[*reg_size].x = xx; + reg[*reg_size].y = yy; + ++(*reg_size); + + /* update region's angle */ + sumdx += cos( angles->data[xx+yy*angles->xsize] ); + sumdy += sin( angles->data[xx+yy*angles->xsize] ); + *reg_angle = atan2(sumdy,sumdx); + } +} + +/*----------------------------------------------------------------------------*/ +/** Try some rectangles variations to improve NFA value. Only if the + rectangle is not meaningful (i.e., log_nfa <= log_eps). + */ +static double rect_improve( struct rect * rec, image_double angles, + double logNT, double log_eps ) +{ + struct rect r; + double log_nfa,log_nfa_new; + double delta = 0.5; + double delta_2 = delta / 2.0; + int n; + + log_nfa = rect_nfa(rec,angles,logNT); + + if( log_nfa > log_eps ) return log_nfa; + + /* try finer precisions */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + r.p /= 2.0; + r.prec = r.p * M_PI; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + log_nfa = log_nfa_new; + rect_copy(&r,rec); + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try to reduce width */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + if( (r.width - delta) >= 0.5 ) + { + r.width -= delta; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + rect_copy(&r,rec); + log_nfa = log_nfa_new; + } + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try to reduce one side of the rectangle */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + if( (r.width - delta) >= 0.5 ) + { + r.x1 += -r.dy * delta_2; + r.y1 += r.dx * delta_2; + r.x2 += -r.dy * delta_2; + r.y2 += r.dx * delta_2; + r.width -= delta; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + rect_copy(&r,rec); + log_nfa = log_nfa_new; + } + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try to reduce the other side of the rectangle */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + if( (r.width - delta) >= 0.5 ) + { + r.x1 -= -r.dy * delta_2; + r.y1 -= r.dx * delta_2; + r.x2 -= -r.dy * delta_2; + r.y2 -= r.dx * delta_2; + r.width -= delta; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + rect_copy(&r,rec); + log_nfa = log_nfa_new; + } + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try even finer precisions */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + r.p /= 2.0; + r.prec = r.p * M_PI; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + log_nfa = log_nfa_new; + rect_copy(&r,rec); + } + } + + return log_nfa; +} + +/*----------------------------------------------------------------------------*/ +/** Reduce the region size, by elimination the points far from the + starting point, until that leads to rectangle with the right + density of region points or to discard the region if too small. + */ +static int reduce_region_radius( struct point * reg, int * reg_size, + image_double modgrad, double reg_angle, + double prec, double p, struct rect * rec, + image_char used, image_double angles, + double density_th ) +{ + double density,radius1,radius2,rad,xc,yc; + int i; + + /* check parameters */ + if( reg == NULL ) error("reduce_region_radius: invalid pointer 'reg'."); + if( reg_size == NULL ) + error("reduce_region_radius: invalid pointer 'reg_size'."); + if( prec < 0.0 ) error("reduce_region_radius: 'prec' must be positive."); + if( rec == NULL ) error("reduce_region_radius: invalid pointer 'rec'."); + if( used == NULL || used->data == NULL ) + error("reduce_region_radius: invalid image 'used'."); + if( angles == NULL || angles->data == NULL ) + error("reduce_region_radius: invalid image 'angles'."); + + /* compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + + /* if the density criterion is satisfied there is nothing to do */ + if( density >= density_th ) return TRUE; + + /* compute region's radius */ + xc = (double) reg[0].x; + yc = (double) reg[0].y; + radius1 = dist( xc, yc, rec->x1, rec->y1 ); + radius2 = dist( xc, yc, rec->x2, rec->y2 ); + rad = radius1 > radius2 ? radius1 : radius2; + + /* while the density criterion is not satisfied, remove farther pixels */ + while( density < density_th ) + { + rad *= 0.75; /* reduce region's radius to 75% of its value */ + + /* remove points from the region and update 'used' map */ + for(i=0; i<*reg_size; i++) + if( dist( xc, yc, (double) reg[i].x, (double) reg[i].y ) > rad ) + { + /* point not kept, mark it as NOTUSED */ + used->data[ reg[i].x + reg[i].y * used->xsize ] = NOTUSED; + /* remove point from the region */ + reg[i].x = reg[*reg_size-1].x; /* if i==*reg_size-1 copy itself */ + reg[i].y = reg[*reg_size-1].y; + --(*reg_size); + --i; /* to avoid skipping one point */ + } + + /* reject if the region is too small. + 2 is the minimal region size for 'region2rect' to work. */ + if( *reg_size < 2 ) return FALSE; + + /* re-compute rectangle */ + region2rect(reg,*reg_size,modgrad,reg_angle,prec,p,rec); + + /* re-compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + } + + /* if this point is reached, the density criterion is satisfied */ + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/** Refine a rectangle. + + For that, an estimation of the angle tolerance is performed by the + standard deviation of the angle at points near the region's + starting point. Then, a new region is grown starting from the same + point, but using the estimated angle tolerance. If this fails to + produce a rectangle with the right density of region points, + 'reduce_region_radius' is called to try to satisfy this condition. + */ +static int refine( struct point * reg, int * reg_size, image_double modgrad, + double reg_angle, double prec, double p, struct rect * rec, + image_char used, image_double angles, double density_th ) +{ + double angle,ang_d,mean_angle,tau,density,xc,yc,ang_c,sum,s_sum; + int i,n; + + /* check parameters */ + if( reg == NULL ) error("refine: invalid pointer 'reg'."); + if( reg_size == NULL ) error("refine: invalid pointer 'reg_size'."); + if( prec < 0.0 ) error("refine: 'prec' must be positive."); + if( rec == NULL ) error("refine: invalid pointer 'rec'."); + if( used == NULL || used->data == NULL ) + error("refine: invalid image 'used'."); + if( angles == NULL || angles->data == NULL ) + error("refine: invalid image 'angles'."); + + /* compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + + /* if the density criterion is satisfied there is nothing to do */ + if( density >= density_th ) return TRUE; + + /*------ First try: reduce angle tolerance ------*/ + + /* compute the new mean angle and tolerance */ + xc = (double) reg[0].x; + yc = (double) reg[0].y; + ang_c = angles->data[ reg[0].x + reg[0].y * angles->xsize ]; + sum = s_sum = 0.0; + n = 0; + for(i=0; i<*reg_size; i++) + { + used->data[ reg[i].x + reg[i].y * used->xsize ] = NOTUSED; + if( dist( xc, yc, (double) reg[i].x, (double) reg[i].y ) < rec->width ) + { + angle = angles->data[ reg[i].x + reg[i].y * angles->xsize ]; + ang_d = angle_diff_signed(angle,ang_c); + sum += ang_d; + s_sum += ang_d * ang_d; + ++n; + } + } + + /* should not happen */ + if(n == 0) return FALSE; + + mean_angle = sum / (double) n; + tau = 2.0 * sqrt( (s_sum - 2.0 * mean_angle * sum) / (double) n + + mean_angle*mean_angle ); /* 2 * standard deviation */ + + /* find a new region from the same starting point and new angle tolerance */ + region_grow(reg[0].x,reg[0].y,angles,reg,reg_size,®_angle,used,tau); + + /* if the region is too small, reject */ + if( *reg_size < 2 ) return FALSE; + + /* re-compute rectangle */ + region2rect(reg,*reg_size,modgrad,reg_angle,prec,p,rec); + + /* re-compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + + /*------ Second try: reduce region radius ------*/ + if( density < density_th ) + return reduce_region_radius( reg, reg_size, modgrad, reg_angle, prec, p, + rec, used, angles, density_th ); + + /* if this point is reached, the density criterion is satisfied */ + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*-------------------------- Line Segment Detector ---------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** LSD full interface. + */ +static +double * LineSegmentDetection( int * n_out, + double * img, int X, int Y, + double scale, double sigma_scale, double quant, + double ang_th, double log_eps, double density_th, + int n_bins, + int ** reg_img, int * reg_x, int * reg_y ) +{ + image_double image; + ntuple_list out = new_ntuple_list(7); + double * return_value; + image_double scaled_image,angles,modgrad; + image_char used; + image_int region = NULL; + struct coorlist * list_p; + void * mem_p; + struct rect rec; + struct point * reg; + int reg_size,min_reg_size,i; + unsigned int xsize,ysize; + double rho,reg_angle,prec,p,log_nfa,logNT; + int ls_count = 0; /* line segments are numbered 1,2,3,... */ + + + /* check parameters */ + if( img == NULL || X <= 0 || Y <= 0 ) error("invalid image input."); + if( scale <= 0.0 ) error("'scale' value must be positive."); + if( sigma_scale <= 0.0 ) error("'sigma_scale' value must be positive."); + if( quant < 0.0 ) error("'quant' value must be positive."); + if( ang_th <= 0.0 || ang_th >= 180.0 ) + error("'ang_th' value must be in the range (0,180)."); + if( density_th < 0.0 || density_th > 1.0 ) + error("'density_th' value must be in the range [0,1]."); + if( n_bins <= 0 ) error("'n_bins' value must be positive."); + + + /* angle tolerance */ + prec = M_PI * ang_th / 180.0; + p = ang_th / 180.0; + rho = quant / sin(prec); /* gradient magnitude threshold */ + + + /* load and scale image (if necessary) and compute angle at each pixel */ + image = new_image_double_ptr( (unsigned int) X, (unsigned int) Y, img ); + if( scale != 1.0 ) + { + scaled_image = gaussian_sampler( image, scale, sigma_scale ); + angles = ll_angle( scaled_image, rho, &list_p, &mem_p, + &modgrad, (unsigned int) n_bins ); + free_image_double(scaled_image); + } + else + angles = ll_angle( image, rho, &list_p, &mem_p, &modgrad, + (unsigned int) n_bins ); + xsize = angles->xsize; + ysize = angles->ysize; + + /* Number of Tests - NT + + The theoretical number of tests is Np.(XY)^(5/2) + where X and Y are number of columns and rows of the image. + Np corresponds to the number of angle precisions considered. + As the procedure 'rect_improve' tests 5 times to halve the + angle precision, and 5 more times after improving other factors, + 11 different precision values are potentially tested. Thus, + the number of tests is + 11 * (X*Y)^(5/2) + whose logarithm value is + log10(11) + 5/2 * (log10(X) + log10(Y)). + */ + logNT = 5.0 * ( log10( (double) xsize ) + log10( (double) ysize ) ) / 2.0 + + log10(11.0); + min_reg_size = (int) (-logNT/log10(p)); /* minimal number of points in region + that can give a meaningful event */ + + + /* initialize some structures */ + if( reg_img != NULL && reg_x != NULL && reg_y != NULL ) /* save region data */ + region = new_image_int_ini(angles->xsize,angles->ysize,0); + used = new_image_char_ini(xsize,ysize,NOTUSED); + reg = (struct point *) calloc( (size_t) (xsize*ysize), sizeof(struct point) ); + if( reg == NULL ) error("not enough memory!"); + + + /* search for line segments */ + for(; list_p != NULL; list_p = list_p->next ) + if( used->data[ list_p->x + list_p->y * used->xsize ] == NOTUSED && + angles->data[ list_p->x + list_p->y * angles->xsize ] != NOTDEF ) + /* there is no risk of double comparison problems here + because we are only interested in the exact NOTDEF value */ + { + /* find the region of connected point and ~equal angle */ + region_grow( list_p->x, list_p->y, angles, reg, ®_size, + ®_angle, used, prec ); + + /* reject small regions */ + if( reg_size < min_reg_size ) continue; + + /* construct rectangular approximation for the region */ + region2rect(reg,reg_size,modgrad,reg_angle,prec,p,&rec); + + /* Check if the rectangle exceeds the minimal density of + region points. If not, try to improve the region. + The rectangle will be rejected if the final one does + not fulfill the minimal density condition. + This is an addition to the original LSD algorithm published in + "LSD: A Fast Line Segment Detector with a False Detection Control" + by R. Grompone von Gioi, J. Jakubowicz, J.M. Morel, and G. Randall. + The original algorithm is obtained with density_th = 0.0. + */ + if( !refine( reg, ®_size, modgrad, reg_angle, + prec, p, &rec, used, angles, density_th ) ) continue; + + /* compute NFA value */ + log_nfa = rect_improve(&rec,angles,logNT,log_eps); + if( log_nfa <= log_eps ) continue; + + /* A New Line Segment was found! */ + ++ls_count; /* increase line segment counter */ + + /* + The gradient was computed with a 2x2 mask, its value corresponds to + points with an offset of (0.5,0.5), that should be added to output. + The coordinates origin is at the center of pixel (0,0). + */ + rec.x1 += 0.5; rec.y1 += 0.5; + rec.x2 += 0.5; rec.y2 += 0.5; + + /* scale the result values if a subsampling was performed */ + if( scale != 1.0 ) + { + rec.x1 /= scale; rec.y1 /= scale; + rec.x2 /= scale; rec.y2 /= scale; + rec.width /= scale; + } + + /* add line segment found to output */ + add_7tuple( out, rec.x1, rec.y1, rec.x2, rec.y2, + rec.width, rec.p, log_nfa ); + + /* add region number to 'region' image if needed */ + if( region != NULL ) + for(i=0; idata[ reg[i].x + reg[i].y * region->xsize ] = ls_count; + } + + + /* free memory */ + free( (void *) image ); /* only the double_image structure should be freed, + the data pointer was provided to this functions + and should not be destroyed. */ + free_image_double(angles); + free_image_double(modgrad); + free_image_char(used); + free( (void *) reg ); + free( (void *) mem_p ); + + /* return the result */ + if( reg_img != NULL && reg_x != NULL && reg_y != NULL ) + { + if( region == NULL ) error("'region' should be a valid image."); + *reg_img = region->data; + if( region->xsize > (unsigned int) INT_MAX || + region->ysize > (unsigned int) INT_MAX ) + error("region image to big to fit in INT sizes."); + *reg_x = (int) (region->xsize); + *reg_y = (int) (region->ysize); + + /* free the 'region' structure. + we cannot use the function 'free_image_int' because we need to keep + the memory with the image data to be returned by this function. */ + free( (void *) region ); + } + if( out->size > (unsigned int) INT_MAX ) + error("too many detections to fit in an INT."); + *n_out = (int) (out->size); + + return_value = out->values; + free( (void *) out ); /* only the 'ntuple_list' structure must be freed, + but the 'values' pointer must be keep to return + as a result. */ + + return return_value; +} +#if 0 +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface with Scale and Region output. + */ +static +double * lsd_scale_region( int * n_out, + double * img, int X, int Y, double scale, + int ** reg_img, int * reg_x, int * reg_y ) +{ + /* LSD parameters */ + double sigma_scale = 0.6; /* Sigma for Gaussian filter is computed as + sigma = sigma_scale/scale. */ + double quant = 2.0; /* Bound to the quantization error on the + gradient norm. */ + double ang_th = 22.5; /* Gradient angle tolerance in degrees. */ + double log_eps = 0.0; /* Detection threshold: -log10(NFA) > log_eps */ + double density_th = 0.7; /* Minimal density of region points in rectangle. */ + int n_bins = 1024; /* Number of bins in pseudo-ordering of gradient + modulus. */ + + return LineSegmentDetection( n_out, img, X, Y, scale, sigma_scale, quant, + ang_th, log_eps, density_th, n_bins, + reg_img, reg_x, reg_y ); +} + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface with Scale. + */ +static +double * lsd_scale(int * n_out, double * img, int X, int Y, double scale) +{ + return lsd_scale_region(n_out,img,X,Y,scale,NULL,NULL,NULL); +} + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface. + */ +static +double * lsd(int * n_out, double * img, int X, int Y) +{ + /* LSD parameters */ + double scale = 0.8; /* Scale the image by Gaussian filter to 'scale'. */ + + return lsd_scale(n_out,img,X,Y,scale); +} +/*----------------------------------------------------------------------------*/ +#endif +/*================================================================================== + * end of LSD code + *==================================================================================*/ + +// clang-format on + +#undef NOTDEF +#undef NOTUSED +#undef USED +#undef RELATIVE_ERROR_FACTOR +#undef TABSIZE + +// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh +// vim: shiftwidth=2 expandtab tabstop=2 cindent +// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; diff --git a/rtengine/ashift_nmsimplex.c b/rtengine/ashift_nmsimplex.c new file mode 100644 index 000000000..512bac878 --- /dev/null +++ b/rtengine/ashift_nmsimplex.c @@ -0,0 +1,425 @@ +/* + This file is part of darktable, + copyright (c) 2016 Ulrich Pegelow. + + 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 . +*/ + +/* For parameter optimization we are using the Nelder-Mead simplex method + * implemented by Michael F. Hutt. + * Changes versus the original code: + * do not include "nmsimplex.h" (not needed) + * renamed configuration variables to NMS_* + * add additional argument to objfun for arbitrary parameters + * simplex() returns number of used iterations instead of min value + * maximum number of iterations as function parameter + * make interface function simplex() static + * initialize i and j to avoid compiler warnings + * comment out printing of status inormation + * reformat according to darktable's clang standards + */ + +/*================================================================================== + * begin nmsimplex code downloaded from http://www.mikehutt.com/neldermead.html + * on February 6, 2016 + *==================================================================================*/ +/* + * Program: nmsimplex.c + * Author : Michael F. Hutt + * http://www.mikehutt.com + * 11/3/97 + * + * An implementation of the Nelder-Mead simplex method. + * + * Copyright (c) 1997-2011 + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Jan. 6, 1999 + * Modified to conform to the algorithm presented + * in Margaret H. Wright's paper on Direct Search Methods. + * + * Jul. 23, 2007 + * Fixed memory leak. + * + * Mar. 1, 2011 + * Added constraints. + */ + +//#include "nmsimplex.h" + +static int simplex(double (*objfunc)(double[], void *params), double start[], int n, double EPSILON, double scale, + int maxiter, void (*constrain)(double[], int n), void *params) +{ + + int vs; /* vertex with smallest value */ + int vh; /* vertex with next smallest value */ + int vg; /* vertex with largest value */ + + int i = 0, j = 0, m, row; + int k; /* track the number of function evaluations */ + int itr; /* track the number of iterations */ + + double **v; /* holds vertices of simplex */ + double pn, qn; /* values used to create initial simplex */ + double *f; /* value of function at each vertex */ + double fr; /* value of function at reflection point */ + double fe; /* value of function at expansion point */ + double fc; /* value of function at contraction point */ + double *vr; /* reflection - coordinates */ + double *ve; /* expansion - coordinates */ + double *vc; /* contraction - coordinates */ + double *vm; /* centroid - coordinates */ + //double min; + + double fsum, favg, s, cent; + + /* dynamically allocate arrays */ + + /* allocate the rows of the arrays */ + v = (double **)malloc((n + 1) * sizeof(double *)); + f = (double *)malloc((n + 1) * sizeof(double)); + vr = (double *)malloc(n * sizeof(double)); + ve = (double *)malloc(n * sizeof(double)); + vc = (double *)malloc(n * sizeof(double)); + vm = (double *)malloc(n * sizeof(double)); + + /* allocate the columns of the arrays */ + for(i = 0; i <= n; i++) + { + v[i] = (double *)malloc(n * sizeof(double)); + } + + /* create the initial simplex */ + /* assume one of the vertices is 0,0 */ + + pn = scale * (sqrt(n + 1) - 1 + n) / (n * sqrt(2)); + qn = scale * (sqrt(n + 1) - 1) / (n * sqrt(2)); + + for(i = 0; i < n; i++) + { + v[0][i] = start[i]; + } + + for(i = 1; i <= n; i++) + { + for(j = 0; j < n; j++) + { + if(i - 1 == j) + { + v[i][j] = pn + start[j]; + } + else + { + v[i][j] = qn + start[j]; + } + } + } + + if(constrain != NULL) + { + constrain(v[j], n); + } + /* find the initial function values */ + for(j = 0; j <= n; j++) + { + f[j] = objfunc(v[j], params); + } + + k = n + 1; +#if 0 + /* print out the initial values */ + printf("Initial Values\n"); + for(j = 0; j <= n; j++) + { + for(i = 0; i < n; i++) + { + printf("%f %f\n", v[j][i], f[j]); + } + } +#endif + + /* begin the main loop of the minimization */ + for(itr = 1; itr <= maxiter; itr++) + { + /* find the index of the largest value */ + vg = 0; + for(j = 0; j <= n; j++) + { + if(f[j] > f[vg]) + { + vg = j; + } + } + + /* find the index of the smallest value */ + vs = 0; + for(j = 0; j <= n; j++) + { + if(f[j] < f[vs]) + { + vs = j; + } + } + + /* find the index of the second largest value */ + vh = vs; + for(j = 0; j <= n; j++) + { + if(f[j] > f[vh] && f[j] < f[vg]) + { + vh = j; + } + } + + /* calculate the centroid */ + for(j = 0; j <= n - 1; j++) + { + cent = 0.0; + for(m = 0; m <= n; m++) + { + if(m != vg) + { + cent += v[m][j]; + } + } + vm[j] = cent / n; + } + + /* reflect vg to new vertex vr */ + for(j = 0; j <= n - 1; j++) + { + /*vr[j] = (1+NMS_ALPHA)*vm[j] - NMS_ALPHA*v[vg][j];*/ + vr[j] = vm[j] + NMS_ALPHA * (vm[j] - v[vg][j]); + } + if(constrain != NULL) + { + constrain(vr, n); + } + fr = objfunc(vr, params); + k++; + + if(fr < f[vh] && fr >= f[vs]) + { + for(j = 0; j <= n - 1; j++) + { + v[vg][j] = vr[j]; + } + f[vg] = fr; + } + + /* investigate a step further in this direction */ + if(fr < f[vs]) + { + for(j = 0; j <= n - 1; j++) + { + /*ve[j] = NMS_GAMMA*vr[j] + (1-NMS_GAMMA)*vm[j];*/ + ve[j] = vm[j] + NMS_GAMMA * (vr[j] - vm[j]); + } + if(constrain != NULL) + { + constrain(ve, n); + } + fe = objfunc(ve, params); + k++; + + /* by making fe < fr as opposed to fe < f[vs], + Rosenbrocks function takes 63 iterations as opposed + to 64 when using double variables. */ + + if(fe < fr) + { + for(j = 0; j <= n - 1; j++) + { + v[vg][j] = ve[j]; + } + f[vg] = fe; + } + else + { + for(j = 0; j <= n - 1; j++) + { + v[vg][j] = vr[j]; + } + f[vg] = fr; + } + } + + /* check to see if a contraction is necessary */ + if(fr >= f[vh]) + { + if(fr < f[vg] && fr >= f[vh]) + { + /* perform outside contraction */ + for(j = 0; j <= n - 1; j++) + { + /*vc[j] = NMS_BETA*v[vg][j] + (1-NMS_BETA)*vm[j];*/ + vc[j] = vm[j] + NMS_BETA * (vr[j] - vm[j]); + } + if(constrain != NULL) + { + constrain(vc, n); + } + fc = objfunc(vc, params); + k++; + } + else + { + /* perform inside contraction */ + for(j = 0; j <= n - 1; j++) + { + /*vc[j] = NMS_BETA*v[vg][j] + (1-NMS_BETA)*vm[j];*/ + vc[j] = vm[j] - NMS_BETA * (vm[j] - v[vg][j]); + } + if(constrain != NULL) + { + constrain(vc, n); + } + fc = objfunc(vc, params); + k++; + } + + + if(fc < f[vg]) + { + for(j = 0; j <= n - 1; j++) + { + v[vg][j] = vc[j]; + } + f[vg] = fc; + } + /* at this point the contraction is not successful, + we must halve the distance from vs to all the + vertices of the simplex and then continue. + 10/31/97 - modified to account for ALL vertices. + */ + else + { + for(row = 0; row <= n; row++) + { + if(row != vs) + { + for(j = 0; j <= n - 1; j++) + { + v[row][j] = v[vs][j] + (v[row][j] - v[vs][j]) / 2.0; + } + } + } + if(constrain != NULL) + { + constrain(v[vg], n); + } + f[vg] = objfunc(v[vg], params); + k++; + if(constrain != NULL) + { + constrain(v[vh], n); + } + f[vh] = objfunc(v[vh], params); + k++; + } + } +#if 0 + /* print out the value at each iteration */ + printf("Iteration %d\n", itr); + for(j = 0; j <= n; j++) + { + for(i = 0; i < n; i++) + { + printf("%f %f\n", v[j][i], f[j]); + } + } +#endif + /* test for convergence */ + fsum = 0.0; + for(j = 0; j <= n; j++) + { + fsum += f[j]; + } + favg = fsum / (n + 1); + s = 0.0; + for(j = 0; j <= n; j++) + { + s += pow((f[j] - favg), 2.0) / (n); + } + s = sqrt(s); + if(s < EPSILON) break; + } + /* end main loop of the minimization */ + + /* find the index of the smallest value */ + vs = 0; + for(j = 0; j <= n; j++) + { + if(f[j] < f[vs]) + { + vs = j; + } + } +#if 0 + printf("The minimum was found at\n"); + for(j = 0; j < n; j++) + { + printf("%e\n", v[vs][j]); + start[j] = v[vs][j]; + } + double min = objfunc(v[vs], params); + k++; + printf("The minimum value is %f\n", min); + printf("%d Function Evaluations\n", k); + printf("%d Iterations through program\n", itr); +#else + for(j = 0; j < n; j++) + { + start[j] = v[vs][j]; + } +#endif + free(f); + free(vr); + free(ve); + free(vc); + free(vm); + for(i = 0; i <= n; i++) + { + free(v[i]); + } + free(v); + return itr; +} + +/*================================================================================== + * end of nmsimplex code + *==================================================================================*/ + +// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh +// vim: shiftwidth=2 expandtab tabstop=2 cindent +// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified; diff --git a/rtengine/bayer_bilinear_demosaic.cc b/rtengine/bayer_bilinear_demosaic.cc new file mode 100644 index 000000000..5b3835ce9 --- /dev/null +++ b/rtengine/bayer_bilinear_demosaic.cc @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////////// +// +// Bilinear bayer demosaic, optimized for speed, intended use is for flat regions of dual-demosaic +// +// copyright (c) 2020 Ingo Weyrich +// +// +// code dated: May 09, 2020 +// +// bayer_bilinear_demosaic.cc 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. +// +// This program 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 this program. If not, see . +// +//////////////////////////////////////////////////////////////// + +#include "rawimagesource.h" +#include "rt_math.h" + +using namespace rtengine; + +void RawImageSource::bayer_bilinear_demosaic(const float* const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue) +{ + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 1; i < H - 1; ++i) { + float **nonGreen1 = red; + float **nonGreen2 = blue; + if (FC(i, 0) == 2 || FC(i, 1) == 2) { // blue row => swap pointers + std::swap(nonGreen1, nonGreen2); + } +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif + for (int j = 2 - (FC(i, 1) & 1); j < W - 2; j += 2) { // always begin with a green pixel + green[i][j] = intp(blend[i][j], green[i][j], rawData[i][j]); + nonGreen1[i][j] = intp(blend[i][j], nonGreen1[i][j], (rawData[i][j - 1] + rawData[i][j + 1]) * 0.5f); + nonGreen2[i][j] = intp(blend[i][j], nonGreen2[i][j], (rawData[i - 1][j] + rawData[i + 1][j]) * 0.5f); + green[i][j + 1] = intp(blend[i][j + 1], green[i][j + 1], ((rawData[i - 1][j + 1] + rawData[i][j]) + (rawData[i][j + 2] + rawData[i + 1][j + 1])) * 0.25f); + nonGreen1[i][j + 1] = intp(blend[i][j + 1], nonGreen1[i][j + 1], rawData[i][j + 1]); + nonGreen2[i][j + 1] = intp(blend[i][j + 1], nonGreen2[i][j + 1], ((rawData[i - 1][j] + rawData[i - 1][j + 2]) + (rawData[i + 1][j] + rawData[i + 1][j + 2])) * 0.25f); + } + } +} diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 5fc7d4062..22270bfe2 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 ], @@ -1143,11 +1144,30 @@ Camera constants: "raw_crop": [ 144, 72, 6984, 4660 ] }, - { // Quality C, only raw crop + { // Quality B, samples by jonathanBieler (#5922). No dual-pixel information. "make_model": [ "Canon EOS R" ], - "raw_crop": [ 144, 46, 6744, 4500 ] + "dcraw_matrix" : [ 8293, -1789, -1094, -5025, 12925, 2327, -1199, 2769, 6108 ], // DNG v2 style + "raw_crop": [ 144, 46, 6744, 4500 ], + "masked_areas": [ 50, 40, 4540, 140 ], // Taken from ART + "ranges" : { "white" : 16367 } // Typically 16383 without LENR, with LENR safest value is 15800 for ISO 25600 }, + { // Quality C + "make_model": "Canon EOS R5", + "dcraw_matrix" : [9766, -2953, -1254, -4276, 12116, 2433, -437, 1336, 5131], + "raw_crop" : [ 124, 92, 8220, 5486 ], + "masked_areas" : [ 94, 20, 5578, 122 ], + "ranges" : { "white" : 16382 } + }, + + { // Quality C + "make_model": "Canon EOS R6", + "dcraw_matrix" : [8293, -1611, -1132, -4759, 12710, 2275, -1013, 2415, 5508], + "raw_crop": [ 72, 38, 5496, 3670 ], + "masked_areas" : [ 40, 10, 5534, 70 ], + "ranges" : { "white" : 16382 } + }, + // Canon Powershot { // Quality C, CHDK DNGs, raw frame correction "make_model": "Canon PowerShot A3100 IS", @@ -1259,15 +1279,18 @@ Camera constants: { // Quality C "make_model": [ "DJI FC2103" ], - "ranges": { - "black": 4080 - } + "ranges": { "black": 4080 } }, { // Quality C "make_model": "DJI FC6310", "ranges": { "white": 64886 } }, + + { // Quality C + "make_model": "DJI FC3170", + "ranges": { "white": 65472 } + }, { // Quality C "make_model": "FUJIFILM GFX 100", @@ -1295,12 +1318,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 } @@ -1349,12 +1366,20 @@ Camera constants: }, { // Quality B - "make_model": [ "FUJIFILM X-T1", "FUJIFILM X-T10", "FUJIFILM X-E2" ], + "make_model": [ "FUJIFILM X-T10", "FUJIFILM X-E2" ], "dcraw_matrix": [ 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 ], // DNG D65 //"dcraw_matrix": [ 9289,-3279,-632,-3539,11137,2758,-1049,1950,6544 ], // X-RITE D55 - //"raw_crop": [ 4, 0, 4936, 3296 ], // full raw 4992,3296, fuji official 4936,3296 - experimental crop + //"raw_crop": [ 4, 0, 4936, 3296 ], // full raw 4992,3296, fuji official 4936,3296 "ranges": { "white": 16100 } }, + + { // Quality B, samples provided by Claes + "make_model": "FUJIFILM X-T1", + "dcraw_matrix": [ 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 ], // DNG D65 + "raw_crop": [ 4, 0, 4936, 3296 ], // full raw 4992,3296, fuji official 4936,3296 + "ranges": { "white": [ 16202, 16277, 16232 ] } // LENR on from ISO4000+ negligibly underestimates white level + // No aperture scaling data provided, but likely negligible + }, { // Quality C "make_model": [ "FUJIFILM X-T100" ], @@ -1375,16 +1400,40 @@ Camera constants: }, { // Quality B - "make_model": [ "FUJIFILM X-T2", "FUJIFILM X-T20", "FUJIFILM X-E3", "FUJIFILM X100F", "FUJIFILM X-PRO2", "FUJIFILM X-H1" ], + "make_model": [ "FUJIFILM X-T20", "FUJIFILM X-E3", "FUJIFILM X100F", "FUJIFILM X-H1" ], "dcraw_matrix": [ 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 ], // DNG_v9.4 D65 // "raw_crop": [ 0, 5, 6032, 4032 ], // full raw 6160,4032, Usable 6032,4032 - for lossless compressed files // "raw_crop": [ 0, 0, 6032, 4032 ], // full raw 6160,4032, Usable 6032,4032 - for uncompressed files "raw_crop": [ 0, 5, 6032, 4026 ], // full raw 6160,4032, Usable 6032,4026 - for uncompressed and lossless compressed files (but reduces height by 6 pixels) "ranges": { "white": 16100 } }, - - { // Quality C, only raw crop - "make_model": [ "FUJIFILM X-T3", "FUJIFILM X-T30", "FUJIFILM X-PRO3" ], + + { // Quality B, samples provided by Daniel Catalina #5824 + "make_model": "FUJIFILM X-T2", + "dcraw_matrix": [ 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 ], // DNG_v9.4 D65 + "raw_crop": [ 0, 5, 6032, 4026 ], // xee X-T20 + "ranges": { "white": [ 16195, 16270, 16195 ] } // With LENR on and ISO4000+ starts to overestimate white level, more realistic would be 16090 + // Negligible aperture scaling effect + }, + + { // Quality B, samples provided by Claes + "make_model": "FUJIFILM X-PRO2", + "dcraw_matrix": [ 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 ], // DNG_v9.4 D65 + "raw_crop": [ 0, 5, 6032, 4026 ], // see X-T2 + "ranges": { "white": [ 16105, 16270, 16082 ] } // These values are the lowest pixel values >16000 for all ISOs. LENR has a negligble effect. + // No aperture scaling data provided, but likely negligible + }, + + { // Quality A, samples provided by Daniel Catalina (#5839) and pi99y (#5860) + "make_model": [ "FUJIFILM X-T3", "FUJIFILM X-PRO3" ], + "dcraw_matrix": [ 13426,-6334,-1177,-4244,12136,2371,-580,1303,5980 ], // DNG_v11, standard_v2 d65 + "raw_crop": [ 0, 5, 6252, 4176], + "white": [ 16170, 16275, 16170 ] // typical safe-margins with LENR + // negligible aperture scaling effect + }, + + { // Quality B + "make_model": [ "FUJIFILM X-T30", "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] }, @@ -1537,10 +1586,14 @@ Camera constants: } }, - { // Quality B + { // Quality A, samples provided by dimonoid (#5842) "make_model": "NIKON COOLPIX P1000", "dcraw_matrix": [ 14294, -6116, -1333, -1628, 10219, 1637, -14, 1158, 5022 ], // ColorMatrix2 from Adobe DNG Converter 11.4 - "ranges": { "black": 200, "white": 4087 } + "ranges": { + "black": 200, + "white": [ 4000, 4050, 3950 ] // Typical values without LENR: 4009, 4093, 3963 + } // No significant influence of ISO + // No aperture scaling reported }, { // Quality B, no LENR samples @@ -1698,6 +1751,60 @@ Camera constants: "pdaf_offset" : 32 }, + { // Quality C, only dcraw looted from ART commit ad88c7d97 + "make_model" : "NIKON Z 5", + "dcraw_matrix" : [8695, -2558, -648, -5015, 12711, 2575, -1279, 2215, 7514] + }, + + { // Quality A, white levels and PDAF lines measured by Yann Leprince #5851 + "make_model" : "Nikon Z 50", + "dcraw_matrix" : [11640, -4829, -1079, -5107, 13006, 2325, -972, 1711, 7380], // Adobe DNG Converter 12.2.1 ColorMatrix2 (D65) + "ranges": { + "white": [ + // White level was consistently measured at 16383 for non-LENR images. These values are computed using + // 16383 - 6 * read_noise (where read_noise values are extracted from + // https://www.photonstophotos.net/Charts/RN_ADU.htm#Nikon%20Z%2050_14 for iso < 1600, fitted in the + // 1600-10183 range, and extrapolated from that fit into the 12800-204800 range, where the read noise + // provided by photonstophotos is underestimated due to in-body noise reduction. These values were + // verified to be below the 1st percentile of the distribution, on LENR white frames taken with a 2 s + // shutter in a variety of conditions (apertures from 1.8 to 6.3). + {"iso": 100, "levels": 16374}, + {"iso": 126, "levels": 16371}, + {"iso": 159, "levels": 16367}, + {"iso": 200, "levels": 16367}, + {"iso": 251, "levels": 16364}, + {"iso": 318, "levels": 16360}, + {"iso": 400, "levels": 16366}, + {"iso": 503, "levels": 16364}, + {"iso": 636, "levels": 16362}, + {"iso": 800, "levels": 16358}, + {"iso": 1006, "levels": 16349}, + {"iso": 1273, "levels": 16345}, + {"iso": 1600, "levels": 16337}, + {"iso": 2011, "levels": 16327}, + {"iso": 2546, "levels": 16313}, + {"iso": 3200, "levels": 16298}, + {"iso": 4022, "levels": 16278}, + {"iso": 5091, "levels": 16253}, + {"iso": 6400, "levels": 16223}, + {"iso": 8045, "levels": 16186}, + {"iso": 10183, "levels": 16139}, + {"iso": 12800, "levels": 16082}, + {"iso": 16090, "levels": 16013}, + {"iso": 20366, "levels": 15924}, + {"iso": 25600, "levels": 15818}, + {"iso": 32180, "levels": 15687}, + {"iso": 40731, "levels": 15521}, + {"iso": 51200, "levels": 15321}, + {"iso": 102400, "levels": 14388}, + {"iso": 204800, "levels": 12633} + ] + }, + "pdaf_offset": 0, + // Every 12th line from 285 to 3441. These lines (specifically, the blue subpixels) have a lower standard deviation on a black frame. + "pdaf_pattern": [285, 297, 309, 321, 333, 345, 357, 369, 381, 393, 405, 417, 429, 441, 453, 465, 477, 489, 501, 513, 525, 537, 549, 561, 573, 585, 597, 609, 621, 633, 645, 657, 669, 681, 693, 705, 717, 729, 741, 753, 765, 777, 789, 801, 813, 825, 837, 849, 861, 873, 885, 897, 909, 921, 933, 945, 957, 969, 981, 993, 1005, 1017, 1029, 1041, 1053, 1065, 1077, 1089, 1101, 1113, 1125, 1137, 1149, 1161, 1173, 1185, 1197, 1209, 1221, 1233, 1245, 1257, 1269, 1281, 1293, 1305, 1317, 1329, 1341, 1353, 1365, 1377, 1389, 1401, 1413, 1425, 1437, 1449, 1461, 1473, 1485, 1497, 1509, 1521, 1533, 1545, 1557, 1569, 1581, 1593, 1605, 1617, 1629, 1641, 1653, 1665, 1677, 1689, 1701, 1713, 1725, 1737, 1749, 1761, 1773, 1785, 1797, 1809, 1821, 1833, 1845, 1857, 1869, 1881, 1893, 1905, 1917, 1929, 1941, 1953, 1965, 1977, 1989, 2001, 2013, 2025, 2037, 2049, 2061, 2073, 2085, 2097, 2109, 2121, 2133, 2145, 2157, 2169, 2181, 2193, 2205, 2217, 2229, 2241, 2253, 2265, 2277, 2289, 2301, 2313, 2325, 2337, 2349, 2361, 2373, 2385, 2397, 2409, 2421, 2433, 2445, 2457, 2469, 2481, 2493, 2505, 2517, 2529, 2541, 2553, 2565, 2577, 2589, 2601, 2613, 2625, 2637, 2649, 2661, 2673, 2685, 2697, 2709, 2721, 2733, 2745, 2757, 2769, 2781, 2793, 2805, 2817, 2829, 2841, 2853, 2865, 2877, 2889, 2901, 2913, 2925, 2937, 2949, 2961, 2973, 2985, 2997, 3009, 3021, 3033, 3045, 3057, 3069, 3081, 3093, 3105, 3117, 3129, 3141, 3153, 3165, 3177, 3189, 3201, 3213, 3225, 3237, 3249, 3261, 3273, 3285, 3297, 3309, 3321, 3333, 3345, 3357, 3369, 3381, 3393, 3405, 3417, 3429, 3441] + }, + { // Quality B, 16Mp and 64Mp raw frames "make_model": "OLYMPUS E-M5MarkII", "dcraw_matrix": [ 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 ], // DNG_v8.8 D65 @@ -2675,6 +2782,12 @@ Camera constants: "ranges": { "black": 0, "white": 64400 } }, + { // Quality B + "make_model": ["HASSELBLAD NEX-7", "SONY NEX-7"], // Hasselblad NEX-7 also known as Hasselblad Lunar + "dcraw_matrix": [ 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 ], // adobe DNGv12.2 d65 + "ranges": { "black": 512, "white": 16372 } // Typical white level (samples provided by @ggc on Pixls, influence from LENR unknown + }, + { // Quality A for tested CFV, the other models have the same sensor (16 megapixel square sensor) "make_model": [ "Hasselblad V96C", "Hasselblad CFV", "Hasselblad CFV-II" ], "dcraw_matrix": [ 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809 ] // borrowed from Adobe's DNG converter diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc index f9850189c..e3097ad2e 100644 --- a/rtengine/canon_cr3_decoder.cc +++ b/rtengine/canon_cr3_decoder.cc @@ -602,7 +602,9 @@ int DCraw::parseCR3( relpos_inBox += lTag; } } - + if (!szItem) { + goto fin; + } relpos_inDir += szItem; } @@ -3130,7 +3132,8 @@ void DCraw::crxLoadRaw() hdr.tileHeight >>= 1; } -// /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1; + // /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1; + tiff_bps = hdr.nBits; std::uint8_t* const hdrBuf = static_cast(malloc(hdr.mdatHdrSize)); diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc index 4dcdd0734..83c44aa18 100644 --- a/rtengine/capturesharpening.cc +++ b/rtengine/capturesharpening.cc @@ -127,12 +127,8 @@ void compute3x3kernel(float sigma, float kernel[3][3]) { float sum = 0.f; for (int i = -1; i <= 1; ++i) { for (int j = -1; j <= 1; ++j) { - if((rtengine::SQR(i) + rtengine::SQR(j)) <= rtengine::SQR(3.0 * 0.84)) { - kernel[i + 1][j + 1] = std::exp((rtengine::SQR(i) + rtengine::SQR(j)) / temp); - sum += kernel[i + 1][j + 1]; - } else { - kernel[i + 1][j + 1] = 0.f; - } + kernel[i + 1][j + 1] = std::exp((rtengine::SQR(i) + rtengine::SQR(j)) / temp); + sum += kernel[i + 1][j + 1]; } } @@ -647,7 +643,7 @@ float calcRadiusBayer(const float * const *rawData, int W, int H, float lowerLim } } } - return std::sqrt((1.f / (std::log(1.f / maxRatio) / 2.f)) / -2.f); + return std::sqrt(1.f / std::log(maxRatio)); } float calcRadiusXtrans(const float * const *rawData, int W, int H, float lowerLimit, float upperLimit, unsigned int starty, unsigned int startx) @@ -738,7 +734,7 @@ float calcRadiusXtrans(const float * const *rawData, int W, int H, float lowerLi } } } - return std::sqrt((1.f / (std::log(1.f / maxRatio) / 2.f)) / -2.f); + return std::sqrt(1.f / std::log(maxRatio)); } bool checkForStop(float** tmpIThr, float** iterCheck, int fullTileSize, int border) @@ -1116,23 +1112,23 @@ BENCHFUN return; } - array2D* Lbuffer = nullptr; + std::unique_ptr> Lbuffer; if (!redCache) { - Lbuffer = new array2D(W, H); + Lbuffer.reset(new array2D(W, H)); } - array2D* YOldbuffer = nullptr; + std::unique_ptr> YOldbuffer; if (!greenCache) { - YOldbuffer = new array2D(W, H); + YOldbuffer.reset(new array2D(W, H)); } - array2D* YNewbuffer = nullptr; + std::unique_ptr> YNewbuffer; if (!blueCache) { - YNewbuffer = new array2D(W, H); + YNewbuffer.reset(new array2D(W, H)); } - array2D& L = Lbuffer ? *Lbuffer : red; - array2D& YOld = YOldbuffer ? * YOldbuffer : green; - array2D& YNew = YNewbuffer ? * YNewbuffer : blue; + array2D& L = Lbuffer.get() ? *Lbuffer.get() : red; + array2D& YOld = YOldbuffer.get() ? *YOldbuffer.get() : green; + array2D& YNew = YNewbuffer.get() ? *YNewbuffer.get() : blue; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 16) @@ -1160,17 +1156,12 @@ BENCHFUN #pragma omp parallel for schedule(dynamic, 16) #endif for (int i = 0; i < H; ++i) { - int j = 0; -#ifdef __SSE2__ - for (; j < W - 3; j += 4) { - const vfloat factor = LVFU(YNew[i][j]) / vmaxf(LVFU(YOld[i][j]), F2V(0.00001f)); - STVFU(red[i][j], LVFU(redVals[i][j]) * factor); - STVFU(green[i][j], LVFU(greenVals[i][j]) * factor); - STVFU(blue[i][j], LVFU(blueVals[i][j]) * factor); - } - +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep #endif - for (; j < W; ++j) { + for (int j = 0; j < W; ++j) { const float factor = YNew[i][j] / std::max(YOld[i][j], 0.00001f); red[i][j] = redVals[i][j] * factor; green[i][j] = greenVals[i][j] * factor; @@ -1178,9 +1169,6 @@ BENCHFUN } } - delete Lbuffer; - delete YOldbuffer; - delete YNewbuffer; if (plistener) { plistener->setProgress(1.0); } 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..11a94d1dc 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 @@ -998,23 +1015,6 @@ void Color::xyz2r (float x, float y, float z, float &r, const double rgb_xyz[3][ r = ((rgb_xyz[0][0] * x + rgb_xyz[0][1] * y + rgb_xyz[0][2] * z)) ; } -// same for float -void Color::xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]) -{ - r = ((rgb_xyz[0][0] * x + rgb_xyz[0][1] * y + rgb_xyz[0][2] * z)) ; - g = ((rgb_xyz[1][0] * x + rgb_xyz[1][1] * y + rgb_xyz[1][2] * z)) ; - b = ((rgb_xyz[2][0] * x + rgb_xyz[2][1] * y + rgb_xyz[2][2] * z)) ; -} - -#ifdef __SSE2__ -void Color::xyz2rgb (vfloat x, vfloat y, vfloat z, vfloat &r, vfloat &g, vfloat &b, const vfloat rgb_xyz[3][3]) -{ - r = ((rgb_xyz[0][0] * x + rgb_xyz[0][1] * y + rgb_xyz[0][2] * z)) ; - g = ((rgb_xyz[1][0] * x + rgb_xyz[1][1] * y + rgb_xyz[1][2] * z)) ; - b = ((rgb_xyz[2][0] * x + rgb_xyz[2][1] * y + rgb_xyz[2][2] * z)) ; -} -#endif // __SSE2__ - #ifdef __SSE2__ void Color::trcGammaBW (float &r, float &g, float &b, float gammabwr, float gammabwg, float gammabwb) { @@ -1172,48 +1172,26 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u float koymcp = 0.f; if(setting == "ROYGCBPM-Abs" || setting == "ROYGCBPM-Rel") { - float obM = 0.f; - float ogM = 0.f; - float orM = 0.f; - - float ybM = 0.f; - float yrM = 0.f; - float ygM = 0.f; - - float mgM = 0.f; - float mrM = 0.f; - float mbM = 0.f; - - float pgM = 0.f; - float prM = 0.f; - float pbM = 0.f; - - float crM = 0.f; - float cgM = 0.f; - float cbM = 0.f; - //printf("mixred=%f\n",mixerRed); - float fcompl = 1.f; - if(complement && algo == "SP") { + if (complement && algo == "SP") { fcompl = 3.f; //special - } else if(complement && algo == "LI") { + } else if (complement && algo == "LI") { fcompl = 1.5f; //linear } // ponderate filters: report to R=G=B=33 // I ponder RGB channel, not only orange or yellow or cyan, etc...it's my choice ! - if(mixerOrange != 33) { - if (algo == "SP") { //special - if (mixerOrange >= 33) { - orM = fcompl * (mixerOrange * 0.67f - 22.11f) / 100.f; - } else { - orM = fcompl * (-0.3f * mixerOrange + 9.9f) / 100.f; - } + if (mixerOrange != 33.f) { + float ogM = 0.f; + float orM = 0.f; - if (mixerOrange >= 33) { + if (algo == "SP") { //special + if (mixerOrange > 33.f) { + orM = fcompl * (mixerOrange * 0.67f - 22.11f) / 100.f; ogM = fcompl * (-0.164f * mixerOrange + 5.412f) / 100.f; } else { + orM = fcompl * (-0.3f * mixerOrange + 9.9f) / 100.f; ogM = fcompl * (0.4f * mixerOrange - 13.2f) / 100.f; } } else if (algo == "LI") { //linear @@ -1221,30 +1199,24 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u ogM = fcompl * (0.5f * mixerOrange - 16.5f) / 100.f; } - if(complement) { - obM = (-0.492f * mixerOrange + 16.236f) / 100.f; - } + const float obM = complement ? (-0.492f * mixerOrange + 16.236f) / 100.f : 0.f; - mixerRed += orM; + mixerRed += orM; mixerGreen += ogM; - mixerBlue += obM; + mixerBlue += obM; koymcp += (orM + ogM + obM); - // printf("mixred+ORange=%f\n",mixerRed); - } - if(mixerYellow != 33) { + if (mixerYellow != 33.f) { + float yrM = 0.f; if (algo == "SP") { yrM = fcompl * (-0.134f * mixerYellow + 4.422f) / 100.f; //22.4 } else if (algo == "LI") { yrM = fcompl * (0.5f * mixerYellow - 16.5f) / 100.f; //22.4 } - ygM = fcompl * (0.5f * mixerYellow - 16.5f ) / 100.f; - - if(complement) { - ybM = (-0.492f * mixerYellow + 16.236f) / 100.f; - } + const float ygM = fcompl * (0.5f * mixerYellow - 16.5f ) / 100.f; + const float ybM = complement ? (-0.492f * mixerYellow + 16.236f) / 100.f : 0.f; mixerRed += yrM; mixerGreen += ygM; @@ -1252,17 +1224,15 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u koymcp += (yrM + ygM + ybM); } - if(mixerMagenta != 33) { + if (mixerMagenta != 33.f) { + float mrM = 0.f; + float mbM = 0.f; if (algo == "SP") { - if(mixerMagenta >= 33) { + if (mixerMagenta > 33.f) { mrM = fcompl * ( 0.67f * mixerMagenta - 22.11f) / 100.f; - } else { - mrM = fcompl * (-0.3f * mixerMagenta + 9.9f) / 100.f; - } - - if(mixerMagenta >= 33) { mbM = fcompl * (-0.164f * mixerMagenta + 5.412f) / 100.f; } else { + mrM = fcompl * (-0.3f * mixerMagenta + 9.9f) / 100.f; mbM = fcompl * ( 0.4f * mixerMagenta - 13.2f) / 100.f; } } else if (algo == "LI") { @@ -1270,9 +1240,7 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u mbM = fcompl * (0.5f * mixerMagenta - 16.5f) / 100.f; } - if(complement) { - mgM = (-0.492f * mixerMagenta + 16.236f) / 100.f; - } + const float mgM = complement ? (-0.492f * mixerMagenta + 16.236f) / 100.f : 0.f; mixerRed += mrM; mixerGreen += mgM; @@ -1280,18 +1248,16 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u koymcp += (mrM + mgM + mbM); } - if(mixerPurple != 33) { + if (mixerPurple != 33.f) { + float prM = 0.f; if (algo == "SP") { prM = fcompl * (-0.134f * mixerPurple + 4.422f) / 100.f; } else if (algo == "LI") { prM = fcompl * (0.5f * mixerPurple - 16.5f) / 100.f; } - pbM = fcompl * (0.5f * mixerPurple - 16.5f) / 100.f; - - if(complement) { - pgM = (-0.492f * mixerPurple + 16.236f) / 100.f; - } + const float pbM = fcompl * (0.5f * mixerPurple - 16.5f) / 100.f; + const float pgM = complement ? (-0.492f * mixerPurple + 16.236f) / 100.f : 0.f; mixerRed += prM; mixerGreen += pgM; @@ -1299,18 +1265,16 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u koymcp += (prM + pgM + pbM); } - if(mixerCyan != 33) { + if (mixerCyan != 33.f) { + float cgM = 0.f; if (algo == "SP") { cgM = fcompl * (-0.134f * mixerCyan + 4.422f) / 100.f; } else if (algo == "LI") { cgM = fcompl * (0.5f * mixerCyan - 16.5f) / 100.f; } - cbM = fcompl * (0.5f * mixerCyan - 16.5f) / 100.f; - - if(complement) { - crM = (-0.492f * mixerCyan + 16.236f) / 100.f; - } + const float cbM = fcompl * (0.5f * mixerCyan - 16.5f) / 100.f; + const float crM = complement ? (-0.492f * mixerCyan + 16.236f) / 100.f : 0.f; mixerRed += crM; mixerGreen += cgM; @@ -1330,7 +1294,7 @@ void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::u filblue = 1.f; filcor = 1.f; - if (filter == "None") { + if (filter == "None") { filred = 1.f; filgreen = 1.f; filblue = 1.f; @@ -1421,15 +1385,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 +1396,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 +1426,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; @@ -1501,101 +1443,79 @@ void Color::interpolateRGBColor (float realL, float iplow, float iphigh, int alg const float xl, const float yl, const float zl, const float x2, const float y2, const float z2, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo) { - float X1, Y1, Z1, X2, Y2, Z2, X, Y, Z, XL, YL, ZL; - float L1 = 0.f, L2, LL, a_1 = 0.f, b_1 = 0.f, a_2 = 0.f, b_2 = 0.f, a_L, b_L; + float L1 = 0.f, a_1 = 0.f, b_1 = 0.f, a_2 = 0.f, b_2 = 0.f, a_L = 0.f, b_L = 0.f; - // converting color 1 to Lab (image) - Color::rgbxyz(r1, g1, b1, X1, Y1, Z1, xyz_rgb); - - if(algm == 1) {//use H interpolate + if (algm == 1) {//use H interpolate + // converting color 1 to Lab (image) + float X1, Y1, Z1; + Color::rgbxyz(r1, g1, b1, X1, Y1, Z1, xyz_rgb); Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1); - //Color::Lab2Lch(a_1, b_1, c_1, h_1) ; } // converting color l lab(low) first color - if(twoc == 0) { // 2 colours - //Color::rgbxyz(rl, gl, bl, XL, YL, ZL, xyz_rgb); - XL = xl; - YL = yl; - ZL = zl; - - if(algm <= 1) {//use H interpolate - Color::XYZ2Lab(XL, YL, ZL, LL, a_L, b_L); + if (twoc == 0) { // 2 colours + if (algm == 1) {//use H interpolate + float unused; + Color::XYZ2Lab(xl, yl, zl, unused, a_L, b_L); } } // converting color 2 to lab (universal or high) - X2 = x2; - Y2 = y2; - Z2 = z2; - - if(algm == 1 ) { - Color::XYZ2Lab(X2, Y2, Z2, L2, a_2, b_2); - //Color::Lab2Lch(a_2, b_2, c_2, h_2) ; + if (algm == 1) { + float unused; + Color::XYZ2Lab(x2, y2, z2, unused, a_2, b_2); } - float cal, calH, calm; - cal = calH = calm = 1.f - chromat; - float med = 1.f; - float medH = 0.f; - - float calan; - calan = chromat; - - float calby; - calby = luma; - - if(twoc == 0) { // 2 colours - calan = chromat; + float cal, calH; + cal = calH = 1.f - chromat; + if (twoc == 0) { // 2 colours //calculate new balance chroma - if (realL > iplow && realL <= med) { - cal = realL * calan / (iplow - med) - med * calan / (iplow - med); + constexpr float med = 1.f; + if (realL > iplow && realL <= med) { + cal = realL * chromat / (iplow - med) - chromat / (iplow - med); } else if (realL <= iplow) { - cal = realL * calan / iplow; + cal = realL * chromat / iplow; } - if (realL > medH && realL <= iphigh) { - calH = realL * calan / (iphigh - medH) - medH * calan / (iphigh - medH); + if (realL > 0.f && realL <= iphigh) { + calH = realL * chromat / iphigh; } else if (realL > iphigh) { - calH = realL * calan; //*(iphigh-1.f) - calan*(iphigh-1.f);//it is better without transition in highlight + calH = realL * chromat; //*(iphigh-1.f) - chromat*(iphigh-1.f);//it is better without transition in highlight } } - float aaH, bbH; - - if(algm <= 1) { - if(twoc == 0 && metchrom == 3) { // 2 colours only with special "ab" - if(algm == 1) { - aaH = a_1 + (a_2 - a_1) * calH; - bbH = b_1 + (b_2 - b_1) * calH; //pass to line after + if (algm <= 1) { + if (twoc == 0 && metchrom == 3) { // 2 colours only with special "ab" + if (algm == 1) { + const float aaH = a_1 + (a_2 - a_1) * calH; + const float bbH = b_1 + (b_2 - b_1) * calH; //pass to line after a_1 = aaH + (a_L - aaH) * cal * balance; b_1 = bbH + (b_L - bbH) * cal * balance; } - } else if(twoc == 1) { - if(metchrom == 0) { + } else if (twoc == 1) { + if (metchrom == 0) { a_1 = a_1 + (a_2 - a_1) * balance; b_1 = b_1 + (b_2 - b_1) * balance; - } else if(metchrom == 1) { - a_1 = a_1 + (a_2 - a_1) * calan * balance; - b_1 = b_1 + (b_2 - b_1) * calan * balance; - } else if(metchrom == 2) { - a_1 = a_1 + (a_2 - a_1) * calan * balance; - b_1 = b_1 + (b_2 - b_1) * calby * balance; + } else if (metchrom == 1) { + a_1 = a_1 + (a_2 - a_1) * chromat * balance; + b_1 = b_1 + (b_2 - b_1) * chromat * balance; + } else if (metchrom == 2) { + a_1 = a_1 + (a_2 - a_1) * chromat * balance; + b_1 = b_1 + (b_2 - b_1) * luma * balance; } } } + float X, Y, Z; Color::Lab2XYZ(L1, a_1, b_1, X, Y, Z); - Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz);// ro go bo in gamut } -void Color::calcGamma (double pwr, double ts, int mode, GammaValues &gamma) +void Color::calcGamma (double pwr, double ts, GammaValues &gamma) { //from Dcraw (D.Coffin) - int i; - double g[6], bnd[2] = {0., 0.}; + double g[6], bnd[2] = {}; g[0] = pwr; g[1] = ts; @@ -1603,7 +1523,7 @@ void Color::calcGamma (double pwr, double ts, int mode, GammaValues &gamma) bnd[g[1] >= 1.] = 1.; if (g[1] && (g[1] - 1.) * (g[0] - 1.) <= 0.) { - for (i = 0; i < 99; i++) { + for (int i = 0; i < 99; i++) { g[2] = (bnd[0] + bnd[1]) / 2.; if (g[0]) { @@ -1626,16 +1546,16 @@ void Color::calcGamma (double pwr, double ts, int mode, GammaValues &gamma) g[5] = 1. / (g[1] * SQR(g[3]) / 2. + 1. - g[2] - g[3] - g[2] * g[3] * (log(g[3]) - 1.)) - 1.; } - if (!mode--) { - gamma[0] = g[0]; - gamma[1] = g[1]; - gamma[2] = g[2]; - gamma[3] = g[3]; - gamma[4] = g[4]; - gamma[5] = g[5]; - gamma[6] = 0.; - return; - } + gamma[0] = g[0]; + gamma[1] = g[1]; + gamma[2] = g[2]; + gamma[3] = g[3]; + gamma[4] = g[4]; + gamma[5] = g[5]; + gamma[6] = 0.; + // if (rtengine::settings->verbose) { + // printf("g0=%f g1=%f g2=%f g3=%f g4=%f g5=%f\n", g[0], g[1], g[2], g[3], g[4], g[5]); + // } } void Color::gammaf2lut (LUTf &gammacurve, float gamma, float start, float slope, float divisor, float factor) { @@ -1712,19 +1632,6 @@ void Color::gammanf2lut (LUTf &gammacurve, float gamma, float divisor, float fac #endif } -void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z) -{ - float LL = L / 327.68f; - float aa = a / 327.68f; - float bb = b / 327.68f; - float fy = (c1By116 * LL) + c16By116; // (L+16)/116 - float fx = (0.002f * aa) + fy; - float fz = fy - (0.005f * bb); - x = 65535.0f * f2xyz(fx) * D50x; - z = 65535.0f * f2xyz(fz) * D50z; - y = (LL > epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / kappa; -} - float Color::L2Y(float L) { const float LL = L / 327.68f; @@ -1742,27 +1649,6 @@ void Color::L2XYZ(float L, float &x, float &y, float &z) // for black & white y = (LL > epskap) ? 65535.0f * fy * fy * fy : 65535.0f * LL / kappa; } - -#ifdef __SSE2__ -void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z) -{ - vfloat c327d68 = F2V(327.68f); - L /= c327d68; - a /= c327d68; - b /= c327d68; - vfloat fy = F2V(c1By116) * L + F2V(c16By116); - vfloat fx = F2V(0.002f) * a + fy; - vfloat fz = fy - (F2V(0.005f) * b); - vfloat c65535 = F2V(65535.f); - x = c65535 * f2xyz(fx) * F2V(D50x); - z = c65535 * f2xyz(fz) * F2V(D50z); - vfloat res1 = fy * fy * fy; - vfloat res2 = L / F2V(kappa); - y = vself(vmaskf_gt(L, F2V(epskap)), res1, res2); - y *= c65535; -} -#endif // __SSE2__ - inline float Color::computeXYZ2Lab(float f) { if (f < 0.f) { @@ -1838,7 +1724,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, } } -void Color::RGB2L(float *R, float *G, float *B, float *L, const float wp[3][3], int width) +void Color::RGB2L(const float *R, const float *G, const float *B, float *L, const float wp[3][3], int width) { #ifdef __SSE2__ @@ -2044,7 +1930,7 @@ void Color::Lch2Luv(float c, float h, float &u, float &v) * columns of the matrix p=xyz_rgb are RGB tristimulus primaries in XYZ * c is the color fixed on the boundary; and m=0 for c=0, m=1 for c=255 */ -void Color::gamutmap(float &X, float &Y, float &Z, const double p[3][3]) +void Color::gamutmap(float &X, float Y, float &Z, const double p[3][3]) { float u = 4 * X / (X + 15 * Y + 3 * Z) - u0; float v = 9 * Y / (X + 15 * Y + 3 * Z) - v0; @@ -2081,96 +1967,33 @@ void Color::gamutmap(float &X, float &Y, float &Z, const double p[3][3]) Z = (12 - 3 * u - 20 * v) * Y / (4 * v); } -void Color::skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s) -{ - float factorskin, factorsat, factor, factorskinext, interm; - float scale = 100.0f / 100.1f; //reduction in normal zone - float scaleext = 1.0f; //reduction in transition zone - float deltaHH = 0.3f; //HH value transition : I have choice 0.3 radians - float HH; - bool doskin = false; - - //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear - if ((float)h > 8.6f && (float)h <= 74.f ) { - HH = (1.15f / 65.4f) * (float)h - 0.0012f; //H > 0.15 H<1.3 - doskin = true; - } else if((float)h > 0.f && (float)h <= 8.6f ) { - HH = (0.19f / 8.6f ) * (float)h - 0.04f; //H>-0.04 H < 0.15 - doskin = true; - } else if((float)h > 355.f && (float)h <= 360.f) { - HH = (0.11f / 5.0f ) * (float)h - 7.96f; //H>-0.15 <-0.04 - doskin = true; - } else if((float)h > 74.f && (float)h < 95.f ) { - HH = (0.30f / 21.0f) * (float)h + 0.24285f; //H>1.3 H<1.6 - doskin = true; - } - - if(doskin) { - float chromapro = sres / Sp; - - if(sk == 1) { //in C mode to adapt dred to J - if (J < 16.0) { - dred = 40.0f; - } else if(J < 22.0) { - dred = 2.5f * (float)J; - } else if(J < 60.0) { - dred = 55.0f; - } else if(J < 70.0) { - dred = -1.5f * (float)J + 145.0f; - } else { - dred = 40.0f; - } - } - - if(chromapro > 0.0) { - Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext); //Scale factor - } - - if(chromapro > 1.0) { - interm = (chromapro - 1.0f) * 100.0f; - factorskin = 1.0f + (interm * scale) / 100.0f; - factorskinext = 1.0f + (interm * scaleext) / 100.0f; - } else { - factorskin = chromapro ; - factorskinext = chromapro ; - } - - factorsat = chromapro; - factor = factorsat; - Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition - s *= factor; - } else { - s = ko * sres; - } - -} void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s) { float HH; bool doskin = false; //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear - if ((float)h > 8.6f && (float)h <= 74.f ) { - HH = (1.15f / 65.4f) * (float)h - 0.0012f; //H > 0.15 H<1.3 + if (h > 8.6f && h <= 74.f) { + HH = (1.15f / 65.4f) * h - 0.0012f; //H > 0.15 H<1.3 doskin = true; - } else if((float)h > 0.f && (float)h <= 8.6f ) { - HH = (0.19f / 8.6f ) * (float)h - 0.04f; //H>-0.04 H < 0.15 + } else if(h > 0.f && h <= 8.6f) { + HH = (0.19f / 8.6f) * h - 0.04f; //H>-0.04 H < 0.15 doskin = true; - } else if((float)h > 355.f && (float)h <= 360.f) { - HH = (0.11f / 5.0f ) * (float)h - 7.96f; //H>-0.15 <-0.04 + } else if(h > 355.f && h <= 360.f) { + HH = (0.11f / 5.0f) * h - 7.96f; //H>-0.15 <-0.04 doskin = true; - } else if((float)h > 74.f && (float)h < 95.f ) { - HH = (0.30f / 21.0f) * (float)h + 0.24285f; //H>1.3 H<1.6 + } else if(h > 74.f && h < 95.f ) { + HH = (0.30f / 21.0f) * h + 0.24285f; //H>1.3 H<1.6 doskin = true; } if(doskin) { - float factorskin, factorsat, factor, factorskinext; + float factorskin, factor, factorskinext; float deltaHH = 0.3f; //HH value transition : I have choice 0.3 radians float chromapro = sres / Sp; if(sk == 1) { //in C mode to adapt dred to J - if (J < 16.f) { + if (J < 16.f) { dred = 40.f; } else if(J < 22.f) { dred = 2.5f * J; @@ -2187,7 +2010,7 @@ void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, f float scale = 0.999000999f; // 100.0f/100.1f; reduction in normal zone float scaleext = 1.0f; //reduction in transition zone Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext);//Scale factor - float interm = (chromapro - 1.0f); + const float interm = chromapro - 1.0f; factorskin = 1.0f + (interm * scale); factorskinext = 1.0f + (interm * scaleext); } else { @@ -2195,21 +2018,14 @@ void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, f factorskinext = chromapro ; } - factorsat = chromapro; - factor = factorsat; - Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition + factor = chromapro; + Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, chromapro, factor); //transition s *= factor; } else { s = ko * sres; } - } - - - - - void Color::scalered ( const float rstprotection, const float param, const float limit, const float HH, const float deltaHH, float &scale, float &scaleext) { if(rstprotection < 99.9999f) { @@ -2264,55 +2080,24 @@ 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; - float correctionHue = 0.0, correctionHueLum = 0.0; - bool correctL; + if (CC >= 6.f && CC < 140.f) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) + constexpr float huelimit[8] = { -2.48f, -0.55f, 0.44f, 1.52f, 1.87f, 3.09f, -0.27f, 0.44f}; //limits hue of blue-purple, red-yellow, green-yellow, red-purple - if(CC >= 6.0 && CC < 140) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) - static const float huelimit[8] = { -2.48, -0.55, 0.44, 1.52, 1.87, 3.09, -0.27, 0.44}; //limits hue of blue-purple, red-yellow, green-yellow, red-purple + Chprov1 = rtengine::LIM(Chprov1, 6.f, 140.f); - if (Chprov1 > 140.f) { - Chprov1 = 139.f; //limits of LUTf - } - - if (Chprov1 < 6.f) { - Chprov1 = 6.f; - } - - for(int zo = 1; zo <= 4; zo++) { - if(HH > huelimit[2 * zo - 2] && HH < huelimit[2 * zo - 1]) { - //zone=zo; - contin1 = contin2 = false; - correctL = false; + for (int zo = 1; zo <= 4; ++zo) { + if (HH > huelimit[2 * zo - 2] && HH < huelimit[2 * zo - 1]) { + bool correctL = false; + float correctionHue = 0.f, correctionHueLum = 0.f; 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) { + bool contin1 = false; float correctlumprov = 0.f; - float correctlumprov2 = 0.f; if(correctL) { //for Munsell luminance correction @@ -2321,64 +2106,22 @@ void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, fl correctL = false; } - correctionHueLum = 0.0; - correctionHue = 0.0; - - if(fabs(Lprov1 - Loldd) > 6.0) { + if (std::fabs(Lprov1 - Loldd) > 6.f) { + correctionHueLum = 0.f; + correctionHue = 0.f; // correction if delta L significative..Munsell luminance MunsellLch (Loldd, HH, Chprov1, Chprov1, correctionHue, zo, correctionHueLum, correctL); - if(correctL) { - correctlumprov2 = correctionHueLum; - contin2 = true; - correctL = false; - } - - correctionHueLum = 0.0; - - 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(contin1) { + correctlum = correctionHueLum - correctlumprov; } } - - if(absCorrectLum > 0.35) - #pragma omp atomic - munsDbgInfo->depassLum++; //verify if no bug in calculation - -#endif } } + break; } } - } - -#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 - } /* @@ -2397,9 +2140,6 @@ void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, fl void Color::AllMunsellLch(float Lprov1, float HH, float Chprov1, float CC, float &correctionHuechroma) { - float correctionHue = 0.f, correctionHueLum = 0.f; - bool correctL; - if(CC >= 6.f && CC < 140.f) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) static const float huelimit[8] = { -2.48f, -0.55f, 0.44f, 1.52f, 1.87f, 3.09f, -0.27f, 0.44f}; //limits hue of blue-purple, red-yellow, green-yellow, red-purple @@ -2412,7 +2152,8 @@ void Color::AllMunsellLch(float Lprov1, float HH, float Chprov1, float CC, float for(int zo = 1; zo <= 4; zo++) { if(HH > huelimit[2 * zo - 2] && HH < huelimit[2 * zo - 1]) { //zone=zo; - correctL = false; + float correctionHue = 0.f, correctionHueLum = 0.f; + bool correctL = false; MunsellLch (Lprov1, HH, Chprov1, CC, correctionHue, zo, correctionHueLum, correctL); //munsell chroma correction correctionHuechroma = correctionHue; //preserve break; @@ -2437,17 +2178,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 +2205,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 +2250,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 +2284,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 +2309,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 +2361,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 +2482,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 +2509,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 +2523,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,19 +2562,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__ // precalculate H and C using SSE float HHBuffer[N]; @@ -2914,9 +2598,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,36 +2610,15 @@ 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; - correctionHuechroma = 0.f; - correctlum = 0.f; + float correctionHuechroma = 0.f; + float 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 +2639,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 +2743,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 +5343,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..b6bf60818 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; @@ -584,9 +570,20 @@ public: */ static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const double rgb_xyz[3][3]); static void xyz2r (float x, float y, float z, float &r, const double rgb_xyz[3][3]); - static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]); + static inline void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]) + { + r = ((rgb_xyz[0][0] * x + rgb_xyz[0][1] * y + rgb_xyz[0][2] * z)) ; + g = ((rgb_xyz[1][0] * x + rgb_xyz[1][1] * y + rgb_xyz[1][2] * z)) ; + b = ((rgb_xyz[2][0] * x + rgb_xyz[2][1] * y + rgb_xyz[2][2] * z)) ; + } + #ifdef __SSE2__ - static void xyz2rgb (vfloat x, vfloat y, vfloat z, vfloat &r, vfloat &g, vfloat &b, const vfloat rgb_xyz[3][3]); + static inline void xyz2rgb (vfloat x, vfloat y, vfloat z, vfloat &r, vfloat &g, vfloat &b, const vfloat rgb_xyz[3][3]) + { + r = ((rgb_xyz[0][0] * x + rgb_xyz[0][1] * y + rgb_xyz[0][2] * z)) ; + g = ((rgb_xyz[1][0] * x + rgb_xyz[1][1] * y + rgb_xyz[1][2] * z)) ; + b = ((rgb_xyz[2][0] * x + rgb_xyz[2][1] * y + rgb_xyz[2][2] * z)) ; + } #endif @@ -617,12 +614,40 @@ public: * @param y Y coordinate [0 ; 65535] ; can be negative! (return value) * @param z Z coordinate [0 ; 65535] ; can be negative! (return value) */ - static void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z); + static inline void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z) + { + float LL = L / 327.68f; + float aa = a / 327.68f; + float bb = b / 327.68f; + float fy = (c1By116 * LL) + c16By116; // (L+16)/116 + float fx = (0.002f * aa) + fy; + float fz = fy - (0.005f * bb); + x = 65535.f * f2xyz(fx) * D50x; + z = 65535.f * f2xyz(fz) * D50z; + y = (LL > epskapf) ? 65535.f * fy * fy * fy : 65535.f * LL / kappaf; + } + static void L2XYZ(float L, float &x, float &y, float &z); static float L2Y(float L); #ifdef __SSE2__ - static void Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z); +static inline void Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z) +{ + vfloat c327d68 = F2V(327.68f); + L /= c327d68; + a /= c327d68; + b /= c327d68; + vfloat fy = F2V(c1By116) * L + F2V(c16By116); + vfloat fx = F2V(0.002f) * a + fy; + vfloat fz = fy - (F2V(0.005f) * b); + vfloat c65535 = F2V(65535.f); + x = c65535 * f2xyz(fx) * F2V(D50x); + z = c65535 * f2xyz(fz) * F2V(D50z); + vfloat res1 = fy * fy * fy; + vfloat res2 = L / F2V(kappa); + y = vself(vmaskf_gt(L, F2V(epskap)), res1, res2); + y *= c65535; +} #endif // __SSE2__ /** @@ -637,7 +662,7 @@ public: static void XYZ2Lab(float x, float y, float z, float &L, float &a, float &b); static void RGB2Lab(float *X, float *Y, float *Z, float *L, float *a, float *b, const float wp[3][3], int width); static void Lab2RGBLimit(float *L, float *a, float *b, float *R, float *G, float *B, const float wp[3][3], float limit, float afactor, float bfactor, int width); - static void RGB2L(float *X, float *Y, float *Z, float *L, const float wp[3][3], int width); + static void RGB2L(const float *R, const float *G, const float *B, float *L, const float wp[3][3], int width); /** * @brief Convert Lab in Yuv @@ -1020,8 +1045,6 @@ public: * @brief Get the gamma curves' parameters used by LCMS2 * @param pwr gamma value [>1] * @param ts slope [0 ; 20] - * @param mode [always 0] - * @imax imax [always 0] * @param gamma a pointer to an array of 6 double gamma values: * gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) * gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) @@ -1030,7 +1053,7 @@ public: * gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) * gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) */ - static void calcGamma (double pwr, double ts, int mode, GammaValues &gamma); + static void calcGamma (double pwr, double ts, GammaValues &gamma); /** @@ -1150,23 +1173,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 +1415,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 +1440,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); @@ -1490,9 +1505,58 @@ public: static void scalered ( float rstprotection, float param, float limit, float HH, float deltaHH, float &scale, float &scaleext); static void transitred (float HH, float Chprov1, float dred, float factorskin, float protect_red, float factorskinext, float deltaHH, float factorsat, float &factor); - static void skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s); 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) { @@ -1772,11 +1836,11 @@ public: /** * @brief Gamut correction in the XYZ color space * @param X X channel input value and corrected output value [0 ; 65535] - * @param Y Y channel input value and corrected output value [0 ; 65535] + * @param Y Y channel input value[0 ; 65535] * @param Z Z channel input value and corrected output value [0 ; 65535] * @param p working profile */ - static void gamutmap(float &X, float &Y, float &Z, const double p[3][3]); + static void gamutmap(float &X, float Y, float &Z, const double p[3][3]); /** @@ -1810,7 +1874,6 @@ public: } else if (HH >= -0.1f && HH < 0.f ) { hr = 0.1 * double(HH) + 0.93; //hr 0.92 0.93 red } - // in case of ! if (hr < 0.0) { hr += 1.0; 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 ebb23e754..640074075 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -37,9 +37,35 @@ using namespace std; +namespace { +void fillCurveArray(const rtengine::DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool needed) +{ + if (needed) { + for (int i = 0; i <= 0xffff; i += i < 0xffff - skip ? skip : 1) { + // change to [0,1] range + // apply custom/parametric/NURBS curve, if any + outCurve[i] = diagCurve->getVal(i / 65535.f); + } + + // if skip > 1, let apply linear interpolation in the skipped points of the curve + if (skip > 1) { + const float skipmul = 1.f / 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; + } + } + } + + outCurve *= 65535.f; + } else { + outCurve.makeIdentity(); + } +} +} namespace rtengine { - bool sanitizeCurve(std::vector& curve) { // A curve is valid under one of the following conditions: @@ -47,19 +73,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 +99,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 +120,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 +129,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 +150,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 +163,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 +200,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; } @@ -200,37 +227,7 @@ void Curve::getControlPoint(int cpNum, double &x, double &y) const const double CurveFactory::sRGBGamma = 2.2; const double CurveFactory::sRGBGammaCurve = 2.4; -void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool needed) -{ - if (needed) { - - 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); - // store result in a temporary array - outCurve[i] = val; - } - - // if skip>1, let apply linear interpolation in the skipped points of the curve - if (skip > 1) { - 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; - } - } - } - - outCurve *= 65535.f; - } else { - outCurve.makeIdentity(); - } -} - -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 +286,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 +316,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; } @@ -335,32 +332,15 @@ 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) -{ - clcutili = false; - std::unique_ptr dCurve; - - if (!clcurvePoints.empty() && clcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(clcurvePoints, CURVES_MIN_POLY_POINTS / skip)); - - if (dCurve && !dCurve->isIdentity()) { - clcutili = true; - } - } - - fillCurveArray(dCurve.get(), clCurve, skip, clcutili); -} - -void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) +bool CurveFactory::diagonalCurve2Lut(const std::vector& curvePoints, LUTf & curve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; std::unique_ptr dCurve; outBeforeCurveHistogram.clear(); bool histNeeded = false; - if (!mapcurvePoints.empty() && mapcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(mapcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve.reset(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCurveHistogram) { histNeeded = true; @@ -368,7 +348,6 @@ void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& m if (dCurve && !dCurve->isIdentity()) { needed = true; - mapcontlutili = true; } } @@ -376,77 +355,32 @@ void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& m histogram.compressTo(outBeforeCurveHistogram, 32768); } - fillCurveArray(dCurve.get(), mapcurve, skip, needed); + fillCurveArray(dCurve.get(), curve, skip, needed); + return needed; } -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; - outBeforeCurveHistogram.clear(); - bool histNeeded = false; - - if (!dehaclcurvePoints.empty() && dehaclcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); - - if (outBeforeCurveHistogram) { - histNeeded = true; - } - - if (dCurve && !dCurve->isIdentity()) { - needed = true; - dehacontlutili = true; - } - } - - if (histNeeded) { - histogram.compressTo(outBeforeCurveHistogram, 32768); - } - - fillCurveArray(dCurve.get(), dehaclCurve, skip, needed); -} - -// add curve Lab wavelet : Cont=f(L) -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)); - - if (dCurve && !dCurve->isIdentity()) { - needed = true; - wavcontlutili = true; - } - } - - fillCurveArray(dCurve.get(), wavclCurve, skip, needed); -} - -// add curve Colortoning : C=f(L) and CLf(L) -void CurveFactory::curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip) +bool CurveFactory::diagonalCurve2Lut(const std::vector& curvePoints, LUTf& curve, 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.reset(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { needed = true; } } - fillCurveArray(dCurve.get(), ToningCurve, skip, needed); + fillCurveArray(dCurve.get(), curve, skip, needed); + return needed; + } - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -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 +388,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.reset(new DiagonalCurve(acurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { autili = true; @@ -463,12 +397,12 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil fillCurveArray(dCurve.get(), aoutCurve, skip, autili); - dCurve = nullptr; + dCurve.reset(); //----------------------------------------------------- if (!bcurvePoints.empty() && bcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(bcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve.reset(new DiagonalCurve(bcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { butili = true; @@ -477,12 +411,12 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil fillCurveArray(dCurve.get(), boutCurve, skip, butili); - dCurve = nullptr; + dCurve.reset(); //----------------------------------------------- if (!cccurvePoints.empty() && cccurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(cccurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve.reset(new DiagonalCurve(cccurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { ccutili = true; @@ -491,12 +425,12 @@ void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutil fillCurveArray(dCurve.get(), satCurve, skip, ccutili); - dCurve = nullptr; + dCurve.reset(); //---------------------------- if (!lccurvePoints.empty() && lccurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(lccurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve.reset(new DiagonalCurve(lccurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { cclutili = true; @@ -522,20 +456,19 @@ 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(); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% std::unique_ptr brightcurve; @@ -548,14 +481,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 +498,10 @@ 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.reset(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 +517,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 +546,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; } @@ -627,9 +558,8 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou // curve without contrast LUTf dcurve(0x10000); - //%%%%%%%%%%%%%%%%%%%%%%%%%% // 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 { @@ -667,11 +597,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou dcurve[i] = val; } - brightcurve = nullptr; - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + brightcurve.reset(); // check if contrast curve is needed if (contr > 0.00001 || contr < -0.00001) { @@ -688,7 +614,6 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou avg /= sum; - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% std::vector contrastcurvePoints(9); contrastcurvePoints[0] = DCT_NURBS; @@ -706,15 +631,12 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou const DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // apply contrast enhancement for (int i = 0; i <= 0xffff; i++) { - dcurve[i] = contrastcurve.getVal (dcurve[i]); + dcurve[i] = contrastcurve.getVal(dcurve[i]); } } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // create second curve if needed bool histNeeded = false; customToneCurve2.Reset(); @@ -726,15 +648,11 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou customToneCurve2.Set(tcurve, gamma_); } - if (outBeforeCCurveHistogram ) { + if (outBeforeCCurveHistogram) { histNeeded = true; } } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // create first curve if needed customToneCurve1.Reset(); @@ -750,8 +668,6 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou } } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - #ifdef __SSE2__ vfloat gamma_v = F2V(gamma_); vfloat startv = F2V(start); @@ -762,7 +678,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 +686,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,55 +704,116 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou } -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, - const LUTu & histogram, LUTf & outCurve, - LUTu & outBeforeCCurveHistogram, int skip, bool & utili) +void CurveFactory::Curvelocalhl(double ecomp, double hlcompr, double hlcomprthresh, LUTf & hlCurve) { - utili = false; - // clear array that stores histogram valid before applying the custom curve - if (outBeforeCCurveHistogram) { - outBeforeCCurveHistogram.clear(); - } + // a: slope of the curve + 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 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 // check if brightness curve is needed if (br > 0.00001 || br < -0.00001) { - utili = true; - + // 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(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.2; // toe point + brightcurvePoints.at(4) = 0.2 + br / 250.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.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(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); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Applying brightness curve for (int i = 0; i < 32768; i++) { // L values range up to 32767, higher values are for highlight overflow @@ -845,7 +822,211 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector 0.00001 || cont < -0.00001) { + + + int k = avg * 32768; + avg = lightCurveloc[k]; + 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 - 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 + + 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 = 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++) { + if (black != 0.0) { + const float bval = i / 65535.f; + shCurve[i] = simplebasecurve(bval, black, 0.015 * shcompr) / bval; + } + + // gamma correction + dcurve[i] = Color::gammatab_bt709[i] / maxran; + } + +#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++) { + outCurve[i] = (maxran - 1.f) * igamma(dcurve[i], gamma_, start, slope, mul, add); + } +#endif +} + +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(); + } + + // 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(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 outCurve[i] = LIM01(val); @@ -855,10 +1036,6 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector 0.00001 || contr < -0.00001) { utili = true; @@ -874,69 +1051,57 @@ 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 } DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); // apply contrast enhancement for (int i = 0; i < 32768; i++) { - outCurve[i] = contrastcurve.getVal (outCurve[i]); + outCurve[i] = contrastcurve.getVal(outCurve[i]); } } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // create a curve if needed std::unique_ptr tcurve; bool histNeeded = false; if (!curvePoints.empty() && curvePoints[0] != 0) { - tcurve = std::unique_ptr(new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip)); + tcurve.reset(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCCurveHistogram) { histNeeded = true; } } - if (tcurve && tcurve->isIdentity()) { - tcurve = nullptr; - } - - if (tcurve) { + if (tcurve && !tcurve->isIdentity()) { utili = true; //if active // L values go up to 32767, last stop is for highlight overflow @@ -950,15 +1115,15 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (outCurve[i]); + val = tcurve->getVal(outCurve[i]); - outCurve[i] = (32767.f * val); + outCurve[i] = 32767.f * 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 - if(histNeeded) { + if (histNeeded) { histogram.compressTo(outBeforeCCurveHistogram, 32768, outCurve); } @@ -967,30 +1132,22 @@ 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.reset(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); } - if (tcurve && tcurve->isIdentity()) { - tcurve = nullptr; - } - - if (tcurve) { + if (tcurve && !tcurve->isIdentity()) { if (!outCurve) { outCurve(65536, 0); } @@ -1007,6 +1164,1328 @@ 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"); +} + + + +bool LocHHmaskCurve::Set(const std::vector &curvePoints) +{ + // 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); + return true; + } else { + Reset(); + return false; + } +} + + + + +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"); +} + + + +bool LocCCmaskCurve::Set(const std::vector &curvePoints) +{ + // 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); + return true; + } else { + Reset(); + return false; + } +} + +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"); +} + + + +bool LocLLmaskCurve::Set(const std::vector &curvePoints) +{ + // 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); + return true; + } else { + Reset(); + return false; + } +} + + + + +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"); +} + + + +bool LocHHCurve::Set(const std::vector &curvePoints) +{ + // 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); + return true; + } else { + Reset(); + return false; + } +} + + +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"); +} + + + + +bool LocLHCurve::Set(const std::vector &curvePoints) +{ + + 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); + return true; + } else { + Reset(); + return false; + } +} + +LocCHCurve::LocCHCurve() : sum(0.f) {}; + +void LocCHCurve::Reset() +{ + lutLocCHCurve.reset(); + sum = 0.f; +} +void LocCHCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutLocCHCurve(501); // raise this value if the quality suffers from this number of samples + sum = 0.f; + + for (int i = 0; i < 501; i++) { + lutLocCHCurve[i] = pCurve.getVal(double (i) / 500.); + + if (lutLocCHCurve[i] < 0.02f) { + lutLocCHCurve[i] = 0.02f; //avoid 0.f for wavelet : under 0.01f quasi no action for each value + } + + sum += lutLocCHCurve[i]; + } + + //lutLocHHCurve.dump("wav"); +} + + + +bool LocCHCurve::Set(const std::vector &curvePoints) +{ + // 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); + return true; + } else { + Reset(); + return false; + } +} + + + + + +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"); +} +bool LocwavCurve::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); + return true; + } else { + Reset(); + return false; + } +} + +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() { @@ -1019,7 +2498,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 +2517,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 +2550,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 +2580,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 +2592,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 +2620,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,18 +2634,13 @@ 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.reset(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); tcurve->setIdentityValue(0.); - } - - if (tcurve) { Set(tcurve.get()); opautili = true; - tcurve = nullptr; } } - WavCurve::WavCurve() : sum(0.f) {} void WavCurve::Reset() @@ -1182,13 +2656,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 +2733,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.); } } @@ -1329,10 +2803,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.); } } @@ -1361,10 +2835,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.); } } @@ -1393,10 +2867,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.); } } @@ -1427,13 +2901,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 } @@ -1507,7 +2981,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; @@ -1523,13 +2997,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; @@ -1539,8 +3013,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); @@ -1548,34 +3022,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 @@ -1585,7 +3052,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; @@ -1593,14 +3060,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) @@ -1608,10 +3067,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)); - } - - if (tcurve) { + tcurve.reset(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); SetXYZ(tcurve.get(), xyz_rgb, satur, lumin); } } @@ -1644,7 +3100,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; @@ -1658,12 +3114,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; @@ -1677,29 +3133,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) @@ -1707,10 +3155,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)); - } - - if (tcurve) { + tcurve.reset(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); SetRGB(tcurve.get()); } } @@ -1753,18 +3198,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]; } @@ -1884,7 +3329,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; @@ -1941,7 +3386,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]); @@ -1964,17 +3409,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; } @@ -1997,11 +3460,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)) { @@ -2014,9 +3477,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; } @@ -2108,10 +3580,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. @@ -2124,9 +3596,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; } @@ -2187,9 +3667,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]; @@ -2212,7 +3701,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 @@ -2280,7 +3769,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 0fb58cc9e..8800e54db 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,36 @@ 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 bool diagonalCurve2Lut(const std::vector& curvePoints, LUTf& curve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); + static bool diagonalCurve2Lut(const std::vector& curvePoints, LUTf& curve, 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 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 +390,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 +428,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 +453,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 +470,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; + explicit 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 +496,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; + explicit 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 +589,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 +607,824 @@ public: } }; +class LocLHCurve +{ +private: + LUTf lutLocLHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocLHCurve() {}; + LocLHCurve(); + void Reset(); + bool Set(const std::vector &curvePoints); + 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(); + bool Set(const std::vector &curvePoints); + 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(); + bool Set(const std::vector &curvePoints); + 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(); + bool Set(const std::vector &curvePoints); + 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(); + bool Set(const std::vector &curvePoints); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocHHCurve[index]; + } + operator bool (void) const + { + return lutLocHHCurve; + } +}; + + +class LocCHCurve +{ +private: + LUTf lutLocCHCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~LocCHCurve() {}; + LocCHCurve(); + void Reset(); + bool Set(const std::vector &curvePoints); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutLocCHCurve[index]; + } + operator bool (void) const + { + return lutLocCHCurve; + } +}; + +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(); + bool Set(const std::vector &curvePoints); + 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: @@ -850,10 +1676,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); } @@ -865,10 +1691,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); } @@ -880,10 +1706,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); } @@ -894,10 +1720,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); } @@ -909,10 +1735,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); } @@ -927,8 +1753,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 @@ -997,27 +1823,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. @@ -1029,11 +1858,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]); @@ -1048,39 +1879,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 } } @@ -1172,19 +2004,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); } @@ -1210,21 +2043,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); @@ -1242,23 +2075,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. @@ -1270,6 +2105,7 @@ inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t en break; #endif } + Apply(r[i], g[i], b[i]); i++; } @@ -1311,6 +2147,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..fd9f9211b 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -273,11 +273,7 @@ void CLASS derror() if (feof(ifp)) fprintf (stderr,_("Unexpected end of file\n")); else -#ifdef WIN32 - fprintf (stderr,_("Corrupt data near 0x%I64x\n"), (INT64) ftello(ifp)); -#else fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); -#endif } data_error++; /*RT Issue 2467 longjmp (failure, 1);*/ @@ -1403,7 +1399,7 @@ void CLASS nikon_load_raw() void CLASS nikon_yuv_load_raw() { - int row, col, yuv[4], rgb[3], b, c; + int row, col, yuv[4] = {}, rgb[3], b, c; UINT64 bitbuf=0; for (row=0; row < raw_height; row++) @@ -2050,9 +2046,8 @@ void CLASS phase_one_load_raw_c() } else if ((col & 7) == 0) { for (int i = 0; i < 2; i++) { int j; - for (j = 0; j < 5 && !ph1_bits(1); j++) - ; - if (j--) { + for (j = 0; j < 5 && !ph1_bits(1); j++) ; + if (j--) { len[i] = length[j * 2 + ph1_bits(1)]; } } @@ -4090,7 +4085,7 @@ void CLASS foveon_interpolate() FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); #undef LAST FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; - sprintf (str, "%sRGBNeutral", model2); + snprintf(str, sizeof(str), "%sRGBNeutral", model2); if (foveon_camf_param ("IncludeBlocks", str)) foveon_fixed (div, 3, str); num = 0; @@ -5625,7 +5620,7 @@ nf: order = 0x4949; if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); if ((tag == 0x25 || tag == 0x28) && strstr(make,"NIKON") && !iso_speed) { // Nikon ISOInfo Tags/ISO & ISO2 - uchar iso[1]; + uchar iso[1] = {}; fread (iso, 1, 1, ifp); iso_speed = 100 * pow(2,(float)iso[0]/12.0-5); } @@ -6207,8 +6202,8 @@ void CLASS parse_exif (int base) case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128) - tiff_ifd[tiff_nifds-1].shutter = - shutter = pow (2, expo); break; + tiff_ifd[tiff_nifds-1].shutter = shutter = pow (2, expo); + break; case 37378: aperture = pow (2, getreal(type)/2); break; case 37386: focal_len = getreal(type); break; case 37500: parse_makernote (base, 0); break; @@ -6728,7 +6723,7 @@ int CLASS parse_tiff_ifd (int base) raw_height = height; left_margin = top_margin = filters = flip = 0; } - sprintf (model, "Ixpress %d-Mp", height*width/1000000); + snprintf(model, sizeof(model), "Ixpress %d-Mp", height*width/1000000); load_raw = &CLASS imacon_full_load_raw; if (filters) { if (left_margin & 1) filters = 0x61616161; @@ -7093,7 +7088,8 @@ void CLASS apply_tiff() load_flags = 24; if (!strcmp(make,"SONY") && tiff_bps < 14 && tiff_ifd[raw].bytes == raw_width*raw_height*2) - tiff_bps = 14; if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { + tiff_bps = 14; + if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { load_flags = 81; tiff_bps = 12; } slr: @@ -7166,7 +7162,8 @@ void CLASS apply_tiff() // load_raw = &CLASS packed_load_raw; load_raw = &CLASS nikon_14bit_load_raw; } else - load_raw = &CLASS nikon_load_raw; break; + load_raw = &CLASS nikon_load_raw; + break; case 65535: load_raw = &CLASS pentax_load_raw; break; case 65000: @@ -7720,7 +7717,7 @@ void CLASS parse_smal (int offset, int fsize) raw_height = height = get2(); raw_width = width = get2(); strcpy (make, "SMaL"); - sprintf (model, "v%d %dx%d", ver, width, height); + snprintf(model, sizeof(model), "v%d %dx%d", ver, width, height); if (ver == 6) load_raw = &CLASS smal_v6_load_raw; if (ver == 9) load_raw = &CLASS smal_v9_load_raw; } @@ -7748,7 +7745,7 @@ void CLASS parse_cine() } fseek (ifp, off_setup+792, SEEK_SET); strcpy (make, "CINE"); - sprintf (model, "%d", get4()); + snprintf(model, sizeof(model), "%d", get4()); fseek (ifp, 12, SEEK_CUR); switch ((i=get4()) & 0xffffff) { case 3: filters = 0x94949494; break; @@ -9061,7 +9058,7 @@ void CLASS adobe_coeff (const char *make, const char *model) char name[130]; int i, j; - sprintf (name, "%s %s", make, model); + snprintf(name, sizeof(name), "%s %s", make, model); // -- RT -------------------------------------------------------------------- @@ -10048,7 +10045,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; } @@ -10525,7 +10522,7 @@ bw: colors = 1; load_raw = &CLASS rollei_load_raw; } if (!model[0]) - sprintf (model, "%dx%d", width, height); + snprintf(model, sizeof(model), "%dx%d", width, height); if (filters == UINT_MAX) filters = 0x94949494; if (thumb_offset && !thumb_height) { fseek (ifp, thumb_offset, SEEK_SET); diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 38f3a9e44..99be415d8 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), spotCrop(nullptr), laboCrop(nullptr), - labnCrop(nullptr), cropImg(nullptr), transCrop(nullptr), cieCrop(nullptr), + : PipetteBuffer(editDataProvider), origCrop(nullptr), spotCrop(nullptr), laboCrop(nullptr), labnCrop(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), @@ -185,8 +187,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; @@ -675,8 +677,16 @@ void Crop::update(int todo) } } + if (params.filmNegative.enabled && params.filmNegative.colorSpace == FilmNegativeParams::ColorSpace::INPUT) { + parent->ipf.filmNegativeProcess(baseCrop, baseCrop, params.filmNegative); + } + parent->imgsrc->convertColorSpace(origCrop, params.icm, parent->currWB); + if (params.filmNegative.enabled && params.filmNegative.colorSpace != FilmNegativeParams::ColorSpace::INPUT) { + parent->ipf.filmNegativeProcess(baseCrop, baseCrop, params.filmNegative); + } + delete [] min_r; delete [] min_b; delete [] lumL; @@ -765,8 +775,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 @@ -832,7 +842,7 @@ void Crop::update(int todo) if (todo & M_RGBCURVE) { Imagefloat *workingCrop = baseCrop; - +/* if (params.icm.workingTRC == "Custom") { //exec TRC IN free const Glib::ustring profile = params.icm.workingProfile; @@ -846,7 +856,7 @@ void Crop::update(int todo) parent->ipf.workingtrc(workingCrop, workingCrop, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, parent->getCustomTransformOut(), false, true, true); } } - +*/ double rrm, ggm, bbm; DCPProfileApplyState as; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, as); @@ -879,12 +889,291 @@ void Crop::update(int todo) }*/ // apply luminance operations - if (todo & (M_LUMINANCE + M_COLOR)) { + if (todo & (M_LUMINANCE + M_COLOR)) { // //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); + if (params.locallab.enabled && !params.locallab.spots.empty()) { + const std::unique_ptr reservCrop(new LabImage(*laboCrop, true)); + const std::unique_ptr lastorigCrop(new LabImage(*laboCrop, true)); + auto& lllocalcurve2 = parent->lllocalcurve; + auto& cllocalcurve2 = parent->cllocalcurve; + auto& lclocalcurve2 = parent->lclocalcurve; + auto& cclocalcurve2 = parent->cclocalcurve; + auto& rgblocalcurve2 = parent->rgblocalcurve; + auto& exlocalcurve2 = parent->exlocalcurve; + auto& lmasklocalcurve2 = parent->lmasklocalcurve; + auto& lmaskexplocalcurve2 = parent->lmaskexplocalcurve; + auto& lmaskSHlocalcurve2 = parent->lmaskSHlocalcurve; + auto& lmaskviblocalcurve2 = parent->lmaskviblocalcurve; + auto& lmasktmlocalcurve2 = parent->lmasktmlocalcurve; + auto& lmaskretilocalcurve2 = parent->lmaskretilocalcurve; + auto& lmaskcblocalcurve2 = parent->lmaskcblocalcurve; + auto& lmaskbllocalcurve2 = parent->lmaskbllocalcurve; + auto& lmasklclocalcurve2 = parent->lmasklclocalcurve; + auto& lmaskloglocalcurve2 = parent->lmaskloglocalcurve; + auto& hltonecurveloc2 = parent->hltonecurveloc; + auto& shtonecurveloc2 = parent->shtonecurveloc; + auto& tonecurveloc2 = parent->tonecurveloc; + auto& lightCurveloc2 = parent->lightCurveloc; + auto& locRETgainCurve = parent->locRETgainCurve; + auto& locRETtransCurve = parent->locRETtransCurve; + auto& loclhCurve = parent->loclhCurve; + auto& lochhCurve = parent->lochhCurve; + auto& locchCurve = parent->locchCurve; + auto& locccmasCurve = parent->locccmasCurve; + auto& locllmasCurve = parent->locllmasCurve; + auto& lochhmasCurve = parent->lochhmasCurve; + auto& lochhhmasCurve = parent->lochhhmasCurve; + auto& locccmasexpCurve = parent->locccmasexpCurve; + auto& locllmasexpCurve = parent->locllmasexpCurve; + auto& lochhmasexpCurve = parent->lochhmasexpCurve; + auto& locccmasSHCurve = parent->locccmasSHCurve; + auto& locllmasSHCurve = parent->locllmasSHCurve; + auto& lochhmasSHCurve = parent->lochhmasSHCurve; + auto& locccmasvibCurve = parent->locccmasvibCurve; + auto& locllmasvibCurve = parent->locllmasvibCurve; + auto& lochhmasvibCurve = parent->lochhmasvibCurve; + auto& locccmaslcCurve = parent->locccmaslcCurve; + auto& locllmaslcCurve = parent->locllmaslcCurve; + auto& lochhmaslcCurve = parent->lochhmaslcCurve; + auto& locccmascbCurve = parent->locccmascbCurve; + auto& locllmascbCurve = parent->locllmascbCurve; + auto& lochhmascbCurve = parent->lochhmascbCurve; + auto& locccmasretiCurve = parent->locccmasretiCurve; + auto& locllmasretiCurve = parent->locllmasretiCurve; + auto& lochhmasretiCurve = parent->lochhmasretiCurve; + auto& locccmastmCurve = parent->locccmastmCurve; + auto& locllmastmCurve = parent->locllmastmCurve; + auto& lochhmastmCurve = parent->lochhmastmCurve; + auto& locccmasblCurve = parent->locccmasblCurve; + auto& locllmasblCurve = parent->locllmasblCurve; + auto& lochhmasblCurve = parent->lochhmasblCurve; + auto& locccmaslogCurve = parent->locccmaslogCurve; + auto& locllmaslogCurve = parent->locllmaslogCurve; + auto& lochhmaslogCurve = parent->lochhmaslogCurve; + + auto& locccmas_Curve = parent->locccmas_Curve; + auto& locllmas_Curve = parent->locllmas_Curve; + auto& lochhmas_Curve = parent->lochhmas_Curve; + auto& lochhhmas_Curve = parent->lochhhmas_Curve; + auto& locwavCurve = parent->locwavCurve; + auto& loclmasCurveblwav = parent->loclmasCurveblwav; + auto& loclmasCurvecolwav = parent->loclmasCurvecolwav; + auto& loclevwavCurve = parent->loclevwavCurve; + auto& locconwavCurve = parent->locconwavCurve; + auto& loccompwavCurve = parent->loccompwavCurve; + auto& loccomprewavCurve = parent->loccomprewavCurve; + auto& locedgwavCurve = parent->locedgwavCurve; + auto& locwavCurveden = parent->locwavCurveden; + auto& lmasklocal_curve2 = parent->lmasklocal_curve; + auto& loclmasCurve_wav = parent->loclmasCurve_wav; + + 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); + const bool LHutili = loclhCurve.Set(params.locallab.spots.at(sp).LHcurve); + const bool HHutili = lochhCurve.Set(params.locallab.spots.at(sp).HHcurve); + const bool CHutili = locchCurve.Set(params.locallab.spots.at(sp).CHcurve); + const bool lcmasutili = locccmasCurve.Set(params.locallab.spots.at(sp).CCmaskcurve); + const bool llmasutili = locllmasCurve.Set(params.locallab.spots.at(sp).LLmaskcurve); + const bool lhmasutili = lochhmasCurve.Set(params.locallab.spots.at(sp).HHmaskcurve); + const bool lhhmasutili = lochhhmasCurve.Set(params.locallab.spots.at(sp).HHhmaskcurve); + const bool lcmasexputili = locccmasexpCurve.Set(params.locallab.spots.at(sp).CCmaskexpcurve); + const bool llmasexputili = locllmasexpCurve.Set(params.locallab.spots.at(sp).LLmaskexpcurve); + const bool lhmasexputili = lochhmasexpCurve.Set(params.locallab.spots.at(sp).HHmaskexpcurve); + const bool lcmasSHutili = locccmasSHCurve.Set(params.locallab.spots.at(sp).CCmaskSHcurve); + const bool llmasSHutili = locllmasSHCurve.Set(params.locallab.spots.at(sp).LLmaskSHcurve); + const bool lhmasSHutili = lochhmasSHCurve.Set(params.locallab.spots.at(sp).HHmaskSHcurve); + const bool lcmasvibutili = locccmasvibCurve.Set(params.locallab.spots.at(sp).CCmaskvibcurve); + const bool llmasvibutili = locllmasvibCurve.Set(params.locallab.spots.at(sp).LLmaskvibcurve); + const bool lhmasvibutili = lochhmasvibCurve.Set(params.locallab.spots.at(sp).HHmaskvibcurve); + const bool lcmascbutili = locccmascbCurve.Set(params.locallab.spots.at(sp).CCmaskcbcurve); + const bool llmascbutili = locllmascbCurve.Set(params.locallab.spots.at(sp).LLmaskcbcurve); + const bool lhmascbutili = lochhmascbCurve.Set(params.locallab.spots.at(sp).HHmaskcbcurve); + const bool lcmasretiutili = locccmasretiCurve.Set(params.locallab.spots.at(sp).CCmaskreticurve); + const bool llmasretiutili = locllmasretiCurve.Set(params.locallab.spots.at(sp).LLmaskreticurve); + const bool lhmasretiutili = lochhmasretiCurve.Set(params.locallab.spots.at(sp).HHmaskreticurve); + const bool lcmastmutili = locccmastmCurve.Set(params.locallab.spots.at(sp).CCmasktmcurve); + const bool llmastmutili = locllmastmCurve.Set(params.locallab.spots.at(sp).LLmasktmcurve); + const bool lhmastmutili = lochhmastmCurve.Set(params.locallab.spots.at(sp).HHmasktmcurve); + const bool lcmasblutili = locccmasblCurve.Set(params.locallab.spots.at(sp).CCmaskblcurve); + const bool llmasblutili = locllmasblCurve.Set(params.locallab.spots.at(sp).LLmaskblcurve); + const bool lhmasblutili = lochhmasblCurve.Set(params.locallab.spots.at(sp).HHmaskblcurve); + const bool lcmaslogutili = locccmaslogCurve.Set(params.locallab.spots.at(sp).CCmaskcurveL); + const bool llmaslogutili = locllmaslogCurve.Set(params.locallab.spots.at(sp).LLmaskcurveL); + const bool lhmaslogutili = lochhmaslogCurve.Set(params.locallab.spots.at(sp).HHmaskcurveL); + + const bool lcmas_utili = locccmas_Curve.Set(params.locallab.spots.at(sp).CCmask_curve); + const bool llmas_utili = locllmas_Curve.Set(params.locallab.spots.at(sp).LLmask_curve); + const bool lhmas_utili = lochhmas_Curve.Set(params.locallab.spots.at(sp).HHmask_curve); + const bool lhhmas_utili = lochhhmas_Curve.Set(params.locallab.spots.at(sp).HHhmask_curve); + const bool lmasutili_wav = loclmasCurve_wav.Set(params.locallab.spots.at(sp).LLmask_curvewav); + const bool lmasutiliblwav = loclmasCurveblwav.Set(params.locallab.spots.at(sp).LLmaskblcurvewav); + const bool lmasutilicolwav = loclmasCurvecolwav.Set(params.locallab.spots.at(sp).LLmaskcolcurvewav); + const bool lcmaslcutili = locccmaslcCurve.Set(params.locallab.spots.at(sp).CCmasklccurve); + const bool llmaslcutili = locllmaslcCurve.Set(params.locallab.spots.at(sp).LLmasklccurve); + const bool lhmaslcutili = lochhmaslcCurve.Set(params.locallab.spots.at(sp).HHmasklccurve); + const bool locwavutili = locwavCurve.Set(params.locallab.spots.at(sp).locwavcurve); + const bool locwavdenutili = locwavCurveden.Set(params.locallab.spots.at(sp).locwavcurveden); + const bool loclevwavutili = loclevwavCurve.Set(params.locallab.spots.at(sp).loclevwavcurve); + const bool locconwavutili = locconwavCurve.Set(params.locallab.spots.at(sp).locconwavcurve); + const bool loccompwavutili = loccompwavCurve.Set(params.locallab.spots.at(sp).loccompwavcurve); + const bool loccomprewavutili = loccomprewavCurve.Set(params.locallab.spots.at(sp).loccomprewavcurve); + const bool locedgwavutili = locedgwavCurve.Set(params.locallab.spots.at(sp).locedgwavcurve); + const bool locallutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).llcurve, lllocalcurve2, skip); + const bool localclutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).clcurve, cllocalcurve2, skip); + const bool locallcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).lccurve, lclocalcurve2, skip); + const bool localrgbutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).rgbcurve, rgblocalcurve2, skip); + const bool localcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).cccurve, cclocalcurve2, skip); + const bool localexutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).excurve, exlocalcurve2, skip); + const bool localmaskutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve2, skip); + const bool localmaskexputili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve2, skip); + const bool localmaskSHutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve2, skip); + const bool localmaskvibutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve2, skip); + const bool localmasktmutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve2, skip); + const bool localmaskretiutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve2, skip); + const bool localmaskcbutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve2, skip); + const bool localmasklcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve2, skip); + const bool localmaskblutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve2, skip); + const bool localmasklogutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).LmaskcurveL, lmaskloglocalcurve2, skip); + const bool localmask_utili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmask_curve, lmasklocal_curve2, skip); + + 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; + 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]; + const float avge = parent->avgs[sp]; + + float minCD; + float maxCD; + float mini; + float maxi; + float Tmean; + float Tsigma; + float Tmin; + float Tmax; + int lastsav; + CurveFactory::complexCurvelocal(ecomp, black / 65535., hlcompr, hlcomprthresh, shcompr, br, cont, lumare, + hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2, avge, + skip); + // Locallab mask are only shown for selected spot + if (sp == params.locallab.selspot) { + parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop.get(), lastorigCrop.get(), cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve, + lllocalcurve2,locallutili, + cllocalcurve2, localclutili, + lclocalcurve2, locallcutili, + loclhCurve, lochhCurve, locchCurve, + lmasklocalcurve2, localmaskutili, + lmaskexplocalcurve2, localmaskexputili, + lmaskSHlocalcurve2, localmaskSHutili, + lmaskviblocalcurve2, localmaskvibutili, + lmasktmlocalcurve2, localmasktmutili, + lmaskretilocalcurve2, localmaskretiutili, + lmaskcblocalcurve2, localmaskcbutili, + lmaskbllocalcurve2, localmaskblutili, + lmasklclocalcurve2, localmasklcutili, + lmaskloglocalcurve2, localmasklogutili, + lmasklocal_curve2, localmask_utili, + + 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, + locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili, + + locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili, + lochhhmas_Curve, lhhmas_utili, + loclmasCurveblwav,lmasutiliblwav, + loclmasCurvecolwav,lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + loclmasCurve_wav,lmasutili_wav, + LHutili, HHutili, CHutili, 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, + parent->localllogMask, parent->locall_Mask, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } else { + parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop.get(), lastorigCrop.get(), cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve, + lllocalcurve2,locallutili, + cllocalcurve2, localclutili, + lclocalcurve2, locallcutili, + loclhCurve, lochhCurve, locchCurve, + lmasklocalcurve2, localmaskutili, + lmaskexplocalcurve2, localmaskexputili, + lmaskSHlocalcurve2, localmaskSHutili, + lmaskviblocalcurve2, localmaskvibutili, + lmasktmlocalcurve2, localmasktmutili, + lmaskretilocalcurve2, localmaskretiutili, + lmaskcblocalcurve2, localmaskcbutili, + lmaskbllocalcurve2, localmaskblutili, + lmasklclocalcurve2, localmasklcutili, + lmaskloglocalcurve2, localmasklogutili, + lmasklocal_curve2, localmask_utili, + + 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, + locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili, + + locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili, + lochhhmas_Curve, lhhmas_utili, + + loclmasCurveblwav,lmasutiliblwav, + loclmasCurvecolwav,lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + loclmasCurve_wav,lmasutili_wav, + LHutili, HHutili, CHutili, 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, 0, 0, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + } + + if (sp + 1u < params.locallab.spots.size()) { + // do not copy for last spot as it is not needed anymore + lastorigCrop->CopyFrom(labnCrop); + } + + if (skip <= 2) { + Glib::usleep(settings->cropsleep); //wait to avoid crash when crop 100% and move window + } + } + } - //parent->ipf.luminanceCurve (labnCrop, labnCrop, parent->lumacurve); bool utili = parent->utili; bool autili = parent->autili; bool butili = parent->butili; @@ -893,9 +1182,8 @@ void Crop::update(int todo) bool cclutili = parent->cclutili; LUTu dummy; - 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)) { @@ -997,15 +1285,18 @@ void Crop::update(int todo) } WavCurve wavCLVCurve; + WavCurve wavdenoise; + WavCurve wavdenoiseh; Wavblcurve wavblcurve; WavOpacityCurveRG waOpacityCurveRG; WavOpacityCurveSH waOpacityCurveSH; WavOpacityCurveBY waOpacityCurveBY; WavOpacityCurveW waOpacityCurveW; WavOpacityCurveWL waOpacityCurveWL; + LUTf wavclCurve; - params.wavelet.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); + params.wavelet.getCurves(wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); LabImage *unshar = nullptr; Glib::ustring provis; LabImage *provradius = nullptr; @@ -1023,19 +1314,17 @@ void Crop::update(int todo) if (WaveParams.softrad > 0.f) { - provradius = new LabImage(labnCrop->W, labnCrop->H); - provradius->CopyFrom(labnCrop); + provradius = new LabImage(*labnCrop, true); } if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { - 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, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); - unshar->CopyFrom(labnCrop); + parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); + unshar = new LabImage(*labnCrop, true); params.wavelet.CLmethod = provis; @@ -1047,7 +1336,11 @@ void Crop::update(int todo) WaveParams.expnoise = false; } - parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); + + +// 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, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { WaveParams.expcontrast = procont; @@ -1086,11 +1379,11 @@ void Crop::update(int todo) } double epsilmax = 0.0001; double epsilmin = 0.00001; - double aepsil = (epsilmax - epsilmin) / 90.f; - double bepsil = epsilmax - 100.f * aepsil; + double aepsil = (epsilmax - epsilmin) / 100.f; + double bepsil = epsilmin; //epsilmax - 100.f * aepsil; double epsil = aepsil * WaveParams.softrad + bepsil; - float blur = 10.f / skip * (0.0001f + 0.8f * WaveParams.softrad); + float blur = 10.f / skip * (0.5f + 0.8f * WaveParams.softrad); rtengine::guidedFilter(guid, ble, ble, blur, epsil, false); @@ -1169,11 +1462,12 @@ void Crop::update(int todo) } + } - - parent->ipf.softLight(labnCrop); + + parent->ipf.softLight(labnCrop, params.softlight); if (params.colorappearance.enabled) { float fnum = parent->imgsrc->getMetaData()->getFNumber(); // F number @@ -1273,6 +1567,7 @@ void Crop::freeAll() laboCrop = nullptr; } + if (labnCrop) { delete labnCrop; labnCrop = nullptr; @@ -1288,6 +1583,11 @@ void Crop::freeAll() cieCrop = nullptr; } + if (shbuffer) { + delete [] shbuffer; + shbuffer = nullptr; + } + PipetteBuffer::flush(); } @@ -1402,8 +1702,11 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter int orW, orH; parent->imgsrc->getSize(cp, orW, orH); - trafx = orx; - trafy = ory; + if (trafx != orx || trafy != ory) { + trafx = orx; + trafy = ory; + changed = true; + } int cw = skips(bw, skip); int ch = skips(bh, skip); @@ -1440,6 +1743,8 @@ 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 } @@ -1458,6 +1763,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 e58ba05c3..361f0462d 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -42,11 +42,13 @@ protected: LabImage* laboCrop; // "one chunk" allocation LabImage* labnCrop; // "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 @@ -64,19 +66,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..92a5ae7ee 100644 --- a/rtengine/dirpyr_equalizer.cc +++ b/rtengine/dirpyr_equalizer.cc @@ -25,6 +25,7 @@ #include "array2D.h" #include "cieimage.h" #include "color.h" +#include "curves.h" #include "improcfun.h" #include "LUT.h" #include "opthelper.h" @@ -37,6 +38,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 +246,22 @@ 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 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++) { + const float hipass = data_fine[i][j] - data_coarse[i][j]; + buffer[i][j] += irangefn[hipass + 0x10000] * hipass; + } + } +} + 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 +525,161 @@ 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 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], 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], 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/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 253468a76..558d9095b 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -33,9 +33,6 @@ #include "../rtgui/options.h" -//#define BENCHMARK -#include "StopWatch.h" - using namespace std; namespace rtengine @@ -43,20 +40,22 @@ namespace rtengine void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast) { - BENCHFUN if (contrast == 0.0 && !autoContrast) { // contrast == 0.0 means only first demosaicer will be used if(isBayer) { - if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4) ) { + if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4)) { amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); - } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) ) { + } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4)) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); - } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4) ) { + } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4)) { rcd_demosaic(options.chunkSizeRCD, options.measure); } } else { - if (raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS) ) { + if (raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS)) { xtrans_interpolate (3, true, options.chunkSizeXT, options.measure); } else { xtrans_interpolate (1, false, options.chunkSizeXT, options.measure); @@ -69,15 +68,19 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams array2D L(winw, winh); if (isBayer) { - if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4) || raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::PIXELSHIFT)) { + if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::PIXELSHIFT)) { amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); - } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) ) { + } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4)) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); - } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4) ) { + } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4)) { rcd_demosaic(options.chunkSizeRCD, options.measure); } } else { - if (raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS) ) { + if (raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS)) { xtrans_interpolate (3, true, options.chunkSizeXT, options.measure); } else { xtrans_interpolate (1, false, options.chunkSizeXT, options.measure); @@ -91,59 +94,47 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams }; #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel for schedule(dynamic,16) #endif - { -#ifdef _OPENMP - #pragma omp for -#endif - for(int i = 0; i < winh; ++i) { - Color::RGB2L(red[i], green[i], blue[i], L[i], xyz_rgb, winw); - } + for(int i = 0; i < winh; ++i) { + Color::RGB2L(red[i], green[i], blue[i], L[i], xyz_rgb, winw); } - // calculate contrast based blend factors to use vng4 in regions with low contrast + + // calculate contrast based blend factors to use flat demosaicer in regions with low contrast JaggedArray blend(winw, winh); float contrastf = contrast / 100.0; buildBlendMask(L, blend, winw, winh, contrastf, autoContrast); contrast = contrastf * 100.f; - array2D& redTmp = L; // L is not needed anymore => reuse it - array2D greenTmp(winw, winh); - array2D blueTmp(winw, winh); - if (isBayer) { - vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); + if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) || + raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBBILINEAR)) { + bayer_bilinear_demosaic(blend, rawData, red, green, blue); + } else { + array2D& redTmp = L; // L is not needed anymore => reuse it + array2D greenTmp(winw, winh); + array2D blueTmp(winw, winh); + vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for(int i = 0; i < winh; ++i) { + // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache + for(int j = 0; j < winw; ++j) { + red[i][j] = intp(blend[i][j], red[i][j], redTmp[i][j]); + } + for(int j = 0; j < winw; ++j) { + green[i][j] = intp(blend[i][j], green[i][j], greenTmp[i][j]); + } + for(int j = 0; j < winw; ++j) { + blue[i][j] = intp(blend[i][j], blue[i][j], blueTmp[i][j]); + } + } + } } else { - fast_xtrans_interpolate(rawData, redTmp, greenTmp, blueTmp); + fast_xtrans_interpolate_blend(blend, rawData, red, green, blue); } - - - // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache -#ifdef _OPENMP - #pragma omp parallel for -#endif - for(int i = 0; i < winh; ++i) { - for(int j = 0; j < winw; ++j) { - red[i][j] = intp(blend[i][j], red[i][j], redTmp[i][j]); - } - } -#ifdef _OPENMP - #pragma omp parallel for -#endif - for(int i = 0; i < winh; ++i) { - for(int j = 0; j < winw; ++j) { - green[i][j] = intp(blend[i][j], green[i][j], greenTmp[i][j]); - } - } -#ifdef _OPENMP - #pragma omp parallel for -#endif - for(int i = 0; i < winh; ++i) { - for(int j = 0; j < winw; ++j) { - blue[i][j] = intp(blend[i][j], blue[i][j], blueTmp[i][j]); - } - } - } } diff --git a/rtengine/fast_demo.cc b/rtengine/fast_demo.cc index 772096b87..ca8fb4cc4 100644 --- a/rtengine/fast_demo.cc +++ b/rtengine/fast_demo.cc @@ -281,7 +281,6 @@ void RawImageSource::fast_demosaic() int right = min(left + TS, W - bord + 2); #ifdef __SSE2__ - int j, cc; __m128 wtuv, wtdv, wtlv, wtrv; __m128 greenv, tempv, absv, abs2v; __m128 c16v = _mm_set1_ps( 16.0f ); @@ -302,7 +301,7 @@ void RawImageSource::fast_demosaic() float wtu, wtd, wtl, wtr; #ifdef __SSE2__ selmask = (vmask)_mm_andnot_ps( (__m128)selmask, (__m128)andmask); - + int j, cc; for (j = left, cc = 0; j < right - 3; j += 4, cc += 4) { tempv = LVFU(rawData[i][j]); absv = vabsf(LVFU(rawData[i - 1][j]) - LVFU(rawData[i + 1][j])); @@ -421,16 +420,12 @@ void RawImageSource::fast_demosaic() temp1v = LVFU(redtile[rr * TS + cc]); temp2v = greenv - zd25v * (greensumv - LVFU(redtile[(rr - 1) * TS + cc]) - LVFU(redtile[(rr + 1) * TS + cc]) - LVFU(redtile[rr * TS + cc - 1]) - LVFU(redtile[rr * TS + cc + 1])); -// temp2v = greenv - zd25v*((LVFU(greentile[(rr-1)*TS+cc])-LVFU(redtile[(rr-1)*TS+cc]))+(LVFU(greentile[(rr+1)*TS+cc])-LVFU(redtile[(rr+1)*TS+cc]))+ -// (LVFU(greentile[rr*TS+cc-1])-LVFU(redtile[rr*TS+cc-1]))+(LVFU(greentile[rr*TS+cc+1])-LVFU(redtile[rr*TS+cc+1]))); _mm_storeu_ps( &redtile[rr * TS + cc], vself(selmask, temp1v, temp2v)); temp1v = LVFU(bluetile[rr * TS + cc]); temp2v = greenv - zd25v * (greensumv - LVFU(bluetile[(rr - 1) * TS + cc]) - LVFU(bluetile[(rr + 1) * TS + cc]) - LVFU(bluetile[rr * TS + cc - 1]) - LVFU(bluetile[rr * TS + cc + 1])); -// temp2v = greenv - zd25v*((LVFU(greentile[(rr-1)*TS+cc])-LVFU(bluetile[(rr-1)*TS+cc]))+(LVFU(greentile[(rr+1)*TS+cc])-LVFU(bluetile[(rr+1)*TS+cc]))+ -// (LVFU(greentile[rr*TS+cc-1])-LVFU(bluetile[rr*TS+cc-1]))+(LVFU(greentile[rr*TS+cc+1])-LVFU(bluetile[rr*TS+cc+1]))); _mm_storeu_ps( &bluetile[rr * TS + cc], vself(selmask, temp1v, temp2v)); } @@ -450,7 +445,7 @@ void RawImageSource::fast_demosaic() for (int i = top + 2, rr = 2; i < bottom - 2; i++, rr++) { #ifdef __SSE2__ - + int j, cc; for (j = left + 2, cc = 2; j < right - 5; j += 4, cc += 4) { _mm_storeu_ps(&red[i][j], vmaxf(LVFU(redtile[rr * TS + cc]), ZEROV)); _mm_storeu_ps(&green[i][j], vmaxf(LVFU(greentile[rr * TS + cc]), ZEROV)); diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index 6d4fe1ad6..ae1813db9 100644 --- a/rtengine/filmnegativeproc.cc +++ b/rtengine/filmnegativeproc.cc @@ -21,550 +21,647 @@ #include "rawimage.h" #include "rawimagesource.h" +#include "improcfun.h" +#include "improccoordinator.h" +#include "imagefloat.h" #include "coord.h" -#include "mytime.h" #include "opthelper.h" #include "pixelsmap.h" #include "procparams.h" #include "rt_algo.h" #include "rtengine.h" +#include "rtthumbnail.h" #include "sleef.h" //#define BENCHMARK -#include "StopWatch.h" +//#include "StopWatch.h" +#include "iccstore.h" +#include "rt_math.h" +#include "color.h" + namespace { -using rtengine::ST_BAYER; -using rtengine::ST_FUJI_XTRANS; using rtengine::settings; +using rtengine::Coord2D; +using rtengine::ColorTemp; +using rtengine::findMinMaxPercentile; +using rtengine::ImageSource; +using rtengine::Imagefloat; +using rtengine::procparams::FilmNegativeParams; +using rtengine::procparams::ColorManagementParams; +using rtengine::procparams::RAWParams; +using rtengine::ICCStore; +using rtengine::MAXVALF; +using rtengine::CLIP; +using rtengine::TMatrix; +using rtengine::Color; +using RGB = rtengine::procparams::FilmNegativeParams::RGB; -bool channelsAvg( - const rtengine::RawImage* ri, - int width, - int height, - const float* cblacksom, - rtengine::Coord spotPos, - int spotSize, - std::array& avgs -) +Coord2D translateCoord(const rtengine::ImProcFunctions& ipf, int fw, int fh, int x, int y) { - avgs = {}; // Channel averages - if (ri->getSensorType() != ST_BAYER && ri->getSensorType() != ST_FUJI_XTRANS) { - return false; - } + const std::vector points = {Coord2D(x, y)}; + + std::vector red; + std::vector green; + std::vector blue; + ipf.transCoord(fw, fh, points, red, green, blue); + + return green[0]; +} + + +void getSpotAvgMax(ImageSource *imgsrc, ColorTemp currWB, const std::unique_ptr ¶ms, + Coord2D p, int tr, int spotSize, RGB &avg, RGB &max) +{ + int x1 = MAX(0, (int)p.x - spotSize / 2); + int y1 = MAX(0, (int)p.y - spotSize / 2); + PreviewProps pp(x1, y1, spotSize, spotSize, 1); if (settings->verbose) { - printf("Spot coord: x=%d y=%d\n", spotPos.x, spotPos.y); + printf("Spot: %d,%d %d,%d\n", x1, y1, x1 + spotSize / 2, y1 + spotSize / 2); } - const int half_spot_size = spotSize / 2; + rtengine::Imagefloat spotImg(spotSize, spotSize); + imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw); - const int& x1 = spotPos.x - half_spot_size; - const int& x2 = spotPos.x + half_spot_size; - const int& y1 = spotPos.y - half_spot_size; - const int& y2 = spotPos.y + half_spot_size; + auto avgMax = [spotSize, &spotImg](RGB & avg, RGB & max) -> void { + avg = {}; + max = {}; - if (x1 < 0 || x2 > width || y1 < 0 || y2 > height) { - return false; // Spot goes outside bounds, bail out. - } + for (int i = 0; i < spotSize; ++i) + { + for (int j = 0; j < spotSize; ++j) { - std::array pxCount = {}; // Per-channel sample counts + float r = spotImg.r(i, j); + float g = spotImg.g(i, j); + float b = spotImg.b(i, j); - for (int c = x1; c < x2; ++c) { - for (int r = y1; r < y2; ++r) { - const int ch = ri->getSensorType() == ST_BAYER ? ri->FC(r, c) : ri->XTRANSFC(r, c); - - ++pxCount[ch]; - - // Sample the original unprocessed values from RawImage, subtracting black levels. - // Scaling is irrelevant, as we are only interested in the ratio between two spots. - avgs[ch] += ri->data[r][c] - cblacksom[ch]; - } - } - - for (int ch = 0; ch < 3; ++ch) { - avgs[ch] /= pxCount[ch]; - } - - return true; -} - -void calcMedians( - const rtengine::RawImage* ri, - float** data, - int x1, int y1, int x2, int y2, - std::array& meds -) -{ - - MyTime t1, t2, t3; - t1.set(); - - // Channel vectors to calculate medians - std::array, 3> cvs; - - // Sample one every 5 pixels, and push the value in the appropriate channel vector. - // Choose an odd step, not a multiple of the CFA size, to get a chance to visit each channel. - if (ri->getSensorType() == ST_BAYER) { - for (int row = y1; row < y2; row += 5) { - const int c0 = ri->FC(row, x1 + 0); - const int c1 = ri->FC(row, x1 + 5); - int col = x1; - - for (; col < x2 - 5; col += 10) { - cvs[c0].push_back(data[row][col]); - cvs[c1].push_back(data[row][col + 5]); - } - - if (col < x2) { - cvs[c0].push_back(data[row][col]); + avg.r += r; + avg.g += g; + avg.b += b; + max.r = MAX(max.r, r); + max.g = MAX(max.g, g); + max.b = MAX(max.b, b); } } - } else if (ri->getSensorType() == ST_FUJI_XTRANS) { - for (int row = y1; row < y2; row += 5) { - const std::array cs = { - ri->XTRANSFC(row, x1 + 0), - ri->XTRANSFC(row, x1 + 5), - ri->XTRANSFC(row, x1 + 10), - ri->XTRANSFC(row, x1 + 15), - ri->XTRANSFC(row, x1 + 20), - ri->XTRANSFC(row, x1 + 25) - }; - int col = x1; - for (; col < x2 - 25; col += 30) { - for (int c = 0; c < 6; ++c) { - cvs[cs[c]].push_back(data[row][col + c * 5]); - } - } - - for (int c = 0; col < x2; col += 5, ++c) { - cvs[cs[c]].push_back(data[row][col]); - } - } - } - - t2.set(); - - if (settings->verbose) { - printf("Median vector fill loop time us: %d\n", t2.etime(t1)); - } - - t2.set(); - - for (int c = 0; c < 3; ++c) { - // Find median values for each channel - if (!cvs[c].empty()) { - rtengine::findMinMaxPercentile(cvs[c].data(), cvs[c].size(), 0.5f, meds[c], 0.5f, meds[c], true); - } - } - - t3.set(); - - if (settings->verbose) { - printf("Sample count: R=%zu, G=%zu, B=%zu\n", cvs[0].size(), cvs[1].size(), cvs[2].size()); - printf("Median calc time us: %d\n", t3.etime(t2)); - } - -} - -std::array calcWBMults( - const rtengine::ColorTemp& wb, - const rtengine::ImageMatrices& imatrices, - const rtengine::RawImage *ri, - const float ref_pre_mul[4]) -{ - std::array wb_mul; - double r, g, b; - wb.getMultipliers(r, g, b); - wb_mul[0] = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b; - wb_mul[1] = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b; - wb_mul[2] = imatrices.cam_rgb[2][0] * r + imatrices.cam_rgb[2][1] * g + imatrices.cam_rgb[2][2] * b; - - for (int c = 0; c < 3; ++c) { - wb_mul[c] = ri->get_pre_mul(c) / wb_mul[c] / ref_pre_mul[c]; - } - - // Normalize max channel gain to 1.0 - float mg = rtengine::max(wb_mul[0], wb_mul[1], wb_mul[2]); - - for (int c = 0; c < 3; ++c) { - wb_mul[c] /= mg; - } - - return wb_mul; -} - -} - -bool rtengine::RawImageSource::getFilmNegativeExponents(Coord2D spotA, Coord2D spotB, int tran, const procparams::FilmNegativeParams ¤tParams, std::array& newExps) -{ - newExps = { - static_cast(currentParams.redRatio * currentParams.greenExp), - static_cast(currentParams.greenExp), - static_cast(currentParams.blueRatio * currentParams.greenExp) + avg.r /= (spotSize * spotSize); + avg.g /= (spotSize * spotSize); + avg.b /= (spotSize * spotSize); }; - constexpr int spotSize = 32; // TODO: Make this configurable? + if (params->filmNegative.colorSpace == rtengine::FilmNegativeParams::ColorSpace::INPUT) { + avgMax(avg, max); + } else { + // Convert spot image to current working space + imgsrc->convertColorSpace(&spotImg, params->icm, currWB); - Coord spot; - std::array clearVals; - std::array denseVals; + avgMax(avg, max); - // 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: - // 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? - - // Sample first spot - transformPosition(spotA.x, spotA.y, tran, spot.x, spot.y); - - if (!channelsAvg(ri, W, H, cblacksom, spot, spotSize, clearVals)) { - return false; + // TODO handle custom color profile ! } - // Sample second spot - transformPosition(spotB.x, spotB.y, tran, spot.x, spot.y); - - if (!channelsAvg(ri, W, H, cblacksom, spot, spotSize, denseVals)) { - return false; - } - - // Detect which one is the dense spot, based on green channel - if (clearVals[1] < denseVals[1]) { - std::swap(clearVals, denseVals); - } + // Clip away zeroes or negative numbers, you never know + avg.r = MAX(avg.r, 1.f); + avg.g = MAX(avg.g, 1.f); + avg.b = MAX(avg.b, 1.f); if (settings->verbose) { - printf("Clear film values: R=%g G=%g B=%g\n", static_cast(clearVals[0]), static_cast(clearVals[1]), static_cast(clearVals[2])); - printf("Dense film values: R=%g G=%g B=%g\n", static_cast(denseVals[0]), static_cast(denseVals[1]), static_cast(denseVals[2])); + printf("Average Spot RGB: %f,%f,%f\n", avg.r, avg.g, avg.b); } +} - const float denseGreenRatio = clearVals[1] / denseVals[1]; - // Calculate logarithms in arbitrary base - const auto logBase = - [](float base, float num) -> float - { - return std::log(num) / std::log(base); - }; +void calcMedians( + const rtengine::Imagefloat* input, + int x1, int y1, int x2, int y2, + float &rmed, float &gmed, float &bmed +) +{ + using rtengine::findMinMaxPercentile; - // Calculate exponents for each channel, based on the ratio between the bright and dark values, - // compared to the ratio in the reference channel (green) - for (int ch = 0; ch < 3; ++ch) { - if (ch == 1) { - newExps[ch] = 1.f; // Green is the reference channel - } else { - newExps[ch] = rtengine::LIM(logBase(clearVals[ch] / denseVals[ch], denseGreenRatio), 0.3f, 4.f); + // Channel vectors to calculate medians + std::vector rv, gv, bv; + + const int sz = (x2 - x1) * (y2 - y1); + rv.reserve(sz); + gv.reserve(sz); + bv.reserve(sz); + + + for (int ii = y1; ii < y2; ii ++) { + for (int jj = x1; jj < x2; jj ++) { + rv.push_back(input->r(ii, jj)); + gv.push_back(input->g(ii, jj)); + bv.push_back(input->b(ii, jj)); } } - if (settings->verbose) { - printf("New exponents: R=%g G=%g B=%g\n", static_cast(newExps[0]), static_cast(newExps[1]), static_cast(newExps[2])); - } - - return true; + // Calculate channel medians of the specified area + findMinMaxPercentile(rv.data(), rv.size(), 0.5f, rmed, 0.5f, rmed, true); + findMinMaxPercentile(gv.data(), gv.size(), 0.5f, gmed, 0.5f, gmed, true); + findMinMaxPercentile(bv.data(), bv.size(), 0.5f, bmed, 0.5f, bmed, true); } -bool rtengine::RawImageSource::getRawSpotValues(Coord2D spotCoord, int spotSize, int tran, const procparams::FilmNegativeParams ¶ms, std::array& rawValues) + +RGB getMedians(const rtengine::Imagefloat* input, int borderPercent) { - Coord spot; - transformPosition(spotCoord.x, spotCoord.y, tran, spot.x, spot.y); + float rmed, gmed, bmed; + // Cut 20% border from medians calculation. It will probably contain outlier values + // from the film holder, which will bias the median result. + const int bW = input->getWidth() * borderPercent / 100; + const int bH = input->getHeight() * borderPercent / 100; + calcMedians(input, bW, bH, + input->getWidth() - bW, input->getHeight() - bH, + rmed, gmed, bmed); if (settings->verbose) { - printf("Transformed coords: %d,%d\n", spot.x, spot.y); + printf("Channel medians: R=%g, G=%g, B=%g\n", rmed, gmed, bmed); } - if (spotSize < 4) { + return { rmed, gmed, bmed }; +} + +/* +// TODO not needed for now +void convertColorSpace(Imagefloat* input, const TMatrix &src2xyz, const TMatrix &xyz2dest) +{ + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < input->getHeight(); i++) { + for (int j = 0; j < input->getWidth(); j++) { + + float newr = input->r(i, j); + float newg = input->g(i, j); + float newb = input->b(i, j); + + float x, y, z; + Color::rgbxyz (newr, newg, newb, x, y, z, src2xyz); + Color::xyz2rgb (x, y, z, newr, newg, newb, xyz2dest); + + input->r(i, j) = newr; + input->g(i, j) = newg; + input->b(i, j) = newb; + + } + } +} +*/ + + +/** + * Perform actual film negative inversion process. + * Returns true if the input and output reference values are not set in params; refIn/refOut will be updated with median-based estimates. + * Otherwise, use provided values in params and return false + */ +bool doProcess(Imagefloat *input, Imagefloat *output, + const FilmNegativeParams ¶ms, const ColorManagementParams &icmParams, + RGB &refIn, RGB &refOut) +{ + bool refsUpdated = false; + + float rexp = -(params.greenExp * params.redRatio); + float gexp = -params.greenExp; + float bexp = -(params.greenExp * params.blueRatio); + + // In case we are processing a thumbnail, reference values might not be set in params, + // so make an estimate on the fly, using channel medians + if (refIn.g <= 0.f) { + // Calc medians, 20% border cut + refIn = getMedians(input, 20); + refsUpdated = true; + } else { + refIn = params.refInput; + } + + if (refOut.g <= 0.f) { + // Median will correspond to gray, 1/24th of max in the output + refOut = { MAXVALF / 24.f, MAXVALF / 24.f, MAXVALF / 24.f }; + refsUpdated = true; + } else { + refOut = params.refOutput; + } + + // Apply channel exponents to reference input values, and compute suitable multipliers + // in order to reach reference output values. + float rmult = refOut.r / pow_F(rtengine::max(refIn.r, 1.f), rexp); + float gmult = refOut.g / pow_F(rtengine::max(refIn.g, 1.f), gexp); + float bmult = refOut.b / pow_F(rtengine::max(refIn.b, 1.f), bexp); + + +#ifdef __SSE2__ + const vfloat clipv = F2V(MAXVALF); + const vfloat rexpv = F2V(rexp); + const vfloat gexpv = F2V(gexp); + const vfloat bexpv = F2V(bexp); + const vfloat rmultv = F2V(rmult); + const vfloat gmultv = F2V(gmult); + const vfloat bmultv = F2V(bmult); +#endif + + const int rheight = input->getHeight(); + const int rwidth = input->getWidth(); + + for (int i = 0; i < rheight; i++) { + float *rlinein = input->r(i); + float *glinein = input->g(i); + float *blinein = input->b(i); + float *rlineout = output->r(i); + float *glineout = output->g(i); + float *blineout = output->b(i); + int j = 0; +#ifdef __SSE2__ + + for (; j < rwidth - 3; j += 4) { + STVFU(rlineout[j], vminf(rmultv * pow_F(LVFU(rlinein[j]), rexpv), clipv)); + STVFU(glineout[j], vminf(gmultv * pow_F(LVFU(glinein[j]), gexpv), clipv)); + STVFU(blineout[j], vminf(bmultv * pow_F(LVFU(blinein[j]), bexpv), clipv)); + } + +#endif + + for (; j < rwidth; ++j) { + rlineout[j] = CLIP(rmult * pow_F(rlinein[j], rexp)); + glineout[j] = CLIP(gmult * pow_F(glinein[j], gexp)); + blineout[j] = CLIP(bmult * pow_F(blinein[j], bexp)); + } + } + + return refsUpdated; +} + + +} + + + +bool rtengine::ImProcFunctions::filmNegativeProcess( + Imagefloat *input, Imagefloat *output, FilmNegativeParams &fnp, + const RAWParams &rawParams, const ImageSource* imgsrc, const ColorTemp &currWB) +{ + //BENCHFUNMICRO + + if (!fnp.enabled) { return false; } - // Calculate averages of raw unscaled channels - if (!channelsAvg(ri, W, H, cblacksom, spot, spotSize, rawValues)) { - return false; + bool paramsUpdated = false; + + RGB &refIn = fnp.refInput; + RGB &refOut = fnp.refOutput; + + // If we're opening a profile from an older version, apply the proper multiplier + // compensations to make processing backwards compatible. + + if (fnp.backCompat == FilmNegativeParams::BackCompat::V1) { + // Calc medians, no border cut, compensate currWB in+out + refIn = getMedians(input, 0); + refOut = { MAXVALF / 24.f, MAXVALF / 24.f, MAXVALF / 24.f }; + + std::array scale_mul = { 1.f, 1.f, 1.f, 1.f }; + float autoGainComp, rm, gm, bm; + imgsrc->getWBMults(currWB, params->raw, scale_mul, autoGainComp, rm, gm, bm); + + refOut.r *= rm; + refOut.g *= gm; + refOut.b *= bm; + + paramsUpdated = true; + + } else if (fnp.backCompat == FilmNegativeParams::BackCompat::V2) { + + std::array scale_mul = { 1.f, 1.f, 1.f, 1.f }; + float autoGainComp, rm, gm, bm; + imgsrc->getWBMults(currWB, params->raw, scale_mul, autoGainComp, rm, gm, bm); + + float rm2, gm2, bm2; + imgsrc->getWBMults(rtengine::ColorTemp(3500., 1., 1., "Custom"), params->raw, scale_mul, autoGainComp, rm2, gm2, bm2); + float mg = rtengine::max(rm2, gm2, bm2); + rm2 /= mg; + gm2 /= mg; + bm2 /= mg; + + if (fnp.refInput.g == 0.f) { + // Calc medians, 20% border cut + refIn = getMedians(input, 20); + refOut = { MAXVALF / 24.f, MAXVALF / 24.f, MAXVALF / 24.f }; + } else if (fnp.refInput.g > 0.f) { + // Calc refInput + refOutput from base levels, compensate currWB in, 3500 out + refIn = fnp.refInput; + refIn.r *= rm * scale_mul[0]; + refIn.g *= gm * scale_mul[1]; + refIn.b *= bm * scale_mul[2]; + refOut = { MAXVALF / 512.f, MAXVALF / 512.f, MAXVALF / 512.f }; + } + + refOut.r *= rm * autoGainComp / rm2; + refOut.g *= gm * autoGainComp / gm2; + refOut.b *= bm * autoGainComp / bm2; + + paramsUpdated = true; + } - if (settings->verbose) { - printf("Raw spot values: R=%g, G=%g, B=%g\n", rawValues[0], rawValues[1], rawValues[2]); + if (settings->verbose && fnp.backCompat != FilmNegativeParams::BackCompat::CURRENT) { + printf("Upgraded from V%d - refIn: R=%g G=%g B=%g refOut: R=%g G=%g B=%g\n", + (int)fnp.backCompat, + static_cast(refIn.r), static_cast(refIn.g), static_cast(refIn.b), + static_cast(refOut.r), static_cast(refOut.g), static_cast(refOut.b)); } - return true; + // FilmNeg params are now upgraded to the latest version + fnp.backCompat = FilmNegativeParams::BackCompat::CURRENT; + + // Perform actual inversion. Return true if reference values are computed from medians + paramsUpdated |= doProcess(input, output, fnp, this->params->icm, refIn, refOut); + + return paramsUpdated; + } -void rtengine::RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams ¶ms, std::array& filmBaseValues) +void rtengine::ImProcFunctions::filmNegativeProcess(rtengine::Imagefloat *input, rtengine::Imagefloat *output, + const procparams::FilmNegativeParams ¶ms) { -// BENCHFUNMICRO + //BENCHFUNMICRO if (!params.enabled) { return; } - // Exponents are expressed as positive in the parameters, so negate them in order - // to get the reciprocals. - const std::array exps = { - static_cast(-params.redRatio * params.greenExp), - static_cast(-params.greenExp), - static_cast(-params.blueRatio * params.greenExp) - }; + RGB refIn = params.refInput, refOut = params.refOutput; - constexpr float MAX_OUT_VALUE = 65000.f; + doProcess(input, output, params, this->params->icm, refIn, refOut); - // Get multipliers for a known, fixed WB setting, that will be the starting point - // for balancing the converted image. - const std::array wb_mul = calcWBMults( - ColorTemp(3500., 1., 1., "Custom"), imatrices, ri, ref_pre_mul); +} - if (rtengine::settings->verbose) { - printf("Fixed WB mults: %g %g %g\n", wb_mul[0], wb_mul[1], wb_mul[2]); - } +bool rtengine::ImProcCoordinator::getFilmNegativeSpot(int x, int y, const int spotSize, RGB &refInput, RGB &refOutput) +{ + MyMutex::MyLock lock(mProcessing); - // Compensation factor to restore the non-autoWB initialGain (see RawImageSource::load) - const float autoGainComp = camInitialGain / initialGain; + const int tr = getCoarseBitMask(params->coarse); - std::array mults; // Channel normalization multipliers + const Coord2D p = translateCoord(ipf, fw, fh, x, y); - // 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 + // Get the average channel values from the sampled spot + RGB avg, max; + getSpotAvgMax(imgsrc, currWB, params, p, tr, spotSize, avg, max); - std::array medians; + float rexp = -(params->filmNegative.greenExp * params->filmNegative.redRatio); + float gexp = -params->filmNegative.greenExp; + float bexp = -(params->filmNegative.greenExp * params->filmNegative.blueRatio); - // Special value for backwards compatibility with profiles saved by RT 5.7 - const bool oldChannelScaling = filmBaseValues[0] == -1.f; + float rmult = params->filmNegative.refOutput.r / pow_F(rtengine::max(params->filmNegative.refInput.r, 1.f), rexp); + float gmult = params->filmNegative.refOutput.g / pow_F(rtengine::max(params->filmNegative.refInput.g, 1.f), gexp); + float bmult = params->filmNegative.refOutput.b / pow_F(rtengine::max(params->filmNegative.refInput.b, 1.f), bexp); - // If using the old channel scaling method, get medians from the whole current image, - // reading values from the already-scaled rawData buffer. - if (oldChannelScaling) { - calcMedians(ri, rawData, 0, 0, W, H, medians); - } else { - // Cut 20% border from medians calculation. It will probably contain outlier values - // from the film holder, which will bias the median result. - const int bW = W * 20 / 100; - const int bH = H * 20 / 100; - calcMedians(ri, rawData, bW, bH, W - bW, H - bH, medians); - } + refInput = avg; - // Un-scale rawData medians - for (int c = 0; c < 3; ++c) { - medians[c] /= scale_mul[c]; - } + refOutput.r = rmult * pow_F(avg.r, rexp); + refOutput.g = gmult * pow_F(avg.g, gexp); + refOutput.b = bmult * pow_F(avg.b, bexp); - if (settings->verbose) { - printf("Channel medians: R=%g, G=%g, B=%g\n", medians[0], medians[1], medians[2]); - } - - for (int c = 0; c < 3; ++c) { - - // Estimate film base values, so that in the output data, each channel - // median will correspond to 1/24th of MAX. - filmBaseValues[c] = pow_F(24.f / 512.f, 1.f / exps[c]) * medians[c]; - - if (oldChannelScaling) { - // If using the old channel scaling method, apply WB multipliers here to undo their - // effect later, since fixed wb compensation was not used in previous version. - // Also, undo the effect of the autoGainComp factor (see below). - filmBaseValues[c] /= pow_F((wb_mul[c] / autoGainComp), 1.f / exps[c]);// / autoGainComp; - } - - } - } + return true; +} - // Calculate multipliers based on previously obtained film base input values. - // Apply current scaling coefficients to raw, unscaled base values. - std::array fb = { - filmBaseValues[0] * scale_mul[0], - filmBaseValues[1] * scale_mul[1], - filmBaseValues[2] * scale_mul[2] - }; + + + + +// ---------- >>> legacy mode >>> --------------- + + +// For backwards compatibility with profiles saved by RT 5.7 - 5.8 +void rtengine::Thumbnail::processFilmNegative( + const procparams::ProcParams ¶ms, + const Imagefloat* baseImg, + const int rwidth, const int rheight +) +{ + + // Channel exponents + const float rexp = -params.filmNegative.redRatio * params.filmNegative.greenExp; + const float gexp = -params.filmNegative.greenExp; + const float bexp = -params.filmNegative.blueRatio * params.filmNegative.greenExp; + + const float MAX_OUT_VALUE = 65000.f; + + // Channel medians + float rmed, gmed, bmed; + + // If using the old method, calculate medians on the whole image + calcMedians(baseImg, 0, 0, rwidth, rheight, rmed, gmed, bmed); if (settings->verbose) { - printf("Input film base values: %g %g %g\n", fb[0], fb[1], fb[2]); + printf("FilmNeg legacy V1 :: Thumbnail input channel medians: %g %g %g\n", rmed, gmed, bmed); } - for (int c = 0; c < 3; ++c) { - // Apply channel exponents, to obtain the corresponding base values in the output data - fb[c] = pow_F(rtengine::max(fb[c], 1.f), exps[c]); + // Calculate output medians + rmed = powf(rmed, rexp); + gmed = powf(gmed, gexp); + bmed = powf(bmed, bexp); - // Determine the channel multiplier so that the film base value is 1/512th of max. - mults[c] = (MAX_OUT_VALUE / 512.f) / fb[c]; + // Calculate output multipliers so that the median value is 1/24 of the output range. + float rmult, gmult, bmult; + rmult = (MAX_OUT_VALUE / 24.f) / rmed; + gmult = (MAX_OUT_VALUE / 24.f) / gmed; + bmult = (MAX_OUT_VALUE / 24.f) / bmed; - // Un-apply the fixed WB multipliers, to reverse their effect later in the WB tool. - // This way, the output image will be adapted to this fixed WB setting - mults[c] /= wb_mul[c]; - - // Also compensate for the initialGain difference between the default scaling (forceAutoWB=true) - // and the non-autoWB scaling (see camInitialGain). - // This effectively restores camera scaling multipliers, and gives us stable multipliers - // (not depending on image content). - mults[c] *= autoGainComp; + float rsum = 0.f, gsum = 0.f, bsum = 0.f; + for (int i = 0; i < rheight; i++) { + for (int j = 0; j < rwidth; j++) { + rsum += baseImg->r(i, j); + gsum += baseImg->g(i, j); + bsum += baseImg->b(i, j); + } } + const float ravg = rsum / (rheight * rwidth); + const float gavg = gsum / (rheight * rwidth); + const float bavg = bsum / (rheight * rwidth); + + // Shifting current WB multipliers, based on channel averages. + rmult /= gavg / ravg; + // gmult /= gAvg / gAvg; green chosen as reference channel + bmult /= gavg / bavg; + if (settings->verbose) { - printf("Output film base values: %g %g %g\n", static_cast(fb[0]), static_cast(fb[1]), static_cast(fb[2])); - printf("Computed multipliers: %g %g %g\n", static_cast(mults[0]), static_cast(mults[1]), static_cast(mults[2])); + printf("FilmNeg legacy V1 :: Thumbnail computed multipliers: %g %g %g\n", static_cast(rmult), static_cast(gmult), static_cast(bmult)); } - - constexpr float CLIP_VAL = 65535.f; - - MyTime t1, t2, t3; - - t1.set(); - - if (ri->getSensorType() == ST_BAYER) { #ifdef __SSE2__ - const vfloat onev = F2V(1.f); - const vfloat clipv = F2V(CLIP_VAL); + const vfloat clipv = F2V(MAXVALF); + const vfloat rexpv = F2V(rexp); + const vfloat gexpv = F2V(gexp); + const vfloat bexpv = F2V(bexp); + const vfloat rmultv = F2V(rmult); + const vfloat gmultv = F2V(gmult); + const vfloat bmultv = F2V(bmult); #endif -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, 16) -#endif - - for (int row = 0; row < H; ++row) { - int col = 0; - // Avoid trouble with zeroes, minimum pixel value is 1. - const float exps0 = exps[FC(row, col)]; - const float exps1 = exps[FC(row, col + 1)]; - const float mult0 = mults[FC(row, col)]; - const float mult1 = mults[FC(row, col + 1)]; + for (int i = 0; i < rheight; i++) { + float *rline = baseImg->r(i); + float *gline = baseImg->g(i); + float *bline = baseImg->b(i); + int j = 0; #ifdef __SSE2__ - const vfloat expsv = _mm_setr_ps(exps0, exps1, exps0, exps1); - const vfloat multsv = _mm_setr_ps(mult0, mult1, mult0, mult1); - for (; col < W - 3; col += 4) { - STVFU(rawData[row][col], vminf(multsv * pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv), clipv)); - } - -#endif // __SSE2__ - - for (; col < W - 1; col += 2) { - rawData[row][col] = rtengine::min(mult0 * pow_F(rtengine::max(rawData[row][col], 1.f), exps0), CLIP_VAL); - rawData[row][col + 1] = rtengine::min(mult1 * pow_F(rtengine::max(rawData[row][col + 1], 1.f), exps1), CLIP_VAL); - } - - if (col < W) { - rawData[row][col] = rtengine::min(mult0 * pow_F(rtengine::max(rawData[row][col], 1.f), exps0), CLIP_VAL); - } + for (; j < rwidth - 3; j += 4) { + STVFU(rline[j], vminf(rmultv * pow_F(LVFU(rline[j]), rexpv), clipv)); + STVFU(gline[j], vminf(gmultv * pow_F(LVFU(gline[j]), gexpv), clipv)); + STVFU(bline[j], vminf(bmultv * pow_F(LVFU(bline[j]), bexpv), clipv)); } - } else if (ri->getSensorType() == ST_FUJI_XTRANS) { -#ifdef __SSE2__ - const vfloat onev = F2V(1.f); - const vfloat clipv = F2V(CLIP_VAL); + #endif -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, 16) -#endif - - for (int row = 0; row < H; row ++) { - int col = 0; - // Avoid trouble with zeroes, minimum pixel value is 1. - const std::array expsc = { - exps[ri->XTRANSFC(row, 0)], - exps[ri->XTRANSFC(row, 1)], - exps[ri->XTRANSFC(row, 2)], - exps[ri->XTRANSFC(row, 3)], - exps[ri->XTRANSFC(row, 4)], - exps[ri->XTRANSFC(row, 5)] - }; - const std::array multsc = { - mults[ri->XTRANSFC(row, 0)], - mults[ri->XTRANSFC(row, 1)], - mults[ri->XTRANSFC(row, 2)], - mults[ri->XTRANSFC(row, 3)], - mults[ri->XTRANSFC(row, 4)], - mults[ri->XTRANSFC(row, 5)] - }; -#ifdef __SSE2__ - const vfloat expsv0 = _mm_setr_ps(expsc[0], expsc[1], expsc[2], expsc[3]); - const vfloat expsv1 = _mm_setr_ps(expsc[4], expsc[5], expsc[0], expsc[1]); - const vfloat expsv2 = _mm_setr_ps(expsc[2], expsc[3], expsc[4], expsc[5]); - const vfloat multsv0 = _mm_setr_ps(multsc[0], multsc[1], multsc[2], multsc[3]); - const vfloat multsv1 = _mm_setr_ps(multsc[4], multsc[5], multsc[0], multsc[1]); - const vfloat multsv2 = _mm_setr_ps(multsc[2], multsc[3], multsc[4], multsc[5]); - - for (; col < W - 11; col += 12) { - STVFU(rawData[row][col], vminf(multsv0 * pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv0), clipv)); - STVFU(rawData[row][col + 4], vminf(multsv1 * pow_F(vmaxf(LVFU(rawData[row][col + 4]), onev), expsv1), clipv)); - STVFU(rawData[row][col + 8], vminf(multsv2 * pow_F(vmaxf(LVFU(rawData[row][col + 8]), onev), expsv2), clipv)); - } - -#endif // __SSE2__ - - for (; col < W - 5; col += 6) { - for (int c = 0; c < 6; ++c) { - rawData[row][col + c] = rtengine::min(multsc[c] * pow_F(rtengine::max(rawData[row][col + c], 1.f), expsc[c]), CLIP_VAL); - } - } - - for (int c = 0; col < W; col++, c++) { - rawData[row][col + c] = rtengine::min(multsc[c] * pow_F(rtengine::max(rawData[row][col + c], 1.f), expsc[c]), CLIP_VAL); - } + for (; j < rwidth; ++j) { + rline[j] = CLIP(rmult * pow_F(rline[j], rexp)); + gline[j] = CLIP(gmult * pow_F(gline[j], gexp)); + bline[j] = CLIP(bmult * pow_F(bline[j], bexp)); } } - - t2.set(); - - if (settings->verbose) { - printf("Pow loop time us: %d\n", t2.etime(t1)); - } - - t2.set(); - - PixelsMap bitmapBads(W, H); - - int totBP = 0; // Hold count of bad pixels to correct - - if (ri->getSensorType() == ST_BAYER) { -#ifdef _OPENMP - #pragma omp parallel for reduction(+:totBP) schedule(dynamic,16) -#endif - - for (int i = 0; i < H; ++i) { - for (int j = 0; j < W; ++j) { - if (rawData[i][j] >= MAX_OUT_VALUE) { - bitmapBads.set(j, i); - ++totBP; - } - } - } - - if (totBP > 0) { - interpolateBadPixelsBayer(bitmapBads, rawData); - } - - } else if (ri->getSensorType() == ST_FUJI_XTRANS) { -#ifdef _OPENMP - #pragma omp parallel for reduction(+:totBP) schedule(dynamic,16) -#endif - - for (int i = 0; i < H; ++i) { - for (int j = 0; j < W; ++j) { - if (rawData[i][j] >= MAX_OUT_VALUE) { - bitmapBads.set(j, i); - totBP++; - } - } - } - - if (totBP > 0) { - interpolateBadPixelsXtrans(bitmapBads); - } - } - - t3.set(); - - if (settings->verbose) { - printf("Bad pixels count: %d\n", totBP); - printf("Bad pixels interpolation time us: %d\n", t3.etime(t2)); - } } + + +// For backwards compatibility with intermediate dev version (see filmneg_stable_mults branch) +void rtengine::Thumbnail::processFilmNegativeV2( + const procparams::ProcParams ¶ms, + const Imagefloat* baseImg, + const int rwidth, const int rheight +) +{ + + // Channel exponents + const float rexp = -params.filmNegative.redRatio * params.filmNegative.greenExp; + const float gexp = -params.filmNegative.greenExp; + const float bexp = -params.filmNegative.blueRatio * params.filmNegative.greenExp; + + // Calculate output multipliers + float rmult, gmult, bmult; + + const float MAX_OUT_VALUE = 65000.f; + + // If the film base values are not set in params, estimate multipliers from each channel's median value. + if (params.filmNegative.refInput.r <= 0.f) { + + // Channel medians + float rmed, gmed, bmed; + + // The new method cuts out a 20% border from medians calculation. + const int bW = rwidth * 20 / 100; + const int bH = rheight * 20 / 100; + calcMedians(baseImg, bW, bH, rwidth - bW, rheight - bH, rmed, gmed, bmed); + + if (settings->verbose) { + printf("FilmNeg legacy V2 :: Thumbnail input channel medians: %g %g %g\n", rmed, gmed, bmed); + } + + // Calculate output medians + rmed = powf(rmed, rexp); + gmed = powf(gmed, gexp); + bmed = powf(bmed, bexp); + + // Calculate output multipliers so that the median value is 1/24 of the output range. + rmult = (MAX_OUT_VALUE / 24.f) / rmed; + gmult = (MAX_OUT_VALUE / 24.f) / gmed; + bmult = (MAX_OUT_VALUE / 24.f) / bmed; + + } else { + + // Read film-base values from params + float rbase = params.filmNegative.refInput.r; // redBase; + float gbase = params.filmNegative.refInput.g; // greenBase; + float bbase = params.filmNegative.refInput.b; // blueBase; + + // Reconstruct scale_mul coefficients from thumbnail metadata: + // redMultiplier / camwbRed is pre_mul[0] + // pre_mul[0] * scaleGain is scale_mul[0] + // Apply channel scaling to raw (unscaled) input base values, to + // match with actual (scaled) data in baseImg + rbase *= (redMultiplier / camwbRed) * scaleGain; + gbase *= (greenMultiplier / camwbGreen) * scaleGain; + bbase *= (blueMultiplier / camwbBlue) * scaleGain; + + if (settings->verbose) { + printf("FilmNeg legacy V2 :: Thumbnail input film base values: %g %g %g\n", rbase, gbase, bbase); + } + + // Apply exponents to get output film base values + rbase = powf(rbase, rexp); + gbase = powf(gbase, gexp); + bbase = powf(bbase, bexp); + + // Calculate multipliers so that film base value is 1/512th of the output range. + rmult = (MAX_OUT_VALUE / 512.f) / rbase; + gmult = (MAX_OUT_VALUE / 512.f) / gbase; + bmult = (MAX_OUT_VALUE / 512.f) / bbase; + + } + + + // Get and un-apply multipliers to adapt the thumbnail to a known fixed WB setting, + // as in the main image processing. + + double r, g, b; + ColorTemp(3500., 1., 1., "Custom").getMultipliers(r, g, b); + //iColorMatrix is cam_rgb + const double rm = camwbRed / (iColorMatrix[0][0] * r + iColorMatrix[0][1] * g + iColorMatrix[0][2] * b); + const double gm = camwbGreen / (iColorMatrix[1][0] * r + iColorMatrix[1][1] * g + iColorMatrix[1][2] * b); + const double bm = camwbBlue / (iColorMatrix[2][0] * r + iColorMatrix[2][1] * g + iColorMatrix[2][2] * b); + + // Normalize max WB multiplier to 1.f + const double m = max(rm, gm, bm); + rmult /= rm / m; + gmult /= gm / m; + bmult /= bm / m; + + + if (settings->verbose) { + printf("FilmNeg legacy V2 :: Thumbnail computed multipliers: %g %g %g\n", static_cast(rmult), static_cast(gmult), static_cast(bmult)); + } + + +#ifdef __SSE2__ + const vfloat clipv = F2V(MAXVALF); + const vfloat rexpv = F2V(rexp); + const vfloat gexpv = F2V(gexp); + const vfloat bexpv = F2V(bexp); + const vfloat rmultv = F2V(rmult); + const vfloat gmultv = F2V(gmult); + const vfloat bmultv = F2V(bmult); +#endif + + for (int i = 0; i < rheight; i++) { + float *rline = baseImg->r(i); + float *gline = baseImg->g(i); + float *bline = baseImg->b(i); + int j = 0; +#ifdef __SSE2__ + + for (; j < rwidth - 3; j += 4) { + STVFU(rline[j], vminf(rmultv * pow_F(LVFU(rline[j]), rexpv), clipv)); + STVFU(gline[j], vminf(gmultv * pow_F(LVFU(gline[j]), gexpv), clipv)); + STVFU(bline[j], vminf(bmultv * pow_F(LVFU(bline[j]), bexpv), clipv)); + } + +#endif + + for (; j < rwidth; ++j) { + rline[j] = CLIP(rmult * pow_F(rline[j], rexp)); + gline[j] = CLIP(gmult * pow_F(gline[j], gexp)); + bline[j] = CLIP(bmult * pow_F(bline[j], bexp)); + } + } +} + +// ----------------- <<< legacy mode <<< ------------ + + diff --git a/rtengine/filmnegativethumb.cc b/rtengine/filmnegativethumb.cc deleted file mode 100644 index 57f2601f9..000000000 --- a/rtengine/filmnegativethumb.cc +++ /dev/null @@ -1,237 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2019 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 "colortemp.h" -#include "LUT.h" -#include "rtengine.h" -#include "rtthumbnail.h" -#include "opthelper.h" -#include "sleef.h" -#include "rt_algo.h" -#include "settings.h" -#include "procparams.h" -#define BENCHMARK -#include "StopWatch.h" - -namespace -{ - -using rtengine::Imagefloat; -using rtengine::findMinMaxPercentile; - - -void calcMedians( - const Imagefloat* baseImg, - const int x1, const int y1, - const int x2, const int y2, - float &rmed, float &gmed, float &bmed -) -{ - // Channel vectors to calculate medians - std::vector rv, gv, bv; - - const int sz = std::max(0, (y2 - y1) * (x2 - x1)); - rv.reserve(sz); - gv.reserve(sz); - bv.reserve(sz); - - for (int i = y1; i < y2; i++) { - for (int j = x1; j < x2; j++) { - rv.push_back(baseImg->r(i, j)); - gv.push_back(baseImg->g(i, j)); - bv.push_back(baseImg->b(i, j)); - } - } - - // Calculate channel medians from whole image - findMinMaxPercentile(rv.data(), rv.size(), 0.5f, rmed, 0.5f, rmed, true); - findMinMaxPercentile(gv.data(), gv.size(), 0.5f, gmed, 0.5f, gmed, true); - findMinMaxPercentile(bv.data(), bv.size(), 0.5f, bmed, 0.5f, bmed, true); -} - -} - -void rtengine::Thumbnail::processFilmNegative( - const procparams::ProcParams ¶ms, - const Imagefloat* baseImg, - const int rwidth, const int rheight -) -{ - - // Channel exponents - const float rexp = -params.filmNegative.redRatio * params.filmNegative.greenExp; - const float gexp = -params.filmNegative.greenExp; - const float bexp = -params.filmNegative.blueRatio * params.filmNegative.greenExp; - - // Calculate output multipliers - float rmult, gmult, bmult; - - const float MAX_OUT_VALUE = 65000.f; - - // For backwards compatibility with profiles saved by RT 5.7 - const bool oldChannelScaling = params.filmNegative.redBase == -1.f; - - // If the film base values are not set in params, estimate multipliers from each channel's median value. - if (params.filmNegative.redBase <= 0.f) { - - // Channel medians - float rmed, gmed, bmed; - - if (oldChannelScaling) { - // If using the old method, calculate nedians on the whole image - calcMedians(baseImg, 0, 0, rwidth, rheight, rmed, gmed, bmed); - } else { - // The new method cuts out a 20% border from medians calculation. - const int bW = rwidth * 20 / 100; - const int bH = rheight * 20 / 100; - calcMedians(baseImg, bW, bH, rwidth - bW, rheight - bH, rmed, gmed, bmed); - } - - if (settings->verbose) { - printf("Thumbnail input channel medians: %g %g %g\n", rmed, gmed, bmed); - } - - // Calculate output medians - rmed = powf(rmed, rexp); - gmed = powf(gmed, gexp); - bmed = powf(bmed, bexp); - - // Calculate output multipliers so that the median value is 1/24 of the output range. - rmult = (MAX_OUT_VALUE / 24.f) / rmed; - gmult = (MAX_OUT_VALUE / 24.f) / gmed; - bmult = (MAX_OUT_VALUE / 24.f) / bmed; - - } else { - - // Read film-base values from params - float rbase = params.filmNegative.redBase; - float gbase = params.filmNegative.greenBase; - float bbase = params.filmNegative.blueBase; - - // Reconstruct scale_mul coefficients from thumbnail metadata: - // redMultiplier / camwbRed is pre_mul[0] - // pre_mul[0] * scaleGain is scale_mul[0] - // Apply channel scaling to raw (unscaled) input base values, to - // match with actual (scaled) data in baseImg - rbase *= (redMultiplier / camwbRed) * scaleGain; - gbase *= (greenMultiplier / camwbGreen) * scaleGain; - bbase *= (blueMultiplier / camwbBlue) * scaleGain; - - if (settings->verbose) { - printf("Thumbnail input film base values: %g %g %g\n", rbase, gbase, bbase); - } - - // Apply exponents to get output film base values - rbase = powf(rbase, rexp); - gbase = powf(gbase, gexp); - bbase = powf(bbase, bexp); - - if (settings->verbose) { - printf("Thumbnail output film base values: %g %g %g\n", rbase, gbase, bbase); - } - - // Calculate multipliers so that film base value is 1/512th of the output range. - rmult = (MAX_OUT_VALUE / 512.f) / rbase; - gmult = (MAX_OUT_VALUE / 512.f) / gbase; - bmult = (MAX_OUT_VALUE / 512.f) / bbase; - - } - - - if (oldChannelScaling) { - // Need to calculate channel averages, to fake the same conditions - // found in rawimagesource, where get_ColorsCoeff is called with - // forceAutoWB=true. - float rsum = 0.f, gsum = 0.f, bsum = 0.f; - - for (int i = 0; i < rheight; i++) { - for (int j = 0; j < rwidth; j++) { - rsum += baseImg->r(i, j); - gsum += baseImg->g(i, j); - bsum += baseImg->b(i, j); - } - } - - const float ravg = rsum / (rheight * rwidth); - const float gavg = gsum / (rheight * rwidth); - const float bavg = bsum / (rheight * rwidth); - - // Shifting current WB multipliers, based on channel averages. - rmult /= gavg / ravg; - // gmult /= gAvg / gAvg; green chosen as reference channel - bmult /= gavg / bavg; - - } else { - - // Get and un-apply multipliers to adapt the thumbnail to a known fixed WB setting, - // as in the main image processing. - - double r, g, b; - ColorTemp(3500., 1., 1., "Custom").getMultipliers(r, g, b); - //iColorMatrix is cam_rgb - const double rm = camwbRed / (iColorMatrix[0][0] * r + iColorMatrix[0][1] * g + iColorMatrix[0][2] * b); - const double gm = camwbGreen / (iColorMatrix[1][0] * r + iColorMatrix[1][1] * g + iColorMatrix[1][2] * b); - const double bm = camwbBlue / (iColorMatrix[2][0] * r + iColorMatrix[2][1] * g + iColorMatrix[2][2] * b); - - // Normalize max WB multiplier to 1.f - const double m = max(rm, gm, bm); - rmult /= rm / m; - gmult /= gm / m; - bmult /= bm / m; - } - - - if (settings->verbose) { - printf("Thumbnail computed multipliers: %g %g %g\n", static_cast(rmult), static_cast(gmult), static_cast(bmult)); - } - - -#ifdef __SSE2__ - const vfloat clipv = F2V(MAXVALF); - const vfloat rexpv = F2V(rexp); - const vfloat gexpv = F2V(gexp); - const vfloat bexpv = F2V(bexp); - const vfloat rmultv = F2V(rmult); - const vfloat gmultv = F2V(gmult); - const vfloat bmultv = F2V(bmult); -#endif - - for (int i = 0; i < rheight; i++) { - float *rline = baseImg->r(i); - float *gline = baseImg->g(i); - float *bline = baseImg->b(i); - int j = 0; -#ifdef __SSE2__ - - for (; j < rwidth - 3; j += 4) { - STVFU(rline[j], vminf(rmultv * pow_F(LVFU(rline[j]), rexpv), clipv)); - STVFU(gline[j], vminf(gmultv * pow_F(LVFU(gline[j]), gexpv), clipv)); - STVFU(bline[j], vminf(bmultv * pow_F(LVFU(bline[j]), bexpv), clipv)); - } - -#endif - - for (; j < rwidth; ++j) { - rline[j] = CLIP(rmult * pow_F(rline[j], rexp)); - gline[j] = CLIP(gmult * pow_F(gline[j], gexp)); - bline[j] = CLIP(bmult * pow_F(bline[j], bexp)); - } - } -} 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..3f5e00e05 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,54 +78,76 @@ 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.getWidth(); + const int H = src.getHeight(); + + 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(); + const int w = res.getWidth(); + const int h = res.getHeight(); #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; + 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()) { + if (d.getWidth() == s.getWidth() && d.getHeight() == s.getHeight()) { #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) { + for (int y = 0; y < s.getHeight(); ++y) { + for (int x = 0; x < s.getWidth(); ++x) { d[y][x] = s[y][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(static_cast(s), static_cast(d), rad, s.width(), s.height(), multithread); + rad = LIM(rad, 0, (min(s.getWidth(), s.getHeight()) - 1) / 2 - 1); + // boxblur(s, d, rad, s.getWidth(), s.getHeight(), multithread); + boxblur(static_cast(s), static_cast(d), rad, s.getWidth(), s.getHeight(), 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.getWidth(); + const int Hs = meana.getHeight(); + const int Wd = q.getWidth(); + const int Hd = q.getHeight(); + 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.getHeight(); ++y) { + for (int x = 0; x < chan.getWidth(); ++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.getHeight(); ++y) { + for (int x = 0; x < chan.getWidth(); ++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/histmatching.cc b/rtengine/histmatching.cc index 0053cb0d4..d3c5d0190 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -279,7 +279,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st { RawMetaDataLocation rml; eSensorType sensor_type; - int w, h; + int w = 0, h = 0; std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true, true)); if (!thumb) { if (settings->verbose) { diff --git a/rtengine/homogeneouscoordinates.cc b/rtengine/homogeneouscoordinates.cc new file mode 100644 index 000000000..85b189b9f --- /dev/null +++ b/rtengine/homogeneouscoordinates.cc @@ -0,0 +1,191 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Lawrence Lee + * + * 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 "homogeneouscoordinates.h" + +namespace rtengine +{ + +template +homogeneous::Vector operator*(const homogeneous::Matrix& a, const homogeneous::Vector& b) +{ + homogeneous::Vector prod; + + prod.fill(0); + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + prod[i] += a[i][j] * b[j]; + } + } + + return prod; +} + +template +homogeneous::Matrix operator*(const homogeneous::Matrix& a, const homogeneous::Matrix& b) +{ + homogeneous::Matrix prod; + + for (int i = 0; i < 4; i++) { + prod[i].fill(0); + + for (int j = 0; j < 4; j++) { + for (int k = 0; k < 4; k++) { + prod[i][j] += a[i][k] * b[k][j]; + } + } + } + + return prod; +} + +namespace homogeneous +{ + +template +Matrix projectionMatrix(T location, Axis normal) +{ + Matrix matrix; + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + matrix[i][j] = 0; + } + } + + matrix[0][0] = location; + matrix[1][1] = location; + matrix[2][2] = location; + matrix[3][3] = 0; + + switch (normal) { + case X: + matrix[3][0] = 1; + break; + + case Y: + matrix[3][1] = 1; + break; + + case Z: + matrix[3][2] = 1; + break; + } + + return matrix; +} + +template +Matrix rotationMatrix(double radians, Axis axis) +{ + Matrix matrix; + + switch (axis) { + case X: + matrix[0][0] = 1; + matrix[0][1] = 0; + matrix[0][2] = 0; + matrix[1][0] = 0; + matrix[1][1] = cos(radians); + matrix[1][2] = -sin(radians); + matrix[2][0] = 0; + matrix[2][1] = sin(radians); + matrix[2][2] = cos(radians); + break; + + case Y: + matrix[0][0] = cos(radians); + matrix[0][1] = 0; + matrix[0][2] = sin(radians); + matrix[1][0] = 0; + matrix[1][1] = 1; + matrix[1][2] = 0; + matrix[2][0] = -sin(radians); + matrix[2][1] = 0; + matrix[2][2] = cos(radians); + break; + + case Z: + matrix[0][0] = cos(radians); + matrix[0][1] = -sin(radians); + matrix[0][2] = 0; + matrix[1][0] = sin(radians); + matrix[1][1] = cos(radians); + matrix[1][2] = 0; + matrix[2][0] = 0; + matrix[2][1] = 0; + matrix[2][2] = 1; + break; + } + + matrix[0][3] = 0; + matrix[1][3] = 0; + matrix[2][3] = 0; + matrix[3][0] = 0; + matrix[3][1] = 0; + matrix[3][2] = 0; + matrix[3][3] = 1; + + return matrix; +} + +template +Matrix scaleMatrix(T x, T y, T z) +{ + Matrix matrix; + + for (int i = 0; i < 4; i++) { + matrix[i].fill(0); + } + + matrix[0][0] = x; + matrix[1][1] = y; + matrix[2][2] = z; + matrix[3][3] = 1; + + return matrix; +} + +template +Matrix translationMatrix(T x, T y, T z) +{ + Matrix matrix; + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 3; j++) { + matrix[i][j] = 0; + } + } + + matrix[0][0] = 1; + matrix[1][1] = 1; + matrix[2][2] = 1; + matrix[0][3] = x; + matrix[1][3] = y; + matrix[2][3] = z; + matrix[3][3] = 1; + + return matrix; +} + +} + +} diff --git a/rtengine/homogeneouscoordinates.h b/rtengine/homogeneouscoordinates.h new file mode 100644 index 000000000..12a2227ae --- /dev/null +++ b/rtengine/homogeneouscoordinates.h @@ -0,0 +1,84 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Lawrence Lee + * + * 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 + +namespace rtengine +{ + +namespace homogeneous +{ + +enum Axis {X, Y, Z}; + +template +using Matrix = std::array, 4>; + +/** + * 3 dimensional homogeneous vector. + */ +template +using Vector = std::array; + +/** + * Creates a 3 dimensional transformation matrix for projection onto a plane. + * @param location Distance from the origin to the plane. + * @param normal Direction of the plane's normal. + */ +template +Matrix projectionMatrix(T location, Axis normal); + +/** + * Creates a 3 dimensional transformation matrix for rotation. + * @param radians Rotation angle. + * @param axis Axis of rotation. + */ +template +Matrix rotationMatrix(double radians, Axis axis); + +/** + * Creates a 3 dimensional transformation matrix for scaling. + * @param x Scale in x-direction + * @param y Scale in y-direction + * @param z Scale in z-direction + */ +template +Matrix scaleMatrix(T x, T y, T z); + +/** + * Creates a 3 dimensional transformation matrix for translation. + * @param x Translation in the the x-direction. + * @param y Translation in the the y-direction. + * @param z Translation in the the z-direction. + */ +template +Matrix translationMatrix(T x, T y, T z); + +} + +template +homogeneous::Vector operator*(const homogeneous::Matrix& a, const homogeneous::Vector& b); + +template +homogeneous::Matrix operator*(const homogeneous::Matrix& a, const homogeneous::Matrix& b); + +} + +#include "homogeneouscoordinates.cc" diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 6b2be1713..2f443522c 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -351,7 +351,7 @@ cmsHPROFILE rtengine::ProfileContent::toProfile() const double slope = slopetag == 0 ? eps : slopetag; GammaValues g_b; //gamma parameters - Color::calcGamma(pwr, ts, 0, g_b); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 + Color::calcGamma(pwr, ts, g_b); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 cmsFloat64Number gammaParams[7]; //gamma parameters gammaParams[4] = g_b[3] * ts; gammaParams[0] = gammatag; @@ -1151,102 +1151,6 @@ std::vector rtengine::ICCStore::getWorkingProfiles() return implementation->getWorkingProfiles(); } -// WARNING: the caller must lock lcmsMutex -cmsHPROFILE rtengine::ICCStore::makeStdGammaProfile(cmsHPROFILE iprof) -{ - // forgive me for the messy code, quick hack to change gamma of an ICC profile to the RT standard gamma - if (!iprof) { - return nullptr; - } - - cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem(iprof, nullptr, &bytesNeeded); - - if (bytesNeeded == 0) { - return nullptr; - } - - uint8_t *data = new uint8_t[bytesNeeded + 1]; - cmsSaveProfileToMem(iprof, data, &bytesNeeded); - const uint8_t *p = &data[128]; // skip 128 byte header - uint32_t tag_count; - memcpy(&tag_count, p, 4); - p += 4; - tag_count = ntohl(tag_count); - - struct icctag { - uint32_t sig; - uint32_t offset; - uint32_t size; - } tags[tag_count]; - - constexpr uint32_t gamma = 0x239; - constexpr int gamma_size = 14; - int data_size = (gamma_size + 3) & ~3; - - for (uint32_t i = 0; i < tag_count; i++) { - memcpy(&tags[i], p, 12); - tags[i].sig = ntohl(tags[i].sig); - tags[i].offset = ntohl(tags[i].offset); - tags[i].size = ntohl(tags[i].size); - p += 12; - - if (tags[i].sig != 0x62545243 && // bTRC - tags[i].sig != 0x67545243 && // gTRC - tags[i].sig != 0x72545243 && // rTRC - tags[i].sig != 0x6B545243) { // kTRC - data_size += (tags[i].size + 3) & ~3; - } - } - - uint32_t sz = 128 + 4 + tag_count * 12 + data_size; - uint8_t *nd = new uint8_t[sz]; - memset(nd, 0, sz); - memcpy(nd, data, 128 + 4); - sz = htonl(sz); - memcpy(nd, &sz, 4); - uint32_t offset = 128 + 4 + tag_count * 12; - uint32_t gamma_offset = 0; - - for (uint32_t i = 0; i < tag_count; i++) { - struct icctag tag; - tag.sig = htonl(tags[i].sig); - - if (tags[i].sig == 0x62545243 || // bTRC - tags[i].sig == 0x67545243 || // gTRC - tags[i].sig == 0x72545243 || // rTRC - tags[i].sig == 0x6B545243) { // kTRC - if (gamma_offset == 0) { - gamma_offset = offset; - uint32_t pcurve[] = { htonl(0x63757276), htonl(0), htonl(/*gamma_size == 12 ? 0U : */1U) }; - memcpy(&nd[offset], pcurve, 12); - - //if (gamma_size == 14) { - uint16_t gm = htons(gamma); - memcpy(&nd[offset + 12], &gm, 2); - //} - - offset += (gamma_size + 3) & ~3; - } - - tag.offset = htonl(gamma_offset); - tag.size = htonl(gamma_size); - } else { - tag.offset = htonl(offset); - tag.size = htonl(tags[i].size); - memcpy(&nd[offset], &data[tags[i].offset], tags[i].size); - offset += (tags[i].size + 3) & ~3; - } - - memcpy(&nd[128 + 4 + i * 12], &tag, 12); - } - - cmsHPROFILE oprof = cmsOpenProfileFromMem(nd, ntohl(sz)); - delete [] nd; - delete [] data; - return oprof; -} - cmsHPROFILE rtengine::ICCStore::createFromMatrix(const double matrix[3][3], bool gamma, const Glib::ustring& name) { diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 117124122..fb2331263 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -96,7 +96,6 @@ public: /*static*/ std::vector getWorkingProfiles(); - static cmsHPROFILE makeStdGammaProfile(cmsHPROFILE iprof); static cmsHPROFILE createFromMatrix(const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); private: diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 2928740cf..bdf069957 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -1862,9 +1862,6 @@ public: * @return The mutex */ virtual MyMutex& getMutex () = 0; virtual cmsHPROFILE getProfile () const = 0; - /** @brief Returns the bits per pixel of the image. - * @return The bits per pixel of the image */ - virtual int getBitsPerPixel () const = 0; /** @brief Saves the image to file. It autodetects the format (jpg, tif, png are supported). * @param fname is the name of the file @return the error code, 0 if none */ @@ -1889,8 +1886,6 @@ public: /** @brief Sets the progress listener if you want to follow the progress of the image saving operations (optional). * @param pl is the pointer to the class implementing the ProgressListener interface */ virtual void setSaveProgressListener (ProgressListener* pl) = 0; - /** @brief Free the image */ - virtual void free () = 0; }; /** @brief This class represents an image having a float pixel planar representation. diff --git a/rtengine/image16.cc b/rtengine/image16.cc index d5a255227..ae981c7bd 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -272,10 +272,10 @@ void Image16::getStdImage(const ColorTemp &ctemp, int tran, Imagefloat* image, c lineB[dst_x] = CLIP(bm * btot); } else { // computing a special factor for this incomplete sub-region - float area = src_sub_width * src_sub_height; - lineR[dst_x] = CLIP(rm2 * rtot / area); - lineG[dst_x] = CLIP(gm2 * gtot / area); - lineB[dst_x] = CLIP(bm2 * btot / area); + float larea = src_sub_width * src_sub_height; + lineR[dst_x] = CLIP(rm2 * rtot / larea); + lineG[dst_x] = CLIP(gm2 * gtot / larea); + lineB[dst_x] = CLIP(bm2 * btot / larea); } } } @@ -309,21 +309,6 @@ void Image16::getStdImage(const ColorTemp &ctemp, int tran, Imagefloat* image, c #undef GCLIP } -Image8* Image16::to8() const -{ - Image8* img8 = new Image8(width, height); - - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { - img8->r(h, w) = uint16ToUint8Rounded(r(h, w)); - img8->g(h, w) = uint16ToUint8Rounded(g(h, w)); - img8->b(h, w) = uint16ToUint8Rounded(b(h, w)); - } - } - - return img8; -} - // Parallelized transformation; create transform with cmsFLAGS_NOCACHE! void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform) { diff --git a/rtengine/image16.h b/rtengine/image16.h index 9d781955a..25b777832 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -41,8 +41,6 @@ public: Image16* copy() const; Image16* copySubRegion (int x, int y, int width, int height); - Image8* to8() const; - void getStdImage(const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp) const override; const char* getType() const override @@ -68,11 +66,6 @@ public: return getEmbeddedProfile(); } - int getBitsPerPixel() const override - { - return 8 * sizeof(unsigned short); - } - int saveToFile(const Glib::ustring &fname) const override { return save(fname); @@ -98,10 +91,6 @@ public: setProgressListener(pl); } - void free() override - { - delete this; - } void ExecCMSTransform(cmsHTRANSFORM hTransform); /* void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); */ diff --git a/rtengine/image8.h b/rtengine/image8.h index a8d20b927..76a580bb6 100644 --- a/rtengine/image8.h +++ b/rtengine/image8.h @@ -64,11 +64,6 @@ public: return getEmbeddedProfile (); } - int getBitsPerPixel () const override - { - return 8 * sizeof(unsigned char); - } - int saveToFile (const Glib::ustring &fname) const override { return save (fname); @@ -94,11 +89,6 @@ public: setProgressListener (pl); } - void free () override - { - delete this; - } - }; } diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index a631a6c8d..16b6a4c91 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", "?"); } } @@ -69,11 +69,20 @@ T getFromFrame( return {}; } +const std::string& validateUft8(const std::string& str, const std::string& on_error = "???") +{ + if (Glib::ustring(str).validate()) { + return str; + } + + return on_error; } -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 +122,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(); + make = validateUft8(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,8 +165,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } tag = newFrameRootDir->findTagUpward("Model"); + if (tag) { - model = tag->valueToString(); + model = validateUft8(tag->valueToString()); } if (!model.empty()) { @@ -179,7 +192,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 { @@ -189,13 +202,14 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* if (model == "Unknown") { tag = newFrameRootDir->findTag("UniqueCameraModel"); if (tag) { - model = tag->valueToString(); + model = validateUft8(tag->valueToString()); } } tag = newFrameRootDir->findTagUpward("Orientation"); + if (tag) { - orientation = tag->valueToString (); + orientation = validateUft8(tag->valueToString()); } // Look for Rating metadata in the following order: @@ -217,45 +231,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 +299,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,14 +312,14 @@ 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) { - serial = tag->valueToString(); + serial = validateUft8(tag->valueToString()); } // guess lens... @@ -311,15 +327,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 = validateUft8(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(); } } @@ -340,9 +356,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* const rtexif::Tag* const lens_make = exif->getTag(0xA433); const std::string make = lens_make - ? lens_make->valueToString() + ? validateUft8(lens_make->valueToString()) : std::string(); - const std::string model = lens_model->valueToString(); + const std::string model = validateUft8(lens_model->valueToString()); if (!model.empty()) { lens = make; @@ -362,7 +378,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 +390,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 = validateUft8(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, validateUft8(exif->getTag("FocalLength")->valueToString())); - if(mnote->getTag ("LensType")) { - std::string ltype = mnote->getTag ("LensType")->valueToString (); + if (mnote->getTag("LensType")) { + const std::string ltype = validateUft8(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 +424,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")) { + const std::string ldata = validateUft8(mnote->getTag("Lens")->valueToString()); size_t i = 0, j = 0; double n[4] = {0.0}; @@ -429,7 +445,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 +461,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")) { + const std::string ltype = validateUft8(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,9 +485,9 @@ 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 (); + const std::string ldata = validateUft8(lt->valueToString()); if (ldata.size() > 1) { found = true; @@ -491,8 +507,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) { + const std::string ldata = validateUft8(lt->valueToString()); if (ldata.size() > 1) { lens = ldata; @@ -503,15 +519,18 @@ 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")) { - lens = mnote->getTag ("LensType")->valueToString(); + + if (mnote->getTag("LensType")) { + lens = validateUft8(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 if (lens == "M-42 or No Lens" || lens == "K or M Lens" || lens == "A Series Lens" || lens == "Sigma") { @@ -522,61 +541,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 (); + lens = validateUft8(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 = validateUft8(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(); + const std::string panalens = validateUft8(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 = validateUft8(exif->getTag("DNGLensInfo")->valueToString()); } else if (!lens_from_make_and_model() && exif->getTag ("LensInfo")) { - lens = exif->getTag ("LensInfo")->valueToString (); + lens = validateUft8(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 +609,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 +621,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 +674,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 +755,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 +781,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 +806,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 +841,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 +853,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 +933,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 +957,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 +972,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 +1243,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); + snprintf(buffer, sizeof(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); + snprintf(buffer, sizeof(buffer), "1/%0.0f", 1.0 / shutter); } else { - sprintf (buffer, "%0.1f", shutter); + snprintf(buffer, sizeof(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); + snprintf(buffer, sizeof(buffer), "%0.2f", expcomp); return buffer; } else { return ""; } } else { - sprintf (buffer, "%0.2f", expcomp); + snprintf(buffer, sizeof(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 +1314,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 +1326,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 +1387,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 +1397,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 +1433,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/imagefloat.cc b/rtengine/imagefloat.cc index 6af835d2b..7bc75fe6d 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -302,10 +302,10 @@ void Imagefloat::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* imag lineB[dst_x] = CLIP0(bm * btot); } else { // computing a special factor for this incomplete sub-region - float area = src_sub_width * src_sub_height; - lineR[dst_x] = CLIP0(rm2 * rtot / area); - lineG[dst_x] = CLIP0(gm2 * gtot / area); - lineB[dst_x] = CLIP0(bm2 * btot / area); + float larea = src_sub_width * src_sub_height; + lineR[dst_x] = CLIP0(rm2 * rtot / larea); + lineG[dst_x] = CLIP0(gm2 * gtot / larea); + lineB[dst_x] = CLIP0(bm2 * btot / larea); } } } @@ -341,53 +341,15 @@ void Imagefloat::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* imag #endif } -Image8* -Imagefloat::to8() const -{ - Image8* img8 = new Image8(width, height); -#ifdef _OPENMP - #pragma omp parallel for schedule(static) -#endif - - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { - img8->r(h, w) = uint16ToUint8Rounded(CLIP(r(h, w))); - img8->g(h, w) = uint16ToUint8Rounded(CLIP(g(h, w))); - img8->b(h, w) = uint16ToUint8Rounded(CLIP(b(h, w))); - } - } - - return img8; -} - -Image16* -Imagefloat::to16() const -{ - Image16* img16 = new Image16(width, height); -#ifdef _OPENMP - #pragma omp parallel for schedule(static) -#endif - - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { - img16->r(h, w) = CLIP(r(h, w)); - img16->g(h, w) = CLIP(g(h, w)); - img16->b(h, w) = CLIP(b(h, w)); - } - } - - return img16; -} - void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal) { - float scale = MAXVALF / (srcMaxVal - srcMinVal); - int w = width; - int h = height; + const float scale = MAXVALF / (srcMaxVal - srcMinVal); + const int w = width; + const int h = height; #ifdef _OPENMP - #pragma omp parallel for firstprivate(w, h, srcMinVal, scale) schedule(dynamic, 5) + #pragma omp parallel for schedule(dynamic, 5) #endif for (int y = 0; y < h; y++) { @@ -403,11 +365,11 @@ void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal) void Imagefloat::normalizeFloatTo1() { - int w = width; - int h = height; + const int w = width; + const int h = height; #ifdef _OPENMP - #pragma omp parallel for firstprivate(w, h) schedule(dynamic, 5) + #pragma omp parallel for schedule(dynamic, 5) #endif for (int y = 0; y < h; y++) { @@ -423,11 +385,11 @@ void Imagefloat::normalizeFloatTo1() void Imagefloat::normalizeFloatTo65535() { - int w = width; - int h = height; + const int w = width; + const int h = height; #ifdef _OPENMP - #pragma omp parallel for firstprivate(w, h) schedule(dynamic, 5) + #pragma omp parallel for schedule(dynamic, 5) #endif for (int y = 0; y < h; y++) { @@ -439,59 +401,6 @@ void Imagefloat::normalizeFloatTo65535() } } -void Imagefloat::calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist) -{ - - hist.clear(); - - // Set up factors to calc the lightness - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.workingProfile); - - float facRed = wprof[1][0]; - float facGreen = wprof[1][1]; - float facBlue = wprof[1][2]; - - - // calc pixel size - int x1, x2, y1, y2; - params.crop.mapToResized(width, height, scale, x1, x2, y1, y2); - -#ifdef _OPENMP - #pragma omp parallel -#endif - { - LUTu histThr(65536); - histThr.clear(); -#ifdef _OPENMP - #pragma omp for nowait -#endif - - for (int y = y1; y < y2; y++) { - for (int x = x1; x < x2; x++) { - int i = (int)(facRed * r(y, x) + facGreen * g(y, x) + facBlue * b(y, x)); - - if (i < 0) { - i = 0; - } else if (i > 65535) { - i = 65535; - } - - histThr[i]++; - } - } - -#ifdef _OPENMP - #pragma omp critical -#endif - { - for(int i = 0; i <= 0xffff; i++) { - hist[i] += histThr[i]; - } - } - } - -} - // Parallelized transformation; create transform with cmsFLAGS_NOCACHE! void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform) { diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index 769bc24fe..fc3ba318d 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -46,9 +46,6 @@ public: Imagefloat* copy () const; Imagefloat* copySubRegion (int x, int y, int width, int height); - Image8* to8() const; - Image16* to16() const; - void getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp) const override; const char* getType () const override @@ -73,10 +70,6 @@ public: { return getEmbeddedProfile (); } - int getBitsPerPixel () const override - { - return 8 * sizeof(float); - } int saveToFile (const Glib::ustring &fname) const override { return save (fname); @@ -97,10 +90,6 @@ public: { setProgressListener (pl); } - void free () override - { - delete this; - } inline uint16_t DNG_FloatToHalf(float f) const { @@ -110,35 +99,35 @@ public: } tmp; tmp.f = f; - int32_t sign = (tmp.i >> 16) & 0x00008000; + const int32_t lsign = (tmp.i >> 16) & 0x00008000; int32_t exponent = ((tmp.i >> 23) & 0x000000ff) - (127 - 15); - int32_t mantissa = tmp.i & 0x007fffff; + int32_t mantissa = tmp.i & 0x007fffff; if (exponent <= 0) { if (exponent < -10) { - return (uint16_t)sign; + return (uint16_t)lsign; } mantissa = (mantissa | 0x00800000) >> (1 - exponent); if (mantissa & 0x00001000) mantissa += 0x00002000; - return (uint16_t)(sign | (mantissa >> 13)); + return (uint16_t)(lsign | (mantissa >> 13)); } else if (exponent == 0xff - (127 - 15)) { if (mantissa == 0) { - return (uint16_t)(sign | 0x7c00); + return (uint16_t)(lsign | 0x7c00); } else { - return (uint16_t)(sign | 0x7c00 | (mantissa >> 13)); + return (uint16_t)(lsign | 0x7c00 | (mantissa >> 13)); } } if (mantissa & 0x00001000) { mantissa += 0x00002000; if (mantissa & 0x00800000) { - mantissa = 0; // overflow in significand, + mantissa = 0; // overflow in significand, exponent += 1; // adjust exponent } } if (exponent > 30) { - return (uint16_t)(sign | 0x7c00); // infinity with the same sign as f. + return (uint16_t)(lsign | 0x7c00); // infinity with the same sign as f. } - return (uint16_t)(sign | (exponent << 10) | (mantissa >> 13)); + return (uint16_t)(lsign | (exponent << 10) | (mantissa >> 13)); } // From DNG SDK dng_utils.h @@ -149,13 +138,13 @@ public: uint32_t i; } tmp; - int32_t sign = (halfValue >> 15) & 0x00000001; + const int32_t lsign = (halfValue >> 15) & 0x00000001; int32_t exponent = (halfValue >> 10) & 0x0000001f; - int32_t mantissa = halfValue & 0x000003ff; + int32_t mantissa = halfValue & 0x000003ff; if (exponent == 0) { if (mantissa == 0) { // Plus or minus zero - tmp.i = (uint32_t) (sign << 31); + tmp.i = (uint32_t) (lsign << 31); return tmp.f; } else { // Denormalized number -- renormalize it @@ -169,7 +158,7 @@ public: } else if (exponent == 31) { if (mantissa == 0) { // Positive or negative infinity, convert to maximum (16 bit) values. - tmp.i = (uint32_t)((sign << 31) | ((0x1eL + 127 - 15) << 23) | (0x3ffL << 13)); + tmp.i = (uint32_t)((lsign << 31) | ((0x1eL + 127 - 15) << 23) | (0x3ffL << 13)); return tmp.f; } else { // Nan -- Just set to zero. @@ -180,32 +169,32 @@ public: exponent += (127 - 15); mantissa <<= 13; // Assemble sign, exponent and mantissa. - tmp.i = (uint32_t) ((sign << 31) | (exponent << 23) | mantissa); + tmp.i = (uint32_t) ((lsign << 31) | (exponent << 23) | mantissa); return tmp.f; } inline uint32_t DNG_FP24ToFloat(const uint8_t * input) { - int32_t sign = (input [0] >> 7) & 0x01; - int32_t exponent = (input [0] ) & 0x7F; - int32_t mantissa = (((int32_t) input [1]) << 8) | input[2]; + const int32_t lsign = (input[0] >> 7) & 0x01; + int32_t exponent = input[0] & 0x7F; + int32_t mantissa = (((int32_t) input[1]) << 8) | input[2]; if (exponent == 0) { if (mantissa == 0) { // Plus or minus zero - return (uint32_t) (sign << 31); + return (uint32_t) (lsign << 31); } else { // Denormalized number -- renormalize it while (!(mantissa & 0x00010000)) { - mantissa <<= 1; - exponent -= 1; - } - exponent += 1; - mantissa &= ~0x00010000; + mantissa <<= 1; + exponent -= 1; + } + exponent += 1; + mantissa &= ~0x00010000; } } else if (exponent == 127) { if (mantissa == 0) { // Positive or negative infinity, convert to maximum (24 bit) values. - return (uint32_t) ((sign << 31) | ((0x7eL + 128 - 64) << 23) | (0xffffL << 7)); + return (uint32_t) ((lsign << 31) | ((0x7eL + 128 - 64) << 23) | (0xffffL << 7)); } else { // Nan -- Just set to zero. return 0; @@ -215,13 +204,12 @@ public: exponent += (128 - 64); mantissa <<= 7; // Assemble sign, exponent and mantissa. - return (uint32_t) ((sign << 31) | (exponent << 23) | mantissa); + return (uint32_t) ((lsign << 31) | (exponent << 23) | mantissa); } void normalizeFloat(float srcMinVal, float srcMaxVal) override; void normalizeFloatTo1(); void normalizeFloatTo65535(); - void calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist); void ExecCMSTransform(cmsHTRANSFORM hTransform); void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); }; 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/imagesource.h b/rtengine/imagesource.h index ea049d37c..a1c3731f1 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -92,9 +92,6 @@ public: ~ImageSource () override {} virtual int load (const Glib::ustring &fname) = 0; virtual void preprocess (const procparams::RAWParams &raw, const procparams::LensProfParams &lensProf, const procparams::CoarseTransformParams& coarse, bool prepareDenoise = true) {}; - virtual void filmNegativeProcess (const procparams::FilmNegativeParams ¶ms, std::array& filmBaseValues) {}; - virtual bool getFilmNegativeExponents (Coord2D spotA, Coord2D spotB, int tran, const procparams::FilmNegativeParams& currentParams, std::array& newExps) { return false; }; - virtual bool getRawSpotValues (Coord2D spot, int spotSize, int tran, const procparams::FilmNegativeParams ¶ms, std::array& rawValues) { return false; }; virtual void demosaic (const procparams::RAWParams &raw, bool autoContrast, double &contrastThreshold, bool cache = false) {}; virtual void retinex (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &deh, const procparams::ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; virtual void retinexPrepareCurves (const procparams::RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; @@ -110,6 +107,7 @@ public: virtual int getFrameCount () = 0; virtual int getFlatFieldAutoClipValue () = 0; + virtual void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const = 0; // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw) = 0; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ba8fa2e95..6ab480d23 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -17,12 +17,11 @@ * along with RawTherapee. If not, see . */ #include -#include -#include #include #include "improccoordinator.h" +#include "array2D.h" #include "cieimage.h" #include "color.h" #include "colortemp.h" @@ -47,18 +46,8 @@ namespace { -using rtengine::Coord2D; -Coord2D translateCoord(const rtengine::ImProcFunctions& ipf, int fw, int fh, int x, int y) { - const std::vector points = {Coord2D(x, y)}; - - std::vector red; - std::vector green; - std::vector blue; - ipf.transCoord(fw, fh, points, red, green, blue); - - return green[0]; -} +constexpr int VECTORSCOPE_SIZE = 128; } @@ -130,6 +119,21 @@ ImProcCoordinator::ImProcCoordinator() : histLRETI(256), + hist_lrgb_dirty(false), + hist_raw_dirty(false), + + vectorscopeScale(0), + vectorscope_hc_dirty(false), + vectorscope_hs_dirty(false), + vectorscope_hc(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), + vectorscope_hs(VECTORSCOPE_SIZE, VECTORSCOPE_SIZE), + waveformScale(0), + waveform_dirty(false), + waveformRed(0, 0), + waveformGreen(0, 0), + waveformBlue(0, 0), + waveformLuma(0, 0), + CAMBrightCurveJ(), CAMBrightCurveQ(), rCurve(), @@ -155,6 +159,7 @@ ImProcCoordinator::ImProcCoordinator() : pdSharpenAutoRadiusListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), + filmNegListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), @@ -184,7 +189,50 @@ ImProcCoordinator::ImProcCoordinator() : highQualityComputed(false), customTransformIn(nullptr), customTransformOut(nullptr), - ipf(params.get(), true) + ipf(params.get(), true), + + // Locallab + locallListener(nullptr), + lllocalcurve(65536, LUT_CLIP_OFF), + cllocalcurve(65536, LUT_CLIP_OFF), + lclocalcurve(65536, LUT_CLIP_OFF), + cclocalcurve(65536, LUT_CLIP_OFF), + rgblocalcurve(65536, LUT_CLIP_OFF), + exlocalcurve(65536, LUT_CLIP_OFF), + hltonecurveloc(65536, LUT_CLIP_OFF), //32768 + shtonecurveloc(65536, LUT_CLIP_OFF), + tonecurveloc(65536, LUT_CLIP_OFF), + lightCurveloc(32770, LUT_CLIP_OFF), + lmasklocalcurve(65536, LUT_CLIP_OFF), + lmaskexplocalcurve(65536, LUT_CLIP_OFF), + lmaskSHlocalcurve(65536, LUT_CLIP_OFF), + lmaskviblocalcurve(65536, LUT_CLIP_OFF), + lmasktmlocalcurve(65536, LUT_CLIP_OFF), + lmaskretilocalcurve(65536, LUT_CLIP_OFF), + lmaskcblocalcurve(65536, LUT_CLIP_OFF), + lmaskbllocalcurve(65536, LUT_CLIP_OFF), + lmasklclocalcurve(65536, LUT_CLIP_OFF), + lmaskloglocalcurve(65536, LUT_CLIP_OFF), + lmasklocal_curve(65536, LUT_CLIP_OFF), + 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), + localllogMask(0), + locall_Mask(0), + retistrsav(nullptr) { } @@ -271,6 +319,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); @@ -330,28 +379,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); + hist_raw_dirty = !(hListener && hListener->updateHistogramRaw()); highDetailPreprocessComputed = highDetailNeeded; - - // After preprocess, run film negative processing if enabled - if ( - (todo & M_RAW) - && ( - imgsrc->getSensorType() == ST_BAYER - || imgsrc->getSensorType() == ST_FUJI_XTRANS - ) - && params->filmNegative.enabled - ) { - std::array filmBaseValues = { - static_cast(params->filmNegative.redBase), - static_cast(params->filmNegative.greenBase), - static_cast(params->filmNegative.blueBase) - }; - imgsrc->filmNegativeProcess(params->filmNegative, filmBaseValues); - if (filmNegListener && params->filmNegative.redBase <= 0.f) { - filmNegListener->filmBaseValuesChanged(filmBaseValues); - } - } } /* @@ -403,6 +433,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); @@ -412,9 +443,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); } @@ -620,7 +653,27 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } */ - imgsrc->convertColorSpace(orig_prev, params->icm, currWB); + + if (params->filmNegative.enabled) { + + // Process film negative AFTER colorspace conversion + if (params->filmNegative.colorSpace != FilmNegativeParams::ColorSpace::INPUT) { + imgsrc->convertColorSpace(orig_prev, params->icm, currWB); + } + + // Perform negative inversion. If needed, upgrade filmNegative params for backwards compatibility with old profiles + if (ipf.filmNegativeProcess(orig_prev, orig_prev, params->filmNegative, params->raw, imgsrc, currWB) && filmNegListener) { + filmNegListener->filmRefValuesChanged(params->filmNegative.refInput, params->filmNegative.refOutput); + } + + // Process film negative BEFORE colorspace conversion (legacy mode) + if (params->filmNegative.colorSpace == FilmNegativeParams::ColorSpace::INPUT) { + imgsrc->convertColorSpace(orig_prev, params->icm, currWB); + } + + } else { + imgsrc->convertColorSpace(orig_prev, params->icm, currWB); + } ipf.firstAnalysis(orig_prev, *params, vhist16); } @@ -653,13 +706,12 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) fattal_11_dcrop_cache = nullptr; } - if (oprevi == orig_prev) { - oprevi = new Imagefloat (pW, pH); - orig_prev->copyData (oprevi); - } + ipf.dehaze(orig_prev, params->dehaze); + ipf.ToneMapFattal02(orig_prev, params->fattal, 3, 0, nullptr, 0, 0, 0); - ipf.dehaze(oprevi); - ipf.ToneMapFattal02(oprevi); + if (oprevi != orig_prev) { + delete oprevi; + } } // Remove transformation if unneeded @@ -722,10 +774,110 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) aeListener->autoMatchedToneCurveChanged(params->toneCurve.curveMode, params->toneCurve.curve); } } + + // Encoding log with locallab + if (params->locallab.enabled && !params->locallab.spots.empty()) { + const int sizespot = (int)params->locallab.spots.size(); + + float *sourceg = nullptr; + sourceg = new float[sizespot]; + float *sourceab = nullptr; + sourceab = 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; + sourceab[sp] = params->locallab.spots.at(sp).sourceabs; + 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, sourceab, 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]; + params->locallab.spots.at(sp).sourceabs = sourceab[sp]; + + if (locallListener) { + locallListener->logencodChanged(blackev[sp], whiteev[sp], sourceg[sp], sourceab[sp], targetg[sp]); + } + } + } + + delete [] locx; + delete [] locy; + delete [] locxL; + delete [] locyT; + delete [] centx; + delete [] centy; + + delete [] Autogr; + delete [] whiteev; + delete [] blackev; + delete [] targetg; + delete [] sourceab; + delete [] sourceg; + delete [] log; + delete [] autocomput; + } } if (todo & (M_AUTOEXP | M_RGBCURVE)) { - if (params->icm.workingTRC == "Custom") { //exec TRC IN free + /* if (params->icm.workingTRC == "Custom") { //exec TRC IN free if (oprevi == orig_prev) { oprevi = new Imagefloat(pW, pH); orig_prev->copyData(oprevi); @@ -754,12 +906,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.workingtrc(oprevi, oprevi, cw, ch, 5, params->icm.workingProfile, params->icm.workingTRCGamma, params->icm.workingTRCSlope, customTransformOut, false, true, true); } } + */ } if ((todo & M_RGBCURVE) || (todo & M_CROP)) { - // if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); - //complexCurve also calculated pre-curves histogram depending on crop CurveFactory::complexCurve(params->toneCurve.expcomp, params->toneCurve.black / 65535.0, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, @@ -782,8 +933,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) {wprof[2][0], wprof[2][1], wprof[2][2]} }; params->colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili); - CurveFactory::curveToning(params->colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); - CurveFactory::curveToning(params->colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + CurveFactory::diagonalCurve2Lut(params->colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); + CurveFactory::diagonalCurve2Lut(params->colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); } if (params->blackwhite.enabled) { @@ -870,11 +1021,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(); @@ -908,19 +1062,272 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (todo & M_LUMACURVE) { - CurveFactory::curveCL(clcutili, params->labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); + clcutili = CurveFactory::diagonalCurve2Lut(params->labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params->labCurve.acurve, params->labCurve.bcurve, params->labCurve.cccurve, 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); + // int maxspot = 1; + //************************************************************* + // locallab + //************************************************************* + + if (params->locallab.enabled && !params->locallab.spots.empty()) { + /* + * 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 + */ + const std::unique_ptr reserv(new LabImage(*oprevl, true)); + const std::unique_ptr lastorigimp(new LabImage(*oprevl, true)); + float **shbuffer = nullptr; + int sca = 1; + double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre; + float avge; + std::vector locallref; + std::vector locallretiminmax; + huerefs.resize(params->locallab.spots.size()); + huerefblurs.resize(params->locallab.spots.size()); + chromarefblurs.resize(params->locallab.spots.size()); + lumarefblurs.resize(params->locallab.spots.size()); + chromarefs.resize(params->locallab.spots.size()); + lumarefs.resize(params->locallab.spots.size()); + sobelrefs.resize(params->locallab.spots.size()); + avgs.resize(params->locallab.spots.size()); + + for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) { + // Set local curves of current spot to LUT + locRETgainCurve.Set(params->locallab.spots.at(sp).localTgaincurve); + locRETtransCurve.Set(params->locallab.spots.at(sp).localTtranscurve); + const bool LHutili = loclhCurve.Set(params->locallab.spots.at(sp).LHcurve); + const bool HHutili = lochhCurve.Set(params->locallab.spots.at(sp).HHcurve); + const bool CHutili = locchCurve.Set(params->locallab.spots.at(sp).CHcurve); + const bool lcmasutili = locccmasCurve.Set(params->locallab.spots.at(sp).CCmaskcurve); + const bool llmasutili = locllmasCurve.Set(params->locallab.spots.at(sp).LLmaskcurve); + const bool lhmasutili = lochhmasCurve.Set(params->locallab.spots.at(sp).HHmaskcurve); + const bool lhhmasutili = lochhhmasCurve.Set(params->locallab.spots.at(sp).HHhmaskcurve); + const bool llmasexputili = locllmasexpCurve.Set(params->locallab.spots.at(sp).LLmaskexpcurve); + const bool lcmasexputili = locccmasexpCurve.Set(params->locallab.spots.at(sp).CCmaskexpcurve); + const bool lhmasexputili = lochhmasexpCurve.Set(params->locallab.spots.at(sp).HHmaskexpcurve); + const bool llmasSHutili = locllmasSHCurve.Set(params->locallab.spots.at(sp).LLmaskSHcurve); + const bool lcmasSHutili = locccmasSHCurve.Set(params->locallab.spots.at(sp).CCmaskSHcurve); + const bool lhmasSHutili = lochhmasSHCurve.Set(params->locallab.spots.at(sp).HHmaskSHcurve); + const bool llmasvibutili = locllmasvibCurve.Set(params->locallab.spots.at(sp).LLmaskvibcurve); + const bool lcmasvibutili = locccmasvibCurve.Set(params->locallab.spots.at(sp).CCmaskvibcurve); + const bool lhmasvibutili = lochhmasvibCurve.Set(params->locallab.spots.at(sp).HHmaskvibcurve); + const bool llmascbutili = locllmascbCurve.Set(params->locallab.spots.at(sp).LLmaskcbcurve); + const bool lcmascbutili = locccmascbCurve.Set(params->locallab.spots.at(sp).CCmaskcbcurve); + const bool lhmascbutili = lochhmascbCurve.Set(params->locallab.spots.at(sp).HHmaskcbcurve); + const bool llmaslcutili = locllmaslcCurve.Set(params->locallab.spots.at(sp).LLmasklccurve); + const bool lcmaslcutili = locccmaslcCurve.Set(params->locallab.spots.at(sp).CCmasklccurve); + const bool lhmaslcutili = lochhmaslcCurve.Set(params->locallab.spots.at(sp).HHmasklccurve); + const bool llmasretiutili = locllmasretiCurve.Set(params->locallab.spots.at(sp).LLmaskreticurve); + const bool lcmasretiutili = locccmasretiCurve.Set(params->locallab.spots.at(sp).CCmaskreticurve); + const bool lhmasretiutili = lochhmasretiCurve.Set(params->locallab.spots.at(sp).HHmaskreticurve); + const bool llmastmutili = locllmastmCurve.Set(params->locallab.spots.at(sp).LLmasktmcurve); + const bool lcmastmutili = locccmastmCurve.Set(params->locallab.spots.at(sp).CCmasktmcurve); + const bool lhmastmutili = lochhmastmCurve.Set(params->locallab.spots.at(sp).HHmasktmcurve); + const bool llmasblutili = locllmasblCurve.Set(params->locallab.spots.at(sp).LLmaskblcurve); + const bool lcmasblutili = locccmasblCurve.Set(params->locallab.spots.at(sp).CCmaskblcurve); + const bool lhmasblutili = lochhmasblCurve.Set(params->locallab.spots.at(sp).HHmaskblcurve); + const bool llmaslogutili = locllmaslogCurve.Set(params->locallab.spots.at(sp).LLmaskcurveL); + const bool lcmaslogutili = locccmaslogCurve.Set(params->locallab.spots.at(sp).CCmaskcurveL); + const bool lhmaslogutili = lochhmaslogCurve.Set(params->locallab.spots.at(sp).HHmaskcurveL); + + const bool lcmas_utili = locccmas_Curve.Set(params->locallab.spots.at(sp).CCmask_curve); + const bool llmas_utili = locllmas_Curve.Set(params->locallab.spots.at(sp).LLmask_curve); + const bool lhmas_utili = lochhmas_Curve.Set(params->locallab.spots.at(sp).HHmask_curve); + const bool lhhmas_utili = lochhhmas_Curve.Set(params->locallab.spots.at(sp).HHhmask_curve); + const bool lmasutiliblwav = loclmasCurveblwav.Set(params->locallab.spots.at(sp).LLmaskblcurvewav); + const bool lmasutilicolwav = loclmasCurvecolwav.Set(params->locallab.spots.at(sp).LLmaskcolcurvewav); + const bool locwavutili = locwavCurve.Set(params->locallab.spots.at(sp).locwavcurve); + const bool loclevwavutili = loclevwavCurve.Set(params->locallab.spots.at(sp).loclevwavcurve); + const bool locconwavutili = locconwavCurve.Set(params->locallab.spots.at(sp).locconwavcurve); + const bool loccompwavutili = loccompwavCurve.Set(params->locallab.spots.at(sp).loccompwavcurve); + const bool loccomprewavutili = loccomprewavCurve.Set(params->locallab.spots.at(sp).loccomprewavcurve); + const bool locwavdenutili = locwavCurveden.Set(params->locallab.spots.at(sp).locwavcurveden); + const bool locedgwavutili = locedgwavCurve.Set(params->locallab.spots.at(sp).locedgwavcurve); + const bool lmasutili_wav = loclmasCurve_wav.Set(params->locallab.spots.at(sp).LLmask_curvewav); + const bool locallutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).llcurve, lllocalcurve, sca); + const bool localclutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).clcurve, cllocalcurve, sca); + const bool locallcutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).lccurve, lclocalcurve, sca); + const bool localcutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).cccurve, cclocalcurve, sca); + const bool localrgbutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).rgbcurve, rgblocalcurve, sca); + const bool localexutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).excurve, exlocalcurve, sca); + const bool localmaskutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve, sca); + const bool localmaskexputili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve, sca); + const bool localmaskSHutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve, sca); + const bool localmaskvibutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve, sca); + const bool localmasktmutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve, sca); + const bool localmaskretiutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve, sca); + const bool localmaskcbutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve, sca); + const bool localmaskblutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve, sca); + const bool localmasklcutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve, sca); + const bool localmasklogutili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).LmaskcurveL, lmaskloglocalcurve, sca); + const bool localmask_utili = CurveFactory::diagonalCurve2Lut(params->locallab.spots.at(sp).Lmask_curve, lmasklocal_curve, 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.get(), reserv.get(), 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); + } + + double huerblu = huerefblurs[sp] = huerefblu; + double chromarblu = chromarefblurs[sp] = chromarefblu; + double lumarblu = lumarefblurs[sp] = lumarefblu; + double huer = huerefs[sp] = huere; + double chromar = chromarefs[sp] = chromare; + double lumar = lumarefs[sp] = lumare ; + double sobeler = sobelrefs[sp] = sobelre; + float 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; + int lastsav; + ipf.Lab_Local(3, sp, (float**)shbuffer, nprevl, nprevl, reserv.get(), lastorigimp.get(), 0, 0, pW, pH, scale, locRETgainCurve, locRETtransCurve, + lllocalcurve, locallutili, + cllocalcurve, localclutili, + lclocalcurve, locallcutili, + loclhCurve, lochhCurve, locchCurve, + lmasklocalcurve, localmaskutili, + lmaskexplocalcurve, localmaskexputili, + lmaskSHlocalcurve, localmaskSHutili, + lmaskviblocalcurve, localmaskvibutili, + lmasktmlocalcurve, localmasktmutili, + lmaskretilocalcurve, localmaskretiutili, + lmaskcblocalcurve, localmaskcbutili, + lmaskbllocalcurve, localmaskblutili, + lmasklclocalcurve, localmasklcutili, + lmaskloglocalcurve, localmasklogutili, + lmasklocal_curve, localmask_utili, + + 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, + locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili, + + locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili, + lochhhmas_Curve, lhhmas_utili, + loclmasCurveblwav, lmasutiliblwav, + loclmasCurvecolwav, lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + loclmasCurve_wav, lmasutili_wav, + LHutili, HHutili, CHutili, 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, 0, 0, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + + if (sp + 1u < params->locallab.spots.size()) { + // do not copy for last spot as it is not needed anymore + 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.get(), reserv.get(), 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; + } + } + + // 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)) { @@ -933,13 +1340,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } - - wavcontlutili = false; - CurveFactory::curveWavContL(wavcontlutili, params->wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); + wavcontlutili = CurveFactory::diagonalCurve2Lut(params->wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); if ((params->wavelet.enabled)) { WaveletParams WaveParams = params->wavelet; - WaveParams.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); + WaveParams.getCurves(wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); int kall = 0; LabImage *unshar = nullptr; Glib::ustring provis; @@ -957,20 +1362,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } if (WaveParams.softrad > 0.f) { - provradius = new LabImage(pW, pH); - provradius->CopyFrom(nprevl); + provradius = new LabImage(*nprevl, true); } - - - if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { - unshar = new LabImage(pW, pH); provis = params->wavelet.CLmethod; params->wavelet.CLmethod = "all"; - ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); - - unshar->CopyFrom(nprevl); + ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); + unshar = new LabImage(*nprevl, true); params->wavelet.CLmethod = provis; @@ -982,7 +1381,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) WaveParams.expnoise = false; } - ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); + ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, scale); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { @@ -1025,11 +1424,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) double epsilmax = 0.0001; double epsilmin = 0.00001; - double aepsil = (epsilmax - epsilmin) / 90.f; - double bepsil = epsilmax - 100.f * aepsil; + double aepsil = (epsilmax - epsilmin) / 100.f; + double bepsil = epsilmin; //epsilmax - 100.f * aepsil; double epsil = aepsil * WaveParams.softrad + bepsil; - float blur = 10.f / scale * (0.0001f + 0.8f * WaveParams.softrad); + float blur = 10.f / scale * (0.5f + 0.8f * WaveParams.softrad); // rtengine::guidedFilter(guid, ble, ble, blur, 0.001, multiTh); rtengine::guidedFilter(guid, ble, ble, blur, epsil, false); @@ -1103,6 +1502,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) delete unshar; unshar = NULL; + + /* if (WaveParams.softrad > 0.f) { array2D ble(pW, pH); @@ -1150,7 +1551,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 @@ -1221,7 +1622,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); @@ -1267,7 +1668,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 @@ -1303,9 +1704,21 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imageListener->imageReady(params->crop); } + hist_lrgb_dirty = vectorscope_hc_dirty = vectorscope_hs_dirty = waveform_dirty = true; if (hListener) { - updateLRGBHistograms(); - hListener->histogramChanged(histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histCCurve, /*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma, histLRETI); + if (hListener->updateHistogram()) { + updateLRGBHistograms(); + } + if (hListener->updateVectorscopeHC()) { + updateVectorscopeHC(); + } + if (hListener->updateVectorscopeHS()) { + updateVectorscopeHS(); + } + if (hListener->updateWaveform()) { + updateWaveforms(); + } + notifyHistogramChanged(); } } @@ -1411,6 +1824,7 @@ void ImProcCoordinator::setScale(int prevscale) oprevi = orig_prev; oprevl = new LabImage(pW, pH); nprevl = 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); @@ -1430,8 +1844,42 @@ void ImProcCoordinator::setScale(int prevscale) } -void ImProcCoordinator::updateLRGBHistograms() +void ImProcCoordinator::notifyHistogramChanged() { + if (hListener) { + hListener->histogramChanged( + histRed, + histGreen, + histBlue, + histLuma, + histToneCurve, + histLCurve, + histCCurve, + histLCAM, + histCCAM, + histRedRaw, + histGreenRaw, + histBlueRaw, + histChroma, + histLRETI, + vectorscopeScale, + vectorscope_hc, + vectorscope_hs, + waveformScale, + waveformRed, + waveformGreen, + waveformBlue, + waveformLuma + ); + } +} + +bool ImProcCoordinator::updateLRGBHistograms() +{ + + if (!hist_lrgb_dirty) { + return false; + } int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); @@ -1489,6 +1937,159 @@ void ImProcCoordinator::updateLRGBHistograms() } } + hist_lrgb_dirty = false; + return true; + +} + +bool ImProcCoordinator::updateVectorscopeHC() +{ + if (!workimg || !vectorscope_hc_dirty) { + return false; + } + + int x1, y1, x2, y2; + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + + constexpr int size = VECTORSCOPE_SIZE; + constexpr float norm_factor = size / (128.f * 655.36f); + vectorscope_hc.fill(0); + + vectorscopeScale = (x2 - x1) * (y2 - y1); + + const std::unique_ptr a(new float[vectorscopeScale]); + const std::unique_ptr b(new float[vectorscopeScale]); + const std::unique_ptr L(new float[vectorscopeScale]); + ipf.rgb2lab(*workimg, x1, y1, x2 - x1, y2 - y1, L.get(), a.get(), b.get(), params->icm); +#ifdef _OPENMP + #pragma omp parallel +#endif + { + array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); +#ifdef _OPENMP + #pragma omp for nowait +#endif + for (int i = y1; i < y2; ++i) { + for (int j = x1, ofs_lab = (i - y1) * (x2 - x1); j < x2; ++j, ++ofs_lab) { + const int col = norm_factor * a[ofs_lab] + size / 2 + 0.5f; + const int row = norm_factor * b[ofs_lab] + size / 2 + 0.5f; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscopeThr[row][col]++; + } + } + } +#ifdef _OPENMP + #pragma omp critical +#endif + { + vectorscope_hc += vectorscopeThr; + } + } + + vectorscope_hc_dirty = false; + return true; +} + +bool ImProcCoordinator::updateVectorscopeHS() +{ + if (!workimg || !vectorscope_hs_dirty) { + return false; + } + + int x1, y1, x2, y2; + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + + constexpr int size = VECTORSCOPE_SIZE; + vectorscope_hs.fill(0); + + vectorscopeScale = (x2 - x1) * (y2 - y1); + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + array2D vectorscopeThr(size, size, ARRAY2D_CLEAR_DATA); +#ifdef _OPENMP + #pragma omp for nowait +#endif + for (int i = y1; i < y2; ++i) { + int ofs = (i * pW + x1) * 3; + for (int j = x1; j < x2; ++j) { + const float red = 257.f * workimg->data[ofs++]; + const float green = 257.f * workimg->data[ofs++]; + const float blue = 257.f * workimg->data[ofs++]; + float h, s, l; + Color::rgb2hslfloat(red, green, blue, h, s, l); + const auto sincosval = xsincosf(2.f * RT_PI_F * h); + const int col = s * sincosval.y * (size / 2) + size / 2; + const int row = s * sincosval.x * (size / 2) + size / 2; + if (col >= 0 && col < size && row >= 0 && row < size) { + vectorscopeThr[row][col]++; + } + } + } +#ifdef _OPENMP + #pragma omp critical +#endif + { + vectorscope_hs += vectorscopeThr; + } + } + + vectorscope_hs_dirty = false; + return true; +} + +bool ImProcCoordinator::updateWaveforms() +{ + if (!workimg) { + // free memory + waveformRed.free(); + waveformGreen.free(); + waveformBlue.free(); + waveformLuma.free(); + return true; + } + + if (!waveform_dirty) { + return false; + } + + int x1, y1, x2, y2; + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + int waveform_width = waveformRed.getWidth(); + + if (waveform_width != x2 - x1) { + // Resize waveform arrays. + waveform_width = x2 - x1; + waveformRed(waveform_width, 256); + waveformGreen(waveform_width, 256); + waveformBlue(waveform_width, 256); + waveformLuma(waveform_width, 256); + } + + // Start with zero. + waveformRed.fill(0); + waveformGreen.fill(0); + waveformBlue.fill(0); + waveformLuma.fill(0); + + constexpr float luma_factor = 255.f / 32768.f; + for (int i = y1; i < y2; i++) { + int ofs = (i * pW + x1) * 3; + float* L_row = nprevl->L[i] + x1; + + for (int j = 0; j < waveform_width; j++) { + waveformRed[workimg->data[ofs++]][j]++; + waveformGreen[workimg->data[ofs++]][j]++; + waveformBlue[workimg->data[ofs++]][j]++; + waveformLuma[LIM(L_row[j] * luma_factor, 0, 255)][j]++; + } + } + + waveformScale = y2 - y1; + waveform_dirty = false; + return true; } bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) @@ -1574,25 +2175,7 @@ void ImProcCoordinator::getSpotWB(int x, int y, int rect, double& temp, double& } } -bool ImProcCoordinator::getFilmNegativeExponents(int xA, int yA, int xB, int yB, std::array& newExps) -{ - MyMutex::MyLock lock(mProcessing); - const int tr = getCoarseBitMask(params->coarse); - - const Coord2D p1 = translateCoord(ipf, fw, fh, xA, yA); - const Coord2D p2 = translateCoord(ipf, fw, fh, xB, yB); - - return imgsrc->getFilmNegativeExponents(p1, p2, tr, params->filmNegative, newExps); -} - -bool ImProcCoordinator::getRawSpotValues(int x, int y, int spotSize, std::array& rawValues) -{ - MyMutex::MyLock lock(mProcessing); - - return imgsrc->getRawSpotValues(translateCoord(ipf, fw, fh, x, y), spotSize, - getCoarseBitMask(params->coarse), params->filmNegative, rawValues); -} void ImProcCoordinator::getAutoCrop(double ratio, int &x, int &y, int &w, int &h) { @@ -1651,7 +2234,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; @@ -1830,8 +2413,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 @@ -1864,6 +2448,7 @@ void ImProcCoordinator::process() || params->dirpyrequalizer != nextParams->dirpyrequalizer || params->dehaze != nextParams->dehaze || params->pdsharpening != nextParams->pdsharpening + || params->filmNegative != nextParams->filmNegative || sharpMaskChanged; sharpMaskChanged = false; @@ -1943,4 +2528,61 @@ void ImProcCoordinator::setHighQualComputed() highQualityComputed = true; } +void ImProcCoordinator::requestUpdateWaveform() +{ + if (!hListener) { + return; + } + bool updated = updateWaveforms(); + if (updated) { + notifyHistogramChanged(); + } +} + +void ImProcCoordinator::requestUpdateHistogram() +{ + if (!hListener) { + return; + } + bool updated = updateLRGBHistograms(); + if (updated) { + notifyHistogramChanged(); + } +} + +void ImProcCoordinator::requestUpdateHistogramRaw() +{ + if (!hListener) { + return; + } + // Don't need to actually update histogram because it is always + // up-to-date. + if (hist_raw_dirty) { + hist_raw_dirty = false; + notifyHistogramChanged(); + } +} + +void ImProcCoordinator::requestUpdateVectorscopeHC() +{ + if (!hListener) { + return; + } + bool updated = updateVectorscopeHC(); + if (updated) { + notifyHistogramChanged(); + } +} + +void ImProcCoordinator::requestUpdateVectorscopeHS() +{ + if (!hListener) { + return; + } + bool updated = updateVectorscopeHS(); + if (updated) { + notifyHistogramChanged(); + } +} + } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 5ba96ce6b..1c9a43390 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -55,7 +55,7 @@ class TweakOperator; * but using this class' LUT and other precomputed parameters. The main preview area is displaying a non framed Crop object, * while detail windows are framed Crop objects. */ -class ImProcCoordinator final : public StagedImageProcessor +class ImProcCoordinator final : public StagedImageProcessor, public HistogramObservable { friend class Crop; @@ -94,7 +94,7 @@ protected: bool highDetailRawComputed; bool allocated; - void freeAll (); + void freeAll(); // Precomputed values used by DetailedCrop ---------------------------------------------- @@ -128,6 +128,16 @@ protected: LUTu histBlue, histBlueRaw; LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; + bool hist_lrgb_dirty; + /// Used to simulate a lazy update of the raw histogram. + bool hist_raw_dirty; + int vectorscopeScale; + bool vectorscope_hc_dirty, vectorscope_hs_dirty; + array2D vectorscope_hc, vectorscope_hs; + /// Waveform's intensity. Same as height of reference image. + int waveformScale; + bool waveform_dirty; + array2D waveformRed, waveformGreen, waveformBlue, waveformLuma; LUTf CAMBrightCurveJ, CAMBrightCurveQ; @@ -141,6 +151,8 @@ protected: NoiseCurve noiseLCurve; NoiseCurve noiseCCurve; WavCurve wavCLVCurve; + WavCurve wavdenoise; + WavCurve wavdenoiseh; Wavblcurve wavblcurve; WavOpacityCurveRG waOpacityCurveRG; WavOpacityCurveSH waOpacityCurveSH; @@ -179,12 +191,13 @@ protected: FrameCountListener *frameCountListener; ImageTypeListener *imageTypeListener; FilmNegListener *filmNegListener; - AutoColorTonListener* actListener; AutoChromaListener* adnListener; WaveletListener* awavListener; RetinexListener* dehaListener; +// LocallabListener* locallListener; + HistogramListener* hListener; std::vector sizeListeners; @@ -196,10 +209,18 @@ protected: void backupParams(); void restoreParams(); - void reallocAll (); void allocCache (Imagefloat* &imgfloat); - void updateLRGBHistograms (); - void setScale (int prevscale); + void notifyHistogramChanged(); + void reallocAll(); + /// Updates L, R, G, and B histograms. Returns true unless not updated. + bool updateLRGBHistograms(); + /// Updates the H-C vectorscope. Returns true unless not updated. + bool updateVectorscopeHC(); + /// Updates the H-S vectorscope. Returns true unless not updated. + bool updateVectorscopeHS(); + /// Updates all waveforms. Returns true unless not updated. + bool updateWaveforms(); + void setScale(int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); MyMutex mProcessing; @@ -230,15 +251,118 @@ 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; + 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; + LUTf lmaskloglocalcurve; + LUTf lmasklocal_curve; + + LocretigainCurve locRETgainCurve; + LocretitransCurve locRETtransCurve; + LocretigainCurverab locRETgainCurverab; + LocLHCurve loclhCurve; + LocHHCurve lochhCurve; + LocCHCurve locchCurve; + 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; + LocCCmaskCurve locccmas_Curve; + LocLLmaskCurve locllmas_Curve; + LocHHmaskCurve lochhmas_Curve; + LocHHmaskCurve lochhhmas_Curve; + LocCCmaskCurve locccmaslogCurve; + LocLLmaskCurve locllmaslogCurve; + LocHHmaskCurve lochhmaslogCurve; + + LocwavCurve locwavCurve; + LocwavCurve loclmasCurveblwav; + LocwavCurve loclmasCurvecolwav; + LocwavCurve loclevwavCurve; + LocwavCurve locconwavCurve; + LocwavCurve loccompwavCurve; + LocwavCurve loccomprewavCurve; + LocwavCurve locwavCurveden; + LocwavCurve locedgwavCurve; + LocwavCurve loclmasCurve_wav; + + std::vector huerefs; + std::vector huerefblurs; + std::vector chromarefblurs; + std::vector lumarefblurs; + std::vector chromarefs; + std::vector lumarefs; + std::vector sobelrefs; + std::vector avgs; + 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; + int localllogMask; + int locall_Mask; public: @@ -254,10 +378,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 { @@ -291,8 +416,7 @@ public: bool getAutoWB (double& temp, double& green, double equal, double tempBias) override; void getCamWB (double& temp, double& green) override; void getSpotWB (int x, int y, int rectSize, double& temp, double& green) override; - bool getFilmNegativeExponents(int xA, int yA, int xB, int yB, std::array& newExps) override; - bool getRawSpotValues(int x, int y, int spotSize, std::array& rawValues) override; + bool getFilmNegativeSpot(int x, int y, int spotSize, FilmNegativeParams::RGB &refInput, FilmNegativeParams::RGB &refOutput) override; void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) override; bool getHighQualComputed() override; void setHighQualComputed() override; @@ -310,6 +434,27 @@ 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, int localllogMask, int locall_Mask) 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; + this->localllogMask = localllogMask; + this->locall_Mask = locall_Mask; + } + void setProgressListener (ProgressListener* pl) override { plistener = pl; @@ -320,14 +465,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 @@ -336,7 +481,13 @@ public: } void setHistogramListener (HistogramListener *h) override { + if (hListener) { + hListener->setObservable(nullptr); + } hListener = h; + if (h) { + h->setObservable(this); + } } void setAutoCamListener (AutoCamListener* acl) override { @@ -362,6 +513,10 @@ public: { dehaListener = adh; } + void setLocallabListener (LocallabListener* lla) override + { + locallListener = lla; + } void setWaveletListener (WaveletListener* awa) override { awavListener = awa; @@ -424,7 +579,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]; @@ -433,6 +588,11 @@ public: } denoiseInfoStore; + void requestUpdateHistogram() override; + void requestUpdateHistogramRaw() override; + void requestUpdateVectorscopeHC() override; + void requestUpdateVectorscopeHS() override; + void requestUpdateWaveform() override; }; } diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index aa5515e79..05cc115d9 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,34 +5213,114 @@ 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. char nm[64]; - sprintf(nm, "%ux%ufloat.bin", lab->W, lab->H); + snprintf(nm, sizeof(nm), "%ux%ufloat.bin", lab->W, lab->H); FILE *f = fopen(nm, "wb"); 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,130 @@ 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::rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings) const +{ // Adapted from ImProcFunctions::lab2rgb + const int src_width = src.getWidth(); + const int src_height = src.getHeight(); + + if (x < 0) { + x = 0; + } + + if (y < 0) { + y = 0; + } + + if (x + w > src_width) { + w = src_width - x; + } + + if (y + h > src_height) { + h = src_height - y; + } + + Glib::ustring profile; + + cmsHPROFILE oprof = nullptr; + + if (settings->HistogramWorking && consider_histogram_settings) { + profile = icm.workingProfile; + } else { + profile = icm.outputProfile; + + if (icm.outputProfile.empty() || icm.outputProfile == ColorManagementParams::NoICMString) { + profile = "sRGB"; + } + oprof = ICCStore::getInstance()->getProfile(profile); + } + + if (oprof) { + cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; // NOCACHE is important for thread safety + + if (icm.outputBPC) { + flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + lcmsMutex->lock(); + cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); + cmsHTRANSFORM hTransform = cmsCreateTransform (oprof, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); + cmsCloseProfile(LabIProf); + lcmsMutex->unlock(); + + // cmsDoTransform is relatively expensive +#ifdef _OPENMP + #pragma omp parallel +#endif + { + AlignedBuffer oBuf(3 * w); + float *outbuffer = oBuf.data; + int condition = y + h; + +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif + + for (int i = y; i < condition; i++) { + const int ix = 3 * (x + i * src_width); + int iy = 0; + float* rL = L + (i - y) * w; + float* ra = a + (i - y) * w; + float* rb = b + (i - y) * w; + + cmsDoTransform (hTransform, src.data + ix, outbuffer, w); + + for (int j = 0; j < w; j++) { + rL[j] = outbuffer[iy++] * 327.68f; + ra[j] = outbuffer[iy++] * 327.68f; + rb[j] = outbuffer[iy++] * 327.68f; + } + } + } // End of parallelization + + cmsDeleteTransform(hTransform); + } else { + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(profile); + 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])} + }; + + const int x2 = x + w; + const int y2 = y + h; + constexpr float rgb_factor = 65355.f / 255.f; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + + for (int i = y; i < y2; i++) { + int offset = (i - y) * w; + for (int j = x; j < x2; j++) { + float X, Y, Z; + // lab2rgb uses gamma2curve, which is gammatab_srgb. + const auto& igamma = Color::igammatab_srgb; + Color::rgbxyz(igamma[rgb_factor * src.r(i, j)], igamma[rgb_factor * src.g(i, j)], igamma[rgb_factor * src.b(i, j)], X, Y, Z, wp); + Color::XYZ2Lab(X, Y, Z, L[offset], a[offset], b[offset]); + offset++; + } + } + } +} + +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 +5842,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 +5859,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 +5905,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 23929a7f1..f704c8da3 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -24,6 +24,11 @@ #include "coord2d.h" #include "gamutwarning.h" #include "imagedimensions.h" +#include "jaggedarray.h" +#include "pipettebuffer.h" +#include "array2D.h" +#include "imagesource.h" +#include namespace Glib { @@ -49,6 +54,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; @@ -75,9 +88,16 @@ namespace procparams class ProcParams; struct SpotEntry; +struct DehazeParams; +struct FattalToneMappingParams; struct ColorManagementParams; struct DirPyrDenoiseParams; +struct FilmNegativeParams; +struct LocalContrastParams; +struct LocallabParams; struct SharpeningParams; +struct SoftLightParams; +struct VibranceParams; struct VignettingParams; struct WaveletParams; @@ -89,6 +109,7 @@ class ImProcFunctions { cmsHTRANSFORM monitorTransform; std::unique_ptr gamutWarning; + Cairo::RefPtr locImage; const procparams::ProcParams* params; double scale; @@ -110,7 +131,6 @@ class ImProcFunctions bool needsLensfun() const; // static cmsUInt8Number* Mempro = NULL; - public: enum class Median { TYPE_3X3_SOFT, @@ -135,6 +155,12 @@ public: bool needsTransform(int oW, int oH, int rawRotationDeg, const FramesMetaData *metadata) const; bool needsPCVignetting() const; + bool filmNegativeProcess(rtengine::Imagefloat *input, rtengine::Imagefloat *output, procparams::FilmNegativeParams &fnp, + const procparams::RAWParams &rawParams, const rtengine::ImageSource* imgsrc, const rtengine::ColorTemp &currWB); + + void filmNegativeProcess(rtengine::Imagefloat *input, rtengine::Imagefloat *output, const procparams::FilmNegativeParams ¶ms); + + 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, @@ -160,12 +186,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, int call); + 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); @@ -177,6 +207,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 @@ -191,46 +223,189 @@ 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 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, float blendmab, int shado, int highl, 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, bool fftt, float blu_ma, float cont_ma, int indic); + void avoidcolshi(struct local_params& lp, int sp, LabImage * original, LabImage *transformed, int cy, int cx); + + 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, + const 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, struct local_params & lp, bool multiThread, int bfw, int bfh); + void getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, float *blackev, float *whiteev, bool *Autogr, float *sourceab, 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, + const 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 LocCHCurve& locchCurve, + 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 LUTf& lmaskloglocalcurve, bool localmasklogutili, + const LUTf& lmasklocal_curve, bool localmask_utili, + + 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 LocCCmaskCurve& locccmaslogCurve, bool lcmaslogutili, const LocLLmaskCurve& locllmaslogCurve, bool llmaslogutili, const LocHHmaskCurve& lochhmaslogCurve, bool lhmaslogutili, + const LocCCmaskCurve& locccmas_Curve, bool lcmas_utili, const LocLLmaskCurve& locllmas_Curve, bool llmas_utili, const LocHHmaskCurve& lochhmas_Curve, bool lhmas_utili, + const LocHHmaskCurve& lochhhmas_Curve, bool lhhmas_utili, + + 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, + const LocwavCurve& loclmasCurve_wav, bool lmasutili_wav, + bool LHutili, bool HHutili, bool CHutili, 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, int lllogMask, int ll_Mask, + 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, 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, int bfhr, int bfwr, LabImage* bufexporig, LabImage* lab, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, const float hueref, const float lumaref, const float chromaref); + 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 WavOpacityCurveSH & waOpacityCurveSH, 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 WavCurve & wavdenoise, WavCurve & wavdenoiseh, 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, + 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(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, + 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(const wavelet_decomposition &WaveletCoeffs_a, const wavelet_decomposition &WaveletCoeffs_b, + 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, float **varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, + 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 ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, const cont_params &cp, + 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 ** WavCoeffs_a, float * WavCoeffs_a0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, + 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); - 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 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); + std::unique_ptr buildMeaLut(const float inVals[11], const float mea[10], float& lutFactor); + 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* WavCoeffs_LL, float gradw, float tloww, float *koeLi, int level, int W_L, int H_L, float edd, float &maxkoeLi, float **tmC, bool multiThread = false); 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); @@ -244,18 +419,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); @@ -267,6 +442,7 @@ public: void removeSpots (rtengine::Imagefloat* img, rtengine::ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const rtengine::ColorTemp &currWB, const procparams::ColorManagementParams *cmp, int tr); // 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 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); @@ -279,16 +455,19 @@ 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); + void rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true) const; Imagefloat* lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); // CieImage *ciec; void workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, cmsHTRANSFORM &transform, bool normalizeIn = true, bool normalizeOut = true, bool keepTransForm = false) const; diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc index 53939b5c0..6ae8be27b 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; @@ -95,16 +103,18 @@ void restore(Imagefloat *rgb, float maxval, bool multithread) } } -int get_dark_channel(const array2D &R, const array2D &G, const array2D &B, const array2D &dst, int patchsize, const float ambient[3], bool clip, bool multithread, float strength) +int get_dark_channel(const array2D &R, const array2D &G, const array2D &B, array2D &dst, int patchsize, const float ambient[3], bool clip, bool multithread, float strength) { - const int W = R.width(); - const int H = R.height(); + const int W = R.getWidth(); + const int H = R.getHeight(); #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,50 +152,56 @@ 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) +int get_dark_channel_downsized(const array2D &R, const array2D &G, const array2D &B, array2D &dst, int patchsize, bool multithread) { - const int W = R.width(); - const int H = R.height(); + const int W = R.getWidth(); + const int H = R.getHeight(); #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]) { - const int W = R.width(); - const int H = R.height(); + const int W = R.getWidth(); + const int H = R.getHeight(); 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,11 +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); - - if (settings->verbose) { - std::cout << "dehaze: strength = " << strength << std::endl; - } + const float strength = LIM01(float(dehazeParams.strength) / 100.f * 0.9f); array2D dark(W, H); @@ -356,16 +378,17 @@ 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; + constexpr float teps = 1.f + 1e-3f; - const bool luminance = params->dehaze.luminance; + const float satBlend = dehazeParams.saturation / 100.f; 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])}; #endif const float ambientY = Color::rgbLuminance(ambient[0], ambient[1], ambient[2], ws); + #ifdef _OPENMP #pragma omp parallel for if (multiThread) #endif @@ -381,30 +404,27 @@ void ImProcFunctions::dehaze(Imagefloat *img) const vfloat t0v = F2V(t0); const vfloat tepsv = F2V(teps); const vfloat cmaxChannelv = F2V(maxChannel); + const vfloat satBlendv = F2V(satBlend); for (; x < W - 3; x += 4) { // ensure that the transmission is such that to avoid clipping... const vfloat r = LVFU(img->r(y, x)); const vfloat g = LVFU(img->g(y, x)); const vfloat b = LVFU(img->b(y, x)); // ... 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) { + const vfloat tlv = tepsv - vminf(r / ambient0v, vminf(g / ambient1v, b / ambient2v)); + const vfloat mtv = vmaxf(LVFU(dark[y][x]), vmaxf(tlv, t0v)); + if (dehazeParams.showDepthMap) { const vfloat valv = vclampf(onev - mtv, ZEROV, onev) * cmaxChannelv; STVFU(img->r(y, x), valv); STVFU(img->g(y, x), valv); STVFU(img->b(y, x), valv); - } else if (luminance) { + } else { const vfloat Yv = Color::rgbLuminance(r, g, b, wsv); const vfloat YYv = (Yv - ambientYv) / mtv + ambientYv; const vfloat fv = vself(vmaskf_gt(Yv, epsYv), cmaxChannelv * YYv / Yv, cmaxChannelv); - STVFU(img->r(y, x), r * fv); - STVFU(img->g(y, x), g * fv); - STVFU(img->b(y, x), b * fv); - } else { - STVFU(img->r(y, x), ((r - ambient0v) / mtv + ambient0v) * cmaxChannelv); - STVFU(img->g(y, x), ((g - ambient1v) / mtv + ambient1v) * cmaxChannelv); - STVFU(img->b(y, x), ((b - ambient2v) / mtv + ambient2v) * cmaxChannelv); + STVFU(img->r(y, x), vintpf(satBlendv, ((r - ambient0v) / mtv + ambient0v) * cmaxChannelv, r * fv)); + STVFU(img->g(y, x), vintpf(satBlendv, ((g - ambient1v) / mtv + ambient1v) * cmaxChannelv, g * fv)); + STVFU(img->b(y, x), vintpf(satBlendv, ((b - ambient2v) / mtv + ambient2v) * cmaxChannelv, b * fv)); } } #endif @@ -414,24 +434,163 @@ void ImProcFunctions::dehaze(Imagefloat *img) const float g = img->g(y, x); const float b = img->b(y, x); // ... 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) { + const float tl = teps - min(r / ambient[0], g / ambient[1], b / ambient[2]); + const float mt = max(dark[y][x], t0, tl); + if (dehazeParams.showDepthMap) { img->r(y, x) = img->g(y, x) = img->b(y, x) = LIM01(1.f - mt) * maxChannel; - } else if (luminance) { + } else { const float Y = Color::rgbLuminance(img->r(y, x), img->g(y, x), img->b(y, x), ws); const float YY = (Y - ambientY) / mt + ambientY; const float f = Y > 1e-5f ? maxChannel * YY / Y : maxChannel; - img->r(y, x) *= f; - img->g(y, x) *= f; - img->b(y, x) *= f; - } else { - img->r(y, x) = ((r - ambient[0]) / mt + ambient[0]) * maxChannel; - img->g(y, x) = ((g - ambient[1]) / mt + ambient[1]) * maxChannel; - img->b(y, x) = ((b - ambient[2]) / mt + ambient[2]) * maxChannel; + img->r(y, x) = intp(satBlend, ((r - ambient[0]) / mt + ambient[0]) * maxChannel, r * f); + img->g(y, x) = intp(satBlend, ((g - ambient[1]) / mt + ambient[1]) * maxChannel, g * f); + img->b(y, x) = intp(satBlend, ((b - ambient[2]) / mt + ambient[2]) * maxChannel, b * f); } } } } +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 + + 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; + + 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; + constexpr float teps = 1e-6f; + const float t0 = max(teps, std::exp(depth * maxDistance)); + + const float satBlend = dehazeParams.saturation / 100.f; + + 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) { + for (int x = 0; x < W; ++x) { + // ensure that the transmission is such that to avoid clipping... + const float rIn = img->r(y, x); + const float gIn = img->g(y, x); + const float bIn = img->b(y, x); + // ... t >= tl to avoid negative values + const float tl = 1.f + teps - min(rIn / ambient[0], gIn / ambient[1], bIn / ambient[2]); + const float mt = max(dark[y][x], t0, tl); + + if (dehazeParams.showDepthMap) { + img->r(y, x) = img->g(y, x) = img->b(y, x) = LIM01(1.f - mt) * maxChannel; + } else { + float f = 1.f; + const float Y = Color::rgbLuminance(rIn, gIn, bIn, ws); + if (Y > 1e-5f) { + float YY = (Y - ambientY) / mt + ambientY; + if (add_haze) { + YY = Y + Y - YY; + } + f = YY / Y; + } + const float r1 = rIn * f; + const float g1 = gIn * f; + const float b1 = bIn * f; + + float r2 = ((rIn - ambient[0]) / mt + ambient[0]); + float g2 = ((gIn - ambient[1]) / mt + ambient[1]); + float b2 = ((bIn - ambient[2]) / mt + ambient[2]); + + if (add_haze) { + r2 = rIn + rIn - r2; + g2 = gIn + gIn - g2; + b2 = bIn + bIn - b2; + } + img->r(y, x) = intp(satBlend, r2, r1); + img->g(y, x) = intp(satBlend, g2, g1); + img->b(y, x) = intp(satBlend, b2, b1); + } + } + } + + 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 // x0W; - int H = src->H; + const int W = src->W; + const int H = src->H; + float rgb_xyzf[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + rgb_xyzf[i][j] = rgb_xyz[i][j]; + } + } + +#ifdef __SSE2__ + vfloat rgb_xyzv[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + rgb_xyzv[i][j] = F2V(rgb_xyzf[i][j]); + } + } +#endif #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif @@ -58,17 +73,47 @@ inline void copyAndClamp(const LabImage *src, unsigned char *dst, const double r float* rb = src->b[i]; int ix = i * 3 * W; - float R, G, B; - float x_, y_, z_; - - for (int j = 0; j < W; ++j) { +#ifdef __SSE2__ + float rbuffer[W] ALIGNED16; + float gbuffer[W] ALIGNED16; + float bbuffer[W] ALIGNED16; + int j = 0; + for (; j < W - 3; j += 4) { + vfloat R, G, B; + vfloat x_, y_, z_; + Color::Lab2XYZ(LVFU(rL[j]), LVFU(ra[j]), LVFU(rb[j]), x_, y_, z_ ); + Color::xyz2rgb(x_, y_, z_, R, G, B, rgb_xyzv); + STVF(rbuffer[j], Color::gamma2curve[R]); + STVF(gbuffer[j], Color::gamma2curve[G]); + STVF(bbuffer[j], Color::gamma2curve[B]); + } + for (; j < W; ++j) { + float R, G, B; + float x_, y_, z_; Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_ ); - Color::xyz2rgb(x_, y_, z_, R, G, B, rgb_xyz); + Color::xyz2rgb(x_, y_, z_, R, G, B, rgb_xyzf); + rbuffer[j] = Color::gamma2curve[R]; + gbuffer[j] = Color::gamma2curve[G]; + bbuffer[j] = Color::gamma2curve[B]; + } + for (int j = 0; j < W; ++j) { + dst[ix++] = uint16ToUint8Rounded(rbuffer[j]); + dst[ix++] = uint16ToUint8Rounded(gbuffer[j]); + dst[ix++] = uint16ToUint8Rounded(bbuffer[j]); + } + +#else + for (int j = 0; j < W; ++j) { + float R, G, B; + float x_, y_, z_; + Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_ ); + Color::xyz2rgb(x_, y_, z_, R, G, B, rgb_xyzf); dst[ix++] = uint16ToUint8Rounded(Color::gamma2curve[R]); dst[ix++] = uint16ToUint8Rounded(Color::gamma2curve[G]); dst[ix++] = uint16ToUint8Rounded(Color::gamma2curve[B]); } +#endif } } @@ -151,8 +196,6 @@ void ImProcFunctions::lab2monitorRgb(LabImage* lab, Image8* image) // otherwise divide by 327.68, convert to xyz and apply the RGB transform, before converting with gamma2curve Image8* ImProcFunctions::lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings) { - //gamutmap(lab); - if (cx < 0) { cx = 0; } @@ -172,11 +215,10 @@ Image8* ImProcFunctions::lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, Image8* image = new Image8(cw, ch); Glib::ustring profile; - bool standard_gamma; + cmsHPROFILE oprof = nullptr; if (settings->HistogramWorking && consider_histogram_settings) { profile = icm.workingProfile; - standard_gamma = true; } else { profile = icm.outputProfile; @@ -184,27 +226,15 @@ Image8* ImProcFunctions::lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, profile = "sRGB"; } - standard_gamma = false; + oprof = ICCStore::getInstance()->getProfile(profile); } - cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(profile); - if (oprof) { - cmsHPROFILE oprofG = oprof; - - if (standard_gamma) { - oprofG = ICCStore::makeStdGammaProfile(oprof); - } - - cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; - - if (icm.outputBPC) { - flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; - } + const cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE | (icm.outputBPC ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0); // NOCACHE is important for thread safety lcmsMutex->lock(); cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); - cmsHTRANSFORM hTransform = cmsCreateTransform (LabIProf, TYPE_Lab_DBL, oprofG, TYPE_RGB_FLT, icm.outputIntent, flags); // NOCACHE is important for thread safety + cmsHTRANSFORM hTransform = cmsCreateTransform (LabIProf, TYPE_Lab_DBL, oprof, TYPE_RGB_FLT, icm.outputIntent, flags); cmsCloseProfile(LabIProf); lcmsMutex->unlock(); @@ -245,9 +275,6 @@ Image8* ImProcFunctions::lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, cmsDeleteTransform(hTransform); - if (oprofG != oprof) { - cmsCloseProfile(oprofG); - } } else { const auto xyz_rgb = ICCStore::getInstance()->workingSpaceInverseMatrix(profile); copyAndClamp(lab, image->data, xyz_rgb, multiThread); @@ -370,7 +397,6 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, if (transform) { hTransform = transform; } else { - double pwr = 1.0 / gampos; double ts = slpos; int five = mul; @@ -486,8 +512,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } GammaValues g_a; //gamma parameters - constexpr int mode = 0; - Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 + Color::calcGamma(pwr, ts, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 cmsFloat64Number gammaParams[7]; diff --git a/rtengine/iplocalcontrast.cc b/rtengine/iplocalcontrast.cc index daeb142dd..74d02d3fa 100644 --- a/rtengine/iplocalcontrast.cc +++ b/rtengine/iplocalcontrast.cc @@ -27,32 +27,51 @@ #include "labimage.h" #include "improcfun.h" #include "procparams.h" +#include "settings.h" namespace rtengine { -void ImProcFunctions::localContrast(LabImage *lab) +void ImProcFunctions::localContrast(LabImage *lab, float **destination, const rtengine::procparams::LocalContrastParams &localContrastParams, bool fftwlc, double scale) { - if (!params->localContrast.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..b80e5fc78 --- /dev/null +++ b/rtengine/iplocallab.cc @@ -0,0 +1,14922 @@ +/* + * 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, 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 * std::cos(hueref); + const float refb = chromaref * std::sin(hueref); + const float refL = lumaref; + float maxdE = 5.f + MAXSCOPE * lap; + + 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++) { + const float val = 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; + dE[y * bfw + x] = val; + maxC = rtengine::max(maxC, val); + } + } + + 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] = dE[y * bfw + x] >= maxdE ? ade * dE[y * bfw + x] + bde : 1.f; + dE[y * bfw + x] = dE[y * bfw + x] >= maxdE ? ade * (dE[y * bfw + x] - maxC) : 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; + 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 str_mas; + float ang_mas; + 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 blendmaL; + float radmaL; + float chromaL; + + 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 dehazeSaturation; + 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; + int showmasklogmet; + int showmask_met; + bool fftbl; + float laplacexp; + float balanexp; + float linear; + int expmet; + int softmet; + int blurmet; + int blmet; + int smasktyp; + int chromet; + int quamet; + 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 islocal; + bool maskena; + 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; + bool enaLMask; + bool ena_Mask; + int highlihs; + int shadowhs; + int radiushs; + int hltonalhs; + int shtonalhs; + int scalereti; + float sourcegray; + float targetgray; + float blackev; + float whiteev; + float detail; + int sensilog; + int sensimas; + 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; + bool fftma; + float blurma; + float contma; + bool activspot; + +}; + +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, int lllogMask, int ll_Mask, 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; + } +*/ + 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.showmasklogmet = lllogMask; + lp.showmask_met = ll_Mask; + + 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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&& lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 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 && lllogMask == 0 && ll_Mask == 0; + lp.ena_Mask = locallab.spots.at(sp).enamask && lllcMask == 0 && llcbMask == 0 && llsoftMask == 0 && llsharMask == 0 && llColorMask == 0 && llExpMask == 0 && llSHMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && lllogMask == 0 && llvibMask == 0; + lp.enaLMask = locallab.spots.at(sp).enaLMask && lllogMask == 0 && llColorMask == 0 && lllcMask == 0 && llsharMask == 0 && llExpMask == 0 && llSHMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llblMask == 0 && llvibMask == 0 && ll_Mask == 0;// Exposure mask is deactivated if Color & Light mask is visible + + // 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).quamethod == "cons") { + lp.quamet = 0; + } else if (locallab.spots.at(sp).quamethod == "agre") { + lp.quamet = 1; + } + + 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).invbl == false) { + lp.blurmet = 0; + } else if (locallab.spots.at(sp).invbl == true) { + 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_dehazeSaturation = locallab.spots.at(sp).dehazeSaturation; + 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_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 strmask = ((float) locallab.spots.at(sp).str_mask); + float angmask = ((float) locallab.spots.at(sp).ang_mask); + 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; + + float blendmaskL = ((float) locallab.spots.at(sp).blendmaskL) / 100.f ; + float radmaskL = ((float) locallab.spots.at(sp).radmaskL); + float chromaskL = ((float) locallab.spots.at(sp).chromaskL); + + 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.sensimas = locallab.spots.at(sp).sensimask; + + 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.str_mas = strmask; + lp.ang_mas = angmask; + + 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.blendmaL = blendmaskL; + lp.radmaL = radmaskL; + lp.chromaL = chromaskL; + + 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.dehazeSaturation = local_dehazeSaturation; + lp.depth = local_depth; + lp.senscb = local_sensicb; + lp.clarityml = local_clarityml; + lp.contresid = local_contresid; + 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; + lp.blurma = (float) locallab.spots.at(sp).blurmask; + lp.fftma = locallab.spots.at(sp).fftmask; + lp.contma = (float) locallab.spots.at(sp).contmask; + + 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.activspot = locallab.spots.at(sp).activ; + + + lp.detailsh = locallab.spots.at(sp).detailSH; + lp.threshol = thresho; + lp.chromacb = chromcbdl; + lp.expvib = locallab.spots.at(sp).expvibrance && lp.activspot ; + lp.colorena = locallab.spots.at(sp).expcolor && lp.activspot && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; // Color & Light tool is deactivated if Exposure mask is visible or SHMask + lp.blurena = locallab.spots.at(sp).expblur && lp.activspot && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.tonemapena = locallab.spots.at(sp).exptonemap && lp.activspot && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llColorMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.retiena = locallab.spots.at(sp).expreti && lp.activspot && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0 && llSHMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.lcena = locallab.spots.at(sp).expcontrast && lp.activspot && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llcbMask == 0 && llsharMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0 && llSHMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.cbdlena = locallab.spots.at(sp).expcbdl && lp.activspot && llExpMask == 0 && llsoftMask == 0 && llSHMask == 0 && llretiMask == 0 && lllcMask == 0 && llsharMask == 0 && lllcMask == 0 && llColorMask == 0 && lltmMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.exposena = locallab.spots.at(sp).expexpose && lp.activspot && llColorMask == 0 && llsoftMask == 0 && llSHMask == 0 && lllcMask == 0 && llsharMask == 0 && llcbMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; // Exposure tool is deactivated if Color & Light mask SHmask is visible + lp.hsena = locallab.spots.at(sp).expshadhigh && lp.activspot && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && lltmMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0;// Shadow Highlight tool is deactivated if Color & Light mask or SHmask is visible + lp.vibena = locallab.spots.at(sp).expvibrance && lp.activspot && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && llSHMask == 0 && lllogMask == 0 && ll_Mask == 0;// vibrance tool is deactivated if Color & Light mask or SHmask is visible + lp.sharpena = locallab.spots.at(sp).expsharp && lp.activspot && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && llSHMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.sfena = locallab.spots.at(sp).expsoft && lp.activspot && llColorMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && llSHMask == 0 && llvibMask == 0 && lllogMask == 0 && ll_Mask == 0; + lp.maskena = locallab.spots.at(sp).expmask && lp.activspot && llColorMask == 0 && llsoftMask == 0 && llExpMask == 0 && llcbMask == 0 && lllcMask == 0 && llsharMask == 0 && llretiMask == 0 && llcbMask == 0 && lltmMask == 0 && lllogMask == 0 && llSHMask == 0;// vibrance tool is deactivated if Color & Light mask or SHmask is visible + lp.logena = locallab.spots.at(sp).explog && lp.activspot && 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.islocal = (lp.expvib || lp.colorena || lp.blurena || lp.tonemapena || lp.retiena || lp.lcena || lp.cbdlena || lp.exposena || lp.hsena || lp.vibena || lp.sharpena || lp.sfena || lp.maskena || lp.logena); + + 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 = pow(interm, 3.f); + 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 vibrance shadows + lp.sens = lp.senscolor; + lp.sensv = lp.senscolor; + lp.senshs = 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, 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; + + float dynamic_range = lp.whiteev - lp.blackev; + if (dynamic_range < 0.5f) { + dynamic_range = 0.5f; + } + const float noise = pow_F(2.f, -16.f); + // const float log2 = xlogf(lp.baselog); + const float log2 = xlogf(2.f); + 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; + f = min(f, 1000000.f); + + r *= f; + b *= f; + g *= f; + r = CLIP(r); + g = CLIP(g); + b = CLIP(b); + } + + 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); + f = min(f, 1000000.f); + + // assert(std::isfinite(f)); + r *= f; + g *= f; + b *= f; + r = CLIP(r); + g = CLIP(g); + b = CLIP(b); + // 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, float *sourceab, 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; + + + //calculate La - Absolute luminance shooting + + const FramesMetaData* metaData = imgsrc->getMetaData(); + int imgNum = 0; + + if (imgsrc->isRAW()) { + if (imgsrc->getSensorType() == ST_BAYER) { + imgNum = rtengine::LIM(params->raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); + } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { + //imgNum = rtengine::LIM(params->raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); + } + } + + float fnum = metaData->getFNumber(imgNum); // F number + float fiso = metaData->getISOSpeed(imgNum) ; // ISO + float fspeed = metaData->getShutterSpeed(imgNum) ; // Speed + double fcomp = metaData->getExpComp(imgNum); // Compensation +/- + double adap; + + if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong + adap = 2000.; + } else { + double E_V = fcomp + std::log2(double ((fnum * fnum) / fspeed / (fiso / 100.f))); + E_V += params->toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV + E_V += std::log2(params->raw.expos); // exposure raw white point ; log2 ==> linear to EV + adap = pow(2.0, E_V - 3.0); // cd / m2 + // end calculation adaptation scene luminosity + } + + sourceab[sp] = adap; + } +} + +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.getWidth(); + const int H = R.getHeight(); + 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, int call) +{ + //BENCHFUN + bool ciec = false; + if (params->locallab.spots.at(sp).ciecam && params->locallab.spots.at(sp).explog && call == 1) { + ciec = true; + } + 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; + + LUTu hist16J; + LUTu hist16Q; + //for J light and contrast + LUTf CAMBrightCurveJ; + CAMBrightCurveJ(32768, LUT_CLIP_ABOVE); + CAMBrightCurveJ.dirty = true; + + LUTf CAMBrightCurveQ; + CAMBrightCurveQ(32768, LUT_CLIP_ABOVE); + CAMBrightCurveQ.dirty = true; + + if (CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty) { + hist16J(32768); + hist16J.clear(); + 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()); + #pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif + { + LUTu hist16Jthr; + LUTu hist16Qthr; + hist16Jthr(hist16J.getSize()); + hist16Jthr.clear(); + hist16Qthr(hist16Q.getSize()); + hist16Qthr.clear(); + +#ifdef _OPENMP + #pragma omp for reduction(+:sum) +#endif + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { //rough correspondence between L and J + float currL = lab->L[i][j] / 327.68f; + float koef; //rough correspondence between L and J + + if (currL > 50.f) { + if (currL > 70.f) { + if (currL > 80.f) { + if (currL > 85.f) { + koef = 0.97f; + } else { + koef = 0.93f; + } + } else { + koef = 0.87f; + } + } else { + if (currL > 60.f) { + koef = 0.85f; + } else { + koef = 0.8f; + } + } + } else { + if (currL > 10.f) { + if (currL > 20.f) { + if (currL > 40.f) { + koef = 0.75f; + } else { + koef = 0.7f; + } + } else { + koef = 0.9f; + } + } else { + koef = 1.0; + } + } + + hist16Jthr[(int)((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J + 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 + sum += static_cast(koef) * static_cast(lab->L[i][j]); //evaluate mean J to calculate Yb + //sum not used, but perhaps... + } + } + +#ifdef _OPENMP + #pragma omp critical +#endif + { + hist16J += hist16Jthr; + hist16Q += hist16Qthr; + } + } +#ifdef _OPENMP + static_cast(numThreads); // to silence cppcheck warning +#endif + + //evaluate lightness, contrast + } + + float contL = 0.f; + float lightL = 0.f; + float contQ = 0.f; + float lightQ = 0.f; + + if (ciec) { + contL = 0.6f *params->locallab.spots.at(sp).contl;//0.6 less effect, no need 1. + lightL = 0.4f *params->locallab.spots.at(sp).lightl;//0.4 less effect, no need 1. + contQ = 0.5f *params->locallab.spots.at(sp).contq;//0.5 less effect, no need 1. + lightQ = 0.4f *params->locallab.spots.at(sp).lightq;//0.4 less effect, no need 1. + + if (CAMBrightCurveJ.dirty) { + Ciecam02::curveJfloat(lightL, contL, hist16J, CAMBrightCurveJ); //lightness J and contrast J + CAMBrightCurveJ /= 327.68f; + CAMBrightCurveJ.dirty = false; + } + + if (CAMBrightCurveQ.dirty) { + Ciecam02::curveJfloat(lightQ, contQ, hist16Q, CAMBrightCurveQ); //brightness Q and contrast Q + CAMBrightCurveQ.dirty = false; + } + + } + int tempo = 5000; + if(params->locallab.spots.at(sp).expvibrance && call == 2) { + if (params->locallab.spots.at(sp).warm > 0) { + tempo = 5000 - 30 * params->locallab.spots.at(sp).warm; + } else if (params->locallab.spots.at(sp).warm < 0){ + tempo = 5000 - 70 * params->locallab.spots.at(sp).warm; + } + } + + if(ciec) { + if (params->locallab.spots.at(sp).catad > 0) { + tempo = 5000 - 30 * params->locallab.spots.at(sp).catad; + } else if (params->locallab.spots.at(sp).catad < 0){ + tempo = 5000 - 70 * params->locallab.spots.at(sp).catad; + } + } + + 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; + if(ciec) { + //surround source with only 2 choices (because Log encoding before) + if (params->locallab.spots.at(sp).sursour == "Average") { + f = 1.0f, c = 0.69f, nc = 1.0f; + } else if (params->locallab.spots.at(sp).sursour == "Dim") { + f = 0.9f; + c = 0.59f; + nc = 0.9f; + } + + //viewing condition for surround + if (params->locallab.spots.at(sp).surround == "Average") { + f2 = 1.0f, c2 = 0.69f, nc2 = 1.0f; + } else if (params->locallab.spots.at(sp).surround == "Dim") { + f2 = 0.9f; + c2 = 0.59f; + nc2 = 0.9f; + } else if (params->locallab.spots.at(sp).surround == "Dark") { + f2 = 0.8f; + c2 = 0.525f; + nc2 = 0.8f; + } else if (params->locallab.spots.at(sp).surround == "ExtremelyDark") { + f2 = 0.8f; + c2 = 0.41f; + nc2 = 0.8f; + } + } + + xwd = 100.0 * Xwout; + zwd = 100.0 * Zwout; + ywd = 100.f; + + xws = 100.0 * Xwsc; + zws = 100.0 * Zwsc; + yws = 100.f; + + + //La and la2 = ambiant luminosity scene and viewing + la = 400.f; + float la2 = 400.f; + if(ciec) { + la = params->locallab.spots.at(sp).sourceabs; + + la2 = params->locallab.spots.at(sp).targabs; + } + + const float pilot = 2.f; + const float pilotout = 2.f; + + //algoritm's params + float yb = 18.f; + yb2 = 18; + if(ciec) { + yb = params->locallab.spots.at(sp).targetGray;//target because we are after Log encoding + + yb2 = params->locallab.spots.at(sp).targetGray; + } + + float schr = 0.f; + float mchr = 0.f; + + if (ciec) { + schr = params->locallab.spots.at(sp).saturl; + + if (schr > 0.f) { + schr = schr / 2.f; //divide sensibility for saturation + } + + if (schr == -100.f) { + schr = -99.8f; + } + + mchr = params->locallab.spots.at(sp).colorfl; + + if (mchr == -100.0f) { + mchr = -99.8f ; + } + if (mchr == 100.0f) { + mchr = 99.9f; + } + } + + 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 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 epsil = 0.0001f; + const float coefQ = 32767.f / wh; + const float pow1n = pow_F(1.64f - pow_F(0.29f, nj), 0.73f); + const float coe = pow_F(fl, 0.25f); + const float QproFactor = (0.4f / c) * (aw + 4.0f) ; + +#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; + /* + */ + if(ciec) { + Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)] / coefQ; //brightness and contrast + float rstprotection = 50.f;//default value to avoid 1 slider + float chr = 0.f;//no use of chroma + float Mp, sres; + Mp = Mpro / 100.0f; + 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); + Cpro = Mpro / coe; + Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero + spro = 100.0f * sqrtf(Mpro / Qpro); + + if (Jpro > 99.9f) { + Jpro = 99.9f; + } + + Jpro = CAMBrightCurveJ[(float)(Jpro * 327.68f)]; //lightness CIECAM02 + contrast + float Sp = spro / 100.0f; + 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); + 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); + } + + //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) / 100.f; + const float bepsil = epsilmin; //epsilmax - 100.f * aepsil; + // const float epsil = aepsil * 0.1f * rad + bepsil; + const float epsil = aepsil * 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) / 1000.f; + const float bepsil = epsilmin; //epsilmax - 100.f * aepsil; + const float epsil = rad < 0.f ? 0.0001f : aepsil * 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, int bfhr, int bfwr, LabImage* bufexporig, LabImage* lab, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, const float hueref, const float lumaref, const float chromaref) +{ + //BENCHFUN + //exposure local + + constexpr float maxran = 65536.f; + if(lp.laplacexp == 0.f) { + lp.linear = 0.f; + } + + const float linear = lp.linear; + int bw = bfw; + int bh = bfh; + if (linear > 0.f && lp.expcomp == 0.f) { + lp.expcomp = 0.001f; + } + const bool exec = (lp.expmet == 1 && linear > 0.f && lp.laplacexp > 0.1f); + + if(!exec) {//for standard exposure + 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 diffde = 100.f - lp.sensex;//the more scope, the less take into account dE for Laplace + if(!lp.invex) {// Laplacian not in inverse + bw = bfwr; + bh = bfhr; + + //Laplacian PDE before exposure to smooth L, algorithm exposure leads to increase L differences + 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(), diffde, bfwr, bfhr, bufexporig, hueref, chromaref, lumaref); + + constexpr float alap = 600.f; + constexpr float blap = 100.f; + constexpr float aa = (alap - blap) / 50.f; + constexpr float bb = 100.f - 30.f * aa; + + float lap; + if (diffde > 80.f) { + lap = alap; + } else if (diffde < 30.f) { + lap = blap; + } else { + lap = aa * diffde + bb; + } + +#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] = bufexporig->L[y][x]; + } + } + + MyMutex::MyLock lock(*fftwMutex); + ImProcFunctions::retinex_pde(datain.get(), dataout.get(), bfwr, bfhr, lap, 1.f, dE.get(), 0, 1, 1);//350 arbitrary value about 45% strength Laplacian +#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++) { + bufexporig->L[y][x] = dataout[y * bfwr + x]; + } + } + + } + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int ir = 0; ir < bh; ir++) {//for standard with Laplacian in normal and without in inverse + for (int jr = 0; jr < bw; 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]; + } + } + } else if(!lp.invex) {//for PDE algorithms + constexpr float kl = 1.f; + const float hlcompthr = lp.hlcompthr / 200.f; + const float hlcomp = lp.hlcomp / 100.f; + +#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.f, 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]; + } + } + } +} + +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, 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 { + calcTransitionrect(lox, loy, ach, lp, zone, localFactor); + } + float reducdE; + if (zone != 2) { + 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])); + reducdE = calcreducdE(dE, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, lp.sensbn); + } + + switch (zone) { + + case 0: { // outside selection and outside transition zone => full effect, no transition + const float diflc = (tmp1->L[y][x] - original->L[y][x]) * reducdE; + const float difa = (tmp1->a[y][x] - original->a[y][x]) * reducdE; + const float difb = (tmp1->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); + + if (blshow) { + transformed->L[y][x] = CLIP(12000.f + diflc); + 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 + const float factorx = 1.f - localFactor; + + const float diflc = (tmp1->L[y][x] - original->L[y][x]) * (reducdE * factorx); + const float difa = (tmp1->a[y][x] - original->a[y][x]) * (reducdE * factorx); + const float difb = (tmp1->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); + + if (blshow) { + transformed->L[y][x] = CLIP(12000.f + diflc); + 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: { // 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]; + } + } + } + } + } +} + + + +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; + } else if (indic == 12) { + stops = -lp.str_mas; + angs = lp.ang_mas; + } + + + 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, float blab, 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 + blab * bufmaskor->a[y][x]); + bufexporig->b[y][x] *= (1.f + blab * 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 + blab * localFactor * bufmaskor->a[y][x]); + original->b[y + ystart][x + xstart] *= (1.f + blab * 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 + blab * bufmaskor->a[y][x]); + bufexporig->b[y][x] *= (1.f + blab * 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 + blab * bufmaskor->a[y][x]); + original->b[y + ystart][x + xstart] *= (1.f + blab * 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 + blab * localFactor * bufmaskor->a[y][x]); + original->b[y + ystart][x + xstart] *= (1.f + blab * 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) +{ + float lum = fabs(lumask * 400.f); + float colo = 0.f; + if(lumask < 0.f) { + lum *= 1.4f; + colo = 30000.f + 12.f * lum; + } + +#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] = (lum) + 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] = (colo) + bufexporig->b[y][x] * bufmaskorigSH->b[y][x]; + } + } else if (inv == 1) { //inverse + if (zone == 0) { + transformed->L[y + ystart][x + xstart] = (lum) + 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] = (colo) + 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 *datashow = nullptr; + if (show != 0) { + datashow = (float *) fftwf_malloc(sizeof(float) * bfw * bfh); + if (!datashow) { + fprintf(stderr, "allocation error\n"); + abort(); + } + } + + float *data_tmp = (float *) fftwf_malloc(sizeof(float) * bfw * bfh); + if (!data_tmp) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + //first call to laplacian with plein strength + discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, thresh); + + float *data_fft = (float *) fftwf_malloc(sizeof(float) * bfw * bfh); + if (!data_fft) { + 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]; + } + } + } + + //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); + fftwf_destroy_plan(dct_fw); + + //execute second + if (dEenable == 1) { + float* data_fft04 = (float *)fftwf_malloc(sizeof(float) * bfw * bfh); + float* data_tmp04 = (float *)fftwf_malloc(sizeof(float) * bfw * bfh); + if (!data_fft04 || !data_tmp04) { + fprintf(stderr, "allocation error\n"); + abort(); + } + //second call to laplacian with 40% strength ==> reduce effect if we are far from ref (deltaE) + discrete_laplacian_threshold(data_tmp04, datain, bfw, bfh, 0.4f * thresh); + 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); + constexpr float exponent = 4.5f; + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { +#ifdef __SSE2__ + const vfloat exponentv = F2V(exponent); +#endif +#ifdef _OPENMP + #pragma omp for +#endif + for (int y = 0; y < bfh ; y++) {//mix two fftw Laplacian : plein if dE near ref + int x = 0; +#ifdef __SSE2__ + for (; x < bfw - 3; x += 4) { + STVFU(data_fft[y * bfw + x], intp(pow_F(LVFU(dE[y * bfw + x]), exponentv), LVFU(data_fft[y * bfw + x]), LVFU(data_fft04[y * bfw + x]))); + } +#endif + for (; x < bfw; x++) { + data_fft[y * bfw + x] = intp(pow_F(dE[y * bfw + x], exponent), data_fft[y * bfw + x], data_fft04[y * bfw + x]); + } + } + } + fftwf_free(data_fft04); + fftwf_free(data_tmp04); + } + 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]; + } + } + } + + /* solve the Poisson PDE in Fourier space */ + /* 1. / (float) (bfw * bfh)) is the DCT normalisation term, see libfftw */ + 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_tmp, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_bw); + fftwf_destroy_plan(dct_bw); + fftwf_free(data_fft); + + if (show != 4 && normalize == 1) { + normalize_mean_dt(data_tmp, 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_tmp[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(data_tmp); + if (datashow) { + fftwf_free(datashow); + } + fftwf_cleanup(); + +#ifdef RT_FFTW3F_OMP + if (multiThread) { + fftwf_cleanup_threads(); + } +#endif +} + +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, float blendmab, int shado, int highl, 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, + bool fftt, float blu_ma, float cont_ma, int indic + ) + + +{ + 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 (blu_ma >= 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 (cont_ma > 0.f) { + float contra = cont_ma; + buildBlendMask(bufcolorig->L, blendblur, bfw, bfh, contra); + + + float radblur = 0.25f + 0.002f * std::fabs(rad);//empirical value + float rm = radblur / sk; + + if (fftt) { + 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 (blu_ma >= 0.25f) { + if (!fftt) { // || (lp.fftColorMask && call != 2)) { +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(bufcolorig->L, blur, bfw, bfh, blu_ma / sk); + } + } else { + ImProcFunctions::fftw_convol_blur2(bufcolorig->L, blur, bfw, bfh, blu_ma / 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 (cont_ma > 0.f) { + + if (blu_ma >= 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) { + // printf("s"); + 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.005f; + constexpr float epsilmin = 0.00001f; + + constexpr float aepsil = (epsilmax - epsilmin) / 100.f; + constexpr float bepsil = epsilmin; //epsilmax - 100.f * aepsil; + const float epsil = rad < 0.f ? 0.001f : aepsil * 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); + } + + if (highl > 0) { + ImProcFunctions::shadowsHighlights(bufmaskblurcol, true, 1, highl, 0, 40, sk, 50, 0); + } + + 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 ((indic == 0 && lp.strmaexp != 0.f) || (indic ==12 && lp.str_mas != 0.f)) { + calclocalGradientParams(lp, gp, ystart, xstart, bfw, bfh, indic); +#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, blendmab, 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 + 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, GW, GH, original, temp.get(), hltonecurveloc, shtonecurveloc, tonecurveloc, hueref, lumaref, chromaref); + + 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.expcomp != 0.f) || (exlocalcurve)) { + if (lp.shadex > 0) { + ImProcFunctions::shadowsHighlights(temp.get(), true, 1, 0, lp.shadex, 40, sk, 0, lp.shcomp); + } + } + + 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, 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; + } else if (senstype == 20) { //common mask + varsens = lp.sensimas; + } + 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 logshow = ((lp.showmasklogmet == 1 || lp.showmasklogmet == 2) && senstype == 11); + + const bool masshow = ((lp.showmask_met == 1) && senstype == 20); + + 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); + const bool previewmas = ((lp.showmask_met == 3) && senstype == 20); + const bool previewlog = ((lp.showmasklogmet == 4) && senstype == 11); + + 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 usemaskmas = (lp.showmask_met == 1 || lp.ena_Mask || lp.showmask_met == 3) && senstype == 20; + const bool usemasklog = (lp.showmasklogmet == 2 || lp.enaLMask || lp.showmasklogmet == 4) && senstype == 11; + const bool usemaskall = (usemaskexp || usemaskvib || usemaskcol || usemaskSH || usemasktm || usemasklc || usemasklog || usemaskmas); + + //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 || logshow || origshow || masshow) && 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 || logshow || origshow || masshow) && 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 || previewlog || previeworig || previewmas || 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); + +#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); + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.5f, 0.3f, 0.2f, 0.1f, 0.05f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); + + 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 if (multiThread) +#endif + { +#ifdef __SSE2__ + const vfloat lutFactorv = F2V(lutFactor); +#endif +#ifdef _OPENMP + #pragma omp for +#endif + for (int y = 0; y < H_L; y++) { + int x = 0; + int j = y * W_L; +#ifdef __SSE2__ + for (; x < W_L - 3; x += 4, j += 4) { + const vfloat valv = LVFU(WavL[j]); + STVFU(WavL[j], intp((*meaLut)[vabsf(valv) * lutFactorv], LVFU(templevel[y][x]), valv)); + } +#endif + for (; x < W_L; x++, j++) { + WavL[j] = intp((*meaLut)[std::fabs(WavL[j]) * lutFactor], 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); + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.7f, 0.5f, 0.3f, 0.2f, 0.1f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); + 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); + const vfloat lutFactorv = F2V(lutFactor); +#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 + const vfloat valv = LVFU(WavL[i * W_L + j]); + STVFU(WavL[i * W_L + j], valv * pow_F(onev + kbav * (*meaLut)[vabsf(valv) * lutFactorv], 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 * (*meaLut)[std::fabs(WavL[i * W_L + j]) * lutFactor], 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 float effect = lp.sigmadr; + constexpr float offs = 1.f; + float mea[10]; + calceffect(level, mean, sigma, mea, effect, offs); + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.65f, 0.5f, 0.4f, 0.25f, 0.1f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); + 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]; + } + } + + 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); + + 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 if (multiThread) +#endif + { +#ifdef __SSE2__ + const vfloat lutFactorv = F2V(lutFactor); +#endif +#ifdef _OPENMP + #pragma omp for +#endif + for (int y = 0; y < H_L; y++) { + int x = 0; + int j = y * W_L; +#ifdef __SSE2__ + for (; x < W_L - 3; x += 4, j += 4) { + const vfloat valv = LVFU(wav_L[j]); + STVFU(wav_L[j], intp((*meaLut)[vabsf(valv) * lutFactorv], LVFU(templevel[y][x]), valv)); + } +#endif + for (; x < W_L; x++, j++) { + wav_L[j] = intp((*meaLut)[std::fabs(wav_L[j]) * lutFactor], 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 + std::unique_ptr 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); + const float mult = lp.strwav < 0.f ? -1.f : 1.f; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H_Lm; y++) { + for (int x = 0; x < W_Lm; x++) { + factorwav[y][x] = mult * (1.f - ImProcFunctions::calcGradientFactor(gpwav, x, y)); + } + } + 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); + auto wav_L = wdspot->level_coeffs(level)[dir]; + 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]; + 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; + } + } + klev *= 0.8f; + const float threshold = mean[level] + lp.sigmalc2 * sigma[level]; + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.6f, 0.5f, 0.4f, 0.3f, 0.1f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); + +#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++) { + const float WavCL = std::fabs(wav_L[y * W_L + x]); + + float absciss; + if (WavCL >= threshold) { //for max + absciss = pow_F(WavCL - logmax, rap); + } else if (WavCL >= mean[level]) { + absciss = asig * WavCL + bsig; + } else { + absciss = amean * WavCL; + } + + const float kc = 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; + wav_L[y * W_L + x] *= (1.f + (kinterm - 1.f) * (*meaLut)[WavCL * lutFactor]); + } + } + } + } + } + } + + 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) { + float* src[H_L]; + for (int i = 0; i < H_L; ++i) { + src[i] = &wav_L0[i * W_L]; + } + +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + gaussianBlur(src, src, W_L, H_L, radblur); + } + } + + if (compress != 0.f && compreena) { + const float Compression = expf(-compress); + const float DetailBoost = std::max(compress, 0.f); + + 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 ((lp.residsha > 0.f || lp.residhi > 0.f)) { + const std::unique_ptr temp(new LabImage(W_L, H_L)); +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + temp->L[i][j] = wav_L0[i * W_L + j]; + } + } + + ImProcFunctions::shadowsHighlights(temp.get(), true, 1, lp.residhi, lp.residsha , 40, sk, lp.residhithr, lp.residshathr); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + wav_L0[i * W_L + j] = temp->L[i][j]; + } + } + } + + 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]; + } + + const float avg = LIM01(avedbl / (32768.f * W_L * H_L)); + 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++) { + wav_L0[i] = resid_contrast.getVal(LIM01(wav_L0[i] / 32768.f)) * 32768.f; + } + } + + 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 *koeLibuffer = new float[12 * H_L * W_L]; //12 + + for (int i = 0; i < 12; i++) { + koeLi[i] = &koeLibuffer[i * W_L * H_L]; + } + + array2D tmC(W_L, H_L); + + float gradw = lp.gradw; + float tloww = lp.tloww; + 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); + calckoe(wav_L[dir], gradw, tloww, koeLi[lvl * 3 + dir - 1], lvl, W_L, H_L, edd, maxkoeLi[lvl * 3 + dir - 1], tmC, true); + // return convolution KoeLi and maxkoeLi of level 0 1 2 3 and Dir Horiz, Vert, Diag + } + } + + tmC.free(); + 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; + const float effect = lp.sigmaed; + constexpr float offset = 1.f; + float mea[10]; + calceffect(lvl, mean, sigma, mea, effect, offset); + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.5f, 0.3f, 0.2f, 0.1f, 0.05f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); + + 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) * (*meaLut)[std::fabs(wav_L[dir][k]) * lutFactor]; + } + } + } + } + } + + if (koeLibuffer) { + delete [] koeLibuffer; + } + } + +//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 = std::fabs(wav_L[dir][i]); + + float absciss; + if (val >= limit1) { //for max + const float valcour = xlogf(val); + absciss = xexpf((valcour - logmax) * rap); + } else if (val >= limit2) { + absciss = asig * val + bsig; + } else { + absciss = amean * 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); + + bool reconstruct = false; + if (wavcurvecon && (chromalev != 1.f) && levelena) { // a if need ) {//contrast by levels for chroma a + // a + wdspot.reset(new wavelet_decomposition(tmpa[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen)); + if (wdspot->memory_allocation_failed()) { + return; + } + wavcbd(*wdspot, level_bl, maxlvl, locconwavCurve, locconwavutili, sigm, offs, chromalev, sk); + reconstruct = true; + } + if (wavcurvelev && radlevblur > 0.f && blurena && chromablu > 0.f && !blurlc) {//chroma blur if need + // a + if (!reconstruct) { + wdspot.reset(new wavelet_decomposition(tmpa[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen)); + if (wdspot->memory_allocation_failed()) { + return; + } + } + wavcont(lp, tmp, *wdspot, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 1, chromablu, 0.f, 0.f, 0.f); + reconstruct = true; + } + if (reconstruct) { + wdspot->reconstruct(tmpa[0], 1.f); + } + + reconstruct = false; + if (wavcurvecon && (chromalev != 1.f) && levelena) { // b if need ) {//contrast by levels for chroma b + //b + wdspot.reset(new wavelet_decomposition(tmpb[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen)); + if (wdspot->memory_allocation_failed()) { + return; + } + //b + wavcbd(*wdspot, level_bl, maxlvl, locconwavCurve, locconwavutili, sigm, offs, chromalev, sk); + reconstruct = true; + } + + if (wavcurvelev && radlevblur > 0.f && blurena && chromablu > 0.f && !blurlc) {//chroma blur if need + //b + if (!reconstruct) { + wdspot.reset(new wavelet_decomposition(tmpb[0], bfw, bfh, maxlvl, 1, sk, numThreads, lp.daubLen)); + if (wdspot->memory_allocation_failed()) { + return; + } + } + wavcont(lp, tmp, *wdspot, level_bl, maxlvl, loclevwavCurve, loclevwavutili, loccompwavCurve, loccompwavutili, loccomprewavCurve, loccomprewavutili, radlevblur, 1, chromablu, 0.f, 0.f, 0.f); + reconstruct = true; + } + if (reconstruct) { + wdspot->reconstruct(tmpb[0], 1.f); + } +} + + +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.quamet == 0 && 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.quamet == 0 && 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.quamet == 0 && 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.quamet == 0 && 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::avoidcolshi(struct local_params& lp, int sp, LabImage * original, LabImage *transformed, int cy, int cx) +{ + if (params->locallab.spots.at(sp).avoid && lp.islocal) { + 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; + } + } + } + } + } +} + + +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 LocCHCurve& locchCurve, + 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 LUTf& lmaskloglocalcurve, bool localmasklogutili, + const LUTf& lmasklocal_curve, bool localmask_utili, + + 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 LocCCmaskCurve& locccmaslogCurve, bool lcmaslogutili, const LocLLmaskCurve& locllmaslogCurve, bool llmaslogutili, const LocHHmaskCurve& lochhmaslogCurve, bool lhmaslogutili, + const LocCCmaskCurve& locccmas_Curve, bool lcmas_utili, const LocLLmaskCurve& locllmas_Curve, bool llmas_utili, const LocHHmaskCurve& lochhmas_Curve, bool lhmas_utili, + const LocHHmaskCurve& lochhhmas_Curve, bool lhhmas_utili, + 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, + const LocwavCurve& loclmasCurve_wav, bool lmasutili_wav, + + bool LHutili, bool HHutili, bool CHutili, 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, int lllogMask, int ll_Mask, + 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, lllogMask, ll_Mask, 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 && lp.activspot) {//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 || lp.showmasklogmet == 2 || lp.enaLMask || lp.showmasklogmet == 3 || lp.showmasklogmet == 4) { + + 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 + + std::unique_ptr bufmaskblurlog; + std::unique_ptr originalmasklog; + std::unique_ptr bufmaskoriglog; + + if (lp.showmasklogmet == 2 || lp.enaLMask || lp.showmasklogmet == 3 || lp.showmasklogmet == 4) { + bufmaskblurlog.reset(new LabImage(bfw, bfh)); + originalmasklog.reset(new LabImage(bfw, bfh)); + bufmaskoriglog.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]; + bufexporig->a[y - ystart][x - xstart] = original->a[y][x]; + bufexporig->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.showmasklogmet == 3) { + showmaske = true; + } + + if (lp.enaLMask) { + enaMask = true; + } + + if (lp.showmasklogmet == 4) { + deltaE = true; + } + + if (lp.showmasklogmet == 2) { + modmask = true; + } + + if (lp.showmasklogmet == 1) { + modif = true; + } + + if (lp.showmasklogmet == 0) { + zero = true; + } + float chrom = lp.chromaL; + float rad = lp.radmaL; + float blendm = lp.blendmaL; + 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; + const int highl = 0; + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskoriglog.get(), originalmasklog.get(), original, reserved, inv, lp, + 0.f, false, + locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, blendm, shado, highl, amountcd, anchorcd, lmaskloglocalcurve, localmasklogutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + if (lp.showmasklogmet == 3) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufexporig.get(), transformed, bufmaskoriglog.get(), 0); + + return; + } + if (lp.showmasklogmet == 0 || lp.showmasklogmet == 1 || lp.showmasklogmet == 2 || lp.showmasklogmet == 4 || lp.enaLMask) { + + bufexpfin->CopyFrom(bufexporig.get(), multiThread); + std::unique_ptr tmpImage(new Imagefloat(bfw, bfh)); + std::unique_ptr tmpImageorig(new Imagefloat(bfw, bfh)); + lab2rgb(*bufexpfin, *tmpImage, 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++) { + tmpImageorig->r(y, x) = tmpImage->r(y, x); + tmpImageorig->g(y, x) = tmpImage->g(y, x); + tmpImageorig->b(y, x) = tmpImage->b(y, x); + } + } + + log_encode(tmpImage.get(), lp, multiThread, bfw, bfh); + float repart = 1.f - 0.01f * params->locallab.spots.at(sp).repar; + +#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++) { + tmpImage->r(y, x) = intp(repart, tmpImageorig->r(y, x), tmpImage->r(y, x)); + tmpImage->g(y, x) = intp(repart, tmpImageorig->g(y, x), tmpImage->g(y, x)); + tmpImage->b(y, x) = intp(repart, tmpImageorig->b(y, x), tmpImage->b(y, x)); + } + } + + rgb2lab(*(tmpImage.get()), *bufexpfin, params->icm.workingProfile); + + tmpImageorig.reset(); + tmpImage.reset(); + if (params->locallab.spots.at(sp).ciecam) { + ImProcFunctions::ciecamloc_02float(sp, bufexpfin.get(), 1); + } + + //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(), originalmasklog.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); + } + } + } + +//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; + + 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; + const std::unique_ptr bufblorig(new LabImage(GW, GH)); + + std::unique_ptr originalmaskbl; + 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, true)); + originalmaskbl.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++) { + bufblorig->L[y][x] = original->L[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.showmaskblmet == 3) { + showmaske = true; + } + + if (lp.enablMask) { + enaMask = true; + } + + if (lp.showmaskblmet == 4) { + deltaE = true; + } + + if (lp.showmaskblmet == 2) { + modmask = true; + } + + if (lp.showmaskblmet == 1) { + modif = true; + } + + if (lp.showmaskblmet == 0) { + zero = true; + } + + float chrom = lp.chromabl; + float rad = lp.radmabl; + float gamma = lp.gammabl; + float slope = lp.slomabl; + float blendm = lp.blendmabl; + float lap = params->locallab.spots.at(sp).lapmaskbl; + bool pde = params->locallab.spots.at(sp).laplac; + LocwavCurve dummy; + bool delt = params->locallab.spots.at(sp).deltae; + int lumask = params->locallab.spots.at(sp).lumask; + int sco = params->locallab.spots.at(sp).scopemask; + int shortcu = 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); + const int shado = params->locallab.spots.at(sp).shadmaskblsha; + const int highl = params->locallab.spots.at(sp).shadmaskbl; + constexpr float amountcd = 0.f; + constexpr float anchorcd = 50.f; + LocHHmaskCurve lochhhmasCurve; + constexpr bool lhhmasutili = false; + const float strumask = 0.02f * params->locallab.spots.at(sp).strumaskbl; + bool astool = params->locallab.spots.at(sp).toolbl; + + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufblorig.get(), bufmaskblurbl.get(), originalmaskbl.get(), original, reserved, inv, lp, + strumask, astool, + locccmasblCurve, lcmasblutili, locllmasblCurve, llmasblutili, lochhmasblCurve, lhmasblutili, lochhhmasCurve, lhhmasutili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, blendm, shado, highl, amountcd, anchorcd, lmaskbllocalcurve, localmaskblutili, loclmasCurveblwav, lmasutiliblwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, 0 + ); + + if (lp.showmaskblmet == 3) { + showmask(lumask, lp, 0, 0, cx, cy, GW, GH, bufblorig.get(), transformed, bufmaskblurbl.get(), inv); + return; + } + + } + + bool execmaskblur = (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.smasktyp != 1; + int strengr = params->locallab.spots.at(sp).strengr; + + if (((radius > 1.5 * GAUSS_SKIP && lp.rad > 1.6) || lp.stren > 0.1 || lp.blmet == 1 || lp.guidb > 0 || strengr > 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 scalegr = 100;//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]; + tmp1->L[y][x] = original->L[y][x]; + tmp1->a[y][x] = original->a[y][x]; + tmp1->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.get(), 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.get(), lp, hueref, chromaref, lumaref, original, transformed, tmp1.get(), cx, cy, sk); + } else { + InverseBlurNoise_Local(original, 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.get(), 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.get(), 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); + } + } + + +//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; + const int highl = 0; + 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, blendm, shado, highl, amountcd, anchorcd, lmaskcblocalcurve, localmaskcbutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.0f, 0.f, -1 + ); + + 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, 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.001, 0.00001, 0.5f, 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, 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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmaskviblocalcurve, localmaskvibutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + 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(), 2); + } + + + 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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmasktmlocalcurve, localmasktmutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + 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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmasktmlocalcurve, localmasktmutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + 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; + const Glib::ustring profile = params->icm.workingProfile; + bool isworking = (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1"); + + if (isworking && (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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmaskSHlocalcurve, localmaskSHutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + 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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmaskSHlocalcurve, localmaskSHutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + + 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 > 1.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; + const int highl = 0; + 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, blendm, shado, highl, amountcd, anchorcd, lmasklclocalcurve, localmasklcutili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, -1 + ); + + 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.001, 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.saturation = lp.dehazeSaturation; + dehazeParams.depth = lp.depth; + 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.shadex > 0 || lp.hlcomp > 0.f || 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 || lp.expmet == 0) { + 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)); + const std::unique_ptr buforig(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]; + buforig->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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmaskexplocalcurve, localmaskexputili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, 0 + ); + + 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.001f;// to enabled + } + + ImProcFunctions::exlabLocal(lp, bfh, bfw, bfhr, bfwr, bufexpfin.get(), bufexpfin.get(), hltonecurveloc, shtonecurveloc, tonecurveloc, hueref, lumaref, chromaref); + + + } else { + if (lp.expcomp != 0.f ) { // || lp.laplacexp > 0.1f + if(lp.laplacexp <= 0.1f) { + lp.laplacexp = 0.2f; //force to use Laplacian wth very small values + } + ImProcFunctions::exlabLocal(lp, bfh, bfw, bfhr, bfwr, bufexporig.get(), bufexpfin.get(), hltonecurveloc, shtonecurveloc, tonecurveloc, hueref, lumaref, chromaref); + } + } + +//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; + } + } + } + } + if (lp.shadex > 0) { + if (lp.expcomp == 0.f) { + lp.expcomp = 0.001f; // to enabled + } + } + + if (lp.hlcomp > 0.f) { + if (lp.expcomp == 0.f) { + lp.expcomp = 0.001f; // to enabled + } + } + + //shadows with ipshadowshighlight + if ((lp.expcomp != 0.f) || (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.001f) || (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(buforig.get(), bufexpfin.get(), lp.softradiusexp, bfh, bfw, 0.1, 0.001, 0.5f, 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 || lp.blac != 0 || lp.hlcomp > 0.f || lp.shadex > 0 || 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; + const int highl = 0; + + 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, blendm, shado, highl, amountcd, anchorcd, lmaskexplocalcurve, localmaskexputili, dummy, lmasutilicolwav, 1, 1, 5, 5, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, false, 0.f, 0.f, 0 + ); + + if (lp.showmaskexpmetinv == 1) { + showmask(lumask, lp, 0, 0, cx, cy, GW, GH, bufexporig.get(), transformed, bufmaskblurexp.get(), inv); + return; + } + + if (lp.shadex > 0) { + if (lp.expcomp == 0.f) { + lp.expcomp = 0.001f; // to enabled + } + } + + + if (lp.hlcomp > 0.f) { + if (lp.expcomp == 0.f) { + lp.expcomp = 0.001f; // to enabled + } + } + + 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; + const int highl = 0; + bool astool = params->locallab.spots.at(sp).toolcol; + + 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, blendm, shado, highl, 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, lp.fftColorMask, lp.blurcolmask, lp.contcolmask, -1 + ); + + 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 = 2.f * float ((lochhCurve[500.f * Color::huelab_to_huehsv2(hhforcurv)] - 0.5f)) + static_cast(hhforcurv); + 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 (locchCurve && CHutili && lp.qualcurvemet != 0) {//C=f(H) curve + const float rhue = xatan2f(bufcolcalcb, bufcolcalca); + const float valparam = locchCurve[500.f * Color::huelab_to_huehsv2(rhue)] - 0.5f; //get valp=f(H) + float chromaChfactor = 1.0f + valparam; + bufcolcalca *= chromaChfactor;//apply C=f(H) + bufcolcalcb *= chromaChfactor; + } + + 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.001, 0.00001, 0.5f, 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.001, 0.00001, 0.5f, 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; + const int highl = 0; + + 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, blendm, shado, highl, 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, lp.fftColorMask, lp.blurcolmask, lp.contcolmask, -1 + ); + + 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); + } + } + } + +//begin common mask + if(lp.maskena) { + 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 (bfw >= mSP && bfh >= mSP) { + + if (lp.blurma >= 0.25f && lp.fftma && call == 2) { + optfft(N_fftwsize, bfh, bfw, bfh, bfw, lp, original->H, original->W, xstart, ystart, xend, yend, cx, cy); + } + array2D blechro(bfw, bfh); + array2D ble(bfw, bfh); + array2D hue(bfw, bfh); + array2D guid(bfw, bfh); + + std::unique_ptr bufcolorigsav; + std::unique_ptr bufcolorig; + std::unique_ptr bufcolfin; + std::unique_ptr bufmaskblurcol; + std::unique_ptr originalmaskcol; + std::unique_ptr bufcolreserv; + + int wo = original->W; + int ho = original->H; + LabImage *origsav = nullptr; + origsav = new LabImage(wo, ho); + origsav->CopyFrom(original); + + if (call <= 3) { + bufcolorig.reset(new LabImage(bfw, bfh)); + bufcolfin.reset(new LabImage(bfw, bfh)); + bufcolorigsav.reset(new LabImage(bfw, bfh)); + + if (lp.showmask_met == 1 || lp.ena_Mask || lp.showmask_met == 2 || lp.showmask_met == 3) { + 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]; + + bufcolorigsav->L[y][x] = original->L[y + ystart][x + xstart]; + bufcolorigsav->a[y][x] = original->a[y + ystart][x + xstart]; + bufcolorigsav->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]; + } + } + const int inv = 0; + const bool showmaske = lp.showmask_met == 2; + const bool enaMask = lp.ena_Mask; + const bool deltaE = lp.showmask_met == 3; + const bool modmask = lp.showmask_met == 1; + const bool zero = lp.showmask_met == 0; + const bool modif = lp.showmask_met == 1; + const float chrom = params->locallab.spots.at(sp).chromask; + const float rad = params->locallab.spots.at(sp).radmask; + const float gamma = params->locallab.spots.at(sp).gammask; + const float slope = params->locallab.spots.at(sp).slopmask; + float blendm = params->locallab.spots.at(sp).blendmask; + float blendmab = params->locallab.spots.at(sp).blendmaskab; + if (lp.showmask_met == 2) { + blendm = 0.f;//normalize behavior mask with others no action of blend + blendmab = 0.f; + } + const float lap = params->locallab.spots.at(sp).lapmask; + const bool pde = params->locallab.spots.at(sp).laplac; + const int shado = params->locallab.spots.at(sp).shadmask; + const int sco = params->locallab.spots.at(sp).scopemask; + const int level_bl = params->locallab.spots.at(sp).csthresholdmask.getBottomLeft(); + const int level_hl = params->locallab.spots.at(sp).csthresholdmask.getTopLeft(); + const int level_br = params->locallab.spots.at(sp).csthresholdmask.getBottomRight(); + const int level_hr = params->locallab.spots.at(sp).csthresholdmask.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).strumaskmask; + const float softr = params->locallab.spots.at(sp).softradiusmask; + + 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; + const int highl = 0; + bool astool = params->locallab.spots.at(sp).toolmask; + + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, reserved, inv, lp, + strumask, astool, + locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili, lochhhmas_Curve, lhhmas_utili, multiThread, + enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm, blendmab, shado, highl, amountcd, anchorcd, lmasklocal_curve, localmask_utili, loclmasCurve_wav, lmasutili_wav, + level_bl, level_hl, level_br, level_hr, + shortcu, delt, hueref, chromaref, lumaref, + maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, sco, lp.fftma, lp.blurma, lp.contma, 12 + ); + + + if (lp.showmask_met == 2) { + showmask(lumask, lp, xstart, ystart, cx, cy, bfw, bfh, bufcolorig.get(), transformed, bufmaskblurcol.get(), 0); + return; + } +#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] = bufcolorig->L[y][x]; + bufcolfin->a[y][x] = bufcolorig->a[y][x]; + bufcolfin->b[y][x] = bufcolorig->b[y][x]; + hue[y][x] = xatan2f(bufcolfin->b[y][x], bufcolfin->a[y][x]); + const float chromah = std::sqrt(SQR(bufcolfin->b[y][x]) + SQR(bufcolfin->a[y][x])); + ble[y][x] = bufcolfin->L[y][x] / 32768.f; + blechro[y][x] = chromah / 32768.f; + guid[y][x] = bufcolorigsav->L[y][x] / 32768.f; + } + } + if (softr != 0.f) {//soft for L a b because we change color... + float rad = softr; + 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.005f; + constexpr float epsilmin = 0.00001f; + + constexpr float aepsil = (epsilmax - epsilmin) / 100.f; + constexpr float bepsil = epsilmin; + const float epsil = rad < 0.f ? 0.001f : aepsil * rad + bepsil; + + rtengine::guidedFilter(guid, blechro, blechro, r1, epsil, multiThread); + rtengine::guidedFilter(guid, ble, ble, r2, 0.2f * 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++) { + float2 sincosval = xsincosf(hue[y][x]); + bufcolfin->L[y][x] = 32768.f * ble[y][x]; + bufcolfin->a[y][x] = 32768.f * blechro[y][x] * sincosval.y; + bufcolfin->b[y][x] = 32768.f * blechro[y][x] * sincosval.x; + } + } + } + + + + float meansob = 0.f; + transit_shapedetect2(call, 20, bufcolorigsav.get(), bufcolfin.get(), originalmaskcol.get(), hueref, chromaref, lumaref, sobelref, meansob, nullptr, lp, origsav, transformed, cx, cy, sk); + delete origsav; + origsav = NULL; + + 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 common mask + +// Gamut and Munsell control - very important do not deactivated to avoid crash + avoidcolshi(lp, sp, original, transformed, cy, cx); +} + +} diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 6768eca93..d65bf1cad 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, 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,854 @@ 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, + const 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.005; + double epsilmin = 0.00001; + + double aepsil = (epsilmax - epsilmin) / 100.f; + double bepsil = epsilmin; //epsilmax - 100.f * aepsil; + double epsil = aepsil * 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, + const 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 + + float mean, stddv, maxtr, mintr; + mean = 0.f; + stddv = 0.f; + maxtr = 0.f; + mintr = 0.f; + 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) { + //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;//on FFTW + float kg = 1.f;//on Gaussianblur + + 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; + } + + 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)); + } + } + } + + } + + if (scal == 1) {//only if user select scal = 1 + const float threslow = threslum * 163.f; + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < H_L; ++y) { + for (int x = 0; x < W_L; ++x) { + const float srcVal = src[y][x]; + const float kval = rtengine::min(srcVal / threslow, 1.f); + float buf = (srcVal - out[y][x]) * value_1; + buf *= (buf > 0.f) ? lig : dar; + luminance[y][x] = LIM(srcVal + (1.f + kval) * buf, -32768.f, 32768.f); + } + } + + double avg = 0.f; + +#ifdef _OPENMP + #pragma omp parallel for reduction(+:avg) +#endif + + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + avg += luminance[i][j]; + } + } + + avg /= H_L * W_L; + 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); + + 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; + } + + float delta = maxi - mini; + 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; + + } 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 b0dc55b2f..a18e616f7 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -21,6 +21,7 @@ #include "imagefloat.h" #include "improcfun.h" +#include "homogeneouscoordinates.h" #include "procparams.h" #include "rt_math.h" #include "rtengine.h" @@ -334,10 +335,96 @@ namespace rtengine #define CLIPTOC(a,b,c,d) ((a)>=(b)?((a)<=(c)?(a):(d=true,(c))):(d=true,(b))) +/** + * Creates an inverse transformation matrix for camera-geometry-based + * perspective correction. Unless otherwise specified, units are the same as the + * units of the vectors which the matrix will transform. The projection_* + * parameters are applied in the order they appear. + * @param camera_focal_length Camera's focal length. + * @param camera_shift_horiz Camera lens's shift to the right. + * @param camera_shift_vert Camera lens's shift upwards. + * @param camera_roll Camera's roll in radians. Counter-clockwise is positive. + * @param camera_pitch Camera's pitch in radians. Up is positive. + * @param camera_yaw Camera's yaw in radians. Right is positive. + * Up is positive. + * @param projection_shift_horiz Shift of perspective-corrected image to the + * right. + * @param projection_shift_vert Shift of perspective-corrected image upwards. + * @param projection_rotate Rotation of perspective-corrected image + * counter-clockwise in radians. + * @param projection_yaw Yaw in radians of simulated perspective distortion. + * Right is positive. + * @param projection_pitch Pitch in radians of simulated perspective distortion. + * Up is positive. + * @param projection_scale Scale factor of perspective-corrected image. + */ +homogeneous::Matrix perspectiveMatrix(double camera_focal_length, double + camera_shift_horiz, double camera_shift_vert, double camera_roll, double + camera_pitch, double camera_yaw, double projection_yaw, double + projection_pitch, double projection_rotate, double + projection_shift_horiz, double projection_shift_vert, double + projection_scale) +{ + const double projection_scale_inverse = 1.0 / projection_scale; + homogeneous::Vector center; + center[0] = 0; + center[1] = 0; + center[2] = camera_focal_length; + center[3] = 1; + + // Locations of image center after rotations. + const homogeneous::Vector camera_center_yaw_pitch = + homogeneous::rotationMatrix(camera_yaw, homogeneous::Axis::Y) * + homogeneous::rotationMatrix(camera_pitch, homogeneous::Axis::X) * + center; + const homogeneous::Vector projection_center_yaw_pitch = + homogeneous::rotationMatrix(-projection_yaw, homogeneous::Axis::Y) * + homogeneous::rotationMatrix(-projection_pitch, homogeneous::Axis::X) * + center; + + // The following comments refer to the forward transformation. + const homogeneous::Matrix matrix = + // Lens/sensor shift and move to z == camera_focal_length. + homogeneous::translationMatrix(-camera_shift_horiz, + -camera_shift_vert, -camera_focal_length) * + // Camera roll. + homogeneous::rotationMatrix(camera_roll, homogeneous::Axis::Z) * + // Perspective correction. + homogeneous::projectionMatrix(camera_focal_length, homogeneous::Axis::Z) * + homogeneous::rotationMatrix(-camera_pitch, homogeneous::Axis::X) * + homogeneous::rotationMatrix(-camera_yaw, homogeneous::Axis::Y) * + // Re-center after perspective rotation. + homogeneous::translationMatrix(camera_center_yaw_pitch[0], + camera_center_yaw_pitch[1], camera_center_yaw_pitch[2] - camera_focal_length) * + // Translate corrected image. + homogeneous::translationMatrix(-projection_shift_horiz, + -projection_shift_vert, 0) * + // Rotate corrected image. + homogeneous::rotationMatrix(projection_rotate, homogeneous::Axis::Z) * + // Un-center for perspective rotation. + homogeneous::translationMatrix(projection_center_yaw_pitch[0], + projection_center_yaw_pitch[1], camera_focal_length - projection_center_yaw_pitch[2]) * + // Simulate perspective transformation. + homogeneous::projectionMatrix(projection_center_yaw_pitch[2], homogeneous::Axis::Z) * + homogeneous::rotationMatrix(projection_yaw, homogeneous::Axis::Y) * + homogeneous::rotationMatrix(projection_pitch, homogeneous::Axis::X) * + // Move to z == 0. + homogeneous::translationMatrix(0, 0, camera_focal_length) * + // Scale corrected image. + homogeneous::scaleMatrix(projection_scale_inverse, + projection_scale_inverse, 1); + + return matrix; +} + bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef, const LensCorrection *pLCPMap) const { + enum PerspType { NONE, SIMPLE, CAMERA_BASED }; + const PerspType perspectiveType = needsPerspective() ? ( + (params->perspective.method == "camera_based") ? + PerspType::CAMERA_BASED : PerspType::SIMPLE ) : PerspType::NONE; bool clipped = false; red.clear (); @@ -367,41 +454,69 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, double cost = cos (params->rotate.degree * rtengine::RT_PI / 180.0); double sint = sin (params->rotate.degree * rtengine::RT_PI / 180.0); - // auxiliary variables for vertical perspective correction + double ascale = ascaleDef > 0 ? ascaleDef : (params->commonTrans.autofill && params->perspective.render ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0); + + // auxiliary variables for perspective correction + // Simple. double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpalpha = (90.0 - vpdeg) / 180.0 * rtengine::RT_PI; double vpteta = fabs (vpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos ((vpdeg > 0 ? 1.0 : -1.0) * sqrt ((-oW * oW * tan (vpalpha) * tan (vpalpha) + (vpdeg > 0 ? 1.0 : -1.0) * oW * tan (vpalpha) * sqrt (16 * maxRadius * maxRadius + oW * oW * tan (vpalpha) * tan (vpalpha))) / (maxRadius * maxRadius * 8))); double vpcospt = (vpdeg >= 0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); - - // auxiliary variables for horizontal perspective correction double hpdeg = params->perspective.horizontal / 100.0 * 45.0; double hpalpha = (90.0 - hpdeg) / 180.0 * rtengine::RT_PI; double hpteta = fabs (hpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos ((hpdeg > 0 ? 1.0 : -1.0) * sqrt ((-oH * oH * tan (hpalpha) * tan (hpalpha) + (hpdeg > 0 ? 1.0 : -1.0) * oH * tan (hpalpha) * sqrt (16 * maxRadius * maxRadius + oH * oH * tan (hpalpha) * tan (hpalpha))) / (maxRadius * maxRadius * 8))); double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); - - double ascale = ascaleDef > 0 ? ascaleDef : (params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0); + // Camera-based. + const double f = + ((params->perspective.camera_focal_length > 0) ? params->perspective.camera_focal_length : 24.0) + * ((params->perspective.camera_crop_factor > 0) ? params->perspective.camera_crop_factor : 1.0) + * (maxRadius / sqrt(18.0*18.0 + 12.0*12.0)); + const double p_camera_yaw = params->perspective.camera_yaw / 180.0 * rtengine::RT_PI; + const double p_camera_pitch = params->perspective.camera_pitch / 180.0 * rtengine::RT_PI; + const double p_camera_roll = params->perspective.camera_roll * rtengine::RT_PI_180; + const double p_camera_shift_horiz = oW / 100.0 * params->perspective.camera_shift_horiz; + const double p_camera_shift_vert = oH / -100.0 * params->perspective.camera_shift_vert; + const double p_projection_shift_horiz = oW / 100.0 * params->perspective.projection_shift_horiz; + const double p_projection_shift_vert = oH / -100.0 * params->perspective.projection_shift_vert; + const double p_projection_rotate = params->perspective.projection_rotate * rtengine::RT_PI_180; + const double p_projection_yaw = -params->perspective.projection_yaw * rtengine::RT_PI_180; + const double p_projection_pitch = -params->perspective.projection_pitch * rtengine::RT_PI_180; + const double p_projection_scale = 1; + const homogeneous::Matrix p_matrix = perspectiveMatrix(f, + p_camera_shift_horiz, p_camera_shift_vert, p_camera_roll, + p_camera_pitch, p_camera_yaw, p_projection_yaw, p_projection_pitch, + p_projection_rotate, p_projection_shift_horiz, + p_projection_shift_vert, p_projection_scale); 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; + 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: + break; + case PerspType::SIMPLE: + // horizontal perspective transformation + y_d *= maxRadius / (maxRadius + x_d * hptanpt); + x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); + + // vertical perspective transformation + x_d *= maxRadius / (maxRadius - y_d * vptanpt); + y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); + break; + case PerspType::CAMERA_BASED: + const double w = p_matrix[3][0] * x_d + p_matrix[3][1] * y_d + p_matrix[3][3]; + const double xw = p_matrix[0][0] * x_d + p_matrix[0][1] * y_d + p_matrix[0][3]; + const double yw = p_matrix[1][0] * x_d + p_matrix[1][1] * y_d + p_matrix[1][3]; + x_d = xw / w; + y_d = yw / w; + break; } - x_d += ascale * (0 - w2); // centering x coord & scale - y_d += ascale * (0 - h2); // centering y coord & scale - - if (needsPerspective()) { - // horizontal perspective transformation - y_d *= maxRadius / (maxRadius + x_d * hptanpt); - x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); - - // vertical perspective transformation - x_d *= maxRadius / (maxRadius - y_d * vptanpt); - y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); + if (pLCPMap && params->lensProf.useDist) { + pLCPMap->correctDistortion(x_d, y_d, w2, h2); } // rotate @@ -580,7 +695,7 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, // steps, using an intermediate temporary image. There's room for // optimization of course... if (pLCPMap && params->lensProf.useCA && pLCPMap->isCACorrectionAvailable()) { - tmpimg.reset(new Imagefloat(original->getWidth(), original->getHeight())); + tmpimg.reset(new Imagefloat(transformed->getWidth(), transformed->getHeight())); dest = tmpimg.get(); } } @@ -699,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; @@ -978,13 +1093,16 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I { // set up stuff, depending on the mode we are + enum PerspType { NONE, SIMPLE, CAMERA_BASED }; const bool enableLCPDist = pLCPMap && params->lensProf.useDist; const bool enableCA = highQuality && needsCA(); const bool enableGradient = needsGradient(); const bool enablePCVignetting = needsPCVignetting(); const bool enableVignetting = needsVignetting(); - const bool enablePerspective = needsPerspective(); const bool enableDistortion = needsDistortion(); + const PerspType perspectiveType = needsPerspective() ? ( + (params->perspective.method == "camera_based") ? + PerspType::CAMERA_BASED : PerspType::SIMPLE ) : PerspType::NONE; const double w2 = static_cast(oW) / 2.0 - 0.5; const double h2 = static_cast(oH) / 2.0 - 0.5; @@ -1028,23 +1146,43 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I const double cost = cos(params->rotate.degree * rtengine::RT_PI / 180.0); const double sint = sin(params->rotate.degree * rtengine::RT_PI / 180.0); - // auxiliary variables for vertical perspective correction + // auxiliary variables for perspective correction + // Simple. const double vpdeg = params->perspective.vertical / 100.0 * 45.0; const double vpalpha = (90.0 - vpdeg) / 180.0 * rtengine::RT_PI; const double vpteta = fabs(vpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos((vpdeg > 0 ? 1.0 : -1.0) * sqrt((-SQR(oW * tan(vpalpha)) + (vpdeg > 0 ? 1.0 : -1.0) * oW * tan(vpalpha) * sqrt(SQR(4 * maxRadius) + SQR(oW * tan(vpalpha)))) / (SQR(maxRadius) * 8))); const double vpcospt = (vpdeg >= 0 ? 1.0 : -1.0) * cos(vpteta); const double vptanpt = tan(vpteta); - - // auxiliary variables for horizontal perspective correction const double hpdeg = params->perspective.horizontal / 100.0 * 45.0; const double hpalpha = (90.0 - hpdeg) / 180.0 * rtengine::RT_PI; const double hpteta = fabs(hpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos((hpdeg > 0 ? 1.0 : -1.0) * sqrt((-SQR(oH * tan(hpalpha)) + (hpdeg > 0 ? 1.0 : -1.0) * oH * tan(hpalpha) * sqrt(SQR(4 * maxRadius) + SQR(oH * tan(hpalpha)))) / (SQR(maxRadius) * 8))); const double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos(hpteta); const double hptanpt = tan(hpteta); + // Camera-based. + const double f = + ((params->perspective.camera_focal_length > 0) ? params->perspective.camera_focal_length : 24.0) + * ((params->perspective.camera_crop_factor > 0) ? params->perspective.camera_crop_factor : 1.0) + * (maxRadius / sqrt(18.0*18.0 + 12.0*12.0)); + const double p_camera_yaw = params->perspective.camera_yaw / 180.0 * rtengine::RT_PI; + const double p_camera_pitch = params->perspective.camera_pitch / 180.0 * rtengine::RT_PI; + const double p_camera_roll = params->perspective.camera_roll * rtengine::RT_PI_180; + const double p_camera_shift_horiz = oW / 100.0 * params->perspective.camera_shift_horiz; + const double p_camera_shift_vert = oH / -100.0 * params->perspective.camera_shift_vert; + const double p_projection_shift_horiz = oW / 100.0 * params->perspective.projection_shift_horiz; + const double p_projection_shift_vert = oH / -100.0 * params->perspective.projection_shift_vert; + const double p_projection_rotate = params->perspective.projection_rotate * rtengine::RT_PI_180; + const double p_projection_yaw = -params->perspective.projection_yaw * rtengine::RT_PI_180; + const double p_projection_pitch = -params->perspective.projection_pitch * rtengine::RT_PI_180; + const double p_projection_scale = 1; + const homogeneous::Matrix p_matrix = perspectiveMatrix(f, + p_camera_shift_horiz, p_camera_shift_vert, p_camera_roll, + p_camera_pitch, p_camera_yaw, p_projection_yaw, p_projection_pitch, + p_projection_rotate, p_projection_shift_horiz, + p_projection_shift_vert, p_projection_scale); - const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0; + const double ascale = params->commonTrans.autofill && params->perspective.render ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0; const bool darkening = (params->vignetting.amount <= 0.0); const bool useLog = params->commonTrans.method == "log" && highQuality; @@ -1078,24 +1216,32 @@ 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 * (x_d + centerFactorx); // centering x coord & scale + y_d = ascale * (y_d + centerFactory); // centering y coord & scale + + switch (perspectiveType) { + case PerspType::NONE: + break; + case PerspType::SIMPLE: + // horizontal perspective transformation + y_d *= maxRadius / (maxRadius + x_d * hptanpt); + x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); + + // vertical perspective transformation + x_d *= maxRadius / (maxRadius - y_d * vptanpt); + y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); + break; + case PerspType::CAMERA_BASED: + const double w = p_matrix[3][0] * x_d + p_matrix[3][1] * y_d + p_matrix[3][3]; + const double xw = p_matrix[0][0] * x_d + p_matrix[0][1] * y_d + p_matrix[0][3]; + const double yw = p_matrix[1][0] * x_d + p_matrix[1][1] * y_d + p_matrix[1][3]; + x_d = xw / w; + y_d = yw / w; + break; } - x_d += ascale * centerFactorx; // centering x coord & scale - y_d += ascale * centerFactory; // centering y coord & scale - - if (enablePerspective) { - // horizontal perspective transformation - y_d *= maxRadius / (maxRadius + x_d * hptanpt); - x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); - - // vertical perspective transformation - x_d *= maxRadius / (maxRadius - y_d * vptanpt); - y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); + if (enableLCPDist) { + pLCPMap->correctDistortion(x_d, y_d, w2, h2); } // rotate @@ -1323,7 +1469,20 @@ bool ImProcFunctions::needsRotation () const bool ImProcFunctions::needsPerspective () const { - return params->perspective.horizontal || params->perspective.vertical; + return ( (params->perspective.method == "simple") && + (params->perspective.horizontal || params->perspective.vertical) ) + || ( (params->perspective.method == "camera_based") && + params->perspective.render && ( + params->perspective.camera_pitch || + params->perspective.camera_roll || + params->perspective.camera_shift_horiz || + params->perspective.camera_shift_vert || + params->perspective.camera_yaw || + params->perspective.projection_pitch || + params->perspective.projection_rotate || + params->perspective.projection_shift_horiz || + params->perspective.projection_shift_vert || + params->perspective.projection_yaw) ); } bool ImProcFunctions::needsGradient () const 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 47bd0f08a..fe6b7be29 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -50,6 +50,8 @@ #endif #include "cplx_wavelet_dec.h" +#define BENCHMARK +#include "StopWatch.h" namespace rtengine { @@ -78,7 +80,7 @@ struct cont_params { float b_lsl, t_lsl, b_rsl, t_rsl; float b_lhl, t_lhl, b_rhl, t_rhl; float edg_low, edg_mean, edg_sd, edg_max; - float lev0s, lev0n, lev1s, lev1n, lev2s, lev2n, lev3s, lev3n; + float lev0s, lev0n, lev1s, lev1n, lev2s, lev2n, lev3s, lev3n, lev4n, lev4t; float b_lpast, t_lpast, b_rpast, t_rpast; float b_lsat, t_lsat, b_rsat, t_rsat; int rad; @@ -94,6 +96,8 @@ struct cont_params { bool opaRG; bool edgcurv; bool diagcurv; + bool denoicurv; + bool denoicurvh; int CHmet; int CHSLmet; int EDmet; @@ -110,13 +114,16 @@ struct cont_params { bool lip3; bool tonemap; bool diag; - int TMmeth; float tmstrength; float balan; float sigmafin; float sigmaton; float sigmacol; float sigmadir; + int denmet; + int mixmet; + int quamet; + int slimet; int ite; int contmet; bool opaW; @@ -159,19 +166,57 @@ struct cont_params { float b_low; float rangeab; float protab; + float sigmm; + float sigmm14; + float sigmm56; + float levden; + float thrden; + float limden; + int complex; }; int wavNestedLevels = 1; +std::unique_ptr ImProcFunctions::buildMeaLut(const float inVals[11], const float mea[10], float& lutFactor) +{ + constexpr int lutSize = 100; -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) + const float lutMax = std::ceil(mea[9]); + const float lutDiff = lutMax / lutSize; + + std::vector lutVals(lutSize); + int jStart = 1; + for (int i = 0; i < lutSize; ++i) { + const float val = i * lutDiff; + if (val < mea[0]) { + // still < first value => no interpolation + lutVals[i] = inVals[0]; + } else { + for (int j = jStart; j < 10; ++j) { + if (val == mea[j]) { + // exact match => no interpolation + lutVals[i] = inVals[j]; + ++jStart; + break; + } + if (val < mea[j]) { + // interpolate + const float dist = (val - mea[j - 1]) / (mea[j] - mea[j - 1]); + lutVals[i] = rtengine::intp(dist, inVals[j], inVals[j - 1]); + break; + } + lutVals[i] = inVals[10]; + } + } + } + lutFactor = 1.f / lutDiff; + return std::unique_ptr(new LUTf(lutVals)); +} + +void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const WavCurve & wavdenoise, WavCurve & wavdenoiseh, 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]}, @@ -179,11 +224,43 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const {wiprof[2][0], wiprof[2][1], wiprof[2][2]} }; const int imheight = lab->H, imwidth = lab->W; + int levwavL; + //Flat curve for H=f(H) in final touchup for guidedfilter + FlatCurve* wavguidCurve = new FlatCurve(params->wavelet.wavguidcurve); //curve H=f(H) + bool wavguidutili = false; + + if (!wavguidCurve || wavguidCurve->isIdentity()) { + if (wavguidCurve) { + delete wavguidCurve; + wavguidCurve = nullptr; + } + } else { + wavguidutili = true; + } +//flat curve for equalizer H + FlatCurve* wavhueCurve = new FlatCurve(params->wavelet.wavhuecurve); //curve H=f(H) + bool wavhueutili = false; + + if (!wavhueCurve || wavhueCurve->isIdentity()) { + if (wavhueCurve) { + delete wavhueCurve; + wavhueCurve = nullptr; + } + } else { + wavhueutili = true; + } struct cont_params cp; cp.avoi = params->wavelet.avoid; + if (params->wavelet.complexmethod == "normal") { + cp.complex = 0; + } else if (params->wavelet.complexmethod == "expert") { + cp.complex = 1; + } + + if (params->wavelet.Medgreinf == "more") { cp.reinforce = 1; } else if (params->wavelet.Medgreinf == "none") { @@ -212,6 +289,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.sigmaton = params->wavelet.sigmaton; cp.sigmacol = params->wavelet.sigmacol; cp.sigmadir = params->wavelet.sigmadir; + cp.sigmm = params->wavelet.sigm; + cp.levden = params->wavelet.levden; + cp.thrden = 0.01f * params->wavelet.thrden; + cp.limden = params->wavelet.limden; if (params->wavelet.TMmethod == "cont") { cp.contmet = 1; @@ -219,6 +300,41 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.contmet = 2; } + + if (params->wavelet.denmethod == "equ") { + cp.denmet = 0; + } else if (params->wavelet.denmethod == "high") { + cp.denmet = 1; + } else if (params->wavelet.denmethod == "low") { + cp.denmet = 2; + } else if (params->wavelet.denmethod == "12high") { + cp.denmet = 3; + } else if (params->wavelet.denmethod == "12low") { + cp.denmet = 4; + } + + if (params->wavelet.mixmethod == "nois") { + cp.mixmet = 0; + } else if (params->wavelet.mixmethod == "mix") { + cp.mixmet = 1; + } else if (params->wavelet.mixmethod == "mix7") { + cp.mixmet = 2; + } else if (params->wavelet.mixmethod == "den") { + cp.mixmet = 3; + } + + if (params->wavelet.quamethod == "cons") { + cp.quamet = 0; + } else if (params->wavelet.quamethod == "agre") { + cp.quamet = 1; + } + + if (params->wavelet.slimethod == "sli") { + cp.slimet = 0; + } else if (params->wavelet.slimethod == "cur") { + cp.slimet = 1; + } + if (params->wavelet.BAmethod != "none") { cp.bam = true; @@ -291,14 +407,14 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } cp.CHSLmet = 1; - cp.EDmet = 1; - + cp.EDmet = 2; +/* if (params->wavelet.EDmethod == "SL") { cp.EDmet = 1; } else if (params->wavelet.EDmethod == "CU") { cp.EDmet = 2; } - +*/ cp.cbena = params->wavelet.cbenab; cp.blhigh = (float)params->wavelet.bluehigh; cp.grhigh = (float)params->wavelet.greenhigh; @@ -309,6 +425,8 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.curv = false; cp.edgcurv = false; cp.diagcurv = false; + cp.denoicurv = false; + cp.denoicurvh = false; cp.opaRG = false; cp.opaBY = false; cp.opaW = false; @@ -393,6 +511,28 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.diagcurv = true; } + if (wavdenoise) { + for (int i = 0; i < 500; i++) { + if (wavdenoise[i] != 1.0) { + cp.denoicurv = true; + break; + } + } + } + + if(cp.complex == 0) { + wavdenoiseh = wavdenoise; + } + + if (wavdenoiseh) { + for (int i = 0; i < 500; i++) { + if (wavdenoiseh[i] != 1.0) { + cp.denoicurvh = true; + break; + } + } + } + for (int m = 0; m < maxmul; m++) { cp.mul[m] = waparams.c[m]; } @@ -438,7 +578,6 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.chromfi = 0.1f * waparams.chromfi; cp.chromco = 0.1f * waparams.chromco; cp.ballum = waparams.ballum; - cp.conres = waparams.rescon; cp.conresH = waparams.resconH; cp.radius = waparams.radius; @@ -462,16 +601,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 = 9 - params->wavelet.threshold2; - int maxlevS = cp.numlevH; - cp.numlevS = rtengine::max(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()); @@ -501,6 +638,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.lev2n = static_cast(params->wavelet.level2noise.getTop()); cp.lev3s = static_cast(params->wavelet.level3noise.getBottom()); cp.lev3n = static_cast(params->wavelet.level3noise.getTop()); + cp.lev4n = static_cast(params->wavelet.leveldenoise.getTop()); + cp.lev4t = 0.01f * static_cast(params->wavelet.leveldenoise.getBottom()); + cp.sigmm14 = static_cast(params->wavelet.levelsigm.getTop()); + cp.sigmm56 = static_cast(params->wavelet.levelsigm.getBottom()); cp.detectedge = params->wavelet.medianlev; int minwin = rtengine::min(imwidth, imheight); @@ -527,12 +668,18 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const maxlevelcrop = 6; } - if (minwin < 64) { + if (minwin * skip < 64) { maxlevelcrop = 5; } - + if (minwin * skip < 32) { + maxlevelcrop = 4; + } + int levwav = params->wavelet.thres; + if(params->wavelet.expnoise) { + levwav = 6; + } if (levwav == 9 && cp.mul[9] != 0) { levwav = 10; @@ -604,6 +751,14 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const maxlev2 = 6; } + if (minsizetile < 64) { + maxlev2 = 5; + } + + if (minsizetile < 32) { + maxlev2 = 4; + } + levwav = rtengine::min(maxlev2, levwav); #ifdef _OPENMP @@ -684,6 +839,12 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float sigmaN[10]; float MaxP[10]; float MaxN[10]; + float meand[10]; + float meanNd[10]; + float sigmad[10]; + float sigmaNd[10]; + float MaxPd[10]; + float MaxNd[10]; float meanab[10]; float meanNab[10]; @@ -847,7 +1008,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const int datalen = labco->W * labco->H; - int levwavL = levwav; + levwavL = levwav; bool ref0 = false; if ((cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f || cp.lev3s > 0.f) && cp.noiseena) { @@ -868,36 +1029,62 @@ 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 (cp.BAmet != 0) { + if (cp.mul[0] == 0.f) { + cp.mul[0] = 0.01f; + } + } + + + if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.finena && !cp.edgeena && 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--; } } + if (levwavL == 6 && cp.noiseena && cp.chromfi == 0.f) { + cp.chromfi = 0.01f; + } + if (cp.chromfi > 0.f || cp.chromco > 0.f) { if (levwavL < 7) { levwavL = 7; } } - if (levwavL < 4) { - levwavL = 4; //to allow edge => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! + if (levwavL < 5 && cp.noiseena) { + levwavL = 6; //to allow edge and denoise => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! } + + +/* + if(cp.denoicurvh || cp.levdenhigh > 0.01f) { + levwavL = levwav; + } +*/ + float th = 0.01f * (float) waparams.thrend; + if(th > 0.f) { + levwavL = levwav; + } + + + bool usechrom = cp.chromfi > 0.f || cp.chromco > 0.f; + levwavL = rtengine::min(maxlevelcrop, levwavL); + levwavL = rtengine::min(maxlev2, levwavL); if (settings->verbose) { printf("Level decomp L=%i\n", levwavL); } - bool usechrom = cp.chromfi > 0.f || cp.chromco > 0.f; - 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)); + // const std::unique_ptr Ldecomp2(new wavelet_decomposition(labco->data, labco->W, labco->H, levwavL, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); - if (!Ldecomp->memoryAllocationFailed) { + if (!Ldecomp->memory_allocation_failed()) { float madL[10][3]; // float madL[8][3]; @@ -910,12 +1097,12 @@ 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); + printf("Luminance noise estimate (sqr) madL=%.0f lvl=%i dir=%i\n", madL[lvl][dir - 1], lvl, dir - 1); } } } @@ -924,6 +1111,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if ((cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f || cp.lev3s > 0.f) && cp.noiseena) { ref = true; + } bool contr = false; @@ -934,82 +1122,391 @@ 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); + // if (cp.val > 0 || ref || contr || cp.denoicurv || cp.denoicurvh || cp.noiseena || cp.levdenlow > 0.f || cp.thrden > 0.f ) { //edge + if (cp.val > 0 || ref || contr || cp.denoicurv || cp.denoicurvh || cp.noiseena || cp.thrden > 0.f ) { //edge + Evaluate2(*Ldecomp, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavNestedLevels); } //init for edge and denoise - float vari[4]; + float vari[6]; 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)); + vari[4] = 0.8f * SQR((cp.lev4n / 125.f) * (1.f + cp.lev4n / 25.f)); + vari[5] = 0.8f * SQR((cp.lev4n / 125.f) * (1.f + cp.lev4n / 25.f)); float kr3 = 1.f; if (cp.lev3n < 10.f) { - kr3 = 0.f; + kr3 = 0.3f; } else if (cp.lev3n < 30.f) { - kr3 = 0.5f; + kr3 = 0.6f; } else if (cp.lev3n < 70.f) { - kr3 = 0.7f; + kr3 = 0.8f; } else { kr3 = 1.f; } - if ((cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f) && cp.noiseena) { - int edge = 5; + float kr4 = 1.f; + + if (cp.lev4n < 10.f) { + kr4 = 0.6f; + } else if (cp.lev4n < 30.f) { + kr4 = 0.8f; + } else if (cp.lev4n < 70.f) { + kr4 = 0.9f; + } else { + kr4 = 1.f; + } + + if ((cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f || cp.lev4n > 0.1f) && cp.noiseena) { + int edge = 6; 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]); - } + vari[4] = rtengine::max(0.000001f, kr4 * vari[4]); + vari[5] = rtengine::max(0.000001f, kr4 * vari[5]); + + const std::unique_ptr Ldecomp2(new wavelet_decomposition(labco->data, labco->W, labco->H, levwavL, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); + if(!Ldecomp2->memory_allocation_failed()){ + if (settings->verbose) { + printf("LUM var0=%f var1=%f var2=%f var3=%f var4=%f\n", vari[0], vari[1], vari[2], vari[3], vari[4]); + } // float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL - int GWL = labco->W; - int GHL = labco->H; - float* noisevarlum = new float[GHL * GWL]; - int GW2L = (GWL + 1) / 2; + int GWL = labco->W; + int GHL = labco->H; + float* noisevarlum = new float[GHL * GWL]; + float* noisevarhue = new float[GHL * GWL]; + int GW2L = (GWL + 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 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 - cp.ballum; - float ac = (nvlh[i] - nvll[i]) / (seuillow - seuilhigh); - float bc = nvlh[i] - seuillow * ac; + float seuillow = 3000.f;//low + float seuilhigh = 18000.f;//high + int i = 10 - cp.ballum; + float ac = (nvlh[i] - nvll[i]) / (seuillow - seuilhigh); + float bc = nvlh[i] - seuillow * ac; #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel for #endif - for (int ir = 0; ir < GHL; ir++) - for (int jr = 0; jr < GWL; jr++) { - float lN = labco->L[ir][jr]; + for (int ir = 0; ir < GHL; ir++) + for (int jr = 0; jr < GWL; jr++) { + float lN = labco->L[ir][jr]; - if (lN < seuillow) { - noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] = nvlh[i]; - } else if (lN < seuilhigh) { - noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] = ac * lN + bc; - } else { - noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] = nvll[i]; + if (lN < seuillow) { + noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] = nvlh[i]; + } else if (lN < seuilhigh) { + noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] = ac * lN + bc; + } else { + noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] = nvll[i]; + } } + + if(wavhueutili) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int ir = 0; ir < GHL; ir++) + for (int jr = 0; jr < GWL; jr++) { + float hueG = xatan2f(labco->b[ir][jr], labco->a[ir][jr]); + noisevarhue[(ir >> 1)*GW2L + (jr >> 1)] = 1.f + 2.f * (static_cast(wavhueCurve->getVal(Color::huelab_to_huehsv2(hueG))) - 0.5f); + noisevarlum[(ir >> 1)*GW2L + (jr >> 1)] *= noisevarhue[(ir >> 1)*GW2L + (jr >> 1)]; + } } - 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); + + if(cp.quamet == 0) { + if (settings->verbose) { + printf("denoise standard\n"); + } + WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge, 1); + } else { + if (settings->verbose) { + printf("denoise bishrink\n"); + } + WaveletDenoiseAll_BiShrinkL(*Ldecomp, noisevarlum, madL, vari, edge, 1); + + WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge, 1); + } + delete[] noisevarlum; + + //evaluate after denoise + bool exitifzero = true; + Evaluate2(*Ldecomp, meand, meanNd, sigmad, sigmaNd, MaxPd, MaxNd, wavNestedLevels); + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < levwavL; level++) { + if(mean[level] < 0.1f || meand[level] < 0.1f || sigma[level] < 0.1f || sigmad[level] < 0.1f) { + printf("near zero - exit\n"); + exitifzero = false; + } + } + } + + //for level 0 1 2 3 + float thr = 0.f; + float thrend = cp.thrden; //cp.levdenlow; + if(thrend < 0.01f) thr = 0.95f; + else if(thrend < 0.02f) thr = 0.9f; + else if(thrend < 0.04f) thr = 0.8f; + else if(thrend < 0.06f) thr = 0.7f; + else if(thrend < 0.08f) thr = 0.6f; + else if(thrend < 0.1f) thr = 0.5f; + else if(thrend < 0.2f) thr = 0.2f; + else thr = 0.f; + + FlatCurve wavlow({ + FCT_MinMaxCPoints, + 0, 1, 0.35, 0.35,thrend, 1.0, 0.35, 0.35, thrend + 0.01f, thr, 0.35, 0.35, 1, thr, 0.35, 0.35 + }); + //for level 4 + float thrhigh = 0.f; + float threndhigh = cp.lev4t; //cp.levdenlow; + if(threndhigh < 0.01f) thrhigh = 0.95f; + else if(threndhigh < 0.02f) thrhigh = 0.9f; + else if(threndhigh < 0.04f) thrhigh = 0.8f; + else if(threndhigh < 0.06f) thrhigh = 0.7f; + else if(threndhigh < 0.08f) thrhigh = 0.6f; + else if(threndhigh < 0.1f) thrhigh = 0.5f; + else thrhigh = 0.f; + + FlatCurve wavhigh({ + FCT_MinMaxCPoints, + 0, 1, 0.35, 0.35,threndhigh, 1.0, 0.35, 0.35, threndhigh + 0.01f, thrhigh, 0.35, 0.35, 1, thrhigh, 0.35, 0.35 + }); + + float thrmed = 0.f; + float threndmed = 1.f - cp.limden; + if(threndmed < 0.02f) thrmed = 0.5f; + else if(threndmed < 0.05f) thrmed = 0.2f; + else thrmed = 0.f; + + FlatCurve wavmed({ + FCT_MinMaxCPoints, + 0, 1, 0.35, 0.35,threndmed, 1.0, 0.35, 0.35, threndmed + 0.01f, thrmed, 0.35, 0.35, 1, thrmed, 0.35, 0.35 + }); + + float siglh[10]; + float levref = 6; + //levref = levwavL-1; + if(cp.complex == 1){ + for (int level = 0; level < levref; level++) { + if(level > 3) { + siglh[level] = cp.sigmm56; + } else { + siglh[level] = cp.sigmm14; + } + } + } else { + levref = 4; + for (int level = 0; level < levref; level++) { + siglh[level] = cp.sigmm; + } + } + +// printf("sig0=%f sig1=%f sig2=%f sig3=%f sig4=%f sig5=%f\n", siglh[0], siglh[1],siglh[2],siglh[3],siglh[4],siglh[5]); + + + bool execut = false; + + if(cp.slimet == 0) { + // if(cp.levdenlow > 0.f) { + if(cp.thrden > 0.f) { + execut = true; + } + } else { + if(cp.denoicurv) { + execut = true; + } + } + // } + if (execut && exitifzero) { + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < levref; level++) { + int Wlvl_L = Ldecomp->level_W(level); + int Hlvl_L = Ldecomp->level_H(level); + float* const* WavCoeffs_L = Ldecomp->level_coeffs(level);//first decomp denoised + float* const* WavCoeffs_L2 = Ldecomp2->level_coeffs(level);//second decomp before denoise + int k4 = 3; + int k5 = 3; + if(cp.complex == 1){ + k4= 4; + k5= 5; + } + auto WavL0 = Ldecomp->level_coeffs(0)[dir]; + auto WavL1 = Ldecomp->level_coeffs(1)[dir]; + auto WavL2 = Ldecomp->level_coeffs(2)[dir]; + auto WavL3 = Ldecomp->level_coeffs(3)[dir]; + auto WavL4 = Ldecomp->level_coeffs(k4)[dir]; + auto WavL5 = Ldecomp->level_coeffs(k5)[dir]; + //not denoise + const auto WavL02 = Ldecomp2->level_coeffs(0)[dir]; + const auto WavL12 = Ldecomp2->level_coeffs(1)[dir]; + const auto WavL22 = Ldecomp2->level_coeffs(2)[dir]; + const auto WavL32 = Ldecomp2->level_coeffs(3)[dir]; + const auto WavL42 = Ldecomp2->level_coeffs(k4)[dir]; + const auto WavL52 = Ldecomp2->level_coeffs(k5)[dir]; + if (settings->verbose) { + printf("level=%i mean=%.0f meanden=%.0f sigma=%.0f sigmaden=%.0f Max=%.0f Maxden=%.0f\n", level, mean[level], meand[level], sigma[level], sigmad[level],MaxP[level], MaxPd[level]); + } + + //find local contrast + float tempmean = 0.f; + float tempsig = 0.f; + float tempmax = 0.f; + if(cp.mixmet == 0){ + tempmean = mean[level]; + tempsig = sigma[level]; + tempmax = MaxP[level]; + } else if(cp.mixmet == 1){ + tempmean = 0.5f * mean[level] + 0.5f * meand[level] ; + tempsig = 0.5f * sigma[level] + 0.5f * sigmad[level] ; + tempmax = 0.5f * MaxP[level] + 0.5f * MaxPd[level] ; + } else if(cp.mixmet == 2){ + tempmean = 0.3f * mean[level] + 0.7f * meand[level] ; + tempsig = 0.3f * sigma[level] + 0.7f * sigmad[level] ; + tempmax = 0.3f * MaxP[level] + 0.7f * MaxPd[level] ; + } else if(cp.mixmet == 3){ + tempmean = meand[level]; + tempsig = sigmad[level]; + tempmax = MaxPd[level]; + } + + if (MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { //curve + float insigma = 0.666f; //SD + float logmax = log(tempmax); //log Max + //cp.sigmm change the "wider" of sigma + float rapX = (tempmean + siglh[level] * tempsig) / (tempmax); //rapport between sD / max + float inx = log(insigma); + float iny = log(rapX); + float rap = inx / iny; //koef + float asig = 0.166f / (tempsig * siglh[level]); + float bsig = 0.5f - asig * tempmean; + float amean = 0.5f / (tempmean); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, Wlvl_L * 16) num_threads(wavNestedLevels) if (wavNestedLevels>1) +#endif + + for (int i = 0; i < Wlvl_L * Hlvl_L; i++) { + float absciss; + float tempwav = 0.f; + if(cp.mixmet == 0){ + tempwav = WavCoeffs_L2[dir][i]; + } else if(cp.mixmet == 1){ + tempwav = 0.5f * WavCoeffs_L[dir][i] + 0.5f * WavCoeffs_L2[dir][i]; + } else if(cp.mixmet == 2){ + tempwav = 0.7f * WavCoeffs_L[dir][i] + 0.3f * WavCoeffs_L2[dir][i]; + } else if(cp.mixmet == 3){ + tempwav = WavCoeffs_L[dir][i]; + } + + if (std::fabs(tempwav) >= (tempmean + siglh[level] * tempsig)) { //for max + float valcour = xlogf(std::fabs(tempwav)); + float valc = valcour - logmax; + float vald = valc * rap; + absciss = xexpf(vald); + } else if (std::fabs(tempwav) >= tempmean) { + absciss = asig * std::fabs(tempwav) + bsig; + } else { + absciss = amean * std::fabs(tempwav); + float k = siglh[level]; + if(siglh[level] > 1.f) { + k = SQR(siglh[level]); + } + float abs = pow(2.f * absciss, (1.f / k)); + absciss = 0.5f * abs; + } + float kc = 0.f; + if(cp.slimet == 0) { + kc = wavlow.getVal(absciss) -1.f; + } else { + kc = wavdenoise[absciss * 500.f] - 1.f; + } + + float kchigh = 0.f; + kchigh = wavhigh.getVal(absciss) -1.f; + kchigh = -SQR(kchigh); + + float kcmed = 0.f; + kcmed = wavmed.getVal(absciss) -1.f; + kcmed = -SQR(kcmed); + + if(kc < 0) { + kc = -SQR(kc);//approximation to simulate sliders denoise + } + //equalizer for levels 0 1 and 3... 1.33 and 0.75 arbitrary values + if(cp.denmet == 1) { + if(level == 0 || level == 3) { + kc *= 1.7f; + } + } else if(cp.denmet == 2) { + if(level == 0 || level == 3) { + kc *= 0.3f; + } + } else if(cp.denmet == 3) { + if(level == 0 || level == 1) { + kc *= 1.7f; + } + } else if(cp.denmet == 4) { + if(level == 0 || level == 1) { + kc *= 0.3f; + } + } + + float reduceeffect = kc <= 0.f ? 1.f : 1.2f;//1.2 allows to increase denoise (not used) + + float kinterm = 1.f + reduceeffect * kc; + kinterm = kinterm <= 0.f ? 0.01f : kinterm; + + float kintermhigh = 1.f + reduceeffect * kchigh; + kintermhigh = kintermhigh <= 0.f ? 0.01f : kintermhigh; + + float kintermed = 1.f + reduceeffect * kcmed; + kintermed = kintermed <= 0.f ? 0.01f : kintermed; + + float kintermlow = kinterm; + if(level < 4) { + WavL0[i] = WavL02[i] + (WavL0[i] - WavL02[i]) * kintermlow; + WavL1[i] = WavL12[i] + (WavL1[i] - WavL12[i]) * kintermlow; + WavL2[i] = WavL22[i] + (WavL2[i] - WavL22[i]) * kintermlow; + WavL3[i] = WavL32[i] + (WavL3[i] - WavL32[i]) * kintermlow; + } + if(cp.complex == 1){ + if(cp.limden > 0.f) { + WavL0[i] = WavL02[i] + (WavL0[i] - WavL02[i]) * kintermed; + WavL1[i] = WavL12[i] + (WavL1[i] - WavL12[i]) * kintermed; + WavL2[i] = WavL22[i] + (WavL2[i] - WavL22[i]) * kintermed; + WavL3[i] = WavL32[i] + (WavL3[i] - WavL32[i]) * kintermed; + } + WavL4[i] = WavL42[i] + (WavL4[i] - WavL42[i]) * kintermhigh; + WavL5[i] = WavL52[i] + (WavL5[i] - WavL52[i]) * kintermhigh; + } + } + } + } + } + if (settings->verbose) { + Evaluate2(*Ldecomp, meand, meanNd, sigmad, sigmaNd, MaxPd, MaxNd, wavNestedLevels); + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < levref; level++) { + printf("AFTER LC level=%i mean=%.0f meanden=%.0f sigma=%.0f sigmaden=%.0f Max=%.0f Maxden=%.0f\n", level, mean[level], meand[level], sigma[level], sigmad[level],MaxP[level], MaxPd[level]); + } + } + } + + } + delete[] noisevarhue; } } - //Flat curve for Contrast=f(H) in levels FlatCurve* ChCurve = new FlatCurve(params->wavelet.Chcurve); //curve C=f(H) bool Chutili = false; @@ -1026,7 +1523,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const 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); @@ -1076,7 +1573,6 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (noiseccb < 0.f) { noiseccb = 0.0001f; } - int edge = 2; variC[0] = SQR(noisecfr); variC[1] = SQR(noisecfr); @@ -1272,7 +1768,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (!hhutili) { //always a or b int levwava = levwav; - if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels + if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.finena && !cp.edgeena&& params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels while (levwava > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwava - 1] == 0.f)) || (cp.CHmet != 2 && (levwava == 10 || (!cp.curv || cp.mulC[levwava - 1] == 0.f))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava - 1] == 0.f)) && ((levwava == 10 || (cp.CHSLmet == 1 && cp.mulC[levwava - 1] == 0.f)))) { levwava--; } @@ -1284,31 +1780,41 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } } + levwava = rtengine::min(maxlevelcrop, levwava); + levwava = rtengine::min(maxlev2, levwava); if (settings->verbose) { printf("Leval decomp a=%i\n", levwava); } 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->memory_allocation_failed()) { + if(levwava == 6) { + edge = 1; + } + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.quamet == 0 )) { - if (!adecomp->memoryAllocationFailed) { - 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){ + + } else if (cp.noiseena && ((cp.chromfi > 0.f && cp.chromco >= 0.f) && cp.quamet == 1 )){ 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); + } } int levwavb = levwav; - if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels + if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.finena && !cp.edgeena && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels while (levwavb > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavb - 1] == 0.f)) || (cp.CHmet != 2 && (levwavb == 10 || (!cp.curv || cp.mulC[levwavb - 1] == 0.f))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb - 1] == 0.f)) && ((levwavb == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavb - 1] == 0.f)))) { levwavb--; } @@ -1320,23 +1826,38 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } } + + levwavb = rtengine::min(maxlevelcrop, levwavb); + levwavb = rtengine::min(maxlev2, levwavb); + if (settings->verbose) { printf("Leval decomp b=%i\n", levwavb); } - 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(levwavb == 6) { + edge = 1; + } - if (!bdecomp->memoryAllocationFailed) { - if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f )) { + if (!bdecomp->memory_allocation_failed()) { + // if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f )) { + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.quamet == 0)) { WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, 1); - } else if (cp.chromfi > 0.f && cp.chromco >= 2.f){ + if (settings->verbose) { + printf("Denoise ab standard\n"); + } + } else if (cp.noiseena && ((cp.chromfi > 0.f && cp.chromco >= 0.f) && cp.quamet == 1 )){ + 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); + if (settings->verbose) { + printf("Denoise ab bishrink\n"); + } + } - 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); } @@ -1344,12 +1865,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; @@ -1360,24 +1875,24 @@ 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.chromco > 0.f) && cp.chromco < 2.f)) { + if (!adecomp->memory_allocation_failed() && !bdecomp->memory_allocation_failed()) { + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.quamet == 0)) { 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); - if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.chromco < 2.f)) { + if (cp.noiseena && ((cp.chromfi > 0.f || cp.chromco > 0.f) && cp.quamet == 0)) { 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); WaveletAandBAllAB(*adecomp, *bdecomp, cp, hhCurve, hhutili); @@ -1398,6 +1913,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (usechrom) { Ldecomp->reconstruct(labco->data, cp.strength); } + } } @@ -1519,13 +2035,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 @@ -1534,11 +2044,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) { @@ -1565,10 +2071,16 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (numtiles > 1) { float factor = Vmask[i1] * Hmask[j1]; + if(L <= 0.f) { + L= 1.f; + } dsttmp->L[i][j] += factor * L; dsttmp->a[i][j] += factor * a; dsttmp->b[i][j] += factor * b; } else { + if(L <= 0.f) { + L= 1.f; + } dsttmp->L[i][j] = L; dsttmp->a[i][j] = a; dsttmp->b[i][j] = b; @@ -1606,8 +2118,30 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } if (waparams.softradend > 0.f && cp.finena) { - array2D ble(lab->W, lab->H); - array2D guid(lab->W, lab->H); + float guid = waparams.softradend; + float strend = waparams.strend; + float detend = (float) waparams.detend; + float thrend = 0.01f * (float) waparams.thrend; + int ww = lab->W; + int hh = lab->H; + array2D LL(ww, hh); + array2D LLbef(ww, hh); + array2D LAbef(ww, hh); + array2D LBbef(ww, hh); + array2D guide(ww, hh); + const float blend = LIM01(float(strend) / 100.f); + float mean[10]; + float meanN[10]; + float sigma[10]; + float sigmaN[10]; + float MaxP[10]; + float MaxN[10]; + float meang[10]; + float meanNg[10]; + float sigmag[10]; + float sigmaNg[10]; + float MaxPg[10]; + float MaxNg[10]; bool multiTh = false; @@ -1619,43 +2153,148 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const #pragma omp parallel for #endif - - for (int ir = 0; ir < lab->H; ir++) { - for (int jr = 0; jr < lab->W; jr++) { - guid[ir][jr] = Color::L2Y(lab->L[ir][jr]) / 32768.f; - ble[ir][jr] = Color::L2Y(dst->L[ir][jr]) / 32768.f; + for (int y = 0; y < hh; y++) { + for (int x = 0; x < ww; x++) { + LL[y][x] = dst->L[y][x]; + LLbef[y][x] = dst->L[y][x]; + LAbef[y][x] = dst->a[y][x]; + LBbef[y][x] = dst->b[y][x]; + float ll = LL[y][x] / 32768.f; + guide[y][x] = xlin2log(rtengine::max(ll, 0.f), 10.f); } } + array2D iL(ww, hh, LL, 0); + int r = rtengine::max(int(guid / skip), 1); - constexpr double epsilmax = 0.002; - constexpr double epsilmin = 0.0005; - constexpr double aepsil = 0.01f * (epsilmax - epsilmin); - constexpr double bepsil = epsilmin; - const double epsil = aepsil * waparams.softradend + bepsil; - - const float blur = 10.f / scale * (0.001f + 0.8f * waparams.softradend); - - rtengine::guidedFilter(guid, ble, ble, blur, epsil, multiTh); - + const float epsil = 0.001f * std::pow(2, - detend); + rtengine::guidedFilterLog(guide, 10.f, LL, r, epsil, multiTh); + //take Hue to modulate LL + //LL in function of LLbef and Labef Lbbef + if(wavguidutili) { #ifdef _OPENMP #pragma omp parallel for #endif - - for (int ir = 0; ir < lab->H; ir++) { - for (int jr = 0; jr < lab->W; jr++) { - dst->L[ir][jr] = Color::computeXYZ2LabY(32768.f * ble[ir][jr]); + for (int y = 0; y < hh ; y++) { + for (int x = 0; x < ww; x++) { + float hueG = xatan2f(LBbef[y][x], LAbef[y][x]); + float valparam = 1.f * (static_cast(wavguidCurve->getVal(Color::huelab_to_huehsv2(hueG))) - 0.5f); + LL[y][x] = LLbef[y][x] + (LL[y][x] - LLbef[y][x]) * (1.f + valparam); + } } } + //end hue + + + if (thrend > 0.f) { + //2 decomposition LL after guidefilter and dst before (perhaps dst no need) + const std::unique_ptr LdecompLL(new wavelet_decomposition(LL[0], ww, hh, levwavL, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); + const std::unique_ptr Ldecompdst(new wavelet_decomposition(dst->L[0], ww, hh, levwavL, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); + if (!LdecompLL->memory_allocation_failed() && !Ldecompdst->memory_allocation_failed()) { + + Evaluate2(*LdecompLL, meang, meanNg, sigmag, sigmaNg, MaxPg, MaxNg, wavNestedLevels); + Evaluate2(*Ldecompdst, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavNestedLevels); + float sig = 2.f; + float thr = 0.f; + if(thrend < 0.02f) thr = 0.5f; + else if(thrend < 0.1f) thr = 0.2f; + else thr = 0.f; + + FlatCurve wavguid({ + FCT_MinMaxCPoints, + 0, 1, 0.35, 0.35,thrend, 1.0, 0.35, 0.35, thrend + 0.01f, thr, 0.35, 0.35, 1, thr, 0.35, 0.35 + }); + + for (int dir = 1; dir < 4; dir++) { + for (int level = 0; level < levwavL-1; level++) { + int Wlvl_L = LdecompLL->level_W(level); + int Hlvl_L = LdecompLL->level_H(level); + float* const* WavCoeffs_L = LdecompLL->level_coeffs(level);//first decomp denoised + float* const* WavCoeffs_L2 = Ldecompdst->level_coeffs(level);//second decomp before denoise + if (settings->verbose) { + printf("level=%i mean=%.0f meanden=%.0f sigma=%.0f sigmaden=%.0f Max=%.0f Maxden=%.0f\n", level, mean[level], meang[level], sigma[level], sigmag[level],MaxP[level], MaxPg[level]); + } + + //find local contrast + float tempmean = 0.f; + float tempsig = 0.f; + float tempmax = 0.f; + tempmean = 0.3f * mean[level] + 0.7f * meang[level] ; + tempsig = 0.3f * sigma[level] + 0.7f * sigmag[level] ; + tempmax = 0.3f * MaxP[level] + 0.7f * MaxPg[level] ; + + if (MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { //curve + float insigma = 0.666f; //SD + float logmax = log(tempmax); //log Max + //cp.sigmm change the "wider" of sigma + float rapX = (tempmean + sig * tempsig) / (tempmax); //rapport between sD / max + float inx = log(insigma); + float iny = log(rapX); + float rap = inx / iny; //koef + float asig = 0.166f / (tempsig * sig); + float bsig = 0.5f - asig * tempmean; + float amean = 0.5f / (tempmean); + + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, Wlvl_L * 16) num_threads(wavNestedLevels) if (wavNestedLevels>1) +#endif + + for (int i = 0; i < Wlvl_L * Hlvl_L; i++) { + float absciss; + float tempwav = 0.f; + tempwav = 0.7f * WavCoeffs_L[dir][i] + 0.3f * WavCoeffs_L2[dir][i]; + + if (std::fabs(tempwav) >= (tempmean + sig * tempsig)) { //for max + float valcour = xlogf(std::fabs(tempwav)); + float valc = valcour - logmax; + float vald = valc * rap; + absciss = xexpf(vald); + } else if (std::fabs(tempwav) >= tempmean) { + absciss = asig * std::fabs(tempwav) + bsig; + } else { + absciss = amean * std::fabs(tempwav); + float k = sig; + if(sig > 1.f) { + k = SQR(sig); + } + float abs = pow(2.f * absciss, (1.f / k)); + absciss = 0.5f * abs; + } + float kc = wavguid.getVal(absciss) -1.f; + + if(kc < 0) { + kc = -SQR(kc);//approximation to simulate sliders denoise + } + float reduceeffect = kc <= 0.f ? 1.f : 1.2f;//1.2 allows to increase denoise (not used) + + float kinterm = 1.f + reduceeffect * kc; + kinterm = kinterm <= 0.f ? 0.01f : kinterm; + float prov = WavCoeffs_L2[dir][i];//save before denoise + WavCoeffs_L[dir][i] = prov + (WavCoeffs_L[dir][i] - prov) * kinterm;//only apply local contrast on difference between denoise and normal + } + } + } + } + LdecompLL->reconstruct(LL[0], cp.strength); + } } -#ifdef _DEBUG - delete MunsDebugInfo; + + //end local contrast +#ifdef _OPENMP + #pragma omp parallel for #endif - + for (int y = 0; y < hh ; y++) { + for (int x = 0; x < ww; x++) { + LL[y][x] = intp(blend, LL[y][x] , iL[y][x]); + dst->L[y][x] = LL[y][x]; + } + } + } } -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 @@ -1666,7 +2305,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; @@ -1710,14 +2349,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++) { @@ -1744,8 +2383,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(); @@ -1755,9 +2393,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); } } @@ -1814,8 +2452,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]; @@ -1824,8 +2461,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; @@ -1916,219 +2553,129 @@ 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, +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) { +// BENCHFUN 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, @@ -2137,43 +2684,30 @@ 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 + if ((cp.conres >= 0.f || cp.conresH >= 0.f) && cp.resena) { // 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++) { @@ -2182,12 +2716,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++) { @@ -2195,18 +2727,12 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * WavCoeffs_L0[i * W_L + j] = temp->L[i][j]; } } - - delete temp; - } + // 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 + if ((cp.conres < 0.f || cp.conresH < 0.f) && cp.resena) { // 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 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++) { @@ -2273,10 +2799,15 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * } } -// - 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) #endif @@ -2292,14 +2823,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) @@ -2307,14 +2839,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 = 0.f; + calckoe (WavCoeffs_LL[dir], gradw, tloww, koeLi[lvl * 3 + dir - 1], lvl, 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++) { @@ -2415,13 +2947,14 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * for (int i = 0; i < 500; i++) { if (wavblcurve[i] != 0.) { wavcurvecomp = true; + break; } } } + std::unique_ptr aft; #ifdef _OPENMP - // #pragma omp for schedule(dynamic) collapse(2) - #pragma omp for reduction(+:n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n32) schedule(dynamic) collapse(2) + #pragma omp for schedule(dynamic) collapse(2) #endif for (int dir = 1; dir < 4; dir++) { @@ -2430,102 +2963,48 @@ 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); - 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, waOpacityCurveSH, ChCurve, Chutili); - int minWL = min(Wlvl_L, Hlvl_L); + 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); - if(minWL > 180) { + if (std::min(Wlvl_L, Hlvl_L) > 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); - - 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]); - - if (WavCL < mea[0]) { - beta[co] = 0.05f; - n0++; - - 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++; - } - - + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.6f, 0.4f, 0.2f, 0.1f, 0.01f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); + if (!aft.get()) { + aft.reset(new float[Wlvl_L * Hlvl_L]); } - 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); + //blur level + const float klev = wavblcurve[lvl * 55.5f] * 80.f / skip; + auto WavL = WavCoeffs_L[dir]; + boxblur(WavL, aft.get(), klev, Wlvl_L, Hlvl_L, false); + + int co = 0; +#ifdef __SSE2__ + const vfloat lutFactorv = F2V(lutFactor); + for (; co < Hlvl_L * Wlvl_L - 3; co += 4) { + const vfloat valv = LVFU(WavL[co]); + STVFU(WavL[co], intp((*meaLut)[vabsf(valv) * lutFactorv], LVFU(aft[co]), valv)); } - - 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]; +#endif + for (; co < Hlvl_L * Wlvl_L; co++) { + WavL[co] = intp((*meaLut)[std::fabs(WavL[co]) * lutFactor], aft[co], WavL[co]); } - - delete[] bef; - delete[] aft; - delete[] beta; } } } } } - - //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"); @@ -2533,8 +3012,8 @@ 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) #endif @@ -2591,15 +3070,15 @@ 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, +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) { - +//BENCHFUN 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) @@ -2655,7 +3134,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 @@ -2734,10 +3213,12 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float for (int i = 0; i < 500; i++) { if (wavblcurve[i] != 0.) { wavcurvecomp = true; + break; } } } + std::unique_ptr aft; #ifdef _OPENMP #pragma omp for schedule(dynamic) collapse(2) #endif @@ -2748,93 +3229,51 @@ 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); + 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(std::min(Wlvl_ab, Hlvl_ab) > 180) { 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]; - - for (int co = 0; co < Wlvl_ab * Hlvl_ab; co++) { - beta[co] = 1.f; - } - + const float effect = cp.bluwav; + constexpr float offs = 1.f; calceffect(lvl, meanab, sigmaab, mea, effect, offs); + float lutFactor; + const float inVals[] = {0.05f, 0.2f, 0.7f, 1.f, 1.f, 0.8f, 0.6f, 0.4f, 0.2f, 0.1f, 0.00f}; + const auto meaLut = buildMeaLut(inVals, mea, lutFactor); - 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; - } - - + if (!aft.get()) { + aft.reset(new float[Wlvl_ab * Hlvl_ab]); } - klev = (wavblcurve[lvl * 55.5f]); + //blur level + const float klev = wavblcurve[lvl * 55.5f] * 80.f / skip; + boxblur(WavCoeffs_ab[dir], aft.get(), klev, Wlvl_ab, Hlvl_ab, false); - 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]; + auto WavAb = WavCoeffs_ab[dir]; + int co = 0; +#ifdef __SSE2__ + const vfloat lutFactorv = F2V(lutFactor); + for (; co < Hlvl_ab * Wlvl_ab - 3; co += 4) { + const vfloat valv = LVFU(WavAb[co]); + STVFU(WavAb[co], intp((*meaLut)[vabsf(valv) * lutFactorv], LVFU(aft[co]), valv)); + } +#endif + for (; co < Hlvl_ab * Wlvl_ab; co++) { + WavAb[co] = intp((*meaLut)[std::fabs(WavAb[co]) * lutFactor], aft[co], WavAb[co]); } - - delete[] bef; - delete[] aft; - delete[] beta; } } - } } - - } } -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -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* WavCoeffs, float gradw, float tloww, float *koeLi, int level, int W_L, int H_L, float edd, float &maxkoeLi, float **tmC, bool multiThread) { - int borderL = 2; - - if (cp.eddetthr < 30.f) { - borderL = 1; + const int borderL = tloww < 75.f ? 1 : 2; + if (tloww < 75.f) { // I calculate coefficients with r size matrix 3x3 r=1 ; 5x5 r=2; 7x7 r=3 /* float k[2*r][2*r]; @@ -2846,139 +3285,159 @@ void ImProcFunctions::calckoe(float ** WavCoeffs_LL, const cont_params& cp, floa //I could also use Gauss.h for 3x3 // If necessary I can put a 7x7 matrix */ - for (int i = 1; i < H_L - 1; i++) { //sigma=0.55 - for (int j = 1; j < W_L - 1; j++) { - tmC[i][j] = (8.94f * WavCoeffs_LL[dir][i * W_L + j] + 1.71f * (WavCoeffs_LL[dir][(i - 1) * W_L + j] + 1.71f * WavCoeffs_LL[dir][(i + 1) * W_L + j] - + 1.71f * WavCoeffs_LL[dir][i * W_L + j + 1] + 1.71f * WavCoeffs_LL[dir][i * W_L + j - 1]) + 0.33f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 1] - + 0.33f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 1] + 0.33f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 1] + 0.33f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 1]) * 0.0584795f; - // apply to each direction Wavelet level : horizontal / vertiacle / diagonal - - - } + float c0, c1, c2, mult; + if (tloww < 30.f) { //sigma=0.55 + c0 = 8.94f; + c1 = 1.71f; + c2 = 0.33f; + mult = 0.0584795f; + } else if (tloww < 50.f) { //sigma=0.85 + c0 = 4.0091f; + c1 = 2.0068f; + c2 = 1.0045f; + mult = 0.062288f; + } else { //sigma=1.1 + c0 = 3.025f; + c1 = 2.001f; + c2 = 1.323f; + mult = 0.06127f; } - } else if (cp.eddetthr >= 30.f && cp.eddetthr < 50.f) { - borderL = 1; - - for (int i = 1; i < H_L - 1; i++) { //sigma=0.85 - for (int j = 1; j < W_L - 1; j++) { - tmC[i][j] = (4.0091f * WavCoeffs_LL[dir][i * W_L + j] + 2.0068f * (WavCoeffs_LL[dir][(i - 1) * W_L + j] + 2.0068f * WavCoeffs_LL[dir][(i + 1) * W_L + j] - + 2.0068f * WavCoeffs_LL[dir][i * W_L + j + 1] + 2.0068f * WavCoeffs_LL[dir][i * W_L + j - 1]) + 1.0045f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 1] - + 1.0045f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 1] + 1.0045f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 1] + 1.0045f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 1]) * 0.062288f; - // apply to each direction Wavelet level : horizontal / vertiacle / diagonal - - - } - } - } - - - else if (cp.eddetthr >= 50.f && cp.eddetthr < 75.f) { - borderL = 1; - + c0 *= mult; + c1 *= mult; + c2 *= mult; +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif for (int i = 1; i < H_L - 1; i++) { - for (int j = 1; j < W_L - 1; j++) { //sigma=1.1 - tmC[i][j] = (3.025f * WavCoeffs_LL[dir][i * W_L + j] + 2.001f * (WavCoeffs_LL[dir][(i - 1) * W_L + j] + 2.001f * WavCoeffs_LL[dir][(i + 1) * W_L + j] - + 2.001f * WavCoeffs_LL[dir][i * W_L + j + 1] + 2.001f * WavCoeffs_LL[dir][i * W_L + j - 1]) + 1.323f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 1] - + 1.323f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 1] + 1.323f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 1] + 1.323f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 1]) * 0.06127f; + for (int j = 1; j < W_L - 1; j++) { + tmC[i][j] = c0 * WavCoeffs[i * W_L + j] + + c1 * ((WavCoeffs[(i - 1) * W_L + j] + WavCoeffs[(i + 1) * W_L + j]) + (WavCoeffs[i * W_L + j + 1] + WavCoeffs[i * W_L + j - 1])) + + c2 * ((WavCoeffs[(i - 1) * W_L + j - 1] + WavCoeffs[(i - 1) * W_L + j + 1]) + (WavCoeffs[(i + 1) * W_L + j - 1] + WavCoeffs[(i + 1) * W_L + j + 1])); } } - } - - else if (cp.eddetthr >= 75.f) { - borderL = 2; - + } else { if (level > 1) { // do not activate 5x5 if level 0 or 1 + // Gaussian 1.1 + // 0.5 2 3 2 0.5 + // 2 7 10 7 2 + // 3 10 15 10 3 + // 2 7 10 7 2 + // 0.5 2 3 2 0.5 + // divi 113 + //Gaussian 1.4 + // 2 4 5 4 2 + // 4 9 12 9 4 + // 5 12 15 12 5 + // 4 9 12 9 4 + // 2 4 5 4 2 + // divi 159 + float c0, c1, c2, c3, c4, c5, mult; + if (tloww < 85.f) { //sigma=1.1 + c0 = 15.f; + c1 = 10.f; + c2 = 7.f; + c3 = 3.f; + c4 = 2.f; + c5 = 0.5f; + mult = 0.0088495f; + } else { //sigma=1.4 + c0 = 15.f; + c1 = 12.f; + c2 = 9.f; + c3 = 5.f; + c4 = 4.f; + c5 = 2.f; + mult = 0.0062893f; + } + c0 *= mult; + c1 *= mult; + c2 *= mult; + c3 *= mult; + c4 *= mult; + c5 *= mult; +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif for (int i = 2; i < H_L - 2; i++) { for (int j = 2; j < W_L - 2; j++) { - // Gaussian 1.1 - // 0.5 2 3 2 0.5 - // 2 7 10 7 2 - // 3 10 15 10 3 - // 2 7 10 7 2 - // 0.5 2 3 2 0.5 - // divi 113 - //Gaussian 1.4 - // 2 4 5 4 2 - // 4 9 12 9 4 - // 5 12 15 12 5 - // 4 9 12 9 4 - // 2 4 5 4 2 - // divi 159 - if (cp.eddetthr < 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] - + 3.f * WavCoeffs_LL[dir][(i - 2) * W_L + j] + 3.f * WavCoeffs_LL[dir][(i + 2) * W_L + j] + 3.f * WavCoeffs_LL[dir][i * W_L + j - 2] + 3.f * WavCoeffs_LL[dir][i * W_L + j + 2] - + 2.f * WavCoeffs_LL[dir][(i - 2) * W_L + j - 1] + 2.f * WavCoeffs_LL[dir][(i - 2) * W_L + j + 1] + 2.f * WavCoeffs_LL[dir][(i + 2) * W_L + j + 1] + 2.f * WavCoeffs_LL[dir][(i + 2) * W_L + j - 1] - + 2.f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 2] + 2.f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 2] + 2.f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 2] + 2.f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 2] - + 0.5f * WavCoeffs_LL[dir][(i - 2) * W_L + j - 2] + 0.5f * WavCoeffs_LL[dir][(i - 2) * W_L + j + 2] + 0.5f * WavCoeffs_LL[dir][(i + 2) * W_L + j - 2] + 0.5f * WavCoeffs_LL[dir][(i + 2) * W_L + j + 2] - ) * 0.0088495f; - - } - - else {//sigma=1.4 - tmC[i][j] = (15.f * WavCoeffs_LL[dir][i * W_L + j] + 12.f * WavCoeffs_LL[dir][(i - 1) * W_L + j] + 12.f * WavCoeffs_LL[dir][(i + 1) * W_L + j] - + 12.f * WavCoeffs_LL[dir][i * W_L + j + 1] + 12.f * WavCoeffs_LL[dir][i * W_L + j - 1] + 9.f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 1] - + 9.f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 1] + 9.f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 1] + 9.f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 1] - + 5.f * WavCoeffs_LL[dir][(i - 2) * W_L + j] + 5.f * WavCoeffs_LL[dir][(i + 2) * W_L + j] + 5.f * WavCoeffs_LL[dir][i * W_L + j - 2] + 5.f * WavCoeffs_LL[dir][i * W_L + j + 2] - + 4.f * WavCoeffs_LL[dir][(i - 2) * W_L + j - 1] + 4.f * WavCoeffs_LL[dir][(i - 2) * W_L + j + 1] + 4.f * WavCoeffs_LL[dir][(i + 2) * W_L + j + 1] + 4.f * WavCoeffs_LL[dir][(i + 2) * W_L + j - 1] - + 4.f * WavCoeffs_LL[dir][(i - 1) * W_L + j - 2] + 4.f * WavCoeffs_LL[dir][(i - 1) * W_L + j + 2] + 4.f * WavCoeffs_LL[dir][(i + 1) * W_L + j + 2] + 4.f * WavCoeffs_LL[dir][(i + 1) * W_L + j - 2] - + 2.f * WavCoeffs_LL[dir][(i - 2) * W_L + j - 2] + 2.f * WavCoeffs_LL[dir][(i - 2) * W_L + j + 2] + 2.f * WavCoeffs_LL[dir][(i + 2) * W_L + j - 2] + 2.f * WavCoeffs_LL[dir][(i + 2) * W_L + j + 2] - ) * 0.0062893f; - } - - - // apply to each direction Wavelet level : horizontal / vertiacle / diagonal + tmC[i][j] = c0 * WavCoeffs[i * W_L + j] + + c1 * ((WavCoeffs[(i - 1) * W_L + j] + WavCoeffs[(i + 1) * W_L + j]) + (WavCoeffs[i * W_L + j + 1] + WavCoeffs[i * W_L + j - 1])) + + c2 * ((WavCoeffs[(i - 1) * W_L + j - 1] + WavCoeffs[(i - 1) * W_L + j + 1]) + (WavCoeffs[(i + 1) * W_L + j - 1] + WavCoeffs[(i + 1) * W_L + j + 1])) + + c3 * ((WavCoeffs[(i - 2) * W_L + j] + WavCoeffs[(i + 2) * W_L + j]) + (WavCoeffs[i * W_L + j - 2] + WavCoeffs[i * W_L + j + 2])) + + c4 * ((WavCoeffs[(i - 2) * W_L + j - 1] + WavCoeffs[(i - 2) * W_L + j + 1]) + (WavCoeffs[(i + 2) * W_L + j + 1] + WavCoeffs[(i + 2) * W_L + j - 1]) + + (WavCoeffs[(i - 1) * W_L + j - 2] + WavCoeffs[(i - 1) * W_L + j + 2]) + (WavCoeffs[(i + 1) * W_L + j + 2] + WavCoeffs[(i + 1) * W_L + j - 2])) + + c5 * ((WavCoeffs[(i - 2) * W_L + j - 2] + WavCoeffs[(i - 2) * W_L + j + 2]) + (WavCoeffs[(i + 2) * W_L + j - 2] + WavCoeffs[(i + 2) * W_L + j + 2])); } } + } else { +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + koeLi[i * W_L + j] = 0.f; + } + } + return; } - } - 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); - - for (int i = 0; i < H_L; i++) { + // fill borders with 1.f + int ii = 0; + for (; ii < borderL; ii++) { for (int j = 0; j < W_L; j++) { - koeLi[level * 3 + dir - 1][i * W_L + j] = 1.f; + koeLi[ii * W_L + j] = 1.f; } } + for (; ii < H_L - borderL; ii++) { + for (int j = 0; j < borderL; j++) { + koeLi[ii * W_L + j] = 1.f; + } + for (int j = W_L - borderL; j < W_L; j++) { + koeLi[ii * W_L + j] = 1.f; + } + } + for (; ii < H_L; ii++) { + for (int j = 0; j < W_L; j++) { + koeLi[ii * W_L + j] = 1.f; + } + } + + constexpr float thr = 40.f; //avoid artifact eg. noise...to test + const float thr2 = 1.5f * edd + gradw / 30.f; //edd can be modified in option ed_detect + const float diffFactor = gradw / 100.f; for (int i = borderL; i < H_L - borderL; i++) { 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 = 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 + float temp = rtengine::max(std::fabs(WavCoeffs[i * W_L + j]), thr); + koeLi[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[i * W_L + j] > maxkoeLi) { + maxkoeLi = koeLi[i * W_L + j]; } - - float diff = maxkoeLi[level * 3 + dir - 1] - koeLi[level * 3 + dir - 1][i * W_L + j]; + float diff = maxkoeLi - koeLi[i * W_L + j]; diff *= diffFactor; - koeLi[level * 3 + dir - 1][i * W_L + j] = maxkoeLi[level * 3 + dir - 1] - diff; + koeLi[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] + cp.sigmafin * 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] * cp.sigmafin); float bsig = 0.5f - asig * mean[level]; - float amean = 0.5f / 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) @@ -3120,7 +3579,7 @@ 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, +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); @@ -3132,11 +3591,11 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz for (int sc = 0; sc < 10; sc++) { scaleskip[sc] = scales[sc] / skip; } - +/* if (settings->verbose) { printf("level=%i mean=%f sigma=%f maxp=%f\n", level, mean[level], sigma[level], MaxP[level]); } - +*/ constexpr float t_r = 40.f; constexpr float t_l = 10.f; constexpr float b_r = 75.f; @@ -3249,7 +3708,6 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz koe[i * W_L + j] = rtengine::min(thr2, std::fabs(tmC[i][j] / temp)); maxkoe = rtengine::max(maxkoe, koe[i * W_L + j]); - float diff = maxkoe - koe[i * W_L + j]; diff *= (cp.eddet / 100.f); float interm = maxkoe - diff; @@ -3280,10 +3738,13 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float atten01234 = 0.80f; value *= (atten01234 * scaleskip[1]); //for zoom < 100% reduce strength...I choose level 1...but!! } - + float edghig = settings->edghi;//increase or reduce "reinforce" + float edglow = settings->edglo;//increase or reduce "reduce" + float limrad = settings->limrad;//threshold action in function radius (rad) + // printf("edghi=%f edglo=%f limrad=%f\n", edghig, edglow, limrad); // 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 lim0 = limrad; //arbitrary limit for low radius and level between 2 or 3 to 30 maxi float lev = float (level); float repart = (float)cp.til; @@ -3291,15 +3752,14 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz if (cp.reinforce != 2) { const float brepart = cp.reinforce == 1 - ? 3.f - : 0.5f; + ? edghig + : edglow; const float arepart = -(brepart - 1.f) / (lim0 / 60.f); - if (rad < lim0 / 60.f) { + if (rad < (lim0 / 60.f)) { repart *= (arepart * rad + brepart); //linear repartition of repart } } - float al0 = 1.f + (repart) / 50.f; float al10 = 1.0f; //arbitrary value ==> less = take into account high levels // float ak =-(al0-al10)/10.f;//10 = maximum levels @@ -3307,15 +3767,16 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float bk = al0; float koef = ak * level + bk; //modulate for levels : more levels high, more koef low ==> concentrated action on low levels, without or near for high levels float expkoef = -std::pow(std::fabs(rad - lev), koef); //reduce effect for high levels + // printf("repart=%f\n", repart); if (cp.reinforce == 3) { - if (rad < lim0 / 60.f && level == 0) { + if (rad < (lim0 / 60.f) && level == 0) { expkoef *= abs(repart); //reduce effect for low values of rad and level=0==> quasi only level 1 is effective } } if (cp.reinforce == 1) { - if (rad < lim0 / 60.f && level == 1) { + if (rad < (lim0 / 60.f) && level == 1) { expkoef /= repart; //increase effect for low values of rad and level=1==> quasi only level 0 is effective } } @@ -3349,13 +3810,13 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz // 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 + 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 asig = 0.166f / (sigma[level]); float bsig = 0.5f - asig * mean[level]; - float amean = 0.5f / mean[level]; + float amean = 0.5f / (mean[level]); float absciss = 0.f; float kinterm; float kmul; @@ -3376,7 +3837,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; } @@ -3482,7 +3943,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; } @@ -3571,32 +4032,26 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz } } - if (!cp.link && cp.noiseena) { //used both with denoise 1 2 3 float refine = 0.f; + if (level == 0) { + refine = cp.lev0s / 40.f; + } else if (level == 1) { + refine = cp.lev1s / 40.f; + } else if (level == 2) { + refine = cp.lev2s / 40.f; + } else if (level == 3) { + refine = cp.lev3s / 40.f; + } - for (int i = 0; i < W_L * H_L; i++) { - if (level == 0) { - refine = cp.lev0s / 40.f; + if (refine != 0.f) { + refine += 1.f; + for (int i = 0; i < W_L * H_L; i++) { + WavCoeffs_L[dir][i] *= refine; } - - if (level == 1) { - refine = cp.lev1s / 40.f; - } - - if (level == 2) { - refine = cp.lev2s / 40.f; - } - - if (level == 3) { - refine = cp.lev3s / 40.f; - } - - WavCoeffs_L[dir][i] *= (1.f + refine); } } - float cpMul = cp.mul[level]; if (cpMul != 0.f && cp.contena) { // cpMul == 0.f means all will be multiplied by 1.f, so we can skip this @@ -3618,10 +4073,12 @@ 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 kLlevH = 1.f; - float kLlevS = 1.f; + float kLlev = 1.f; if (cpMul < 0.f) { lbeta = 1.f; // disabled for negatives values "less contrast" @@ -3725,41 +4182,43 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float aaarS = (alpha - 1.f) / (cp.t_rsl - cp.b_rsl); float bbbrS = 1.f - cp.b_rsl * aaarS; -// if (level <= cp.numlevH) { //in function of levels - float klevred = 2.f * (waOpacityCurveSH[level * 55.5f] - 0.5f); - if(klevred > 0.f && level <= 6) {// level < 6 to avoid bad use of the curve if user put negative values positives + if (level <= cp.numlevH) { //in function of levels if ((LL100 > cp.t_lhl * kH[level] && LL100 < cp.t_rhl * kH[level])) { - kLlevH = alpha; + kLlev = alpha; } else if ((LL100 > cp.b_lhl * kH[level] && LL100 <= cp.t_lhl * kH[level])) { - kLlevH = aaal * LL100 + bbal; + kLlev = aaal * LL100 + bbal; } else if ((LL100 > cp.t_rhl * kH[level] && LL100 <= cp.b_rhl * kH[level])) { - kLlevH = aaar * LL100 + bbbr; + kLlev = aaar * LL100 + bbbr; } else { - kLlevH = 1.f; + kLlev = 1.f; } - kLlevH = 1.f + (kLlevH - 1.f) * klevred; } - // if (level >= (9 - cp.numlevS)) { - if(klevred < 0.f && level >= 3) {//level > 3 to avoid bad use of the curve if user put positives values negatives + 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)) { - kLlevS = alpha; + kLlev = alpha; + // n++; } else if ((LL100 > cp.b_lsl && LL100 <= cp.t_lsl)) { - kLlevS = aaalS * LL100 + bbalS; + kLlev = aaalS * LL100 + bbalS; + // m++; } else if ((LL100 > cp.t_rsl && LL100 <= cp.b_rsl)) { - kLlevS = aaarS * LL100 + bbbrS; + kLlev = aaarS * LL100 + bbbrS; + // p++; } else { - kLlevS = 1.f; + kLlev = 1.f; + // q++; } - kLlevS = 1.f - (kLlevS - 1.f) * klevred; } } else { - kLlevH = kLlevS = alpha; + kLlev = alpha; } - WavCoeffs_L[dir][i] *= (kLlevH * kLlevS); + WavCoeffs_L[dir][i] *= (kLlev); } + + // printf("lev=%i n=%i m=%i p=%i q=%i\n", level, n, m, p, q); } if (waOpacityCurveW) { @@ -3907,7 +4366,7 @@ 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, +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]; diff --git a/rtengine/jdatasrc.cc b/rtengine/jdatasrc.cc index e461b60f5..f9256899d 100644 --- a/rtengine/jdatasrc.cc +++ b/rtengine/jdatasrc.cc @@ -248,12 +248,18 @@ my_error_exit (j_common_ptr cinfo) } -//const char * const jpeg_std_message_table[] = { -//#include "jerror.h" -// NULL -//}; -extern const char * const jpeg_std_message_table[]; +#ifdef WIN32 +#define JVERSION "6b 27-Mar-1998" +#define JCOPYRIGHT_SHORT "(C) 1998, Thomas G. Lane" +#define JMESSAGE(code,string) string , +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; +#else +extern const char * const jpeg_std_message_table[]; +#endif /* * Actual output of an error or trace message. @@ -373,9 +379,9 @@ format_message (j_common_ptr cinfo, char * buffer) /* Format the message into the passed buffer */ if (isstring) { - sprintf(buffer, msgtext, err->msg_parm.s); + snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.s); } else - sprintf(buffer, msgtext, + snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.i[0], err->msg_parm.i[1], err->msg_parm.i[2], err->msg_parm.i[3], err->msg_parm.i[4], err->msg_parm.i[5], diff --git a/rtengine/klt/trackFeatures.cc b/rtengine/klt/trackFeatures.cc index a99225543..8c0cd5ba6 100644 --- a/rtengine/klt/trackFeatures.cc +++ b/rtengine/klt/trackFeatures.cc @@ -1044,7 +1044,7 @@ static int _am_trackFeatureAffine( #ifdef DEBUG_AFFINE_MAPPING aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_trans_diff_win%03d.%03d.pgm", glob_index, counter); + snprintf(fname, sizeof(fname), "./debug/kltimg_trans_diff_win%03d.%03d.pgm", glob_index, counter); printf("%s\n", fname); _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); printf("iter = %d translation tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); @@ -1095,13 +1095,13 @@ static int _am_trackFeatureAffine( counter++; _am_computeAffineMappedImage(img1, x1, y1, 1.0, 0.0 , 0.0, 1.0, width, height, imgdiff); aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_1.pgm", glob_index, counter); + snprintf(fname, sizeof(fname), "./debug/kltimg_aff_diff_win%03d.%03d_1.pgm", glob_index, counter); printf("%s\n", fname); _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); _am_computeAffineMappedImage(img2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, width, height, imgdiff); aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_2.pgm", glob_index, counter); + snprintf(fname, sizeof(fname), "./debug/kltimg_aff_diff_win%03d.%03d_2.pgm", glob_index, counter); printf("%s\n", fname); _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); #endif @@ -1110,7 +1110,7 @@ static int _am_trackFeatureAffine( width, height, imgdiff); #ifdef DEBUG_AFFINE_MAPPING aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_3.pgm", glob_index,counter); + snprintf(fname, sizeof(fname), "./debug/kltimg_aff_diff_win%03d.%03d_3.pgm", glob_index,counter); printf("%s\n", fname); _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); @@ -1335,17 +1335,17 @@ void KLTTrackFeatures( if (tc->writeInternalImages) { char fname[80]; for (i = 0 ; i < tc->nPyramidLevels ; i++) { - sprintf(fname, "kltimg_tf_i%d.pgm", i); + snprintf(fname, sizeof(fname), "kltimg_tf_i%d.pgm", i); _KLTWriteFloatImageToPGM(pyramid1->img[i], fname); - sprintf(fname, "kltimg_tf_i%d_gx.pgm", i); + snprintf(fname, sizeof(fname), "kltimg_tf_i%d_gx.pgm", i); _KLTWriteFloatImageToPGM(pyramid1_gradx->img[i], fname); - sprintf(fname, "kltimg_tf_i%d_gy.pgm", i); + snprintf(fname, sizeof(fname), "kltimg_tf_i%d_gy.pgm", i); _KLTWriteFloatImageToPGM(pyramid1_grady->img[i], fname); - sprintf(fname, "kltimg_tf_j%d.pgm", i); + snprintf(fname, sizeof(fname), "kltimg_tf_j%d.pgm", i); _KLTWriteFloatImageToPGM(pyramid2->img[i], fname); - sprintf(fname, "kltimg_tf_j%d_gx.pgm", i); + snprintf(fname, sizeof(fname), "kltimg_tf_j%d_gx.pgm", i); _KLTWriteFloatImageToPGM(pyramid2_gradx->img[i], fname); - sprintf(fname, "kltimg_tf_j%d_gy.pgm", i); + snprintf(fname, sizeof(fname), "kltimg_tf_j%d_gy.pgm", i); _KLTWriteFloatImageToPGM(pyramid2_grady->img[i], fname); } } diff --git a/rtengine/klt/writeFeatures.cc b/rtengine/klt/writeFeatures.cc index 1bfe3f20f..d3bf6f3d4 100644 --- a/rtengine/klt/writeFeatures.cc +++ b/rtengine/klt/writeFeatures.cc @@ -97,6 +97,7 @@ static FILE* _printSetupTxt( const char *fname, /* Input: filename, or NULL for stderr */ const char *fmt, /* Input: format (e.g., %5.1f or %3d) */ char *format, /* Output: format (e.g., (%5.1f,%5.1f)=%3d) */ + std::size_t format_size, char *type) /* Output: either 'f' or 'd', based on input format */ { FILE *fp; @@ -124,7 +125,7 @@ static FILE* _printSetupTxt( } /* Construct feature format */ - sprintf(format, "(%s,%s)=%%%dd ", fmt, fmt, val_width); + snprintf(format, format_size, "(%s,%s)=%%%dd ", fmt, fmt, val_width); return fp; } @@ -163,7 +164,7 @@ static void _printInteger( int width) { char fmt[80]; - sprintf(fmt, "%%%dd", width); + snprintf(fmt, sizeof(fmt), "%%%dd", width); fprintf(fp, fmt, integer); } @@ -358,7 +359,7 @@ void KLTWriteFeatureList( } if (fmt != nullptr) { /* text file or stderr */ - fp = _printSetupTxt(fname, fmt, format, &type); + fp = _printSetupTxt(fname, fmt, format, sizeof(format), &type); _printHeader(fp, format, FEATURE_LIST, 0, fl->nFeatures); for (i = 0 ; i < fl->nFeatures ; i++) { @@ -396,7 +397,7 @@ void KLTWriteFeatureHistory( } if (fmt != nullptr) { /* text file or stderr */ - fp = _printSetupTxt(fname, fmt, format, &type); + fp = _printSetupTxt(fname, fmt, format, sizeof(format), &type); _printHeader(fp, format, FEATURE_HISTORY, fh->nFrames, 0); for (i = 0 ; i < fh->nFrames ; i++) { @@ -435,7 +436,7 @@ void KLTWriteFeatureTable( } if (fmt != nullptr) { /* text file or stderr */ - fp = _printSetupTxt(fname, fmt, format, &type); + fp = _printSetupTxt(fname, fmt, format, sizeof(format), &type); _printHeader(fp, format, FEATURE_TABLE, ft->nFrames, ft->nFeatures); for (j = 0 ; j < ft->nFeatures ; j++) { diff --git a/rtengine/labimage.cc b/rtengine/labimage.cc index 153af4c75..68d3857e5 100644 --- a/rtengine/labimage.cc +++ b/rtengine/labimage.cc @@ -24,9 +24,18 @@ 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 (const LabImage& source, bool multiThread) : W(source.W), H(source.H) +{ + allocLab(W, H); + CopyFrom(&source, multiThread); } LabImage::~LabImage () @@ -34,12 +43,24 @@ LabImage::~LabImage () deleteLab(); } -void LabImage::CopyFrom(LabImage *Img) +void LabImage::CopyFrom(const 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) +void LabImage::getPipetteData (float &v1, float &v2, float &v3, int posX, int posY, int squareSize) const { float accumulator_L = 0.f; float accumulator_a = 0.f; @@ -102,4 +123,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..4d1c05aed 100644 --- a/rtengine/labimage.h +++ b/rtengine/labimage.h @@ -35,14 +35,16 @@ public: float** a; float** b; - LabImage (int w, int h); + LabImage (int w, int h, bool initZero = false, bool multiThread = true); + LabImage (const LabImage& source, bool multiThread); ~LabImage (); //Copies image data in Img into this instance. - void CopyFrom(LabImage *Img); - void getPipetteData (float &L, float &a, float &b, int posX, int posY, int squareSize); + void CopyFrom(const LabImage *Img, bool multiThread = true); + void getPipetteData (float &L, float &a, float &b, int posX, int posY, int squareSize) const; 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/lmmse_demosaic.cc b/rtengine/lmmse_demosaic.cc index 5c4ddffed..c2d5bffbf 100644 --- a/rtengine/lmmse_demosaic.cc +++ b/rtengine/lmmse_demosaic.cc @@ -41,6 +41,18 @@ namespace rtengine // TODO Tiles to reduce memory consumption void RawImageSource::lmmse_interpolate_omp(int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations) { + // Test for RGB cfa + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + if (FC(i, j) == 3) { + // avoid crash + std::cout << "lmmse_interpolate_omp supports only RGB Colour filter arrays. Falling back to igv_interpolate" << std::endl; + igv_interpolate(winw, winh); + return; + } + } + } + const int width = winw, height = winh; const int ba = 10; const int rr1 = height + 2 * ba; diff --git a/rtengine/myfile.h b/rtengine/myfile.h index 423edea9a..34b90c525 100644 --- a/rtengine/myfile.h +++ b/rtengine/myfile.h @@ -107,13 +107,13 @@ inline int getc (IMFILE* f) return fgetc(f); } -inline int fread (void* dst, int es, int count, IMFILE* f) +inline int fread (void* dst, size_t es, size_t count, IMFILE* f) { - int s = es * count; - int avail = f->size - f->pos; + size_t s = es * count; + size_t avail = static_cast(f->size) - static_cast(f->pos); - if (s <= avail) { + if (static_cast(s) <= static_cast(avail)) { memcpy (dst, f->data + f->pos, s); f->pos += s; diff --git a/rtengine/perspectivecorrection.cc b/rtengine/perspectivecorrection.cc new file mode 100644 index 000000000..7a56ef5a8 --- /dev/null +++ b/rtengine/perspectivecorrection.cc @@ -0,0 +1,411 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Alberto Griggio + * + * 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 . + */ + +// taken from darktable (src/iop/ashift.c) +/* + This file is part of darktable, + copyright (c) 2016 Ulrich Pegelow. + + 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 . +*/ +// Inspiration to this module comes from the program ShiftN (http://www.shiftn.de) by +// Marcus Hebel. + +// Thanks to Marcus for his support when implementing part of the ShiftN functionality +// to darktable. + + +#include "perspectivecorrection.h" +#include "improcfun.h" +#include "procparams.h" +#include "rt_math.h" +#include +#include +#include +#include +#include +#include +#include + +#include "../rtgui/threadutils.h" +#include "colortemp.h" +#include "imagefloat.h" +#include "settings.h" + +namespace rtengine { extern const Settings *settings; } + +#define _(msg) (msg) +#define dt_control_log(msg) \ + if (settings->verbose) { \ + printf("%s\n", msg); \ + fflush(stdout); \ + } + + +namespace rtengine { + +namespace { + +inline int mat3inv(float *const dst, const float *const src) +{ + std::array, 3> tmpsrc; + std::array, 3> tmpdst; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + tmpsrc[i][j] = src[3 * i + j]; + } + } + if (invertMatrix(tmpsrc, tmpdst)) { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + dst[3 * i + j] = tmpdst[i][j]; + } + } + return 0; + } else { + return 1; + } +} + + +// the darktable ashift iop (adapted to RT), which does most of the work +#include "ashift_dt.c" + + +} // namespace + + +namespace { + +/* +std::vector get_corners(int w, int h) +{ + int x1 = 0, y1 = 0; + int x2 = w, y2 = h; + + std::vector corners = { + Coord2D(x1, y1), + Coord2D(x1, y2), + Coord2D(x2, y2), + Coord2D(x2, y1) + }; + return corners; +} +*/ + +void init_dt_structures(dt_iop_ashift_params_t *p, dt_iop_ashift_gui_data_t *g, + const procparams::PerspectiveParams *params) +{ + dt_iop_ashift_params_t dp = { + 0.0f, + 0.0f, + 0.0f, + 0.0f, + DEFAULT_F_LENGTH, + 1.f, + 0.0f, + 1.0f, + ASHIFT_MODE_SPECIFIC, + 0, + ASHIFT_CROP_OFF, + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f + }; + *p = dp; + + g->buf = NULL; + g->buf_width = 0; + g->buf_height = 0; + g->buf_x_off = 0; + g->buf_y_off = 0; + g->buf_scale = 1.0f; + g->buf_hash = 0; + g->isflipped = 0; + g->lastfit = ASHIFT_FIT_NONE; + g->fitting = 0; + g->lines = NULL; + g->lines_count =0; + g->horizontal_count = 0; + g->vertical_count = 0; + g->grid_hash = 0; + g->lines_hash = 0; + g->rotation_range = ROTATION_RANGE_SOFT; + g->lensshift_v_range = LENSSHIFT_RANGE_SOFT; + g->lensshift_h_range = LENSSHIFT_RANGE_SOFT; + g->shear_range = SHEAR_RANGE_SOFT; + g->camera_pitch_range = CAMERA_ANGLE_RANGE_SOFT; + g->camera_yaw_range = CAMERA_ANGLE_RANGE_SOFT; + g->lines_suppressed = 0; + g->lines_version = 0; + g->show_guides = 0; + g->isselecting = 0; + g->isdeselecting = 0; + g->isbounding = ASHIFT_BOUNDING_OFF; + g->near_delta = 0; + g->selecting_lines_version = 0; + g->points = NULL; + g->points_idx = NULL; + g->points_lines_count = 0; + g->points_version = 0; + g->jobcode = ASHIFT_JOBCODE_NONE; + g->jobparams = 0; + g->adjust_crop = FALSE; + g->lastx = g->lasty = -1.0f; + g->crop_cx = g->crop_cy = 1.0f; + + if (params) { + p->rotation = params->camera_roll; + p->lensshift_v = params->camera_shift_vert; + p->lensshift_h = params->camera_shift_horiz; + p->f_length = params->camera_focal_length; + p->crop_factor = params->camera_crop_factor; + p->camera_pitch = params->camera_pitch; + p->camera_yaw = params->camera_yaw; + } +} + + +/* +void get_view_size(int w, int h, const procparams::PerspectiveParams ¶ms, double &cw, double &ch) +{ + double min_x = RT_INFINITY, max_x = -RT_INFINITY; + double min_y = RT_INFINITY, max_y = -RT_INFINITY; + + auto corners = get_corners(w, h); + + float homo[3][3]; + homography((float *)homo, params.angle, params.vertical / 100.0, -params.horizontal / 100.0, params.shear / 100.0, params.flength * params.cropfactor, 100.f, params.aspect, w, h, ASHIFT_HOMOGRAPH_FORWARD); + + for (auto &c : corners) { + float pin[3] = { float(c.x), float(c.y), 1.f }; + float pout[3]; + mat3mulv(pout, (float *)homo, pin); + double x = pout[0] / pout[2]; + double y = pout[1] / pout[2]; + min_x = min(min_x, x); + max_x = max(max_x, x); + min_y = min(min_y, y); + max_y = max(max_y, y); + } + + cw = max_x - min_x; + ch = max_y - min_y; +} +*/ + +/** + * Allocates a new array and populates it with ashift lines corresponding to the + * provided control lines. + */ +std::unique_ptr toAshiftLines(const std::vector *lines) +{ + std::unique_ptr retval(new dt_iop_ashift_line_t[lines->size()]); + + for (size_t i = 0; i < lines->size(); i++) { + const float x1 = (*lines)[i].x1; + const float y1 = (*lines)[i].y1; + const float x2 = (*lines)[i].x2; + const float y2 = (*lines)[i].y2; + retval[i].p1[0] = x1; + retval[i].p1[1] = y1; + retval[i].p1[2] = 1.0f; + retval[i].p2[0] = x2; + retval[i].p2[1] = y2; + retval[i].p2[2] = 1.0f; + retval[i].length = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + retval[i].width = 1.0f; + retval[i].weight = retval[i].length; + if ((*lines)[i].type == ControlLine::HORIZONTAL) { + retval[i].type = ASHIFT_LINE_HORIZONTAL_SELECTED; + } else if ((*lines)[i].type == ControlLine::VERTICAL) { + retval[i].type = ASHIFT_LINE_VERTICAL_SELECTED; + } else { + retval[i].type = ASHIFT_LINE_IRRELEVANT; + } + } + + return retval; +} + +} // namespace + + +PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata, const std::vector *control_lines) +{ + auto pcp = procparams::PerspectiveParams(pparams->perspective); + procparams::PerspectiveParams dflt; + /* + pcp.horizontal = dflt.horizontal; + pcp.vertical = dflt.vertical; + pcp.angle = dflt.angle; + pcp.shear = dflt.shear; + */ + pcp.camera_pitch = dflt.camera_pitch; + pcp.camera_roll = dflt.camera_roll; + pcp.camera_yaw = dflt.camera_yaw; + + dt_iop_ashift_params_t p; + dt_iop_ashift_gui_data_t g; + init_dt_structures(&p, &g, &pparams->perspective); + dt_iop_module_t module; + module.gui_data = &g; + module.is_raw = src->isRAW(); + + int tr = getCoarseBitMask(pparams->coarse); + int fw, fh; + src->getFullSize(fw, fh, tr); + if (control_lines == nullptr) { + int skip = max(float(max(fw, fh)) / 900.f + 0.5f, 1.f); + PreviewProps pp(0, 0, fw, fh, skip); + int w, h; + src->getSize(pp, w, h); + std::unique_ptr img(new Imagefloat(w, h)); + + ProcParams neutral; + neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); + neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); + neutral.icm.outputProfile = ColorManagementParams::NoICMString; + src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw); + src->convertColorSpace(img.get(), pparams->icm, src->getWB()); + + neutral.commonTrans.autofill = false; // Ensures crop factor is correct. + // TODO: Ensure image borders of rotated image do not get detected as lines. + neutral.rotate = pparams->rotate; + neutral.distortion = pparams->distortion; + neutral.lensProf = pparams->lensProf; + ImProcFunctions ipf(&neutral, true); + if (ipf.needsTransform(w, h, src->getRotateDegree(), src->getMetaData())) { + Imagefloat *tmp = new Imagefloat(w, h); + ipf.transform(img.get(), tmp, 0, 0, 0, 0, w, h, w, h, + src->getMetaData(), src->getRotateDegree(), false); + img.reset(tmp); + } + + // allocate the gui buffer + g.buf = static_cast(malloc(sizeof(float) * w * h * 4)); + g.buf_width = w; + g.buf_height = h; + + img->normalizeFloatTo1(); + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + int i = (y * w + x) * 4; + g.buf[i] = img->r(y, x); + g.buf[i+1] = img->g(y, x); + g.buf[i+2] = img->b(y, x); + g.buf[i+3] = 1.f; + } + } + } + + dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; + if (corr_pitch && corr_yaw) { + fitaxis = ASHIFT_FIT_BOTH_SHEAR; + } else if (corr_pitch) { + fitaxis = ASHIFT_FIT_VERTICALLY; + } else if (corr_yaw) { + fitaxis = ASHIFT_FIT_HORIZONTALLY; + } + + // reset the pseudo-random seed for repeatability -- ashift_dt uses rand() + // internally! + srand(1); + + bool res; + if (control_lines == nullptr) { + res = do_get_structure(&module, &p, ASHIFT_ENHANCE_EDGES) && do_fit(&module, &p, fitaxis); + } else { + std::unique_ptr ashift_lines = toAshiftLines(control_lines); + dt_iop_ashift_gui_data_t *g = module.gui_data; + g->lines_count = control_lines->size(); + g->lines = ashift_lines.get(); + g->lines_in_height = fh; + g->lines_in_width = fw; + update_lines_count(g->lines, g->lines_count, &(g->vertical_count), &(g->horizontal_count)); + res = do_fit(&module, &p, fitaxis, 2); + g->lines = nullptr; + } + Params retval = { + .angle = p.rotation, + .pitch = p.camera_pitch, + .yaw = p.camera_yaw + }; + + // cleanup the gui + if (g.lines) free(g.lines); + if (g.points) free(g.points); + if (g.points_idx) free(g.points_idx); + if (g.buf) free(g.buf); + + if (!res) { + retval.angle = pparams->perspective.camera_roll; + retval.pitch = pparams->perspective.camera_pitch; + retval.yaw = pparams->perspective.camera_yaw; + } + return retval; +} + + +/* +void PerspectiveCorrection::autocrop(int width, int height, bool fixratio, const procparams::PerspectiveParams ¶ms, const FramesMetaData *metadata, int &x, int &y, int &w, int &h) +{ + auto pp = import_meta(params, metadata); + double cw, ch; + get_view_size(width, height, params, cw, ch); + double s = min(double(width)/cw, double(height)/ch); + dt_iop_ashift_params_t p; + dt_iop_ashift_gui_data_t g; + init_dt_structures(&p, &g, &pp); + dt_iop_module_t module = { &g, false }; + g.buf_width = width; + g.buf_height = height; + p.cropmode = fixratio ? ASHIFT_CROP_ASPECT : ASHIFT_CROP_LARGEST; + do_crop(&module, &p); + cw *= s; + ch *= s; + double ox = p.cl * cw; + double oy = p.ct * ch; + x = ox - (cw - width)/2.0 + 0.5; + y = oy - (ch - height)/2.0 + 0.5; + w = (p.cr - p.cl) * cw; + h = (p.cb - p.ct) * ch; +} +*/ + +} // namespace rtengine diff --git a/rtengine/perspectivecorrection.h b/rtengine/perspectivecorrection.h new file mode 100644 index 000000000..f092f2c8c --- /dev/null +++ b/rtengine/perspectivecorrection.h @@ -0,0 +1,63 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Alberto Griggio + * + * 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 + +namespace rtengine { + +namespace procparams +{ + +class ProcParams; + +} + +class ImageSource; +class FramesMetaData; + +class ControlLine +{ +public: + enum Type + { + HORIZONTAL, + VERTICAL + }; + float x1, y1, x2, y2; + Type type; +}; + +class PerspectiveCorrection { +public: + struct Params + { + double angle; + double pitch; + double yaw; + }; + + static Params autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata, const std::vector *control_lines = nullptr); + + //static void autocrop(int width, int height, bool fixratio, const procparams::PerspectiveParams ¶ms, const FramesMetaData *metadata, int &x, int &y, int &w, int &h); +}; + +} // namespace rtengine diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 2e98b7b22..ff7be3e40 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -283,20 +283,20 @@ void calcFrameBrightnessFactor(unsigned int frame, uint32_t datalen, LUTu *histo { float medians[4]; - for(int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) { //find median of histogram - uint32_t median = 0, count = 0; + uint32_t lmedian = 0, count = 0; - while(count < datalen / 2) { - count += (*histo[i])[median]; - ++median; + while (count < datalen / 2) { + count += (*histo[i])[lmedian]; + ++lmedian; } - const float weight = (count - datalen / 2.f) / (*histo[i])[median - 1]; - medians[i] = rtengine::intp(weight, (float)(median - 2), (float)(median - 1)); + const float weight = (count - datalen / 2.f) / (*histo[i])[lmedian - 1]; + medians[i] = rtengine::intp(weight, (float)(lmedian - 2), (float)(lmedian - 1)); } - for(int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) { brightnessFactor[i] = medians[frame] / medians[i]; } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 1b00d4218..9f4e3e77c 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -518,29 +518,535 @@ 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, + EvlocallabdehazeSaturation = 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, + EvLocena_mask = 927, + Evlocallabsensimask = 928, + Evlocallabblendmask = 929, + EvLocallabEnaMask = 930, + Evlocallabradmask = 931, + Evlocallablapmask = 932, + Evlocallabchromask = 933, + Evlocallabgammask = 934, + Evlocallabslopmask = 935, + EvlocallabCCmask_shape = 936, + EvlocallabLLmask_shape = 937, + EvlocallabHHmask_shape = 938, + EvLocallabtoolmask = 939, + Evlocallabstrumaskmask = 940, + EvlocallabHHhmask_shape = 941, + EvLocallabfftmask = 942, + Evlocallabblurmask = 943, + Evlocallabcontmask = 944, + Evlocallabshadmask = 945, + EvlocallabLmask_shape = 946, + EvlocallabLLmask_shapewav = 947, + EvlocallabcsThresholdmask = 948, + Evlocallabstr_mask = 949, + Evlocallabang_mask = 950, + Evlocallabsoftradiusmask = 951, + Evlocallabblendmaskab = 952, + EvLocallabSpotprevMethod = 953, + Evlocallabactiv = 954, + EvlocallabCHshape = 955, + EvlocallabquaMethod = 956, + Evlocallabhishow = 957, + Evlocallabinvbl = 958, + Evlocallabcatad = 959, + Evlocallabciecam = 960, + Evlocallabsourceabs = 961, + Evlocallabtargabs = 962, + Evlocallabsurround = 963, + Evlocallabsaturl = 964, + Evlocallabcontl = 965, + EvlocallabCCmaskshapeL = 966, + EvlocallabLLmaskshapeL = 967, + EvlocallabHHmaskshapeL = 968, + EvLocallabEnaLMask = 969, + EvLocallabblendmaskL = 970, + EvLocallabradmaskL = 971, + EvLocallabchromaskL = 972, + EvlocallabLmaskshapeL = 973, + Evlocallablightl = 974, + EvlocallabLshapeL = 975, + Evlocallabcontq = 976, + Evlocallabsursour = 977, + Evlocallablightq = 978, + Evlocallabcolorfl = 979, + Evlocallabrepar = 980, 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 fba29188b..cfbdb8510 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -112,6 +112,16 @@ void getFromKeyfile( value = keyfile.get_double(group_name, key); } +void getFromKeyfile( + const Glib::KeyFile& keyfile, + const Glib::ustring& group_name, + const Glib::ustring& key, + float& value +) +{ + value = static_cast(keyfile.get_double(group_name, key)); +} + void getFromKeyfile( const Glib::KeyFile& keyfile, const Glib::ustring& group_name, @@ -132,6 +142,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, @@ -143,6 +163,21 @@ void getFromKeyfile( rtengine::sanitizeCurve(value); } +void getFromKeyfile( + const Glib::KeyFile& keyfile, + const Glib::ustring& group_name, + const Glib::ustring& key, + rtengine::procparams::FilmNegativeParams::RGB& value +) +{ + const std::vector v = keyfile.get_double_list(group_name, key); + if(v.size() >= 3) { + value.r = v[0]; + value.g = v[1]; + value.b = v[2]; + } +} + template bool assignFromKeyfile( const Glib::KeyFile& keyfile, @@ -209,6 +244,16 @@ void putToKeyfile( keyfile.set_integer(group_name, key, value); } +void putToKeyfile( + const Glib::ustring& group_name, + const Glib::ustring& key, + float value, + Glib::KeyFile& keyfile +) +{ + keyfile.set_double(group_name, key, static_cast(value)); +} + void putToKeyfile( const Glib::ustring& group_name, const Glib::ustring& key, @@ -261,6 +306,18 @@ void putToKeyfile( keyfile.set_double_list(group_name, key, list); } +void putToKeyfile( + const Glib::ustring& group_name, + const Glib::ustring& key, + const rtengine::procparams::FilmNegativeParams::RGB& value, + Glib::KeyFile& keyfile +) +{ + const std::vector vec = { value.r, value.g, value.b }; + keyfile.set_double_list(group_name, key, vec); +} + + template bool saveToKeyfile( bool save, @@ -453,6 +510,7 @@ RetinexParams::RetinexParams() : shadows(0), stonalwidth(80), radius(40), + complexmethod("normal"), retinexMethod("high"), retinexcolorspace("Lab"), gammaretinex("none"), @@ -490,6 +548,7 @@ bool RetinexParams::operator ==(const RetinexParams& other) const && shadows == other.shadows && stonalwidth == other.stonalwidth && radius == other.radius + && complexmethod == other.complexmethod && retinexMethod == other.retinexMethod && retinexcolorspace == other.retinexcolorspace && gammaretinex == other.gammaretinex @@ -608,7 +667,6 @@ bool RGBCurvesParams::operator !=(const RGBCurvesParams& other) const return !(*this == other); } - LocalContrastParams::LocalContrastParams(): enabled(false), radius(80), @@ -618,7 +676,6 @@ LocalContrastParams::LocalContrastParams(): { } - bool LocalContrastParams::operator==(const LocalContrastParams &other) const { return @@ -629,13 +686,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; @@ -648,46 +703,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 @@ -700,13 +755,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), @@ -745,7 +798,7 @@ ColorToningParams::ColorToningParams() : strength(50), balance(0), hlColSat(60, 80, false), - shadowsColSat (80, 208, false), + shadowsColSat(80, 208, false), clcurve{ DCT_NURBS, 0.00, @@ -848,7 +901,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.] @@ -890,7 +943,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.] @@ -1278,17 +1331,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 @@ -1309,8 +1368,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}, @@ -1369,6 +1426,7 @@ ColorAppearanceParams::ColorAppearanceParams() : curveMode(TcMode::LIGHT), curveMode2(TcMode::LIGHT), curveMode3(CtcMode::CHROMA), + complexmethod("normal"), surround("Average"), surrsrc("Average"), adapscen(2000.0), @@ -1417,6 +1475,7 @@ bool ColorAppearanceParams::operator ==(const ColorAppearanceParams& other) cons && curveMode == other.curveMode && curveMode2 == other.curveMode2 && curveMode3 == other.curveMode3 + && complexmethod == other.complexmethod && surround == other.surround && surrsrc == other.surrsrc && adapscen == other.adapscen @@ -1914,16 +1973,49 @@ LensProfParams::LcMode LensProfParams::getMethodNumber(const Glib::ustring& mode } PerspectiveParams::PerspectiveParams() : + method("simple"), + render(true), horizontal(0.0), - vertical(0.0) + vertical(0.0), + camera_crop_factor(0.0), + camera_focal_length(0.0), + camera_pitch(0.0), + camera_roll(0.0), + camera_shift_horiz(0.0), + camera_shift_vert(0.0), + camera_yaw(0.0), + projection_pitch(0.0), + projection_rotate(0.0), + projection_shift_horiz(0.0), + projection_shift_vert(0.0), + projection_yaw(0.0) { } bool PerspectiveParams::operator ==(const PerspectiveParams& other) const { return - horizontal == other.horizontal - && vertical == other.vertical; + method == other.method + && render == other.render + && horizontal == other.horizontal + && vertical == other.vertical + && camera_focal_length == other.camera_focal_length + && camera_crop_factor == other.camera_crop_factor + && camera_pitch == other.camera_pitch + && camera_roll == other.camera_roll + && camera_shift_horiz == other.camera_shift_horiz + && camera_shift_vert == other.camera_shift_vert + && camera_yaw == other.camera_yaw + && projection_shift_horiz == other.projection_shift_horiz + && projection_shift_vert == other.projection_shift_vert + && projection_rotate == other.projection_rotate + && projection_pitch == other.projection_pitch + && projection_yaw == other.projection_yaw + // Lines could still be equivalent if the vectors aren't, but this is + // rare and a small issue. Besides, a proper comparison requires lots + // more code which introduces clutter. + && control_line_values == other.control_line_values + && control_line_types == other.control_line_types; } bool PerspectiveParams::operator !=(const PerspectiveParams& other) const @@ -2223,6 +2315,36 @@ WaveletParams::WaveletParams() : 0.35, 0.35 }, + wavdenoise{ + 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 + }, + wavdenoiseh{ + 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 + }, blcurve{ static_cast(FCT_MinMaxCPoints), 0.0, @@ -2231,12 +2353,21 @@ WaveletParams::WaveletParams() : 0.35, 0.5, 0., + 0.35, + 0.35, + 1.0, + 0.0, + 0.35, + 0.35 +/* + 0.0, 0.35, 0.35, 1.0, 0.0, 0.35, 0.35 +*/ }, opacityCurveRG{ static_cast(FCT_MinMaxCPoints), @@ -2249,6 +2380,42 @@ 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, @@ -2268,6 +2435,7 @@ WaveletParams::WaveletParams() : 0.35, 0.35 }, +*/ opacityCurveBY{ static_cast(FCT_MinMaxCPoints), 0.0, @@ -2312,6 +2480,12 @@ WaveletParams::WaveletParams() : hhcurve{ FCT_Linear }, + wavguidcurve{ + FCT_Linear + }, + wavhuecurve{ + FCT_Linear + }, Chcurve{ FCT_Linear }, @@ -2321,7 +2495,7 @@ WaveletParams::WaveletParams() : enabled(false), median(false), medianlev(false), - linkedg(true), + linkedg(false), cbenab(false), greenlow(0), bluelow(0), @@ -2330,13 +2504,20 @@ WaveletParams::WaveletParams() : greenhigh(0), bluehigh(0), ballum(7.), + sigm(1.0), + levden(0.), + thrden(0.), + limden(0.), balchrom(0.), chromfi(0.), chromco(0.), - mergeL(40.), + mergeL(20.), mergeC(20.), softrad(0.), softradend(0.), + strend(50.), + detend(0), + thrend(0), lipst(false), avoid(false), showmask(false), @@ -2370,6 +2551,11 @@ WaveletParams::WaveletParams() : CLmethod("all"), Backmethod("grey"), Tilesmethod("full"), + complexmethod("normal"), + denmethod("12low"), + mixmethod("mix"), + slimethod("sli"), + quamethod("cons"), daubcoeffmethod("4_"), CHmethod("without"), Medgreinf("less"), @@ -2398,7 +2584,7 @@ WaveletParams::WaveletParams() : thres(7), chroma(5), chro(0), - threshold(5), + threshold(4), threshold2(5), edgedetect(90), edgedetectthr(20), @@ -2426,7 +2612,9 @@ WaveletParams::WaveletParams() : level0noise(0, 0, false), level1noise(0, 0, false), level2noise(0, 0, false), - level3noise(0, 0, false) + level3noise(0, 0, false), + leveldenoise(0, 0, false), + levelsigm(1, 1, false) { } @@ -2434,6 +2622,8 @@ bool WaveletParams::operator ==(const WaveletParams& other) const { return ccwcurve == other.ccwcurve + && wavdenoise == other.wavdenoise + && wavdenoiseh == other.wavdenoiseh && blcurve == other.blcurve && opacityCurveRG == other.opacityCurveRG && opacityCurveSH == other.opacityCurveSH @@ -2441,6 +2631,8 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && opacityCurveW == other.opacityCurveW && opacityCurveWL == other.opacityCurveWL && hhcurve == other.hhcurve + && wavguidcurve == other.wavguidcurve + && wavhuecurve == other.wavhuecurve && Chcurve == other.Chcurve && wavclCurve == other.wavclCurve && enabled == other.enabled @@ -2455,6 +2647,10 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && greenhigh == other.greenhigh && bluehigh == other.bluehigh && ballum == other.ballum + && sigm == other.sigm + && levden == other.levden + && thrden == other.thrden + && limden == other.limden && balchrom == other.balchrom && chromfi == other.chromfi && chromco == other.chromco @@ -2462,6 +2658,9 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && mergeC == other.mergeC && softrad == other.softrad && softradend == other.softradend + && strend == other.strend + && detend == other.detend + && thrend == other.thrend && lipst == other.lipst && avoid == other.avoid && showmask == other.showmask @@ -2502,6 +2701,11 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && CLmethod == other.CLmethod && Backmethod == other.Backmethod && Tilesmethod == other.Tilesmethod + && complexmethod == other.complexmethod + && denmethod == other.denmethod + && mixmethod == other.mixmethod + && slimethod == other.slimethod + && quamethod == other.quamethod && daubcoeffmethod == other.daubcoeffmethod && CHmethod == other.CHmethod && Medgreinf == other.Medgreinf @@ -2558,7 +2762,9 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && level0noise == other.level0noise && level1noise == other.level1noise && level2noise == other.level2noise - && level3noise == other.level3noise; + && level3noise == other.level3noise + && leveldenoise == other.leveldenoise + && levelsigm == other.levelsigm; } bool WaveletParams::operator !=(const WaveletParams& other) const @@ -2568,6 +2774,8 @@ bool WaveletParams::operator !=(const WaveletParams& other) const void WaveletParams::getCurves( WavCurve& cCurve, + WavCurve& wavdenoise, + WavCurve& wavdenoiseh, Wavblcurve& tCurve, WavOpacityCurveRG& opacityCurveLUTRG, WavOpacityCurveSH& opacityCurveLUTSH, @@ -2577,6 +2785,8 @@ void WaveletParams::getCurves( ) const { cCurve.Set(this->ccwcurve); + wavdenoise.Set(this->wavdenoise); + wavdenoiseh.Set(this->wavdenoiseh); tCurve.Set(this->blcurve); opacityCurveLUTRG.Set(this->opacityCurveRG); opacityCurveLUTSH.Set(this->opacityCurveSH); @@ -2586,6 +2796,1897 @@ void WaveletParams::getCurves( } +LocallabParams::LocallabSpot::LocallabSpot() : + // Control spot settings + name(""), + isvisible(true), + prevMethod("hide"), + 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), + hishow(false), + activ(true), + avoid(true), + blwh(false), + recurs(false), + laplac(true), + deltae(true), + shortc(false), + savrest(false), + scopemask(60), + lumask(10), + // Color & Light + visicolor(false), + expcolor(false), + complexcolor(2), + 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 + }, + CHcurve{ + 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(false), + 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(20), + 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("tone"), + 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"), + quamethod("cons"), + 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), + invbl(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(60), + 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), + dehazeSaturation(50.0), + 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), + 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.), + sourceabs(2000.), + targabs(16.), + targetGray(18.), + catad(0.), + saturl(0.), + lightl(0.), + lightq(0.), + contl(0.), + contq(0.), + colorfl(0.), + LcurveL{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + Autogray(true), + fullimage(true), + repar(100.0), + ciecam(false), + blackEv(-5.0), + whiteEv(10.0), + detail(0.6), + sensilog(60), + sursour("Average"), + surround("Average"), + baselog(2.), + strlog(0.0), + anglog(0.0), + CCmaskcurveL{ + 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 + }, + LLmaskcurveL{ + 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 + }, + HHmaskcurveL{ + 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 + }, + enaLMask(false), + blendmaskL(0), + radmaskL(0.), + chromaskL(0.), + LmaskcurveL{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + // mask + visimask(false), + complexmask(0), + expmask(false), + sensimask(60), + blendmask(-10.), + blendmaskab(-10.), + softradiusmask(1.0), + enamask(false), + fftmask(true), + blurmask(0.2), + contmask(0.), + CCmask_curve{ + 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 + }, + LLmask_curve{ + 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 + }, + HHmask_curve{ + 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 + }, + strumaskmask(0.), + toolmask(false), + radmask(0.0), + lapmask(0.0), + chromask(0.0), + gammask(1.0), + slopmask(0.0), + shadmask(0.0), + str_mask(0), + ang_mask(0), + HHhmask_curve{ + 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 + }, + Lmask_curve{ + static_cast(DCT_NURBS), + 0.0, + 0.0, + 1.0, + 1.0 + }, + LLmask_curvewav{ + static_cast(FCT_MinMaxCPoints), + 0.0, + 0.5, + 0.35, + 0.35, + 1., + 0.5, + 0.35, + 0.35 + }, + csthresholdmask(0, 0, 6, 5, false) + +{ +} + +bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const +{ + return + // Control spot settings + name == other.name + && isvisible == other.isvisible + && prevMethod == other.prevMethod + && 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 + && hishow == other.hishow + && activ == other.activ + && 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 + && CHcurve == other.CHcurve + && 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 + && quamethod == other.quamethod + && 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 + && invbl == other.invbl + && 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 + && dehazeSaturation == other.dehazeSaturation + && 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 + && 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 + && complexlog == other.complexlog + && autocompute == other.autocompute + && sourceGray == other.sourceGray + && sourceabs == other.sourceabs + && targabs == other.targabs + && targetGray == other.targetGray + && catad == other.catad + && saturl == other.saturl + && lightl == other.lightl + && lightq == other.lightq + && contl == other.contl + && contq == other.contq + && colorfl == other.colorfl + && LcurveL == other.LcurveL + && Autogray == other.Autogray + && fullimage == other.fullimage + && repar == other.repar + && ciecam == other.ciecam + && blackEv == other.blackEv + && whiteEv == other.whiteEv + && detail == other.detail + && sensilog == other.sensilog + && baselog == other.baselog + && sursour == other.sursour + && surround == other.surround + && strlog == other.strlog + && anglog == other.anglog + && CCmaskcurveL == other.CCmaskcurveL + && LLmaskcurveL == other.LLmaskcurveL + && HHmaskcurveL == other.HHmaskcurveL + && enaLMask == other.enaLMask + && blendmaskL == other.blendmaskL + && radmaskL == other.radmaskL + && chromaskL == other.chromaskL + && LmaskcurveL == other.LmaskcurveL + + // mask + && visimask == other.visimask + && complexmask == other.complexmask + && expmask == other.expmask + && sensimask == other.sensimask + && blendmask == other.blendmask + && blendmaskab == other.blendmaskab + && softradiusmask == other.softradiusmask + && enamask == other.enamask + && fftmask == other.fftmask + && blurmask == other.blurmask + && contmask == other.contmask + && CCmask_curve == other.CCmask_curve + && LLmask_curve == other.LLmask_curve + && HHmask_curve == other.HHmask_curve + && strumaskmask == other.strumaskmask + && toolmask == other.toolmask + && radmask == other.radmask + && lapmask == other.lapmask + && chromask == other.chromask + && gammask == other.gammask + && slopmask == other.slopmask + && shadmask == other.shadmask + && str_mask == other.str_mask + && ang_mask == other.ang_mask + && HHhmask_curve == other.HHhmask_curve + && Lmask_curve == other.Lmask_curve + && LLmask_curvewav == other.LLmask_curvewav + && csthresholdmask == other.csthresholdmask; + +} + +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), @@ -2599,7 +4700,7 @@ DirPyrEqualizerParams::DirPyrEqualizerParams() : }, threshold(0.2), skinprotect(0.0), - hueskin (-5, 25, 170, 120, false), + hueskin(-5, 25, 170, 120, false), cbdlMethod("bef") { } @@ -2699,9 +4800,9 @@ bool SoftLightParams::operator !=(const SoftLightParams& other) const DehazeParams::DehazeParams() : enabled(false), strength(50), + saturation(50), showDepthMap(false), - depth(25), - luminance(false) + depth(25) { } @@ -2712,7 +4813,7 @@ bool DehazeParams::operator ==(const DehazeParams& other) const && strength == other.strength && showDepthMap == other.showDepthMap && depth == other.depth - && luminance == other.luminance; + && saturation == other.saturation; } bool DehazeParams::operator !=(const DehazeParams& other) const @@ -2819,10 +4920,13 @@ const std::vector& RAWParams::BayerSensor::getMethodStrings() { static const std::vector method_strings { "amaze", + "amazebilinear", "amazevng4", "rcd", + "rcdbilinear", "rcdvng4", "dcb", + "dcbbilinear", "dcbvng4", "lmmse", "igv", @@ -2859,8 +4963,6 @@ Glib::ustring RAWParams::BayerSensor::getPSDemosaicMethodString(PSDemosaicMethod return getPSDemosaicMethodStrings()[toUnderlying(method)]; } - - RAWParams::XTransSensor::XTransSensor() : method(getMethodString(Method::THREE_PASS)), dualDemosaicAutoContrast(true), @@ -3013,12 +5115,35 @@ FilmNegativeParams::FilmNegativeParams() : redRatio(1.36), greenExp(1.5), blueRatio(0.86), - redBase(0), - greenBase(0), - blueBase(0) + refInput({0.0, 0.0, 0.0}), + refOutput({0.0, 0.0, 0.0}), + colorSpace(ColorSpace::WORKING), + backCompat(BackCompat::CURRENT) { } +bool FilmNegativeParams::RGB::operator ==(const FilmNegativeParams::RGB& other) const +{ + return + r == other.r + && g == other.g + && b == other.b; +} + +bool FilmNegativeParams::RGB::operator !=(const FilmNegativeParams::RGB& other) const +{ + return !(*this == other); +} + +FilmNegativeParams::RGB FilmNegativeParams::RGB::operator *(const FilmNegativeParams::RGB& other) const +{ + return { + (*this).r * other.r, + (*this).g * other.g, + (*this).b * other.b + }; +} + bool FilmNegativeParams::operator ==(const FilmNegativeParams& other) const { return @@ -3026,9 +5151,10 @@ bool FilmNegativeParams::operator ==(const FilmNegativeParams& other) const && redRatio == other.redRatio && greenExp == other.greenExp && blueRatio == other.blueRatio - && redBase == other.redBase - && greenBase == other.greenBase - && blueBase == other.blueBase; + && refInput == other.refInput + && refOutput == other.refOutput + && colorSpace == other.colorSpace + && backCompat == other.backCompat; } bool FilmNegativeParams::operator !=(const FilmNegativeParams& other) const @@ -3107,6 +5233,8 @@ void ProcParams::setDefaults() vignetting = {}; + locallab = {}; + chmixer = {}; blackwhite = {}; @@ -3215,6 +5343,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->retinex.limd, "Retinex", "Limd", retinex.limd, keyFile); saveToKeyfile(!pedited || pedited->retinex.highl, "Retinex", "highl", retinex.highl, keyFile); saveToKeyfile(!pedited || pedited->retinex.skal, "Retinex", "skal", retinex.skal, keyFile); + saveToKeyfile(!pedited || pedited->retinex.complexmethod, "Retinex", "complexMethod", retinex.complexmethod, keyFile); saveToKeyfile(!pedited || pedited->retinex.retinexMethod, "Retinex", "RetinexMethod", retinex.retinexMethod, keyFile); saveToKeyfile(!pedited || pedited->retinex.mapMethod, "Retinex", "mapMethod", retinex.mapMethod, keyFile); saveToKeyfile(!pedited || pedited->retinex.viewMethod, "Retinex", "viewMethod", retinex.viewMethod, keyFile); @@ -3381,6 +5510,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->colorappearance.degreeout, "Color appearance", "Degreeout", colorappearance.degreeout, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.autodegreeout, "Color appearance", "AutoDegreeout", colorappearance.autodegreeout, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.surround, "Color appearance", "Surround", colorappearance.surround, keyFile); + saveToKeyfile(!pedited || pedited->colorappearance.complexmethod, "Color appearance", "complex", colorappearance.complexmethod, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.surrsrc, "Color appearance", "Surrsrc", colorappearance.surrsrc, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.adaplum, "Color appearance", "AdaptLum", colorappearance.adaplum, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.badpixsl, "Color appearance", "Badpixsl", colorappearance.badpixsl, keyFile); @@ -3427,7 +5557,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 @@ -3451,7 +5580,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile); saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile); saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile); - saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Luminance", dehaze.luminance, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Saturation", dehaze.saturation, keyFile); // Directional pyramid denoising saveToKeyfile(!pedited || pedited->dirpyrDenoise.enabled, "Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled, keyFile); @@ -3545,8 +5674,24 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->lensProf.lfLens, "LensProfile", "LFLens", lensProf.lfLens, keyFile); // Perspective correction + saveToKeyfile(!pedited || pedited->perspective.method, "Perspective", "Method", perspective.method, keyFile); saveToKeyfile(!pedited || pedited->perspective.horizontal, "Perspective", "Horizontal", perspective.horizontal, keyFile); saveToKeyfile(!pedited || pedited->perspective.vertical, "Perspective", "Vertical", perspective.vertical, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_crop_factor, "Perspective", "CameraCropFactor", perspective.camera_crop_factor, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_focal_length, "Perspective", "CameraFocalLength", perspective.camera_focal_length, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_pitch, "Perspective", "CameraPitch", perspective.camera_pitch, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_roll, "Perspective", "CameraRoll", perspective.camera_roll, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_shift_horiz, "Perspective", "CameraShiftHorizontal", perspective.camera_shift_horiz, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_shift_vert, "Perspective", "CameraShiftVertical", perspective.camera_shift_vert, keyFile); + saveToKeyfile(!pedited || pedited->perspective.camera_yaw, "Perspective", "CameraYaw", perspective.camera_yaw, keyFile); + saveToKeyfile(!pedited || pedited->perspective.projection_shift_horiz, "Perspective", "ProjectionShiftHorizontal", perspective.projection_shift_horiz, keyFile); + saveToKeyfile(!pedited || pedited->perspective.projection_pitch, "Perspective", "ProjectionPitch", perspective.projection_pitch, keyFile); + saveToKeyfile(!pedited || pedited->perspective.projection_rotate, "Perspective", "ProjectionRotate", perspective.projection_rotate, keyFile); + saveToKeyfile(!pedited || pedited->perspective.projection_shift_horiz, "Perspective", "ProjectionShiftHorizontal", perspective.projection_shift_horiz, keyFile); + saveToKeyfile(!pedited || pedited->perspective.projection_shift_vert, "Perspective", "ProjectionShiftVertical", perspective.projection_shift_vert, keyFile); + saveToKeyfile(!pedited || pedited->perspective.projection_yaw, "Perspective", "ProjectionYaw", perspective.projection_yaw, keyFile); + saveToKeyfile(!pedited || pedited->perspective.control_lines, "Perspective", "ControlLineValues", perspective.control_line_values, keyFile); + saveToKeyfile(!pedited || pedited->perspective.control_lines, "Perspective", "ControlLineTypes", perspective.control_line_types, keyFile); // Gradient saveToKeyfile(!pedited || pedited->gradient.enabled, "Gradient", "Enabled", gradient.enabled, keyFile); @@ -3556,6 +5701,547 @@ 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->prevMethod, "Locallab", "PrevMethod_" + index_str, spot.prevMethod, 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->hishow, "Locallab", "Hishow_" + index_str, spot.hishow, keyFile); + saveToKeyfile(!pedited || spot_edited->activ, "Locallab", "Activ_" + index_str, spot.activ, 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->CHcurve, "Locallab", "CHCurve_" + index_str, spot.CHcurve, 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->quamethod, "Locallab", "QuaMethod_" + index_str, spot.quamethod, 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->invbl, "Locallab", "Invbl_" + index_str, spot.invbl, 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->dehazeSaturation, "Locallab", "dehazeSaturation_" + index_str, spot.dehazeSaturation, 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->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->complexlog, "Locallab", "Complexlog_" + index_str, spot.complexlog, 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->sourceabs, "Locallab", "Sourceabs_" + index_str, spot.sourceabs, keyFile); + saveToKeyfile(!pedited || spot_edited->targabs, "Locallab", "Targabs_" + index_str, spot.targabs, keyFile); + saveToKeyfile(!pedited || spot_edited->targetGray, "Locallab", "TargetGray_" + index_str, spot.targetGray, keyFile); + saveToKeyfile(!pedited || spot_edited->catad, "Locallab", "Catad_" + index_str, spot.catad, keyFile); + saveToKeyfile(!pedited || spot_edited->saturl, "Locallab", "Saturl_" + index_str, spot.saturl, keyFile); + saveToKeyfile(!pedited || spot_edited->LcurveL, "Locallab", "LCurveL_" + index_str, spot.LcurveL, keyFile); + saveToKeyfile(!pedited || spot_edited->lightl, "Locallab", "Lightl_" + index_str, spot.lightl, keyFile); + saveToKeyfile(!pedited || spot_edited->lightq, "Locallab", "Brightq_" + index_str, spot.lightq, keyFile); + saveToKeyfile(!pedited || spot_edited->contl, "Locallab", "Contl_" + index_str, spot.contl, keyFile); + saveToKeyfile(!pedited || spot_edited->contq, "Locallab", "Contq_" + index_str, spot.contq, keyFile); + saveToKeyfile(!pedited || spot_edited->colorfl, "Locallab", "Colorfl_" + index_str, spot.colorfl, 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->repar, "Locallab", "Repart_" + index_str, spot.repar, keyFile); + saveToKeyfile(!pedited || spot_edited->ciecam, "Locallab", "Ciecam_" + index_str, spot.ciecam, 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->sursour, "Locallab", "Sursour_" + index_str, spot.sursour, keyFile); + saveToKeyfile(!pedited || spot_edited->surround, "Locallab", "Surround_" + index_str, spot.surround, 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); + saveToKeyfile(!pedited || spot_edited->CCmaskcurveL, "Locallab", "CCmaskCurveL_" + index_str, spot.CCmaskcurveL, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmaskcurveL, "Locallab", "LLmaskCurveL_" + index_str, spot.LLmaskcurveL, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmaskcurveL, "Locallab", "HHmaskCurveL_" + index_str, spot.HHmaskcurveL, keyFile); + saveToKeyfile(!pedited || spot_edited->enaLMask, "Locallab", "EnaLMask_" + index_str, spot.enaLMask, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskL, "Locallab", "blendmaskL_" + index_str, spot.blendmaskL, keyFile); + saveToKeyfile(!pedited || spot_edited->radmaskL, "Locallab", "radmaskL_" + index_str, spot.radmaskL, keyFile); + saveToKeyfile(!pedited || spot_edited->chromaskL, "Locallab", "chromaskL_" + index_str, spot.chromaskL, keyFile); + saveToKeyfile(!pedited || spot_edited->LmaskcurveL, "Locallab", "LmaskCurveL_" + index_str, spot.LmaskcurveL, keyFile); + + } + //mask + if ((!pedited || spot_edited->visimask) && spot.visimask) { + saveToKeyfile(!pedited || spot_edited->expmask, "Locallab", "Expmask_" + index_str, spot.expmask, keyFile); + saveToKeyfile(!pedited || spot_edited->complexmask, "Locallab", "Complexmask_" + index_str, spot.complexmask, keyFile); + saveToKeyfile(!pedited || spot_edited->sensimask, "Locallab", "Sensimask_" + index_str, spot.sensimask, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmask, "Locallab", "Blendmaskmask_" + index_str, spot.blendmask, keyFile); + saveToKeyfile(!pedited || spot_edited->blendmaskab, "Locallab", "Blendmaskmaskab_" + index_str, spot.blendmaskab, keyFile); + saveToKeyfile(!pedited || spot_edited->softradiusmask, "Locallab", "Softradiusmask_" + index_str, spot.softradiusmask, keyFile); + saveToKeyfile(!pedited || spot_edited->enamask, "Locallab", "Enamask_" + index_str, spot.enamask, keyFile); + saveToKeyfile(!pedited || spot_edited->fftmask, "Locallab", "Fftmask_" + index_str, spot.fftmask, keyFile); + saveToKeyfile(!pedited || spot_edited->blurmask, "Locallab", "Blurmask_" + index_str, spot.blurmask, keyFile); + saveToKeyfile(!pedited || spot_edited->contmask, "Locallab", "Contmask_" + index_str, spot.contmask, keyFile); + saveToKeyfile(!pedited || spot_edited->CCmask_curve, "Locallab", "CCmask_Curve_" + index_str, spot.CCmask_curve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmask_curve, "Locallab", "LLmask_Curve_" + index_str, spot.LLmask_curve, keyFile); + saveToKeyfile(!pedited || spot_edited->HHmask_curve, "Locallab", "HHmask_Curve_" + index_str, spot.HHmask_curve, keyFile); + saveToKeyfile(!pedited || spot_edited->strumaskmask, "Locallab", "Strumaskmask_" + index_str, spot.strumaskmask, keyFile); + saveToKeyfile(!pedited || spot_edited->toolmask, "Locallab", "Toolmask_" + index_str, spot.toolmask, keyFile); + saveToKeyfile(!pedited || spot_edited->radmask, "Locallab", "Radmask_" + index_str, spot.radmask, keyFile); + saveToKeyfile(!pedited || spot_edited->lapmask, "Locallab", "Lapmask_" + index_str, spot.lapmask, keyFile); + saveToKeyfile(!pedited || spot_edited->chromask, "Locallab", "Chromask_" + index_str, spot.chromask, keyFile); + saveToKeyfile(!pedited || spot_edited->gammask, "Locallab", "Gammask_" + index_str, spot.gammask, keyFile); + saveToKeyfile(!pedited || spot_edited->slopmask, "Locallab", "Slopmask_" + index_str, spot.slopmask, keyFile); + saveToKeyfile(!pedited || spot_edited->shadmask, "Locallab", "Shadmask_" + index_str, spot.shadmask, keyFile); + saveToKeyfile(!pedited || spot_edited->str_mask, "Locallab", "Str_mask_" + index_str, spot.str_mask, keyFile); + saveToKeyfile(!pedited || spot_edited->ang_mask, "Locallab", "Ang_mask_" + index_str, spot.ang_mask, keyFile); + saveToKeyfile(!pedited || spot_edited->HHhmask_curve, "Locallab", "HHhmask_Curve_" + index_str, spot.HHhmask_curve, keyFile); + saveToKeyfile(!pedited || spot_edited->Lmask_curve, "Locallab", "Lmask_Curve_" + index_str, spot.Lmask_curve, keyFile); + saveToKeyfile(!pedited || spot_edited->LLmask_curvewav, "Locallab", "LLmask_Curvewav_" + index_str, spot.LLmask_curvewav, keyFile); + saveToKeyfile(!pedited || spot_edited->csthresholdmask, "Locallab", "CSThresholdmask_" + index_str, spot.csthresholdmask.toVector(), keyFile); + } + } + } + // Post-crop vignette saveToKeyfile(!pedited || pedited->pcvignette.enabled, "PCVignette", "Enabled", pcvignette.enabled, keyFile); saveToKeyfile(!pedited || pedited->pcvignette.strength, "PCVignette", "Strength", pcvignette.strength, keyFile); @@ -3651,6 +6337,11 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo 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); + saveToKeyfile(!pedited || pedited->wavelet.complexmethod, "Wavelet", "complexMethod", wavelet.complexmethod, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.denmethod, "Wavelet", "denMethod", wavelet.denmethod, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.mixmethod, "Wavelet", "mixMethod", wavelet.mixmethod, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.slimethod, "Wavelet", "sliMethod", wavelet.slimethod, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.quamethod, "Wavelet", "quaMethod", wavelet.quamethod, keyFile); saveToKeyfile(!pedited || pedited->wavelet.daubcoeffmethod, "Wavelet", "DaubMethod", wavelet.daubcoeffmethod, keyFile); saveToKeyfile(!pedited || pedited->wavelet.CLmethod, "Wavelet", "ChoiceLevMethod", wavelet.CLmethod, keyFile); saveToKeyfile(!pedited || pedited->wavelet.Backmethod, "Wavelet", "BackMethod", wavelet.Backmethod, keyFile); @@ -3663,6 +6354,10 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.bluemed, "Wavelet", "CBbluemed", wavelet.bluemed, keyFile); saveToKeyfile(!pedited || pedited->wavelet.bluelow, "Wavelet", "CBbluelow", wavelet.bluelow, keyFile); saveToKeyfile(!pedited || pedited->wavelet.ballum, "Wavelet", "Ballum", wavelet.ballum, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.sigm, "Wavelet", "Sigm", wavelet.sigm, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.levden, "Wavelet", "Levden", wavelet.levden, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.thrden, "Wavelet", "Thrden", wavelet.thrden, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.limden, "Wavelet", "Limden", wavelet.limden, keyFile); saveToKeyfile(!pedited || pedited->wavelet.balchrom, "Wavelet", "Balchrom", wavelet.balchrom, keyFile); saveToKeyfile(!pedited || pedited->wavelet.chromfi, "Wavelet", "Chromfine", wavelet.chromfi, keyFile); saveToKeyfile(!pedited || pedited->wavelet.chromco, "Wavelet", "Chromcoarse", wavelet.chromco, keyFile); @@ -3670,6 +6365,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.mergeC, "Wavelet", "MergeC", wavelet.mergeC, keyFile); saveToKeyfile(!pedited || pedited->wavelet.softrad, "Wavelet", "Softrad", wavelet.softrad, keyFile); saveToKeyfile(!pedited || pedited->wavelet.softradend, "Wavelet", "Softradend", wavelet.softradend, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.strend, "Wavelet", "Strend", wavelet.strend, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.detend, "Wavelet", "Detend", wavelet.detend, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.thrend, "Wavelet", "Thrend", wavelet.thrend, keyFile); saveToKeyfile(!pedited || pedited->wavelet.expcontrast, "Wavelet", "Expcontrast", wavelet.expcontrast, keyFile); saveToKeyfile(!pedited || pedited->wavelet.expchroma, "Wavelet", "Expchroma", wavelet.expchroma, keyFile); saveToKeyfile(!pedited || pedited->wavelet.expedge, "Wavelet", "Expedge", wavelet.expedge, keyFile); @@ -3707,6 +6405,8 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.level1noise, "Wavelet", "Level1noise", wavelet.level1noise.toVector(), keyFile); saveToKeyfile(!pedited || pedited->wavelet.level2noise, "Wavelet", "Level2noise", wavelet.level2noise.toVector(), keyFile); saveToKeyfile(!pedited || pedited->wavelet.level3noise, "Wavelet", "Level3noise", wavelet.level3noise.toVector(), keyFile); + saveToKeyfile(!pedited || pedited->wavelet.leveldenoise, "Wavelet", "Leveldenoise", wavelet.leveldenoise.toVector(), keyFile); + saveToKeyfile(!pedited || pedited->wavelet.levelsigm, "Wavelet", "Levelsigm", wavelet.levelsigm.toVector(), keyFile); saveToKeyfile(!pedited || pedited->wavelet.threshold, "Wavelet", "ThresholdHighlight", wavelet.threshold, keyFile); saveToKeyfile(!pedited || pedited->wavelet.threshold2, "Wavelet", "ThresholdShadow", wavelet.threshold2, keyFile); saveToKeyfile(!pedited || pedited->wavelet.edgedetect, "Wavelet", "Edgedetect", wavelet.edgedetect, keyFile); @@ -3731,9 +6431,13 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo 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.wavdenoise, "Wavelet", "wavdenoise", wavelet.wavdenoise, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.wavdenoiseh, "Wavelet", "wavdenoiseh", wavelet.wavdenoiseh, keyFile); saveToKeyfile(!pedited || pedited->wavelet.opacityCurveW, "Wavelet", "OpacityCurveW", wavelet.opacityCurveW, keyFile); saveToKeyfile(!pedited || pedited->wavelet.opacityCurveWL, "Wavelet", "OpacityCurveWL", wavelet.opacityCurveWL, keyFile); saveToKeyfile(!pedited || pedited->wavelet.hhcurve, "Wavelet", "HHcurve", wavelet.hhcurve, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.wavguidcurve, "Wavelet", "Wavguidcurve", wavelet.wavguidcurve, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.wavhuecurve, "Wavelet", "Wavhuecurve", wavelet.wavhuecurve, keyFile); saveToKeyfile(!pedited || pedited->wavelet.Chcurve, "Wavelet", "CHcurve", wavelet.Chcurve, keyFile); saveToKeyfile(!pedited || pedited->wavelet.wavclCurve, "Wavelet", "WavclCurve", wavelet.wavclCurve, keyFile); saveToKeyfile(!pedited || pedited->wavelet.median, "Wavelet", "Median", wavelet.median, keyFile); @@ -3947,9 +6651,18 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->filmNegative.redRatio, "Film Negative", "RedRatio", filmNegative.redRatio, keyFile); saveToKeyfile(!pedited || pedited->filmNegative.greenExp, "Film Negative", "GreenExponent", filmNegative.greenExp, keyFile); saveToKeyfile(!pedited || pedited->filmNegative.blueRatio, "Film Negative", "BlueRatio", filmNegative.blueRatio, keyFile); - saveToKeyfile(!pedited || pedited->filmNegative.baseValues, "Film Negative", "RedBase", filmNegative.redBase, keyFile); - saveToKeyfile(!pedited || pedited->filmNegative.baseValues, "Film Negative", "GreenBase", filmNegative.greenBase, keyFile); - saveToKeyfile(!pedited || pedited->filmNegative.baseValues, "Film Negative", "BlueBase", filmNegative.blueBase, keyFile); + + // FIXME to be removed: only for backwards compatibility with an intermediate dev version + if (filmNegative.backCompat == FilmNegativeParams::BackCompat::V2) { + saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "RedBase", filmNegative.refInput.r, keyFile); + saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "GreenBase", filmNegative.refInput.g, keyFile); + saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "BlueBase", filmNegative.refInput.b, keyFile); + } + + saveToKeyfile(!pedited || pedited->filmNegative.colorSpace, "Film Negative", "ColorSpace", toUnderlying(filmNegative.colorSpace), keyFile); + saveToKeyfile(!pedited || pedited->filmNegative.refInput, "Film Negative", "RefInput", filmNegative.refInput, keyFile); + saveToKeyfile(!pedited || pedited->filmNegative.refOutput, "Film Negative", "RefOutput", filmNegative.refOutput, keyFile); + saveToKeyfile(true, "Film Negative", "BackCompat", toUnderlying(filmNegative.backCompat), keyFile); // Preprocess WB saveToKeyfile(!pedited || pedited->raw.preprocessWB.mode, "RAW Preprocess WB", "Mode", toUnderlying(raw.preprocessWB.mode), keyFile); @@ -4176,6 +6889,16 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Retinex")) { assignFromKeyfile(keyFile, "Retinex", "Median", pedited, retinex.medianmap, pedited->retinex.medianmap); + + if (keyFile.has_key("Retinex", "complexMethod")) { + assignFromKeyfile(keyFile, "Retinex", "complexMethod", pedited, retinex.complexmethod, pedited->retinex.complexmethod); + } else if (retinex.enabled) { + retinex.complexmethod = "expert"; + if (pedited) { + pedited->retinex.complexmethod = true; + } + } + assignFromKeyfile(keyFile, "Retinex", "RetinexMethod", pedited, retinex.retinexMethod, pedited->retinex.retinexMethod); assignFromKeyfile(keyFile, "Retinex", "mapMethod", pedited, retinex.mapMethod, pedited->retinex.mapMethod); assignFromKeyfile(keyFile, "Retinex", "viewMethod", pedited, retinex.viewMethod, pedited->retinex.viewMethod); @@ -4290,14 +7013,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); @@ -4342,10 +7068,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; } @@ -4425,6 +7153,14 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Color appearance", "AutoDegreeout", pedited, colorappearance.autodegreeout, pedited->colorappearance.autodegreeout); + if (keyFile.has_key("Color appearance", "complex")) { + assignFromKeyfile(keyFile, "Color appearance", "complex", pedited, colorappearance.complexmethod, pedited->colorappearance.complexmethod); + } else if (colorappearance.enabled) { + colorappearance.complexmethod = "expert"; + if (pedited) { + pedited->colorappearance.complexmethod = true; + } + } assignFromKeyfile(keyFile, "Color appearance", "Surround", pedited, colorappearance.surround, pedited->colorappearance.surround); assignFromKeyfile(keyFile, "Color appearance", "Surrsrc", pedited, colorappearance.surrsrc, pedited->colorappearance.surrsrc); assignFromKeyfile(keyFile, "Color appearance", "AdaptLum", pedited, colorappearance.adaplum, pedited->colorappearance.adaplum); @@ -4542,7 +7278,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); @@ -4693,8 +7429,28 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } if (keyFile.has_group("Perspective")) { + assignFromKeyfile(keyFile, "Perspective", "Method", pedited, perspective.method, pedited->perspective.method); assignFromKeyfile(keyFile, "Perspective", "Horizontal", pedited, perspective.horizontal, pedited->perspective.horizontal); assignFromKeyfile(keyFile, "Perspective", "Vertical", pedited, perspective.vertical, pedited->perspective.vertical); + assignFromKeyfile(keyFile, "Perspective", "CameraShiftHorizontal", pedited, perspective.camera_shift_horiz, pedited->perspective.camera_shift_horiz); + assignFromKeyfile(keyFile, "Perspective", "CameraShiftVertical", pedited, perspective.camera_shift_vert, pedited->perspective.camera_shift_vert); + assignFromKeyfile(keyFile, "Perspective", "CameraPitch", pedited, perspective.camera_pitch, pedited->perspective.camera_pitch); + assignFromKeyfile(keyFile, "Perspective", "CameraRoll", pedited, perspective.camera_roll, pedited->perspective.camera_roll); + assignFromKeyfile(keyFile, "Perspective", "CameraCropFactor", pedited, perspective.camera_crop_factor, pedited->perspective.camera_crop_factor); + assignFromKeyfile(keyFile, "Perspective", "CameraFocalLength", pedited, perspective.camera_focal_length, pedited->perspective.camera_focal_length); + assignFromKeyfile(keyFile, "Perspective", "CameraYaw", pedited, perspective.camera_yaw, pedited->perspective.camera_yaw); + assignFromKeyfile(keyFile, "Perspective", "ProjectionPitch", pedited, perspective.projection_pitch, pedited->perspective.projection_pitch); + assignFromKeyfile(keyFile, "Perspective", "ProjectionRotate", pedited, perspective.projection_rotate, pedited->perspective.projection_rotate); + assignFromKeyfile(keyFile, "Perspective", "ProjectionShiftHorizontal", pedited, perspective.projection_shift_horiz, pedited->perspective.projection_shift_horiz); + assignFromKeyfile(keyFile, "Perspective", "ProjectionShiftVertical", pedited, perspective.projection_shift_vert, pedited->perspective.projection_shift_vert); + assignFromKeyfile(keyFile, "Perspective", "ProjectionYaw", pedited, perspective.projection_yaw, pedited->perspective.projection_yaw); + if (keyFile.has_key("Perspective", "ControlLineValues") && keyFile.has_key("Perspective", "ControlLineTypes")) { + perspective.control_line_values = keyFile.get_integer_list("Perspective", "ControlLineValues"); + perspective.control_line_types = keyFile.get_integer_list("Perspective", "ControlLineTypes"); + if (pedited) { + pedited->perspective.control_lines = true; + } + } } if (keyFile.has_group("Gradient")) { @@ -4706,6 +7462,650 @@ 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", "PrevMethod_" + index_str, pedited, spot.prevMethod, spotEdited.prevMethod); + 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", "Hishow_" + index_str, pedited, spot.hishow, spotEdited.hishow); + assignFromKeyfile(keyFile, "Locallab", "Activ_" + index_str, pedited, spot.activ, spotEdited.activ); + 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", "CHCurve_" + index_str, pedited, spot.CHcurve, spotEdited.CHcurve); + 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", "QuaMethod_" + index_str, pedited, spot.quamethod, spotEdited.quamethod); + 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", "Invbl_" + index_str, pedited, spot.invbl, spotEdited.invbl); + 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", "dehazeSaturation" + index_str, pedited, spot.dehazeSaturation, spotEdited.dehazeSaturation); + 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", "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", "Complexlog_" + index_str, pedited, spot.complexlog, spotEdited.complexlog); + + 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", "Sourceabs_" + index_str, pedited, spot.sourceabs, spotEdited.sourceabs); + assignFromKeyfile(keyFile, "Locallab", "Targabs_" + index_str, pedited, spot.targabs, spotEdited.targabs); + assignFromKeyfile(keyFile, "Locallab", "TargetGray_" + index_str, pedited, spot.targetGray, spotEdited.targetGray); + assignFromKeyfile(keyFile, "Locallab", "Catad_" + index_str, pedited, spot.catad, spotEdited.catad); + assignFromKeyfile(keyFile, "Locallab", "Saturl_" + index_str, pedited, spot.saturl, spotEdited.saturl); + assignFromKeyfile(keyFile, "Locallab", "Lightl_" + index_str, pedited, spot.lightl, spotEdited.lightl); + assignFromKeyfile(keyFile, "Locallab", "Brightq_" + index_str, pedited, spot.lightq, spotEdited.lightq); + assignFromKeyfile(keyFile, "Locallab", "Contl_" + index_str, pedited, spot.contl, spotEdited.contl); + assignFromKeyfile(keyFile, "Locallab", "Contq_" + index_str, pedited, spot.contq, spotEdited.contq); + assignFromKeyfile(keyFile, "Locallab", "Colorfl_" + index_str, pedited, spot.colorfl, spotEdited.colorfl); + assignFromKeyfile(keyFile, "Locallab", "LCurveL_" + index_str, pedited, spot.LcurveL, spotEdited.LcurveL); + 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", "Repart_" + index_str, pedited, spot.repar, spotEdited.repar); + assignFromKeyfile(keyFile, "Locallab", "Ciecam_" + index_str, pedited, spot.ciecam, spotEdited.ciecam); + 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", "Sursour_" + index_str, pedited, spot.sursour, spotEdited.sursour); + assignFromKeyfile(keyFile, "Locallab", "Surround_" + index_str, pedited, spot.surround, spotEdited.surround); + assignFromKeyfile(keyFile, "Locallab", "Strlog_" + index_str, pedited, spot.strlog, spotEdited.strlog); + assignFromKeyfile(keyFile, "Locallab", "Anglog_" + index_str, pedited, spot.anglog, spotEdited.anglog); + assignFromKeyfile(keyFile, "Locallab", "CCmaskCurveL_" + index_str, pedited, spot.CCmaskcurveL, spotEdited.CCmaskcurveL); + assignFromKeyfile(keyFile, "Locallab", "LLmaskCurveL_" + index_str, pedited, spot.LLmaskcurveL, spotEdited.LLmaskcurveL); + assignFromKeyfile(keyFile, "Locallab", "HHmaskCurveL_" + index_str, pedited, spot.HHmaskcurveL, spotEdited.HHmaskcurveL); + assignFromKeyfile(keyFile, "Locallab", "EnaLMask_" + index_str, pedited, spot.enaLMask, spotEdited.enaLMask); + assignFromKeyfile(keyFile, "Locallab", "blendmaskL_" + index_str, pedited, spot.blendmaskL, spotEdited.blendmaskL); + assignFromKeyfile(keyFile, "Locallab", "radmaskL_" + index_str, pedited, spot.radmaskL, spotEdited.radmaskL); + assignFromKeyfile(keyFile, "Locallab", "chromaskL_" + index_str, pedited, spot.chromaskL, spotEdited.chromaskL); + assignFromKeyfile(keyFile, "Locallab", "LmaskCurveL_" + index_str, pedited, spot.LmaskcurveL, spotEdited.LmaskcurveL); + + // mask + spot.visimask = assignFromKeyfile(keyFile, "Locallab", "Expmask_" + index_str, pedited, spot.expmask, spotEdited.expmask); + assignFromKeyfile(keyFile, "Locallab", "Complexmask_" + index_str, pedited, spot.complexmask, spotEdited.complexmask); + assignFromKeyfile(keyFile, "Locallab", "Sensimask_" + index_str, pedited, spot.sensimask, spotEdited.sensimask); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskmask_" + index_str, pedited, spot.blendmask, spotEdited.blendmask); + assignFromKeyfile(keyFile, "Locallab", "Blendmaskmaskab_" + index_str, pedited, spot.blendmaskab, spotEdited.blendmaskab); + assignFromKeyfile(keyFile, "Locallab", "Softradiusmask_" + index_str, pedited, spot.softradiusmask, spotEdited.softradiusmask); + assignFromKeyfile(keyFile, "Locallab", "Enamask_" + index_str, pedited, spot.enamask, spotEdited.enamask); + assignFromKeyfile(keyFile, "Locallab", "Fftmask_" + index_str, pedited, spot.fftmask, spotEdited.fftmask); + assignFromKeyfile(keyFile, "Locallab", "Blurmask_" + index_str, pedited, spot.blurmask, spotEdited.blurmask); + assignFromKeyfile(keyFile, "Locallab", "Contmask_" + index_str, pedited, spot.contmask, spotEdited.contmask); + assignFromKeyfile(keyFile, "Locallab", "CCmask_Curve_" + index_str, pedited, spot.CCmask_curve, spotEdited.CCmask_curve); + assignFromKeyfile(keyFile, "Locallab", "LLmask_Curve_" + index_str, pedited, spot.LLmask_curve, spotEdited.LLmask_curve); + assignFromKeyfile(keyFile, "Locallab", "HHmask_Curve_" + index_str, pedited, spot.HHmask_curve, spotEdited.HHmask_curve); + assignFromKeyfile(keyFile, "Locallab", "Strumaskmask_" + index_str, pedited, spot.strumaskmask, spotEdited.strumaskmask); + assignFromKeyfile(keyFile, "Locallab", "Toolmask_" + index_str, pedited, spot.toolmask, spotEdited.toolmask); + assignFromKeyfile(keyFile, "Locallab", "Radmask_" + index_str, pedited, spot.radmask, spotEdited.radmask); + assignFromKeyfile(keyFile, "Locallab", "Lapmask_" + index_str, pedited, spot.lapmask, spotEdited.lapmask); + assignFromKeyfile(keyFile, "Locallab", "Chromask_" + index_str, pedited, spot.chromask, spotEdited.chromask); + assignFromKeyfile(keyFile, "Locallab", "Gammask_" + index_str, pedited, spot.gammask, spotEdited.gammask); + assignFromKeyfile(keyFile, "Locallab", "Slopmask_" + index_str, pedited, spot.slopmask, spotEdited.slopmask); + assignFromKeyfile(keyFile, "Locallab", "Shadmask_" + index_str, pedited, spot.shadmask, spotEdited.shadmask); + assignFromKeyfile(keyFile, "Locallab", "Str_mask_" + index_str, pedited, spot.str_mask, spotEdited.str_mask); + assignFromKeyfile(keyFile, "Locallab", "Ang_mask_" + index_str, pedited, spot.ang_mask, spotEdited.ang_mask); + assignFromKeyfile(keyFile, "Locallab", "HHhmask_Curve_" + index_str, pedited, spot.HHhmask_curve, spotEdited.HHhmask_curve); + assignFromKeyfile(keyFile, "Locallab", "Lmask_Curve_" + index_str, pedited, spot.Lmask_curve, spotEdited.Lmask_curve); + assignFromKeyfile(keyFile, "Locallab", "LLmask_Curvewav_" + index_str, pedited, spot.LLmask_curvewav, spotEdited.LLmask_curvewav); + + if (keyFile.has_key("Locallab", "CSThresholdmask_" + index_str)) { + const std::vector thresh = keyFile.get_integer_list("Locallab", "CSThresholdmask_" + index_str); + + if (thresh.size() >= 4) { + spot.csthresholdmask.setValues(thresh[0], thresh[1], min(thresh[2], 10), min(thresh[3], 10)); + } + + spotEdited.csthresholdmask = true; + } + + if (spot.visimask) { + spotEdited.visimask = true; + } + + // 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); @@ -4901,6 +8301,10 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "CBbluemed", pedited, wavelet.bluemed, pedited->wavelet.bluemed); assignFromKeyfile(keyFile, "Wavelet", "CBbluelow", pedited, wavelet.bluelow, pedited->wavelet.bluelow); assignFromKeyfile(keyFile, "Wavelet", "Ballum", pedited, wavelet.ballum, pedited->wavelet.ballum); + assignFromKeyfile(keyFile, "Wavelet", "Sigm", pedited, wavelet.sigm, pedited->wavelet.sigm); + assignFromKeyfile(keyFile, "Wavelet", "Levden", pedited, wavelet.levden, pedited->wavelet.levden); + assignFromKeyfile(keyFile, "Wavelet", "Thrden", pedited, wavelet.thrden, pedited->wavelet.thrden); + assignFromKeyfile(keyFile, "Wavelet", "Limden", pedited, wavelet.limden, pedited->wavelet.limden); assignFromKeyfile(keyFile, "Wavelet", "Balchrom", pedited, wavelet.balchrom, pedited->wavelet.balchrom); assignFromKeyfile(keyFile, "Wavelet", "Chromfine", pedited, wavelet.chromfi, pedited->wavelet.chromfi); assignFromKeyfile(keyFile, "Wavelet", "Chromcoarse", pedited, wavelet.chromco, pedited->wavelet.chromco); @@ -4908,6 +8312,9 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "MergeC", pedited, wavelet.mergeC, pedited->wavelet.mergeC); assignFromKeyfile(keyFile, "Wavelet", "Softrad", pedited, wavelet.softrad, pedited->wavelet.softrad); assignFromKeyfile(keyFile, "Wavelet", "Softradend", pedited, wavelet.softradend, pedited->wavelet.softradend); + assignFromKeyfile(keyFile, "Wavelet", "Strend", pedited, wavelet.strend, pedited->wavelet.strend); + assignFromKeyfile(keyFile, "Wavelet", "Detend", pedited, wavelet.detend, pedited->wavelet.detend); + assignFromKeyfile(keyFile, "Wavelet", "Thrend", pedited, wavelet.thrend, pedited->wavelet.thrend); assignFromKeyfile(keyFile, "Wavelet", "Lipst", pedited, wavelet.lipst, pedited->wavelet.lipst); assignFromKeyfile(keyFile, "Wavelet", "AvoidColorShift", pedited, wavelet.avoid, pedited->wavelet.avoid); assignFromKeyfile(keyFile, "Wavelet", "Showmask", pedited, wavelet.showmask, pedited->wavelet.showmask); @@ -4933,6 +8340,20 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "ChoiceLevMethod", pedited, wavelet.CLmethod, pedited->wavelet.CLmethod); assignFromKeyfile(keyFile, "Wavelet", "BackMethod", pedited, wavelet.Backmethod, pedited->wavelet.Backmethod); assignFromKeyfile(keyFile, "Wavelet", "TilesMethod", pedited, wavelet.Tilesmethod, pedited->wavelet.Tilesmethod); + + if (keyFile.has_key("Wavelet", "complexMethod")) { + assignFromKeyfile(keyFile, "Wavelet", "complexMethod", pedited, wavelet.complexmethod, pedited->wavelet.complexmethod); + } else if (wavelet.enabled) { + wavelet.complexmethod = "expert"; + if (pedited) { + pedited->wavelet.complexmethod = true; + } + } + + assignFromKeyfile(keyFile, "Wavelet", "denMethod", pedited, wavelet.denmethod, pedited->wavelet.denmethod); + assignFromKeyfile(keyFile, "Wavelet", "mixMethod", pedited, wavelet.mixmethod, pedited->wavelet.mixmethod); + assignFromKeyfile(keyFile, "Wavelet", "sliMethod", pedited, wavelet.slimethod, pedited->wavelet.slimethod); + assignFromKeyfile(keyFile, "Wavelet", "quaMethod", pedited, wavelet.quamethod, pedited->wavelet.quamethod); assignFromKeyfile(keyFile, "Wavelet", "DaubMethod", pedited, wavelet.daubcoeffmethod, pedited->wavelet.daubcoeffmethod); assignFromKeyfile(keyFile, "Wavelet", "CHromaMethod", pedited, wavelet.CHmethod, pedited->wavelet.CHmethod); assignFromKeyfile(keyFile, "Wavelet", "Medgreinf", pedited, wavelet.Medgreinf, pedited->wavelet.Medgreinf); @@ -4979,11 +8400,15 @@ 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", "Levelshc", pedited, wavelet.opacityCurveSH, pedited->wavelet.opacityCurveSH); + assignFromKeyfile(keyFile, "Wavelet", "Levalshc", pedited, wavelet.opacityCurveSH, pedited->wavelet.opacityCurveSH); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveBY", pedited, wavelet.opacityCurveBY, pedited->wavelet.opacityCurveBY); + assignFromKeyfile(keyFile, "Wavelet", "wavdenoise", pedited, wavelet.wavdenoise, pedited->wavelet.wavdenoise); + assignFromKeyfile(keyFile, "Wavelet", "wavdenoiseh", pedited, wavelet.wavdenoiseh, pedited->wavelet.wavdenoiseh); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveW", pedited, wavelet.opacityCurveW, pedited->wavelet.opacityCurveW); assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveWL", pedited, wavelet.opacityCurveWL, pedited->wavelet.opacityCurveWL); assignFromKeyfile(keyFile, "Wavelet", "HHcurve", pedited, wavelet.hhcurve, pedited->wavelet.hhcurve); + assignFromKeyfile(keyFile, "Wavelet", "Wavguidcurve", pedited, wavelet.wavguidcurve, pedited->wavelet.wavguidcurve); + assignFromKeyfile(keyFile, "Wavelet", "Wavhuecurve", pedited, wavelet.wavhuecurve, pedited->wavelet.wavhuecurve); assignFromKeyfile(keyFile, "Wavelet", "CHcurve", pedited, wavelet.Chcurve, pedited->wavelet.Chcurve); assignFromKeyfile(keyFile, "Wavelet", "WavclCurve", pedited, wavelet.wavclCurve, pedited->wavelet.wavclCurve); @@ -5095,6 +8520,30 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } + if (keyFile.has_key("Wavelet", "Leveldenoise")) { + const std::vector thresh = keyFile.get_double_list("Wavelet", "Leveldenoise"); + + if (thresh.size() >= 2) { + wavelet.leveldenoise.setValues(thresh[0], thresh[1]); + } + + if (pedited) { + pedited->wavelet.leveldenoise = true; + } + } + + if (keyFile.has_key("Wavelet", "Levelsigm")) { + const std::vector thresh = keyFile.get_double_list("Wavelet", "Levelsigm"); + + if (thresh.size() >= 2) { + wavelet.levelsigm.setValues(thresh[0], thresh[1]); + } + + if (pedited) { + pedited->wavelet.levelsigm = true; + } + } + if (keyFile.has_key("Wavelet", "Pastlev")) { const std::vector thresh = keyFile.get_integer_list("Wavelet", "Pastlev"); @@ -5230,7 +8679,15 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Dehaze", "Strength", pedited, dehaze.strength, pedited->dehaze.strength); assignFromKeyfile(keyFile, "Dehaze", "ShowDepthMap", pedited, dehaze.showDepthMap, pedited->dehaze.showDepthMap); assignFromKeyfile(keyFile, "Dehaze", "Depth", pedited, dehaze.depth, pedited->dehaze.depth); - assignFromKeyfile(keyFile, "Dehaze", "Luminance", pedited, dehaze.luminance, pedited->dehaze.luminance); + if (ppVersion < 349 && dehaze.enabled && keyFile.has_key("Dehaze", "Luminance")) { + const bool luminance = keyFile.get_boolean("Dehaze", "Luminance"); + dehaze.saturation = luminance ? 0 : 100; + if (pedited) { + pedited->dehaze.saturation = true; + } + } else { + assignFromKeyfile(keyFile, "Dehaze", "Saturation", pedited, dehaze.saturation, pedited->dehaze.saturation); + } } if (keyFile.has_group("Film Simulation")) { @@ -5533,9 +8990,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); @@ -5550,12 +9009,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; } @@ -5589,23 +9050,48 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Film Negative", "RedRatio", pedited, filmNegative.redRatio, pedited->filmNegative.redRatio); assignFromKeyfile(keyFile, "Film Negative", "GreenExponent", pedited, filmNegative.greenExp, pedited->filmNegative.greenExp); assignFromKeyfile(keyFile, "Film Negative", "BlueRatio", pedited, filmNegative.blueRatio, pedited->filmNegative.blueRatio); - if (ppVersion >= 347) { + + if (ppVersion < 347) { + // Backwards compatibility with RT v5.8 + filmNegative.colorSpace = FilmNegativeParams::ColorSpace::INPUT; + filmNegative.backCompat = FilmNegativeParams::BackCompat::V1; + if (pedited) { + pedited->filmNegative.refInput = true; + pedited->filmNegative.refOutput = true; + pedited->filmNegative.colorSpace = true; + } + + } else if (!keyFile.has_key("Film Negative", "RefInput")) { + // Backwards compatibility with intermediate dev version (after v5.8) using film base values bool r, g, b; - assignFromKeyfile(keyFile, "Film Negative", "RedBase", pedited, filmNegative.redBase, r); - assignFromKeyfile(keyFile, "Film Negative", "GreenBase", pedited, filmNegative.greenBase, g); - assignFromKeyfile(keyFile, "Film Negative", "BlueBase", pedited, filmNegative.blueBase, b); + assignFromKeyfile(keyFile, "Film Negative", "RedBase", pedited, filmNegative.refInput.r, r); + assignFromKeyfile(keyFile, "Film Negative", "GreenBase", pedited, filmNegative.refInput.g, g); + assignFromKeyfile(keyFile, "Film Negative", "BlueBase", pedited, filmNegative.refInput.b, b); if (pedited) { - pedited->filmNegative.baseValues = r || g || b; + pedited->filmNegative.refInput = r || g || b; + pedited->filmNegative.refOutput = r || g || b; + pedited->filmNegative.colorSpace = true; } - } else { - // Backwards compatibility with film negative in RT 5.7: use special film base value -1, - // to signal that the old channel scaling method should be used. - filmNegative.redBase = -1.f; - filmNegative.greenBase = -1.f; - filmNegative.blueBase = -1.f; - if (pedited) { - pedited->filmNegative.baseValues = true; + + filmNegative.colorSpace = FilmNegativeParams::ColorSpace::INPUT; + // Special value -1 used to mean that this should be treated as a v5.8 profile + filmNegative.backCompat = (filmNegative.refInput.r == -1.f) + ? FilmNegativeParams::BackCompat::V1 + : FilmNegativeParams::BackCompat::V2; + + } else { // current version + + assignFromKeyfile(keyFile, "Film Negative", "RefInput", pedited, filmNegative.refInput, pedited->filmNegative.refInput); + assignFromKeyfile(keyFile, "Film Negative", "RefOutput", pedited, filmNegative.refOutput, pedited->filmNegative.refOutput); + + int cs = toUnderlying(filmNegative.colorSpace); + assignFromKeyfile(keyFile, "Film Negative", "ColorSpace", pedited, cs, pedited->filmNegative.colorSpace); + filmNegative.colorSpace = static_cast(cs); + + if (keyFile.has_key("Film Negative", "BackCompat")) { + filmNegative.backCompat = FilmNegativeParams::BackCompat(keyFile.get_integer("Film Negative", "BackCompat")); } + } } @@ -5723,6 +9209,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 71d5989b8..f1369ee6e 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -47,6 +47,17 @@ class WavOpacityCurveSH; class WavOpacityCurveRG; class WavOpacityCurveW; class WavOpacityCurveWL; +class LocretigainCurve; +class LocretigainCurverab; +class LocLHCurve; +class LocHHCurve; +class LocCHCurve; +class LocLLmaskCurve; +class LocCCmaskCurve; +class LocHHmaskCurve; +class LocLLmaskexpCurve; +class LocCCmaskexpCurve; +class LocHHmaskexpCurve; enum RenderingIntent : int { RI_PERCEPTUAL = INTENT_PERCEPTUAL, @@ -105,6 +116,12 @@ public: } } + template + typename std::enable_if::value, bool>::type operator !=(const Threshold& rhs) const + { + return !(*this == rhs); + } + T getBottom() const { return bottom_left; @@ -320,6 +337,7 @@ struct RetinexParams { int stonalwidth; int radius; + Glib::ustring complexmethod; Glib::ustring retinexMethod; Glib::ustring retinexcolorspace; Glib::ustring gammaretinex; @@ -404,7 +422,6 @@ struct RGBCurvesParams { /** * Parameters of the Color Toning */ - struct ColorToningParams { bool enabled; bool autosat; @@ -492,6 +509,7 @@ struct ColorToningParams { void getCurves(ColorGradientCurve& colorCurveLUT, OpacityCurve& opacityCurveLUT, const double xyz_rgb[3][3], bool& opautili) const; }; + /** * Parameters of the sharpening */ @@ -531,8 +549,10 @@ struct SharpenEdgeParams { bool operator ==(const SharpenEdgeParams& other) const; bool operator !=(const SharpenEdgeParams& other) const; + }; + struct SharpenMicroParams { bool enabled; bool matrix; @@ -653,6 +673,7 @@ struct ColorAppearanceParams { TcMode curveMode; TcMode curveMode2; CtcMode curveMode3; + Glib::ustring complexmethod; Glib::ustring surround; Glib::ustring surrsrc; @@ -912,8 +933,26 @@ struct LensProfParams { * Parameters of the perspective correction */ struct PerspectiveParams { + Glib::ustring method; + bool render; double horizontal; double vertical; + double camera_crop_factor; + double camera_focal_length; + double camera_pitch; + double camera_roll; + double camera_shift_horiz; + double camera_shift_vert; + double camera_yaw; + double projection_pitch; + double projection_rotate; + double projection_shift_horiz; + double projection_shift_vert; + double projection_yaw; + /** A line is stored as 4 integers in this order: x1, y1, x2, y2 */ + std::vector control_line_values; + /** 0 is vertical, 1 is horizontal, undefined otherwise. */ + std::vector control_line_types; PerspectiveParams(); @@ -938,6 +977,538 @@ 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 prevMethod; // show, hide + 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 hishow; + bool activ; + 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; + std::vector CHcurve; + 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 quamethod; // cons agre + 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 invbl; + 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; + double dehazeSaturation; + 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 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; + int complexlog; + bool autocompute; + double sourceGray; + double sourceabs; + double targabs; + double targetGray; + double catad; + double saturl; + double lightl; + double lightq; + double contl; + double contq; + double colorfl; + std::vector LcurveL; + bool Autogray; + bool fullimage; + double repar; + bool ciecam; + double blackEv; + double whiteEv; + double detail; + int sensilog; + Glib::ustring sursour; + Glib::ustring surround; + double baselog; + double strlog; + double anglog; + std::vector CCmaskcurveL; + std::vector LLmaskcurveL; + std::vector HHmaskcurveL; + bool enaLMask; + double blendmaskL; + double radmaskL; + double chromaskL; + std::vector LmaskcurveL; + + // mask + bool visimask; + int complexmask; + bool expmask; + int sensimask; + double blendmask; + double blendmaskab; + double softradiusmask; + bool enamask; + bool fftmask; + double blurmask; + double contmask; + std::vector CCmask_curve; + std::vector LLmask_curve; + std::vector HHmask_curve; + double strumaskmask; + bool toolmask; + double radmask; + double lapmask; + double chromask; + double gammask; + double slopmask; + double shadmask; + int str_mask; + int ang_mask; + std::vector HHhmask_curve; + std::vector Lmask_curve; + std::vector LLmask_curvewav; + Threshold csthresholdmask; + + 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 */ @@ -1223,6 +1794,8 @@ private: struct WaveletParams { std::vector ccwcurve; + std::vector wavdenoise; + std::vector wavdenoiseh; std::vector blcurve; std::vector levelshc; std::vector opacityCurveRG; @@ -1231,6 +1804,8 @@ struct WaveletParams { std::vector opacityCurveW; std::vector opacityCurveWL; std::vector hhcurve; + std::vector wavguidcurve; + std::vector wavhuecurve; std::vector Chcurve; std::vector wavclCurve; bool enabled; @@ -1245,6 +1820,10 @@ struct WaveletParams { int greenhigh; int bluehigh; double ballum; + double sigm; + double levden; + double thrden; + double limden; double balchrom; double chromfi; double chromco; @@ -1252,6 +1831,9 @@ struct WaveletParams { double mergeC; double softrad; double softradend; + double strend; + int detend; + double thrend; bool lipst; bool avoid; @@ -1289,6 +1871,11 @@ struct WaveletParams { Glib::ustring CLmethod; Glib::ustring Backmethod; Glib::ustring Tilesmethod; + Glib::ustring complexmethod; + Glib::ustring denmethod; + Glib::ustring mixmethod; + Glib::ustring slimethod; + Glib::ustring quamethod; Glib::ustring daubcoeffmethod; Glib::ustring CHmethod; Glib::ustring Medgreinf; @@ -1346,6 +1933,8 @@ struct WaveletParams { Threshold level1noise; Threshold level2noise; Threshold level3noise; + Threshold leveldenoise; + Threshold levelsigm; WaveletParams(); @@ -1354,6 +1943,8 @@ struct WaveletParams { void getCurves( WavCurve& cCurve, + WavCurve& wavdenoise, + WavCurve& wavdenoiseh, Wavblcurve& tCurve, WavOpacityCurveRG& opacityCurveLUTRG, WavOpacityCurveSH& opacityCurveLUTSH, @@ -1424,9 +2015,9 @@ struct SoftLightParams { struct DehazeParams { bool enabled; int strength; + int saturation; bool showDepthMap; int depth; - bool luminance; DehazeParams(); @@ -1444,10 +2035,13 @@ struct RAWParams { struct BayerSensor { enum class Method { AMAZE, + AMAZEBILINEAR, AMAZEVNG4, RCD, + RCDBILINEAR, RCDVNG4, DCB, + DCBBILINEAR, DCBVNG4, LMMSE, IGV, @@ -1626,10 +2220,28 @@ struct FilmNegativeParams { double greenExp; double blueRatio; - double redBase; - double greenBase; - double blueBase; - + struct RGB { + float r, g, b; + + bool operator ==(const RGB& other) const; + bool operator !=(const RGB& other) const; + RGB operator *(const RGB& other) const; + }; + + RGB refInput; + RGB refOutput; + + enum class ColorSpace { + INPUT = 0, + WORKING + // TODO : add support for custom color profile + }; + + ColorSpace colorSpace; + + enum class BackCompat { CURRENT = 0, V1, V2 }; + BackCompat backCompat; + FilmNegativeParams(); bool operator ==(const FilmNegativeParams& other) const; @@ -1671,6 +2283,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..2354f343a 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]; } @@ -1021,8 +1046,10 @@ DCraw::dcraw_coeff_overrides(const char make[], const char model[], const int is } } - char name[strlen(make) + strlen(model) + 32]; - sprintf(name, "%s %s", make, model); + const std::size_t name_size = strlen(make) + strlen(model) + 32; + + char name[name_size]; + snprintf(name, name_size, "%s %s", make, model); for (size_t i = 0; i < sizeof table / sizeof(table[0]); i++) { if (strcasecmp(name, table[i].prefix) == 0) { 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 f94070f2d..689dddf20 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -636,6 +636,56 @@ float calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const flo return gain; } + +void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, std::array& out_scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const +{ + // compute channel multipliers + double r, g, b; + //float rm, gm, bm; + + if (ctemp.getTemp() < 0) { + // no white balance, ie revert the pre-process white balance to restore original unbalanced raw camera color + rm = ri->get_pre_mul(0); + gm = ri->get_pre_mul(1); + bm = ri->get_pre_mul(2); + } else { + ctemp.getMultipliers (r, g, b); + rm = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b; + gm = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b; + bm = imatrices.cam_rgb[2][0] * r + imatrices.cam_rgb[2][1] * g + imatrices.cam_rgb[2][2] * b; + } + + // adjust gain so the maximum raw value of the least scaled channel just hits max + const float new_pre_mul[4] = { ri->get_pre_mul(0) / rm, ri->get_pre_mul(1) / gm, ri->get_pre_mul(2) / bm, ri->get_pre_mul(3) / gm }; + float new_scale_mul[4]; + + bool isMono = (ri->getSensorType() == ST_FUJI_XTRANS && raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO)) + || (ri->getSensorType() == ST_BAYER && raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)); + + float c_white[4]; + for (int i = 0; i < 4; ++i) { + c_white[i] = (ri->get_white(i) - cblacksom[i]) / static_cast(raw.expos) + cblacksom[i]; + } + + float gain = calculate_scale_mul(new_scale_mul, new_pre_mul, c_white, cblacksom, isMono, ri->get_colors()); + rm = new_scale_mul[0] / scale_mul[0] * gain; + gm = new_scale_mul[1] / scale_mul[1] * gain; + bm = new_scale_mul[2] / scale_mul[2] * gain; + //fprintf(stderr, "camera gain: %f, current wb gain: %f, diff in stops %f\n", camInitialGain, gain, log2(camInitialGain) - log2(gain)); + + const float expcomp = std::pow(2, ri->getBaselineExposure()); + rm *= expcomp; + gm *= expcomp; + bm *= expcomp; + + out_scale_mul[0] = scale_mul[0]; + out_scale_mul[1] = scale_mul[1]; + out_scale_mul[2] = scale_mul[2]; + out_scale_mul[3] = scale_mul[3]; + + autoGainComp = camInitialGain / initialGain; +} + void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) { MyMutex::MyLock lock(getImageMutex); @@ -1235,7 +1285,8 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le { // 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) - ri->get_colorsCoeff( ref_pre_mul, scale_mul, c_black, raw.preprocessWB.mode == RAWParams::PreprocessWB::Mode::AUTO); + 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]; @@ -1577,8 +1628,11 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c ahd_demosaic (); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZE)) { amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); - } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) + } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEBILINEAR) + || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) + || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBBILINEAR) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) + || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDBILINEAR) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4)) { if (!autoContrast) { double threshold = raw.bayersensor.dualDemosaicContrast; @@ -1716,10 +1770,8 @@ void RawImageSource::retinexPrepareBuffers(const ColorManagementParams& cmp, con std::swap(pwr, gamm); } - int mode = 0; - Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope + Color::calcGamma(pwr, ts, g_a); // call to calcGamma with selected gamma and slope - // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); double start; double add; @@ -1947,12 +1999,12 @@ void RawImageSource::retinexPrepareCurves(const RetinexParams &retinexParams, LU useHsl = (retinexParams.retinexcolorspace == "HSLLOG" || retinexParams.retinexcolorspace == "HSLLIN"); if (useHsl) { - CurveFactory::curveDehaContL (retinexcontlutili, retinexParams.cdHcurve, cdcurve, 1, lhist16RETI, histLRETI); + retinexcontlutili = CurveFactory::diagonalCurve2Lut(retinexParams.cdHcurve, cdcurve, 1, lhist16RETI, histLRETI); } else { - CurveFactory::curveDehaContL (retinexcontlutili, retinexParams.cdcurve, cdcurve, 1, lhist16RETI, histLRETI); + retinexcontlutili = CurveFactory::diagonalCurve2Lut(retinexParams.cdcurve, cdcurve, 1, lhist16RETI, histLRETI); } - CurveFactory::mapcurve(mapcontlutili, retinexParams.mapcurve, mapcurve, 1, lhist16RETI, histLRETI); + mapcontlutili = CurveFactory::diagonalCurve2Lut(retinexParams.mapcurve, mapcurve, 1, lhist16RETI, histLRETI); mapcurve *= 0.5f; retinexParams.getCurves(retinextransmissionCurve, retinexgaintransmissionCurve); } @@ -1983,13 +2035,12 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara double gamm = deh.gam; double gamm2 = gamm; double ts = deh.slope; - int mode = 0; if (gamm2 < 1.) { std::swap(pwr, gamm); } - Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope + Color::calcGamma(pwr, ts, g_a); // call to calcGamma with selected gamma and slope double mul = 1. + g_a[4]; double add; @@ -2257,15 +2308,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 @@ -2406,10 +2450,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) { @@ -4429,17 +4474,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 @@ -4996,7 +5041,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 @@ -5027,7 +5072,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, @@ -5041,7 +5086,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) { @@ -5209,8 +5254,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..b463ea788 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; @@ -124,9 +124,6 @@ public: int load(const Glib::ustring &fname) override { return load(fname, false); } int load(const Glib::ustring &fname, bool firstFrameOnly); void preprocess (const procparams::RAWParams &raw, const procparams::LensProfParams &lensProf, const procparams::CoarseTransformParams& coarse, bool prepareDenoise = true) override; - void filmNegativeProcess (const procparams::FilmNegativeParams ¶ms, std::array& filmBaseValues) override; - bool getFilmNegativeExponents (Coord2D spotA, Coord2D spotB, int tran, const procparams::FilmNegativeParams ¤tParams, std::array& newExps) override; - bool getRawSpotValues(Coord2D spot, int spotSize, int tran, const procparams::FilmNegativeParams ¶ms, std::array& rawValues) override; void demosaic (const procparams::RAWParams &raw, bool autoContrast, double &contrastThreshold, bool cache = false) override; void retinex (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &deh, const procparams::ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) override; void retinexPrepareCurves (const procparams::RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) override; @@ -147,6 +144,7 @@ public: void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override; void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) override; + void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override; void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override; eSensorType getSensorType () const override; bool isMono () const override; @@ -190,11 +188,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 +230,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); @@ -247,7 +245,7 @@ protected: double cared, double cablue, bool avoidColourshift, - const array2D &rawData, + array2D &rawData, double* fitParamsTransfer, bool fitParamsIn, bool fitParamsOut, @@ -265,7 +263,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 +280,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,11 +293,13 @@ 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); + void fast_xtrans_interpolate_blend (const float* const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void pixelshift(int winx, int winy, int winw, int winh, const procparams::RAWParams &rawParams, unsigned int frame, const std::string &make, const std::string &model, float rawWpCorrection); + void bayer_bilinear_demosaic(const float *const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void hflip (Imagefloat* im); void vflip (Imagefloat* im); void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override; diff --git a/rtengine/rcd_demosaic.cc b/rtengine/rcd_demosaic.cc index 5a86aec40..ff477281b 100644 --- a/rtengine/rcd_demosaic.cc +++ b/rtengine/rcd_demosaic.cc @@ -1,7 +1,7 @@ /* * This file is part of RawTherapee. * - * Copyright (c) 2017-2018 Luis Sanz Rodriguez (luis.sanz.rodriguez(at)gmail(dot)com) and Ingo Weyrich (heckflosse67@gmx.de) + * Copyright (c) 2017-2020 Luis Sanz Rodriguez (luis.sanz.rodriguez(at)gmail(dot)com) and Ingo Weyrich (heckflosse67@gmx.de) * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,6 +48,18 @@ namespace rtengine // Tiled version by Ingo Weyrich (heckflosse67@gmx.de) void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) { + // Test for RGB cfa + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + if (FC(i, j) == 3) { + // avoid crash + std::cout << "rcd_demosaic supports only RGB Colour filter arrays. Falling back to igv_interpolate" << std::endl; + igv_interpolate(W, H); + return; + } + } + } + std::unique_ptr stop; if (measure) { @@ -70,8 +82,8 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) const int numTw = W / (tileSizeN) + ((W % (tileSizeN)) ? 1 : 0); constexpr int w1 = tileSize, w2 = 2 * tileSize, w3 = 3 * tileSize, w4 = 4 * tileSize; //Tolerance to avoid dividing by zero - static constexpr float eps = 1e-5f; - static constexpr float epssq = 1e-10f; + constexpr float eps = 1e-5f; + constexpr float epssq = 1e-10f; #ifdef _OPENMP #pragma omp parallel @@ -87,16 +99,16 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) #ifdef _OPENMP #pragma omp for schedule(dynamic, chunkSize) collapse(2) nowait #endif - for(int tr = 0; tr < numTh; ++tr) { - for(int tc = 0; tc < numTw; ++tc) { + for (int tr = 0; tr < numTh; ++tr) { + for (int tc = 0; tc < numTw; ++tc) { const int rowStart = tr * tileSizeN; const int rowEnd = std::min(rowStart + tileSize, H); - if(rowStart + rcdBorder == rowEnd - rcdBorder) { + if (rowStart + rcdBorder == rowEnd - rcdBorder) { continue; } const int colStart = tc * tileSizeN; const int colEnd = std::min(colStart + tileSize, W); - if(colStart + rcdBorder == colEnd - rcdBorder) { + if (colStart + rcdBorder == colEnd - rcdBorder) { continue; } @@ -113,7 +125,7 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) cfa[indx] = rgb[c0][indx] = LIM01(rawData[row][col] / 65535.f); cfa[indx + 1] = rgb[c1][indx + 1] = LIM01(rawData[row][col + 1] / 65535.f); } - if(col < colEnd) { + if (col < colEnd) { cfa[indx] = rgb[c0][indx] = LIM01(rawData[row][col] / 65535.f); } } @@ -148,36 +160,74 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) * STEP 3: Populate the green channel */ // Step 3.1: Populate the green channel at blue and red CFA positions - for (int row = 4; row < tileRows - 4; row++) { - for (int col = 4 + (fc(cfarray, row, 0) & 1), indx = row * tileSize + col; col < tilecols - 4; col += 2, indx += 2) { - - // Refined vertical and horizontal local discrimination - float VH_Central_Value = VH_Dir[indx]; - float VH_Neighbourhood_Value = 0.25f * ((VH_Dir[indx - w1 - 1] + VH_Dir[indx - w1 + 1]) + (VH_Dir[indx + w1 - 1] + VH_Dir[indx + w1 + 1])); - - float VH_Disc = std::fabs(0.5f - VH_Central_Value) < std::fabs(0.5f - VH_Neighbourhood_Value) ? VH_Neighbourhood_Value : VH_Central_Value; - - // Cardinal gradients - float N_Grad = eps + std::fabs(cfa[indx - w1] - cfa[indx + w1]) + std::fabs(cfa[indx] - cfa[indx - w2]) + std::fabs(cfa[indx - w1] - cfa[indx - w3]) + std::fabs(cfa[indx - w2] - cfa[indx - w4]); - float S_Grad = eps + std::fabs(cfa[indx - w1] - cfa[indx + w1]) + std::fabs(cfa[indx] - cfa[indx + w2]) + std::fabs(cfa[indx + w1] - cfa[indx + w3]) + std::fabs(cfa[indx + w2] - cfa[indx + w4]); - float W_Grad = eps + std::fabs(cfa[indx - 1] - cfa[indx + 1]) + std::fabs(cfa[indx] - cfa[indx - 2]) + std::fabs(cfa[indx - 1] - cfa[indx - 3]) + std::fabs(cfa[indx - 2] - cfa[indx - 4]); - float E_Grad = eps + std::fabs(cfa[indx - 1] - cfa[indx + 1]) + std::fabs(cfa[indx] - cfa[indx + 2]) + std::fabs(cfa[indx + 1] - cfa[indx + 3]) + std::fabs(cfa[indx + 2] - cfa[indx + 4]); + for (int row = 4; row < tileRows - 4; row++) { + int col = 4 + (fc(cfarray, row, 0) & 1); + int indx = row * tileSize + col; +#ifdef __SSE2__ + const vfloat zd5v = F2V(0.5f); + const vfloat zd25v = F2V(0.25f); + const vfloat epsv = F2V(eps); + for (; col < tilecols - 7; col += 8, indx += 8) { + // Cardinal gradients + const vfloat cfai = LC2VFU(cfa[indx]); + const vfloat N_Grad = epsv + (vabsf(LC2VFU(cfa[indx - w1]) - LC2VFU(cfa[indx + w1])) + vabsf(cfai - LC2VFU(cfa[indx - w2]))) + (vabsf(LC2VFU(cfa[indx - w1]) - LC2VFU(cfa[indx - w3])) + vabsf(LC2VFU(cfa[indx - w2]) - LC2VFU(cfa[indx - w4]))); + const vfloat S_Grad = epsv + (vabsf(LC2VFU(cfa[indx - w1]) - LC2VFU(cfa[indx + w1])) + vabsf(cfai - LC2VFU(cfa[indx + w2]))) + (vabsf(LC2VFU(cfa[indx + w1]) - LC2VFU(cfa[indx + w3])) + vabsf(LC2VFU(cfa[indx + w2]) - LC2VFU(cfa[indx + w4]))); + const vfloat W_Grad = epsv + (vabsf(LC2VFU(cfa[indx - 1]) - LC2VFU(cfa[indx + 1])) + vabsf(cfai - LC2VFU(cfa[indx - 2]))) + (vabsf(LC2VFU(cfa[indx - 1]) - LC2VFU(cfa[indx - 3])) + vabsf(LC2VFU(cfa[indx - 2]) - LC2VFU(cfa[indx - 4]))); + const vfloat E_Grad = epsv + (vabsf(LC2VFU(cfa[indx - 1]) - LC2VFU(cfa[indx + 1])) + vabsf(cfai - LC2VFU(cfa[indx + 2]))) + (vabsf(LC2VFU(cfa[indx + 1]) - LC2VFU(cfa[indx + 3])) + vabsf(LC2VFU(cfa[indx + 2]) - LC2VFU(cfa[indx + 4]))); // Cardinal pixel estimations - float N_Est = cfa[indx - w1] * (1.f + (lpf[indx>>1] - lpf[(indx - w2)>>1]) / (eps + lpf[indx>>1] + lpf[(indx - w2)>>1])); - float S_Est = cfa[indx + w1] * (1.f + (lpf[indx>>1] - lpf[(indx + w2)>>1]) / (eps + lpf[indx>>1] + lpf[(indx + w2)>>1])); - float W_Est = cfa[indx - 1] * (1.f + (lpf[indx>>1] - lpf[(indx - 2)>>1]) / (eps + lpf[indx>>1] + lpf[(indx - 2)>>1])); - float E_Est = cfa[indx + 1] * (1.f + (lpf[indx>>1] - lpf[(indx + 2)>>1]) / (eps + lpf[indx>>1] + lpf[(indx + 2)>>1])); + const vfloat lpfi = LVFU(lpf[indx>>1]); + const vfloat N_Est = LC2VFU(cfa[indx - w1]) + (LC2VFU(cfa[indx - w1]) * (lpfi - LVFU(lpf[(indx - w2)>>1])) / (epsv + lpfi + LVFU(lpf[(indx - w2)>>1]))); + const vfloat S_Est = LC2VFU(cfa[indx + w1]) + (LC2VFU(cfa[indx + w1]) * (lpfi - LVFU(lpf[(indx + w2)>>1])) / (epsv + lpfi + LVFU(lpf[(indx + w2)>>1]))); + const vfloat W_Est = LC2VFU(cfa[indx - 1]) + (LC2VFU(cfa[indx - 1]) * (lpfi - LVFU(lpf[(indx - 2)>>1])) / (epsv + lpfi + LVFU(lpf[(indx - 2)>>1]))); + const vfloat E_Est = LC2VFU(cfa[indx + 1]) + (LC2VFU(cfa[indx + 1]) * (lpfi - LVFU(lpf[(indx + 2)>>1])) / (epsv + lpfi + LVFU(lpf[(indx + 2)>>1]))); // Vertical and horizontal estimations - float V_Est = (S_Grad * N_Est + N_Grad * S_Est) / (N_Grad + S_Grad); - float H_Est = (W_Grad * E_Est + E_Grad * W_Est) / (E_Grad + W_Grad); + const vfloat V_Est = (S_Grad * N_Est + N_Grad * S_Est) / (N_Grad + S_Grad); + const vfloat H_Est = (W_Grad * E_Est + E_Grad * W_Est) / (E_Grad + W_Grad); // G@B and G@R interpolation - rgb[1][indx] = VH_Disc * H_Est + (1.f - VH_Disc) * V_Est; + // Refined vertical and horizontal local discrimination + const vfloat VH_Central_Value = LC2VFU(VH_Dir[indx]); + const vfloat VH_Neighbourhood_Value = zd25v * ((LC2VFU(VH_Dir[indx - w1 - 1]) + LC2VFU(VH_Dir[indx - w1 + 1])) + (LC2VFU(VH_Dir[indx + w1 - 1]) + LC2VFU(VH_Dir[indx + w1 + 1]))); +#if defined(__clang__) + const vfloat VH_Disc = vself(vmaskf_lt(vabsf(zd5v - VH_Central_Value), vabsf(zd5v - VH_Neighbourhood_Value)), VH_Neighbourhood_Value, VH_Central_Value); +#else + const vfloat VH_Disc = vabsf(zd5v - VH_Central_Value) < vabsf(zd5v - VH_Neighbourhood_Value) ? VH_Neighbourhood_Value : VH_Central_Value; +#endif + STC2VFU(rgb[1][indx], vintpf(VH_Disc, H_Est, V_Est)); + } +#endif + for (; col < tilecols - 4; col += 2, indx += 2) { + // Cardinal gradients + const float cfai = cfa[indx]; + const float N_Grad = eps + (std::fabs(cfa[indx - w1] - cfa[indx + w1]) + std::fabs(cfai - cfa[indx - w2])) + (std::fabs(cfa[indx - w1] - cfa[indx - w3]) + std::fabs(cfa[indx - w2] - cfa[indx - w4])); + const float S_Grad = eps + (std::fabs(cfa[indx - w1] - cfa[indx + w1]) + std::fabs(cfai - cfa[indx + w2])) + (std::fabs(cfa[indx + w1] - cfa[indx + w3]) + std::fabs(cfa[indx + w2] - cfa[indx + w4])); + const float W_Grad = eps + (std::fabs(cfa[indx - 1] - cfa[indx + 1]) + std::fabs(cfai - cfa[indx - 2])) + (std::fabs(cfa[indx - 1] - cfa[indx - 3]) + std::fabs(cfa[indx - 2] - cfa[indx - 4])); + const float E_Grad = eps + (std::fabs(cfa[indx - 1] - cfa[indx + 1]) + std::fabs(cfai - cfa[indx + 2])) + (std::fabs(cfa[indx + 1] - cfa[indx + 3]) + std::fabs(cfa[indx + 2] - cfa[indx + 4])); + + // Cardinal pixel estimations + const float lpfi = lpf[indx>>1]; + const float N_Est = cfa[indx - w1] * (1.f + (lpfi - lpf[(indx - w2)>>1]) / (eps + lpfi + lpf[(indx - w2)>>1])); + const float S_Est = cfa[indx + w1] * (1.f + (lpfi - lpf[(indx + w2)>>1]) / (eps + lpfi + lpf[(indx + w2)>>1])); + const float W_Est = cfa[indx - 1] * (1.f + (lpfi - lpf[(indx - 2)>>1]) / (eps + lpfi + lpf[(indx - 2)>>1])); + const float E_Est = cfa[indx + 1] * (1.f + (lpfi - lpf[(indx + 2)>>1]) / (eps + lpfi + lpf[(indx + 2)>>1])); + + // Vertical and horizontal estimations + const float V_Est = (S_Grad * N_Est + N_Grad * S_Est) / (N_Grad + S_Grad); + const float H_Est = (W_Grad * E_Est + E_Grad * W_Est) / (E_Grad + W_Grad); + + // G@B and G@R interpolation + // Refined vertical and horizontal local discrimination + const float VH_Central_Value = VH_Dir[indx]; + const float VH_Neighbourhood_Value = 0.25f * ((VH_Dir[indx - w1 - 1] + VH_Dir[indx - w1 + 1]) + (VH_Dir[indx + w1 - 1] + VH_Dir[indx + w1 + 1])); + + const float VH_Disc = std::fabs(0.5f - VH_Central_Value) < std::fabs(0.5f - VH_Neighbourhood_Value) ? VH_Neighbourhood_Value : VH_Central_Value; + rgb[1][indx] = VH_Disc * H_Est + (1.f - VH_Disc) * V_Est; } } + /** * STEP 4: Populate the red and blue channels */ @@ -191,7 +241,6 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) float Q_Stat = max(epssq, - 18.f * cfai * (cfa[indx + w1 - 1] + cfa[indx - w1 + 1] + 2.f * (cfa[indx + w2 - 2] + cfa[indx - w2 + 2]) - cfa[indx + w3 - 3] - cfa[indx - w3 + 3]) - 2.f * cfai * (cfa[indx + w4 - 4] + cfa[indx - w4 + 4] - 19.f * cfai) - cfa[indx + w1 - 1] * (70.f * cfa[indx - w1 + 1] - 12.f * cfa[indx + w2 - 2] + 24.f * cfa[indx - w2 + 2] - 38.f * cfa[indx + w3 - 3] + 16.f * cfa[indx - w3 + 3] + 12.f * cfa[indx + w4 - 4] - 6.f * cfa[indx - w4 + 4] + 46.f * cfa[indx + w1 - 1]) + cfa[indx - w1 + 1] * (24.f * cfa[indx + w2 - 2] - 12.f * cfa[indx - w2 + 2] + 16.f * cfa[indx + w3 - 3] - 38.f * cfa[indx - w3 + 3] - 6.f * cfa[indx + w4 - 4] + 12.f * cfa[indx - w4 + 4] + 46.f * cfa[indx - w1 + 1]) + cfa[indx + w2 - 2] * (14.f * cfa[indx - w2 + 2] - 12.f * cfa[indx - w3 + 3] - 2.f * (cfa[indx + w4 - 4] - cfa[indx - w4 + 4]) + 11.f * cfa[indx + w2 - 2]) - cfa[indx - w2 + 2] * (12.f * cfa[indx + w3 - 3] + 2.f * (cfa[indx + w4 - 4] - cfa[indx - w4 + 4]) + 11.f * cfa[indx - w2 + 2]) + cfa[indx + w3 - 3] * (2.f * cfa[indx - w3 + 3] - 6.f * cfa[indx + w4 - 4] + 10.f * cfa[indx + w3 - 3]) - cfa[indx - w3 + 3] * (6.f * cfa[indx - w4 + 4] + 10.f * cfa[indx - w3 + 3]) + cfa[indx + w4 - 4] * cfa[indx + w4 - 4] + cfa[indx - w4 + 4] * cfa[indx - w4 + 4]); PQ_Dir[indx] = P_Stat / (P_Stat + Q_Stat); - } } @@ -223,7 +272,6 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) // R@B and B@R interpolation rgb[c][indx] = rgb[1][indx] + (1.f - PQ_Disc) * P_Est + PQ_Disc * Q_Est; - } } @@ -267,7 +315,6 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) // R@G and B@G interpolation rgb[c][indx] = rgb1 + (1.f - VH_Disc) * V_Est + VH_Disc * H_Est; - } } } @@ -281,9 +328,9 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) } } - if(plistener) { + if (plistener) { progresscounter++; - if(progresscounter % 32 == 0) { + if (progresscounter % 32 == 0) { #ifdef _OPENMP #pragma omp critical (rcdprogress) #endif @@ -294,7 +341,6 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) } } } - } } @@ -309,7 +355,6 @@ void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) if (plistener) { plistener->setProgress(1); } - // ------------------------------------------------------------------------- } } /* namespace */ diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index b77eac29c..e424ef14d 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,493 @@ 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 + 0, // 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, // EvlocallabdehazeSaturation + 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 + 0, // can be reused + LUMINANCECURVE, // EvLocallabSpotcolorscope + LUMINANCECURVE, // EvlocallabshowmasktypMethod + LUMINANCECURVE, // Evlocallabshadmaskblsha + LUMINANCECURVE, // EvLocenamask + LUMINANCECURVE, // Evlocallabsensimask + LUMINANCECURVE, // Evlocallabblendmask + LUMINANCECURVE, // EvLocallabEna_Mask + LUMINANCECURVE, // Evlocallabradmask + LUMINANCECURVE, // Evlocallablapmask + LUMINANCECURVE, // Evlocallabchromask + LUMINANCECURVE, // Evlocallabgammask + LUMINANCECURVE, // Evlocallabslopmask + LUMINANCECURVE, // EvlocallabCCmask_shape + LUMINANCECURVE, // EvlocallabLLmask_shape + LUMINANCECURVE, // EvlocallabHHmask_shape + LUMINANCECURVE, // EvLocallabtoolmask + LUMINANCECURVE, // Evlocallabstrumaskmask + LUMINANCECURVE, // EvlocallabHHhmask_shape + LUMINANCECURVE, // EvLocallabfftmask + LUMINANCECURVE, // Evlocallabblurmask + LUMINANCECURVE, // Evlocallabcontmask + LUMINANCECURVE, // Evlocallabshadmask + LUMINANCECURVE, // EvlocallabLmask_shape + LUMINANCECURVE, // EvlocallabLLmask_shapewav + LUMINANCECURVE, // EvlocallabcsThresholdmask + LUMINANCECURVE, // Evlocallabstr_mask + LUMINANCECURVE, // Evlocallabang_mask + LUMINANCECURVE, // Evlocallabsoftradiusmask + LUMINANCECURVE, // Evlocallabblendmaskab + LUMINANCECURVE, // EvLocallabSpotprevMethod + LUMINANCECURVE, // Evlocallabactiv + LUMINANCECURVE, // EvlocallabCHshape + LUMINANCECURVE, //EvlocallabquaMethod + LUMINANCECURVE, //Evlocallabhishow + LUMINANCECURVE, // Evlocallabinvbl + LUMINANCECURVE, // Evlocallabcatad + LUMINANCECURVE, // Evlocallabciecam + LUMINANCECURVE, // Evlocallabsourceabs + LUMINANCECURVE, // Evlocallabtargabs + LUMINANCECURVE, // Evlocallabsurround + LUMINANCECURVE, // Evlocallabsaturl + LUMINANCECURVE, // Evlocallabcontl + LUMINANCECURVE, //EvlocallabCCmaskshapeL + LUMINANCECURVE, //EvlocallabLLmaskshapeL + LUMINANCECURVE, // EvlocallabHHmaskshapeL + LUMINANCECURVE, // EvlocallabenaLMask + LUMINANCECURVE, // EvlocallabblendmaskL + LUMINANCECURVE, // EvlocallabradmaskL + LUMINANCECURVE, // EvlocallabchromaskL + LUMINANCECURVE, //EvlocallabLmaskshapeL + LUMINANCECURVE, // Evlocallablightl + LUMINANCECURVE, // EvlocallabLshapeL + LUMINANCECURVE, // Evlocallabcontq + LUMINANCECURVE, // Evlocallabsursour + LUMINANCECURVE, // Evlocallablightq + LUMINANCECURVE, // Evlocallabcolorfl + LUMINANCECURVE // Evlocallabrepar }; @@ -553,6 +1039,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/rescale.h b/rtengine/rescale.h index 2138cd8e8..3126a7c58 100644 --- a/rtengine/rescale.h +++ b/rtengine/rescale.h @@ -31,8 +31,8 @@ namespace rtengine inline float getBilinearValue(const array2D &src, float x, float y) { - const int W = src.width(); - const int H = src.height(); + const int W = src.getWidth(); + const int H = src.getHeight(); // Get integer and fractional parts of numbers int xi = x; @@ -57,10 +57,10 @@ inline float getBilinearValue(const array2D &src, float x, float y) inline void rescaleBilinear(const array2D &src, array2D &dst, bool multithread) { - const int Ws = src.width(); - const int Hs = src.height(); - const int Wd = dst.width(); - const int Hd = dst.height(); + const int Ws = src.getWidth(); + const int Hs = src.getHeight(); + const int Wd = dst.getWidth(); + const int Hd = dst.getHeight(); float col_scale = float (Ws) / float (Wd); float row_scale = float (Hs) / float (Hd); @@ -81,10 +81,10 @@ inline void rescaleBilinear(const array2D &src, array2D &dst, bool inline void rescaleNearest(const array2D &src, array2D &dst, bool multithread) { - const int width = src.width(); - const int height = src.height(); - const int nw = dst.width(); - const int nh = dst.height(); + const int width = src.getWidth(); + const int height = src.getHeight(); + const int nw = dst.getWidth(); + const int nh = dst.getHeight(); #ifdef _OPENMP #pragma omp parallel for if (multithread) diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index a5b48af95..e4ae84a46 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -34,23 +34,14 @@ #include "sleef.h" namespace { -float calcBlendFactor(float val, float threshold) { - // sigmoid function - // result is in ]0;1] range - // inflexion point is at (x, y) (threshold, 0.5) - return 1.f / (1.f + xexpf(16.f - 16.f * val / threshold)); -} -#ifdef __SSE2__ -vfloat calcBlendFactor(vfloat valv, vfloat thresholdv) { +template +T calcBlendFactor(T val, T threshold) { // sigmoid function // result is in ]0;1] range // inflexion point is at (x, y) (threshold, 0.5) - const vfloat onev = F2V(1.f); - const vfloat c16v = F2V(16.f); - return onev / (onev + xexpf(c16v - c16v * valv / thresholdv)); + return 1.f / (1.f + xexpf(16.f - (16.f / threshold) * val)); } -#endif float tileAverage(const float * const *data, size_t tileY, size_t tileX, size_t tilesize) { @@ -488,4 +479,25 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H, } } +double accumulateProduct(const float* data1, const float* data2, size_t n, bool multiThread) { + if (n == 0) { + return 0.0; + } + + // use two accumulators to reduce dependencies (improves speed) and increase accuracy + double acc1 = 0.0; + double acc2 = 0.0; +#ifdef _OPENMP + #pragma omp parallel for reduction(+:acc1,acc2) if(multiThread) +#endif + for (size_t i = 0; i < n - 1; i += 2) { + acc1 += static_cast(data1[i]) * static_cast(data2[i]); + acc2 += static_cast(data1[i + 1]) * static_cast(data2[i + 1]); + } + + if (n & 1) { + acc1 += static_cast(data1[n -1]) * static_cast(data2[n -1]); + } + return acc1 + acc2; +} } diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h index 81147fd75..bffe17b57 100644 --- a/rtengine/rt_algo.h +++ b/rtengine/rt_algo.h @@ -25,4 +25,9 @@ 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); +double accumulateProduct(const float* data1, const float* data2, size_t n, bool multiThread = true); } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index ea4c84125..f78885da6 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -35,12 +35,16 @@ #include "../rtgui/threadutils.h" + /** * @file * This file contains the main functionality of the RawTherapee engine. * */ +template +class array2D; + template class LUT; @@ -302,6 +306,8 @@ public: virtual void sizeChanged(int w, int h, int ow, int oh) = 0; }; +class HistogramObservable; + /** This listener is used when the histogram of the final image has changed. */ class HistogramListener { @@ -327,8 +333,43 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, const LUTu& histChroma, - const LUTu& histLRETI + const LUTu& histLRETI, + int vectorscopeScale, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, + int waveformScale, + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) = 0; + /** Tells which observable is notifying the listener. */ + virtual void setObservable(HistogramObservable* observable) = 0; + /** Returns if the listener wants the histogram to be updated. */ + virtual bool updateHistogram(void) const = 0; + /** Returns if the listener wants the raw histogram to be updated. */ + virtual bool updateHistogramRaw(void) const = 0; + /** Returns if the listener wants the H-C vectorscope to be updated. */ + virtual bool updateVectorscopeHC(void) const = 0; + /** Returns if the listener wants the H-S vectorscope to be updated. */ + virtual bool updateVectorscopeHS(void) const = 0; + /** Returns if the listener wants the waveform to be updated. */ + virtual bool updateWaveform(void) const = 0; +}; + +class HistogramObservable +{ +public: + /** Tells the observable to update the histogram data. */ + virtual void requestUpdateHistogram() = 0; + /** Tells the observable to update the raw histogram data. */ + virtual void requestUpdateHistogramRaw() = 0; + /** Tells the observable to update the H-C vectorscope data. */ + virtual void requestUpdateVectorscopeHC() = 0; + /** Tells the observable to update the H-S vectorscope data. */ + virtual void requestUpdateVectorscopeHS() = 0; + /** Tells the observable to update the waveform data. */ + virtual void requestUpdateWaveform() = 0; }; /** This listener is used when the auto exposure has been recomputed (e.g. when the clipping ratio changed). */ @@ -376,6 +417,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 sourceab, const float targetg) = 0; +}; + class AutoColorTonListener { public: @@ -444,7 +511,7 @@ class FilmNegListener { public: virtual ~FilmNegListener() = default; - virtual void filmBaseValuesChanged(std::array rgb) = 0; + virtual void filmRefValuesChanged(const procparams::FilmNegativeParams::RGB &refInput, const procparams::FilmNegativeParams::RGB &refOutput) = 0; }; /** This class represents a detailed part of the image (looking through a kind of window). @@ -534,6 +601,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, int localllogMask, int locall_Mask) = 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 */ @@ -542,9 +611,8 @@ public: virtual bool getAutoWB (double& temp, double& green, double equal, double tempBias) = 0; virtual void getCamWB (double& temp, double& green) = 0; virtual void getSpotWB (int x, int y, int rectSize, double& temp, double& green) = 0; - virtual bool getFilmNegativeExponents(int xA, int yA, int xB, int yB, std::array& newExps) = 0; - virtual bool getRawSpotValues (int x, int y, int spotSize, std::array& rawValues) = 0; - + virtual bool getFilmNegativeSpot(int x, int y, int spotSize, procparams::FilmNegativeParams::RGB &refInput, procparams::FilmNegativeParams::RGB &refOutput) = 0; + virtual void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) = 0; virtual void saveInputICCReference (const Glib::ustring& fname, bool apply_wb) = 0; @@ -569,6 +637,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..58f3d12a3 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; } @@ -440,7 +438,7 @@ std::vector LFDatabase::getLenses() const LFCamera LFDatabase::findCamera(const Glib::ustring &make, const Glib::ustring &model) const { LFCamera ret; - if (data_) { + if (data_ && !make.empty()) { MyMutex::MyLock lock(lfDBMutex); auto found = data_->FindCamerasExt(make.c_str(), model.c_str()); if (found) { @@ -455,7 +453,7 @@ LFCamera LFDatabase::findCamera(const Glib::ustring &make, const Glib::ustring & LFLens LFDatabase::findLens(const LFCamera &camera, const Glib::ustring &name) const { LFLens ret; - if (data_) { + if (data_ && !name.empty()) { MyMutex::MyLock lock(lfDBMutex); auto found = data_->FindLenses(camera.data_, nullptr, name.c_str()); for (size_t pos = 0; !found && pos < name.size(); ) { 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..b724992ff 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -205,11 +205,6 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, ImageIO* img = imgSrc.getImageIO(); - // agriggio -- hotfix for #3794, to be revised once a proper solution is implemented - if (std::max(img->getWidth(), img->getHeight()) / std::min(img->getWidth(), img->getHeight()) >= 10) { - return nullptr; - } - Thumbnail* tpp = new Thumbnail (); unsigned char* data; @@ -235,15 +230,29 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, h = img->getHeight(); tpp->scale = 1.; } else { - if (fixwh == 1) { + if (fixwh < 0 && w > 0 && h > 0) { + const int ww = h * img->getWidth() / img->getHeight(); + const int hh = w * img->getHeight() / img->getWidth(); + if (ww <= w) { + w = ww; + tpp->scale = static_cast(img->getHeight()) / h; + } else { + h = hh; + tpp->scale = static_cast(img->getWidth()) / w; + } + } else if (fixwh == 1) { w = h * img->getWidth() / img->getHeight(); - tpp->scale = (double)img->getHeight() / h; + tpp->scale = static_cast(img->getHeight()) / h; } else { h = w * img->getHeight() / img->getWidth(); - tpp->scale = (double)img->getWidth() / w; + tpp->scale = static_cast(img->getWidth()) / w; } } + // Precaution to prevent division by zero later on + if (h < 1) h = 1; + if (w < 1) w = 1; + // bilinear interpolation if (tpp->thumbImg) { delete tpp->thumbImg; @@ -594,7 +603,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati tpp->defGain = 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]); tpp->defGain *= std::pow(2, ri->getBaselineExposure()); - tpp->scaleGain = scale_mul[0] / pre_mul[0]; // used to reconstruct scale_mul from filmnegativethumb.cc + tpp->scaleGain = scale_mul[0] / pre_mul[0]; // can be used to reconstruct scale_mul later in processing tpp->gammaCorrected = true; @@ -1178,11 +1187,18 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT rwidth = int (size_t (thumbImg->getWidth()) * size_t (rheight) / size_t (thumbImg->getHeight())); } + if (rwidth < 1) rwidth = 1; + if (rheight < 1) rheight = 1; Imagefloat* baseImg = resizeTo (rwidth, rheight, interp, thumbImg); - if (isRaw && params.filmNegative.enabled) { - processFilmNegative(params, baseImg, rwidth, rheight); + // Film negative legacy mode, for backwards compatibility RT v5.8 + if (params.filmNegative.enabled) { + if (params.filmNegative.backCompat == FilmNegativeParams::BackCompat::V1) { + processFilmNegative(params, baseImg, rwidth, rheight); + } else if (params.filmNegative.backCompat == FilmNegativeParams::BackCompat::V2) { + processFilmNegativeV2(params, baseImg, rwidth, rheight); + } } if (params.coarse.rotate) { @@ -1224,6 +1240,19 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT // if luma denoise has to be done for thumbnails, it should be right here + int fw = baseImg->getWidth(); + int fh = baseImg->getHeight(); + //ColorTemp::CAT02 (baseImg, ¶ms) ;//perhaps not good! + + ImProcFunctions ipf (¶ms, forHistogramMatching); // enable multithreading when forHistogramMatching is true + ipf.setScale (sqrt (double (fw * fw + fh * fh)) / sqrt (double (thumbImg->getWidth() * thumbImg->getWidth() + thumbImg->getHeight() * thumbImg->getHeight()))*scale); + ipf.updateColorProfiles (ICCStore::getInstance()->getDefaultMonitorProfileName(), RenderingIntent(settings->monitorIntent), false, false); + + // Process film negative BEFORE colorspace conversion, if needed + if (params.filmNegative.enabled && params.filmNegative.backCompat == FilmNegativeParams::BackCompat::CURRENT && params.filmNegative.colorSpace == FilmNegativeParams::ColorSpace::INPUT) { + ipf.filmNegativeProcess(baseImg, baseImg, params.filmNegative); + } + // perform color space transformation if (isRaw) { @@ -1233,20 +1262,17 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, thumbImg->getSampleFormat()); } - int fw = baseImg->getWidth(); - int fh = baseImg->getHeight(); - //ColorTemp::CAT02 (baseImg, ¶ms) ;//perhaps not good! - - ImProcFunctions ipf (¶ms, forHistogramMatching); // enable multithreading when forHistogramMatching is true - ipf.setScale (sqrt (double (fw * fw + fh * fh)) / sqrt (double (thumbImg->getWidth() * thumbImg->getWidth() + thumbImg->getHeight() * thumbImg->getHeight()))*scale); - ipf.updateColorProfiles (ICCStore::getInstance()->getDefaultMonitorProfileName(), RenderingIntent(settings->monitorIntent), false, false); + // Process film negative AFTER colorspace conversion, if needed + if (params.filmNegative.enabled && params.filmNegative.backCompat == FilmNegativeParams::BackCompat::CURRENT && params.filmNegative.colorSpace != FilmNegativeParams::ColorSpace::INPUT) { + ipf.filmNegativeProcess(baseImg, baseImg, params.filmNegative); + } LUTu hist16 (65536); 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; @@ -1327,10 +1353,10 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT params.colorToning.getCurves (ctColorCurve, ctOpacityCurve, wp, opautili); clToningcurve (65536); - CurveFactory::curveToning (params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); + CurveFactory::diagonalCurve2Lut (params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); cl2Toningcurve (65536); - CurveFactory::curveToning (params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + CurveFactory::diagonalCurve2Lut (params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); } if (params.blackwhite.enabled) { @@ -1406,23 +1432,23 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 16, utili); - bool clcutili; - CurveFactory::curveCL (clcutili, params.labCurve.clcurve, clcurve, 16); + const bool clcutili = CurveFactory::diagonalCurve2Lut(params.labCurve.clcurve, clcurve, 16); bool autili, butili, ccutili, cclutili; 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/rtthumbnail.h b/rtengine/rtthumbnail.h index a0033d35f..6ec1dfb34 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -78,6 +78,7 @@ class Thumbnail double scaleGain; void processFilmNegative(const procparams::ProcParams& params, const Imagefloat* baseImg, int rwidth, int rheight); + void processFilmNegativeV2(const procparams::ProcParams& params, const Imagefloat* baseImg, int rwidth, int rheight); public: diff --git a/rtengine/settings.h b/rtengine/settings.h index 529336cbc..0fb4996df 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; @@ -90,6 +99,10 @@ public: int itcwb_delta; bool itcwb_stdobserver10; int itcwb_precis; +//wavelet levels + double edghi; + double edglo; + double limrad; enum class ThumbnailInspectorMode { 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 2e567aa6a..2c9bc566a 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -219,16 +219,6 @@ private: imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); imgsrc->preprocess(params.raw, params.lensProf, params.coarse, params.dirpyrDenoise.enabled); - // After preprocess, run film negative processing if enabled - if ((imgsrc->getSensorType() == ST_BAYER || (imgsrc->getSensorType() == ST_FUJI_XTRANS)) && params.filmNegative.enabled) { - std::array filmBaseValues = { - static_cast(params.filmNegative.redBase), - static_cast(params.filmNegative.greenBase), - static_cast(params.filmNegative.blueBase) - }; - imgsrc->filmNegativeProcess (params.filmNegative, filmBaseValues); - } - if (pl) { pl->setProgress(0.20); } @@ -878,15 +868,31 @@ private: //ImProcFunctions ipf (¶ms, true); ImProcFunctions &ipf = * (ipf_p.get()); - imgsrc->convertColorSpace(baseImg, params.icm, currWB); + if (params.filmNegative.enabled) { + // Process film negative AFTER colorspace conversion if camera space is NOT selected + if (params.filmNegative.colorSpace != FilmNegativeParams::ColorSpace::INPUT) { + imgsrc->convertColorSpace(baseImg, params.icm, currWB); + } + + FilmNegativeParams copy = params.filmNegative; + ipf.filmNegativeProcess(baseImg, baseImg, copy, params.raw, imgsrc, currWB); + + // ... otherwise, process film negative BEFORE colorspace conversion + if (params.filmNegative.colorSpace == FilmNegativeParams::ColorSpace::INPUT) { + imgsrc->convertColorSpace(baseImg, params.icm, currWB); + } + + } else { + imgsrc->convertColorSpace(baseImg, params.icm, currWB); + } // perform first analysis hist16(65536); 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())) { @@ -923,7 +929,7 @@ private: ipf.lab2rgb(labcbdl, *baseImg, params.icm.workingProfile); } - //gamma TRC working +/* //gamma TRC working if (params.icm.workingTRC == "Custom") { //exec TRC IN free const Glib::ustring profile = params.icm.workingProfile; @@ -937,7 +943,7 @@ private: ipf.workingtrc(baseImg, baseImg, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, dummyTransForm, false, true, false); } } - +*/ // RGB processing curve1(65536); @@ -970,9 +976,9 @@ private: }; params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili); clToningcurve(65536, 0); - CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, 1); + CurveFactory::diagonalCurve2Lut(params.colorToning.clcurve, clToningcurve, 1); cl2Toningcurve(65536, 0); - CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, 1); + CurveFactory::diagonalCurve2Lut(params.colorToning.cl2curve, cl2Toningcurve, 1); } labView = new LabImage(fw, fh); @@ -1075,13 +1081,268 @@ private: bool utili; CurveFactory::complexLCurve(params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 1, utili); - bool clcutili; - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 1); + const bool clcutili = CurveFactory::diagonalCurve2Lut(params.labCurve.clcurve, clcurve, 1); bool ccutili, cclutili; CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1); + + if (params.locallab.enabled && params.locallab.spots.size() > 0) { + MyTime t1, t2; + t1.set(); + const std::unique_ptr reservView(new LabImage(*labView, true)); + const std::unique_ptr lastorigView(new LabImage(*labView, true)); + LocretigainCurve locRETgainCurve; + LocretitransCurve locRETtransCurve; + LocLHCurve loclhCurve; + LocHHCurve lochhCurve; + LocCHCurve locchCurve; + 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; + LocCCmaskCurve locccmaslogCurve; + LocLLmaskCurve locllmaslogCurve; + LocHHmaskCurve lochhmaslogCurve; + + LocCCmaskCurve locccmas_Curve; + LocLLmaskCurve locllmas_Curve; + LocHHmaskCurve lochhmas_Curve; + LocHHmaskCurve lochhhmas_Curve; + + LocwavCurve loclmasCurveblwav; + LocwavCurve loclmasCurvecolwav; + LocwavCurve loclmasCurve_wav; + LocwavCurve locwavCurve; + LocwavCurve loclevwavCurve; + LocwavCurve locconwavCurve; + LocwavCurve loccompwavCurve; + LocwavCurve loccomprewavCurve; + LocwavCurve locedgwavCurve; + LocwavCurve locwavCurveden; + LUTf lllocalcurve(65536, LUT_CLIP_OFF); + LUTf lclocalcurve(65536, LUT_CLIP_OFF); + LUTf cllocalcurve(65536, LUT_CLIP_OFF); + LUTf cclocalcurve(65536, LUT_CLIP_OFF); + LUTf rgblocalcurve(65536, LUT_CLIP_OFF); + LUTf hltonecurveloc(65536, LUT_CLIP_OFF); + LUTf shtonecurveloc(65536, LUT_CLIP_OFF); + LUTf tonecurveloc(65536, LUT_CLIP_OFF); + LUTf lightCurveloc(32770, LUT_CLIP_OFF); + LUTf exlocalcurve(65536, LUT_CLIP_OFF); + LUTf lmasklocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskexplocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskSHlocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskviblocalcurve(65536, LUT_CLIP_OFF); + LUTf lmasktmlocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskretilocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskcblocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskbllocalcurve(65536, LUT_CLIP_OFF); + LUTf lmasklclocalcurve(65536, LUT_CLIP_OFF); + LUTf lmaskloglocalcurve(65536, LUT_CLIP_OFF); + LUTf lmasklocal_curve(65536, LUT_CLIP_OFF); + + array2D shbuffer; + for (size_t sp = 0; sp < params.locallab.spots.size(); sp++) { + if (params.locallab.spots.at(sp).inverssha) { + shbuffer(fw, fh); + break; + } + } + + for (size_t sp = 0; sp < params.locallab.spots.size(); sp++) { + // Set local curves of current spot to LUT + locRETgainCurve.Set(params.locallab.spots.at(sp).localTgaincurve); + locRETtransCurve.Set(params.locallab.spots.at(sp).localTtranscurve); + const bool LHutili = loclhCurve.Set(params.locallab.spots.at(sp).LHcurve); + const bool HHutili = lochhCurve.Set(params.locallab.spots.at(sp).HHcurve); + const bool CHutili = locchCurve.Set(params.locallab.spots.at(sp).CHcurve); + const bool lcmasutili = locccmasCurve.Set(params.locallab.spots.at(sp).CCmaskcurve); + const bool llmasutili = locllmasCurve.Set(params.locallab.spots.at(sp).LLmaskcurve); + const bool lhmasutili = lochhmasCurve.Set(params.locallab.spots.at(sp).HHmaskcurve); + const bool lhhmasutili = lochhhmasCurve.Set(params.locallab.spots.at(sp).HHhmaskcurve); + const bool lcmasexputili = locccmasexpCurve.Set(params.locallab.spots.at(sp).CCmaskexpcurve); + const bool llmasexputili = locllmasexpCurve.Set(params.locallab.spots.at(sp).LLmaskexpcurve); + const bool lhmasexputili = lochhmasexpCurve.Set(params.locallab.spots.at(sp).HHmaskexpcurve); + const bool lcmasSHutili = locccmasSHCurve.Set(params.locallab.spots.at(sp).CCmaskSHcurve); + const bool llmasSHutili = locllmasSHCurve.Set(params.locallab.spots.at(sp).LLmaskSHcurve); + const bool lhmasSHutili = lochhmasSHCurve.Set(params.locallab.spots.at(sp).HHmaskSHcurve); + const bool lcmasvibutili = locccmasvibCurve.Set(params.locallab.spots.at(sp).CCmaskvibcurve); + const bool llmasvibutili = locllmasvibCurve.Set(params.locallab.spots.at(sp).LLmaskvibcurve); + const bool lhmasvibutili = lochhmasvibCurve.Set(params.locallab.spots.at(sp).HHmaskvibcurve); + const bool lcmascbutili = locccmascbCurve.Set(params.locallab.spots.at(sp).CCmaskcbcurve); + const bool llmascbutili = locllmascbCurve.Set(params.locallab.spots.at(sp).LLmaskcbcurve); + const bool lhmascbutili = lochhmascbCurve.Set(params.locallab.spots.at(sp).HHmaskcbcurve); + const bool lcmasretiutili = locccmasretiCurve.Set(params.locallab.spots.at(sp).CCmaskreticurve); + const bool llmasretiutili = locllmasretiCurve.Set(params.locallab.spots.at(sp).LLmaskreticurve); + const bool lhmasretiutili = lochhmasretiCurve.Set(params.locallab.spots.at(sp).HHmaskreticurve); + const bool lcmastmutili = locccmastmCurve.Set(params.locallab.spots.at(sp).CCmasktmcurve); + const bool lhmaslcutili = lochhmaslcCurve.Set(params.locallab.spots.at(sp).HHmasklccurve); + const bool llmastmutili = locllmastmCurve.Set(params.locallab.spots.at(sp).LLmasktmcurve); + const bool lhmastmutili = lochhmastmCurve.Set(params.locallab.spots.at(sp).HHmasktmcurve); + const bool lcmasblutili = locccmasblCurve.Set(params.locallab.spots.at(sp).CCmaskblcurve); + const bool llmasblutili = locllmasblCurve.Set(params.locallab.spots.at(sp).LLmaskblcurve); + const bool lhmasblutili = lochhmasblCurve.Set(params.locallab.spots.at(sp).HHmaskblcurve); + const bool lcmaslogutili = locccmaslogCurve.Set(params.locallab.spots.at(sp).CCmaskcurveL); + const bool llmaslogutili = locllmaslogCurve.Set(params.locallab.spots.at(sp).LLmaskcurveL); + const bool lhmaslogutili = lochhmaslogCurve.Set(params.locallab.spots.at(sp).HHmaskcurveL); + + const bool lcmas_utili = locccmas_Curve.Set(params.locallab.spots.at(sp).CCmask_curve); + const bool llmas_utili = locllmas_Curve.Set(params.locallab.spots.at(sp).LLmask_curve); + const bool lhmas_utili = lochhmas_Curve.Set(params.locallab.spots.at(sp).HHmask_curve); + const bool lhhmas_utili = lochhhmas_Curve.Set(params.locallab.spots.at(sp).HHhmask_curve); + const bool lmasutiliblwav = loclmasCurveblwav.Set(params.locallab.spots.at(sp).LLmaskblcurvewav); + const bool lmasutilicolwav = loclmasCurvecolwav.Set(params.locallab.spots.at(sp).LLmaskcolcurvewav); + const bool lcmaslcutili = locccmaslcCurve.Set(params.locallab.spots.at(sp).CCmasklccurve); + const bool llmaslcutili = locllmaslcCurve.Set(params.locallab.spots.at(sp).LLmasklccurve); + const bool lmasutili_wav = loclmasCurve_wav.Set(params.locallab.spots.at(sp).LLmask_curvewav); + const bool locwavutili = locwavCurve.Set(params.locallab.spots.at(sp).locwavcurve); + const bool locwavdenutili = locwavCurveden.Set(params.locallab.spots.at(sp).locwavcurveden); + const bool loclevwavutili = loclevwavCurve.Set(params.locallab.spots.at(sp).loclevwavcurve); + const bool locconwavutili = locconwavCurve.Set(params.locallab.spots.at(sp).locconwavcurve); + const bool loccompwavutili = loccompwavCurve.Set(params.locallab.spots.at(sp).loccompwavcurve); + const bool loccomprewavutili = loccomprewavCurve.Set(params.locallab.spots.at(sp).loccomprewavcurve); + const bool locedgwavutili = locedgwavCurve.Set(params.locallab.spots.at(sp).locedgwavcurve); + const bool locallutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).llcurve, lllocalcurve, 1); + const bool localclutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).clcurve, cllocalcurve, 1); + const bool locallcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).lccurve, lclocalcurve, 1); + const bool localcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).cccurve, cclocalcurve, 1); + const bool localrgbutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).rgbcurve, rgblocalcurve, 1); + const bool localexutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).excurve, exlocalcurve, 1); + const bool localmaskutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskcurve, lmasklocalcurve, 1); + const bool localmaskexputili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskexpcurve, lmaskexplocalcurve, 1); + const bool localmaskSHutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).LmaskSHcurve, lmaskSHlocalcurve, 1); + const bool localmaskvibutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskvibcurve, lmaskviblocalcurve, 1); + const bool localmasktmutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmasktmcurve, lmasktmlocalcurve, 1); + const bool localmaskretiutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskreticurve, lmaskretilocalcurve, 1); + const bool localmaskcbutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskcbcurve, lmaskcblocalcurve, 1); + const bool localmaskblutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmaskblcurve, lmaskbllocalcurve, 1); + const bool localmasklcutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmasklccurve, lmasklclocalcurve, 1); + const bool localmasklogutili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).LmaskcurveL, lmaskloglocalcurve, 1); + const bool localmask_utili = CurveFactory::diagonalCurve2Lut(params.locallab.spots.at(sp).Lmask_curve, lmasklocal_curve, 1); + + //provisory + double ecomp = params.locallab.spots.at(sp).expcomp; + double lblack = params.locallab.spots.at(sp).black; + double lhlcompr = params.locallab.spots.at(sp).hlcompr; + double lhlcomprthresh = 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 (lblack < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) { + lblack *= 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.get(), reservView.get(), 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, lblack / 65535., lhlcompr, lhlcomprthresh, 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, shbuffer, labView, labView, reservView.get(), lastorigView.get(), 0, 0, fw, fh, 1, locRETgainCurve, locRETtransCurve, + lllocalcurve, locallutili, + cllocalcurve, localclutili, + lclocalcurve, locallcutili, + loclhCurve, lochhCurve, locchCurve, + lmasklocalcurve, localmaskutili, + lmaskexplocalcurve, localmaskexputili, + lmaskSHlocalcurve, localmaskSHutili, + lmaskviblocalcurve, localmaskvibutili, + lmasktmlocalcurve, localmasktmutili, + lmaskretilocalcurve, localmaskretiutili, + lmaskcblocalcurve, localmaskcbutili, + lmaskbllocalcurve, localmaskblutili, + lmasklclocalcurve, localmasklcutili, + lmaskloglocalcurve, localmasklogutili, + lmasklocal_curve, localmask_utili, + + 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, + locccmaslogCurve, lcmaslogutili, locllmaslogCurve, llmaslogutili, lochhmaslogCurve, lhmaslogutili, + + locccmas_Curve, lcmas_utili, locllmas_Curve, llmas_utili, lochhmas_Curve, lhmas_utili, + lochhhmas_Curve, lhhmas_utili, + loclmasCurveblwav,lmasutiliblwav, + loclmasCurvecolwav,lmasutilicolwav, + locwavCurve, locwavutili, + loclevwavCurve, loclevwavutili, + locconwavCurve, locconwavutili, + loccompwavCurve, loccompwavutili, + loccomprewavCurve, loccomprewavutili, + locwavCurveden, locwavdenutili, + locedgwavCurve, locedgwavutili, + loclmasCurve_wav,lmasutili_wav, + LHutili, HHutili, CHutili, 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, 0, 0, + minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + + if (sp + 1u < params.locallab.spots.size()) { + // do not copy for last spot as it is not needed anymore + lastorigView->CopyFrom(labView); + } + + if (params.locallab.spots.at(sp).spotMethod == "exc") { + ipf.calc_ref(sp, reservView.get(), reservView.get(), 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); + } + } + + t2.set(); + + if (settings->verbose) { + printf("Total local:- %d usec\n", t2.etime(t1)); + } + + } + 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)) { @@ -1089,7 +1350,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 @@ -1125,11 +1386,10 @@ private: if ((params.wavelet.enabled)) { LabImage *unshar = nullptr; - Glib::ustring provis; - - bool wavcontlutili = false; WaveletParams WaveParams = params.wavelet; WavCurve wavCLVCurve; + WavCurve wavdenoise; + WavCurve wavdenoiseh; Wavblcurve wavblcurve; WavOpacityCurveRG waOpacityCurveRG; WavOpacityCurveSH waOpacityCurveSH; @@ -1151,20 +1411,18 @@ private: } */ if (WaveParams.softrad > 0.f) { - provradius = new LabImage(fw, fh); - provradius->CopyFrom(labView); + provradius = new LabImage(*labView, true); } - params.wavelet.getCurves(wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); + params.wavelet.getCurves(wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); - CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1); + CurveFactory::diagonalCurve2Lut(params.wavelet.wavclCurve, wavclCurve, 1); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { - unshar = new LabImage(fw, fh); - provis = params.wavelet.CLmethod; + const Glib::ustring provis = params.wavelet.CLmethod; params.wavelet.CLmethod = "all"; - ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); - unshar->CopyFrom(labView); + ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); + unshar = new LabImage(*labView, true); params.wavelet.CLmethod = provis; WaveParams.expcontrast = false; @@ -1175,7 +1433,7 @@ private: WaveParams.expnoise = false; } - ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); + ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, wavdenoise, wavdenoiseh, wavblcurve, waOpacityCurveRG, waOpacityCurveSH, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, 1); if ((WaveParams.ushamethod == "sharp" || WaveParams.ushamethod == "clari") && WaveParams.expclari && WaveParams.CLmethod != "all") { WaveParams.expcontrast = procont; @@ -1214,11 +1472,11 @@ private: } double epsilmax = 0.0001; double epsilmin = 0.00001; - double aepsil = (epsilmax - epsilmin) / 90.f; - double bepsil = epsilmax - 100.f * aepsil; + double aepsil = (epsilmax - epsilmin) / 100.f; + double bepsil = epsilmin; //epsilmax - 100.f * aepsil; double epsil = aepsil * WaveParams.softrad + bepsil; - float blur = 10.f / 1 * (0.0001f + 0.8f * WaveParams.softrad); + float blur = 10.f / 1 * (0.5f + 0.8f * WaveParams.softrad); // rtengine::guidedFilter(guid, ble, ble, blur, 0.001, multiTh); rtengine::guidedFilter(guid, ble, ble, blur, epsil, false); @@ -1284,7 +1542,7 @@ private: wavCLVCurve.Reset(); } - ipf.softLight(labView); + ipf.softLight(labView, params.softlight); //Colorappearance and tone-mapping associated @@ -1428,8 +1686,6 @@ private: delete labView; labView = nullptr; - - if (bwonly) { //force BW r=g=b if (settings->verbose) { printf("Force BW\n"); diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index f937188b4..9b95fe34e 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -57,6 +57,7 @@ public: ~StdImageSource () override; int load (const Glib::ustring &fname) override; + void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override {}; void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override; void getrgbloc (int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) override {}; ColorTemp getWB () const override diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc index cee57c851..f49fe9c53 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).getHeight(); } int getCols() const { - return const_cast (*this).width(); + return const_cast(*this).getWidth(); } 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,71 @@ 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 { + + { + 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 +1237,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/vng4_demosaic_RT.cc b/rtengine/vng4_demosaic_RT.cc index ef456af3a..34cab71d1 100644 --- a/rtengine/vng4_demosaic_RT.cc +++ b/rtengine/vng4_demosaic_RT.cc @@ -63,6 +63,18 @@ namespace rtengine void RawImageSource::vng4_demosaic (const array2D &rawData, array2D &red, array2D &green, array2D &blue) { + // Test for RGB cfa + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + if (FC(i, j) == 3) { + // avoid crash + std::cout << "vng4_demosaic supports only RGB Colour filter arrays. Falling back to igv_interpolate" << std::endl; + igv_interpolate(W, H); + return; + } + } + } + BENCHFUN const signed short int *cp, terms[] = { -2, -2, +0, -1, 0, 0x01, -2, -2, +0, +0, 1, 0x01, -2, -1, -1, +0, 0, 0x01, diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index b01b0ac1c..bcad4d7d3 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; @@ -1025,6 +1027,67 @@ void RawImageSource::fast_xtrans_interpolate (const array2D &rawData, arr plistener->setProgress (1.0); } } + +void RawImageSource::fast_xtrans_interpolate_blend (const float* const * blend, const array2D &rawData, array2D &red, array2D &green, array2D &blue) +{ + + if (plistener) { + plistener->setProgressStr(Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), M("TP_RAW_XTRANSFAST"))); + plistener->setProgress(0.0); + } + + int xtrans[6][6]; + ri->getXtransMatrix(xtrans); + + const float weight[3][3] = { + {0.25f, 0.5f, 0.25f}, + {0.5f, 0.f, 0.5f}, + {0.25f, 0.5f, 0.25f} + }; +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) +#endif + for (int row = 8; row < H - 8; ++row) { + for (int col = 8; col < W - 8; ++col) { + float sum[3] = {}; + + for (int v = -1; v <= 1; v++) { + for (int h = -1; h <= 1; h++) { + sum[fcol(row + v, col + h)] += rawData[row + v][(col + h)] * weight[v + 1][h + 1]; + } + } + + switch(fcol(row, col)) { + case 0: // red pixel + red[row][col] = intp(blend[row][col], red[row][col], rawData[row][col]); + green[row][col] = intp(blend[row][col], green[row][col], sum[1] * 0.5f); + blue[row][col] = intp(blend[row][col], blue[row][col], sum[2]); + break; + + case 1: // green pixel + green[row][col] = intp(blend[row][col], green[row][col], rawData[row][col]); + if (fcol(row, col - 1) == fcol(row, col + 1)) { // Solitary green pixel always has exactly two direct red and blue neighbors in 3x3 grid + red[row][col] = intp(blend[row][col], red[row][col], sum[0]); + blue[row][col] = intp(blend[row][col], blue[row][col], sum[2]); + } else { // Non solitary green pixel always has one direct and one diagonal red and blue neighbor in 3x3 grid + red[row][col] = intp(blend[row][col], red[row][col], sum[0] * 1.3333333f); + blue[row][col] = intp(blend[row][col], blue[row][col], sum[2] * 1.3333333f); + } + break; + + case 2: // blue pixel + red[row][col] = intp(blend[row][col], red[row][col], sum[0]); + green[row][col] = intp(blend[row][col], green[row][col], sum[1] * 0.5f); + blue[row][col] = intp(blend[row][col], blue[row][col], rawData[row][col]); + break; + } + } + } + + if (plistener) { + plistener->setProgress (1.0); + } +} #undef fcol #undef isgreen diff --git a/rtexif/canonattribs.cc b/rtexif/canonattribs.cc index a91b7266c..57fe6d07e 100644 --- a/rtexif/canonattribs.cc +++ b/rtexif/canonattribs.cc @@ -70,7 +70,7 @@ public: return "undef"; } - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } }; @@ -99,7 +99,7 @@ public: } char buffer[32]; - sprintf (buffer, "%.1fs %s", sec / 10., (sec & 0x4000) ? ",Custom" : ""); + snprintf(buffer, sizeof(buffer), "%.1fs %s", sec / 10., (sec & 0x4000) ? ",Custom" : ""); return buffer; } }; @@ -542,7 +542,7 @@ public: } char buffer[32]; - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } }; @@ -917,10 +917,11 @@ public: {253, "Canon EF 70-200mm f/2.8L IS II USM + 2x"}, {253, "Canon EF 70-200mm f/2.8L IS III USM + 2x"}, {254, "Canon EF 100mm f/2.8L Macro IS USM"}, - {255, "Sigma 24-105mm f/4 DG OS HSM | A or Other Sigma Lens"}, + {255, "Sigma 24-105mm f/4 DG OS HSM | A or Other Lens"}, {255, "Sigma 180mm f/2.8 EX DG OS HSM APO Macro"}, + {255, "Tamron SP 70-200mm f/2.8 Di VC USD"}, {368, "Sigma 14-24mm f/2.8 DG HSM | A or other Sigma Lens"}, - {368, "Sigma 20mm f/1.4 DG HSM | A"}, + {368, "Sigma 35mm f/1.4 DG HSM | A"}, {368, "Sigma 50mm f/1.4 DG HSM | A"}, {368, "Sigma 40mm f/1.4 DG HSM | A"}, {368, "Sigma 60-600mm f/4.5-6.3 DG OS HSM | S"}, @@ -966,13 +967,14 @@ public: {749, "Tamron 100-400mm f/4.5-6.3 Di VC USD A035E + 2x"}, {750, "Canon EF 35mm f/1.4L II USM or Tamron Lens"}, {750, "Tamron SP 85mm f/1.8 Di VC USD (F016)"}, + {750, "Tamron SP 45mm f/1.8 Di VC USD (F013)"}, {751, "Canon EF 16-35mm f/2.8L III USM"}, {752, "Canon EF 24-105mm f/4L IS II USM"}, {753, "Canon EF 85mm f/1.4L IS USM"}, {754, "Canon EF 70-200mm f/4L IS II USM"}, {757, "Canon EF 400mm f/2.8L IS III USM"}, {758, "Canon EF 600mm f/4L IS III USM"}, - {1136, "Sigma 24-70mm f/2.8 DG OS HSM | Art 017"}, + {1136, "Sigma 24-70mm f/2.8 DG OS HSM | A"}, {4142, "Canon EF-S 18-135mm f/3.5-5.6 IS STM"}, {4143, "Canon EF-M 18-55mm f/3.5-5.6 IS STM or Tamron Lens"}, {4143, "Tamron 18-200mm f/3.5-6.3 Di III VC"}, @@ -1173,7 +1175,7 @@ public: } char buffer[32]; - sprintf (buffer, "%.2fmm", val * 25.4 / 1000); + snprintf(buffer, sizeof(buffer), "%.2fmm", val * 25.4 / 1000); return buffer; } }; @@ -1186,7 +1188,7 @@ public: { char buffer[32]; double d = pow (2, - t->toInt() / 32.0); - sprintf (buffer, "%.3f", d); + snprintf(buffer, sizeof(buffer), "%.3f", d); return buffer; } }; @@ -1197,7 +1199,7 @@ class CAEVInterpreter : public Interpreter std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%.1f", t->toDouble() / 32.0 ); + snprintf(buffer, sizeof(buffer), "%.1f", t->toDouble() / 32.0 ); return buffer; } }; @@ -1210,7 +1212,7 @@ public: { char buffer[32]; int a = t->toInt(); - sprintf (buffer, "%d", a); + snprintf(buffer, sizeof(buffer), "%d", a); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1352,7 +1354,7 @@ public: } char buffer[32]; - sprintf (buffer, "%.0f", n / 32. ); + snprintf(buffer, sizeof(buffer), "%.0f", n / 32. ); return buffer; } }; @@ -1407,7 +1409,7 @@ public: std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%.2f", t->toDouble() / 100 ); + snprintf(buffer, sizeof(buffer), "%.2f", t->toDouble() / 100 ); return buffer; } }; @@ -1419,7 +1421,7 @@ public: std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%.1f", t->toDouble() / 8 - 6 ); + snprintf(buffer, sizeof(buffer), "%.1f", t->toDouble() / 8 - 6 ); return buffer; } }; @@ -1555,7 +1557,7 @@ public: { unsigned long val = t->toInt (0, LONG); char buffer[32]; - sprintf (buffer, "%ld", ((val & 0xffc0) >> 6) * 10000 + ((val >> 16) & 0xff) + ((val & 0x3f) << 8) ); + snprintf(buffer, sizeof(buffer), "%ld", ((val & 0xffc0) >> 6) * 10000 + ((val >> 16) & 0xff) + ((val & 0x3f) << 8) ); return buffer; } }; @@ -1901,6 +1903,7 @@ public: choices[2147484712] = "EOS-1D X Mark III"; choices[2147484722] = "EOS Rebel T7 / 2000D / 1500D / Kiss X90"; choices[2147484723] = "EOS RP"; + choices[2147484725] = "EOS Rebel T8i / 850D / X10i"; choices[2147484726] = "EOS SL3 / 250D / Kiss X10"; choices[2147484727] = "EOS 90D"; choices[2147484960] = "EOS D2000C"; diff --git a/rtexif/nikonattribs.cc b/rtexif/nikonattribs.cc index 0bc9ce730..0ea476a24 100644 --- a/rtexif/nikonattribs.cc +++ b/rtexif/nikonattribs.cc @@ -35,7 +35,7 @@ public: std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%d", t->toInt (2)); + snprintf(buffer, sizeof(buffer), "%d", t->toInt (2)); return buffer; } }; @@ -49,7 +49,7 @@ public: { char buffer[32]; int a = t->toInt(); - sprintf (buffer, "%d", a); + snprintf(buffer, sizeof(buffer), "%d", a); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -128,7 +128,7 @@ public: default: { char buffer[32]; - sprintf (buffer, "0x%04X", a); + snprintf(buffer, sizeof(buffer), "0x%04X", a); return buffer; } } @@ -563,6 +563,7 @@ const std::map NALensDataInterpreter::lenses = { {"00 47 44 44 24 24 00 06", "Tokina AT-X M35 PRO DX (AF 35mm f/2.8 Macro)"}, {"00 47 53 80 30 3C 00 06", "Tamron AF 55-200mm f/4-5.6 Di II LD (A15)"}, {"00 48 1C 29 24 24 00 06", "Tokina AT-X 116 PRO DX (AF 11-16mm f/2.8)"}, + {"00 48 27 27 24 24 00 00", "Carl Zeiss Distagon T* 2.8/15 ZF.2"}, {"00 48 29 3C 24 24 00 06", "Tokina AT-X 16-28 AF PRO FX (AF 16-28mm f/2.8)"}, {"00 48 29 50 24 24 00 06", "Tokina AT-X 165 PRO DX (AF 16-50mm f/2.8)"}, {"00 48 32 32 24 24 00 00", "Carl Zeiss Distagon T* 2.8/21 ZF.2"}, @@ -819,6 +820,7 @@ const std::map NALensDataInterpreter::lenses = { {"4A 4C 24 24 1E 6C 4D 06", "Samyang 14mm f/2.4 Premium"}, {"4A 54 29 29 18 0C 4D 02", "Samyang 16mm f/2.0 ED AS UMC CS"}, {"4A 54 62 62 0C 0C 4D 02", "AF Nikkor 85mm f/1.4D IF"}, + {"4A 58 30 30 14 0C 4D 02", "Rokinon 20mm f/1.8 ED AS UMC"}, {"4A 60 36 36 0C 0C 4D 02", "Samyang 24mm f/1.4 ED AS UMC"}, {"4A 60 44 44 0C 0C 4D 02", "Samyang 35mm f/1.4 AS UMC"}, {"4A 60 62 62 0C 0C 4D 02", "Samyang AE 85mm f/1.4 AS IF UMC"}, @@ -900,6 +902,7 @@ const std::map NALensDataInterpreter::lenses = { {"7A 48 5C 80 24 24 4B 06", "Sigma 70-200mm f/2.8 EX APO DG Macro HSM II"}, {"7A 54 6E 8E 24 24 4B 02", "Sigma APO 120-300mm f/2.8 EX DG HSM"}, {"7B 48 80 98 30 30 80 0E", "AF-S VR Zoom-Nikkor 200-400mm f/4G IF-ED"}, + {"7C 54 2B 50 24 24 00 06", "Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16)"}, {"7D 48 2B 53 24 24 82 06", "AF-S DX Zoom-Nikkor 17-55mm f/2.8G IF-ED"}, {"7F 40 2D 5C 2C 34 84 06", "AF-S DX Zoom-Nikkor 18-70mm f/3.5-4.5G IF-ED"}, {"7F 48 2B 5C 24 34 1C 06", "Sigma 17-70mm f/2.8-4.5 DC Macro Asp. IF"}, @@ -965,6 +968,7 @@ const std::map NALensDataInterpreter::lenses = { {"A0 54 50 50 0C 0C A2 06", "AF-S Nikkor 50mm f/1.4G"}, {"A1 40 18 37 2C 34 A3 06", "AF-S DX Nikkor 10-24mm f/3.5-4.5G ED"}, {"A1 41 19 31 2C 2C 4B 06", "Sigma 10-20mm f/3.5 EX DC HSM"}, + {"A1 48 6E 8E 24 24 DB 4E", "AF-S Nikkor 120-300mm f/2.8E FL ED SR VR"}, {"A1 54 55 55 0C 0C BC 06", "AF-S Nikkor 58mm f/1.4G"}, {"A2 38 5C 8E 34 40 CD 86", "AF-P DX Nikkor 70-300mm f/4.5-6.3G VR"}, {"A2 40 2D 53 2C 3C BD 0E", "AF-S DX Nikkor 18-55mm f/3.5-5.6G VR II"}, @@ -1041,9 +1045,11 @@ const std::map NALensDataInterpreter::lenses = { {"C1 48 24 37 24 24 4B 46", "Sigma 14-24mm f/2.8 DG HSM | A"}, {"C2 4C 24 24 14 14 4B 06", "Sigma 14mm f/1.8 DG HSM | A"}, {"C3 34 68 98 38 40 4B 4E", "Sigma 100-400mm f/5-6.3 DG OS HSM | C"}, + {"C4 4C 73 73 14 14 4B 46", "Sigma 135mm f/1.8 DG HSM | A"}, {"C8 54 44 44 0D 0D DF 46", "Tamron SP 35mm f/1.4 Di USD (F045)"}, {"C8 54 62 62 0C 0C 4B 06", "Sigma 85mm f/1.4 DG HSM | A"}, {"C8 54 62 62 0C 0C 4B 46", "Sigma 85mm f/1.4 DG HSM | A"}, + {"C9 3C 44 76 25 31 DF 4E", "Tamron 35-150mm f/2.8-4 Di VC OSD (A043)"}, {"C9 48 37 5C 24 24 4B 4E", "Sigma 24-70mm f/2.8 DG OS HSM | A"}, {"CA 48 27 3E 24 24 DF 4E", "Tamron SP 15-30mm f/2.8 Di VC USD G2 (A041)"}, {"CB 3C 2B 44 24 31 DF 46", "Tamron 17-35mm f/2.8-4 Di OSD (A037)"}, @@ -1053,6 +1059,7 @@ const std::map NALensDataInterpreter::lenses = { {"CE 47 37 5C 25 25 DF 4E", "Tamron SP 24-70mm f/2.8 Di VC USD G2 (A032)"}, {"CF 38 6E 98 34 3C 4B 0E", "Sigma APO 120-400mm f/4.5-5.6 DG OS HSM"}, {"CF 47 5C 8E 31 3D DF 0E", "Tamron SP 70-300mm f/4-5.6 Di VC USD (A030)"}, + {"D2 3C 8E B0 3C 3C 4B 02", "Sigma APO 300-800mm f/5.6 EX DG HSM"}, {"DC 48 19 19 24 24 4B 06", "Sigma 10mm f/2.8 EX DC HSM Fisheye"}, {"DE 54 50 50 0C 0C 4B 06", "Sigma 50mm f/1.4 EX DG HSM"}, {"E0 3C 5C 8E 30 3C 4B 06", "Sigma 70-300mm f/4-5.6 APO DG Macro HSM"}, diff --git a/rtexif/olympusattribs.cc b/rtexif/olympusattribs.cc index 52fbec55d..d0b3bdeda 100644 --- a/rtexif/olympusattribs.cc +++ b/rtexif/olympusattribs.cc @@ -192,7 +192,10 @@ public: lenses["02 28 10"] = "Lumix G Vario 12-60mm f/3.5-5.6 Asph. Power OIS"; lenses["02 29 10"] = "Leica DG Summilux 12mm f/1.4 Asph."; lenses["02 30 10"] = "Leica DG Vario-Elmarit 12-60mm f/2.8-4 Asph. Power OIS"; + lenses["02 31 10"] = "Lumix G Vario 45-200mm f/4.0-5.6 II"; + lenses["02 32 10"] = "Lumix G Vario 100-300mm f/4.0-5.6 II"; lenses["02 33 10"] = "Lumix G X Vario 12-35mm f/2.8 II Asph. Power OIS"; + lenses["02 34 10"] = "Lumix G Vario 35-100mm f/2.8 II"; lenses["02 35 10"] = "Leica DG Vario-Elmarit 8-18mm f/2.8-4 Asph."; lenses["02 36 10"] = "Leica DG Elmarit 200mm f/2.8 Power OIS"; lenses["02 37 10"] = "Leica DG Vario-Elmarit 50-200mm f/2.8-4 Asph. Power OIS"; @@ -200,6 +203,7 @@ public: lenses["03 01 00"] = "Leica D Vario Elmarit 14-50mm f/2.8-3.5 Asph."; lenses["03 02 00"] = "Leica D Summilux 25mm f/1.4 Asph."; lenses["05 01 10"] = "Tamron 14-150mm f/3.5-5.8 Di III"; + lenses["024 01 10"] = "Venus Optics Laowa 50mm f/2.8 2x Macro"; } std::string toString (const Tag* t) const override { diff --git a/rtexif/pentaxattribs.cc b/rtexif/pentaxattribs.cc index d6b9a9c84..f534d549a 100644 --- a/rtexif/pentaxattribs.cc +++ b/rtexif/pentaxattribs.cc @@ -422,7 +422,7 @@ public: return "undef"; } - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } }; @@ -626,7 +626,7 @@ public: return s.str(); } else { char buffer[1024]; - t->toString (buffer); + t->toString (buffer, sizeof(buffer)); return std::string (buffer); } } @@ -1341,7 +1341,7 @@ public: } char buffer[32]; - sprintf (buffer, "%d", a ); + snprintf(buffer, sizeof(buffer), "%d", a ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1369,7 +1369,7 @@ public: if (a > 1.) { char buffer[32]; - sprintf (buffer, "%.2f", a / 100. ); + snprintf(buffer, sizeof(buffer), "%.2f", a / 100. ); return buffer; } else { return "n/a"; @@ -1399,7 +1399,7 @@ public: if (b > 1.0) { char buffer[32]; - sprintf (buffer, "%.2f", b ); + snprintf(buffer, sizeof(buffer), "%.2f", b ); return buffer; } else { return "n/a"; @@ -1428,7 +1428,7 @@ public: int a = t->toInt (0, BYTE); char buffer[32]; double v = 100.*exp (double (a - 32) * log (2.) / 8.); - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1456,7 +1456,7 @@ public: return "undef"; } - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } else { return "n/a"; @@ -1485,7 +1485,7 @@ public: int a = t->toInt (0, BYTE); char buffer[32]; double v = double (a - 64) / 8.; - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1505,7 +1505,7 @@ public: int a = t->toInt (0, SBYTE); char buffer[32]; double v = double (a) / 8.; - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1525,7 +1525,7 @@ public: int a = t->toInt (0, BYTE); char buffer[32]; double v = exp ((double (a) - 68.) * log (2.) / 16.); - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1545,7 +1545,7 @@ public: int a = t->toInt (0, BYTE); char buffer[32]; double v = 24.*exp (- (double (a) - 32.) * log (2.) / 8.); - sprintf (buffer, "%.6f", v ); + snprintf(buffer, sizeof(buffer), "%.6f", v ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1565,7 +1565,7 @@ public: char buffer[32]; int a = t->toInt (0, BYTE); int mina = a & 0x0F; - sprintf (buffer, "%.1f", double (int (pow (2.0, double (mina + 10) / 4.0) + 0.2))); + snprintf(buffer, sizeof(buffer), "%.1f", double (int (pow (2.0, double (mina + 10) / 4.0) + 0.2))); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1585,7 +1585,7 @@ public: char buffer[32]; int a = t->toInt (0, BYTE); int maxa = (a & 0xF0) >> 4; - sprintf (buffer, "%.1f", double (int (pow (2.0, double (maxa) / 4.0) + 0.2)) ); + snprintf(buffer, sizeof(buffer), "%.1f", double (int (pow (2.0, double (maxa) / 4.0) + 0.2)) ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -1702,7 +1702,7 @@ public: { char buffer[32]; int b = t->toInt (0, BYTE) & 0x1F; - sprintf (buffer, "%.0f", pow (2., b / 16. + 4) ); + snprintf(buffer, sizeof(buffer), "%.0f", pow (2., b / 16. + 4) ); return buffer; } }; @@ -1788,7 +1788,7 @@ public: return r->second; } else { char buffer[1024]; - t->toString (buffer); + t->toString (buffer, sizeof(buffer)); return std::string (buffer); } } diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index 95b46c2b9..b3d31b950 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -1017,13 +1017,13 @@ Tag::Tag (TagDirectory* p, FILE* f, int base) Tag* tmake = parent->getRoot()->getTag ("Make"); if (tmake) { - tmake->toString (make); + tmake->toString (make, sizeof(make)); } Tag* tmodel = parent->getRoot()->getTag ("Model"); if (tmodel) { - tmodel->toString (model); + tmodel->toString (model, sizeof(model)); } if (!strncmp (make, "SONY", 4)) { @@ -1677,8 +1677,11 @@ void Tag::toRational (int& num, int& denom, int ofs) const } } -void Tag::toString (char* buffer, int ofs) const +void Tag::toString (char* buffer, std::size_t size, int ofs) const { + if (!buffer || !size) { + return; + } if (type == UNDEFINED && !directory) { bool isstring = true; @@ -1690,67 +1693,80 @@ void Tag::toString (char* buffer, int ofs) const } if (isstring) { - int j = 0; + if (size < 3) { + return; + } + + std::size_t j = 0; for (i = 0; i + ofs < count && i < 64 && value[i + ofs]; i++) { if (value[i + ofs] == '<' || value[i + ofs] == '>') { buffer[j++] = '\\'; + if (j > size - 2) { + break; + } } buffer[j++] = value[i + ofs]; + if (j > size - 2) { + break; + } } buffer[j++] = 0; return; } } else if (type == ASCII) { - sprintf (buffer, "%.64s", value + ofs); + snprintf(buffer, size, "%.64s", value + ofs); return; } size_t maxcount = rtengine::min(count, 10); - strcpy (buffer, ""); + buffer[0] = 0; for (ssize_t i = 0; i < rtengine::min(maxcount, valuesize - ofs); i++) { - if (i > 0) { + std::size_t len = strlen(buffer); + + if (i > 0 && size - len > 2) { strcat (buffer, ", "); + len += 2; } - char* b = buffer + strlen (buffer); + char* b = buffer + len; switch (type) { case UNDEFINED: case BYTE: - sprintf (b, "%d", value[i + ofs]); + snprintf(b, size - len, "%d", value[i + ofs]); break; case SSHORT: - sprintf (b, "%d", toInt (2 * i + ofs)); + snprintf(b, size - len, "%d", toInt (2 * i + ofs)); break; case SHORT: - sprintf (b, "%u", toInt (2 * i + ofs)); + snprintf(b, size - len, "%u", toInt (2 * i + ofs)); break; case SLONG: - sprintf (b, "%d", toInt (4 * i + ofs)); + snprintf(b, size - len, "%d", toInt (4 * i + ofs)); break; case LONG: - sprintf (b, "%u", toInt (4 * i + ofs)); + snprintf(b, size - len, "%u", toInt (4 * i + ofs)); break; case SRATIONAL: - sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder())); + snprintf(b, size - len, "%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())); + snprintf(b, size - len, "%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)); + snprintf(b, size - len, "%g", toDouble (8 * i + ofs)); break; default: @@ -1758,7 +1774,7 @@ void Tag::toString (char* buffer, int ofs) const } } - if (count > maxcount) { + if (count > maxcount && size - strlen(buffer) > 3) { strcat (buffer, "..."); } } @@ -1771,7 +1787,7 @@ std::string Tag::nameToString (int i) if (attrib) { strncpy (buffer, attrib->name, 1024); } else { - sprintf (buffer, "0x%x", tag); + snprintf(buffer, sizeof(buffer), "0x%x", tag); } if (i > 0) { @@ -1788,7 +1804,7 @@ std::string Tag::valueToString () const return attrib->interpreter->toString (this); } else { char buffer[1024]; - toString (buffer); + toString (buffer, sizeof(buffer)); return buffer; } } @@ -2763,7 +2779,7 @@ parse_leafdata (TagDirectory* root, ByteOrder order) &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) { char tstr[64]; - sprintf (tstr, "%04d:%02d:%02d %02d:%02d:%02d", tm.tm_year, tm.tm_mon, + snprintf(tstr, sizeof(tstr), "%04d:%02d:%02d %02d:%02d:%02d", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); t->initString (tstr); exif->getDirectory()->addTagFront (t); @@ -3059,19 +3075,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) { @@ -3253,7 +3264,43 @@ int ExifManager::createJPEGMarker (const TagDirectory* root, const rtengine::pro TagDirectory* cl; if (root) { - cl = (const_cast (root))->clone (nullptr); + cl = root->clone(nullptr); + + // Drop unwanted tags before exporting + // For example, Nikon Z-series has a 52Kb MakerNotes->ShotInfo tag + // which does not fit into the 65Kb limit on JPEG exif tags + const Tag* const make_tag = cl->getTag(271); + if (make_tag && !std::strncmp((const char*)make_tag->getValue(), "NIKON CORPORATION", 17)) { + [cl]() + { + Tag* const exif_tag = cl->getTag(34665); + if (!exif_tag) { + return; + } + + TagDirectory* const exif_dir = exif_tag->getDirectory(); + if (!exif_dir) { + return; + } + + Tag* const make_notes_tag = exif_dir->getTag(37500); + if (!make_notes_tag) { + return; + } + + TagDirectory* const maker_notes_dir = make_notes_tag->getDirectory(); + if (!maker_notes_dir) { + return; + } + + Tag* const shot_info_tag = maker_notes_dir->getTag(145); + if (!shot_info_tag) { + return; + } + + shot_info_tag->setKeep(false); + }(); + } } else { cl = new TagDirectory (nullptr, ifdAttribs, INTEL); } diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index 5084f70de..dd89b70ce 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -304,7 +304,7 @@ public: double toDouble (int ofs = 0) const; double* toDoubleArray (int ofs = 0) const; void toRational (int& num, int& denom, int ofs = 0) const; - void toString (char* buffer, int ofs = 0) const; + void toString (char* buffer, std::size_t size, int ofs = 0) const; void fromString (const char* v, int size = -1); void setInt (int v, int ofs = 0, TagType astype = LONG); int getDistanceFrom (const TagDirectory *root); @@ -392,7 +392,7 @@ public: virtual std::string toString (const Tag* t) const { char buffer[1024]; - t->toString (buffer); + t->toString (buffer, sizeof(buffer)); std::string s (buffer); std::string::size_type p1 = s.find_first_not_of (' '); @@ -526,7 +526,7 @@ public: return r->second; } else { char buffer[1024]; - t->toString(buffer); + t->toString(buffer, sizeof(buffer)); return buffer; } } diff --git a/rtexif/sonyminoltaattribs.cc b/rtexif/sonyminoltaattribs.cc index 4c901b8c0..95aea1252 100644 --- a/rtexif/sonyminoltaattribs.cc +++ b/rtexif/sonyminoltaattribs.cc @@ -1098,6 +1098,7 @@ public: choices.insert (p_t (32853, "Sony E 16-55mm f/2.8 G")); choices.insert (p_t (32854, "Sony E 70-350mm f/4.5-6.3 G OSS")); choices.insert (p_t (32858, "Sony FE 35mm f/1.8")); + choices.insert (p_t (32859, "Sony FE 20mm f/1.8 G")); choices.insert (p_t (33072, "Sony FE 70-200mm f/2.8 GM OSS + 1.4X Teleconverter")); choices.insert (p_t (33073, "Sony FE 70-200mm f/2.8 GM OSS + 2X Teleconverter")); choices.insert (p_t (33076, "Sony FE 100mm f/2.8 STF GM OSS (macro mode)")); @@ -1127,6 +1128,8 @@ public: choices.insert (p_t (49459, "Tamron 35mm f/2.8 Di III OSD M1:2")); choices.insert (p_t (49460, "Tamron 24mm f/2.8 Di III OSD M1:2")); choices.insert (p_t (49461, "Tamron 20mm f/2.8 Di III OSD M1:2")); + choices.insert (p_t (49462, "Tamron 70-180mm f/2.8 Di III VXD")); + choices.insert (p_t (49463, "Tamron 28-200mm f/2.8-5.6 Di III RXD")); choices.insert (p_t (49712, "Tokina FiRIN 20mm f/2 FE AF")); choices.insert (p_t (49713, "Tokina FiRIN 100mm f/2.8 FE MACRO")); choices.insert (p_t (50480, "Sigma 30mm f/1.4 DC DN | C")); @@ -1154,6 +1157,7 @@ public: choices.insert (p_t (50515, "Sigma 35mm f/1.2 DG DN | A")); choices.insert (p_t (50516, "Sigma 14-24mm f/2.8 DG DN | A")); choices.insert (p_t (50517, "Sigma 24-70mm f/2.8 DG DN | A")); + choices.insert (p_t (50518, "Sigma 100-400mm f/5-6.3 DG DN OS")); choices.insert (p_t (50992, "Voigtlander SUPER WIDE-HELIAR 15mm f/4.5 III")); choices.insert (p_t (50993, "Voigtlander HELIAR-HYPER WIDE 10mm f/5.6")); choices.insert (p_t (50994, "Voigtlander ULTRA WIDE-HELIAR 12mm f/5.6 III")); @@ -1165,12 +1169,14 @@ public: choices.insert (p_t (51000, "Voigtlander NOKTON 50mm f/1.2 Aspherical")); choices.insert (p_t (51001, "Voigtlander NOKTON 21mm f/1.4 Aspherical")); choices.insert (p_t (51002, "Voigtlander APO-LANTHAR 50mm f/2 Aspherical")); + choices.insert (p_t (51003, "Voigtlander NOKTON 35mm f/1.2 Aspherical SE")); choices.insert (p_t (51504, "Samyang AF 50mm f/1.4")); choices.insert (p_t (51505, "Samyang AF 14mm f/2.8 or Samyang AF 35mm f/2.8")); choices.insert (p_t (51505, "Samyang AF 35mm f/2.8")); choices.insert (p_t (51507, "Samyang AF 35mm f/1.4")); choices.insert (p_t (51508, "Samyang AF 45mm f/1.8")); choices.insert (p_t (51510, "Samyang AF 18mm f/2.8")); + choices.insert (p_t (51512, "Samyang AF 75mm f/1.8")); } std::string toString (const Tag* t) const override @@ -1973,7 +1979,7 @@ public: if (a > 0) { char buffer[32]; - sprintf (buffer, "%.4f", a); + snprintf(buffer, sizeof(buffer), "%.4f", a); return buffer; } else { return "n/a"; @@ -2033,7 +2039,7 @@ public: if (a) { char buffer[32]; - sprintf (buffer, "%.1f", a / 100. ); + snprintf(buffer, sizeof(buffer), "%.1f", a / 100. ); return buffer; } else { return "n/a"; @@ -2093,7 +2099,7 @@ public: if (a) { char buffer[32]; - sprintf (buffer, "%d", a ); + snprintf(buffer, sizeof(buffer), "%d", a ); return buffer; } else { return "Auto"; @@ -2132,7 +2138,7 @@ public: { double a = t->toDouble(); char buffer[32]; - sprintf (buffer, "%.2f", a ); + snprintf(buffer, sizeof(buffer), "%.2f", a ); return buffer; } double toDouble (const Tag* t, int ofs) override @@ -2152,7 +2158,7 @@ public: std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%d", t->getValue()[0] - 20); + snprintf(buffer, sizeof(buffer), "%d", t->getValue()[0] - 20); return buffer; } int toInt (const Tag* t, int ofs, TagType astype) override @@ -2191,7 +2197,7 @@ public: std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%d", t->getValue()[0] & 0x7f); + snprintf(buffer, sizeof(buffer), "%d", t->getValue()[0] & 0x7f); return buffer; } int toInt (const Tag* t, int ofs, TagType astype) override @@ -2247,7 +2253,7 @@ public: std::string toString (const Tag* t) const override { char buffer[32]; - sprintf (buffer, "%d", t->toInt()); + snprintf(buffer, sizeof(buffer), "%d", t->toInt()); return buffer; } int toInt (const Tag* t, int ofs, TagType astype) override diff --git a/rtexif/stdattribs.cc b/rtexif/stdattribs.cc index be7a28a5c..e6e3bb35b 100644 --- a/rtexif/stdattribs.cc +++ b/rtexif/stdattribs.cc @@ -334,7 +334,7 @@ public: return "undef"; } - sprintf (buffer, "%0.1f", v); + snprintf(buffer, sizeof(buffer), "%0.1f", v); return buffer; } }; @@ -353,7 +353,7 @@ public: return "undef"; } - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } }; @@ -372,7 +372,7 @@ public: return "undef"; } - sprintf (buffer, "%+0.2f", v ); + snprintf(buffer, sizeof(buffer), "%+0.2f", v ); return buffer; } }; @@ -388,9 +388,9 @@ public: double d = pow (2.0, -t->toDouble()); if (d > 0.0 && d <= 0.5) { - sprintf (buffer, "1/%.0f", 1.0 / d); + snprintf(buffer, sizeof(buffer), "1/%.0f", 1.0 / d); } else { - sprintf (buffer, "%.1f", d); + snprintf(buffer, sizeof(buffer), "%.1f", d); } return buffer; @@ -408,9 +408,9 @@ public: double d = t->toDouble(); if (d > 0.0 && d <= 0.5) { - sprintf (buffer, "1/%.0f", 1.0 / d); + snprintf(buffer, sizeof(buffer), "1/%.0f", 1.0 / d); } else { - sprintf (buffer, "%.1f", d); + snprintf(buffer, sizeof(buffer), "%.1f", d); } return buffer; @@ -431,7 +431,7 @@ public: return "undef"; } - sprintf (buffer, "%.1f", v ); + snprintf(buffer, sizeof(buffer), "%.1f", v ); return buffer; } }; @@ -637,7 +637,7 @@ public: int lastSegmentWidth = t->toInt(4, SHORT); char buffer[32]; - sprintf (buffer, "%d %d %d", segmentNumber, segmentWidth, lastSegmentWidth); + snprintf(buffer, sizeof(buffer), "%d %d %d", segmentNumber, segmentWidth, lastSegmentWidth); return buffer; } }; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 2fdc7f374..e0ec2c9cb 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -34,6 +34,8 @@ set(NONCLISOURCEFILES colorappearance.cc coloredbar.cc colortoning.cc + controllines.cc + controlspotpanel.cc coordinateadjuster.cc crop.cc crophandler.cc @@ -90,6 +92,9 @@ set(NONCLISOURCEFILES lensgeom.cc lensprofile.cc localcontrast.cc + locallab.cc + locallabtools.cc + locallabtools2.cc lockablecolorpicker.cc lwbutton.cc lwbuttonset.cc diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 7a267bb02..6f68c6ae7 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -18,6 +18,12 @@ enum { ADDSET_ROTATE_DEGREE, ADDSET_DIST_AMOUNT, ADDSET_PERSPECTIVE, + ADDSET_PERSP_CAM_ANGLE, + ADDSET_PERSP_CAM_FOCAL_LENGTH, + ADDSET_PERSP_CAM_SHIFT, + ADDSET_PERSP_PROJ_ANGLE, + ADDSET_PERSP_PROJ_ROTATE, + ADDSET_PERSP_PROJ_SHIFT, ADDSET_CA, ADDSET_VIGN_AMOUNT, ADDSET_VIGN_RADIUS, diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc index 142374213..6f8c0e83a 100644 --- a/rtgui/adjuster.cc +++ b/rtgui/adjuster.cc @@ -36,7 +36,7 @@ double one2one(double val) } } -Adjuster::Adjuster ( +Adjuster::Adjuster( Glib::ustring vlabel, double vmin, double vmax, @@ -45,21 +45,20 @@ Adjuster::Adjuster ( Gtk::Image *imgIcon1, Gtk::Image *imgIcon2, double2double_fun slider2value, - double2double_fun value2slider) - - : - + double2double_fun value2slider +) : adjustmentName(std::move(vlabel)), grid(nullptr), label(nullptr), imageIcon1(imgIcon1), automatic(nullptr), adjusterListener(nullptr), + spinChange(options.adjusterMinDelay, options.adjusterMaxDelay), + sliderChange(options.adjusterMinDelay, options.adjusterMaxDelay), editedCheckBox(nullptr), afterReset(false), blocked(false), addMode(false), - eventPending(false), vMin(vmin), vMax(vmax), vStep(vstep), @@ -67,8 +66,7 @@ Adjuster::Adjuster ( logPivot(0), logAnchorMiddle(false), value2slider(value2slider ? value2slider : &one2one), - slider2value(slider2value ? slider2value : &one2one), - delay(options.adjusterMinDelay) + slider2value(slider2value ? slider2value : &one2one) { set_hexpand(true); @@ -155,8 +153,27 @@ Adjuster::Adjuster ( defaultVal = ctorDefaultVal = shapeValue(vdefault); editedState = defEditedState = Irrelevant; - sliderChange = slider->signal_value_changed().connect( sigc::mem_fun(*this, &Adjuster::sliderChanged) ); - spinChange = spin->signal_value_changed().connect( sigc::mem_fun(*this, &Adjuster::spinChanged), true); + spinChange.connect( + spin->signal_value_changed(), + sigc::mem_fun(*this, &Adjuster::spinChanged), + [this]() + { + sliderChange.block(true); + setSliderValue(addMode ? spin->get_value() : this->value2slider(spin->get_value())); + sliderChange.block(false); + } + ); + sliderChange.connect( + slider->signal_value_changed(), + sigc::mem_fun(*this, &Adjuster::sliderChanged), + [this]() + { + spinChange.block(); + const double v = shapeValue(getSliderValue()); + spin->set_value(addMode ? v : this->slider2value(v)); + spinChange.unblock(); + } + ); reset->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &Adjuster::resetPressed) ); show_all(); @@ -165,9 +182,8 @@ Adjuster::Adjuster ( Adjuster::~Adjuster () { - sliderChange.block(true); - spinChange.block(true); - delayConnection.block(true); + sliderChange.block(); + spinChange.block(); adjusterListener = nullptr; } @@ -211,8 +227,6 @@ void Adjuster::throwOnButtonRelease(bool throwOnBRelease) buttonReleaseSpin.disconnect(); } } - - eventPending = false; } void Adjuster::setDefault (double def) @@ -239,9 +253,7 @@ void Adjuster::sliderReleased (GdkEventButton* event) { if ((event != nullptr) && (event->button == 1)) { - if (delayConnection.connected()) { - delayConnection.disconnect(); - } + sliderChange.cancel(); notifyListener(); } @@ -250,10 +262,8 @@ void Adjuster::sliderReleased (GdkEventButton* event) void Adjuster::spinReleased (GdkEventButton* event) { - if ((event != nullptr) && delay == 0) { - if (delayConnection.connected()) { - delayConnection.disconnect(); - } + if (event) { + spinChange.cancel(); notifyListener(); } @@ -351,31 +361,15 @@ void Adjuster::setAddMode(bool addM) } } -void Adjuster::spinChanged () +void Adjuster::spinChanged() { - if (delayConnection.connected()) { - delayConnection.disconnect(); - } - - sliderChange.block(true); - setSliderValue(addMode ? spin->get_value() : value2slider(spin->get_value())); - sliderChange.block(false); - - if (delay == 0) { - if (adjusterListener && !blocked) { - if (!buttonReleaseSlider.connected() || afterReset) { - eventPending = false; - if (automatic) { - setAutoValue(false); - } - adjusterListener->adjusterChanged(this, spin->get_value()); - } else { - eventPending = true; + if (adjusterListener && !blocked) { + if (!buttonReleaseSlider.connected() || afterReset) { + if (automatic) { + setAutoValue(false); } + adjusterListener->adjusterChanged(this, spin->get_value()); } - } else { - eventPending = true; - delayConnection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Adjuster::notifyListener), delay); } if (editedState == UnEdited) { @@ -393,31 +387,13 @@ void Adjuster::spinChanged () void Adjuster::sliderChanged () { - - if (delayConnection.connected()) { - delayConnection.disconnect(); - } - - spinChange.block(true); - const double v = shapeValue(getSliderValue()); - spin->set_value(addMode ? v : slider2value(v)); - spinChange.block(false); - - if (delay == 0 || afterReset) { - if (adjusterListener && !blocked) { - if (!buttonReleaseSlider.connected() || afterReset) { - eventPending = false; - if (automatic) { - setAutoValue(false); - } - adjusterListener->adjusterChanged(this, spin->get_value()); - } else { - eventPending = true; + if (adjusterListener && !blocked) { + if (!buttonReleaseSlider.connected() || afterReset) { + if (automatic) { + setAutoValue(false); } + adjusterListener->adjusterChanged(this, spin->get_value()); } - } else { - eventPending = true; - delayConnection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Adjuster::notifyListener), delay); } if (!afterReset && editedState == UnEdited) { @@ -435,12 +411,12 @@ void Adjuster::sliderChanged () void Adjuster::setValue (double a) { - spinChange.block(true); + spinChange.block(); sliderChange.block(true); spin->set_value(shapeValue(a)); setSliderValue(addMode ? shapeValue(a) : value2slider(shapeValue(a))); sliderChange.block(false); - spinChange.block(false); + spinChange.unblock(); afterReset = false; } @@ -455,16 +431,13 @@ void Adjuster::setAutoValue (bool a) bool Adjuster::notifyListener () { - - if (eventPending && adjusterListener != nullptr && !blocked) { + if (adjusterListener != nullptr && !blocked) { if (automatic) { setAutoValue(false); } adjusterListener->adjusterChanged(this, spin->get_value()); } - eventPending = false; - return false; } @@ -555,8 +528,6 @@ void Adjuster::editedToggled () } adjusterListener->adjusterChanged(this, spin->get_value()); } - - eventPending = false; } void Adjuster::trimValue (double &val) const @@ -706,3 +677,9 @@ bool Adjuster::getAddMode() const { return addMode; } + +void Adjuster::setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms) +{ + spinChange.setDelay(min_delay_ms, max_delay_ms); + sliderChange.setDelay(min_delay_ms, max_delay_ms); +} diff --git a/rtgui/adjuster.h b/rtgui/adjuster.h index 143268786..abafbd730 100644 --- a/rtgui/adjuster.h +++ b/rtgui/adjuster.h @@ -19,6 +19,7 @@ #pragma once #include "editedstate.h" +#include "delayed.h" #include "guiutils.h" class Adjuster; @@ -35,7 +36,6 @@ typedef double(*double2double_fun)(double val); class Adjuster final : public Gtk::Grid { - protected: Glib::ustring adjustmentName; Gtk::Grid* grid; @@ -46,9 +46,8 @@ protected: Gtk::Button* reset; Gtk::CheckButton* automatic; AdjusterListener* adjusterListener; - sigc::connection delayConnection; - sigc::connection spinChange; - sigc::connection sliderChange; + DelayedConnection<> spinChange; + DelayedConnection<> sliderChange; sigc::connection editedChange; sigc::connection autoChange; sigc::connection buttonReleaseSlider; @@ -62,7 +61,6 @@ protected: bool afterReset; bool blocked; bool addMode; - bool eventPending; double vMin; double vMax; double vStep; @@ -78,11 +76,18 @@ protected: void setSliderValue(double val); public: - - int delay; - - Adjuster (Glib::ustring vlabel, double vmin, double vmax, double vstep, double vdefault, Gtk::Image *imgIcon1 = nullptr, Gtk::Image *imgIcon2 = nullptr, double2double_fun slider2value = nullptr, double2double_fun value2slider = nullptr); - ~Adjuster () override; + Adjuster( + Glib::ustring vlabel, + double vmin, + double vmax, + double vstep, + double vdefault, + Gtk::Image *imgIcon1 = nullptr, + Gtk::Image *imgIcon2 = nullptr, + double2double_fun slider2value = nullptr, + double2double_fun value2slider = nullptr + ); + ~Adjuster() override; // Add an "Automatic" checkbox next to the reset button. void addAutoButton(const Glib::ustring &tooltip = ""); @@ -127,4 +132,5 @@ public: void trimValue (float &val) const; void trimValue (int &val) const; void setLogScale(double base, double pivot, bool anchorMiddle = false); + void setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms = 0); }; diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 8b4583877..19da96fb5 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -344,8 +344,9 @@ bool BatchQueue::loadBatchQueue () auto job = rtengine::ProcessingJob::create (source, thumb->getType () == FT_Raw, pparams, fast); - const auto prevh = getMaxThumbnailHeight (); - const auto prevw = thumb->getThumbnailWidth(prevh, &pparams); + auto prevh = getMaxThumbnailHeight(); + auto prevw = prevh; + thumb->getThumbnailSize(prevw, prevh, &pparams); auto entry = new BatchQueueEntry (job, pparams, source, prevw, prevh, thumb, options.overwriteOutputFile); thumb->decreaseRef (); // Removing the refCount acquired by cacheMgr->getEntry @@ -390,7 +391,7 @@ Glib::ustring BatchQueue::getTempFilenameForParams( const Glib::ustring &filenam timeval tv; gettimeofday(&tv, nullptr); char mseconds[11]; - sprintf(mseconds, "%d", (int)(tv.tv_usec / 1000)); + snprintf(mseconds, sizeof(mseconds), "%d", (int)(tv.tv_usec / 1000)); time_t rawtime; struct tm *timeinfo; char stringTimestamp [80]; @@ -699,7 +700,7 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) err = img->saveAsJPEG (fname, saveFormat.jpegQuality, saveFormat.jpegSubSamp); } - img->free (); + delete img; if (err) { throw Glib::FileError(Glib::FileError::FAILED, M("MAIN_MSG_CANNOTSAVE") + "\n" + fname); diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 90079b2cc..31a6f40c7 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -106,8 +106,12 @@ void BatchQueueEntry::refreshThumbnailImage () void BatchQueueEntry::calcThumbnailSize () { - prew = preh * origpw / origph; + if (prew > options.maxThumbnailWidth) { + const float s = static_cast(options.maxThumbnailWidth) / prew; + prew = options.maxThumbnailWidth; + preh = std::max(preh * s, 1); + } } @@ -261,9 +265,8 @@ void BatchQueueEntry::_updateImage (guint8* img, int w, int h) MYWRITERLOCK(l, lockRW); prew = w; - assert (preview == nullptr); - preview = new guint8 [prew * preh * 3]; - memcpy (preview, img, prew * preh * 3); + preview.resize(prew * preh * 3); + std::copy(img, img + preview.size(), preview.begin()); if (parent) { parent->redrawNeeded (this); diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index a61264d94..9e74ddb90 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); @@ -151,7 +152,7 @@ void BatchToolPanelCoordinator::initSession () rotate->setAdjusterBehavior (false); resize->setAdjusterBehavior (false); distortion->setAdjusterBehavior (false); - perspective->setAdjusterBehavior (false); + perspective->setAdjusterBehavior (false, false, false, false, false, false, false); gradient->setAdjusterBehavior (false, false, false, false); pcvignette->setAdjusterBehavior (false, false, false); cacorrection->setAdjusterBehavior (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]); @@ -196,7 +197,7 @@ void BatchToolPanelCoordinator::initSession () rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); resize->setAdjusterBehavior (options.baBehav[ADDSET_RESIZE_SCALE]); distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); - perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE]); + perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE], options.baBehav[ADDSET_PERSP_CAM_FOCAL_LENGTH], options.baBehav[ADDSET_PERSP_CAM_SHIFT], options.baBehav[ADDSET_PERSP_CAM_ANGLE], options.baBehav[ADDSET_PERSP_PROJ_ANGLE], options.baBehav[ADDSET_PERSP_PROJ_SHIFT], options.baBehav[ADDSET_PERSP_PROJ_ROTATE]); gradient->setAdjusterBehavior (options.baBehav[ADDSET_GRADIENT_DEGREE], options.baBehav[ADDSET_GRADIENT_FEATHER], options.baBehav[ADDSET_GRADIENT_STRENGTH], options.baBehav[ADDSET_GRADIENT_CENTER]); pcvignette->setAdjusterBehavior (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH], options.baBehav[ADDSET_PCVIGNETTE_FEATHER], options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]); cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA]); @@ -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]); @@ -308,6 +309,12 @@ void BatchToolPanelCoordinator::initSession () if (options.baBehav[ADDSET_RESIZE_SCALE]) { pparams.resize.scale = 0; } if (options.baBehav[ADDSET_DIST_AMOUNT]) { pparams.distortion.amount = 0; } if (options.baBehav[ADDSET_PERSPECTIVE]) { pparams.perspective.horizontal = pparams.perspective.vertical = 0; } + if (options.baBehav[ADDSET_PERSP_CAM_FOCAL_LENGTH]) { pparams.perspective.camera_focal_length = pparams.perspective.camera_crop_factor = 0; } + if (options.baBehav[ADDSET_PERSP_CAM_SHIFT]) { pparams.perspective.camera_shift_horiz = pparams.perspective.camera_shift_vert = 0; } + if (options.baBehav[ADDSET_PERSP_CAM_ANGLE]) { pparams.perspective.camera_yaw = pparams.perspective.camera_pitch = 0; } + if (options.baBehav[ADDSET_PERSP_PROJ_ANGLE]) { pparams.perspective.projection_yaw = pparams.perspective.projection_pitch = 0; } + if (options.baBehav[ADDSET_PERSP_PROJ_SHIFT]) { pparams.perspective.projection_shift_horiz = pparams.perspective.projection_shift_vert = 0; } + if (options.baBehav[ADDSET_PERSP_PROJ_ROTATE]) { pparams.perspective.projection_rotate = 0; } if (options.baBehav[ADDSET_GRADIENT_DEGREE]) { pparams.gradient.degree = 0; } if (options.baBehav[ADDSET_GRADIENT_FEATHER]) { pparams.gradient.feather = 0; } if (options.baBehav[ADDSET_GRADIENT_STRENGTH]) { pparams.gradient.strength = 0; } @@ -392,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) @@ -405,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++) { @@ -417,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); } @@ -425,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) { @@ -447,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; @@ -489,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; @@ -607,13 +618,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); } } @@ -624,7 +635,7 @@ void BatchToolPanelCoordinator::endBatchPParamsChange() closeSession (false); initSession (); blockedUpdate = false; - parent->set_sensitive(true); + parent->set_sensitive (true); } /* @@ -646,7 +657,7 @@ void BatchToolPanelCoordinator::profileChange( return; } - pparams = *(nparams->pparams); + pparams = * (nparams->pparams); if (paramsEdited) { pparamsEdited = *paramsEdited; diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index 0c01213e7..2a1896d80 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -37,18 +37,14 @@ BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, "bayerpreprocess", lineDenoise = Gtk::manage(new Adjuster(M("TP_PREPROCESS_LINEDENOISE"), 0, 1000, 1, 0)); lineDenoise->setAdjusterListener(this); - if (lineDenoise->delay < options.adjusterMaxDelay) { - lineDenoise->delay = options.adjusterMaxDelay; - } + lineDenoise->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); lineDenoise->show(); greenEqThreshold = Gtk::manage(new Adjuster(M("TP_PREPROCESS_GREENEQUIL"), 0, 100, 1, 0)); greenEqThreshold->setAdjusterListener(this); - if (greenEqThreshold->delay < options.adjusterMaxDelay) { - greenEqThreshold->delay = options.adjusterMaxDelay; - } + greenEqThreshold->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); greenEqThreshold->show(); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 5b5cfe9c4..d219dbdd1 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(); @@ -58,9 +60,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA dualDemosaicContrast->setAdjusterListener(this); dualDemosaicContrast->addAutoButton(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP")); dualDemosaicContrast->setAutoValue(true); - if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { - dualDemosaicContrast->delay = options.adjusterMaxDelay; - } + dualDemosaicContrast->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); dualDemosaicContrast->show(); dualDemosaicOptions->pack_start(*dualDemosaicContrast); @@ -70,9 +70,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA border = Gtk::manage(new Adjuster(M("TP_RAW_BORDER"), 0, 16, 1, 4)); border->setAdjusterListener (this); - if (border->delay < options.adjusterMaxDelay) { - border->delay = options.adjusterMaxDelay; - } + border->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); border->show(); borderbox->pack_start(*border); @@ -94,22 +92,17 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); ccSteps->setAdjusterListener (this); - if (ccSteps->delay < options.adjusterMaxDelay) { - ccSteps->delay = options.adjusterMaxDelay; - } + ccSteps->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); ccSteps->show(); pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); - dcbOptions = Gtk::manage (new Gtk::VBox ()); dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"), 0, 5, 1, 2)); dcbIterations->setAdjusterListener (this); - if (dcbIterations->delay < options.adjusterMaxDelay) { - dcbIterations->delay = options.adjusterMaxDelay; - } + dcbIterations->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); dcbIterations->show(); dcbEnhance = Gtk::manage (new CheckBox(M("TP_RAW_DCBENHANCE"), multiImage)); @@ -124,9 +117,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA lmmseIterations->setAdjusterListener (this); lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); - if (lmmseIterations->delay < options.adjusterMaxDelay) { - lmmseIterations->delay = options.adjusterMaxDelay; - } + lmmseIterations->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); lmmseIterations->show(); lmmseOptions->pack_start(*lmmseIterations); @@ -207,9 +198,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftSigma->set_tooltip_text (M("TP_RAW_PIXELSHIFTSIGMA_TOOLTIP")); pixelShiftSigma->setAdjusterListener (this); - if (pixelShiftSigma->delay < options.adjusterMaxDelay) { - pixelShiftSigma->delay = options.adjusterMaxDelay; - } + pixelShiftSigma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); pixelShiftSigma->show(); pixelShiftOptions->pack_start(*pixelShiftSigma); @@ -219,9 +208,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftSmooth->set_tooltip_text (M("TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP")); pixelShiftSmooth->setAdjusterListener (this); - if (pixelShiftSmooth->delay < options.adjusterMaxDelay) { - pixelShiftSmooth->delay = options.adjusterMaxDelay; - } + pixelShiftSmooth->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); pixelShiftSmooth->show(); pixelShiftOptions->pack_start(*pixelShiftSmooth); @@ -230,9 +217,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pixelShiftEperIso->set_tooltip_text(M("TP_RAW_PIXELSHIFTEPERISO_TOOLTIP")); pixelShiftEperIso->setAdjusterListener (this); - if (pixelShiftEperIso->delay < options.adjusterMaxDelay) { - pixelShiftEperIso->delay = options.adjusterMaxDelay; - } + pixelShiftEperIso->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); pixelShiftEperIso->show(); pixelShiftOptions->pack_start(*pixelShiftEperIso); @@ -364,7 +349,10 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params dcbOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCB) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4)); lmmseOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::LMMSE)); dualDemosaicOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4) + || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEBILINEAR) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) + || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBBILINEAR) + || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4)); if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::PIXELSHIFT)) { pixelShiftOptions->set_visible(pp->raw.bayersensor.pixelShiftMotionCorrectionMethod == RAWParams::BayerSensor::PSMotionCorrectionMethod::CUSTOM); @@ -573,7 +561,12 @@ void BayerProcess::methodChanged () lmmseOptions->hide(); } - if (currentMethod == procparams::RAWParams::BayerSensor::Method::AMAZEVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::DCBVNG4 || currentMethod == procparams::RAWParams::BayerSensor::Method::RCDVNG4) { + if (currentMethod == procparams::RAWParams::BayerSensor::Method::AMAZEVNG4 || + currentMethod == procparams::RAWParams::BayerSensor::Method::DCBVNG4 || + currentMethod == procparams::RAWParams::BayerSensor::Method::RCDVNG4 || + currentMethod == procparams::RAWParams::BayerSensor::Method::AMAZEBILINEAR || + currentMethod == procparams::RAWParams::BayerSensor::Method::DCBBILINEAR || + currentMethod == procparams::RAWParams::BayerSensor::Method::RCDBILINEAR) { dualDemosaicOptions->show(); } else { dualDemosaicOptions->hide(); diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index 9d8f9fff8..bb3c3a48a 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -31,33 +31,25 @@ BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposur PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"), -2048, 2048, 1.0, 0)); //black level PexBlack1->setAdjusterListener (this); - if (PexBlack1->delay < options.adjusterMaxDelay) { - PexBlack1->delay = options.adjusterMaxDelay; - } + PexBlack1->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlack1->show(); PexBlack2 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_2"), -2048, 2048, 1.0, 0)); //black level PexBlack2->setAdjusterListener (this); - if (PexBlack2->delay < options.adjusterMaxDelay) { - PexBlack2->delay = options.adjusterMaxDelay; - } + PexBlack2->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlack2->show(); PexBlack3 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_3"), -2048, 2048, 1.0, 0)); //black level PexBlack3->setAdjusterListener (this); - if (PexBlack3->delay < options.adjusterMaxDelay) { - PexBlack3->delay = options.adjusterMaxDelay; - } + PexBlack3->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlack3->show(); PexBlack0 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_0"), -2048, 2048, 1.0, 0)); //black level PexBlack0->setAdjusterListener (this); - if (PexBlack0->delay < options.adjusterMaxDelay) { - PexBlack0->delay = options.adjusterMaxDelay; - } + PexBlack0->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlack0->show(); PextwoGreen = Gtk::manage(new CheckBox(M("TP_RAWEXPOS_TWOGREEN"), multiImage));// two green diff --git a/rtgui/bqentryupdater.cc b/rtgui/bqentryupdater.cc index 61683e158..7115447c2 100644 --- a/rtgui/bqentryupdater.cc +++ b/rtgui/bqentryupdater.cc @@ -146,7 +146,7 @@ void BatchQueueEntryUpdater::processThread () } memcpy(current.oimg, img->getData(), prevw * prevh * 3); - img->free(); + delete img; } } 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/colorappearance.cc b/rtgui/colorappearance.cc index bdbe3de3a..b4d5459ce 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -222,11 +222,35 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" Evcatpreset = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_CAT02PRESET"); EvCATAutotempout = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_TEMPOUT"); EvCATillum = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ILLUM"); + EvCATcomplex = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_CATCOMPLEX"); //preset button cat02 + Gtk::Frame *genFrame; + Gtk::VBox *genVBox; + genFrame = Gtk::manage (new Gtk::Frame (M ("TP_COLORAPP_GEN")) ); + genFrame->set_label_align (0.025, 0.5); + genFrame->set_tooltip_markup (M ("TP_COLORAPP_GEN_TOOLTIP")); + genVBox = Gtk::manage ( new Gtk::VBox()); + genVBox->set_spacing (2); + + complexmethod = Gtk::manage (new MyComboBoxText ()); + complexmethod->append(M("TP_WAVELET_COMPNORMAL")); + complexmethod->append(M("TP_WAVELET_COMPEXPERT")); + complexmethodconn = complexmethod->signal_changed().connect(sigc::mem_fun(*this, &ColorAppearance::complexmethodChanged)); + complexmethod->set_tooltip_text(M("TP_WAVELET_COMPLEX_TOOLTIP")); + Gtk::HBox* const complexHBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const complexLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_COMPLEXLAB") + ":")); + complexHBox->pack_start(*complexLabel, Gtk::PACK_SHRINK, 4); + complexHBox->pack_start(*complexmethod); + genVBox->pack_start (*complexHBox, Gtk::PACK_SHRINK); + + presetcat02 = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_PRESETCAT02"))); presetcat02->set_tooltip_markup (M("TP_COLORAPP_PRESETCAT02_TIP")); presetcat02conn = presetcat02->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::presetcat02pressed)); - pack_start (*presetcat02, Gtk::PACK_SHRINK); + genVBox->pack_start (*presetcat02, Gtk::PACK_SHRINK); + + genFrame->add (*genVBox); + pack_start (*genFrame, Gtk::PACK_EXPAND_WIDGET, 4); // ----------------------- Process #1: Converting to CIECAM @@ -238,15 +262,14 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" p1Frame = Gtk::manage (new Gtk::Frame (M ("TP_COLORAPP_LABEL_SCENE")) ); p1Frame->set_label_align (0.025, 0.5); - + p1Frame->set_tooltip_markup (M ("TP_COLORAPP_SOURCEF_TOOLTIP")); p1VBox = Gtk::manage ( new Gtk::VBox()); p1VBox->set_spacing (2); degree = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREE"), 0., 100., 1., 90.)); + degree->set_tooltip_markup (M ("TP_COLORAPP_DEGREE_TOOLTIP")); - if (degree->delay < options.adjusterMaxDelay) { - degree->delay = options.adjusterMaxDelay; - } + degree->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); degree->throwOnButtonRelease(); degree->addAutoButton (M ("TP_COLORAPP_CAT02ADAPTATION_TOOLTIP")); @@ -258,8 +281,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" Gtk::HBox* surrHBox1 = Gtk::manage (new Gtk::HBox ()); surrHBox1->set_spacing (2); - surrHBox1->set_tooltip_markup (M ("TP_COLORAPP_SURROUND_TOOLTIP")); - Gtk::Label* surrLabel1 = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_SURROUND") + ":")); + surrHBox1->set_tooltip_markup (M ("TP_COLORAPP_SURSOURCE_TOOLTIP")); + Gtk::Label* surrLabel1 = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_SURROUNDSRC") + ":")); surrHBox1->pack_start (*surrLabel1, Gtk::PACK_SHRINK); surrsrc = Gtk::manage (new MyComboBoxText ()); surrsrc->append (M ("TP_COLORAPP_SURROUND_AVER")); @@ -272,7 +295,11 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" // p1VBox->pack_start (*surrsource, Gtk::PACK_SHRINK); - Gtk::HBox* wbmHBox = Gtk::manage (new Gtk::HBox ()); + + +// Gtk::HBox* wbmHBox = Gtk::manage (new Gtk::HBox ()); + wbmHBox = Gtk::manage (new Gtk::HBox ()); + wbmHBox->set_spacing (2); wbmHBox->set_tooltip_markup (M ("TP_COLORAPP_MODEL_TOOLTIP")); Gtk::Label* wbmLab = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_MODEL") + ":")); @@ -287,7 +314,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" p1VBox->pack_start (*wbmHBox); - Gtk::HBox* illumHBox = Gtk::manage (new Gtk::HBox ()); +// Gtk::HBox* illumHBox = Gtk::manage (new Gtk::HBox ()); + illumHBox = Gtk::manage (new Gtk::HBox ()); illumHBox->set_spacing (2); illumHBox->set_tooltip_markup (M ("TP_COLORAPP_ILLUM_TOOLTIP")); Gtk::Label* illumLab = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_ILLUM") + ":")); @@ -325,19 +353,17 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" // adapscen = Gtk::manage (new Adjuster (M ("TP_COLORAPP_ABSOLUTELUMINANCE"), 0.01, 16384., 0.001, 2000.)); // EV -7 ==> EV 17 adapscen = Gtk::manage (new Adjuster (M ("TP_COLORAPP_ABSOLUTELUMINANCE"), MINLA0, MAXLA0, 0.01, 1997.4, NULL, NULL, &wbSlider2la, &wbla2Slider)); - if (adapscen->delay < options.adjusterMaxDelay) { - adapscen->delay = options.adjusterMaxDelay; - } + adapscen->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + adapscen->set_tooltip_markup (M ("TP_COLORAPP_ADAPSCEN_TOOLTIP")); adapscen->throwOnButtonRelease(); adapscen->addAutoButton(); p1VBox->pack_start (*adapscen); ybscen = Gtk::manage (new Adjuster (M ("TP_COLORAPP_MEANLUMINANCE"), 1, 90, 1, 18)); + ybscen->set_tooltip_markup (M ("TP_COLORAPP_YBSCEN_TOOLTIP")); - if (ybscen->delay < options.adjusterMaxDelay) { - ybscen->delay = options.adjusterMaxDelay; - } + ybscen->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); ybscen->throwOnButtonRelease(); ybscen->addAutoButton(); @@ -368,7 +394,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" p2VBox = Gtk::manage ( new Gtk::VBox()); p2VBox->set_spacing (2); - Gtk::HBox* alHBox = Gtk::manage (new Gtk::HBox ()); +// Gtk::HBox* alHBox = Gtk::manage (new Gtk::HBox ()); + alHBox = Gtk::manage (new Gtk::HBox ()); alHBox->set_spacing (2); alHBox->set_tooltip_markup (M ("TP_COLORAPP_ALGO_TOOLTIP")); Gtk::Label* alLabel = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_ALGO") + ":")); @@ -386,9 +413,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" jlight = Gtk::manage (new Adjuster (M ("TP_COLORAPP_LIGHT"), -100.0, 100.0, 0.1, 0.)); - if (jlight->delay < options.adjusterMaxDelay) { - jlight->delay = options.adjusterMaxDelay; - } + jlight->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); jlight->throwOnButtonRelease(); jlight->set_tooltip_markup (M ("TP_COLORAPP_LIGHT_TOOLTIP")); @@ -396,9 +421,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" qbright = Gtk::manage (new Adjuster (M ("TP_COLORAPP_BRIGHT"), -100.0, 100.0, 0.1, 0.)); - if (qbright->delay < options.adjusterMaxDelay) { - qbright->delay = options.adjusterMaxDelay; - } + qbright->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); qbright->throwOnButtonRelease(); qbright->set_tooltip_markup (M ("TP_COLORAPP_BRIGHT_TOOLTIP")); @@ -406,9 +429,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" chroma = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CHROMA"), -100.0, 100.0, 0.1, 0.)); - if (chroma->delay < options.adjusterMaxDelay) { - chroma->delay = options.adjusterMaxDelay; - } + chroma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); chroma->throwOnButtonRelease(); chroma->set_tooltip_markup (M ("TP_COLORAPP_CHROMA_TOOLTIP")); @@ -417,9 +438,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" schroma = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CHROMA_S"), -100.0, 100.0, 0.1, 0.)); - if (schroma->delay < options.adjusterMaxDelay) { - schroma->delay = options.adjusterMaxDelay; - } + schroma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); schroma->throwOnButtonRelease(); schroma->set_tooltip_markup (M ("TP_COLORAPP_CHROMA_S_TOOLTIP")); @@ -427,9 +446,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" mchroma = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CHROMA_M"), -100.0, 100.0, 0.1, 0.)); - if (mchroma->delay < options.adjusterMaxDelay) { - mchroma->delay = options.adjusterMaxDelay; - } + mchroma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); mchroma->throwOnButtonRelease(); mchroma->set_tooltip_markup (M ("TP_COLORAPP_CHROMA_M_TOOLTIP")); @@ -437,9 +454,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" rstprotection = Gtk::manage ( new Adjuster (M ("TP_COLORAPP_RSTPRO"), 0., 100., 0.1, 0.) ); - if (rstprotection->delay < options.adjusterMaxDelay) { - rstprotection->delay = options.adjusterMaxDelay; - } + rstprotection->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); rstprotection->throwOnButtonRelease(); rstprotection->set_tooltip_markup (M ("TP_COLORAPP_RSTPRO_TOOLTIP")); @@ -447,9 +462,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" contrast = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CONTRAST"), -100.0, 100.0, 0.1, 0.)); - if (contrast->delay < options.adjusterMaxDelay) { - contrast->delay = options.adjusterMaxDelay; - } + contrast->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); contrast->throwOnButtonRelease(); contrast->set_tooltip_markup (M ("TP_COLORAPP_CONTRAST_TOOLTIP")); @@ -457,9 +470,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" qcontrast = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CONTRAST_Q"), -100.0, 100.0, 0.1, 0.)); - if (qcontrast->delay < options.adjusterMaxDelay) { - qcontrast->delay = options.adjusterMaxDelay; - } + qcontrast->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); qcontrast->throwOnButtonRelease(); qcontrast->set_tooltip_markup (M ("TP_COLORAPP_CONTRAST_Q_TOOLTIP")); @@ -468,9 +479,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" colorh = Gtk::manage (new Adjuster (M ("TP_COLORAPP_HUE"), -100.0, 100.0, 0.1, 0.)); - if (colorh->delay < options.adjusterMaxDelay) { - colorh->delay = options.adjusterMaxDelay; - } + colorh->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); colorh->throwOnButtonRelease(); colorh->set_tooltip_markup (M ("TP_COLORAPP_HUE_TOOLTIP")); @@ -607,6 +616,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" p3Frame = Gtk::manage (new Gtk::Frame (M ("TP_COLORAPP_LABEL_VIEWING")) ); // "Editing viewing conditions" ??? p3Frame->set_label_align (0.025, 0.5); + p3Frame->set_tooltip_markup (M ("TP_COLORAPP_VIEWINGF_TOOLTIP")); p3VBox = Gtk::manage ( new Gtk::VBox()); p3VBox->set_spacing (2); @@ -618,9 +628,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" // adaplum = Gtk::manage (new Adjuster (M ("TP_COLORAPP_ABSOLUTELUMINANCE"), 0.1, 16384., 0.1, 16.)); adaplum = Gtk::manage (new Adjuster (M ("TP_COLORAPP_ABSOLUTELUMINANCE"), MINLA0, MAXLA0, 0.01, 16, NULL, NULL, &wbSlider2la, &wbla2Slider)); - if (adaplum->delay < options.adjusterMaxDelay) { - adaplum->delay = options.adjusterMaxDelay; - } + adaplum->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); adaplum->throwOnButtonRelease(); adaplum->set_tooltip_markup (M ("TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP")); @@ -631,11 +639,11 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" degreeout = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREE"), 0., 100., 1., 90.)); - if (degreeout->delay < options.adjusterMaxDelay) { - degreeout->delay = options.adjusterMaxDelay; - } + degreeout->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); degreeout->throwOnButtonRelease(); + degreeout->set_tooltip_markup (M ("TP_COLORAPP_DEGREOUT_TOOLTIP")); + degreeout->addAutoButton (M ("TP_COLORAPP_CAT02ADAPTATION_TOOLTIP")); p3VBox->pack_start (*degreeout); /* @@ -647,6 +655,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" tempout = Gtk::manage (new Adjuster (M ("TP_WBALANCE_TEMPERATURE"), MINTEMP0, MAXTEMP0, 5, CENTERTEMP0, itempR1, itempL1, &wbSlider2Temp, &wbTemp2Slider)); greenout = Gtk::manage (new Adjuster (M ("TP_WBALANCE_GREEN"), MINGREEN0, MAXGREEN0, 0.001, 1.0, igreenR1, igreenL1)); ybout = Gtk::manage (new Adjuster (M ("TP_COLORAPP_MEANLUMINANCE"), 5, 90, 1, 18)); + ybout->set_tooltip_markup (M ("TP_COLORAPP_YBOUT_TOOLTIP")); + tempout->set_tooltip_markup (M ("TP_COLORAPP_TEMP2_TOOLTIP")); tempout->throwOnButtonRelease(); tempout->addAutoButton (M ("TP_COLORAPP_TEMPOUT_TOOLTIP")); @@ -694,9 +704,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" */ badpixsl = Gtk::manage (new Adjuster (M ("TP_COLORAPP_BADPIXSL"), 0, 2, 1, 0)); - if (badpixsl->delay < options.adjusterMaxDelay) { - badpixsl->delay = options.adjusterMaxDelay; - } + badpixsl->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); badpixsl->throwOnButtonRelease(); badpixsl->set_tooltip_markup (M ("TP_COLORAPP_BADPIXSL_TOOLTIP")); @@ -833,6 +841,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); + complexmethodconn.block(true); tcmodeconn.block (true); tcmode2conn.block (true); tcmode3conn.block (true); @@ -891,6 +900,9 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) if (!pedited->colorappearance.curveMode) { toneCurveMode->set_active (2); } + if (!pedited->colorappearance.complexmethod) { + complexmethod->set_active_text(M("GENERAL_UNCHANGED")); + } if (!pedited->colorappearance.curveMode2) { toneCurveMode2->set_active (2); @@ -906,6 +918,13 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) setEnabled (pp->colorappearance.enabled); + if (pp->colorappearance.complexmethod == "normal") { + complexmethod->set_active(0); + } else if (pp->colorappearance.complexmethod == "expert") { + complexmethod->set_active(1); + } + + surrsrcconn.block (true); if (pedited && !pedited->colorappearance.surrsrc) { @@ -1068,9 +1087,18 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) presetcat02conn.block (false); lastpresetcat02 = pp->colorappearance.presetcat02; + if (complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + convertParamToNormal(); + + } else { + updateGUIToMode(1); + } + tcmode3conn.block (false); tcmode2conn.block (false); tcmodeconn.block (false); + complexmethodconn.block(false); enableListener (); } void ColorAppearance::autoOpenCurve () @@ -1149,6 +1177,7 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) } if (pedited) { + pedited->colorappearance.complexmethod = complexmethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->colorappearance.degree = degree->getEditedState (); pedited->colorappearance.degreeout = degreeout->getEditedState (); pedited->colorappearance.adapscen = adapscen->getEditedState (); @@ -1196,6 +1225,14 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) } + if (complexmethod->get_active_row_number() == 0) { + pp->colorappearance.complexmethod = "normal"; + } else if (complexmethod->get_active_row_number() == 1) { + pp->colorappearance.complexmethod = "expert"; + } + + + if (surrsrc->get_active_row_number() == 0) { pp->colorappearance.surrsrc = "Average"; } else if (surrsrc->get_active_row_number() == 1) { @@ -1254,6 +1291,71 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) } } + + +void ColorAppearance::updateGUIToMode(int mode) +{ + if(mode ==0) { + alHBox->hide(); + wbmHBox->hide(); + curveEditorG->hide(); + curveEditorG2->hide(); + curveEditorG3->hide(); + greenout->hide(); + badpixsl->hide(); + datacie->hide(); + } else { + alHBox->show(); + wbmHBox->show(); + curveEditorG->show(); + curveEditorG2->show(); + curveEditorG3->show(); + greenout->show(); + badpixsl->show(); + datacie->show(); + } + +} + +void ColorAppearance::convertParamToNormal() +{ + const ColorAppearanceParams def_params; + disableListener(); + algo->set_active (0); + shape->setCurve(def_params.curve); + shape2->setCurve(def_params.curve2); + shape3->setCurve(def_params.curve3); + shape->reset(); + shape2->reset(); + shape3->reset(); + wbmodel->set_active (0); + if (presetcat02->get_active ()) { + wbmodel->set_active (2); + } + greenout->setValue(def_params.greenout); + badpixsl->setValue(def_params.badpixsl); + + enableListener(); + + // Update GUI based on converted widget parameters: +} + +void ColorAppearance::complexmethodChanged() +{ + if (complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + convertParamToNormal(); + + } else { + updateGUIToMode(1); + } + + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(EvCATcomplex, complexmethod->get_active_text()); + } +} + + void ColorAppearance::curveChanged (CurveEditor* ce) { @@ -1954,6 +2056,7 @@ void ColorAppearance::wbmodelChanged () { if (wbmodel->get_active_row_number() == 0 || wbmodel->get_active_row_number() == 1) { illum->hide(); + illumHBox->hide(); tempsc->hide(); greensc->hide(); tempsc->setValue (5003); @@ -1961,6 +2064,7 @@ void ColorAppearance::wbmodelChanged () } if (wbmodel->get_active_row_number() == 2) { + illumHBox->show(); tempsc->show(); greensc->show(); illum->show(); @@ -2111,6 +2215,7 @@ void ColorAppearance::setBatchMode (bool batchMode) tempsc->showEditedCB (); greensc->showEditedCB (); + complexmethod->append(M("GENERAL_UNCHANGED")); surround->append (M ("GENERAL_UNCHANGED")); surrsrc->append (M ("GENERAL_UNCHANGED")); wbmodel->append (M ("GENERAL_UNCHANGED")); diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index c326b06f9..6976f4d29 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -77,6 +77,9 @@ public: void curveMode3Changed (); bool curveMode3Changed_ (); void neutral_pressed (); + void complexmethodChanged(); + void convertParamToNormal(); + void updateGUIToMode(int mode); void expandCurve (bool isExpanded); bool isCurveExpanded (); @@ -104,6 +107,7 @@ private: rtengine::ProcEvent Evcatpreset; rtengine::ProcEvent EvCATAutotempout; rtengine::ProcEvent EvCATillum; + rtengine::ProcEvent EvCATcomplex; bool bgTTipQuery (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); bool srTTipQuery (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); void foldAllButMe (GdkEventButton* event, MyExpander *expander); @@ -139,6 +143,7 @@ private: MyComboBoxText* toneCurveMode; MyComboBoxText* toneCurveMode2; MyComboBoxText* toneCurveMode3; + MyComboBoxText* complexmethod; //Adjuster* edge; Gtk::CheckButton* surrsource; @@ -165,6 +170,10 @@ private: sigc::connection surrconn; sigc::connection gamutconn, datacieconn, tonecieconn /*,badpixconn , sharpcieconn*/; sigc::connection tcmodeconn, tcmode2conn, tcmode3conn, neutralconn; + sigc::connection complexmethodconn; + Gtk::HBox* alHBox; + Gtk::HBox* wbmHBox; + Gtk::HBox* illumHBox; CurveEditorGroup* curveEditorG; CurveEditorGroup* curveEditorG2; CurveEditorGroup* curveEditorG3; diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index ddf917149..77bc31638 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -488,11 +488,11 @@ ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLOR pack_start(*labRegionBox, Gtk::PACK_EXPAND_WIDGET, 4); - labRegionSaturation->delay = options.adjusterMaxDelay; - labRegionSlope->delay = options.adjusterMaxDelay; - labRegionOffset->delay = options.adjusterMaxDelay; - labRegionPower->delay = options.adjusterMaxDelay; - labRegionMaskBlur->delay = options.adjusterMaxDelay; + labRegionSaturation->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + labRegionSlope->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + labRegionOffset->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + labRegionPower->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + labRegionMaskBlur->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); //------------------------------------------------------------------------ show_all(); 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/controllines.cc b/rtgui/controllines.cc new file mode 100644 index 000000000..573b3263f --- /dev/null +++ b/rtgui/controllines.cc @@ -0,0 +1,492 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2020 Lawrence Lee + * + * 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 "controllines.h" +#include "editcallbacks.h" +#include "editwidgets.h" +#include "rtsurface.h" + +#include "../rtengine/perspectivecorrection.h" + +using namespace rtengine; + +::ControlLine::~ControlLine() = default; + +ControlLineManager::ControlLineManager(): + EditSubscriber(ET_OBJECTS), + canvas_area(new Rectangle()), + cursor(CSHandOpen), + draw_mode(false), + drawing_line(false), + edited(false), + prev_obj(-1), + selected_object(-1) +{ + canvas_area->filled = true; + canvas_area->topLeft = Coord(0, 0); + mouseOverGeometry.push_back(canvas_area.get()); + + line_icon_h = Cairo::RefPtr(new RTSurface( + "bidirectional-arrow-horizontal-hicontrast.png")); + line_icon_v = Cairo::RefPtr(new RTSurface( + "bidirectional-arrow-vertical-hicontrast.png")); + line_icon_h_prelight = Cairo::RefPtr(new RTSurface( + "bidirectional-arrow-horizontal-prelight.png")); + line_icon_v_prelight = Cairo::RefPtr(new RTSurface( + "bidirectional-arrow-vertical-prelight.png")); +} + +ControlLineManager::~ControlLineManager() = default; + +void ControlLineManager::setActive(bool active) +{ + EditDataProvider* provider = getEditProvider(); + + if (!provider || (this == provider->getCurrSubscriber()) == active) { + return; + } + + if (active) { + subscribe(); + + int ih, iw; + provider->getImageSize(iw, ih); + canvas_area->bottomRight = Coord(iw, ih); + } else { + unsubscribe(); + } +} + +void ControlLineManager::setDrawMode(bool draw) +{ + draw_mode = draw; +} + +size_t ControlLineManager::size(void) const +{ + return control_lines.size(); +} + +bool ControlLineManager::button1Pressed(int modifierKey) +{ + EditDataProvider* dataProvider = getEditProvider(); + + if (!dataProvider) { + return false; + } + + drag_delta = Coord(0, 0); + + const int object = dataProvider->getObject(); + + if (object > 0) { // A control line. + if (object % ::ControlLine::OBJ_COUNT == 2) { // Icon. + action = Action::PICKING; + } else { + selected_object = object; + action = Action::DRAGGING; + } + } else if (draw_mode && (modifierKey & GDK_CONTROL_MASK)) { // Add new line. + addLine(dataProvider->posImage, dataProvider->posImage); + drawing_line = true; + selected_object = mouseOverGeometry.size() - 1; // Select endpoint. + action = Action::DRAGGING; + } + + return true; +} + +bool ControlLineManager::button1Released(void) +{ + action = Action::NONE; + + if (selected_object > 0) { + mouseOverGeometry[selected_object]->state = Geometry::NORMAL; + } + + edited = true; + callbacks->lineChanged(); + drawing_line = false; + selected_object = -1; + return false; +} + +bool ControlLineManager::button3Pressed(int modifierKey) +{ + EditDataProvider* provider = getEditProvider(); + + action = Action::NONE; + + if (!provider || provider->getObject() < 1) { + return false; + } + + action = Action::PICKING; + return false; +} + +bool ControlLineManager::pick1(bool picked) +{ + action = Action::NONE; + + if (!picked) { + return false; + } + + EditDataProvider* provider = getEditProvider(); + + if (!provider || provider->getObject() % ::ControlLine::OBJ_COUNT != 2) { + return false; + } + + // Change line type. + int object_id = provider->getObject(); + ::ControlLine& line = + *control_lines[(object_id - 1) / ::ControlLine::OBJ_COUNT]; + + if (line.type == rtengine::ControlLine::HORIZONTAL) { + line.icon = line.icon_v; + line.type = rtengine::ControlLine::VERTICAL; + } else if (line.type == rtengine::ControlLine::VERTICAL) { + line.icon = line.icon_h; + line.type = rtengine::ControlLine::HORIZONTAL; + } + + visibleGeometry[object_id - 1] = line.icon.get(); + + edited = true; + callbacks->lineChanged(); + + return true; +} + +bool ControlLineManager::pick3(bool picked) +{ + action = Action::NONE; + + if (!picked) { + return false; + } + + EditDataProvider* provider = getEditProvider(); + + if (!provider) { + return false; + } + + removeLine((provider->getObject() - 1) / ::ControlLine::OBJ_COUNT); + prev_obj = -1; + selected_object = -1; + return false; +} + +bool ControlLineManager::drag1(int modifierKey) +{ + EditDataProvider* provider = getEditProvider(); + + if (!provider || selected_object < 1) { + return false; + } + + ::ControlLine& control_line = + *control_lines[(selected_object - 1) / ::ControlLine::OBJ_COUNT]; + // 0 == end, 1 == line, 2 == icon, 3 == begin + int component = selected_object % ::ControlLine::OBJ_COUNT; + Coord mouse = provider->posImage + provider->deltaImage; + Coord delta = provider->deltaImage - drag_delta; + int ih, iw; + provider->getImageSize(iw, ih); + + switch (component) { + case (0): // end + control_line.end->center = mouse; + control_line.end->center.clip(iw, ih); + control_line.line->end = control_line.end->center; + control_line.end->state = Geometry::DRAGGED; + break; + + case (1): { // line + // Constrain delta so the end stays above the image. + Coord new_delta = control_line.end->center + delta; + new_delta.clip(iw, ih); + new_delta -= control_line.end->center; + // Constrain delta so the beginning stays above the image. + new_delta += control_line.begin->center; + new_delta.clip(iw, ih); + new_delta -= control_line.begin->center; + // Move all objects in the control line. + control_line.end->center += new_delta; + control_line.begin->center += new_delta; + control_line.line->end = control_line.end->center; + control_line.line->begin = control_line.begin->center; + drag_delta += new_delta; + control_line.line->state = Geometry::DRAGGED; + break; + } + + case (3): // begin + control_line.begin->center = mouse; + control_line.begin->center.clip(iw, ih); + control_line.line->begin = control_line.begin->center; + control_line.begin->state = Geometry::DRAGGED; + break; + } + + control_line.icon_h->position.x = (control_line.begin->center.x + + control_line.end->center.x) / 2; + control_line.icon_h->position.y = (control_line.begin->center.y + + control_line.end->center.y) / 2; + control_line.icon_v->position.x = control_line.icon_h->position.x; + control_line.icon_v->position.y = control_line.icon_h->position.y; + + if (drawing_line) { + autoSetLineType(selected_object); + } + + return false; +} + +bool ControlLineManager::getEdited(void) const +{ + return edited; +} + +CursorShape ControlLineManager::getCursor(int objectID) const +{ + return cursor; +} + +bool ControlLineManager::mouseOver(int modifierKey) +{ + EditDataProvider* provider = getEditProvider(); + + if (!provider) { + return false; + } + + int cur_obj = provider->getObject(); + + if (cur_obj == 0) { // Canvas + if (draw_mode && modifierKey & GDK_CONTROL_MASK) { + cursor = CSCrosshair; + } else { + cursor = CSHandOpen; + } + } else if (cur_obj < 0) { // Nothing + cursor = CSArrow; + } else if (cur_obj % ::ControlLine::OBJ_COUNT == 2) { // Icon + visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT; + cursor = CSArrow; + } else { // Object + visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT; + cursor = CSMove2D; + } + + if (prev_obj != cur_obj && prev_obj > 0) { + visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + } + + prev_obj = cur_obj; + + return true; +} + +void ControlLineManager::switchOffEditMode(void) +{ + if (callbacks) { + callbacks->switchOffEditMode(); + } +} + +void ControlLineManager::setEdited(bool edited) +{ + this->edited = edited; +} + +void ControlLineManager::setEditProvider(EditDataProvider* provider) +{ + EditSubscriber::setEditProvider(provider); +} + +void ControlLineManager::setLines(const std::vector& + lines) +{ + removeAll(); + + for (auto&& line : lines) { + Coord start(line.x1, line.y1); + Coord end(line.x2, line.y2); + addLine(start, end, line.type); + } +} + +void ControlLineManager::addLine(Coord begin, Coord end, + rtengine::ControlLine::Type type) +{ + constexpr int line_width = 2; + constexpr int handle_radius = 6; + std::unique_ptr line; + std::shared_ptr icon_h, icon_v; + std::unique_ptr begin_c, end_c; + + line = std::unique_ptr(new Line()); + line->datum = Geometry::IMAGE; + line->innerLineWidth = line_width; + line->begin = begin; + line->end = end; + + const Cairo::RefPtr null_surface = + Cairo::RefPtr(nullptr); + + icon_h = std::make_shared(line_icon_h, null_surface, + line_icon_h_prelight, + null_surface, null_surface, + Geometry::DP_CENTERCENTER); + icon_h->position = Coord((begin.x + end.x) / 2, (begin.y + end.y) / 2); + + icon_v = std::make_shared(line_icon_v, null_surface, + line_icon_v_prelight, + null_surface, null_surface, + Geometry::DP_CENTERCENTER); + icon_v->position = Coord((begin.x + end.x) / 2, (begin.y + end.y) / 2); + + begin_c = std::unique_ptr(new Circle()); + begin_c->datum = Geometry::IMAGE; + begin_c->filled = true; + begin_c->radius = handle_radius; + begin_c->center = begin; + + end_c = std::unique_ptr(new Circle()); + end_c->datum = Geometry::IMAGE; + end_c->filled = true; + end_c->radius = handle_radius; + end_c->center = end; + + std::unique_ptr<::ControlLine> control_line(new ::ControlLine()); + control_line->begin = std::move(begin_c); + control_line->end = std::move(end_c); + control_line->icon_h = icon_h; + control_line->icon_v = icon_v; + + if (type == rtengine::ControlLine::HORIZONTAL) { + control_line->icon = icon_h; + } else { + control_line->icon = icon_v; + } + + control_line->line = std::move(line); + control_line->type = type; + + EditSubscriber::visibleGeometry.push_back(control_line->line.get()); + EditSubscriber::visibleGeometry.push_back(control_line->icon.get()); + EditSubscriber::visibleGeometry.push_back(control_line->begin.get()); + EditSubscriber::visibleGeometry.push_back(control_line->end.get()); + + EditSubscriber::mouseOverGeometry.push_back(control_line->line.get()); + EditSubscriber::mouseOverGeometry.push_back(control_line->icon.get()); + EditSubscriber::mouseOverGeometry.push_back(control_line->begin.get()); + EditSubscriber::mouseOverGeometry.push_back(control_line->end.get()); + + control_lines.push_back(std::move(control_line)); +} + +void ControlLineManager::autoSetLineType(int object_id) +{ + int line_id = (object_id - 1) / ::ControlLine::OBJ_COUNT; + ::ControlLine& line = *control_lines[line_id]; + + int dx = line.begin->center.x - line.end->center.x; + int dy = line.begin->center.y - line.end->center.y; + + if (dx < 0) { + dx = -dx; + } + + if (dy < 0) { + dy = -dy; + } + + rtengine::ControlLine::Type type; + std::shared_ptr icon; + + if (dx > dy) { // More horizontal than vertical. + type = rtengine::ControlLine::HORIZONTAL; + icon = line.icon_h; + } else { + type = rtengine::ControlLine::VERTICAL; + icon = line.icon_v; + } + + if (type != line.type) { // Need to update line type. + line.type = type; + line.icon = icon; + visibleGeometry[line_id * ::ControlLine::OBJ_COUNT + 1] = + line.icon.get(); + } +} + +void ControlLineManager::removeAll(void) +{ + visibleGeometry.clear(); + mouseOverGeometry.erase(mouseOverGeometry.begin() + 1, + mouseOverGeometry.end()); + control_lines.clear(); + prev_obj = -1; + selected_object = -1; + edited = true; + callbacks->lineChanged(); +} + +void ControlLineManager::removeLine(size_t line_id) +{ + if (line_id >= control_lines.size()) { + return; + } + + visibleGeometry.erase( + visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id, + visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + + ::ControlLine::OBJ_COUNT + ); + mouseOverGeometry.erase( + mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + 1, + mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + + ::ControlLine::OBJ_COUNT + 1 + ); + control_lines.erase(control_lines.begin() + line_id); + + edited = true; + callbacks->lineChanged(); +} + +void ControlLineManager::toControlLines(std::vector& + converted) const +{ + converted.clear(); + converted.resize(control_lines.size()); + + for (unsigned int i = 0; i < control_lines.size(); i++) { + converted[i].x1 = control_lines[i]->begin->center.x; + converted[i].y1 = control_lines[i]->begin->center.y; + converted[i].x2 = control_lines[i]->end->center.x; + converted[i].y2 = control_lines[i]->end->center.y; + converted[i].type = control_lines[i]->type; + } +} diff --git a/rtgui/controllines.h b/rtgui/controllines.h new file mode 100644 index 000000000..c623ee1db --- /dev/null +++ b/rtgui/controllines.h @@ -0,0 +1,115 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2020 Lawrence Lee + * + * 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 "editcallbacks.h" +#include "../rtengine/perspectivecorrection.h" + +class Circle; +class Line; +class OPIcon; +class Rectangle; +class RTSurface; + +struct ControlLine { + static constexpr int OBJ_COUNT = 4; + std::unique_ptr line; + std::shared_ptr icon; + std::shared_ptr icon_h, icon_v; + std::unique_ptr begin, end; + rtengine::ControlLine::Type type; + + ~ControlLine(); +}; + +class ControlLineManager: EditSubscriber +{ + +protected: + /** Hidden object for capturing mouse events. */ + std::unique_ptr canvas_area; + rtengine::Coord drag_delta; + std::vector> control_lines; + CursorShape cursor; + bool draw_mode; + bool drawing_line; + bool edited; + Cairo::RefPtr line_icon_h, line_icon_v; + Cairo::RefPtr line_icon_h_prelight, line_icon_v_prelight; + int prev_obj; + int selected_object; + + void addLine(rtengine::Coord begin, rtengine::Coord end, + rtengine::ControlLine::Type type = rtengine::ControlLine::VERTICAL); + /** + * Set the line type of the line containing the object according to the + * line's angle. + * + * If the line is within 45 degrees of a perfectly vertical + * line, inclusive, the line type is set to vertical. Otherwise, horizontal. + */ + void autoSetLineType(int object_id); + void removeLine(size_t line_id); + +public: + class Callbacks + { + public: + virtual ~Callbacks() {}; + /** Called when a line changed (added, removed, moved, etc.). */ + virtual void lineChanged(void) {}; + /** Called when the EditSubscriber's switchOffEditMode is called. */ + virtual void switchOffEditMode(void) {}; + }; + + /** Callbacks to invoke. */ + std::shared_ptr callbacks; + + ControlLineManager(); + ~ControlLineManager(); + + bool getEdited(void) const; + void removeAll(void); + /** Sets whether or not the lines are visible and interact-able. */ + void setActive(bool active); + /** Set whether or not lines can be drawn and deleted. */ + void setDrawMode(bool draw); + void setEdited(bool edited); + void setEditProvider(EditDataProvider* provider); + void setLines(const std::vector& lines); + /** Returns the number of lines. */ + size_t size(void) const; + /** + * Allocates a new array and populates it with copies of the control lines. + */ + void toControlLines(std::vector& converted) const; + + // EditSubscriber overrides + bool button1Pressed(int modifierKey) override; + bool button1Released(void) override; + bool button3Pressed(int modifierKey) override; + bool pick1(bool picked) override; + bool pick3(bool picked) override; + bool drag1(int modifierKey) override; + CursorShape getCursor(int objectID) const; + bool mouseOver(int modifierKey) override; + void switchOffEditMode(void) override; +}; diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc new file mode 100644 index 000000000..9ed4c95ee --- /dev/null +++ b/rtgui/controlspotpanel.cc @@ -0,0 +1,2749 @@ +/* + * 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")))), + + prevMethod_(Gtk::manage(new MyComboBoxText())), + 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"), -50, 30, 1, 10, Gtk::manage(new RTImage("circle-yellow-small.png")), Gtk::manage(new RTImage("circle-gray-small.png")) ))), + + hishow_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_PREVSHOW")))), + activ_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ACTIVSPOT")))), + 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")))), + ctboxshape(Gtk::manage(new Gtk::HBox())), + ctboxshapemethod(Gtk::manage(new Gtk::HBox())), + + 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; + pack_start(*hishow_); + + Gtk::HBox* const ctboxprevmethod = Gtk::manage(new Gtk::HBox()); + prevMethod_->append(M("TP_LOCALLAB_PREVHIDE")); + prevMethod_->append(M("TP_LOCALLAB_PREVSHOW")); + prevMethod_->set_active(0); + prevMethodconn_ = prevMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::prevMethodChanged)); + +// ctboxprevmethod->pack_start(*prevMethod_); + pack_start(*ctboxprevmethod); + + + 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 ctboxactivmethod = Gtk::manage(new Gtk::HBox()); + ctboxactivmethod->pack_start(*activ_); + pack_start(*ctboxactivmethod); + +// 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_); + + 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")); + transitweak_->set_tooltip_text(M("TP_LOCALLAB_TRANSITWEAK_TOOLTIP")); + feather_->set_tooltip_text(M("TP_LOCALLAB_FEATH_TOOLTIP")); + transitgrad_->set_tooltip_text(M("TP_LOCALLAB_TRANSITGRAD_TOOLTIP")); + 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 artifBox2 = Gtk::manage(new ToolParamBlock()); + + artifBox2->pack_start(*preview_); + artifBox2->pack_start(*colorscope_); + pack_start(*artifBox2); + ToolParamBlock* const specCaseBox = Gtk::manage(new ToolParamBlock()); + + hishowconn_ = hishow_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::hishowChanged)); + + activConn_ = activ_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::activChanged)); + + 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_); + specCaseBox->pack_start(*ctboxshapemethod); + + 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_); + specCaseBox->pack_start(*ctboxwavmethod); + + + 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 + prevMethod_->set_active(row[spots_.prevMethod]); + 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]); + hishow_->set_active(row[spots_.hishow]); + activ_->set_active(row[spots_.activ]); + avoid_->set_active(row[spots_.avoid]); + blwh_->set_active(row[spots_.blwh]); + recurs_->set_active(row[spots_.recurs]); + // laplac_->set_active(row[spots_.laplac]); + laplac_->set_active(true); + 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::prevMethodChanged() +{ + // printf("prevMethodChanged\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_.prevMethod] = prevMethod_->get_active_row_number(); +/* + // Update Control Spot GUI according to spotMethod_ combobox state (to be compliant with updateParamVisibility function) + if (multiImage && prevMethod_->get_active_text() == M("GENERAL_UNCHANGED")) { + expTransGrad_->show(); + expShapeDetect_->show(); + expSpecCases_->show(); + expMaskMerge_->show(); + circrad_->show(); + ctboxshape->show(); + } else if (prevMethod_->get_active_row_number() == 0) { // Normal case + expTransGrad_->hide(); + expShapeDetect_->hide(); + expSpecCases_->hide(); + expMaskMerge_->hide(); + circrad_->hide(); + ctboxshape->hide(); + shapeMethod_->set_active(0); + + } else { // Excluding case + expTransGrad_->show(); + expShapeDetect_->show(); + expSpecCases_->show(); + expMaskMerge_->show(); + circrad_->show(); + ctboxshape->show(); + } +*/ + // Raise event + if (listener) { +// listener->panelChanged(EvLocallabSpotprevMethod, prevMethod_->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(); + } + +/* + if (multiImage && prevMethod_->get_active_text() == M("GENERAL_UNCHANGED")) { + expTransGrad_->show(); + expShapeDetect_->show(); + expSpecCases_->show(); + expMaskMerge_->show(); + circrad_->show(); + ctboxshape->show(); + } else if (prevMethod_->get_active_row_number() == 0) { // Normal case + */ + if (!hishow_->get_active()) { // Normal case + expTransGrad_->hide(); + expShapeDetect_->hide(); + expSpecCases_->hide(); + expMaskMerge_->hide(); + circrad_->hide(); + ctboxshape->hide(); + } else { // Excluding case + expTransGrad_->show(); + expShapeDetect_->show(); + expSpecCases_->show(); + expMaskMerge_->show(); + circrad_->show(); + ctboxshape->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::hishowChanged() +{ + // 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_.hishow] = hishow_->get_active(); + + + + if (!hishow_->get_active()) { // Normal case + expTransGrad_->hide(); + expShapeDetect_->hide(); + expSpecCases_->hide(); + expMaskMerge_->hide(); + circrad_->hide(); + ctboxshape->hide(); + shapeMethod_->set_active(0); + + } else { // Excluding case + expTransGrad_->show(); + expShapeDetect_->show(); + expSpecCases_->show(); + expMaskMerge_->show(); + circrad_->show(); + ctboxshape->show(); + } + + // Raise event + if (listener) { + if (hishow_->get_active()) { + listener->panelChanged(Evlocallabhishow, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabhishow, M("GENERAL_DISABLED")); + } + } +} + + + +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::activChanged() +{ + // printf("activChanged\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_.activ] = activ_->get_active(); + + // Raise event + if (listener) { + if (activ_->get_active()) { + listener->panelChanged(Evlocallabactiv, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabactiv, 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); + prevMethodconn_.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); + hishowconn_.block(cond); + activConn_.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); + + prevMethod_->set_sensitive(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); + hishow_->set_sensitive(cond); + activ_->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); + preview_->set_sensitive(cond); + + if (!cond) { + // Reset complex parameters visibility to default state + expTransGrad_->hide(); + expShapeDetect_->hide(); + expSpecCases_->hide(); + expMaskMerge_->hide(); + circrad_->hide(); + ctboxshape->hide(); + excluFrame->hide(); +// ctboxshapemethod->hide(); + locX_->hide(); + locXL_->hide(); + locY_->hide(); + locYT_->hide(); + centerX_->hide(); + centerY_->hide(); + } +} + +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->prevMethod = row[spots_.prevMethod]; + 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->hishow = row[spots_.hishow]; + r->activ = row[spots_.activ]; + 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_.prevMethod] = newSpot->prevMethod; + 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_.hishow] = newSpot->hishow; + row[spots_.activ] = newSpot->activ; + 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(prevMethod); + 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(hishow); + add(activ); + 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..baa5665cf --- /dev/null +++ b/rtgui/controlspotpanel.h @@ -0,0 +1,449 @@ +/* + * 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 prevMethod; // 0 = Normal, 1 = Excluding + 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 hishow; + bool activ; + 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 prevMethodChanged(); + void shapeChanged(); + void spotMethodChanged(); + void shapeMethodChanged(); + void qualityMethodChanged(); + void complexMethodChanged(); + void wavMethodChanged(); + + void updateParamVisibility(); + + void adjusterChanged(Adjuster* a, double newval) override; + + void hishowChanged(); + void activChanged(); + 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; + 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 prevMethod; // 0 = hide, 1 = show + 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 hishow; + Gtk::TreeModelColumn activ; + 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 prevMethod_; + sigc::connection prevMethodconn_; + 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 hishow_; + sigc::connection hishowconn_; + Gtk::CheckButton* const activ_; + sigc::connection activConn_; + 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_; + + Gtk::HBox* const ctboxshape; + Gtk::HBox* const ctboxshapemethod; + + // 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/crop.cc b/rtgui/crop.cc index 48d1e09af..961f1908b 100644 --- a/rtgui/crop.cc +++ b/rtgui/crop.cc @@ -82,6 +82,7 @@ public: {"17:22", 17.0 / 22.0}, // L1.294..., P0.772... {"45:35 - ePassport", 45.0 / 35.0}, // L1.285,... P0.777... {"64:27", 64.0 / 27.0}, // L2.370..., P0.421... + {"13:18", 13.0 / 18.0}, // L1.384..., P0.722... } { } diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index f588190c0..a3e00c80a 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -125,13 +125,13 @@ void CropWindow::initZoomSteps() char lbl[64]; for (int s = 100; s >= 11; --s) { float z = 10.f / s; - sprintf(lbl, "% 2d%%", int(z * 100)); + snprintf(lbl, sizeof(lbl), "% 2d%%", int(z * 100)); bool is_major = (s == s/10 * 10); zoomSteps.push_back(ZoomStep(lbl, z, s, is_major)); } zoom11index = zoomSteps.size(); for (int s = 1; s <= 8; ++s) { - sprintf(lbl, "%d00%%", s); + snprintf(lbl, sizeof(lbl), "%d00%%", s); zoomSteps.push_back(ZoomStep(lbl, s, s * 1000, true)); } zoomSteps.push_back(ZoomStep("1600%", 16, 16000, true)); @@ -414,7 +414,8 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) action_y = 0; needRedraw = true; } - } else if (iarea->getToolMode () == TMHand + } else if ((iarea->getToolMode () == TMHand + || iarea->getToolMode() == TMPerspective) && editSubscriber && cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) @@ -429,6 +430,8 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) state = SEditPick1; pickedObject = iarea->getObject(); pickModifierKey = bstate; + } else if (iarea->getToolMode() == TMPerspective) { + state = SCropImgMove; } press_x = x; press_y = y; @@ -592,7 +595,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) } } } else if (button == 3) { - if (iarea->getToolMode () == TMHand) { + if (iarea->getToolMode () == TMHand || iarea->getToolMode() == TMPerspective) { EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { needRedraw = editSubscriber->button3Pressed(bstate); @@ -764,7 +767,10 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) iarea->setObject(ObjectMOBuffer::getObjectID(cropPos)); - bool elemPicked = iarea->getObject() == pickedObject && bstate == pickModifierKey; + int buttonMask = ((state == SEditPick1) ? GDK_BUTTON1_MASK : 0) + | ((state == SEditPick2) ? GDK_BUTTON2_MASK : 0) + | ((state == SEditPick3) ? GDK_BUTTON3_MASK : 0); + bool elemPicked = iarea->getObject() == pickedObject && bstate == (pickModifierKey | buttonMask); if (state == SEditPick1) { needRedraw = editSubscriber->pick1 (elemPicked); diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 5b5d4395d..67cea5174 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 09ef7d824..398c63603 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/dehaze.cc b/rtgui/dehaze.cc index 6b7fcd64f..76d309afc 100644 --- a/rtgui/dehaze.cc +++ b/rtgui/dehaze.cc @@ -36,7 +36,7 @@ Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, EvDehazeStrength = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_STRENGTH"); EvDehazeShowDepthMap = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP"); EvDehazeDepth = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_DEPTH"); - EvDehazeLuminance = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_LUMINANCE"); + EvDehazeSaturation = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_SATURATION"); strength = Gtk::manage(new Adjuster(M("TP_DEHAZE_STRENGTH"), 0., 100., 1., 50.)); strength->setAdjusterListener(this); @@ -46,9 +46,9 @@ Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, depth->setAdjusterListener(this); depth->show(); - luminance = Gtk::manage(new Gtk::CheckButton(M("TP_DEHAZE_LUMINANCE"))); - luminance->signal_toggled().connect(sigc::mem_fun(*this, &Dehaze::luminanceChanged)); - luminance->show(); + saturation = Gtk::manage(new Adjuster(M("TP_DEHAZE_SATURATION"), 0., 100., 1., 50.)); + saturation->setAdjusterListener(this); + saturation->show(); showDepthMap = Gtk::manage(new Gtk::CheckButton(M("TP_DEHAZE_SHOW_DEPTH_MAP"))); showDepthMap->signal_toggled().connect(sigc::mem_fun(*this, &Dehaze::showDepthMapChanged)); @@ -56,65 +56,65 @@ Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, pack_start(*strength); pack_start(*depth); - pack_start(*luminance); + pack_start(*saturation); pack_start(*showDepthMap); } - void Dehaze::read(const ProcParams *pp, const ParamsEdited *pedited) { disableListener(); if (pedited) { strength->setEditedState(pedited->dehaze.strength ? Edited : UnEdited); + saturation->setEditedState(pedited->dehaze.saturation ? Edited : UnEdited); depth->setEditedState(pedited->dehaze.depth ? Edited : UnEdited); set_inconsistent(multiImage && !pedited->dehaze.enabled); showDepthMap->set_inconsistent(!pedited->dehaze.showDepthMap); - luminance->set_inconsistent(!pedited->dehaze.luminance); } setEnabled(pp->dehaze.enabled); strength->setValue(pp->dehaze.strength); + saturation->setValue(pp->dehaze.saturation); depth->setValue(pp->dehaze.depth); showDepthMap->set_active(pp->dehaze.showDepthMap); - luminance->set_active(pp->dehaze.luminance); enableListener(); } - void Dehaze::write(ProcParams *pp, ParamsEdited *pedited) { pp->dehaze.strength = strength->getValue(); + pp->dehaze.saturation = saturation->getValue(); pp->dehaze.depth = depth->getValue(); pp->dehaze.enabled = getEnabled(); pp->dehaze.showDepthMap = showDepthMap->get_active(); - pp->dehaze.luminance = luminance->get_active(); if (pedited) { pedited->dehaze.strength = strength->getEditedState(); + pedited->dehaze.saturation = saturation->getEditedState(); pedited->dehaze.depth = depth->getEditedState(); pedited->dehaze.enabled = !get_inconsistent(); pedited->dehaze.showDepthMap = !showDepthMap->get_inconsistent(); - pedited->dehaze.luminance = !luminance->get_inconsistent(); } } void Dehaze::setDefaults(const ProcParams *defParams, const ParamsEdited *pedited) { strength->setDefault(defParams->dehaze.strength); + saturation->setDefault(defParams->dehaze.saturation); depth->setDefault(defParams->dehaze.depth); if (pedited) { + saturation->setDefaultEditedState(pedited->dehaze.saturation ? Edited : UnEdited); strength->setDefaultEditedState(pedited->dehaze.strength ? Edited : UnEdited); depth->setDefaultEditedState(pedited->dehaze.depth ? Edited : UnEdited); } else { + saturation->setDefaultEditedState(Irrelevant); strength->setDefaultEditedState(Irrelevant); depth->setDefaultEditedState(Irrelevant); } } - void Dehaze::adjusterChanged(Adjuster* a, double newval) { if (listener && getEnabled()) { @@ -122,11 +122,12 @@ void Dehaze::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvDehazeStrength, a->getTextValue()); } else if (a == depth) { listener->panelChanged(EvDehazeDepth, a->getTextValue()); + } else if (a == saturation) { + listener->panelChanged(EvDehazeSaturation, a->getTextValue()); } } } - void Dehaze::enabledChanged () { if (listener) { @@ -140,7 +141,6 @@ void Dehaze::enabledChanged () } } - void Dehaze::showDepthMapChanged() { if (listener) { @@ -148,13 +148,6 @@ void Dehaze::showDepthMapChanged() } } -void Dehaze::luminanceChanged() -{ - if (listener) { - listener->panelChanged(EvDehazeLuminance, luminance->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); - } -} - void Dehaze::setBatchMode(bool batchMode) { ToolPanel::setBatchMode(batchMode); @@ -163,9 +156,7 @@ void Dehaze::setBatchMode(bool batchMode) depth->showEditedCB(); } - void Dehaze::setAdjusterBehavior(bool strengthAdd) { strength->setAddMode(strengthAdd); } - diff --git a/rtgui/dehaze.h b/rtgui/dehaze.h index 79d2e015c..155efa522 100644 --- a/rtgui/dehaze.h +++ b/rtgui/dehaze.h @@ -28,14 +28,15 @@ class Dehaze final : public ToolParamBlock, public AdjusterListener, public Fold private: Adjuster *strength; Adjuster *depth; + Adjuster *saturation; Gtk::CheckButton *showDepthMap; - Gtk::CheckButton *luminance; +// Gtk::CheckButton *luminance; rtengine::ProcEvent EvDehazeEnabled; rtengine::ProcEvent EvDehazeStrength; rtengine::ProcEvent EvDehazeDepth; rtengine::ProcEvent EvDehazeShowDepthMap; - rtengine::ProcEvent EvDehazeLuminance; + rtengine::ProcEvent EvDehazeSaturation; public: @@ -49,7 +50,7 @@ public: void adjusterChanged(Adjuster *a, double newval) override; void enabledChanged() override; void showDepthMapChanged(); - void luminanceChanged(); +// void luminanceChanged(); void setAdjusterBehavior(bool strengthAdd); }; diff --git a/rtgui/delayed.h b/rtgui/delayed.h new file mode 100644 index 000000000..b57d7300b --- /dev/null +++ b/rtgui/delayed.h @@ -0,0 +1,240 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (C) 2020 Flössie + * + * 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 +#include + +#include +#include + +#include "../rtengine/noncopyable.h" + +namespace delayed_helper +{ + + // C++14 + + // See https://gist.github.com/ntessore/dc17769676fb3c6daa1f + template + struct index_sequence + { + }; + + template + struct make_index_sequence : + make_index_sequence + { + }; + + template + struct make_index_sequence<0, Is...> : + index_sequence + { + }; + + // C++17 + + // See https://aherrmann.github.io/programming/2016/02/28/unpacking-tuples-in-cpp14/ + template + void apply_impl(F f, T t, index_sequence) + { + f(std::get(t)...); + } + + template + void apply(F f, T t) + { + apply_impl(f, t, make_index_sequence{}>{}); + } + +} + +template +class DelayedCall final : + public rtengine::NonCopyable +{ +public: + DelayedCall(std::function _function, unsigned int _min_delay_ms, unsigned int _max_delay_ms = 0) : + function(_function), + min_delay_ms(_min_delay_ms), + max_delay_ms(_max_delay_ms) + { + } + + DelayedCall(unsigned int _min_delay_ms, unsigned int _max_delay_ms = 0) : + DelayedCall({}, _min_delay_ms, _max_delay_ms) + { + } + + void setFunction(std::function function) + { + this->function = function; + } + + void operator ()(Ts... ts) + { + if (!function) { + return; + } + + if (!min_delay_ms) { + function(ts...); + return; + } + + params = std::make_tuple(ts...); + + min_timeout.disconnect(); + min_timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &DelayedCall::onMinTimeout), min_delay_ms); + + if (max_delay_ms && !max_timeout.connected()) { + max_timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &DelayedCall::onMaxTimeout), max_delay_ms); + } + } + + void cancel() + { + min_timeout.disconnect(); + max_timeout.disconnect(); + } + +private: + bool onMinTimeout() + { + max_timeout.disconnect(); + if (function) { + delayed_helper::apply(function, params); + } + return false; + } + + bool onMaxTimeout() + { + min_timeout.disconnect(); + if (function) { + delayed_helper::apply(function, params); + } + return false; + } + + std::function function; + + unsigned int min_delay_ms; + unsigned int max_delay_ms; + + sigc::connection min_timeout; + sigc::connection max_timeout; + + std::tuple params; +}; + +template +class DelayedConnection final : + public rtengine::NonCopyable +{ +public: + DelayedConnection(unsigned int _min_delay_ms, unsigned int _max_delay_ms = 0) : + min_delay_ms(_min_delay_ms), + max_delay_ms(_max_delay_ms) + { + } + + void connect(Glib::SignalProxy signal, const sigc::slot& slot, const sigc::slot& immediate_slot = {}) + { + this->slot = slot; + this->immediate_slot = immediate_slot; + this->signal = signal.connect(sigc::mem_fun(*this, &DelayedConnection::onSignal)); + } + + void block(bool value = true) + { + signal.block(value); + } + + void unblock() + { + signal.unblock(); + } + + void cancel() + { + min_timeout.disconnect(); + max_timeout.disconnect(); + } + + void setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms = 0) + { + this->min_delay_ms = min_delay_ms; + this->max_delay_ms = max_delay_ms; + + min_timeout.disconnect(); + max_timeout.disconnect(); + } + +private: + void onSignal(Ts... ts) + { + if (immediate_slot) { + immediate_slot(ts...); + } + + if (!min_delay_ms) { + slot(ts...); + return; + } + + params = std::make_tuple(ts...); + + min_timeout.disconnect(); + min_timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &DelayedConnection::onMinTimeout), min_delay_ms); + + if (max_delay_ms && !max_timeout.connected()) { + max_timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &DelayedConnection::onMaxTimeout), max_delay_ms); + } + } + + bool onMinTimeout() + { + max_timeout.disconnect(); + delayed_helper::apply(slot, params); + return false; + } + + bool onMaxTimeout() + { + min_timeout.disconnect(); + delayed_helper::apply(slot, params); + return false; + } + + unsigned int min_delay_ms; + unsigned int max_delay_ms; + + sigc::connection signal; + sigc::connection min_timeout; + sigc::connection max_timeout; + + sigc::slot slot; + sigc::slot immediate_slot; + + std::tuple params; +}; diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index 079a083ea..f4fc8449e 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -399,6 +399,25 @@ DiagonalCurveEditor* DiagonalCurveEditorSubGroup::addCurve(Glib::ustring curveLa return newCE; } + +void DiagonalCurveEditorSubGroup::updateLocallabBackground(CurveEditor* ce) +{ + if (ce == parent->displayedCurve) { + paramCurve->updateLocallabBackground(ce->locallabRef); + customCurve->updateLocallabBackground(ce->locallabRef); + NURBSCurve->updateLocallabBackground(ce->locallabRef); + } +} + +void DiagonalCurveEditorSubGroup::restoreLocallabBackground() +{ + if (parent->displayedCurve) { + paramCurve->updateLocallabBackground(parent->displayedCurve->locallabRef); + customCurve->updateLocallabBackground(parent->displayedCurve->locallabRef); + NURBSCurve->updateLocallabBackground(parent->displayedCurve->locallabRef); + } +} + /* * Switch off the edit button */ diff --git a/rtgui/diagonalcurveeditorsubgroup.h b/rtgui/diagonalcurveeditorsubgroup.h index 9b1f67462..08e0828f5 100644 --- a/rtgui/diagonalcurveeditorsubgroup.h +++ b/rtgui/diagonalcurveeditorsubgroup.h @@ -95,6 +95,7 @@ public: void pipetteDrag(EditDataProvider *provider, int modifierKey) override; void showCoordinateAdjuster(CoordinateProvider *provider) override; void stopNumericalAdjustment() override; + void updateLocallabBackground(CurveEditor* ce) override; bool curveReset (CurveEditor *ce) override; @@ -102,6 +103,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/editcallbacks.cc b/rtgui/editcallbacks.cc index 2991c946a..71c342874 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 ffb1a1202..134ea6477 100644 --- a/rtgui/editcallbacks.h +++ b/rtgui/editcallbacks.h @@ -162,12 +162,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 @@ -194,4 +195,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..34d677206 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -21,6 +21,7 @@ #include +#include "../rtengine/array2D.h" #include "../rtengine/imagesource.h" #include "../rtengine/iccstore.h" #include "batchqueue.h" @@ -47,6 +48,8 @@ using namespace rtengine::procparams; +using ScopeType = Options::ScopeType; + namespace { @@ -470,7 +473,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), previewHandler (nullptr), beforePreviewHandler (nullptr), beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr), beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr), - selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false) + selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false), + histogram_observable(nullptr), histogram_scope_type(ScopeType::NONE) { epih = new EditorPanelIdleHelper; @@ -957,6 +961,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 +1685,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 +1751,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(); } @@ -1782,7 +1799,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, bool EditorPanel::idle_imageSaved (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams) { - img->free (); + delete img; if (! pc->returnValue() ) { openThm->imageDeveloped (); @@ -1982,7 +1999,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm err = 1; } - img->free(); + delete img; return !err; } @@ -2044,7 +2061,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p } if (tries == 1000) { - img->free (); + delete img; return false; } @@ -2065,7 +2082,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename) { - img->free (); + delete img; int errore = pc->returnValue(); setProgressState(false); delete pc; @@ -2232,16 +2249,94 @@ void EditorPanel::histogramChanged( const LUTu& histGreenRaw, const LUTu& histBlueRaw, const LUTu& histChroma, - const LUTu& histLRETI + const LUTu& histLRETI, + int vectorscopeScale, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, + int waveformScale, + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) { if (histogramPanel) { - histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw); + histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI); } +void EditorPanel::setObservable(rtengine::HistogramObservable* observable) +{ + histogram_observable = observable; +} + +bool EditorPanel::updateHistogram(void) const +{ + return histogram_scope_type == ScopeType::HISTOGRAM + || histogram_scope_type == ScopeType::NONE; +} + +bool EditorPanel::updateHistogramRaw(void) const +{ + return histogram_scope_type == ScopeType::HISTOGRAM_RAW + || histogram_scope_type == ScopeType::NONE; +} + +bool EditorPanel::updateVectorscopeHC(void) const +{ + return + histogram_scope_type == ScopeType::VECTORSCOPE_HC + || histogram_scope_type == ScopeType::NONE; +} + +bool EditorPanel::updateVectorscopeHS(void) const +{ + return + histogram_scope_type == ScopeType::VECTORSCOPE_HS + || histogram_scope_type == ScopeType::NONE; +} + +bool EditorPanel::updateWaveform(void) const +{ + return histogram_scope_type == ScopeType::WAVEFORM + || histogram_scope_type == ScopeType::PARADE + || histogram_scope_type == ScopeType::NONE; +} + +void EditorPanel::scopeTypeChanged(ScopeType new_type) +{ + histogram_scope_type = new_type; + + if (!histogram_observable) { + return; + } + + // Make sure the new scope is updated since we only actively update the + // current scope. + switch (new_type) { + case ScopeType::HISTOGRAM: + histogram_observable->requestUpdateHistogram(); + break; + case ScopeType::HISTOGRAM_RAW: + histogram_observable->requestUpdateHistogramRaw(); + break; + case ScopeType::VECTORSCOPE_HC: + histogram_observable->requestUpdateVectorscopeHC(); + break; + case ScopeType::VECTORSCOPE_HS: + histogram_observable->requestUpdateVectorscopeHS(); + break; + case ScopeType::PARADE: + case ScopeType::WAVEFORM: + histogram_observable->requestUpdateWaveform(); + break; + case ScopeType::NONE: + break; + } +} + bool EditorPanel::CheckSidePanelsVisibility() { if (tbTopPanel_1) { @@ -2358,6 +2453,10 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) break; } + if (histogramPanel) { + histogramPanel->setPanelListener(this); + } + iareapanel->imageArea->setPointerMotionHListener (histogramPanel); } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 8993fea07..a277ffd3a 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -32,6 +32,12 @@ #include "../rtengine/noncopyable.h" #include "../rtengine/rtengine.h" +namespace rtengine +{ +template +class array2D; +} + class BatchQueueEntry; class EditorPanel; class FilePanel; @@ -55,6 +61,7 @@ class EditorPanel final : public ThumbnailListener, public HistoryBeforeLineListener, public rtengine::HistogramListener, + public HistogramPanelListener, public rtengine::NonCopyable { public: @@ -79,6 +86,7 @@ public: void writeOptions(); void writeToolExpandedStatus (std::vector &tpOpen); + void updateShowtooltipVisibility (bool showtooltip); void showTopPanel (bool show); bool isRealized() @@ -125,8 +133,25 @@ public: const LUTu& histGreenRaw, const LUTu& histBlueRaw, const LUTu& histChroma, - const LUTu& histLRETI + const LUTu& histLRETI, + int vectorscopeScale, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, + int waveformScale, + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) override; + void setObservable(rtengine::HistogramObservable* observable) override; + bool updateHistogram(void) const override; + bool updateHistogramRaw(void) const override; + bool updateVectorscopeHC(void) const override; + bool updateVectorscopeHS(void) const override; + bool updateWaveform(void) const override; + + // HistogramPanelListener + void scopeTypeChanged(Options::ScopeType new_type) override; // event handlers void info_toggled (); @@ -259,4 +284,7 @@ private: bool isProcessing; IdleRegister idle_register; + + rtengine::HistogramObservable* histogram_observable; + Options::ScopeType histogram_scope_type; }; diff --git a/rtgui/editwidgets.cc b/rtgui/editwidgets.cc index 2d0170a49..f9c9b3781 100644 --- a/rtgui/editwidgets.cc +++ b/rtgui/editwidgets.cc @@ -649,6 +649,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 17a8ca27d..fd539c355 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -238,6 +238,7 @@ public: float innerLineWidth; // ...outerLineWidth = innerLineWidth+2 Datum datum; State state; // set by the Subscriber + float opacity; // Percentage of opacity Geometry (); virtual ~Geometry() {} @@ -330,6 +331,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" { @@ -494,7 +514,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 () : @@ -538,6 +558,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 ( @@ -558,5 +582,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/exifpanel.cc b/rtgui/exifpanel.cc index 341d0f303..3f6bbacb5 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -209,6 +209,9 @@ void ExifPanel::setImageData (const FramesMetaData* id) Gtk::TreeModel::Children ExifPanel::addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, rtexif::ActionCode action, bool editable) { + if (!value.validate()) { + value = "???"; + } Gtk::TreeModel::Row row = * (exifTreeModel->append (root)); row[exifColumns.action] = action; diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index caa60ebbc..a8ce94e7f 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -27,8 +27,10 @@ #include "batchqueue.h" #include "clipboard.h" +#include "inspector.h" #include "multilangmgr.h" #include "options.h" +#include "paramsedited.h" #include "profilestorecombobox.h" #include "procparamchangers.h" #include "rtimage.h" @@ -151,6 +153,10 @@ FileBrowser::FileBrowser () : pmenu = new Gtk::Menu (); pmenu->attach (*Gtk::manage(open = new Gtk::MenuItem (M("FILEBROWSER_POPUPOPEN"))), 0, 1, p, p + 1); p++; + if (options.inspectorWindow) { + pmenu->attach (*Gtk::manage(inspect = new Gtk::MenuItem (M("FILEBROWSER_POPUPINSPECT"))), 0, 1, p, p + 1); + p++; + } pmenu->attach (*Gtk::manage(develop = new MyImageMenuItem (M("FILEBROWSER_POPUPPROCESS"), "gears.png")), 0, 1, p, p + 1); p++; pmenu->attach (*Gtk::manage(developfast = new Gtk::MenuItem (M("FILEBROWSER_POPUPPROCESSFAST"))), 0, 1, p, p + 1); @@ -404,6 +410,8 @@ FileBrowser::FileBrowser () : trash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Delete, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); untrash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Delete, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); open->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Return, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); + if (options.inspectorWindow) + inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_F, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); develop->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); developfast->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); copyprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_C, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); @@ -415,6 +423,10 @@ FileBrowser::FileBrowser () : // Bind to event handlers open->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), open)); + if (options.inspectorWindow) { + inspect->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), inspect)); + } + for (int i = 0; i < 6; i++) { rank[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rank[i])); } @@ -697,7 +709,6 @@ void FileBrowser::menuColorlabelActivated (Gtk::MenuItem* m) void FileBrowser::menuItemActivated (Gtk::MenuItem* m) { - std::vector mselected; { @@ -750,6 +761,8 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) if (m == open) { openRequested(mselected); + } else if (options.inspectorWindow && m == inspect) { + inspectRequested(mselected); } else if (m == remove) { tbl->deleteRequested (mselected, false, true); } else if (m == removeInclProc) { @@ -1066,6 +1079,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 +1407,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 +1423,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(); @@ -2071,3 +2089,8 @@ void FileBrowser::openRequested( std::vector mselected) tbl->openRequested (entries); } + +void FileBrowser::inspectRequested(std::vector mselected) +{ + getInspector()->showWindow(false, false); +} diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 53f3f1f2b..03a8636e5 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -81,6 +81,7 @@ protected: Gtk::MenuItem* remove; Gtk::MenuItem* removeInclProc; Gtk::MenuItem* open; + Gtk::MenuItem* inspect; Gtk::MenuItem* selall; Gtk::MenuItem* copyTo; Gtk::MenuItem* moveTo; @@ -136,6 +137,7 @@ protected: void requestColorLabel(int colorlabel); void notifySelectionListener (); void openRequested( std::vector mselected); + void inspectRequested( std::vector mselected); ExportPanel* exportPanel; type_trash_changed m_trash_changed; diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 3129e93e2..432296f38 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -116,9 +116,12 @@ void FileBrowserEntry::refreshQuickThumbnailImage () void FileBrowserEntry::calcThumbnailSize () { - if (thumbnail) { - prew = thumbnail->getThumbnailWidth(preh); + int ow = prew, oh = preh; + thumbnail->getThumbnailSize(prew, preh); + if (ow != prew || oh != preh || preview.size() != static_cast(prew * preh * 3)) { + preview.clear(); + } } } @@ -230,7 +233,7 @@ void FileBrowserEntry::updateImage(rtengine::IImage8* img, double scale, const r --feih->pending; } - img->free(); + delete img; return false; } @@ -255,28 +258,22 @@ void FileBrowserEntry::_updateImage(rtengine::IImage8* img, double s, const rten bool rotated = false; if (preh == img->getHeight()) { - const bool resize = !preview || prew != img->getWidth(); prew = img->getWidth (); // Check if image has been rotated since last time - rotated = preview && newLandscape != landscape; + rotated = !preview.empty() && newLandscape != landscape; - if (resize) { - if (preview) { - delete [] preview; - } - preview = new guint8 [prew * preh * 3]; - } - memcpy(preview, img->getData(), prew * preh * 3); + preview.resize(prew * preh * 3); + std::copy(img->getData(), img->getData() + preview.size(), preview.begin()); { - GThreadLock lock; - updateBackBuffer (); + GThreadLock lock; + updateBackBuffer (); } } landscape = newLandscape; - img->free(); + delete img; if (parent) { if (rotated) { @@ -601,7 +598,7 @@ bool FileBrowserEntry::onArea (CursorArea a, int x, int y) { MYREADERLOCK(l, lockRW); - if (!drawable || !preview) { + if (!drawable || preview.empty()) { return false; } diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 102c17daf..08bcc276b 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -42,6 +42,7 @@ #include "pathutils.h" #include "thumbnail.h" #include "toolbar.h" +#include "inspector.h" using namespace std; @@ -1227,8 +1228,9 @@ void FileCatalog::developRequested(const std::vector& tbe, bo rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline); - const int ph = BatchQueue::calcMaxThumbnailHeight(); - const int pw = th->getThumbnailWidth(ph); + int pw; + int ph = BatchQueue::calcMaxThumbnailHeight(); + th->getThumbnailSize (pw, ph); // processThumbImage is the processing intensive part, but adding to queue must be ordered //#pragma omp ordered @@ -2446,6 +2448,8 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) case GDK_KEY_underscore: zoomOut(); return true; + default: // do nothing, avoids a cppcheck false positive + break; } } @@ -2506,6 +2510,15 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) } } + if (!ctrl && !alt) { + switch (event->keyval) { + case GDK_KEY_f: + case GDK_KEY_F: + fileBrowser->getInspector()->showWindow(!shift); + return true; + } + } + return fileBrowser->keyPressed(event); } diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 1a66aed7c..17a5c9c5b 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -115,9 +115,12 @@ FilePanel::FilePanel () : parent(nullptr), error(0) Gtk::Label* devLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_DEVELOP")) ); devLab->set_name ("LabelRightNotebook"); devLab->set_angle (90); - Gtk::Label* inspectLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_INSPECT")) ); - inspectLab->set_name ("LabelRightNotebook"); - inspectLab->set_angle (90); + Gtk::Label* inspectLab = nullptr; + if (!options.inspectorWindow) { + inspectLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_INSPECT")) ); + inspectLab->set_name ("LabelRightNotebook"); + inspectLab->set_angle (90); + } Gtk::Label* filtLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_FILTER")) ); filtLab->set_name ("LabelRightNotebook"); filtLab->set_angle (90); @@ -132,7 +135,8 @@ FilePanel::FilePanel () : parent(nullptr), error(0) tpcPaned->pack2 (*history, true, false); rightNotebook->append_page (*sFilterPanel, *filtLab); - rightNotebook->append_page (*inspectorPanel, *inspectLab); + if (!options.inspectorWindow) + rightNotebook->append_page (*inspectorPanel, *inspectLab); rightNotebook->append_page (*tpcPaned, *devLab); //rightNotebook->append_page (*taggingBox, *tagLab); commented out: currently the tab is empty ... rightNotebook->append_page (*sExportPanel, *exportLab); diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index 276f57a70..4f5c36f29 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -26,64 +26,196 @@ #include "rtimage.h" #include "../rtengine/procparams.h" +#include "../rtengine/color.h" namespace { -Adjuster* createExponentAdjuster(AdjusterListener* listener, const Glib::ustring& label, double minV, double maxV, double defaultVal) +double toAdjuster(double v) { - Adjuster* const adj = Gtk::manage(new Adjuster(label, minV, maxV, 0.001, defaultVal)); + return CLAMP(std::log2(v), 6, 16) - 6; +} + +double fromAdjuster(double v) +{ + return std::pow(2, v + 6); +} + +Adjuster* createExponentAdjuster(AdjusterListener* listener, const Glib::ustring& label, double minV, double maxV, double step, double defaultVal) +{ + Adjuster* const adj = Gtk::manage(new Adjuster(label, minV, maxV, step, defaultVal)); adj->setAdjusterListener(listener); adj->setLogScale(6, 1, true); - if (adj->delay < options.adjusterMaxDelay) { - adj->delay = options.adjusterMaxDelay; - } + adj->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); adj->show(); return adj; } -Glib::ustring formatBaseValues(const std::array& rgb) +Adjuster* createLevelAdjuster(AdjusterListener* listener, const Glib::ustring& label) { - if (rgb[0] <= 0.f && rgb[1] <= 0.f && rgb[2] <= 0.f) { +// Adjuster* const adj = Gtk::manage(new Adjuster(label, 1.0, 65535.0, 1.0, rtengine::MAXVALF / 24.)); + Adjuster* const adj = Gtk::manage(new Adjuster(label, 0.0, 10.0, 0.01, toAdjuster(rtengine::MAXVALF / 24.))); + adj->setAdjusterListener(listener); +// adj->setLogScale(6, 1000.0, true); + + adj->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + + adj->show(); + return adj; +} + +Adjuster* createBalanceAdjuster(AdjusterListener* listener, const Glib::ustring& label, double minV, double maxV, double defaultVal, + const Glib::ustring& leftIcon, const Glib::ustring& rightIcon) +{ + Adjuster* const adj = Gtk::manage(new Adjuster(label, minV, maxV, 0.01, defaultVal, + Gtk::manage(new RTImage(leftIcon)), Gtk::manage(new RTImage(rightIcon)))); + adj->setAdjusterListener(listener); + adj->setLogScale(9, 0, true); + + adj->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + + adj->show(); + return adj; +} + + +Glib::ustring fmt(const RGB& rgb) +{ + if (rgb.r <= 0.f && rgb.g <= 0.f && rgb.b <= 0.f) { return "- - -"; } else { - return Glib::ustring::format(std::fixed, std::setprecision(1), rgb[0]) + " " + - Glib::ustring::format(std::fixed, std::setprecision(1), rgb[1]) + " " + - Glib::ustring::format(std::fixed, std::setprecision(1), rgb[2]); + return Glib::ustring::format(std::fixed, std::setprecision(1), rgb.r) + " " + + Glib::ustring::format(std::fixed, std::setprecision(1), rgb.g) + " " + + Glib::ustring::format(std::fixed, std::setprecision(1), rgb.b); } } + +RGB getFilmNegativeExponents(const RGB &ref1, const RGB &ref2) // , const RGB &clearValsOut, const RGB &denseValsOut) +{ + using rtengine::settings; + + RGB clearVals = ref1; + RGB denseVals = ref2; + + // Detect which one is the dense spot, based on green channel + if (clearVals.g < denseVals.g) { + std::swap(clearVals, denseVals); + //std::swap(clearValsOut, denseValsOut); + } + + if (settings->verbose) { + printf("Clear input values: R=%g G=%g B=%g\n", static_cast(clearVals.r), static_cast(clearVals.g), static_cast(clearVals.b)); + printf("Dense input values: R=%g G=%g B=%g\n", static_cast(denseVals.r), static_cast(denseVals.g), static_cast(denseVals.b)); + + // printf("Clear output values: R=%g G=%g B=%g\n", static_cast(clearValsOut.r), static_cast(clearValsOut.g), static_cast(clearValsOut.b)); + // printf("Dense output values: R=%g G=%g B=%g\n", static_cast(denseValsOut.r), static_cast(denseValsOut.g), static_cast(denseValsOut.b)); + } + + const float denseGreenRatio = clearVals.g / denseVals.g; + + // Calculate logarithms in arbitrary base + const auto logBase = + [](float base, float num) -> float + { + return std::log(num) / std::log(base); + }; + + // const auto ratio = + // [](float a, float b) -> float + // { + // return a > b ? a / b : b / a; + // }; + + RGB newExps; + newExps.r = logBase(clearVals.r / denseVals.r, denseGreenRatio); + newExps.g = 1.f; // logBase(ratio(clearVals.g, denseVals.g), ratio(denseValsOut.g, clearValsOut.g) ); + newExps.b = logBase(clearVals.b / denseVals.b, denseGreenRatio); + + + + if (settings->verbose) { + printf("New exponents: R=%g G=%g B=%g\n", static_cast(newExps.r), static_cast(newExps.g), static_cast(newExps.b)); + } + + // // Re-adjust color balance based on dense spot values and new exponents + // calcBalance(rtengine::max(static_cast(params->filmNegative.refInput.g), 1.f), + // -newExps[0], -newExps[1], -newExps[2], + // denseVals[0], denseVals[1], denseVals[2], + // rBal, bBal); + + return newExps; + +} + +void temp2rgb(double outLev, double temp, double green, RGB &refOut) +{ + rtengine::ColorTemp ct = rtengine::ColorTemp(temp, green, 1., "Custom"); + + double rm, gm, bm; + ct.getMultipliers(rm, gm, bm); + + double maxGain = rtengine::max(rm, gm, bm); + + refOut.r = (rm / maxGain) * outLev; + refOut.g = (gm / maxGain) * outLev; + refOut.b = (bm / maxGain) * outLev; +} + + +void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) +{ + double maxVal = rtengine::max(refOut.r, refOut.g, refOut.b); + + rtengine::ColorTemp ct = rtengine::ColorTemp( + refOut.r / maxVal, + refOut.g / maxVal, + refOut.b / maxVal, + 1.); + + outLev = maxVal; + temp = ct.getTemp(); + green = ct.getGreen(); +} + + } FilmNegative::FilmNegative() : FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS), - evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_VALUES")), - evFilmNegativeEnabled(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_ENABLED")), - evFilmBaseValues(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_FILMBASE")), - filmBaseValues({0.f, 0.f, 0.f}), + NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1.)), + evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_VALUES")), + evFilmNegativeEnabled(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_ENABLED")), + evFilmNegativeRefSpot(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_REF_SPOT")), + evFilmNegativeBalance(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_BALANCE")), + evFilmNegativeColorSpace(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_COLORSPACE")), + refInputValues({0.f, 0.f, 0.f}), + paramsUpgraded(false), fnp(nullptr), - greenExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_GREEN"), 0.3, 4, 1.5)), // master exponent (green channel) - redRatio(createExponentAdjuster(this, M("TP_FILMNEGATIVE_RED"), 0.3, 3, (2.04 / 1.5))), // ratio of red exponent to master exponent - blueRatio(createExponentAdjuster(this, M("TP_FILMNEGATIVE_BLUE"), 0.3, 3, (1.29 / 1.5))), // ratio of blue exponent to master exponent - spotgrid(Gtk::manage(new Gtk::Grid())), - spotbutton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_PICK")))), - filmBaseLabel(Gtk::manage(new Gtk::Label(M("TP_FILMNEGATIVE_FILMBASE_VALUES"), Gtk::ALIGN_START))), - filmBaseValuesLabel(Gtk::manage(new Gtk::Label("- - -"))), - filmBaseSpotButton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_FILMBASE_PICK")))) + colorSpace(Gtk::manage(new MyComboBoxText())), + greenExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_GREEN"), 0.3, 4, 0.01, 1.5)), // master exponent (green channel) + redRatio(createExponentAdjuster(this, M("TP_FILMNEGATIVE_RED"), 0.3, 5, 0.01, (2.04 / 1.5))), // ratio of red exponent to master exponent + blueRatio(createExponentAdjuster(this, M("TP_FILMNEGATIVE_BLUE"), 0.3, 5, 0.01, (1.29 / 1.5))), // ratio of blue exponent to master exponent + spotButton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_PICK")))), + refInputLabel(Gtk::manage(new Gtk::Label(Glib::ustring::compose(M("TP_FILMNEGATIVE_REF_LABEL"), "- - -")))), + refSpotButton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_REF_PICK")))), + outputLevel(createLevelAdjuster(this, M("TP_FILMNEGATIVE_OUT_LEVEL"))), // ref level + greenBalance(createBalanceAdjuster(this, M("TP_FILMNEGATIVE_GREENBALANCE"), -3.0, 3.0, 0.0, "circle-magenta-small.png", "circle-green-small.png")), // green balance + blueBalance(createBalanceAdjuster(this, M("TP_FILMNEGATIVE_BLUEBALANCE"), -3.0, 3.0, 0.0, "circle-blue-small.png", "circle-yellow-small.png")) // blue balance { - spotgrid->get_style_context()->add_class("grid-spacing"); - setExpandAlignProperties(spotgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + setExpandAlignProperties(spotButton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + spotButton->get_style_context()->add_class("independent"); + spotButton->set_tooltip_text(M("TP_FILMNEGATIVE_GUESS_TOOLTIP")); + spotButton->set_image(*Gtk::manage(new RTImage("color-picker-small.png"))); - setExpandAlignProperties(spotbutton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - spotbutton->get_style_context()->add_class("independent"); - spotbutton->set_tooltip_text(M("TP_FILMNEGATIVE_GUESS_TOOLTIP")); - spotbutton->set_image(*Gtk::manage(new RTImage("color-picker-small.png"))); + refSpotButton->set_tooltip_text(M("TP_FILMNEGATIVE_REF_TOOLTIP")); - filmBaseSpotButton->set_tooltip_text(M("TP_FILMNEGATIVE_FILMBASE_TOOLTIP")); - setExpandAlignProperties(filmBaseValuesLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(refInputLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); +// refInputLabel->set_justify(Gtk::Justification::JUSTIFY_CENTER); +// refInputLabel->set_line_wrap(true); // TODO make spot size configurable ? @@ -100,30 +232,53 @@ FilmNegative::FilmNegative() : // spotsize->set_active(0); // spotsize->append ("4"); - spotgrid->attach(*spotbutton, 0, 1, 1, 1); + // spotgrid->attach(*spotButton, 0, 1, 1, 1); // spotgrid->attach (*slab, 1, 0, 1, 1); // spotgrid->attach (*wbsizehelper, 2, 0, 1, 1); + colorSpace->append(M("TP_FILMNEGATIVE_COLORSPACE_INPUT")); + colorSpace->append(M("TP_FILMNEGATIVE_COLORSPACE_WORKING")); + setExpandAlignProperties(colorSpace, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + colorSpace->set_tooltip_markup(M("TP_FILMNEGATIVE_COLORSPACE_TOOLTIP")); + + Gtk::Grid* csGrid = Gtk::manage(new Gtk::Grid()); + Gtk::Label* csLabel = Gtk::manage(new Gtk::Label(M("TP_FILMNEGATIVE_COLORSPACE"))); + csGrid->attach(*csLabel, 0, 0, 1, 1); + csGrid->attach(*colorSpace, 1, 0, 1, 1); + + pack_start(*csGrid); + + colorSpace->set_active((int)ColorSpace::WORKING); + colorSpace->signal_changed().connect(sigc::mem_fun(*this, &FilmNegative::colorSpaceChanged)); + colorSpace->show(); + pack_start(*greenExp, Gtk::PACK_SHRINK, 0); pack_start(*redRatio, Gtk::PACK_SHRINK, 0); pack_start(*blueRatio, Gtk::PACK_SHRINK, 0); - pack_start(*spotgrid, Gtk::PACK_SHRINK, 0); + pack_start(*spotButton, Gtk::PACK_SHRINK, 0); + +// pack_start(*oldMethod, Gtk::PACK_SHRINK, 0); Gtk::HSeparator* const sep = Gtk::manage(new Gtk::HSeparator()); sep->get_style_context()->add_class("grid-row-separator"); pack_start(*sep, Gtk::PACK_SHRINK, 0); - Gtk::Grid* const fbGrid = Gtk::manage(new Gtk::Grid()); - fbGrid->attach(*filmBaseLabel, 0, 0, 1, 1); - fbGrid->attach(*filmBaseValuesLabel, 1, 0, 1, 1); - pack_start(*fbGrid, Gtk::PACK_SHRINK, 0); +// Gtk::Grid* const fbGrid = Gtk::manage(new Gtk::Grid()); +// fbGrid->attach(*refInputLabel, 0, 0, 1, 1); +// fbGrid->attach(*filmBaseValuesLabel, 1, 0, 1, 1); +// pack_start(*fbGrid, Gtk::PACK_SHRINK, 0); + pack_start(*refInputLabel, Gtk::PACK_SHRINK, 0); - pack_start(*filmBaseSpotButton, Gtk::PACK_SHRINK, 0); + pack_start(*outputLevel, Gtk::PACK_SHRINK, 0); + pack_start(*blueBalance, Gtk::PACK_SHRINK, 0); + pack_start(*greenBalance, Gtk::PACK_SHRINK, 0); - spotbutton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::editToggled)); + pack_start(*refSpotButton, Gtk::PACK_SHRINK, 0); + + spotButton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::editToggled)); // spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) ); - filmBaseSpotButton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::baseSpotToggled)); + refSpotButton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::refSpotToggled)); // Editing geometry; create the spot rectangle Rectangle* const spotRect = new Rectangle(); @@ -141,6 +296,8 @@ FilmNegative::FilmNegative() : FilmNegative::~FilmNegative() { + idle_register.destroy(); + for (auto geometry : visibleGeometry) { delete geometry; } @@ -150,6 +307,26 @@ FilmNegative::~FilmNegative() } } + +void FilmNegative::readOutputSliders(RGB &refOut) +{ + temp2rgb(fromAdjuster(outputLevel->getValue()), + NEUTRAL_TEMP.getTemp() / std::pow(2., blueBalance->getValue()), + NEUTRAL_TEMP.getGreen() / std::pow(2., greenBalance->getValue()), + refOut); +} + +void FilmNegative::writeOutputSliders(const RGB &refOut) +{ + double outLev, cTemp, green; + rgb2temp(refOut, outLev, cTemp, green); + + outputLevel->setValue(toAdjuster(outLev)); + blueBalance->setValue(std::log2(NEUTRAL_TEMP.getTemp() / cTemp)); + greenBalance->setValue(std::log2(NEUTRAL_TEMP.getGreen() / green)); +} + + void FilmNegative::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener(); @@ -158,27 +335,54 @@ void FilmNegative::read(const rtengine::procparams::ProcParams* pp, const Params redRatio->setEditedState(pedited->filmNegative.redRatio ? Edited : UnEdited); greenExp->setEditedState(pedited->filmNegative.greenExp ? Edited : UnEdited); blueRatio->setEditedState(pedited->filmNegative.blueRatio ? Edited : UnEdited); + outputLevel->setEditedState(pedited->filmNegative.refOutput ? Edited : UnEdited); + greenBalance->setEditedState(pedited->filmNegative.refOutput ? Edited : UnEdited); + blueBalance->setEditedState(pedited->filmNegative.refOutput ? Edited : UnEdited); set_inconsistent(multiImage && !pedited->filmNegative.enabled); } setEnabled(pp->filmNegative.enabled); + + colorSpace->set_active(CLAMP((int)pp->filmNegative.colorSpace, 0, 1)); redRatio->setValue(pp->filmNegative.redRatio); greenExp->setValue(pp->filmNegative.greenExp); blueRatio->setValue(pp->filmNegative.blueRatio); - filmBaseValues[0] = pp->filmNegative.redBase; - filmBaseValues[1] = pp->filmNegative.greenBase; - filmBaseValues[2] = pp->filmNegative.blueBase; + refInputValues = pp->filmNegative.refInput; - // If base values are not set in params, estimated values will be passed in later + // If reference input values are not set in params, estimated values will be passed in later // (after processing) via FilmNegListener - filmBaseValuesLabel->set_text(formatBaseValues(filmBaseValues)); + refInputLabel->set_markup( + Glib::ustring::compose(M("TP_FILMNEGATIVE_REF_LABEL"), fmt(refInputValues))); + + if (pp->filmNegative.backCompat == BackCompat::CURRENT) { + outputLevel->show(); + blueBalance->show(); + greenBalance->show(); + } else { + outputLevel->hide(); + blueBalance->hide(); + greenBalance->hide(); + } + + // If reference output values are not set in params, set the default output + // chosen for median estimation: gray 1/24th of max + if (pp->filmNegative.refOutput.r <= 0) { + float gray = rtengine::MAXVALF / 24.f; + writeOutputSliders({gray, gray, gray}); + } else { + writeOutputSliders(pp->filmNegative.refOutput); + } enableListener(); } void FilmNegative::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { + if (colorSpace->get_active_row_number() != 3) { // UNCHANGED entry, see setBatchMode + pp->filmNegative.colorSpace = rtengine::procparams::FilmNegativeParams::ColorSpace(colorSpace->get_active_row_number()); + } + pp->filmNegative.redRatio = redRatio->getValue(); pp->filmNegative.greenExp = greenExp->getValue(); pp->filmNegative.blueRatio = blueRatio->getValue(); @@ -186,18 +390,23 @@ void FilmNegative::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped pp->filmNegative.enabled = getEnabled(); if (pedited) { + pedited->filmNegative.colorSpace = colorSpace->get_active_row_number() != 3; // UNCHANGED entry, see setBatchMode pedited->filmNegative.redRatio = redRatio->getEditedState(); pedited->filmNegative.greenExp = greenExp->getEditedState(); pedited->filmNegative.blueRatio = blueRatio->getEditedState(); - pedited->filmNegative.baseValues = filmBaseValues[0] != pp->filmNegative.redBase - || filmBaseValues[1] != pp->filmNegative.greenBase - || filmBaseValues[2] != pp->filmNegative.blueBase; + pedited->filmNegative.refOutput = outputLevel->getEditedState() || greenBalance->getEditedState() || blueBalance->getEditedState(); + // In batch mode, make sure refinput is always updated together with the balance sliders + pedited->filmNegative.refInput = pedited->filmNegative.refOutput || (refInputValues != pp->filmNegative.refInput); pedited->filmNegative.enabled = !get_inconsistent(); } - pp->filmNegative.redBase = filmBaseValues[0]; - pp->filmNegative.greenBase = filmBaseValues[1]; - pp->filmNegative.blueBase = filmBaseValues[2]; + pp->filmNegative.refInput = refInputValues; + + readOutputSliders(pp->filmNegative.refOutput); + + if (paramsUpgraded) { + pp->filmNegative.backCompat = BackCompat::CURRENT; + } } @@ -207,44 +416,70 @@ void FilmNegative::setDefaults(const rtengine::procparams::ProcParams* defParams greenExp->setValue(defParams->filmNegative.greenExp); blueRatio->setValue(defParams->filmNegative.blueRatio); + float gray = rtengine::MAXVALF / 24.f; + writeOutputSliders({gray, gray, gray}); + if (pedited) { redRatio->setDefaultEditedState(pedited->filmNegative.redRatio ? Edited : UnEdited); greenExp->setDefaultEditedState(pedited->filmNegative.greenExp ? Edited : UnEdited); blueRatio->setDefaultEditedState(pedited->filmNegative.blueRatio ? Edited : UnEdited); + + outputLevel->setDefaultEditedState(pedited->filmNegative.refOutput ? Edited : UnEdited); + greenBalance->setDefaultEditedState(pedited->filmNegative.refOutput ? Edited : UnEdited); + blueBalance->setDefaultEditedState(pedited->filmNegative.refOutput ? Edited : UnEdited); } else { redRatio->setDefaultEditedState(Irrelevant); greenExp->setDefaultEditedState(Irrelevant); blueRatio->setDefaultEditedState(Irrelevant); + outputLevel->setDefaultEditedState(Irrelevant); + greenBalance->setDefaultEditedState(Irrelevant); + blueBalance->setDefaultEditedState(Irrelevant); } } void FilmNegative::setBatchMode(bool batchMode) { + ToolPanel::setBatchMode(batchMode); + if (batchMode) { - removeIfThere(this, spotgrid, false); - removeIfThere(this, filmBaseSpotButton, false); - ToolPanel::setBatchMode(batchMode); + removeIfThere(this, spotButton, false); + removeIfThere(this, refSpotButton, false); + colorSpace->append(M("GENERAL_UNCHANGED")); + colorSpace->set_active_text(M("GENERAL_UNCHANGED")); redRatio->showEditedCB(); greenExp->showEditedCB(); blueRatio->showEditedCB(); + removeIfThere(this, refInputLabel, false); + removeIfThere(this, outputLevel, false); + removeIfThere(this, greenBalance, false); + removeIfThere(this, blueBalance, false); } } void FilmNegative::adjusterChanged(Adjuster* a, double newval) { - if (listener) { + if (listener && getEnabled()) { if (a == redRatio || a == greenExp || a == blueRatio) { - if (getEnabled()) { - listener->panelChanged( - evFilmNegativeExponents, - Glib::ustring::compose( - "Ref=%1\nR=%2\nB=%3", - greenExp->getValue(), - redRatio->getValue(), - blueRatio->getValue() - ) - ); - } + listener->panelChanged( + evFilmNegativeExponents, + Glib::ustring::compose( + "Ref=%1\nR=%2\nB=%3", + greenExp->getValue(), + redRatio->getValue(), + blueRatio->getValue() + ) + ); + } else if (a == outputLevel || a == greenBalance || a == blueBalance) { + + listener->panelChanged( + evFilmNegativeBalance, + Glib::ustring::compose( + "Lev=%1 G=%2 B=%3", + outputLevel->getValue(), + greenBalance->getValue(), + blueBalance->getValue() + ) + ); } } } @@ -262,10 +497,37 @@ void FilmNegative::enabledChanged() } } -void FilmNegative::filmBaseValuesChanged(std::array rgb) +void FilmNegative::colorSpaceChanged() { - filmBaseValues = rgb; - filmBaseValuesLabel->set_text(formatBaseValues(filmBaseValues)); + if (listener) { + listener->panelChanged(evFilmNegativeColorSpace, colorSpace->get_active_text()); + } +} + +void FilmNegative::filmRefValuesChanged(const RGB &refInput, const RGB &refOutput) +{ + + idle_register.add( + [this, refInput, refOutput]() -> bool { + refInputValues = refInput; + paramsUpgraded = true; + + disableListener(); + + refInputLabel->set_markup( + Glib::ustring::compose(M("TP_FILMNEGATIVE_REF_LABEL"), fmt(refInputValues))); + + writeOutputSliders(refOutput); + + outputLevel->show(); + blueBalance->show(); + greenBalance->show(); + + enableListener(); + return false; + } + ); + } void FilmNegative::setFilmNegProvider(FilmNegProvider* provider) @@ -299,7 +561,7 @@ bool FilmNegative::button1Pressed(int modifierKey) EditSubscriber::action = EditSubscriber::Action::NONE; if (listener) { - if (spotbutton->get_active()) { + if (spotButton->get_active()) { refSpotCoords.push_back(provider->posImage); @@ -307,17 +569,23 @@ bool FilmNegative::button1Pressed(int modifierKey) // User has selected 2 reference gray spots. Calculating new exponents // from channel values and updating parameters. - std::array newExps; + RGB ref1, ref2, dummy; + + if (fnp->getFilmNegativeSpot(refSpotCoords[0], 32, ref1, dummy) && + fnp->getFilmNegativeSpot(refSpotCoords[1], 32, ref2, dummy)) { - if (fnp->getFilmNegativeExponents(refSpotCoords[0], refSpotCoords[1], newExps)) { disableListener(); + + RGB newExps = getFilmNegativeExponents(ref1, ref2); + // Leaving green exponent unchanged, setting red and blue exponents based on // the ratios between newly calculated exponents. - redRatio->setValue(newExps[0] / newExps[1]); - blueRatio->setValue(newExps[2] / newExps[1]); + redRatio->setValue(newExps.r / newExps.g); + blueRatio->setValue(newExps.b / newExps.g); + enableListener(); - if (listener && getEnabled()) { + if (getEnabled()) { listener->panelChanged( evFilmNegativeExponents, Glib::ustring::compose( @@ -328,32 +596,37 @@ bool FilmNegative::button1Pressed(int modifierKey) ) ); } + } switchOffEditMode(); + } - } else if (filmBaseSpotButton->get_active()) { - std::array newBaseLev; + } else if (refSpotButton->get_active()) { - if (fnp->getRawSpotValues(provider->posImage, 32, newBaseLev)) { - disableListener(); + RGB refOut; + fnp->getFilmNegativeSpot(provider->posImage, 32, refInputValues, refOut); - filmBaseValues = newBaseLev; + disableListener(); - enableListener(); + float gray = rtengine::Color::rgbLuminance(refOut.r, refOut.g, refOut.b); + writeOutputSliders({gray, gray, gray}); - const Glib::ustring vs = formatBaseValues(filmBaseValues); + refInputLabel->set_text( + Glib::ustring::compose(M("TP_FILMNEGATIVE_REF_LABEL"), fmt(refInputValues))); - filmBaseValuesLabel->set_text(vs); + enableListener(); - if (listener && getEnabled()) { - listener->panelChanged(evFilmBaseValues, vs); - } - } + listener->panelChanged( + evFilmNegativeRefSpot, + Glib::ustring::compose( + "%1, %2, %3", + round(refInputValues.r), round(refInputValues.g), round(refInputValues.b) + ) + ); - switchOffEditMode(); } } @@ -366,19 +639,26 @@ bool FilmNegative::button1Released() return true; } +bool FilmNegative::button3Pressed(int modifierKey) +{ + EditSubscriber::action = EditSubscriber::Action::NONE; + switchOffEditMode(); + return true; +} + void FilmNegative::switchOffEditMode() { refSpotCoords.clear(); unsubscribe(); - spotbutton->set_active(false); - filmBaseSpotButton->set_active(false); + spotButton->set_active(false); + refSpotButton->set_active(false); } void FilmNegative::editToggled() { - if (spotbutton->get_active()) { + if (spotButton->get_active()) { - filmBaseSpotButton->set_active(false); + refSpotButton->set_active(false); refSpotCoords.clear(); subscribe(); @@ -396,11 +676,12 @@ void FilmNegative::editToggled() } } -void FilmNegative::baseSpotToggled() + +void FilmNegative::refSpotToggled() { - if (filmBaseSpotButton->get_active()) { + if (refSpotButton->get_active()) { - spotbutton->set_active(false); + spotButton->set_active(false); refSpotCoords.clear(); subscribe(); @@ -412,6 +693,7 @@ void FilmNegative::baseSpotToggled() // This is to make sure the getCursor() call is fired everywhere. Rectangle* const imgRect = static_cast(mouseOverGeometry.at(0)); imgRect->setXYWH(0, 0, w, h); + } else { refSpotCoords.clear(); unsubscribe(); diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h index 8dda5ea71..64ec572d3 100644 --- a/rtgui/filmnegative.h +++ b/rtgui/filmnegative.h @@ -27,13 +27,21 @@ #include "guiutils.h" #include "toolpanel.h" +#include "../rtengine/colortemp.h" + +namespace +{ +using RGB = rtengine::procparams::FilmNegativeParams::RGB; +using ColorSpace = rtengine::procparams::FilmNegativeParams::ColorSpace; +using BackCompat = rtengine::procparams::FilmNegativeParams::BackCompat; +} + class FilmNegProvider { public: virtual ~FilmNegProvider() = default; - virtual bool getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, std::array& newExps) = 0; - virtual bool getRawSpotValues(rtengine::Coord spot, int spotSize, std::array& rawValues) = 0; + virtual bool getFilmNegativeSpot(rtengine::Coord spot, int spotSize, RGB &refInput, RGB &refOutput) = 0; }; class FilmNegative final : @@ -54,8 +62,9 @@ public: void adjusterChanged(Adjuster* a, double newval) override; void enabledChanged() override; + void colorSpaceChanged(); - void filmBaseValuesChanged(std::array rgb) override; + void filmRefValuesChanged(const RGB &refInput, const RGB &refOutput) override; void setFilmNegProvider(FilmNegProvider* provider); @@ -66,31 +75,47 @@ public: bool mouseOver(int modifierKey) override; bool button1Pressed(int modifierKey) override; bool button1Released() override; + bool button3Pressed(int modifierKey) override; void switchOffEditMode() override; private: void editToggled(); - void baseSpotToggled(); + void refSpotToggled(); + + void readOutputSliders(RGB &refOutput); + void writeOutputSliders(const RGB &refOutput); + + // ColorTemp value corresponding to neutral RGB multipliers (1,1,1). Should be around 6500K. + const rtengine::ColorTemp NEUTRAL_TEMP; const rtengine::ProcEvent evFilmNegativeExponents; const rtengine::ProcEvent evFilmNegativeEnabled; - const rtengine::ProcEvent evFilmBaseValues; + const rtengine::ProcEvent evFilmNegativeRefSpot; + const rtengine::ProcEvent evFilmNegativeBalance; + const rtengine::ProcEvent evFilmNegativeColorSpace; std::vector refSpotCoords; - std::array filmBaseValues; + RGB refInputValues; + bool paramsUpgraded; FilmNegProvider* fnp; + MyComboBoxText* const colorSpace; + Adjuster* const greenExp; Adjuster* const redRatio; Adjuster* const blueRatio; - Gtk::Grid* const spotgrid; - Gtk::ToggleButton* const spotbutton; + Gtk::ToggleButton* const spotButton; - Gtk::Label* const filmBaseLabel; - Gtk::Label* const filmBaseValuesLabel; - Gtk::ToggleButton* const filmBaseSpotButton; + Gtk::Label* const refInputLabel; + Gtk::ToggleButton* const refSpotButton; + + Adjuster* const outputLevel; + Adjuster* const greenBalance; + Adjuster* const blueBalance; + + IdleRegister idle_register; }; 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/flatfield.cc b/rtgui/flatfield.cc index 7433fd4de..69d14c463 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -47,9 +47,7 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L flatFieldBlurRadius = Gtk::manage(new Adjuster (M("TP_FLATFIELD_BLURRADIUS"), 0, 200, 2, 32)); flatFieldBlurRadius->setAdjusterListener (this); - if (flatFieldBlurRadius->delay < options.adjusterMaxDelay) { - flatFieldBlurRadius->delay = options.adjusterMaxDelay; - } + flatFieldBlurRadius->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); flatFieldBlurRadius->show(); @@ -67,9 +65,7 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L flatFieldClipControl->setAdjusterListener(this); flatFieldClipControl->addAutoButton(""); - if (flatFieldClipControl->delay < options.adjusterMaxDelay) { - flatFieldClipControl->delay = options.adjusterMaxDelay; - } + flatFieldClipControl->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); flatFieldClipControl->show(); flatFieldClipControl->set_tooltip_markup (M("TP_FLATFIELD_CLIPCONTROL_TOOLTIP")); diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index af949f538..09d75f970 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/histogrampanel.cc b/rtgui/histogrampanel.cc index b8338e4e8..83db36cb4 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -22,17 +22,51 @@ #include "options.h" #include #include +#include "../rtengine/array2D.h" #include "../rtengine/LUT.h" #include "rtimage.h" #include "../rtengine/color.h" using namespace rtengine; +constexpr float HistogramArea::MAX_BRIGHT; +constexpr float HistogramArea::MIN_BRIGHT; + +using ScopeType = Options::ScopeType; // // // HistogramPanel -HistogramPanel::HistogramPanel () +HistogramPanel::HistogramPanel () : + pointer_moved_delayed_call( + [this](bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int r, int g, int b) + { + bool update_hist_area; + + if (!validPos) { + // do something to un-show vertical bars + if (histogramRGBArea) { + histogramRGBArea->updateBackBuffer(-1, -1, -1); + } + update_hist_area = histogramArea->updatePointer(-1, -1, -1); + } else { + // do something to show vertical bars + if (histogramRGBArea) { + histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); + } + update_hist_area = histogramArea->updatePointer(r, g, b, profile, profileW); + } + if (histogramRGBArea) { + histogramRGBArea->queue_draw(); + } + if (update_hist_area) { + histogramArea->queue_draw(); + } + }, + 50, + 100 + ), + panel_listener(nullptr) { setExpandAlignProperties(this, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); set_name("HistogramPanel"); @@ -40,30 +74,51 @@ HistogramPanel::HistogramPanel () histogramArea = Gtk::manage (new HistogramArea (this)); setExpandAlignProperties(histogramArea, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - histogramRGBArea = Gtk::manage (new HistogramRGBArea ()); - setExpandAlignProperties(histogramRGBArea, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); - histogramRGBArea->show(); + histogramRGBAreaHori.reset(new HistogramRGBAreaHori()); + setExpandAlignProperties(histogramRGBAreaHori.get(), true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); + + histogramRGBAreaVert.reset(new HistogramRGBAreaVert()); + setExpandAlignProperties(histogramRGBAreaVert.get(), false, true, Gtk::ALIGN_END, Gtk::ALIGN_FILL); + + switch (options.histogramScopeType) { + case ScopeType::NONE: + case ScopeType::HISTOGRAM_RAW: + case ScopeType::VECTORSCOPE_HC: + case ScopeType::VECTORSCOPE_HS: + histogramRGBArea = nullptr; + break; + case ScopeType::PARADE: + case ScopeType::WAVEFORM: + histogramRGBArea = histogramRGBAreaVert.get(); + break; + case ScopeType::HISTOGRAM: + histogramRGBArea = histogramRGBAreaHori.get(); + break; + } // connecting the two childs - histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBArea, &HistogramRGBArea::factorChanged) ); + histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBAreaHori, &HistogramRGBArea::factorChanged) ); + histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBAreaVert, &HistogramRGBArea::factorChanged) ); gfxGrid = Gtk::manage (new Gtk::Grid ()); - gfxGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); gfxGrid->set_row_spacing(1); gfxGrid->set_column_spacing(1); - histogramRGBArea->setParent(gfxGrid); gfxGrid->add(*histogramArea); - - if (options.histogramBar) { - gfxGrid->add (*histogramRGBArea); - } + gfxGrid->attach_next_to( + *histogramRGBAreaVert, *histogramArea, + options.histogramPosition == 1 ? Gtk::POS_RIGHT : Gtk::POS_LEFT, + 1, + 1 + ); + gfxGrid->attach_next_to(*histogramRGBAreaHori, *histogramArea, Gtk::POS_BOTTOM, 1, 1); + histogramRGBAreaHori->set_no_show_all(); + histogramRGBAreaVert->set_no_show_all(); redImage = new RTImage ("histogram-red-on-small.png"); greenImage = new RTImage ("histogram-green-on-small.png"); blueImage = new RTImage ("histogram-blue-on-small.png"); valueImage = new RTImage ("histogram-silver-on-small.png"); chroImage = new RTImage ("histogram-gold-on-small.png"); - rawImage = new RTImage ("histogram-bayer-on-small.png"); barImage = new RTImage ("histogram-bar-on-small.png"); redImage_g = new RTImage ("histogram-red-off-small.png"); @@ -71,21 +126,41 @@ HistogramPanel::HistogramPanel () blueImage_g = new RTImage ("histogram-blue-off-small.png"); valueImage_g = new RTImage ("histogram-silver-off-small.png"); chroImage_g = new RTImage ("histogram-gold-off-small.png"); - rawImage_g = new RTImage ("histogram-bayer-off-small.png"); barImage_g = new RTImage ("histogram-bar-off-small.png"); mode0Image = new RTImage ("histogram-mode-linear-small.png"); mode1Image = new RTImage ("histogram-mode-logx-small.png"); mode2Image = new RTImage ("histogram-mode-logxy-small.png"); + Gtk::Image* histImage = Gtk::manage(new RTImage("histogram-type-histogram-small.png")); + Gtk::Image* histRawImage = Gtk::manage(new RTImage("histogram-type-histogram-raw-small.png")); + Gtk::Image* paradeImage = Gtk::manage(new RTImage("histogram-type-parade-small.png")); + Gtk::Image* waveImage = Gtk::manage(new RTImage("histogram-type-waveform-small.png")); + Gtk::Image* vectHcImage = Gtk::manage(new RTImage("histogram-type-vectorscope-hc-small.png")); + Gtk::Image* vectHsImage = Gtk::manage(new RTImage("histogram-type-vectorscope-hs-small.png")); + showRed = Gtk::manage (new Gtk::ToggleButton ()); showGreen = Gtk::manage (new Gtk::ToggleButton ()); showBlue = Gtk::manage (new Gtk::ToggleButton ()); showValue = Gtk::manage (new Gtk::ToggleButton ()); showChro = Gtk::manage (new Gtk::ToggleButton ()); - showRAW = Gtk::manage (new Gtk::ToggleButton ()); showMode = Gtk::manage (new Gtk::Button ()); showBAR = Gtk::manage (new Gtk::ToggleButton ()); + scopeOptions = Gtk::manage (new Gtk::ToggleButton ()); + + Gtk::RadioButtonGroup scopeTypeGroup; + scopeHistBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeHistRawBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeParadeBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeWaveBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeVectHcBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeVectHsBtn = Gtk::manage(new Gtk::RadioButton(scopeTypeGroup)); + scopeHistBtn->set_mode(false); + scopeHistRawBtn->set_mode(false); + scopeParadeBtn->set_mode(false); + scopeWaveBtn->set_mode(false); + scopeVectHcBtn->set_mode(false); + scopeVectHsBtn->set_mode(false); showRed->set_name("histButton"); showRed->set_can_focus(false); @@ -97,40 +172,68 @@ HistogramPanel::HistogramPanel () showValue->set_can_focus(false); showChro->set_name("histButton"); showChro->set_can_focus(false); - showRAW->set_name("histButton"); - showRAW->set_can_focus(false); showMode->set_name("histButton"); showMode->set_can_focus(false); + scopeOptions->set_name("histButton"); + scopeOptions->set_can_focus(false); showBAR->set_name("histButton"); showBAR->set_can_focus(false); + scopeHistBtn->set_name("histButton"); + scopeHistBtn->set_can_focus(false); + scopeHistRawBtn->set_name("histButton"); + scopeHistRawBtn->set_can_focus(false); + scopeParadeBtn->set_name("histButton"); + scopeParadeBtn->set_can_focus(false); + scopeWaveBtn->set_name("histButton"); + scopeWaveBtn->set_can_focus(false); + scopeVectHcBtn->set_name("histButton"); + scopeVectHcBtn->set_can_focus(false); + scopeVectHsBtn->set_name("histButton"); + scopeVectHsBtn->set_can_focus(false); showRed->set_relief (Gtk::RELIEF_NONE); showGreen->set_relief (Gtk::RELIEF_NONE); showBlue->set_relief (Gtk::RELIEF_NONE); showValue->set_relief (Gtk::RELIEF_NONE); showChro->set_relief (Gtk::RELIEF_NONE); - showRAW->set_relief (Gtk::RELIEF_NONE); showMode->set_relief (Gtk::RELIEF_NONE); + scopeOptions->set_relief (Gtk::RELIEF_NONE); showBAR->set_relief (Gtk::RELIEF_NONE); + scopeHistBtn->set_relief (Gtk::RELIEF_NONE); + scopeHistRawBtn->set_relief (Gtk::RELIEF_NONE); + scopeParadeBtn->set_relief (Gtk::RELIEF_NONE); + scopeWaveBtn->set_relief (Gtk::RELIEF_NONE); + scopeVectHcBtn->set_relief (Gtk::RELIEF_NONE); + scopeVectHsBtn->set_relief (Gtk::RELIEF_NONE); showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R")); showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G")); showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B")); showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); showChro->set_tooltip_text (M("HISTOGRAM_TOOLTIP_CHRO")); - showRAW->set_tooltip_text (M("HISTOGRAM_TOOLTIP_RAW")); showMode->set_tooltip_text (M("HISTOGRAM_TOOLTIP_MODE")); - showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); + scopeOptions->set_tooltip_text(M("HISTOGRAM_TOOLTIP_SHOW_OPTIONS")); + scopeHistBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM")); + scopeHistRawBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW")); + scopeParadeBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_PARADE")); + scopeWaveBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_WAVEFORM")); + scopeVectHcBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HC")); + scopeVectHsBtn->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TYPE_VECTORSCOPE_HS")); buttonGrid = Gtk::manage (new Gtk::Grid ()); - buttonGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); + buttonGrid->set_orientation(Gtk::ORIENTATION_HORIZONTAL); + persistentButtons = Gtk::manage(new Gtk::Box()); + persistentButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); + optionButtons = Gtk::manage(new Gtk::Box()); + optionButtons->set_orientation(Gtk::ORIENTATION_VERTICAL); + showRed->set_active (options.histogramRed); showGreen->set_active (options.histogramGreen); showBlue->set_active (options.histogramBlue); showValue->set_active (options.histogramLuma); showChro->set_active (options.histogramChroma); - showRAW->set_active (options.histogramRAW); // no showMode->set_active(), as it's not a ToggleButton + scopeOptions->set_active(options.histogramShowOptionButtons); showBAR->set_active (options.histogramBar); showRed->set_image (showRed->get_active() ? *redImage : *redImage_g); @@ -138,66 +241,145 @@ HistogramPanel::HistogramPanel () showBlue->set_image (showBlue->get_active() ? *blueImage : *blueImage_g); showValue->set_image (showValue->get_active() ? *valueImage : *valueImage_g); showChro->set_image (showChro->get_active() ? *chroImage : *chroImage_g); - showRAW->set_image (showRAW->get_active() ? *rawImage : *rawImage_g); if (options.histogramDrawMode == 0) showMode->set_image(*mode0Image); else if (options.histogramDrawMode == 1) showMode->set_image(*mode1Image); else showMode->set_image(*mode2Image); + scopeHistBtn->set_image(*histImage); + scopeHistRawBtn->set_image(*histRawImage); + scopeParadeBtn->set_image(*paradeImage); + scopeWaveBtn->set_image(*waveImage); + scopeVectHcBtn->set_image(*vectHcImage); + scopeVectHsBtn->set_image(*vectHsImage); + switch(options.histogramScopeType) { + case ScopeType::HISTOGRAM: + scopeHistBtn->set_active(); + break; + case ScopeType::HISTOGRAM_RAW: + scopeHistRawBtn->set_active(); + break; + case ScopeType::PARADE: + scopeParadeBtn->set_active(); + break; + case ScopeType::WAVEFORM: + scopeWaveBtn->set_active(); + break; + case ScopeType::VECTORSCOPE_HS: + scopeVectHsBtn->set_active(); + break; + case ScopeType::VECTORSCOPE_HC: + scopeVectHcBtn->set_active(); + break; + case ScopeType::NONE: + break; + } + scopeOptions->set_image(*Gtk::manage(new RTImage("histogram-ellipsis-small.png"))); showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); - - raw_toggled(); // Make sure the luma/chroma toggles are enabled or disabled - setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showRAW , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(scopeOptions, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + setExpandAlignProperties(scopeOptions, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeHistBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeHistRawBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeParadeBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeWaveBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeVectHcBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(scopeVectHsBtn, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(persistentButtons, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + setExpandAlignProperties(optionButtons, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::red_toggled), showRed ); showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::green_toggled), showGreen ); showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::blue_toggled), showBlue ); showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::value_toggled), showValue ); showChro->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::chro_toggled), showChro ); - showRAW->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::raw_toggled), showRAW ); showMode->signal_released().connect( sigc::mem_fun(*this, &HistogramPanel::mode_released), showMode ); + scopeOptions->signal_toggled().connect(sigc::mem_fun(*this, &HistogramPanel::scopeOptionsToggled)); showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); + scopeHistBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistBtn)); + scopeHistRawBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeHistRawBtn)); + scopeParadeBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeParadeBtn)); + scopeWaveBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeWaveBtn)); + scopeVectHcBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHcBtn)); + scopeVectHsBtn->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &HistogramPanel::type_selected), scopeVectHsBtn)); - buttonGrid->add (*showRed); - buttonGrid->add (*showGreen); - buttonGrid->add (*showBlue); - buttonGrid->add (*showValue); - buttonGrid->add (*showChro); - buttonGrid->add (*showRAW); - buttonGrid->add (*showMode); - buttonGrid->add (*showBAR); + brightnessWidget = Gtk::manage(new Gtk::Scale(Gtk::ORIENTATION_VERTICAL)); + brightnessWidget->set_inverted(); + brightnessWidget->set_range(log(HistogramArea::MIN_BRIGHT), log(HistogramArea::MAX_BRIGHT)); + brightnessWidget->set_draw_value(false); + brightnessWidget->signal_value_changed().connect(sigc::mem_fun(*this, &HistogramPanel::brightnessWidgetValueChanged)); + brightnessWidget->set_name("histScale"); + brightnessWidget->set_tooltip_text(M("HISTOGRAM_TOOLTIP_TRACE_BRIGHTNESS")); + setExpandAlignProperties(brightnessWidget, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + + optionButtons->add(*showRed); + optionButtons->add(*showGreen); + optionButtons->add(*showBlue); + optionButtons->add(*showValue); + optionButtons->add(*showChro); + optionButtons->add(*showMode); + optionButtons->add(*showBAR); + optionButtons->add(*brightnessWidget); + + Gtk::VSeparator* separator = Gtk::manage(new Gtk::VSeparator()); + setExpandAlignProperties(separator, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + persistentButtons->add(*scopeHistBtn); + persistentButtons->add(*scopeHistRawBtn); + persistentButtons->add(*scopeParadeBtn); + persistentButtons->add(*scopeWaveBtn); + persistentButtons->add(*scopeVectHsBtn); + persistentButtons->add(*scopeVectHcBtn); + persistentButtons->add(*separator); + persistentButtons->add(*scopeOptions); // Put the button vbox next to the window's border to be less disturbing if (options.histogramPosition == 1) { + buttonGrid->add(*persistentButtons); + buttonGrid->add(*optionButtons); + add (*buttonGrid); add (*gfxGrid); } else { + buttonGrid->add(*optionButtons); + buttonGrid->add(*persistentButtons); + add (*gfxGrid); add (*buttonGrid); } show_all (); + optionButtons->set_no_show_all(); + optionButtons->set_visible(options.histogramShowOptionButtons); + type_changed(); + updateHistAreaOptions(); + if (histogramRGBArea) { + updateHistRGBAreaOptions(); + } + + brightness_changed_connection = histogramArea->getBrighnessChangedSignal().connect(sigc::mem_fun(*this, &HistogramPanel::brightnessUpdated)); rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); + + histogramArea->setBrightness(options.histogramTraceBrightness); } HistogramPanel::~HistogramPanel () { + pointer_moved_delayed_call.cancel(); + delete redImage; delete greenImage; delete blueImage; delete valueImage; delete chroImage; - delete rawImage; delete mode0Image; delete mode1Image; delete mode2Image; @@ -208,24 +390,51 @@ HistogramPanel::~HistogramPanel () delete blueImage_g; delete valueImage_g; delete chroImage_g; - delete rawImage_g; delete barImage_g; } +void HistogramPanel::showRGBBar() +{ + histogramRGBAreaHori->set_visible( + histogramRGBArea == histogramRGBAreaHori.get() && showBAR->get_active()); + histogramRGBAreaVert->set_visible( + histogramRGBArea == histogramRGBAreaVert.get() && showBAR->get_active()); + histogramRGBAreaHori->setShow(false); + histogramRGBAreaVert->setShow(false); + + if (!histogramRGBArea) { + return; + } + + setHistRGBInvalid(); + histogramRGBArea->setShow(showBAR->get_active()); +} + void HistogramPanel::resized (Gtk::Allocation& req) { + static int old_height = 0; + static int old_width = 0; - histogramArea->updateBackBuffer (); - histogramArea->queue_draw (); + bool size_changed = + old_height != req.get_height() || old_width != req.get_width(); + + if (!histogramArea->updatePending() && size_changed) { + histogramArea->updateBackBuffer (); + histogramArea->queue_draw (); + } // set histogramRGBArea invalid; - histogramRGBArea->updateBackBuffer(-1, -1, -1); - histogramRGBArea->queue_draw (); + if (histogramRGBArea && size_changed) { + histogramRGBArea->updateBackBuffer(-1, -1, -1); + histogramRGBArea->queue_draw (); + } // Store current height of the histogram options.histogramHeight = get_height(); + old_height = req.get_height(); + old_width = req.get_width(); } void HistogramPanel::red_toggled () @@ -258,21 +467,6 @@ void HistogramPanel::chro_toggled () rgbv_toggled(); } -void HistogramPanel::raw_toggled () -{ - if (showRAW->get_active()) { - showRAW->set_image(*rawImage); - showValue->set_sensitive(false); - showChro->set_sensitive(false); - } else { - showRAW->set_image(*rawImage_g); - showValue->set_sensitive(true); - showChro->set_sensitive(true); - } - - rgbv_toggled(); -} - void HistogramPanel::mode_released () { options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; @@ -285,21 +479,141 @@ void HistogramPanel::mode_released () rgbv_toggled(); } +void HistogramPanel::brightnessWidgetValueChanged(void) +{ + ConnectionBlocker blocker(brightness_changed_connection); + histogramArea->setBrightness(exp(brightnessWidget->get_value())); + options.histogramTraceBrightness = histogramArea->getBrightness(); +} + +void HistogramPanel::brightnessUpdated(float brightness) +{ + brightnessWidget->set_value(log(brightness)); + options.histogramTraceBrightness = histogramArea->getBrightness(); +} + +void HistogramPanel::scopeOptionsToggled() +{ + options.histogramShowOptionButtons = scopeOptions->get_active(); + optionButtons->set_visible(scopeOptions->get_active()); +} + +void HistogramPanel::type_selected(Gtk::RadioButton* button) +{ + ScopeType new_type = ScopeType::NONE; + + if (button == scopeHistBtn) { + new_type = ScopeType::HISTOGRAM; + } else if (button == scopeHistRawBtn) { + new_type = ScopeType::HISTOGRAM_RAW; + } else if (button == scopeParadeBtn) { + new_type = ScopeType::PARADE; + } else if (button == scopeWaveBtn) { + new_type = ScopeType::WAVEFORM; + } else if (button == scopeVectHcBtn) { + new_type = ScopeType::VECTORSCOPE_HC; + } else if (button == scopeVectHsBtn) { + new_type = ScopeType::VECTORSCOPE_HS; + } + + if (new_type == options.histogramScopeType) { + return; + } + + options.histogramScopeType = new_type; + + type_changed(); + updateHistAreaOptions(); + if (histogramRGBArea) { + updateHistRGBAreaOptions(); + } + histogramArea->setDirty(true); + histogramArea->queue_draw(); +} + +void HistogramPanel::type_changed() +{ + switch (options.histogramScopeType) { + case ScopeType::HISTOGRAM: + showRed->show(); + showGreen->show(); + showBlue->show(); + showValue->show(); + showChro->show(); + showMode->show(); + showBAR->show(); + showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_BAR")); + brightnessWidget->hide(); + histogramRGBArea = histogramRGBAreaHori.get(); + break; + case ScopeType::HISTOGRAM_RAW: + showRed->show(); + showGreen->show(); + showBlue->show(); + showValue->hide(); + showChro->hide(); + showMode->show(); + showBAR->hide(); + brightnessWidget->hide(); + histogramRGBArea = nullptr; + break; + case ScopeType::PARADE: + case ScopeType::WAVEFORM: + showRed->show(); + showGreen->show(); + showBlue->show(); + showValue->show(); + showChro->hide(); + showMode->hide(); + showBAR->show(); + showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_BAR")); + brightnessWidget->show(); + histogramRGBArea = histogramRGBAreaVert.get(); + break; + case ScopeType::VECTORSCOPE_HC: + case ScopeType::VECTORSCOPE_HS: + showRed->hide(); + showGreen->hide(); + showBlue->hide(); + showValue->hide(); + showChro->hide(); + showMode->hide(); + showBAR->show(); + showBAR->set_tooltip_text(M("HISTOGRAM_TOOLTIP_CROSSHAIR")); + brightnessWidget->show(); + histogramRGBArea = nullptr; + break; + case ScopeType::NONE: + break; + } + + if (panel_listener) { + updateHistAreaOptions(); + panel_listener->scopeTypeChanged(options.histogramScopeType); + } + + showRGBBar(); +} + void HistogramPanel::bar_toggled () { showBAR->set_image(showBAR->get_active() ? *barImage : *barImage_g); rgbv_toggled(); + showRGBBar(); } void HistogramPanel::rgbv_toggled () { // Update Display - histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), options.histogramDrawMode); + updateHistAreaOptions(); + histogramArea->updateBackBuffer (); histogramArea->queue_draw (); - histogramRGBArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), showBAR->get_active()); - histogramRGBArea->updateBackBuffer (0, 0, 0); - histogramRGBArea->queue_draw (); + if (histogramRGBArea) { + updateHistRGBAreaOptions(); + histogramRGBArea->updateBackBuffer(-1, -1, -1); + histogramRGBArea->queue_draw (); + } } void HistogramPanel::setHistRGBInvalid () @@ -311,15 +625,7 @@ void HistogramPanel::setHistRGBInvalid () void HistogramPanel::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) { - - if (!validPos) { - // do something to un-show vertical bars - histogramRGBArea->updateBackBuffer(-1, -1, -1); - } else { - // do something to show vertical bars - histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); - } - histogramRGBArea->queue_draw (); + pointer_moved_delayed_call(validPos, profile, profileW, r, g, b); } /* @@ -333,11 +639,27 @@ void HistogramPanel::reorder (Gtk::PositionType align) removeIfThere(this, gfxGrid, false); add (*gfxGrid); gfxGrid->unreference(); + + gfxGrid->remove(*histogramRGBAreaVert); + gfxGrid->add(*histogramRGBAreaVert); + + optionButtons->reference(); + removeIfThere(buttonGrid, optionButtons, false); + buttonGrid->add(*optionButtons); + optionButtons->unreference(); } else { buttonGrid->reference(); removeIfThere(this, buttonGrid, false); add (*buttonGrid); buttonGrid->unreference(); + + gfxGrid->remove(*histogramRGBAreaVert); + gfxGrid->attach_next_to(*histogramRGBAreaVert, *histogramArea, Gtk::POS_LEFT, 1, 1); + + persistentButtons->reference(); + removeIfThere(buttonGrid, persistentButtons, false); + buttonGrid->add(*persistentButtons); + persistentButtons->unreference(); } } @@ -352,6 +674,41 @@ void HistogramPanel::toggleButtonMode () showMode->set_image(*mode2Image); } +void HistogramPanel::setPanelListener(HistogramPanelListener* listener) +{ + panel_listener = listener; + + if (listener) { + listener->scopeTypeChanged(options.histogramScopeType); + } +} + +void HistogramPanel::updateHistAreaOptions() +{ + histogramArea->updateOptions( + showRed->get_active(), + showGreen->get_active(), + showBlue->get_active(), + showValue->get_active(), + showChro->get_active(), + options.histogramDrawMode, + options.histogramScopeType, + showBAR->get_active() + ); +} + +void HistogramPanel::updateHistRGBAreaOptions() +{ + histogramRGBArea->updateOptions( + showRed->get_active(), + showGreen->get_active(), + showBlue->get_active(), + showValue->get_active(), + showChro->get_active(), + showBAR->get_active() + ); +} + // // // @@ -369,10 +726,9 @@ double HistogramScaling::log(double vsize, double val) HistogramRGBArea::HistogramRGBArea () : val(0), r(0), g(0), b(0), valid(false), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), - needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), + needLuma(options.histogramLuma), needChroma(options.histogramChroma), showMode(options.histogramBar), barDisplayed(options.histogramBar), parent(nullptr) { - get_style_context()->add_class("drawingarea"); set_name("HistogramRGBArea"); @@ -394,46 +750,41 @@ HistogramRGBArea::~HistogramRGBArea () } -Gtk::SizeRequestMode HistogramRGBArea::get_request_mode_vfunc () const +void HistogramRGBArea::getPreferredThickness(int& min_thickness, int& natural_thickness) const { - return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; + int minimumLength = 0; + int naturalLength = 0; + getPreferredLength(minimumLength, naturalLength); + getPreferredThicknessForLength(minimumLength, min_thickness, natural_thickness); } -void HistogramRGBArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const -{ - int minimumWidth = 0; - int naturalWidth = 0; - get_preferred_width_vfunc(minimumWidth, naturalWidth); - get_preferred_height_for_width_vfunc (minimumWidth, minimum_height, natural_height); -} - -void HistogramRGBArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +void HistogramRGBArea::getPreferredLength(int& min_length, int& natural_length) const { int s = RTScalable::getScale(); - minimum_width = 60 * s; - natural_width = 200 * s; + min_length = 60 * s; + natural_length = 200 * s; } -void HistogramRGBArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +void HistogramRGBArea::getPreferredThicknessForLength(int length, int& min_thickness, int& natural_thickness) const { - int bHeight = width / 30; + int bThickness = length / 30; int s = RTScalable::getScale(); - if (bHeight > (10 * s)) { - bHeight = 10 * s; - } else if (bHeight < (5 * s)) { - bHeight = 5 * s; + if (bThickness > (10 * s)) { + bThickness = 10 * s; + } else if (bThickness < (5 * s)) { + bThickness = 5 * s; } - minimum_height = bHeight; - natural_height = bHeight; + min_thickness = bThickness; + natural_thickness = bThickness; } // unused? -void HistogramRGBArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +void HistogramRGBArea::getPreferredLengthForThickness(int thickness, int& min_length, int& natural_length) const { - get_preferred_width_vfunc (minimum_width, natural_width); + getPreferredLength(min_length, natural_length); } bool HistogramRGBArea::getShow() @@ -441,9 +792,18 @@ bool HistogramRGBArea::getShow() return(showMode); } +void HistogramRGBArea::setShow(bool show) +{ + showMode = show; +} + void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { - if (!get_realized () || !showMode || rawMode) { + if (!get_realized () || !showMode || !( + options.histogramScopeType == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::PARADE + || options.histogramScopeType == ScopeType::WAVEFORM + )) { return; } @@ -474,72 +834,41 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin if (needRed) { // Red cc->set_source_rgb(1.0, 0.0, 0.0); - if (options.histogramDrawMode < 2) { - cc->move_to(r * (winw - 1.) / 255.0 + 0.5*s, 0); // Rescaling seems needed to fit between boundaries of draw area - cc->line_to(r * (winw - 1.) / 255.0 + 0.5*s, winh - 0); - } else { - cc->move_to(HistogramScaling::log (255, r) * (winw - 1.*s) / 255.0 + 0.5*s, 0); - cc->line_to(HistogramScaling::log (255, r) * (winw - 1.*s) / 255.0 + 0.5*s, winh - 0); - } - cc->stroke(); + drawBar(cc, r, 255.0, winw, winh, s); } if (needGreen) { // Green cc->set_source_rgb(0.0, 1.0, 0.0); - if (options.histogramDrawMode < 2) { - cc->move_to(g * (winw - 1.) / 255.0 + 0.5*s, 0); - cc->line_to(g * (winw - 1.) / 255.0 + 0.5*s, winh - 0); - } else { - cc->move_to(HistogramScaling::log (255, g) * (winw - 1.) / 255.0 + 0.5*s, 0); - cc->line_to(HistogramScaling::log (255, g) * (winw - 1.) / 255.0 + 0.5*s, winh - 0); - } - cc->stroke(); + drawBar(cc, g, 255.0, winw, winh, s); } if (needBlue) { // Blue cc->set_source_rgb(0.0, 0.4, 1.0); - if (options.histogramDrawMode < 2) { - cc->move_to(b * (winw - 1.) / 255.0 + 0.5*s, 0); - cc->line_to(b * (winw - 1.) / 255.0 + 0.5*s, winh - 0); - } else { - cc->move_to(HistogramScaling::log (255, b) * (winw - 1.) / 255.0 + 0.5*s, 0); - cc->line_to(HistogramScaling::log (255, b) * (winw - 1.) / 255.0 + 0.5*s, winh - 0); - } - cc->stroke(); + drawBar(cc, b, 255.0, winw, winh, s); } - if(needLuma || needChroma) { + if( + (needLuma || needChroma) + && (options.histogramScopeType == ScopeType::HISTOGRAM + || options.histogramScopeType == ScopeType::PARADE + || options.histogramScopeType == ScopeType::WAVEFORM) + ) { float Lab_L, Lab_a, Lab_b; rtengine::Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, Lab_L, Lab_a, Lab_b, options.rtSettings.HistogramWorking); if (needLuma) { // Luma cc->set_source_rgb(1.0, 1.0, 1.0); - if (options.histogramDrawMode < 2) { - cc->move_to(static_cast(Lab_L) * (winw - 3. * s) / 100.0 + 0.5 * s, 0); - cc->line_to(static_cast(Lab_L) * (winw - 3. * s) / 100.0 + 0.5 * s, winh - 0); - } else { - cc->move_to(HistogramScaling::log(100, Lab_L) * (winw - 1.) / 100.0 + 0.5 * s, 0); - cc->line_to(HistogramScaling::log(100, Lab_L) * (winw - 1.) / 100.0 + 0.5 * s, winh - 0); - } - cc->stroke(); + drawBar(cc, Lab_L, 100.0, winw, winh, s); } - if (needChroma) { + if (needChroma && options.histogramScopeType == ScopeType::HISTOGRAM) { // Chroma double chromaval = sqrt(Lab_a * Lab_a + Lab_b * Lab_b) / 1.8; - // float chromaval = sqrt(Lab_a*Lab_a + Lab_b*Lab_b); cc->set_source_rgb(0.9, 0.9, 0.0); - if (options.histogramDrawMode < 2) { - cc->move_to(chromaval * (winw - 1.) / 100.0 + 0.5 * s, 0); - cc->line_to(chromaval * (winw - 1.) / 100.0 + 0.5 * s, winh - 0); - } else { - cc->move_to(HistogramScaling::log(100, chromaval) * (winw - 1.) / 100.0 + 0.5 * s, 0); - cc->line_to(HistogramScaling::log(100, chromaval) * (winw - 1.) / 100.0 + 0.5 * s, winh - 0); - } - cc->stroke(); + drawBar(cc, chromaval, 100.0, winw, winh, s); } } } @@ -586,7 +915,7 @@ void HistogramRGBArea::update (int valh, int rh, int gh, int bh) ); } -void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, bool bar) +void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool bar) { options.histogramRed = needRed = r; @@ -594,18 +923,8 @@ void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bo options.histogramBlue = needBlue = b; options.histogramLuma = needLuma = l; options.histogramChroma = needChroma = c; - options.histogramRAW = rawMode = raw; options.histogramBar = showMode = bar; - // Show/hide the RGB bar widget - if (bar && !barDisplayed) { - parent->add(*this); - barDisplayed = true; - } else if (!bar && barDisplayed) { - removeIfThere(parent, this, false); - barDisplayed = false; - } - } void HistogramRGBArea::on_realize () @@ -650,16 +969,105 @@ void HistogramRGBArea::factorChanged (double newFactor) factor = newFactor; } +void HistogramRGBAreaHori::drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) +{ + double pos; + if (options.histogramDrawMode < 2) { + pos = padding + value * (winw - padding * 2.0) / max_value + 0.5 * scale; + } else { + pos = padding + HistogramScaling::log (max_value, value) * (winw - padding * 2.0) / max_value + 0.5 * scale; + } + cc->move_to(pos, 0.0); + cc->line_to(pos, winh - 0.0); + cc->stroke(); +} + +Gtk::SizeRequestMode HistogramRGBAreaHori::get_request_mode_vfunc () const +{ + return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; +} + +void HistogramRGBAreaHori::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const +{ + getPreferredThickness(minimum_height, natural_height); +} + +void HistogramRGBAreaHori::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +{ + getPreferredLength(minimum_width, natural_width); +} + +void HistogramRGBAreaHori::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +{ + getPreferredThicknessForLength(width, minimum_height, natural_height); +} + +void HistogramRGBAreaHori::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +{ + getPreferredLengthForThickness(height, minimum_width, natural_width); +} + +void HistogramRGBAreaVert::drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) +{ + double pos; + if (options.histogramDrawMode < 2 || options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { + pos = padding + value * (winh - padding * 2.0 - 1) / max_value + 0.5 * scale; + } else { + pos = padding + HistogramScaling::log (max_value, value) * (winh - padding * 2.0) / max_value + 0.5 * scale; + } + cc->move_to(0.0, winh - pos); + cc->line_to(winw, winh - pos); + cc->stroke(); +} + +Gtk::SizeRequestMode HistogramRGBAreaVert::get_request_mode_vfunc () const +{ + return Gtk::SIZE_REQUEST_WIDTH_FOR_HEIGHT; +} + +void HistogramRGBAreaVert::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const +{ + getPreferredLength(minimum_height, natural_height); +} + +void HistogramRGBAreaVert::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +{ + minimum_width = 10 * RTScalable::getScale(); + natural_width = minimum_width; +} + +void HistogramRGBAreaVert::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +{ + getPreferredLengthForThickness(width, minimum_height, natural_height); +} + +void HistogramRGBAreaVert::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +{ + get_preferred_width_vfunc(minimum_width, natural_width); +} + // // // // HistogramArea HistogramArea::HistogramArea (DrawModeListener *fml) : + vectorscope_scale(0), + vect_hc(0, 0), vect_hs(0, 0), + vect_hc_buffer_dirty(true), vect_hs_buffer_dirty(true), + waveform_scale(0), + rwave(0, 0), gwave(0, 0),bwave(0, 0), lwave(0, 0), + parade_buffer_r_dirty(true), parade_buffer_g_dirty(true), parade_buffer_b_dirty(true), + wave_buffer_dirty(true), wave_buffer_luma_dirty(true), valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), + scopeType(options.histogramScopeType), oldwidth(-1), oldheight(-1), + trace_brightness(1.0), needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), - needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), - isPressed(false), movingPosition(0.0) + needLuma(options.histogramLuma), needChroma(options.histogramChroma), + isPressed(false), movingPosition(0.0), + needPointer(options.histogramBar), + pointer_red(-1), pointer_green(-1), pointer_blue(-1), + pointer_a(0), pointer_b(0) { rhist(256); @@ -695,7 +1103,7 @@ Gtk::SizeRequestMode HistogramArea::get_request_mode_vfunc () const void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const { - int s = (int)RTScalable::getScale(); + int s = RTScalable::getScale(); minimum_height = 100 * s; natural_height = 200 * s; } @@ -703,7 +1111,7 @@ void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natura void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const { - int s = (int)RTScalable::getScale(); + int s = RTScalable::getScale(); minimum_width = 200 * s; natural_width = 400 * s; } @@ -720,18 +1128,23 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim get_preferred_width_vfunc (minimum_width, natural_width); } -void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode) +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, ScopeType type, bool pointer) { + wave_buffer_dirty = wave_buffer_dirty || needRed != r || needGreen != g || needBlue != b; options.histogramRed = needRed = r; options.histogramGreen = needGreen = g; options.histogramBlue = needBlue = b; options.histogramLuma = needLuma = l; options.histogramChroma = needChroma = c; - options.histogramRAW = rawMode = raw; options.histogramDrawMode = drawMode = mode; + options.histogramScopeType = scopeType = type; + options.histogramBar = needPointer = pointer; +} - updateBackBuffer (); +bool HistogramArea::updatePending(void) +{ + return haih->pending > 0 && !haih->destroyed; } void HistogramArea::update( @@ -742,18 +1155,53 @@ void HistogramArea::update( const LUTu& histChroma, const LUTu& histRedRaw, const LUTu& histGreenRaw, - const LUTu& histBlueRaw + const LUTu& histBlueRaw, + int vectorscopeScale, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, + int waveformScale, + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ) { if (histRed) { - rhist = histRed; - ghist = histGreen; - bhist = histBlue; - lhist = histLuma; - chist = histChroma; - rhistRaw = histRedRaw; - ghistRaw = histGreenRaw; - bhistRaw = histBlueRaw; + switch (scopeType) { + case ScopeType::HISTOGRAM: + rhist = histRed; + ghist = histGreen; + bhist = histBlue; + lhist = histLuma; + chist = histChroma; + break; + case ScopeType::HISTOGRAM_RAW: + rhistRaw = histRedRaw; + ghistRaw = histGreenRaw; + bhistRaw = histBlueRaw; + break; + case ScopeType::PARADE: + case ScopeType::WAVEFORM: + waveform_scale = waveformScale; + rwave = waveformRed; + gwave = waveformGreen; + bwave = waveformBlue; + lwave = waveformLuma; + parade_buffer_r_dirty = parade_buffer_g_dirty = parade_buffer_b_dirty = wave_buffer_dirty = wave_buffer_luma_dirty = true; + break; + case ScopeType::VECTORSCOPE_HS: + vectorscope_scale = vectorscopeScale; + vect_hs = vectorscopeHS; + vect_hs_buffer_dirty = true; + break; + case ScopeType::VECTORSCOPE_HC: + vectorscope_scale = vectorscopeScale; + vect_hc = vectorscopeHC; + vect_hc_buffer_dirty = true; + break; + case ScopeType::NONE: + break; + } valid = true; } else { valid = false; @@ -788,7 +1236,6 @@ void HistogramArea::update( void HistogramArea::updateBackBuffer () { - if (!get_realized ()) { return; } @@ -822,42 +1269,53 @@ void HistogramArea::updateBackBuffer () cr->set_dash (ch_ds, 0); // determine the number of h-gridlines based on current h - int nrOfHGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2)); + int nrOfHGridPartitions = static_cast(rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2))); int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) // draw vertical gridlines - if (options.histogramDrawMode < 2) { - for (int i = 1; i < nrOfVGridPartitions; i++) { - cr->move_to ((pow(2.0,i) - 1) / 255.0 * w + 0.5, 0.); - cr->line_to ((pow(2.0,i) - 1) / 255.0 * w + 0.5, h); - cr->stroke (); - } - } else { - for (int i = 1; i < nrOfVGridPartitions; i++) { - cr->move_to (HistogramScaling::log (255, pow(2.0,i) - 1) / 255.0 * w + 0.5, 0.); - cr->line_to (HistogramScaling::log (255, pow(2.0,i) - 1) / 255.0 * w + 0.5, h); + if (options.histogramScopeType == ScopeType::HISTOGRAM || options.histogramScopeType == ScopeType::HISTOGRAM_RAW) { + for (int i = 0; i <= nrOfVGridPartitions; i++) { + double xpos = padding + 0.5; + if (options.histogramDrawMode < 2) { + xpos += (pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + } else { + xpos += HistogramScaling::log (255, pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + } + cr->move_to (xpos, 0.); + cr->line_to (xpos, h); cr->stroke (); } } // draw horizontal gridlines - if (options.histogramDrawMode == 0) { + if (options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { + for (int i = 0; i <= nrOfVGridPartitions; i++) { + const double ypos = h - padding - (pow(2.0,i) - 1) * (h - 2 * padding - 1) / 255.0; + cr->move_to(0, ypos); + cr->line_to(w, ypos); + cr->stroke(); + } + } else if (options.histogramScopeType == ScopeType::VECTORSCOPE_HC || options.histogramScopeType == ScopeType::VECTORSCOPE_HS) { + // Vectorscope has no gridlines. + } else if (options.histogramDrawMode == 0) { for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (0., i * (double)h / nrOfHGridPartitions + 0.5); - cr->line_to (w, i * (double)h / nrOfHGridPartitions + 0.5); + cr->move_to (padding, i * static_cast(h) / nrOfHGridPartitions + 0.5); + cr->line_to (w - padding, i * static_cast(h) / nrOfHGridPartitions + 0.5); cr->stroke (); } } else { for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (0., h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5*s); - cr->line_to (w, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5*s); + cr->move_to (padding, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); + cr->line_to (w - padding, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); cr->stroke (); } } cr->unset_dash(); - if (valid) { + if (valid && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW)) { + bool rawMode = scopeType == ScopeType::HISTOGRAM_RAW; + // For RAW mode use the other hists LUTu& rh = rawMode ? rhistRaw : rhist; LUTu& gh = rawMode ? ghistRaw : ghist; @@ -964,6 +1422,12 @@ void HistogramArea::updateBackBuffer () drawMarks(cr, bhchanged, realhistheight, w, ui, oi); } + } else if (scopeType == ScopeType::PARADE && rwave.getWidth() > 0) { + drawParade(cr, w, h); + } else if (scopeType == ScopeType::WAVEFORM && rwave.getWidth() > 0) { + drawWaveform(cr, w, h); + } else if (scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS) { + drawVectorscope(cr, w, h); } // Draw the frame's border @@ -975,6 +1439,24 @@ void HistogramArea::updateBackBuffer () setDirty(false); } +bool HistogramArea::updatePointer(int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) +{ + if (!needPointer || !(scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS)) { + return false; + } + if (pointer_red == r && pointer_green == g && pointer_blue == b) { + return false; + } + + float L; + pointer_red = r; + pointer_green = g; + pointer_blue = b; + Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, L, pointer_a, pointer_b, options.rtSettings.HistogramWorking); + updateBackBuffer(); + return true; +} + void HistogramArea::on_realize () { @@ -988,28 +1470,28 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, double s = RTScalable::getScale(); cr->set_line_width(s); - cr->move_to (0, vsize - 1); + cr->move_to (padding, vsize - 1); scale = scale <= 0.0 ? 0.001 : scale; // avoid division by zero and negative values for (int i = 0; i < 256; i++) { - double val = data[i] * (double)vsize / scale; + double val = data[i] * static_cast(vsize) / scale; if (drawMode > 0) { // scale y for single and double log-scale - val = HistogramScaling::log ((double)vsize, val); + val = HistogramScaling::log (static_cast(vsize), val); } double iscaled = i; if (drawMode == 2) { // scale x for double log-scale - iscaled = HistogramScaling::log (255.0, (double)i); + iscaled = HistogramScaling::log (255.0, static_cast(i)); } - double posX = (iscaled / 255.0) * (hsize - 1); + double posX = padding + iscaled * (hsize - padding * 2.0) / 255.0; double posY = vsize - 2 + val * (4 - vsize) / vsize; cr->line_to (posX, posY); } - cr->line_to (hsize - 1, vsize - 1); + cr->line_to (hsize - padding, vsize - 1); } void HistogramArea::drawMarks(Cairo::RefPtr &cr, @@ -1018,20 +1500,389 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, int s = 8 * RTScalable::getScale(); if(data[0] > scale) { - cr->rectangle(0, (ui++)*s, s, s); + cr->rectangle(padding, (ui++)*s, s, s); } if(data[255] > scale) { - cr->rectangle(hsize - s, (oi++)*s, s, s); + cr->rectangle(hsize - s - padding, (oi++)*s, s, s); } cr->fill(); } +void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) +{ + // Arbitrary scale factor divided by current scale. + const float scale = trace_brightness * 32.f * 255.f / waveform_scale; + const int wave_width = rwave.getWidth(); + const int wave_height = rwave.getHeight(); + + // See Cairo documentation on stride. + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); + const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; + + if (parade_buffer_r_dirty && needRed) { + parade_buffer_r.assign(buffer_size, 0); + assert(parade_buffer_r.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const r_row = rwave[val]; + std::uint32_t* const buffer_r_row = reinterpret_cast(parade_buffer_r.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char r = std::min(scale * r_row[col], 0xff); + if (r != 0) { + buffer_r_row[col] = (r << 16) | (r << 24); + } + } + } + + parade_buffer_r_dirty = false; + } + + if (parade_buffer_g_dirty && needGreen) { + parade_buffer_g.assign(buffer_size, 0); + assert(parade_buffer_g.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const g_row = gwave[val]; + std::uint32_t* const buffer_g_row = reinterpret_cast(parade_buffer_g.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char g = std::min(scale * g_row[col], 0xff); + if (g != 0) { + buffer_g_row[col] = (g << 8) | (g << 24); + } + } + } + + parade_buffer_g_dirty = false; + } + + if (parade_buffer_b_dirty && needBlue) { + parade_buffer_b.assign(buffer_size, 0); + assert(parade_buffer_b.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const b_row = bwave[val]; + std::uint32_t* const buffer_b_row = reinterpret_cast(parade_buffer_b.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char b = std::min(scale * b_row[col], 0xff); + if (b != 0) { + const unsigned char green = b / 2; // Make blue easier to see. + buffer_b_row[col] = b | (green << 8) | (b << 24); + } + } + } + + parade_buffer_b_dirty = false; + } + + if (wave_buffer_luma_dirty && needLuma) { + wave_buffer_luma.assign(buffer_size, 0); + assert(wave_buffer_luma.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const l_row = lwave[val]; + std::uint32_t* const buffer_row = + reinterpret_cast(wave_buffer_luma.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char l = std::min(scale * l_row[col], 0xff); + buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); + } + } + + wave_buffer_luma_dirty = false; + } + + std::vector buffers; + if (needLuma) { + buffers.push_back(wave_buffer_luma.data()); + } + if (needRed) { + buffers.push_back(parade_buffer_r.data()); + } + if (needGreen) { + buffers.push_back(parade_buffer_g.data()); + } + if (needBlue) { + buffers.push_back(parade_buffer_b.data()); + } + + auto orig_matrix = cr->get_matrix(); + const double display_wave_width = static_cast(w) / buffers.size(); + for (unsigned i = 0; i < buffers.size(); i++) { + Cairo::RefPtr surface; + cr->translate(i * display_wave_width, padding); + cr->scale(display_wave_width / wave_width, (h - 2 * padding) / wave_height); + surface = Cairo::ImageSurface::create( + buffers[i], Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + cr->set_matrix(orig_matrix); + } +} + +void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, int h) +{ + if (scopeType != ScopeType::VECTORSCOPE_HC && scopeType != ScopeType::VECTORSCOPE_HS) { + return; + } + + const auto& vect = (scopeType == ScopeType::VECTORSCOPE_HC) ? vect_hc : vect_hs; + auto& vect_buffer = (scopeType == ScopeType::VECTORSCOPE_HC) ? vect_hc_buffer : vect_hs_buffer; + auto& vect_buffer_dirty = (scopeType == ScopeType::VECTORSCOPE_HC) ? vect_hc_buffer_dirty : vect_hs_buffer_dirty; + + const int vect_width = vect.getWidth(); + const int vect_height = vect.getHeight(); + // Arbitrary scale factor multiplied by vectorscope area and divided by + // current scale. + const float scale = trace_brightness * 8.f * vect_width * vect_height / vectorscope_scale; + + // See Cairo documentation on stride. + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, vect_width); + + if (vect_buffer_dirty && vectorscope_scale > 0) { + if (vect_buffer.size() != static_cast(cairo_stride) * vect_height) { + vect_buffer.resize(static_cast(cairo_stride) * vect_height); + } + + assert(vect_buffer.size() % 4 == 0); + + for (int y = 0; y < vect_height; y++) { + const int* const vect_row = vect[y]; + std::uint32_t* const buffer_row = + reinterpret_cast(vect_buffer.data() + (vect_height - 1 - y) * cairo_stride); + for (int x = 0; x < vect_width; x++) { + const unsigned char value = std::min(scale * vect_row[x], 0xff); + buffer_row[x] = value | (value << 8) | (value << 16) | (value << 24); + } + } + + vect_buffer_dirty = false; + } + + const bool fit_width = + vect_width * (h - 2 * padding) > vect_height * (w - 2 * padding); + const float scope_scale = fit_width ? + (w - 2 * padding) / vect_width : (h - 2 * padding) / vect_height; + const float scope_size = (vectorscope_scale > 0) ? + scope_scale * std::max(vect_width, vect_height) : std::min(w, h) - 2 * padding; + const float o_x = (w - scope_scale * vect_width) / 2; + const float o_y = (h - scope_scale * vect_height) / 2; + const double s = RTScalable::getScale(); + auto orig_matrix = cr->get_matrix(); + const double line_length = scope_size / 2.0; + std::valarray ch_ds(1); + + cr->translate(w / 2.0, h / 2.0); + cr->set_line_width (1.0 * s); + cr->set_antialias(Cairo::ANTIALIAS_SUBPIXEL); + ch_ds[0] = 4; + + if (scopeType == ScopeType::VECTORSCOPE_HS) { // Hue-Saturation. + // RYGCBM lines. + cr->set_line_width (2.0 * s); + constexpr double color_labels[6][3] = { + {1, 0, 0}, // R + {0, 1, 0}, // G + {0, 0, 1}, // B + {0, 1, 1}, // C + {1, 0, 1}, // M + {1, 1, 0}, // Y + }; + for (int i = 0; i < 3; i++) { + auto gradient = Cairo::LinearGradient::create(-line_length, 0, line_length, 0); + const double (&color_1)[3] = color_labels[i]; + const double (&color_2)[3] = color_labels[i + 3]; + cr->set_source(gradient); + gradient->add_color_stop_rgba(0, color_2[0], color_2[1], color_2[2], 0.5); + gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); + gradient->add_color_stop_rgba(1, color_1[0], color_1[1], color_1[2], 0.5); + cr->move_to(-line_length, 0); + cr->line_to(line_length, 0); + cr->rotate_degrees(-120); + cr->stroke(); + } + cr->set_line_width (1.0 * s); + cr->set_source_rgba (1, 1, 1, 0.25); + // 100% saturation circle. + cr->arc(0, 0, scope_size / 2.0, 0, 2 * RT_PI); + cr->stroke(); + // 25%, 50%, and 75% saturation. + cr->set_dash(ch_ds, 0); + for (int i = 1; i < 4; i++) { + cr->arc(0, 0, i * scope_size / 8.0, 0, 2 * RT_PI); + cr->stroke(); + } + // HSV skin tone line derived from -I axis of YIQ. + cr->rotate(-0.134900 * RT_PI); + cr->move_to(0, 0); + cr->line_to(line_length, 0); + cr->stroke(); + cr->unset_dash(); + } else if (scopeType == ScopeType::VECTORSCOPE_HC) { // Hue-Chroma. + // a and b axes. + Cairo::RefPtr gradient; + cr->set_line_width (2.0 * s); + gradient = Cairo::LinearGradient::create(0, -line_length, 0, line_length); + cr->set_source(gradient); + gradient->add_color_stop_rgba(0, 1, 1, 0, 0.5); // "yellow" + gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); // neutral + gradient->add_color_stop_rgba(1, 0, 0, 1, 0.5); // "blue" + cr->move_to(0, 0); + cr->line_to(0, line_length); + cr->move_to(0, 0); + cr->line_to(0, -line_length); + cr->stroke(); + gradient = Cairo::LinearGradient::create(-line_length, 0, line_length, 0); + cr->set_source(gradient); + gradient->add_color_stop_rgba(0, 0, 1, 0, 0.5); // "green" + gradient->add_color_stop_rgba(0.5, 1, 1, 1, 0.25); // neutral + gradient->add_color_stop_rgba(1, 1, 0, 1, 0.5); // "magenta" + cr->move_to(0, 0); + cr->line_to(line_length, 0); + cr->move_to(0, 0); + cr->line_to(-line_length, 0); + cr->stroke(); + cr->set_source_rgba (1, 1, 1, 0.25); + cr->set_line_width (1.0 * s); + // 25%, 50%, 75%, and 100% of standard chroma range. + cr->set_dash(ch_ds, 0); + for (int i = 1; i <= 4; i++) { + cr->arc(0, 0, i * scope_size / 8.0, 0, 2 * RT_PI); + cr->stroke(); + } + // CIELAB skin tone line, approximated by 50% saturation and + // value along the HSV skin tone line. + cr->rotate(-0.321713 * RT_PI); + cr->move_to(0, 0); + cr->line_to(line_length, 0); + cr->stroke(); + cr->unset_dash(); + } + cr->set_matrix(orig_matrix); + + // Vectorscope trace. + if (vectorscope_scale > 0) { + Cairo::RefPtr surface = Cairo::ImageSurface::create( + vect_buffer.data(), Cairo::FORMAT_ARGB32, vect_width, vect_height, cairo_stride); + cr->translate(o_x, o_y); + cr->scale(scope_scale, scope_scale); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + cr->set_matrix(orig_matrix); + + if (needPointer && pointer_red >= 0 && pointer_green >= 0 && pointer_blue >= 0) { + float cx, cy; + if (scopeType == ScopeType::VECTORSCOPE_HS) { + float H, S, L; + Color::rgb2hslfloat(pointer_red * 257.f, pointer_green * 257.f, pointer_blue * 257.f, H, S, L); + cx = (w + scope_size * S * std::cos(H * 2 * RT_PI_F)) / 2; + cy = (h - scope_size * S * std::sin(H * 2 * RT_PI_F)) / 2; + } else { + constexpr float ab_factor = 1.f / 256.f; + cx = w / 2.f + scope_size * pointer_a * ab_factor; + cy = h / 2.f - scope_size * pointer_b * ab_factor; + } + const float crosshair_size = 20.f * s; + cr->set_source_rgba(1, 1, 1, 0.5); + cr->move_to(cx - crosshair_size, cy); + cr->line_to(cx + crosshair_size, cy); + cr->move_to(cx, cy - crosshair_size); + cr->line_to(cx, cy + crosshair_size); + cr->stroke(); + cr->arc(cx, cy, 3 * s, 0, 2 * RT_PI); + cr->set_source_rgb(1, 1, 1); + cr->fill_preserve(); + cr->set_source_rgb(0, 0, 0); + cr->set_line_width (1.0 * s); + cr->stroke(); + } + } +} + +void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h) +{ + // Arbitrary scale factor divided by current scale. + const float scale = trace_brightness * 32.f * 255.f / waveform_scale; + const int wave_width = rwave.getWidth(); + const int wave_height = rwave.getHeight(); + + // See Cairo documentation on stride. + const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, rwave.getWidth()); + const auto buffer_size = static_cast::size_type>(wave_height) * cairo_stride; + + if (wave_buffer_dirty && (needRed || needGreen || needBlue)) { + wave_buffer.assign(buffer_size, 0); + assert(wave_buffer.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const r_row = rwave[val]; + const int* const g_row = gwave[val]; + const int* const b_row = bwave[val]; + std::uint32_t* const buffer_row = reinterpret_cast(wave_buffer.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char r = needRed ? std::min(scale * r_row[col], 0xff) : 0; + const unsigned char g = needGreen ? std::min(scale * g_row[col], 0xff) : 0; + const unsigned char b = needBlue ? std::min(scale * b_row[col], 0xff) : 0; + const unsigned char value = rtengine::max(r, g, b); + if (value != 0) { + // Ensures correct order regardless of endianness. + buffer_row[col] = b | (g << 8) | (r << 16) | (value << 24); + } + } + } + + wave_buffer_dirty = false; + } + + if (wave_buffer_luma_dirty && needLuma) { + wave_buffer_luma.assign(buffer_size, 0); + assert(wave_buffer_luma.size() % 4 == 0); + + for (int val = 0; val < wave_height; val++) { + const int* const l_row = lwave[val]; + std::uint32_t* const buffer_row = + reinterpret_cast(wave_buffer_luma.data() + (255 - val) * cairo_stride); + for (int col = 0; col < wave_width; col++) { + const unsigned char l = std::min(scale * l_row[col], 0xff); + buffer_row[col] = l | (l << 8) | (l << 16) | (l << 24); + } + } + + wave_buffer_luma_dirty = false; + } + + Cairo::RefPtr surface; + auto orig_matrix = cr->get_matrix(); + cr->translate(0, padding); + cr->scale(static_cast(w) / wave_width, (h - 2 * padding) / wave_height); + if (needLuma) { + surface = Cairo::ImageSurface::create( + wave_buffer_luma.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + } + if (needRed || needGreen || needBlue) { + surface = Cairo::ImageSurface::create( + wave_buffer.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); + cr->set_source(surface, 0, 0); + cr->set_operator(Cairo::OPERATOR_OVER); + cr->paint(); + surface->finish(); + } + cr->set_matrix(orig_matrix); +} + bool HistogramArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) { - if (get_width() != oldwidth || get_height() != oldheight || isDirty ()) { + if (!updatePending() && (get_width() != oldwidth || get_height() != oldheight || isDirty())) { updateBackBuffer (); } @@ -1048,7 +1899,10 @@ bool HistogramArea::on_button_press_event (GdkEventButton* event) isPressed = true; movingPosition = event->x; - if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { + if ( + event->type == GDK_2BUTTON_PRESS && event->button == 1 + && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW) + ) { drawMode = (drawMode + 1) % 3; options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; @@ -1072,8 +1926,18 @@ bool HistogramArea::on_button_release_event (GdkEventButton* event) bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) { - if (isPressed) - { + if ( + drawMode == 0 + && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW) + ) { + return false; + } + + if (!isPressed) { + return true; + } + + if (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW) { // Adjust log scale. double mod = 1 + (event->x - movingPosition) / get_width(); factor /= mod; @@ -1086,11 +1950,45 @@ bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) setDirty(true); queue_draw (); + } else if ( + scopeType == ScopeType::PARADE + || scopeType == ScopeType::WAVEFORM + || scopeType == ScopeType::VECTORSCOPE_HC + || scopeType == ScopeType::VECTORSCOPE_HS + ) { // Adjust brightness. + constexpr float RANGE = MAX_BRIGHT / MIN_BRIGHT; + double dx = (event->x - movingPosition) / get_width(); + float new_brightness = LIM(trace_brightness * pow(RANGE, dx), MIN_BRIGHT, MAX_BRIGHT); + setBrightness(new_brightness); + movingPosition = event->x; } return true; } +float HistogramArea::getBrightness(void) +{ + return trace_brightness; +} + +void HistogramArea::setBrightness(float brightness) +{ + brightness = LIM(brightness, MIN_BRIGHT, MAX_BRIGHT); + if (brightness != trace_brightness) { + parade_buffer_r_dirty = parade_buffer_g_dirty = parade_buffer_b_dirty = wave_buffer_dirty = wave_buffer_luma_dirty = vect_hc_buffer_dirty = vect_hs_buffer_dirty = true; + trace_brightness = brightness; + setDirty(true); + queue_draw(); + + signal_brightness_changed.emit(trace_brightness); + } +} + +HistogramArea::SignalBrightnessChanged HistogramArea::getBrighnessChangedSignal(void) +{ + return signal_brightness_changed; +} + HistogramArea::type_signal_factor_changed HistogramArea::signal_factor_changed() { return sigFactorChanged; diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index cec44ed03..393df51a5 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -18,15 +18,20 @@ */ #pragma once +#include + #include #include #include +#include "delayed.h" #include "guiutils.h" +#include "options.h" #include "pointermotionlistener.h" +#include "../rtengine/array2D.h" #include "../rtengine/LUT.h" #include "../rtengine/noncopyable.h" @@ -53,7 +58,7 @@ public: double log (double vsize, double val); }; -class HistogramRGBArea final : public Gtk::DrawingArea, public BackBuffer, private HistogramScaling, public rtengine::NonCopyable +class HistogramRGBArea : public Gtk::DrawingArea, public BackBuffer, protected HistogramScaling, public rtengine::NonCopyable { private: typedef const double (*TMatrix)[3]; @@ -73,40 +78,67 @@ protected: bool needBlue; bool needLuma; bool needChroma; - bool rawMode; bool showMode; bool barDisplayed; Gtk::Grid* parent; + + double padding = 5.0; HistogramRGBAreaIdleHelper* harih; + /** Draw an indicator bar for the value. */ + virtual void drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) = 0; + + void getPreferredThickness(int& min_thickness, int& natural_length) const; + void getPreferredLength(int& min_length, int& natural_length) const; + void getPreferredThicknessForLength(int length, int& min_thickness, int& natural_length) const; + void getPreferredLengthForThickness(int thickness, int& min_length, int& natural_length) const; + public: HistogramRGBArea(); ~HistogramRGBArea() override; void updateBackBuffer (int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = ""); bool getShow (); + void setShow(bool show); void setParent (Gtk::Grid* p) { parent = p; }; void update (int val, int rh, int gh, int bh); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, bool show); + void updateOptions (bool r, bool g, bool b, bool l, bool c, bool show); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; bool on_button_press_event (GdkEventButton* event) override; void factorChanged (double newFactor); +}; + +class HistogramRGBAreaHori final : public HistogramRGBArea +{ private: + void drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) override; + Gtk::SizeRequestMode get_request_mode_vfunc () const override; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override; void get_preferred_width_for_height_vfunc (int h, int &minimum_width, int &natural_width) const override; +}; +class HistogramRGBAreaVert final : public HistogramRGBArea +{ +private: + void drawBar(Cairo::RefPtr cc, double value, double max_value, int winw, int winh, double scale) override; + + Gtk::SizeRequestMode get_request_mode_vfunc () const override; + void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; + void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; + void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override; + void get_preferred_width_for_height_vfunc (int h, int &minimum_width, int &natural_width) const override; }; class DrawModeListener @@ -120,7 +152,10 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private { public: typedef sigc::signal type_signal_factor_changed; + typedef sigc::signal SignalBrightnessChanged; + static constexpr float MIN_BRIGHT = 0.1; + static constexpr float MAX_BRIGHT = 3; private: IdleRegister idle_register; type_signal_factor_changed sigFactorChanged; @@ -128,24 +163,49 @@ private: protected: LUTu rhist, ghist, bhist, lhist, chist; LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? + int vectorscope_scale; + array2D vect_hc, vect_hs; + std::vector vect_hc_buffer, vect_hs_buffer; + bool vect_hc_buffer_dirty, vect_hs_buffer_dirty; + int waveform_scale; + array2D rwave, gwave, bwave, lwave; + std::vector parade_buffer_r; + std::vector parade_buffer_g; + std::vector parade_buffer_b; + bool parade_buffer_r_dirty, parade_buffer_g_dirty, parade_buffer_b_dirty; + std::vector wave_buffer; + std::vector wave_buffer_luma; + bool wave_buffer_dirty, wave_buffer_luma_dirty; bool valid; int drawMode; DrawModeListener *myDrawModeListener; + Options::ScopeType scopeType; int oldwidth, oldheight; + /// Intensity of waveform and vectorscope trace. + float trace_brightness; bool needRed, needGreen, needBlue, needLuma, needChroma; - bool rawMode; bool isPressed; double movingPosition; + bool needPointer; + + double padding = 5.0; HistogramAreaIdleHelper* haih; + int pointer_red, pointer_green, pointer_blue; + float pointer_a, pointer_b; + + SignalBrightnessChanged signal_brightness_changed; + public: explicit HistogramArea(DrawModeListener *fml = nullptr); ~HistogramArea() override; void updateBackBuffer (); + /// Update pointer values. Returns true if widget needs redrawing. + bool updatePointer(int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = ""); void update( const LUTu& histRed, const LUTu& histGreen, @@ -154,19 +214,35 @@ public: const LUTu& histChroma, const LUTu& histRedRaw, const LUTu& histGreenRaw, - const LUTu& histBlueRaw + const LUTu& histBlueRaw, + int vectorscopeScale, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, + int waveformScale, + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma ); - void updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode); + void updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, Options::ScopeType type, bool pointer); + bool updatePending(); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; bool on_button_press_event (GdkEventButton* event) override; bool on_button_release_event (GdkEventButton* event) override; bool on_motion_notify_event (GdkEventMotion* event) override; + float getBrightness(void); + /** Set the trace brightness, with 1 being normal. */ + void setBrightness(float brightness); + SignalBrightnessChanged getBrighnessChangedSignal(void); type_signal_factor_changed signal_factor_changed(); private: void drawCurve(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int vsize); void drawMarks(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi); + void drawParade(Cairo::RefPtr &cr, int hsize, int vsize); + void drawVectorscope(Cairo::RefPtr &cr, int hsize, int vsize); + void drawWaveform(Cairo::RefPtr &cr, int hsize, int vsize); Gtk::SizeRequestMode get_request_mode_vfunc () const override; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; @@ -174,29 +250,48 @@ private: void get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const override; }; +class HistogramPanelListener +{ +public: + virtual void scopeTypeChanged(Options::ScopeType new_type) = 0; +}; + class HistogramPanel final : public Gtk::Grid, public PointerMotionListener, public DrawModeListener, public rtengine::NonCopyable { +private: + DelayedCall pointer_moved_delayed_call; protected: Gtk::Grid* gfxGrid; Gtk::Grid* buttonGrid; + Gtk::Box* persistentButtons; + Gtk::Box* optionButtons; HistogramArea* histogramArea; HistogramRGBArea* histogramRGBArea; + std::unique_ptr histogramRGBAreaHori; + std::unique_ptr histogramRGBAreaVert; Gtk::ToggleButton* showRed; Gtk::ToggleButton* showGreen; Gtk::ToggleButton* showBlue; Gtk::ToggleButton* showValue; - Gtk::ToggleButton* showRAW; Gtk::ToggleButton* showBAR; Gtk::ToggleButton* showChro; Gtk::Button* showMode; + Gtk::ToggleButton* scopeOptions; + Gtk::Scale* brightnessWidget; + + Gtk::RadioButton* scopeHistBtn; + Gtk::RadioButton* scopeHistRawBtn; + Gtk::RadioButton* scopeParadeBtn; + Gtk::RadioButton* scopeWaveBtn; + Gtk::RadioButton* scopeVectHcBtn; + Gtk::RadioButton* scopeVectHsBtn; Gtk::Image *redImage; Gtk::Image *greenImage; Gtk::Image *blueImage; Gtk::Image *valueImage; - Gtk::Image *rawImage; Gtk::Image *barImage; Gtk::Image *chroImage; @@ -204,7 +299,6 @@ protected: Gtk::Image *greenImage_g; Gtk::Image *blueImage_g; Gtk::Image *valueImage_g; - Gtk::Image *rawImage_g; Gtk::Image *barImage_g; Gtk::Image *chroImage_g; @@ -212,8 +306,14 @@ protected: Gtk::Image *mode1Image; Gtk::Image *mode2Image; + HistogramPanelListener* panel_listener; + + sigc::connection brightness_changed_connection; sigc::connection rconn; void setHistInvalid (); + void showRGBBar(); + void updateHistAreaOptions(); + void updateHistRGBAreaOptions(); public: @@ -228,9 +328,18 @@ public: const LUTu& histChroma, const LUTu& histRedRaw, const LUTu& histGreenRaw, - const LUTu& histBlueRaw) + const LUTu& histBlueRaw, + int vectorscopeScale, + const array2D& vectorscopeHC, + const array2D& vectorscopeHS, + int waveformScale, + const array2D& waveformRed, + const array2D& waveformGreen, + const array2D& waveformBlue, + const array2D& waveformLuma + ) { - histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw); + histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } // pointermotionlistener interface void pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw = false) override; @@ -243,13 +352,19 @@ public: void green_toggled (); void blue_toggled (); void value_toggled (); - void raw_toggled (); void chro_toggled (); void bar_toggled (); void mode_released (); + void brightnessWidgetValueChanged(); + void brightnessUpdated(float brightness); + void scopeOptionsToggled(); + void type_selected(Gtk::RadioButton* button); + void type_changed (); void rgbv_toggled (); void resized (Gtk::Allocation& req); // drawModeListener interface void toggleButtonMode () override; + + void setPanelListener(HistogramPanelListener* listener); }; 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/iccprofilecreator.cc b/rtgui/iccprofilecreator.cc index a8f9be007..3f1ed4089 100644 --- a/rtgui/iccprofilecreator.cc +++ b/rtgui/iccprofilecreator.cc @@ -151,9 +151,7 @@ ICCProfileCreator::ICCProfileCreator(RTWindow *rtwindow) aGamma = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_GAMMA"), 1, 3.5, 0.00001, 2.4)); setExpandAlignProperties(aGamma, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - if (aGamma->delay < options.adjusterMaxDelay) { - aGamma->delay = options.adjusterMaxDelay; - } + aGamma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); aGamma->show(); mainGrid->attach(*aGamma, 1, 3, 1, 1); //gamma @@ -161,9 +159,7 @@ ICCProfileCreator::ICCProfileCreator(RTWindow *rtwindow) aSlope = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_SLOPE"), 0, 15, 0.00001, 12.92310)); setExpandAlignProperties(aSlope, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - if (aSlope->delay < options.adjusterMaxDelay) { - aSlope->delay = options.adjusterMaxDelay; - } + aSlope->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); aSlope->show(); mainGrid->attach(*aSlope, 1, 4, 1, 1); //slope @@ -328,7 +324,7 @@ ICCProfileCreator::ICCProfileCreator(RTWindow *rtwindow) close->signal_clicked().connect(sigc::mem_fun(*this, &ICCProfileCreator::closePressed)); get_action_area()->pack_start(*close); - //--------------- Show childrens + //--------------- Show children show_all_children(); @@ -881,8 +877,7 @@ void ICCProfileCreator::savePressed() double ts = slope; double slope2 = slope == 0 ? eps : slope; - int mode = 0; - rtengine::Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 + rtengine::Color::calcGamma(pwr, ts, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2 ga[4] = g_a[3] * ts; //printf("g_a.gamma0=%f g_a.gamma1=%f g_a.gamma2=%f g_a.gamma3=%f g_a.gamma4=%f\n", g_a.gamma0,g_a.gamma1,g_a.gamma2,g_a.gamma3,g_a.gamma4); ga[0] = gamma; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 3e3c0508c..92827bf30 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -194,33 +194,29 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wTRCHBox->pack_start(*wtrclab, Gtk::PACK_SHRINK); wTRC = Gtk::manage(new MyComboBoxText()); wTRCHBox->pack_start(*wTRC, Gtk::PACK_EXPAND_WIDGET); - wProfVBox->pack_start(*wTRCHBox, Gtk::PACK_EXPAND_WIDGET); + // wProfVBox->pack_start(*wTRCHBox, Gtk::PACK_EXPAND_WIDGET); wTRC->append(M("TP_ICM_WORKING_TRC_NONE")); wTRC->append(M("TP_ICM_WORKING_TRC_CUSTOM")); - wTRC->set_active(0); - wTRC->set_tooltip_text(M("TP_ICM_WORKING_TRC_TOOLTIP")); +// wTRC->set_active(0); +// wTRC->set_tooltip_text(M("TP_ICM_WORKING_TRC_TOOLTIP")); wGamma = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_TRC_GAMMA"), 0.40, 15.0, 0.001, 2.4)); wSlope = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_TRC_SLOPE"), 0., 150., 0.01, 12.92310)); - wProfVBox->pack_start(*wGamma, Gtk::PACK_SHRINK); - wGamma->show(); +// wProfVBox->pack_start(*wGamma, Gtk::PACK_SHRINK); +// wGamma->show(); - wProfVBox->pack_start(*wSlope, Gtk::PACK_SHRINK); - wSlope->show(); +// wProfVBox->pack_start(*wSlope, Gtk::PACK_SHRINK); +// wSlope->show(); wGamma->setAdjusterListener(this); wSlope->setAdjusterListener(this); - if (wGamma->delay < options.adjusterMaxDelay) { - wGamma->delay = options.adjusterMaxDelay; - } + wGamma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); - if (wSlope->delay < options.adjusterMaxDelay) { - wSlope->delay = options.adjusterMaxDelay; - } + wSlope->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); wFrame->add(*wProfVBox); @@ -428,8 +424,8 @@ void ICMPanel::updateDCP(int dcpIlluminant, Glib::ustring dcp_name) if (illuminants.will_interpolate) { if (dcpTemperatures[0] != illuminants.temperature_1 || dcpTemperatures[1] != illuminants.temperature_2) { char tempstr1[64], tempstr2[64]; - sprintf(tempstr1, "%.0fK", illuminants.temperature_1); - sprintf(tempstr2, "%.0fK", illuminants.temperature_2); + snprintf(tempstr1, sizeof(tempstr1), "%.0fK", illuminants.temperature_1); + snprintf(tempstr2, sizeof(tempstr2), "%.0fK", illuminants.temperature_2); int curr_active = dcpIll->get_active_row_number(); dcpIll->remove_all(); dcpIll->append(M("TP_ICM_DCPILLUMINANT_INTERPOLATED")); 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/inspector.cc b/rtgui/inspector.cc index 9002cc389..37ed20207 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -82,18 +82,283 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), zoom(0.0), active(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false) { set_name("Inspector"); + + if (!options.inspectorWindow) { + window = nullptr; + } + else { + window = new Gtk::Window(); + window->set_title("RawTherapee Inspector"); + window->set_visible(false); + window->add_events(Gdk::KEY_PRESS_MASK); + window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); + window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press)); + + add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); + gestureZoom = Gtk::GestureZoom::create(*this); + gestureZoom->signal_begin().connect(sigc::mem_fun(*this, &Inspector::on_zoom_begin)); + gestureZoom->signal_scale_changed().connect(sigc::mem_fun(*this, &Inspector::on_zoom_scale_changed)); + + window->add(*this); + window->set_size_request(500, 500); + initialized = false; // delay init to avoid flickering on some systems + active = true; // always track inspected thumbnails + } } Inspector::~Inspector() { deleteBuffers(); + if (window) + delete window; +} + +void Inspector::showWindow(bool scaled, bool fullscreen) +{ + if (!window) + return; + + // initialize when shown first + if (!initialized) { + window->show_all(); + window->set_visible(false); + initialized = true; + } + + // show inspector window + this->scaled = scaled; + if (fullscreen) + window->fullscreen(); + else + window->unfullscreen(); + this->fullscreen = fullscreen; + window->set_visible(true); + pinned = false; + + // update content when becoming visible + switchImage(next_image_path); + mouseMove(next_image_pos, 0); +} + +bool Inspector::on_key_release(GdkEventKey *event) +{ + if (!window) + return false; + + if (!pinned) { + switch (event->keyval) { + case GDK_KEY_f: + case GDK_KEY_F: + zoomScale = 1.0; + window->set_visible(false); + return true; + } + } + return false; +} + +bool Inspector::on_key_press(GdkEventKey *event) +{ + if (!window) + return false; + + switch (event->keyval) { + case GDK_KEY_z: + case GDK_KEY_F: + // show image unscaled in 100% view + if (pinned || scaled) + zoomScale = 1.0; // reset if not key hold + scaled = false; + queue_draw(); + return true; + case GDK_KEY_f: + // show image scaled to window size + if (pinned || !scaled) + zoomScale = 1.0; // reset if not key hold + scaled = true; + queue_draw(); + return true; + case GDK_KEY_F11: + // toggle fullscreen + if (fullscreen) + window->unfullscreen(); + else + window->fullscreen(); + fullscreen = !fullscreen; + return true; + case GDK_KEY_Escape: + // hide window + zoomScale = 1.0; + window->set_visible(false); + return true; + } + + return false; +} + +bool Inspector::on_button_press_event(GdkEventButton *event) +{ + if (!window) + return false; + + if (event->type == GDK_BUTTON_PRESS) { + button_pos.set(event->x, event->y); + if (!pinned) + // pin window with mouse click + pinned = true; + return true; + } + return false; +} + +bool Inspector::on_motion_notify_event(GdkEventMotion *event) +{ + if (!currImage || !window) + return false; + + int deviceScale = get_scale_factor(); + int delta_x = (button_pos.x - event->x)*deviceScale; + int delta_y = (button_pos.y - event->y)*deviceScale; + int imW = currImage->imgBuffer.getWidth(); + int imH = currImage->imgBuffer.getHeight(); + + moveCenter(delta_x, delta_y, imW, imH, deviceScale); + button_pos.set(event->x, event->y); + + if (!dirty) { + dirty = true; + queue_draw(); + } + + return true; +} + +bool Inspector::on_scroll_event(GdkEventScroll *event) +{ + if (!currImage || !window) + return false; + + bool alt = event->state & GDK_MOD1_MASK; + int deviceScale = get_scale_factor(); + int imW = currImage->imgBuffer.getWidth(); + int imH = currImage->imgBuffer.getHeight(); + +#ifdef GDK_WINDOWING_QUARTZ + // event reports speed of scroll wheel + double step_x = -event->delta_x; + double step_y = event->delta_y; +#else + // assume fixed step of 5% + double step_x = 5; + double step_y = 5; +#endif + int delta_x = 0; + int delta_y = 0; + switch (event->direction) { + case GDK_SCROLL_SMOOTH: +#ifdef GDK_WINDOWING_QUARTZ + // no additional step for smooth scrolling + delta_x = event->delta_x * deviceScale; + delta_y = event->delta_y * deviceScale; +#else + // apply step to smooth scrolling as well + delta_x = event->delta_x * deviceScale * step_x * imW / 100; + delta_y = event->delta_y * deviceScale * step_y * imH / 100; +#endif + break; + case GDK_SCROLL_DOWN: + delta_y = step_y * deviceScale * imH / 100; + break; + case GDK_SCROLL_UP: + delta_y = -step_y * deviceScale * imH / 100; + break; + case GDK_SCROLL_LEFT: + delta_x = step_x * deviceScale * imW / 100; + break; + case GDK_SCROLL_RIGHT: + delta_x = -step_x * deviceScale * imW / 100; + break; + } + + if ((options.zoomOnScroll && !alt) || (!options.zoomOnScroll && alt)) { + // zoom + beginZoom(event->x, event->y); + if (std::fabs(delta_y) > std::fabs(delta_x)) + on_zoom_scale_changed(1.0 - (double)delta_y / imH / deviceScale); + else + on_zoom_scale_changed(1.0 - (double)delta_x / imW / deviceScale); + return true; + } + + // scroll + moveCenter(delta_x, delta_y, imW, imH, deviceScale); + + if (!dirty) { + dirty = true; + queue_draw(); + } + + return true; +} + +void Inspector::moveCenter(int delta_x, int delta_y, int imW, int imH, int deviceScale) +{ + rtengine::Coord margin; // limit to image size + margin.x = rtengine::min(window->get_width() * deviceScale / scale, imW) / 2; + margin.y = rtengine::min(window->get_height() * deviceScale / scale, imH) / 2; + center.set(rtengine::LIM(center.x + delta_x, margin.x, imW - margin.x), + rtengine::LIM(center.y + delta_y, margin.y, imH - margin.y)); +} + +void Inspector::beginZoom(double x, double y) +{ + if (!currImage || !window) + return; + + int deviceScale = get_scale_factor(); + int imW = currImage->imgBuffer.getWidth(); + int imH = currImage->imgBuffer.getHeight(); + + // limit center to image size + moveCenter(0, 0, imW, imH, deviceScale); + + // store center and current position for zooming + dcenterBegin.x = (x - window->get_width()/2) / scale * deviceScale; + dcenterBegin.y = (y - window->get_height()/2) / scale * deviceScale; + centerBegin = center; + zoomScaleBegin = zoomScale; + +} + +void Inspector::on_zoom_begin(GdkEventSequence *s) +{ + double x, y; + if (gestureZoom->get_point(s, x, y)) + beginZoom(x, y); +} + +void Inspector::on_zoom_scale_changed(double zscale) +{ + if (!currImage || !window) + return; + + zoomScale = rtengine::LIM(zoomScaleBegin * zscale, 0.01, 16.0); + double dcenterRatio = 1.0 - zoomScaleBegin / zoomScale; + center.x = centerBegin.x + dcenterBegin.x * dcenterRatio; + center.y = centerBegin.y + dcenterBegin.y * dcenterRatio; + + if (!dirty) { + dirty = true; + queue_draw(); + } } bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) { + dirty = false; Glib::RefPtr win = get_window(); @@ -116,10 +381,24 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) rtengine::Coord availableSize; rtengine::Coord topLeft; rtengine::Coord dest(0, 0); - availableSize.x = win->get_width(); - availableSize.y = win->get_height(); - int imW = currImage->imgBuffer.getWidth(); - int imH = currImage->imgBuffer.getHeight(); + int deviceScale = window? get_scale_factor(): 1; + availableSize.x = win->get_width() * deviceScale; + availableSize.y = win->get_height() * deviceScale; + int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); + int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); + scale = rtengine::min((double)availableSize.x / imW, (double)availableSize.y / imH); + if (scaled) { + // reduce size of image to fit into window, no further zoom down + zoomScale = rtengine::max(zoomScale, 1.0); + scale *= zoomScale; + } + else { + // limit zoom to fill at least complete window or 1:1 + zoomScale = rtengine::max(zoomScale, rtengine::min(1.0, scale)); + scale = zoomScale; + } + availableSize.x /= scale; + availableSize.y /= scale; if (imW < availableSize.x) { // center the image in the available space along X @@ -146,7 +425,6 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) topLeft.y -= availableSize.y; topLeft.y = rtengine::max(topLeft.y, 0); } - //printf("center: %d, %d (img: %d, %d) (availableSize: %d, %d) (topLeft: %d, %d)\n", center.x, center.y, imW, imH, availableSize.x, availableSize.y, topLeft.x, topLeft.y); // define the destination area @@ -162,25 +440,54 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) Gdk::RGBA c; Glib::RefPtr style = get_style_context(); - // draw the background - style->render_background(cr, 0, 0, get_width(), get_height()); + if (!window) { + // draw the background + style->render_background(cr, 0, 0, get_width(), get_height()); + } + else { + ///* --- old method (the new method does not seem to work) + c = style->get_background_color (Gtk::STATE_FLAG_NORMAL); + cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue()); + cr->set_line_width (0); + cr->rectangle (0, 0, availableSize.x, availableSize.y); + cr->fill (); + //*/ + } - /* --- old method - c = style->get_background_color (Gtk::STATE_FLAG_NORMAL); - cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue()); - cr->set_line_width (0); - cr->rectangle (0, 0, availableSize.x, availableSize.y); - cr->fill (); - */ + bool scaledImage = scale != 1.0; + if (!window || (deviceScale == 1 && !scaledImage)) { + // standard drawing + currImage->imgBuffer.copySurface(win); + } + else { + // consider device scale and image scale + if (deviceScale > 1) { + // use full device resolution and let it scale the image (macOS) + cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale); + scaledImage = false; + } + int viewW = rtengine::min(imW, availableSize.x); + int viewH = rtengine::min(imH, availableSize.y); + Glib::RefPtr crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeft.x, topLeft.y, viewW, viewH); + if (!scaledImage) { + Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x, dest.y); + } + else { + // scale crop as the device does not seem to support it (Linux) + crop = crop->scale_simple(viewW*scale, viewH*scale, Gdk::INTERP_BILINEAR); + Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x*scale, dest.y*scale); + } + cr->paint(); + } - currImage->imgBuffer.copySurface(win); - - // draw the frame - c = style->get_border_color (Gtk::STATE_FLAG_NORMAL); - cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue()); - cr->set_line_width (1); - cr->rectangle (0.5, 0.5, availableSize.x - 1, availableSize.y - 1); - cr->stroke (); + if (!window) { + // draw the frame + c = style->get_border_color (Gtk::STATE_FLAG_NORMAL); + cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue()); + cr->set_line_width (1); + cr->rectangle (0.5, 0.5, availableSize.x - 1, availableSize.y - 1); + cr->stroke (); + } } return true; @@ -192,6 +499,12 @@ void Inspector::mouseMove (rtengine::Coord2D pos, int transform) return; } + next_image_pos = pos; + + // skip actual update of content when not visible + if (window && !window->get_visible()) + return; + if (currImage) { center.set(int(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth())), int(rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight()))); } else { @@ -212,6 +525,11 @@ void Inspector::switchImage (const Glib::ustring &fullPath) } next_image_path = fullPath; + + // skip actual update of content when not visible + if (window && !window->get_visible()) + return; + if (!options.inspectorDelay) { doSwitchImage(); } else { @@ -309,7 +627,8 @@ void Inspector::setActive(bool state) flushBuffers(); } - active = state; + if (!window) + active = state; } diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 1526f90be..726bc947c 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -47,11 +47,35 @@ private: rtengine::Coord center; std::vector images; InspectorBuffer* currImage; - double zoom; + bool scaled; // fit image into window + double scale; // current scale + double zoomScale, zoomScaleBegin; // scale during zoom + rtengine::Coord centerBegin, dcenterBegin; // center during zoom bool active; + bool pinned; + bool dirty; + bool initialized; + bool fullscreen; // window is shown in fullscreen mode sigc::connection delayconn; Glib::ustring next_image_path; + rtengine::Coord2D next_image_pos; + + Gtk::Window *window; + bool on_key_release(GdkEventKey *event); + bool on_key_press(GdkEventKey *event); + + rtengine::Coord button_pos; + bool on_button_press_event(GdkEventButton *event) override; + bool on_motion_notify_event(GdkEventMotion *event) override; + + bool on_scroll_event(GdkEventScroll *event) override; + void moveCenter(int delta_x, int delta_y, int imW, int imH, int deviceScale); + + Glib::RefPtr gestureZoom; + void beginZoom(double x, double y); + void on_zoom_begin(GdkEventSequence *); + void on_zoom_scale_changed(double zscale); bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; void deleteBuffers(); @@ -62,6 +86,11 @@ public: Inspector(); ~Inspector() override; + /** @brief Show or hide window + * @param scaled fit image into window + */ + void showWindow(bool scaled, bool fullscreen = true); + /** @brief Mouse movement to a new position * @param pos Location of the mouse, in percentage (i.e. [0;1] range) relative to the full size image ; -1,-1 == out of the image * @param transform H/V flip and coarse rotation transformation diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index 5f4febc0a..27a8bee52 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -663,6 +663,8 @@ void LCurve::updateCurveBackgroundHistogram( { lshape->updateBackgroundHistogram (histLCurve); ccshape->updateBackgroundHistogram (histCCurve); + lcshape->updateBackgroundHistogram (histCCurve); + clshape->updateBackgroundHistogram (histLCurve); } void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) diff --git a/rtgui/lensgeomlistener.h b/rtgui/lensgeomlistener.h index 7bfa0fb45..b9979f9a2 100644 --- a/rtgui/lensgeomlistener.h +++ b/rtgui/lensgeomlistener.h @@ -18,6 +18,15 @@ */ #pragma once +#include +#include + +namespace rtengine +{ +class ControlLine; +class ProcEvent; +} + class LensGeomListener { public: @@ -25,4 +34,6 @@ public: virtual void straightenRequested () = 0; virtual void autoCropRequested () = 0; virtual double autoDistorRequested () = 0; + virtual void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector *lines = nullptr) = 0; + virtual void updateTransformPreviewRequested (rtengine::ProcEvent event, bool render_perspective) = 0; }; diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc new file mode 100644 index 000000000..886fbaf64 --- /dev/null +++ b/rtgui/locallab.cc @@ -0,0 +1,1224 @@ +/* + * 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())), + expmask(Gtk::manage(new LocallabMask())), + + // 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, expshadhigh); + addTool(toolpanel, expvibrance); + addTool(toolpanel, explog); + addTool(toolpanel, expexpose); + addTool(toolpanel, expmask); + addTool(toolpanel, expsoft); + addTool(toolpanel, expblur); + addTool(toolpanel, exptonemap); + addTool(toolpanel, expreti); + addTool(toolpanel, expsharp); + addTool(toolpanel, expcontrast); + addTool(toolpanel, expcbdl); + 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).prevMethod == "hide") { + r->prevMethod = 0; + } else { + r->prevMethod = 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->hishow = pp->locallab.spots.at(i).hishow; + r->activ = pp->locallab.spots.at(i).activ; + 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 = true; //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->prevMethod == "hide") { + r->prevMethod = 0; + } else { + r->prevMethod = 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->hishow = newSpot->hishow; + r->activ = newSpot->activ; + 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->prevMethod == "hide") { + r->prevMethod = 0; + } else { + r->prevMethod = 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->activ = newSpot->activ; + 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->prevMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).prevMethod = "hide"; + } else { + pp->locallab.spots.at(pp->locallab.selspot).prevMethod = "show"; + } + + + 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).hishow = r->hishow; + pp->locallab.spots.at(pp->locallab.selspot).activ = r->activ; + 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 sourceab, const float targetg) +{ + // Update Locallab Log Encoding accordingly + explog->updateAutocompute(blackev, whiteev, sourceg, sourceab, 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, logMask, maskMask; + + for (auto tool : locallabTools) { + tool->getMaskView(colorMask, colorMaskinv, expMask, expMaskinv, shMask, shMaskinv, vibMask, softMask, blMask, tmMask, retiMask, sharMask, lcMask, cbMask, logMask, maskMask); + } + + // 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) || (logMask == 0) || (maskMask == 0); + expsettings->setMaskPrevActive(isMaskActive); + + return {prevDeltaE, colorMask, colorMaskinv, expMask, expMaskinv, shMask, shMaskinv, vibMask, softMask, blMask, tmMask, retiMask, sharMask, lcMask, cbMask, logMask, maskMask}; +} + +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..511e28c03 --- /dev/null +++ b/rtgui/locallab.h @@ -0,0 +1,212 @@ +/* + * 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; + LocallabMask* const expmask; + + 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 sourceab, 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; + int logMask; + int maskMask; + }; + + 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..da5f746dd --- /dev/null +++ b/rtgui/locallabtools.cc @@ -0,0 +1,7160 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath frame +fft * + * 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-2020 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->append(M("TP_LOCALLAB_MODE_SIMPLE")); + complexity->set_active(2); + 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 if (complexity->get_active_row_number() == Expert) { + updateGUIToMode(Expert); + } else if (complexity->get_active_row_number() == Simple) { + convertParamToNormal(); + updateGUIToMode(Normal); + convertParamToSimple(); + updateGUIToMode(Simple); + } + + } + + 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() == Simple) { // New selected mode is Simple one + const bool maskPreviewActivated = isMaskViewActive(); + + // Convert tool widget parameters + convertParamToNormal(); // From Expert mode to Normal mode + convertParamToSimple(); // From Normal mode to Simple mode + // Update GUI based on new mode + updateGUIToMode(Simple); + + if (maskPreviewActivated) { + // This event is called to transmit reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + } + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_SIMPLE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else 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); + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_NORMAL") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else if (complexity->get_active_row_number() == Expert) { // New selected mode is Expert one + // Update GUI based on new mode + updateGUIToMode(Expert); + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + 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 + lumFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LUMFRA")))), + 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))), + curvactiv(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_CURV")))), + 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, 100.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))), + H3CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_HLH"))), + CHshape(static_cast(H3CurveEditorG->addCurve(CT_Flat, "C(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")))), + mergecolFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_MERGECOLFRA")))), + 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))), + toolcolFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK")))), + radmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.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 + lumFrame->set_label_align(0.025, 0.5); + + lightness->setAdjusterListener(this); + + contrast->setAdjusterListener(this); + + chroma->setAdjusterListener(this); + + curvactivConn = curvactiv->signal_toggled().connect(sigc::mem_fun(*this, &LocallabColor::curvactivChanged)); + + 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(); + + H3CurveEditorG->setCurveListener(this); + + CHshape->setIdentityValue(0.); + CHshape->setResetCurve(FlatCurveType(defSpot.CHcurve.at(0)), defSpot.CHcurve); + CHshape->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP")); + CHshape->setCurveColorProvider(this, 3); + CHshape->setBottomBarBgGradient(six_shape); + + H3CurveEditorG->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->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->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 + ToolParamBlock* const lumBox = Gtk::manage(new ToolParamBlock()); + lumBox->pack_start(*lightness); + lumBox->pack_start(*contrast); + lumBox->pack_start(*chroma); + lumFrame->add(*lumBox); + pack_start(*lumFrame); + 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()); + 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(*H3CurveEditorG, 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); + 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 H3CurveEditorG; + 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, int &logMask, int &maskMask) +{ + colorMask = showmaskcolMethod->get_active_row_number(); + colorMaskinv = showmaskcolMethodinv->get_active_row_number(); +} + +void LocallabColor::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + lumFrame->set_tooltip_text(M("TP_LOCALLAB_EXPCOLOR_TOOLTIP")); + lightness->set_tooltip_text(M("TP_LOCALLAB_LIGHTN_TOOLTIP")); + gridMethod->set_tooltip_text(M("TP_LOCALLAB_GRIDMETH_TOOLTIP")); + strengthgrid->set_tooltip_text(M("TP_LOCALLAB_STRENGRID_TOOLTIP")); + blurcolde->set_tooltip_text(M("TP_LOCALLAB_BLURCOLDE_TOOLTIP")); + softradiuscol->set_tooltip_text(M("TP_LOCALLAB_SOFTRADIUSCOL_TOOLTIP")); + expgradcol->set_tooltip_text(M("TP_LOCALLAB_EXPGRADCOL_TOOLTIP")); + rgbCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_RGBCURVE_TOOLTIP")); + sensi->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + structcol->set_tooltip_text(M("TP_LOCALLAB_STRUCT_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")); + special->set_tooltip_text(M("TP_LOCALLAB_SPECIAL_TOOLTIP")); + expmaskcol1->set_tooltip_text(M("TP_LOCALLAB_EXPMERGEFILE_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")); + struFrame->set_tooltip_text(M("TP_LOCALLAB_STRUMASK_TOOLTIP")); + blurFrame->set_tooltip_text(M("TP_LOCALLAB_BLURMASK_TOOLTIP")); + blendmaskcol->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmaskcol->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + maskHCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_HHMASK_TOOLTIP")); + mask2CurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmaskshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + mask2CurveEditorGwav->set_tooltip_text(M("TP_LOCALLAB_WAVMASK_TOOLTIP")); + LLmaskcolshapewav->setTooltip(M("TP_LOCALLAB_LMASK_LEVEL_TOOLTIP")); + mergecolFrame->set_tooltip_markup(M("TP_LOCALLAB_MERGECOLFRMASK_TOOLTIP")); + maskCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + strumaskcol->set_tooltip_text(M("TP_LOCALLAB_STRUSTRMASK_TOOLTIP")); + toolcol->set_tooltip_text(M("TP_LOCALLAB_TOOLMASK_TOOLTIP")); + toolcolFrame->set_tooltip_text(M("TP_LOCALLAB_TOOLCOLFRMASK_TOOLTIP")); + fftColorMask->set_tooltip_text(M("TP_LOCALLAB_FFTMASK_TOOLTIP")); + gammaskcol->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskcol->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskcol->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + shadmaskcol->set_tooltip_text(M("TP_LOCALLAB_SHADMASK_TOOLTIP")); + contcol->set_tooltip_text(M("TP_LOCALLAB_CONTTHMASK_TOOLTIP")); + blurcol->set_tooltip_text(M("TP_LOCALLAB_BLURRMASK_TOOLTIP")); + lapmaskcol->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + csThresholdcol->set_tooltip_text(M("TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP")); + } else { + lumFrame->set_tooltip_text(""); + lightness->set_tooltip_text(""); + gridMethod->set_tooltip_text(""); + strengthgrid->set_tooltip_text(""); + blurcolde->set_tooltip_text(""); + softradiuscol->set_tooltip_text(""); + expgradcol->set_tooltip_text(""); + rgbCurveEditorG->set_tooltip_text(""); + sensi->set_tooltip_text(""); + structcol->set_tooltip_text(""); + strcol->set_tooltip_text(""); + angcol->set_tooltip_text(""); + qualitycurveMethod->set_tooltip_markup(""); + special->set_tooltip_text(""); + expmaskcol1->set_tooltip_text(""); + maskCurveEditorG->set_tooltip_markup(""); + mercol->set_tooltip_text(""); + opacol->set_tooltip_text(""); + conthrcol->set_tooltip_text(""); + gridmerFrame->set_tooltip_text(""); + expmaskcol->set_tooltip_markup(""); + mergecolFrame->set_tooltip_markup(""); + CCmaskshape->setTooltip(""); + LLmaskshape->setTooltip(""); + HHmaskshape->setTooltip(""); + struFrame->set_tooltip_text(""); + strumaskcol->set_tooltip_text(""); + toolcol->set_tooltip_text(""); + toolcolFrame->set_tooltip_text(""); + fftColorMask->set_tooltip_text(""); + gammaskcol->set_tooltip_text(""); + chromaskcol->set_tooltip_text(""); + slomaskcol->set_tooltip_text(""); + shadmaskcol->set_tooltip_text(""); + contcol->set_tooltip_text(""); + blurcol->set_tooltip_text(""); + blurFrame->set_tooltip_text(""); + blendmaskcol->set_tooltip_text(""); + radmaskcol->set_tooltip_text(""); + lapmaskcol->set_tooltip_text(""); + maskHCurveEditorG->set_tooltip_text(""); + mask2CurveEditorG->set_tooltip_text(""); + Lmaskshape->setTooltip(""); + mask2CurveEditorGwav->set_tooltip_text(""); + LLmaskcolshapewav->setTooltip(""); + csThresholdcol->set_tooltip_text(""); + } +} + +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); + + lightness->setValue(spot.lightness); + contrast->setValue(spot.contrast); + chroma->setValue(spot.chroma); + curvactiv->set_active(spot.curvactiv); + 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); + CHshape->setCurve(spot.CHcurve); + + 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.lightness = lightness->getIntValue(); + spot.contrast = contrast->getIntValue(); + spot.chroma = chroma->getIntValue(); + spot.curvactiv = curvactiv->get_active(); + 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(); + spot.CHcurve = CHshape->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 == CHshape) { + if (listener) { + listener->panelChanged(EvlocallabCHshape, + 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); + structcol->setValue((double)defSpot.structcol); + strcolab->setValue(defSpot.strcolab); + strcolh->setValue(defSpot.strcolh); + clshape->setCurve(defSpot.clcurve); + lcshape->setCurve(defSpot.lccurve); + LHshape->setCurve(defSpot.LHcurve); + CHshape->setCurve(defSpot.CHcurve); + 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); + blurcol->setValue(defSpot.blurcol); + 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::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + softradiuscol->setValue(defSpot.softradiuscol); + strcol->setValue(defSpot.strcol); + angcol->setValue(defSpot.angcol); + + if (defSpot.qualitycurveMethod == "none") { + qualitycurveMethod->set_active(0); + } else if (defSpot.qualitycurveMethod == "std") { + qualitycurveMethod->set_active(1); + } + + llshape->setCurve(defSpot.llcurve); + ccshape->setCurve(defSpot.cccurve); + showmaskcolMethod->set_active(0); + showmaskcolMethodinv->set_active(0); + enaColorMask->set_active(defSpot.enaColorMask); + CCmaskshape->setCurve(defSpot.CCmaskcurve); + LLmaskshape->setCurve(defSpot.LLmaskcurve); + HHmaskshape->setCurve(defSpot.HHmaskcurve); + blendmaskcol->setValue((double)defSpot.blendmaskcol); + radmaskcol->setValue(defSpot.radmaskcol); + chromaskcol->setValue(defSpot.chromaskcol); + Lmaskshape->setCurve(defSpot.Lmaskcurve); + + // Enable all listeners + enableListener(); +} + +void LocallabColor::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + structcol->hide(); + blurcolde->hide(); + softradiuscol->hide(); + expgradcol->hide(); + expcurvcol->hide(); + expmaskcol1->hide(); + expmaskcol->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + structcol->hide(); + blurcolde->hide(); + strcolab->hide(); + strcolh->hide(); + clCurveEditorG->hide(); + HCurveEditorG->hide(); + H3CurveEditorG->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(); + // Specific Simple mode widgets are shown in Normal mode + softradiuscol->show(); + + if (!invers->get_active()) { // Keep widget hidden when invers is toggled + expgradcol->show(); + } + + expcurvcol->show(); + expmaskcol->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + structcol->show(); + blurcolde->show(); + + if (!invers->get_active()) { // Keep widget hidden when invers is toggled + softradiuscol->show(); + expgradcol->show(); + } + + strcolab->show(); + strcolh->show(); + expcurvcol->show(); + + if (!invers->get_active()) { // Keep widgets hidden when invers is toggled + clCurveEditorG->show(); + HCurveEditorG->show(); + H3CurveEditorG->show(); + } + + H2CurveEditorG->show(); + rgbCurveEditorG->show(); + special->show(); + + if (!invers->get_active()) { // Keep widget hidden when invers is toggled + expmaskcol1->show(); + } + + expmaskcol->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); + Lmaskshape->updateLocallabBackground(normLumar); + HHshape->updateLocallabBackground(normHuer); + CHshape->updateLocallabBackground(normHuer); + LHshape->updateLocallabBackground(normHuer); + llshape->updateLocallabBackground(normLumar); + ccshape->updateLocallabBackground(normChromar); + clshape->updateLocallabBackground(normLumar); + lcshape->updateLocallabBackground(normChromar); + + 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() +{ + const bool maskPreviewActivated = isMaskViewActive(); + + // Update GUI according to invers button state + updateColorGUI1(); + + if (maskPreviewActivated) { + // This event is called to transmit 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(); + H3CurveEditorG->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(); + + if (mode == Expert) { // Keep widget hidden in Normal and Simple mode + structcol->show(); + } + + if (mode == Expert || mode == Normal) { // Keep widget hidden in Simple mode + softradiuscol->show(); + expgradcol->show(); + } + + labqualcurv->show(); + qualitycurveMethod->show(); + + if (mode == Expert) { // Keep widgets hidden in Normal and Simple mode + clCurveEditorG->show(); + HCurveEditorG->show(); + H3CurveEditorG->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")))), + exppde(Gtk::manage(new MyExpander(false, 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.01, 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))), + labelexpmethod(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_NOISEMETH") + ":"))), + exnoiseMethod(Gtk::manage(new MyComboBoxText())), +// fatFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_FATFRA")))), + expfat(Gtk::manage(new MyExpander(false, 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_LOCALLAB_EXPCOMP"), MINEXP, MAXEXP, 0.01, 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, 20))), + 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, 100.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"), 0.0, 100.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); + setExpandAlignProperties(exppde, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties(expfat, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + 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->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); + exppde->add(*pdeBox, false); +// pdeFrame->add(*pdeBox); +// pack_start(*pdeFrame); + pack_start(*exppde); + 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); + expfat->add(*fatBox, false); +// pack_start(*fatFrame); + pack_start(*expfat); + pack_start(*expcomp); + pack_start(*sensiex); + pack_start(*structexp); + pack_start(*blurexpde); + ToolParamBlock* const toolBox = Gtk::manage(new ToolParamBlock()); + 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, int &logMask, int &maskMask) +{ + 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")); +// pdeFrame->set_tooltip_text(M("TP_LOCALLAB_PDEFRAME_TOOLTIP")); + exppde->set_tooltip_text(M("TP_LOCALLAB_PDEFRAME_TOOLTIP")); + blurexpde->set_tooltip_text(M("TP_LOCALLAB_BLURCOLDE_TOOLTIP")); + laplacexp->set_tooltip_text(M("TP_LOCALLAB_EXPLAP_TOOLTIP")); + linear->set_tooltip_text(M("TP_LOCALLAB_EXPLAPLIN_TOOLTIP")); + balanexp->set_tooltip_text(M("TP_LOCALLAB_EXPLAPBAL_TOOLTIP")); + gamm->set_tooltip_text(M("TP_LOCALLAB_EXPLAPGAMM_TOOLTIP")); + labelexpmethod->set_tooltip_text(M("TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP")); + exnoiseMethod->set_tooltip_text(M("TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP")); +// fatFrame->set_tooltip_text(M("TP_LOCALLAB_FATFRAME_TOOLTIP")); + expfat->set_tooltip_text(M("TP_LOCALLAB_FATFRAME_TOOLTIP")); + expcomp->set_tooltip_text(M("TP_LOCALLAB_EXPCOMP_TOOLTIP")); + sensiex->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + structexp->set_tooltip_text(M("TP_LOCALLAB_STRUCT_TOOLTIP")); + expchroma->set_tooltip_text(M("TP_LOCALLAB_EXPCHROMA_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")); + blendmaskexp->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmaskexp->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + lapmaskexp->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + strmaskexp->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + mask2expCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmaskexpshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + maskexpCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + gammaskexp->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskexp->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskexp->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + lapmaskexp->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + exppde->set_tooltip_text(""); + blurexpde->set_tooltip_text(""); + laplacexp->set_tooltip_text(""); + linear->set_tooltip_text(""); + balanexp->set_tooltip_text(""); + gamm->set_tooltip_text(""); + labelexpmethod->set_tooltip_text(""); + exnoiseMethod->set_tooltip_text(""); + expfat->set_tooltip_text(""); + expcomp->set_tooltip_text(""); + sensiex->set_tooltip_text(""); + structexp->set_tooltip_text(""); + expchroma->set_tooltip_text(""); + shapeexpos->setTooltip(""); + strexp->set_tooltip_text(""); + expmaskexp->set_tooltip_markup(""); + CCmaskexpshape->setTooltip(""); + LLmaskexpshape->setTooltip(""); + HHmaskexpshape->setTooltip(""); + blendmaskexp->set_tooltip_text(""); + radmaskexp->set_tooltip_text(""); + strmaskexp->set_tooltip_text(""); + mask2expCurveEditorG->set_tooltip_text(""); + Lmaskexpshape->setTooltip(""); + gammaskexp->set_tooltip_text(""); + chromaskexp->set_tooltip_text(""); + slomaskexp->set_tooltip_text(""); + lapmaskexp->set_tooltip_text(""); + } +} + +void LocallabExposure::setDefaultExpanderVisibility() +{ + exptoolexp->set_expanded(false); + exppde->set_expanded(false); + expfat->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 + structexp->setValue((double)defSpot.structexp); + 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); + + // Enable all listeners + enableListener(); +} + +void LocallabExposure::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + strexp->setValue(defSpot.strexp); + angexp->setValue(defSpot.angexp); + softradiusexp->setValue(defSpot.softradiusexp); + enaExpMask->set_active(defSpot.enaExpMask); + enaExpMaskaft->set_active(defSpot.enaExpMaskaft); + CCmaskexpshape->setCurve(defSpot.CCmaskexpcurve); + LLmaskexpshape->setCurve(defSpot.CCmaskexpcurve); + HHmaskexpshape->setCurve(defSpot.HHmaskexpcurve); + blendmaskexp->setValue((double)defSpot.blendmaskexp); + radmaskexp->setValue(defSpot.radmaskexp); + chromaskexp->setValue(defSpot.chromaskexp); + Lmaskexpshape->setCurve(defSpot.Lmaskexpcurve); + + // Enable all listeners + enableListener(); +} + +void LocallabExposure::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + structexp->hide(); + blurexpde->hide(); + expgradexp->hide(); + softradiusexp->hide(); + expmaskexp->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + structexp->hide(); + blurexpde->hide(); + lapmaskexp->hide(); + gammaskexp->hide(); + slomaskexp->hide(); + gradFramemask->hide(); + + // Specific Simple mode widgets are shown in Normal mode + if (!inversex->get_active()) { // Keep widget hidden when invers is toggled + expgradexp->show(); + softradiusexp->show(); + } + + expmaskexp->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + if (!inversex->get_active()) { // Keep widget hidden when invers is toggled + structexp->show(); + } + + blurexpde->show(); + + if (!inversex->get_active()) { // Keep widget hidden when invers is toggled + expgradexp->show(); + softradiusexp->show(); + } + + expmaskexp->show(); + lapmaskexp->show(); + gammaskexp->show(); + slomaskexp->show(); + gradFramemask->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); + shapeexpos->updateLocallabBackground(normLumar); + Lmaskexpshape->updateLocallabBackground(normLumar); + 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() +{ + const bool maskPreviewActivated = isMaskViewActive(); + + // Update exposure GUI according to inversex button state + updateExposureGUI3(); + + if (maskPreviewActivated) { + // This event is called to transmit 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(); + exppde->hide(); + expfat->hide(); + softradiusexp->set_sensitive(true); + sensiex->set_sensitive(true); + } else if (expMethod->get_active_row_number() == 1) { + // pdeFrame->show(); + // fatFrame->show(); + exppde->show(); + expfat->show(); + softradiusexp->set_sensitive(false); + sensiex->set_sensitive(true); + } + */ +} + +void LocallabExposure::updateExposureGUI3() +{ + const int mode = complexity->get_active_row_number(); + + // Update exposure GUI according to inversex button state + if (inversex->get_active()) { + expMethod->hide(); + expcomp->setLabel(M("TP_LOCALLAB_EXPCOMPINV")); + + // 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(); + } + + 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(); + expcomp->setLabel(M("TP_LOCALLAB_EXPCOMP")); + + if (mode == Expert || mode == Normal) { // Keep widgets hidden in Simple mode + 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, 500.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"), 0.0, 100.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 (const auto multiplier : multipliersh) { + multiplier->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->setLogScale(16, 0); + + 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->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 (const auto multiplier : multipliersh) { + pack_start(*multiplier); + } + + 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); + 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, int &logMask, int &maskMask) +{ + 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")); + + for (const auto multiplier : multipliersh) { + multiplier->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")); + strSH->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); + expmasksh->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + blurSHde->set_tooltip_text(M("TP_LOCALLAB_BLURCOLDE_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")); + blendmaskSH->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmaskSH->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + mask2SHCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + LmaskSHshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + maskSHCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + gammaskSH->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskSH->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskSH->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + lapmaskSH->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + /* + highlights->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + h_tonalwidth->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + shadows->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + s_tonalwidth->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + sh_radius->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + */ + highlights->set_tooltip_text(""); + h_tonalwidth->set_tooltip_text(""); + shadows->set_tooltip_text(""); + s_tonalwidth->set_tooltip_text(""); + sh_radius->set_tooltip_text(""); + + } else { + exp->set_tooltip_text(""); + + for (const auto multiplier : multipliersh) { + multiplier->set_tooltip_text(""); + } + gamSH->set_tooltip_text(""); + sloSH->set_tooltip_text(""); + strSH->set_tooltip_text(""); + blurSHde->set_tooltip_text(""); + expmasksh->set_tooltip_markup(""); + CCmaskSHshape->setTooltip(""); + LLmaskSHshape->setTooltip(""); + HHmaskSHshape->setTooltip(""); + blendmaskSH->set_tooltip_text(""); + radmaskSH->set_tooltip_text(""); + lapmaskSH->set_tooltip_text(""); + mask2SHCurveEditorG->set_tooltip_text(""); + LmaskSHshape->setTooltip(""); + maskSHCurveEditorG->set_tooltip_markup(""); + gammaskSH->set_tooltip_text(""); + chromaskSH->set_tooltip_text(""); + slomaskSH->set_tooltip_text(""); + highlights->set_tooltip_text(""); + h_tonalwidth->set_tooltip_text(""); + shadows->set_tooltip_text(""); + s_tonalwidth->set_tooltip_text(""); + sh_radius->set_tooltip_text(""); + + } +} + +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::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + gamSH->setValue(defSpot.gamSH); + sloSH->setValue(defSpot.sloSH); + strSH->setValue(defSpot.strSH); + angSH->setValue(defSpot.angSH); + showmaskSHMethod->set_active(0); + showmaskSHMethodinv->set_active(0); + enaSHMask->set_active(defSpot.enaSHMask); + CCmaskSHshape->setCurve(defSpot.CCmaskSHcurve); + LLmaskSHshape->setCurve(defSpot.LLmaskSHcurve); + HHmaskSHshape->setCurve(defSpot.HHmaskSHcurve); + blendmaskSH->setValue((double)defSpot.blendmaskSH); + radmaskSH->setValue(defSpot.radmaskSH); + chromaskSH->setValue(defSpot.chromaskSH); + LmaskSHshape->setCurve(defSpot.LmaskSHcurve); + + // Enable all listeners + enableListener(); +} + +void LocallabShadow::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + blurSHde->hide(); + gamFrame->hide(); + expgradsh->hide(); + expmasksh->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + blurSHde->hide(); + lapmaskSH->hide(); + gammaskSH->hide(); + slomaskSH->hide(); + fatSHFrame->hide(); + + // Specific Simple mode widgets are shown in Normal mode + if (shMethod->get_active_row_number() != 0) { // Keep widget hidden when shMethod is equal to 0 + gamFrame->show(); + } + + if (!inverssh->get_active()) { // Keep widget hidden when inverssh is toggled + expgradsh->show(); + } + + expmasksh->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + blurSHde->show(); + + if (shMethod->get_active_row_number() != 0) { // Keep widget hidden when shMethod is equal to 0 + gamFrame->show(); + } + + if (!inverssh->get_active()) { // Keep widget hidden when inverssh is toggled + expgradsh->show(); + } + + expmasksh->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); + LmaskSHshape->updateLocallabBackground(normLumar); + + 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() +{ + const bool maskPreviewActivated = isMaskViewActive(); + + // Update shadow highlight GUI according to inverssh button state + updateShadowGUI1(); + + if (maskPreviewActivated) { + // This event is called to transmit 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() +{ + const int mode = complexity->get_active_row_number(); + + // 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 { + if (mode == Expert || mode == Normal) { // Keep widget hidden in Simple mode + expgradsh->show(); + } + + showmaskSHMethod->show(); + showmaskSHMethodinv->hide(); + // Reset hidden mask combobox + showmaskSHMethodConninv.block(true); + showmaskSHMethodinv->set_active(0); + showmaskSHMethodConninv.block(false); + } +} + +void LocallabShadow::updateShadowGUI2() +{ + const int mode = complexity->get_active_row_number(); + + // Update shadow highlight GUI according to shMethod combobox state + if (shMethod->get_active_row_number() == 0) { + for (const auto multiplier : multipliersh) { + multiplier->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 (const auto multiplier : multipliersh) { + multiplier->show(); + } + + if (mode == Expert || mode == Normal) { // Keep widget hidden in Simple mode + 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"), 0.0, 100.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->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, int &logMask, int &maskMask) +{ + vibMask = showmaskvibMethod->get_active_row_number(); +} + +void LocallabVibrance::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_VIBRA_TOOLTIP")); + 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")); + blendmaskvib->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2vibCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmaskvibshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + maskvibCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + gammaskvib->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskvib->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskvib->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + lapmaskvib->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); +/* + saturated->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + pastels->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + psThreshold->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + protectSkins->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + avoidColorShift->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + pastSatTog->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + sensiv->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); + curveEditorGG->set_tooltip_text(M("TP_LOCALLAB_NUL_TOOLTIP")); +*/ + + saturated->set_tooltip_text(""); + pastels->set_tooltip_text(""); + psThreshold->set_tooltip_text(""); + protectSkins->set_tooltip_text(""); + avoidColorShift->set_tooltip_text(""); + pastSatTog->set_tooltip_text(""); + sensiv->set_tooltip_text(""); + curveEditorGG->set_tooltip_text(""); + + } else { + exp->set_tooltip_text(""); + warm->set_tooltip_text(""); + strvib->set_tooltip_text(""); + expmaskvib->set_tooltip_markup(""); + CCmaskvibshape->setTooltip(""); + LLmaskvibshape->setTooltip(""); + HHmaskvibshape->setTooltip(""); + blendmaskvib->set_tooltip_text(""); + mask2vibCurveEditorG->set_tooltip_text(""); + Lmaskvibshape->setTooltip(""); + maskvibCurveEditorG->set_tooltip_markup(""); + gammaskvib->set_tooltip_text(""); + chromaskvib->set_tooltip_text(""); + slomaskvib->set_tooltip_text(""); + lapmaskvib->set_tooltip_text(""); + saturated->set_tooltip_text(""); + pastels->set_tooltip_text(""); + psThreshold->set_tooltip_text(""); + protectSkins->set_tooltip_text(""); + avoidColorShift->set_tooltip_text(""); + pastSatTog->set_tooltip_text(""); + sensiv->set_tooltip_text(""); + curveEditorGG->set_tooltip_text(""); + } +} + +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::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + strvib->setValue(defSpot.strvib); + angvib->setValue(defSpot.angvib); + showmaskvibMethod->set_active(0); + enavibMask->set_active(defSpot.enavibMask); + CCmaskvibshape->setCurve(defSpot.CCmaskvibcurve); + LLmaskvibshape->setCurve(defSpot.LLmaskvibcurve); + HHmaskvibshape->setCurve(defSpot.HHmaskvibcurve); + blendmaskvib->setValue((double)defSpot.blendmaskvib); + radmaskvib->setValue(defSpot.radmaskvib); + chromaskvib->setValue(defSpot.chromaskvib); + Lmaskvibshape->setCurve(defSpot.Lmaskvibcurve); + + // Enable all listener + enableListener(); +} + +void LocallabVibrance::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + saturated->hide(); + pastels->setLabel(M("TP_LOCALLAB_PASTELS2")); + psThreshold->hide(); + protectSkins->hide(); + avoidColorShift->hide(); + pastSatTog->hide(); + curveEditorGG->hide(); + expgradvib->hide(); + expmaskvib->hide(); + + break; + + case Normal: + // Expert mode 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(); + // Specific Simple mode widgets are shown in Normal mode + expgradvib->show(); + expmaskvib->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + saturated->show(); + pastels->setLabel(M("TP_VIBRANCE_PASTELS")); + psThreshold->show(); + protectSkins->show(); + avoidColorShift->show(); + pastSatTog->show(); + curveEditorGG->show(); + expgradvib->show(); + strvibab->show(); + strvibh->show(); + expmaskvib->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); + Lmaskvibshape->updateLocallabBackground(normLumar); + + 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); + 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, int &logMask, int &maskMask) +{ + softMask = showmasksoftMethod->get_active_row_number(); +} + +void LocallabSoft::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_markup(M("TP_LOCALLAB_SOFTMETHOD_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")); + sensisf->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + + } else { + exp->set_tooltip_text(""); + showmasksoftMethod->set_tooltip_markup(""); + streng->set_tooltip_text(""); + laplace->set_tooltip_text(""); + sensisf->set_tooltip_text(""); + } +} + +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::complexityModeChanged() +{ + if (complexity->get_active_row_number() == Simple) { // New selected mode is Simple one + const bool maskPreviewActivated = isMaskViewActive(); + + // Convert tool widget parameters + convertParamToNormal(); // From Expert mode to Normal mode + convertParamToSimple(); // From Normal mode to Simple mode + // Update GUI based on new mode + updateGUIToMode(Simple); + + if (maskPreviewActivated) { + // This event is called to transmit reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + } + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_SIMPLE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else if (complexity->get_active_row_number() == Normal) { // New selected mode is Normal one + const bool maskPreviewActivated = isMaskViewActive(); + + // Convert tool widget parameters + convertParamToNormal(); + // Update GUI based on new mode + updateGUIToMode(Normal); + + if (maskPreviewActivated) { + // This event is called to transmit reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + } + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_NORMAL") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else if (complexity->get_active_row_number() == Expert) { // New selected mode is Expert one + // Update GUI based on new mode + updateGUIToMode(Expert); + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_EXPERT") + " (" + 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 + showmasksoftMethod->set_active(0); + + // Enable all listeners + enableListener(); +} + +void LocallabSoft::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple 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) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + softMethod->hide(); + ctboxsoftmethod->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + ctboxsoftmethod->hide(); + // Specific Simple mode widgets are shown in Normal mode + softMethod->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + softMethod->show(); + + if (softMethod->get_active_row_number() != 0) { // Keep widget hidden when softMethod is equal to 0 + ctboxsoftmethod->show(); + } + } +} + +void LocallabSoft::softMethodChanged() +{ + const bool maskPreviewActivated = isMaskViewActive(); + + // Update soft light GUI according to softMethod combobox + updateSoftGUI(); + + if (maskPreviewActivated) { + // This event is called to transmit 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 + const int comp = complexity->get_active_row_number(); + + 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 { + if (comp == Expert) { // Keep widget hidden in Simple and Normal mode + 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_SENSI"), 0, 100, 1, 40))), + blurMethod(Gtk::manage(new MyComboBoxText())), + invbl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVBL")))), + 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")))), + quamethod(Gtk::manage(new MyComboBoxText())), + 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_SENSI"), 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")))), + toolblFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK")))), + blendmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.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))), + quaHBox(Gtk::manage(new Gtk::HBox())), + 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)); + invblConn = invbl->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::invblChanged)); + + 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); + + + quamethod->append(M("TP_WAVELET_QUACONSER")); + quamethod->append(M("TP_WAVELET_QUAAGRES")); + quamethodconn = quamethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::quamethodChanged)); + Gtk::Label* const quaLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DENQUA") + ":")); + quaHBox->pack_start(*quaLabel, Gtk::PACK_SHRINK, 4); + quaHBox->pack_start(*quamethod); + + 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->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(*invbl); + 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(*quaHBox); + 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); + 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 LocalcurveEditorwavden; + delete maskblCurveEditorG; + delete mask2blCurveEditorG; + delete mask2blCurveEditorGwav; +} + +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, int &logMask, int &maskMask) +{ + 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")); + strength->set_tooltip_text(M("TP_LOCALLAB_NOISE_TOOLTIP")); + grainFrame->set_tooltip_text(M("TP_LOCALLAB_GRAIN_TOOLTIP")); + sensibn->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + medMethod->set_tooltip_text(M("TP_LOCALLAB_MEDIAN_TOOLTIP")); + itera->set_tooltip_text(M("TP_LOCALLAB_MEDIANITER_TOOLTIP")); + fftwbl->set_tooltip_text(M("TP_LOCALLAB_FFTMASK_TOOLTIP")); + guidbl->set_tooltip_text(M("TP_LOCALLAB_GUIDBL_TOOLTIP")); + strbl->set_tooltip_text(M("TP_LOCALLAB_GUIDSTRBL_TOOLTIP")); + epsbl->set_tooltip_text(M("TP_LOCALLAB_GUIDEPSBL_TOOLTIP")); + blurMethod->set_tooltip_markup(M("TP_LOCALLAB_BLMETHOD_TOOLTIP")); + invbl->set_tooltip_markup(M("TP_LOCALLAB_INVBL_TOOLTIP")); + expdenoise->set_tooltip_markup(M("TP_LOCALLAB_DENOI_TOOLTIP")); + quamethod->set_tooltip_markup(M("TP_LOCALLAB_DENOIQUA_TOOLTIP")); + wavshapeden->setTooltip(M("TP_LOCALLAB_WASDEN_TOOLTIP")); + LocalcurveEditorwavden->setTooltip(M("TP_LOCALLAB_WASDEN_TOOLTIP")); + noiselequal->set_tooltip_text(M("TP_LOCALLAB_DENOIEQUAL_TOOLTIP")); + noiselumdetail->set_tooltip_text(M("TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP")); + noisechrof->set_tooltip_text(M("TP_LOCALLAB_DENOICHROF_TOOLTIP")); + noisechroc->set_tooltip_text(M("TP_LOCALLAB_DENOICHROC_TOOLTIP")); + noisechrodetail->set_tooltip_text(M("TP_LOCALLAB_DENOICHRODET_TOOLTIP")); + detailthr->set_tooltip_text(M("TP_LOCALLAB_DENOITHR_TOOLTIP")); + adjblur->set_tooltip_text(M("TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP")); + bilateral->set_tooltip_text(M("TP_LOCALLAB_DENOIBILAT_TOOLTIP")); + noiselumc->set_tooltip_text(M("TP_LOCALLAB_NOISECHROC_TOOLTIP")); + expmaskbl->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + showmaskblMethodtyp->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKTYP_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")); + blendmaskbl->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_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")); + maskblCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + strumaskbl->set_tooltip_text(M("TP_LOCALLAB_STRUSTRMASK_TOOLTIP")); + toolbl->set_tooltip_text(M("TP_LOCALLAB_TOOLMASK_TOOLTIP")); + toolblFrame->set_tooltip_text(M("TP_LOCALLAB_TOOLCOLFRMASK_TOOLTIP")); + gammaskbl->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskbl->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskbl->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + shadmaskbl->set_tooltip_text(M("TP_LOCALLAB_SHADHMASK_TOOLTIP")); + shadmaskblsha->set_tooltip_text(M("TP_LOCALLAB_SHADMASK_TOOLTIP")); + lapmaskbl->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + csThresholdblur->set_tooltip_text(M("TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP")); + sensiden->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + + } else { + + expblnoise->set_tooltip_markup(""); + radius->set_tooltip_text(""); + strength->set_tooltip_text(""); + grainFrame->set_tooltip_text(""); + sensibn->set_tooltip_text(""); + medMethod->set_tooltip_text(""); + itera->set_tooltip_text(""); + fftwbl->set_tooltip_text(""); + guidbl->set_tooltip_text(""); + strbl->set_tooltip_text(""); + epsbl->set_tooltip_text(""); + blurMethod->set_tooltip_markup(""); + quamethod->set_tooltip_markup(""); + LocalcurveEditorwavden->setTooltip(""); + noiselequal->set_tooltip_text(""); + noiselumdetail->set_tooltip_text(""); + noisechrof->set_tooltip_text(""); + noisechroc->set_tooltip_text(""); + noisechrodetail->set_tooltip_text(""); + detailthr->set_tooltip_text(""); + adjblur->set_tooltip_text(""); + bilateral->set_tooltip_text(""); + sensibn->set_tooltip_text(""); + blurMethod->set_tooltip_markup(""); + expdenoise->set_tooltip_markup(""); + wavshapeden->setTooltip(""); + noiselumc->set_tooltip_text(""); + expmaskbl->set_tooltip_markup(""); + showmaskblMethodtyp->set_tooltip_markup(""); + CCmaskblshape->setTooltip(""); + LLmaskblshape->setTooltip(""); + HHmaskblshape->setTooltip(""); + blendmaskbl->set_tooltip_text(""); + radmaskbl->set_tooltip_text(""); + lapmaskbl->set_tooltip_text(""); + Lmaskblshape->setTooltip(""); + LLmaskblshapewav->setTooltip(""); + maskblCurveEditorG->set_tooltip_markup(""); + strumaskbl->set_tooltip_text(""); + toolbl->set_tooltip_text(""); + toolblFrame->set_tooltip_text(""); + gammaskbl->set_tooltip_text(""); + chromaskbl->set_tooltip_text(""); + slomaskbl->set_tooltip_text(""); + shadmaskbl->set_tooltip_text(""); + shadmaskblsha->set_tooltip_text(""); + csThresholdblur->set_tooltip_text(""); + sensiden->set_tooltip_text(""); + + } +} + +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); + invblConn.block(true); + medMethodConn.block(true); + blurMethodConn.block(true); + chroMethodConn.block(true); + quamethodconn.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); + invblConn.block(false); + medMethodConn.block(false); + blurMethodConn.block(false); + chroMethodConn.block(false); + quamethodconn.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); + invbl->set_active(spot.invbl); + 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.quamethod == "cons") { + quamethod->set_active(0); + } else if (spot.quamethod == "agre") { + quamethod->set_active(1); + } + + 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); + + 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); + } + + 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.invbl = invbl->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 (quamethod->get_active_row_number() == 0) { + spot.quamethod = "cons"; + } else if (quamethod->get_active_row_number() == 1) { + spot.quamethod = "agre"; + } + + 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(); + + 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.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); + shadmaskbl->setValue((double)defSpot.shadmaskbl); + shadmaskblsha->setValue((double)defSpot.shadmaskblsha); + LLmaskblshapewav->setCurve(defSpot.LLmaskblcurvewav); + csThresholdblur->setValue(defSpot.csthresholdblur); + + // Enable all listeners + enableListener(); +} + +void LocallabBlur::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + showmaskblMethod->set_active(0); + + if (defSpot.showmaskblMethodtyp == "blur") { + showmaskblMethodtyp ->set_active(0); + } else if (defSpot.showmaskblMethodtyp == "nois") { + showmaskblMethodtyp->set_active(1); + } else if (defSpot.showmaskblMethodtyp == "all") { + showmaskblMethodtyp->set_active(2); + } + + enablMask->set_active(defSpot.enablMask); + CCmaskblshape->setCurve(defSpot.CCmaskblcurve); + LLmaskblshape->setCurve(defSpot.LLmaskblcurve); + HHmaskblshape->setCurve(defSpot.HHmaskblcurve); + blendmaskbl->setValue((double)defSpot.blendmaskbl); + radmaskbl->setValue(defSpot.radmaskbl); + chromaskbl->setValue(defSpot.chromaskbl); + gammaskbl->setValue(defSpot.gammaskbl); + slomaskbl->setValue(defSpot.slomaskbl); + Lmaskblshape->setCurve(defSpot.Lmasklccurve); + + // Enable all listeners + enableListener(); +} + +void LocallabBlur::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + fftwbl->hide(); + expmaskbl->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + fftwbl->hide(); + strumaskbl->hide(); + toolbl->hide(); + lapmaskbl->hide(); + shadmaskbl->hide(); + shadmaskblsha->hide(); + mask2blCurveEditorGwav->hide(); + csThresholdblur->hide(); + // Specific Simple mode widgets are shown in Normal mode + expmaskbl->show(); + + break; + + case Expert: + + // Show widgets hidden in Normal and Simple mode + if (blMethod->get_active_row_number() == 0) { // Keep widget hidden when blMethod is > 0 + fftwbl->show(); + } + + expmaskbl->show(); + strumaskbl->show(); + toolbl->show(); + lapmaskbl->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); + Lmaskblshape->updateLocallabBackground(normLumar); + + return false; + } + ); +} + +void LocallabBlur::blMethodChanged() +{ + // Update Blur & Noise GUI according to blMethod combobox state + updateBlurGUI(); + const LocallabParams::LocallabSpot defSpot; + + if (invbl->get_active() && blMethod->get_active_row_number() == 2) { + radius->setValue(defSpot.radius); + medMethod->set_active(0); + } else if(invbl->get_active() && blMethod->get_active_row_number() == 0) { + guidbl->setValue(defSpot.guidbl); + medMethod->set_active(0); + } else if(invbl->get_active() && blMethod->get_active_row_number() == 1) { + radius->setValue(defSpot.radius); + guidbl->setValue(defSpot.guidbl); + } + + + 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::invblChanged() +{ + const LocallabParams::LocallabSpot defSpot; + + if (invbl->get_active() && blMethod->get_active_row_number() == 2) { + radius->setValue(defSpot.radius); + medMethod->set_active(0); + } else if(invbl->get_active() && blMethod->get_active_row_number() == 0) { + guidbl->setValue(defSpot.guidbl); + medMethod->set_active(0); + } else if(invbl->get_active() && blMethod->get_active_row_number() == 1) { + radius->setValue(defSpot.radius); + guidbl->setValue(defSpot.guidbl); + } + + + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (invbl->get_active()) { + listener->panelChanged(Evlocallabinvbl, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabinvbl, + 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::quamethodChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabquaMethod, + quamethod->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() +{ + const LocallabParams::LocallabSpot defSpot; + + if (invbl->get_active() && blMethod->get_active_row_number() == 2) { + radius->setValue(defSpot.radius); + medMethod->set_active(0); + } else if(invbl->get_active() && blMethod->get_active_row_number() == 0) { + guidbl->setValue(defSpot.guidbl); + medMethod->set_active(0); + } else if(invbl->get_active() && blMethod->get_active_row_number() == 1) { + radius->setValue(defSpot.radius); + guidbl->setValue(defSpot.guidbl); + } + + + const int mode = complexity->get_active_row_number(); + + if (blMethod->get_active_row_number() == 0) { + if (mode == Expert) { // Keep widget hidden in Normal and Simple mode + 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..c221983c1 --- /dev/null +++ b/rtgui/locallabtools.h @@ -0,0 +1,1372 @@ +/* + * 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-2020 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, + Simple = 2 + }; + + // 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, int &logMask, int &maskMask) {}; + + // 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() {}; // From Expert mode to Normal mode; Only necessary when using mode + virtual void convertParamToSimple() {}; // From Normal mode to Simple mode; 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::Frame* const lumFrame; + Adjuster* const lightness; + Adjuster* const contrast; + Adjuster* const chroma; + Gtk::CheckButton* const curvactiv; + 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 H3CurveEditorG; + FlatCurveEditor* const CHshape; + 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; + Gtk::Frame* const mergecolFrame ; + 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; + Gtk::Frame* const toolcolFrame; + 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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; + MyExpander* const exppde; + Adjuster* const laplacexp; + Adjuster* const linear; + Adjuster* const balanexp; + Adjuster* const gamm; + Gtk::Label* const labelexpmethod; + MyComboBoxText* const exnoiseMethod; +// Gtk::Frame* const fatFrame; + MyExpander* const expfat; + 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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, int &logMask, int &maskMask) 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 complexityModeChanged(); + + void enabledChanged() override; + void convertParamToNormal() override; + void convertParamToSimple() 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; + Gtk::CheckButton* const invbl; + MyComboBoxText* const chroMethod; + Gtk::CheckButton* const activlum; + MyExpander* const expdenoise; + MyComboBoxText* const quamethod; + 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; + Gtk::Frame* const toolblFrame; + 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; + Gtk::HBox* const quaHBox; + ThresholdAdjuster* const csThresholdblur; + + sigc::connection blMethodConn, fftwblConn, invblConn, medMethodConn, blurMethodConn, chroMethodConn, activlumConn, showmaskblMethodConn, showmaskblMethodtypConn, enablMaskConn, toolblConn; + sigc::connection quamethodconn; +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, int &logMask, int &maskMask) 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 convertParamToSimple() 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 invblChanged(); + void medMethodChanged(); + void blurMethodChanged(); + void chroMethodChanged(); + void activlumChanged(); + void showmaskblMethodChanged(); + void showmaskblMethodtypChanged(); + void enablMaskChanged(); + void toolblChanged(); + void quamethodChanged(); + + 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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 + Gtk::Frame* const dehaFrame; + Adjuster* const dehaz; + Adjuster* const depth; + Adjuster* const dehazeSaturation; + 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 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, int &logMask, int &maskMask) 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 convertParamToSimple() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + 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; + Gtk::Frame* const sharFrame; + 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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; + Gtk::Frame* const contFrame; + Adjuster* const sigmalc; + CurveEditorGroup* const LocalcurveEditorwav; + FlatCurveEditor* const wavshape; + ThresholdAdjuster* const csThreshold; + Adjuster* const levelwav; + 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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: + Gtk::Frame* const levFrame; + const std::array multiplier; + Adjuster* const chromacbdl; + Adjuster* const threshold; + 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, int &logMask, int &maskMask) 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 convertParamToSimple() 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: + Adjuster* const repar; + Gtk::CheckButton* const ciecam; + Gtk::ToggleButton* const autocompute; + Gtk::Frame* const logPFrame; + Adjuster* const blackEv; + Adjuster* const whiteEv; + Gtk::CheckButton* const fullimage; + Gtk::Frame* const logFrame; + Gtk::CheckButton* const Autogray; + Adjuster* const sourceGray; + Adjuster* const sourceabs; + MyComboBoxText* const sursour; + Gtk::HBox* const surHBox; + Gtk::Frame* const log1Frame; + Gtk::Frame* const log2Frame; + Adjuster* const targetGray; + Adjuster* const detail; + Adjuster* const catad; + Adjuster* const lightl; + Adjuster* const lightq; + Adjuster* const contl; + Adjuster* const contq; + Adjuster* const colorfl; + Adjuster* const saturl; + MyExpander* const expL; + CurveEditorGroup* const CurveEditorL; + DiagonalCurveEditor* const LshapeL; + Adjuster* const targabs; + MyComboBoxText* const surround; + Gtk::HBox* const surrHBox; + + Adjuster* const baselog; + Adjuster* const sensilog; + Gtk::Frame* const gradlogFrame; + Adjuster* const strlog; + Adjuster* const anglog; + MyExpander* const expmaskL; + MyComboBoxText* const showmaskLMethod; + Gtk::CheckButton* const enaLMask; + CurveEditorGroup* const maskCurveEditorL; + FlatCurveEditor* const CCmaskshapeL; + FlatCurveEditor* const LLmaskshapeL; + FlatCurveEditor* const HHmaskshapeL; + Adjuster* const blendmaskL; + Adjuster* const radmaskL; + Adjuster* const chromaskL; + CurveEditorGroup* const mask2CurveEditorL; + DiagonalCurveEditor* const LmaskshapeL; + + sigc::connection autoconn, ciecamconn, fullimageConn, AutograyConn; + sigc::connection surroundconn, sursourconn; + sigc::connection showmaskLMethodConn, enaLMaskConn; +public: + LocallabLog(); + ~LocallabLog(); + + 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, int &logMask, int &maskMask) override; + + void updateAdviceTooltips(const bool showTooltips) override; + void surroundChanged(); + void sursourChanged(); + 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; + + void updateAutocompute(const float blackev, const float whiteev, const float sourceg, const float sourceab, const float targetg); + +private: + void enabledChanged() override; + void convertParamToNormal() override; + void convertParamToSimple() override; + void updateGUIToMode(const modeType new_type) override; + void complexityModeChanged(); + + void autocomputeToggled(); + void fullimageChanged(); + void AutograyChanged(); + void ciecamChanged(); + void showmaskLMethodChanged(); + void enaLMaskChanged(); + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void updateLogGUI(); + void updateLogGUI2(); +}; + + +/* ==== LocallabMask ==== */ +class LocallabMask: + public Gtk::VBox, + public LocallabTool, + public ThresholdAdjusterListener +{ +private: + Adjuster* const sensimask; + Adjuster* const blendmask; + Adjuster* const blendmaskab; + Adjuster* const softradiusmask; + MyComboBoxText* const showmask_Method; + Gtk::CheckButton* const enamask; + CurveEditorGroup* const mask_CurveEditorG; + FlatCurveEditor* const CCmask_shape; + FlatCurveEditor* const LLmask_shape; + FlatCurveEditor* const HHmask_shape; + Gtk::Frame* const struFrame; + Adjuster* const strumaskmask; + Gtk::CheckButton* const toolmask; + Gtk::Frame* const blurFrame; + Gtk::CheckButton* const fftmask; + Adjuster* const contmask; + Adjuster* const blurmask; + Gtk::Frame* const toolmaskFrame; + Adjuster* const radmask; + Adjuster* const lapmask; + Adjuster* const chromask; + Adjuster* const gammask; + Adjuster* const slopmask; + Adjuster* const shadmask; + CurveEditorGroup* const mask_HCurveEditorG; + FlatCurveEditor* const HHhmask_shape; + CurveEditorGroup* const mask2CurveEditorG; + DiagonalCurveEditor* const Lmask_shape; + CurveEditorGroup* const mask2CurveEditorGwav; + FlatCurveEditor* const LLmask_shapewav; + ThresholdAdjuster* const csThresholdmask; + Gtk::Frame* const gradFramemask; + Adjuster* const str_mask; + Adjuster* const ang_mask; + + sigc::connection showmask_MethodConn, enamaskConn, toolmaskConn, fftmaskConn; + +public: + LocallabMask(); + ~LocallabMask(); + + 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, int &logMask, int &maskMask) 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; + 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 complexityModeChanged(); + + void enabledChanged() override; + void convertParamToNormal() override; + void convertParamToSimple() override; + void updateGUIToMode(const modeType new_type) override; + + void updateMaskBackground(const double normChromar, const double normLumar, const double normHuer) override; + + void showmask_MethodChanged(); + void enamaskChanged(); + void toolmaskChanged(); + void fftmaskChanged(); + + void updateMaskGUI(); +}; + +#endif diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc new file mode 100644 index 000000000..52d5d9ad3 --- /dev/null +++ b/rtgui/locallabtools2.cc @@ -0,0 +1,6612 @@ +/* + * 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-2020 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, 100.0, 0.1, 0.))), + sensitm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))), + 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"), 0.0, 100.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->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, int &logMask, int &maskMask) +{ + tmMask = showmasktmMethod->get_active_row_number(); +} + +void LocallabTone::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_TONEMAP_TOOLTIP")); + equiltm->set_tooltip_text(M("TP_LOCALLAB_EQUILTM_TOOLTIP")); + gamma->set_tooltip_text(M("TP_LOCALLAB_TONEMAPGAM_TOOLTIP")); + estop->set_tooltip_text(M("TP_LOCALLAB_TONEMAPESTOP_TOOLTIP")); + scaltm->set_tooltip_text(M("TP_LOCALLAB_TONEMASCALE_TOOLTIP")); + rewei->set_tooltip_text(M("TP_LOCALLAB_TONEMAPREWEI_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")); + blendmasktm->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmasktm->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + mask2tmCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmasktmshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + masktmCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + gammasktm->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromasktm->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomasktm->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + lapmasktm->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + + } else { + exp->set_tooltip_text(""); + equiltm->set_tooltip_text(""); + gamma->set_tooltip_text(""); + estop->set_tooltip_text(""); + scaltm->set_tooltip_text(""); + rewei->set_tooltip_text(""); + sensitm->set_tooltip_text(""); + expmasktm->set_tooltip_markup(""); + CCmasktmshape->setTooltip(""); + LLmasktmshape->setTooltip(""); + HHmasktmshape->setTooltip(""); + blendmasktm->set_tooltip_text(""); + radmasktm->set_tooltip_text(""); + mask2tmCurveEditorG->set_tooltip_text(""); + Lmasktmshape->setTooltip(""); + mask2tmCurveEditorG->set_tooltip_text(""); + Lmasktmshape->setTooltip(""); + masktmCurveEditorG->set_tooltip_markup(""); + gammasktm->set_tooltip_text(""); + chromasktm->set_tooltip_text(""); + slomasktm->set_tooltip_text(""); + lapmasktm->set_tooltip_text(""); + } +} + +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() && listener) { + const auto spName = " (" + escapeHtmlChars(spotName) + ")"; + + if (a == amount) { + listener->panelChanged(Evlocallabamount, amount->getTextValue() + spName); + } else if (a == stren) { + listener->panelChanged(Evlocallabstren, stren->getTextValue() + spName); + } else if (a == gamma) { + listener->panelChanged(Evlocallabgamma, gamma->getTextValue() + spName); + } else if (a == satur) { + listener->panelChanged(Evlocallabsatur, satur->getTextValue() + spName); + } else if (a == estop) { + listener->panelChanged(Evlocallabestop, estop->getTextValue() + spName); + } else if (a == scaltm) { + listener->panelChanged(Evlocallabscaltm, scaltm->getTextValue() + spName); + } else if (a == rewei) { + listener->panelChanged(Evlocallabrewei, rewei->getTextValue() + spName); + } else if (a == softradiustm) { + listener->panelChanged(Evlocallabsoftradiustm, softradiustm->getTextValue() + spName); + } else if (a == sensitm) { + listener->panelChanged(Evlocallabsensitm, sensitm->getTextValue() + spName); + } else if (a == blendmasktm) { + listener->panelChanged(Evlocallabblendmasktm, blendmasktm->getTextValue() + spName); + } else if (a == lapmasktm) { + listener->panelChanged(Evlocallablapmasktm, lapmasktm->getTextValue() + spName); + } else if (a == radmasktm) { + listener->panelChanged(Evlocallabradmasktm, radmasktm->getTextValue() + spName); + } else if (a == chromasktm) { + listener->panelChanged(Evlocallabchromasktm, chromasktm->getTextValue() + spName); + } else if (a == gammasktm) { + listener->panelChanged(Evlocallabgammasktm, gammasktm->getTextValue() + spName); + } else if (a == slomasktm) { + listener->panelChanged(Evlocallabslomasktm, slomasktm->getTextValue() + spName); + } + } +} + +void LocallabTone::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled() && listener) { + const auto spName = M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"; + + if (ce == CCmasktmshape) { + listener->panelChanged(EvlocallabCCmasktmshape, spName); + } else if (ce == LLmasktmshape) { + listener->panelChanged(EvlocallabLLmasktmshape, spName); + } else if (ce == HHmasktmshape) { + listener->panelChanged(EvlocallabHHmasktmshape, spName); + } else if (ce == Lmasktmshape) { + listener->panelChanged(EvlocallabLmasktmshape, spName); + } + } +} + +void LocallabTone::enabledChanged() +{ + if (isLocActivated && listener) { + listener->panelChanged(EvLocenatonemap, (exp->getEnabled() ? M("GENERAL_ENABLED") : 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::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + showmasktmMethod->set_active(0); + enatmMask->set_active(defSpot.enatmMask); + enatmMaskaft->set_active(defSpot.enatmMaskaft); + CCmasktmshape->setCurve(defSpot.CCmasktmcurve); + LLmasktmshape->setCurve(defSpot.LLmasktmcurve); + HHmasktmshape->setCurve(defSpot.HHmasktmcurve); + blendmasktm->setValue((double)defSpot.blendmasktm); + radmasktm->setValue(defSpot.radmasktm); + chromasktm->setValue(defSpot.chromasktm); + Lmasktmshape->setCurve(defSpot.Lmasktmcurve); + + // Enable all listeners + enableListener(); +} + +void LocallabTone::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + gamma->hide(); + satur->hide(); + rewei->hide(); + expmasktm->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + gamma->hide(); + satur->hide(); + rewei->hide(); + lapmasktm->hide(); + gammasktm->hide(); + slomasktm->hide(); + // Specific Simple mode widgets are shown in Normal mode + expmasktm->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + gamma->show(); + satur->show(); + rewei->show(); + expmasktm->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); + Lmasktmshape->updateLocallabBackground(normLumar); + + 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 + dehaFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_DEHAFRA")))), + 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))), + dehazeSaturation(Gtk::manage(new Adjuster(M("TP_DEHAZE_SATURATION"), 0, 100, 1, 50))), + 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_SENSI"), 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, 100.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"), 0.0, 100.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->setAdjusterListener(this); + + dehazeSaturation->setAdjusterListener(this); + depth->setAdjusterListener(this); + + 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(*dehazeSaturation); + 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, int &logMask, int &maskMask) +{ + retiMask = showmaskretiMethod->get_active_row_number(); +} + +void LocallabRetinex::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + dehaFrame->set_tooltip_text(M("TP_LOCALLAB_DEHAZFRAME_TOOLTIP")); + dehaz->set_tooltip_text(M("TP_LOCALLAB_DEHAZ_TOOLTIP")); + retiFrame->set_tooltip_text(M("TP_LOCALLAB_RETIFRAME_TOOLTIP")); + loglin->set_tooltip_text(M("TP_LOCALLAB_RETI_LOGLIN_TOOLTIP")); + sensih->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + fftwreti->set_tooltip_text(M("TP_LOCALLAB_LC_FFTW_TOOLTIP")); + equilret->set_tooltip_text(M("TP_LOCALLAB_EQUILTM_TOOLTIP")); + neigh->set_tooltip_text(M("TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP")); + vart->set_tooltip_text(M("TP_LOCALLAB_RETI_NEIGH_VART_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")); + darkness->set_tooltip_text(M("TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP")); + lightnessreti->set_tooltip_text(M("TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP")); + cliptm->set_tooltip_text(M("TP_LOCALLAB_RETI_LIMDOFFS_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")); + transLabels2->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")); + blendmaskreti->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmaskreti->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + mask2retiCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmaskretishape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + maskretiCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + gammaskreti->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskreti->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskreti->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + lapmaskreti->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + + } else { + dehaFrame->set_tooltip_text(""); + dehaz->set_tooltip_text(""); + retiFrame->set_tooltip_text(""); + loglin->set_tooltip_text(""); + sensih->set_tooltip_text(""); + fftwreti->set_tooltip_text(""); + equilret->set_tooltip_text(""); + neigh->set_tooltip_text(""); + vart->set_tooltip_text(""); + scalereti->set_tooltip_text(""); + limd->set_tooltip_text(""); + offs->set_tooltip_text(""); + darkness->set_tooltip_text(""); + lightnessreti->set_tooltip_text(""); + cliptm->set_tooltip_text(""); + softradiusret->set_tooltip_text(""); + cTtransshape->setTooltip(""); + mMLabels->set_tooltip_markup(""); + transLabels->set_tooltip_markup(""); + transLabels2->set_tooltip_markup(""); + cTgainshape->setTooltip(""); + expmaskreti->set_tooltip_markup(""); + enaretiMasktmap->set_tooltip_markup(""); + CCmaskretishape->setTooltip(""); + LLmaskretishape->setTooltip(""); + HHmaskretishape->setTooltip(""); + blendmaskreti->set_tooltip_text(""); + radmaskreti->set_tooltip_text(""); + mask2retiCurveEditorG->set_tooltip_text(""); + Lmaskretishape->setTooltip(""); + maskretiCurveEditorG->set_tooltip_markup(""); + gammaskreti->set_tooltip_text(""); + chromaskreti->set_tooltip_text(""); + slomaskreti->set_tooltip_text(""); + lapmaskreti->set_tooltip_text(""); + } +} + +void LocallabRetinex::setDefaultExpanderVisibility() +{ + expretitools->set_expanded(false); + expmaskreti->set_expanded(false); +} + +void LocallabRetinex::disableListener() +{ + LocallabTool::disableListener(); + + 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(); + + 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); + dehazeSaturation->setValue((double)spot.dehazeSaturation); + 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.dehazeSaturation = dehazeSaturation->getIntValue(); + 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); + dehazeSaturation->setDefault((double)defSpot.dehazeSaturation); + 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 == dehazeSaturation) { + if (listener) { + listener->panelChanged(EvlocallabdehazeSaturation, + dehazeSaturation->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); + showmaskretiMethod->set_active(0); + 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::convertParamToSimple() +{ +} + +void LocallabRetinex::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + retiFrame->hide(); + retitoolFrame->hide(); + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + retiFrame->hide(); + retitoolFrame->hide(); + // Specific Simple mode widgets are shown in Normal mode + break; + + case Expert: + // Show widgets hidden in Normal and Simple 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); + Lmaskretishape->updateLocallabBackground(normLumar); + + return false; + } + ); +} + +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() +{ + const bool maskPreviewActivated = isMaskViewActive(); + + // Update Retinex GUI according to inversret button state + updateRetinexGUI2(); + + if (maskPreviewActivated) { + // This event is called to transmit reset mask state + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } + } + + 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(); + showmaskretiMethodConn.block(true); + showmaskretiMethod->set_active(0); + showmaskretiMethodConn.block(false); + } 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_SENSI"), 0, 100, 1, 40))), + inverssha(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVERS")))), + sharFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_SHARFRAME")))), + 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); + 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, int &logMask, int &maskMask) +{ + 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_SENSI_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 + sharcontrast->setValue((double)defSpot.sharcontrast); + sharblur->setValue(defSpot.sharblur); + sharamount->setValue(defSpot.sharamount); + shardamping->setValue((double)defSpot.shardamping); + shariter->setValue((double)defSpot.shariter); + + // Enable all listeners + enableListener(); +} + +void LocallabSharp::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + showmasksharMethod->set_active(0); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: +} + +void LocallabSharp::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + sharcontrast->hide(); + sharblur->hide(); + sharamount->hide(); + shardamping->hide(); + shariter->hide(); + sharFrame->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + sharcontrast->hide(); + sharblur->hide(); + sharamount->hide(); + shardamping->hide(); + shariter->hide(); + // Specific Simple mode widgets are shown in Normal mode + sharFrame->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + sharcontrast->show(); + sharblur->show(); + sharamount->show(); + shardamping->show(); + shariter->show(); + sharFrame->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))), + contFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_CONTWFRA")))), + 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))), + csThreshold(Gtk::manage(new ThresholdAdjuster(M("TP_LOCALLAB_CSTHRESHOLD"), 0, 9, 0, 0, 6, 6, 0, false))), + levelwav(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LEVELWAV"), 1, 9, 1, 4))), + 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_SENSI"), 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, 100.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"), 0.0, 100.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); + + contFrame->set_label_align(0.025, 0.5); + + 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(); + + csThreshold->setAdjusterListener(this); + + levelwav->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->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(*csThreshold); + ToolParamBlock* const coBox = Gtk::manage(new ToolParamBlock()); + coBox->pack_start(*sigmalc); + coBox->pack_start(*LocalcurveEditorwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + // coBox->pack_start(*csThreshold); + contFrame->add(*coBox); + pack_start(*contFrame); + // pack_start(*levelwav); + ToolParamBlock* const resiBox = Gtk::manage(new ToolParamBlock()); + resiBox->pack_start(*residcont); + resiBox->pack_start(*residchro); + Gtk::Frame* const shresFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_SHRESFRA"))); + shresFrame->set_label_align(0.025, 0.5); + 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 contFrame2 = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_CONTFRA"))); + contFrame2->set_label_align(0.025, 0.5); + contFrame2->set_label_widget(*wavcont); + Gtk::VBox* const contlevBox = Gtk::manage(new Gtk::VBox()); + contlevBox->set_spacing(2); + 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 + contFrame2->add(*contlevBox); + blurcontBox2->pack_start(*contFrame2); + Gtk::Frame* const compreFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_COMPREFRA"))); + compreFrame->set_label_align(0.025, 0.5); + compreFrame->set_label_widget(*wavcompre); + Gtk::VBox* const compreBox = Gtk::manage(new Gtk::VBox()); + compreBox->set_spacing(2); + 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); + compFrame->set_label_widget(*wavcomp); + Gtk::VBox* const compBox = Gtk::manage(new Gtk::VBox()); + compBox->set_spacing(2); + 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, int &logMask, int &maskMask) +{ + lcMask = showmasklcMethod->get_active_row_number(); +} + +void LocallabContrast::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + contFrame->set_tooltip_text(M("TP_LOCALLAB_EXPCONTRAST_TOOLTIP")); + LocalcurveEditorwav->set_tooltip_markup(M("TP_LOCALLAB_WAT_LEVELLOCCONTRAST_TOOLTIP")); + csThreshold->set_tooltip_markup(M("TP_LOCALLAB_WAT_THRESHOLDWAV_TOOLTIP")); + levelwav->set_tooltip_markup(M("TP_LOCALLAB_LEVELWAV_TOOLTIP")); + clariFrame->set_tooltip_markup(M("TP_LOCALLAB_CLARI_TOOLTIP")); + clarisoft->set_tooltip_markup(M("TP_LOCALLAB_CLARISOFT_TOOLTIP")); + + wavshape->setTooltip(M("TP_LOCALLAB_WAT_WAVSHAPE_TOOLTIP")); + clarilres->set_tooltip_text(M("TP_LOCALLAB_WAT_CLARIL_TOOLTIP")); + claricres->set_tooltip_text(M("TP_LOCALLAB_WAT_CLARIC_TOOLTIP")); + sigmalc->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + sigmalc2->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + sigmaed->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + sigmabl->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + sigma->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + sigmadc->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + sigmadr->set_tooltip_text(M("TP_LOCALLAB_WAT_SIGMALC_TOOLTIP")); + origlc->set_tooltip_text(M("TP_LOCALLAB_WAT_ORIGLC_TOOLTIP")); + strwav->set_tooltip_text(M("TP_LOCALLAB_WAT_STRWAV_TOOLTIP")); + angwav->set_tooltip_text(M("TP_LOCALLAB_WAT_STRWAV_TOOLTIP")); + strengthw->set_tooltip_text(M("TP_LOCALLAB_WAT_STRENGTHW_TOOLTIP")); + LocalcurveEditorwavedg->set_tooltip_markup(M("TP_LOCALLAB_WAT_LOCCONTRASTEDG_TOOLTIP")); + wavshapeedg->setTooltip(M("TP_LOCALLAB_WAT_LOCCONTRASTEDG_TOOLTIP")); + gradw->set_tooltip_text(M("TP_LOCALLAB_WAT_GRADW_TOOLTIP")); + waveshow->set_tooltip_text(M("TP_LOCALLAB_WAT_WAVESHOW_TOOLTIP")); + LocalcurveEditorwavlev->set_tooltip_markup(M("TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP")); + wavshapelev->setTooltip(M("TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP")); + levelblur->set_tooltip_text(M("TP_LOCALLAB_WAT_WAVLEVELBLUR_TOOLTIP")); + residblur->set_tooltip_text(M("TP_LOCALLAB_WAT_RESIDBLUR_TOOLTIP")); + blurlc->set_tooltip_text(M("TP_LOCALLAB_WAT_BLURLC_TOOLTIP")); + offset->set_tooltip_text(M("TP_LOCALLAB_WAT_CONTOFFSET_TOOLTIP")); + chromalev->set_tooltip_text(M("TP_LOCALLAB_WAT_CONTCHROMALEV_TOOLTIP")); + LocalcurveEditorwavcon->set_tooltip_markup(M("TP_LOCALLAB_WAT_WAVCBDL_TOOLTIP")); + wavshapecon->setTooltip(M("TP_LOCALLAB_WAT_WAVCBDL_TOOLTIP")); + LocalcurveEditorwavcompre->set_tooltip_markup(M("TP_LOCALLAB_WAT_WAVTM_TOOLTIP")); + wavshapecompre->setTooltip(M("TP_LOCALLAB_WAT_WAVTM_TOOLTIP")); + deltad->set_tooltip_text(M("TP_LOCALLAB_WAT_DELTABAL_TOOLTIP")); + LocalcurveEditorwavcomp->set_tooltip_markup(M("TP_LOCALLAB_WAT_WAVDELTABAL_TOOLTIP")); + wavshapecomp->setTooltip(M("TP_LOCALLAB_WAT_WAVDELTABAL_TOOLTIP")); + threswav->set_tooltip_text(M("TP_LOCALLAB_WAT_BALTHRES_TOOLTIP")); + residcomp->set_tooltip_text(M("TP_LOCALLAB_WAT_RESIDCOMP_TOOLTIP")); + + + expresidpyr->set_tooltip_text(M("TP_LOCALLAB_WAT_EXPRESID_TOOLTIP")); + expcontrastpyr->set_tooltip_text(M("TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP")); + wavgradl->set_tooltip_text(M("TP_LOCALLAB_WAVGRAD_TOOLTIP")); + wavedg->set_tooltip_text(M("TP_LOCALLAB_WAVEEDG_TOOLTIP")); + wavblur->set_tooltip_text(M("TP_LOCALLAB_WAVBLUR_TOOLTIP")); + chromablu->set_tooltip_text(M("TP_LOCALLAB_CHROMABLU_TOOLTIP")); + expcontrastpyr2->set_tooltip_text(M("TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP")); + wavcont->set_tooltip_text(M("TP_LOCALLAB_WAVCONTF_TOOLTIP")); + chromalev->set_tooltip_text(M("TP_LOCALLAB_CHROMABLU_TOOLTIP")); + wavcompre->set_tooltip_text(M("TP_LOCALLAB_WAVCOMPRE_TOOLTIP")); + wavcomp->set_tooltip_text(M("TP_LOCALLAB_WAVCOMP_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")); + blendmasklc->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + mask2lcCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmasklcshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + masklcCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + chromasklc->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + sensilc->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + } else { + contFrame->set_tooltip_text(""); + LocalcurveEditorwav->set_tooltip_markup(""); + csThreshold->set_tooltip_markup(""); + expresidpyr->set_tooltip_text(""); + levelwav->set_tooltip_markup(""); + clariFrame->set_tooltip_markup(""); + clarisoft->set_tooltip_markup(""); + expcontrastpyr->set_tooltip_text(""); + wavgradl->set_tooltip_text(""); + wavedg->set_tooltip_text(""); + wavblur->set_tooltip_text(""); + chromablu->set_tooltip_text(""); + expcontrastpyr2->set_tooltip_text(""); + wavcont->set_tooltip_text(""); + chromalev->set_tooltip_text(""); + wavcompre->set_tooltip_text(""); + wavcomp->set_tooltip_text(""); + fftwlc->set_tooltip_text(""); + expmasklc->set_tooltip_markup(""); + CCmasklcshape->setTooltip(""); + LLmasklcshape->setTooltip(""); + HHmasklcshape->setTooltip(""); + blendmasklc->set_tooltip_text(""); + mask2lcCurveEditorG->set_tooltip_text(""); + Lmasklcshape->setTooltip(""); + masklcCurveEditorG->set_tooltip_markup(""); + chromasklc->set_tooltip_text(""); + sensilc->set_tooltip_text(""); + + wavshape->setTooltip(""); + clarilres->set_tooltip_text(""); + claricres->set_tooltip_text(""); + sigmalc->set_tooltip_text(""); + sigmalc2->set_tooltip_text(""); + sigmaed->set_tooltip_text(""); + sigmabl->set_tooltip_text(""); + sigma->set_tooltip_text(""); + sigmadc->set_tooltip_text(""); + sigmadr->set_tooltip_text(""); + origlc->set_tooltip_text(""); + strwav->set_tooltip_text(""); + angwav->set_tooltip_text(""); + strengthw->set_tooltip_text(""); + LocalcurveEditorwavedg->set_tooltip_markup(""); + wavshapeedg->setTooltip(""); + gradw->set_tooltip_text(""); + waveshow->set_tooltip_text(""); + LocalcurveEditorwavlev->set_tooltip_markup(""); + wavshapelev->setTooltip(""); + residblur->set_tooltip_text(""); + blurlc->set_tooltip_text(""); + levelblur->set_tooltip_text(""); + offset->set_tooltip_text(""); + chromalev->set_tooltip_text(""); + LocalcurveEditorwavcon->set_tooltip_markup(""); + wavshapecon->setTooltip(""); + LocalcurveEditorwavcompre->set_tooltip_markup(""); + wavshapecompre->setTooltip(""); + deltad->set_tooltip_text(""); + LocalcurveEditorwavcomp->set_tooltip_markup(""); + wavshapecomp->setTooltip(""); + threswav->set_tooltip_text(""); + residcomp->set_tooltip_text(""); + + } +} + +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); + csThreshold->setValue(spot.csthreshold); + levelwav->setValue((double)spot.levelwav); + 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.csthreshold = csThreshold->getValue(); + spot.levelwav = levelwav->getIntValue(); + 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 + origlc->set_active(defSpot.origlc); + wavgradl->set_active(defSpot.wavgradl); + sigmalc2->setValue(defSpot.sigmalc2); + strwav->setValue(defSpot.strwav); + angwav->setValue(defSpot.angwav); + wavedg->set_active(defSpot.wavedg); + strengthw->setValue(defSpot.strengthw); + sigmaed->setValue(defSpot.sigmaed); + wavshapeedg->setCurve(defSpot.locedgwavcurve); + gradw->setValue(defSpot.gradw); + waveshow->set_active(defSpot.waveshow); + radiusw->setValue(defSpot.radiusw); + detailw->setValue(defSpot.detailw); + + if (defSpot.localedgMethod == "fir") { + localedgMethod->set_active(0); + } else if (defSpot.localedgMethod == "sec") { + localedgMethod->set_active(1); + } else if (defSpot.localedgMethod == "thr") { + localedgMethod->set_active(2); + } + + tloww->setValue(defSpot.tloww); + thigw->setValue(defSpot.thigw); + edgw->setValue(defSpot.edgw); + basew->setValue(defSpot.basew); + + if (defSpot.localneiMethod == "none") { + localneiMethod->set_active(0); + } else if (defSpot.localneiMethod == "low") { + localneiMethod->set_active(1); + } else if (defSpot.localneiMethod == "high") { + localneiMethod->set_active(2); + } + + wavblur->set_active(defSpot.wavblur); + levelblur->setValue(defSpot.levelblur); + sigmabl->setValue(defSpot.sigmabl); + chromablu->setValue(defSpot.chromablu); + wavshapelev->setCurve(defSpot.loclevwavcurve); + residblur->setValue(defSpot.residblur); + blurlc->set_active(defSpot.blurlc); + wavcont->set_active(defSpot.wavcont); + sigma->setValue(defSpot.sigma); + offset->setValue(defSpot.offset); + chromalev->setValue(defSpot.chromalev); + wavshapecon->setCurve(defSpot.locconwavcurve); + wavcompre->set_active(defSpot.wavcompre); + wavshapecompre->setCurve(defSpot.loccomprewavcurve); + sigmadr->setValue(defSpot.sigmadr); + threswav->setValue(defSpot.threswav); + residcomp->setValue(defSpot.residcomp); + wavcomp->set_active(defSpot.wavcomp); + sigmadc->setValue(defSpot.sigmadc); + deltad->setValue(defSpot.deltad); + wavshapecomp->setCurve(defSpot.loccompwavcurve); + fatres->setValue(defSpot.fatres); + fftwlc->set_active(defSpot.fftwlc); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update Local contrast GUI according to fftwlc button state + updateContrastGUI3(); +} + +void LocallabContrast::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + if (defSpot.localcontMethod == "loc") { + localcontMethod->set_active(0); + } else if (defSpot.localcontMethod == "wav") { + localcontMethod->set_active(1); + } + + showmasklcMethod->set_active(0); + enalcMask->set_active(defSpot.enalcMask); + CCmasklcshape->setCurve(defSpot.CCmasklccurve); + LLmasklcshape->setCurve(defSpot.LLmasklccurve); + HHmasklcshape->setCurve(defSpot.HHmasklccurve); + blendmasklc->setValue((double)defSpot.blendmasklc); + radmasklc->setValue(defSpot.radmasklc); + chromasklc->setValue(defSpot.chromasklc); + Lmasklcshape->setCurve(defSpot.Lmasklccurve); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update Local contrast GUI according to localcontMethod combobox value + updateContrastGUI1(); +} + +void LocallabContrast::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + localcontMethod->hide(); + origlc->hide(); + expcontrastpyr->hide(); + expcontrastpyr2->hide(); + fftwlc->hide(); + expmasklc->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + origlc->hide(); + expcontrastpyr->hide(); + expcontrastpyr2->hide(); + fftwlc->hide(); + // Specific Simple mode widgets are shown in Normal mode + localcontMethod->show(); + expmasklc->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + localcontMethod->show(); + origlc->show(); + + if (localcontMethod->get_active_row_number() != 0) { // Keep widgets hidden when localcontMethod is equal to 0 + expcontrastpyr->show(); + expcontrastpyr2->show(); + } + + if (localcontMethod->get_active_row_number() != 1) { // Keep widget hidden when localcontMethod is equal to 1 + fftwlc->show(); + } + + expmasklc->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); + Lmasklcshape->updateLocallabBackground(normLumar); + + 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() +{ + const int mode = complexity->get_active_row_number(); + + // Update Local contrast GUI according to localcontMethod combobox value + if (localcontMethod->get_active_row_number() == 0) { + lcradius->show(); + lcamount->show(); + lcdarkness->show(); + lclightness->show(); + contFrame->hide(); + csThreshold->hide(); + levelwav->hide(); + expresidpyr->hide(); + clariFrame->hide(); + expcontrastpyr->hide(); + expcontrastpyr2->hide(); + + if (mode == Expert) { // Keep widget hidden in Normal and Simple mode + fftwlc->show(); + } + } else if (localcontMethod->get_active_row_number() == 1) { + lcradius->hide(); + lcamount->hide(); + lcdarkness->hide(); + lclightness->hide(); + contFrame->show(); + csThreshold->show(); + levelwav->show(); + expresidpyr->show(); + clariFrame->show(); + + if (mode == Expert) { // Keep widget hidden in Normal and Simple mode + 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 + levFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LEVFRA")))), + 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))), + 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, 100.0, 0.5, 0.))), + sensicb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 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"), 0.0, 100.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); + + 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->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 + ToolParamBlock* const levBox = Gtk::manage(new ToolParamBlock()); + Gtk::HBox* buttonBox = Gtk::manage(new Gtk::HBox(true, 10)); + buttonBox->pack_start(*lumacontrastMinusButton); + buttonBox->pack_start(*lumaneutralButton); + buttonBox->pack_start(*lumacontrastPlusButton); + levBox->pack_start(*buttonBox); + + for (const auto adj : multiplier) { + levBox->pack_start(*adj); + } + + Gtk::HSeparator* const separator = Gtk::manage(new Gtk::HSeparator()); + levBox->pack_start(*separator, Gtk::PACK_SHRINK, 2); + levBox->pack_start(*chromacbdl); + levBox->pack_start(*threshold); + levFrame->add(*levBox); + pack_start(*levFrame); + 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, int &logMask, int &maskMask) +{ + cbMask = showmaskcbMethod->get_active_row_number(); +} + +void LocallabCBDL::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + levFrame->set_tooltip_text(M("TP_LOCALLAB_EXPCBDL_TOOLTIP")); + + for (const auto adj : multiplier) { + adj->set_tooltip_text(M("TP_LOCALLAB_CBDL_ADJ_TOOLTIP")); + } + + chromacbdl->set_tooltip_text(M("TP_LOCALLAB_CHROMACB_TOOLTIP")); + threshold->set_tooltip_text(M("TP_LOCALLAB_CBDL_THRES_TOOLTIP")); + clarityml->set_tooltip_text(M("TP_LOCALLAB_CBDLCLARI_TOOLTIP")); + sensicb->set_tooltip_text(M("TP_LOCALLAB_SENSI_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")); + blendmaskcb->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmaskcb->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + mask2cbCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + Lmaskcbshape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + maskcbCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + gammaskcb->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromaskcb->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slomaskcb->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + lapmaskcb->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + } else { + levFrame->set_tooltip_text(""); + + for (const auto adj : multiplier) { + adj->set_tooltip_text(""); + } + + chromacbdl->set_tooltip_text(""); + threshold->set_tooltip_text(""); + clarityml->set_tooltip_text(""); + sensicb->set_tooltip_text(""); + expmaskcb->set_tooltip_markup(""); + CCmaskcbshape->setTooltip(""); + LLmaskcbshape->setTooltip(""); + HHmaskcbshape->setTooltip(""); + blendmaskcb->set_tooltip_text(""); + radmaskcb->set_tooltip_text(""); + mask2cbCurveEditorG->set_tooltip_text(""); + Lmaskcbshape->setTooltip(""); + maskcbCurveEditorG->set_tooltip_markup(""); + gammaskcb->set_tooltip_text(""); + chromaskcb->set_tooltip_text(""); + slomaskcb->set_tooltip_text(""); + lapmaskcb->set_tooltip_text(""); + } +} + +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); + 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.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); + 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 == 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::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + softradiuscb->setValue(defSpot.softradiuscb); + showmaskcbMethod->set_active(0); + enacbMask->set_active(defSpot.enacbMask); + CCmaskcbshape->setCurve(defSpot.CCmaskcbcurve); + LLmaskcbshape->setCurve(defSpot.LLmaskcbcurve); + HHmaskcbshape->setCurve(defSpot.HHmaskcbcurve); + blendmaskcb->setValue((double)defSpot.blendmaskcb); + radmaskcb->setValue(defSpot.radmaskcb); + chromaskcb->setValue(defSpot.chromaskcb); + gammaskcb->setValue(defSpot.gammaskcb); + slomaskcb->setValue(defSpot.slomaskcb); + Lmaskcbshape->setCurve(defSpot.Lmaskcbcurve); + + // Enable all listers + enableListener(); +} + +void LocallabCBDL::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + softradiuscb->hide(); + expmaskcb->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + lapmaskcb->hide(); + // Specific Simple mode widgets are shown in Normal mode + softradiuscb->show(); + expmaskcb->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + softradiuscb->show(); + expmaskcb->show(); + 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); + Lmaskcbshape->updateLocallabBackground(normLumar); + + 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), + + // Log encoding specific widgets + repar(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), + ciecam(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_CIEC")))), + 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., 32.0, 0.1, 10.0))), + fullimage(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FULLIMAGE")))), + logFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LOGFRA")))), + 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))), + sourceabs(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOURCE_ABS"), 0.01, 16384.0, 0.01, 2000.0))), + sursour(Gtk::manage (new MyComboBoxText ())), + surHBox(Gtk::manage(new Gtk::HBox())), + log1Frame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LOG1FRA")))), + log2Frame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LOG2FRA")))), + 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))), + catad(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CATAD"), -100., 100., 0.5, 0., Gtk::manage(new RTImage("circle-blue-small.png")), Gtk::manage(new RTImage("circle-orange-small.png"))))), + lightl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGLIGHTL"), -100., 100., 0.5, 0.))), + lightq(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGLIGHTQ"), -100., 100., 0.5, 0.))), + contl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGCONTL"), -100., 100., 0.5, 0.))), + contq(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGCONQL"), -100., 100., 0.5, 0.))), + colorfl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGCOLORFL"), -100., 100., 0.5, 0.))), + saturl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SATURV"), -100., 100., 0.5, 0.))), + expL(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_LOGEXP")))), + CurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_LOGCONTQ"))), + LshapeL(static_cast(CurveEditorL->addCurve(CT_Diagonal, "Q(Q)"))), + targabs(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOURCE_ABS"), 0.01, 16384.0, 0.01, 16.0))), + surround(Gtk::manage (new MyComboBoxText ())), + surrHBox(Gtk::manage(new Gtk::HBox())), + baselog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BASELOG"), 1.3, 3., 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_SENSI"), 0, 100, 1, 60))), + gradlogFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRADLOGFRA")))), + 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.))), + expmaskL(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWC")))), + showmaskLMethod(Gtk::manage(new MyComboBoxText())), + enaLMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + maskCurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), + CCmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + blendmaskL(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), + radmaskL(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromaskL(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + mask2CurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + LmaskshapeL(static_cast(mask2CurveEditorL->addCurve(CT_Diagonal, "L(L)"))) + + +{ + // Parameter Log encoding specific widgets + autoconn = autocompute->signal_toggled().connect(sigc::mem_fun(*this, &LocallabLog::autocomputeToggled)); + const LocallabParams::LocallabSpot defSpot; + repar->setAdjusterListener(this); + + blackEv->setLogScale(2, -8); + blackEv->setAdjusterListener(this); + + whiteEv->setLogScale(16, 0); + whiteEv->setAdjusterListener(this); + ciecamconn = ciecam->signal_toggled().connect(sigc::mem_fun(*this, &LocallabLog::ciecamChanged)); + + 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); + + sourceabs->setLogScale(500, 0); + + sourceabs->setAdjusterListener(this); + + targetGray->setAdjusterListener(this); + + detail->setAdjusterListener(this); + + catad->setAdjusterListener(this); + + setExpandAlignProperties(expL, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + saturl->setAdjusterListener(this); + + lightl->setAdjusterListener(this); + + lightq->setAdjusterListener(this); + contl->setAdjusterListener(this); + + contq->setAdjusterListener(this); + colorfl->setAdjusterListener(this); + + CurveEditorL->setCurveListener(this); + + LshapeL->setResetCurve(DiagonalCurveType(defSpot.LcurveL.at(0)), defSpot.LcurveL); + LshapeL->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + LshapeL->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + CurveEditorL->curveListComplete(); + + + targabs->setLogScale(500, 0); + + targabs->setAdjusterListener(this); + + baselog->setAdjusterListener(this); + + sensilog->setAdjusterListener(this); + + strlog->setAdjusterListener(this); + + anglog->setAdjusterListener(this); + + surHBox->set_spacing (2); + surHBox->set_tooltip_markup (M ("TP_LOCALLAB_LOGSURSOUR_TOOLTIP")); + Gtk::Label* surLabel = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_SURROUND") + ":")); + surHBox->pack_start (*surLabel, Gtk::PACK_SHRINK); + sursour->append (M ("TP_COLORAPP_SURROUND_AVER")); + sursour->append (M ("TP_COLORAPP_SURROUND_DIM")); +// sursour->append (M ("TP_COLORAPP_SURROUND_DARK")); + sursour->set_active (0); + surHBox->pack_start (*sursour); + sursourconn = sursour->signal_changed().connect ( sigc::mem_fun (*this, &LocallabLog::sursourChanged) ); + + + +// Gtk::HBox* surrHBox = Gtk::manage (new Gtk::HBox ()); + surrHBox->set_spacing (2); + surrHBox->set_tooltip_markup (M ("TP_COLORAPP_SURROUND_TOOLTIP")); + Gtk::Label* surrLabel = Gtk::manage (new Gtk::Label (M ("TP_COLORAPP_SURROUND") + ":")); + surrHBox->pack_start (*surrLabel, Gtk::PACK_SHRINK); + surround->append (M ("TP_COLORAPP_SURROUND_AVER")); + surround->append (M ("TP_COLORAPP_SURROUND_DIM")); + surround->append (M ("TP_COLORAPP_SURROUND_DARK")); + surround->append (M ("TP_COLORAPP_SURROUND_EXDARK")); + surround->set_active (0); + surrHBox->pack_start (*surround); + surroundconn = surround->signal_changed().connect ( sigc::mem_fun (*this, &LocallabLog::surroundChanged) ); + + setExpandAlignProperties(expmaskL, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + + showmaskLMethod->append(M("TP_LOCALLAB_SHOWMNONE")); + showmaskLMethod->append(M("TP_LOCALLAB_SHOWMODIF")); + showmaskLMethod->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmaskLMethod->append(M("TP_LOCALLAB_SHOWMASK")); + showmaskLMethod->append(M("TP_LOCALLAB_SHOWREF")); + showmaskLMethod->set_active(0); + showmaskLMethod->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmaskLMethodConn = showmaskLMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabLog::showmaskLMethodChanged)); + + + enaLMaskConn = enaLMask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabLog::enaLMaskChanged)); + + maskCurveEditorL->setCurveListener(this); + + CCmaskshapeL->setIdentityValue(0.); + CCmaskshapeL->setResetCurve(FlatCurveType(defSpot.CCmaskcurveL.at(0)), defSpot.CCmaskcurveL); + CCmaskshapeL->setBottomBarColorProvider(this, 1); + + LLmaskshapeL->setIdentityValue(0.); + LLmaskshapeL->setResetCurve(FlatCurveType(defSpot.LLmaskcurveL.at(0)), defSpot.LLmaskcurveL); + LLmaskshapeL->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmaskshapeL->setIdentityValue(0.); + HHmaskshapeL->setResetCurve(FlatCurveType(defSpot.HHmaskcurveL.at(0)), defSpot.HHmaskcurveL); + HHmaskshapeL->setCurveColorProvider(this, 2); + HHmaskshapeL->setBottomBarColorProvider(this, 2); + + maskCurveEditorL->curveListComplete(); + + blendmaskL->setAdjusterListener(this); + radmaskL->setAdjusterListener(this); + chromaskL->setAdjusterListener(this); + + mask2CurveEditorL->setCurveListener(this); + + LmaskshapeL->setResetCurve(DiagonalCurveType(defSpot.LmaskcurveL.at(0)), defSpot.LmaskcurveL); + LmaskshapeL->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + LmaskshapeL->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2CurveEditorL->curveListComplete(); + + // Add Log encoding specific widgets to GUI + pack_start(*repar); + pack_start(*ciecam); + 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); + logFBox->pack_start(*sourceabs); + logFBox->pack_start (*surHBox); +// logFBox->pack_start(*baselog); + logFrame->add(*logFBox); + pack_start(*logFrame); + log1Frame->set_label_align(0.025, 0.5); + ToolParamBlock* const logP1Box = Gtk::manage(new ToolParamBlock()); + logP1Box->pack_start(*detail); + logP1Box->pack_start(*contl); + logP1Box->pack_start(*saturl); + ToolParamBlock* const logP11Box = Gtk::manage(new ToolParamBlock()); + logP11Box->pack_start(*lightl); + logP11Box->pack_start(*lightq); + logP11Box->pack_start(*contq); + logP11Box->pack_start(*colorfl); + expL->add(*logP11Box, false); + logP1Box->pack_start(*expL, false, false); + +// logP1Box->pack_start(*CurveEditorL, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + log1Frame->add(*logP1Box); + pack_start(*log1Frame); + log2Frame->set_label_align(0.025, 0.5); + ToolParamBlock* const logP2Box = Gtk::manage(new ToolParamBlock()); + logP2Box->pack_start(*targetGray); + logP2Box->pack_start(*targabs); + logP2Box->pack_start(*catad); + logP2Box->pack_start (*surrHBox); + ToolParamBlock* const logP3Box = Gtk::manage(new ToolParamBlock()); + logP3Box->pack_start(*showmaskLMethod, Gtk::PACK_SHRINK, 4); + logP3Box->pack_start(*enaLMask, Gtk::PACK_SHRINK, 0); + logP3Box->pack_start(*maskCurveEditorL, Gtk::PACK_SHRINK, 4); + logP3Box->pack_start(*blendmaskL); + logP3Box->pack_start(*radmaskL); + logP3Box->pack_start(*chromaskL); + logP3Box->pack_start(*mask2CurveEditorL, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + expmaskL->add(*logP3Box, false); + + + log2Frame->add(*logP2Box); + pack_start(*log2Frame); + +// pack_start(*baselog); + pack_start(*sensilog); + pack_start(*expmaskL, false, false); + + // 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); +} + +LocallabLog::~LocallabLog() +{ + delete maskCurveEditorL; + delete mask2CurveEditorL; + delete CurveEditorL; + +} + +void LocallabLog::setDefaultExpanderVisibility() +{ + expmaskL->set_expanded(false); + expL->set_expanded(false); + +} + +void LocallabLog::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_LOGENCOD_TOOLTIP")); + repar->set_tooltip_text(M("TP_LOCALLAB_LOGREPART_TOOLTIP")); + logPFrame->set_tooltip_text(M("TP_LOCALLAB_LOGFRAME_TOOLTIP")); + logFrame->set_tooltip_text(M("TP_LOCALLAB_LOGSCENE_TOOLTIP")); + log1Frame->set_tooltip_text(M("TP_LOCALLAB_LOGIMAGE_TOOLTIP")); + log2Frame->set_tooltip_text(M("TP_LOCALLAB_LOGVIEWING_TOOLTIP")); + autocompute->set_tooltip_text(M("TP_LOCALLAB_LOGAUTO_TOOLTIP")); + Autogray->set_tooltip_text(M("TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP")); + // blackEv->set_tooltip_text(M("TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP")); + // whiteEv->set_tooltip_text(M("TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP")); + blackEv->set_tooltip_text(""); + whiteEv->set_tooltip_text(""); + sourceGray->set_tooltip_text(""); + sourceabs->set_tooltip_text(M("TP_COLORAPP_ADAPSCEN_TOOLTIP")); + targabs->set_tooltip_text(M("TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP")); + targetGray->set_tooltip_text(M("TP_COLORAPP_YBOUT_TOOLTIP")); + 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")); + contl->set_tooltip_text(M("TP_LOCALLAB_LOGCONTL_TOOLTIP")); + contq->set_tooltip_text(M("TP_LOCALLAB_LOGCONTQ_TOOLTIP")); + colorfl->set_tooltip_text(M("TP_LOCALLAB_LOGCOLORF_TOOLTIP")); + lightl->set_tooltip_text(M("TP_LOCALLAB_LOGLIGHTL_TOOLTIP")); + lightq->set_tooltip_text(M("TP_LOCALLAB_LOGLIGHTQ_TOOLTIP")); + saturl->set_tooltip_text(M("TP_LOCALLAB_LOGSATURL_TOOLTIP")); + detail->set_tooltip_text(M("TP_LOCALLAB_LOGDETAIL_TOOLTIP")); + catad->set_tooltip_text(M("TP_LOCALLAB_LOGCATAD_TOOLTIP")); + sensilog->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + fullimage->set_tooltip_text(M("TP_LOCALLAB_FULLIMAGELOG_TOOLTIP")); + ciecam->set_tooltip_text(M("TP_LOCALLAB_CIECAMLOG_TOOLTIP")); + expmaskL->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP")); + CCmaskshapeL->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + LLmaskshapeL->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + HHmaskshapeL->setTooltip(M("TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP")); + blendmaskL->set_tooltip_text(M("TP_LOCALLAB_BLENDMASK_TOOLTIP")); + radmaskL->set_tooltip_text(M("TP_LOCALLAB_LAPRAD2_TOOLTIP")); + chromaskL->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); +// mask2CurveEditorL->set_tooltip_text(M("TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP")); + LmaskshapeL->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + + + } else { + exp->set_tooltip_text(""); + repar->set_tooltip_text(""); + logPFrame->set_tooltip_text(""); + logFrame->set_tooltip_text(""); + log1Frame->set_tooltip_text(""); + log2Frame->set_tooltip_text(""); + autocompute->set_tooltip_text(""); + blackEv->set_tooltip_text(""); + whiteEv->set_tooltip_text(""); + sourceGray->set_tooltip_text(""); + sourceabs->set_tooltip_text(""); + targabs->set_tooltip_text(""); + targetGray->set_tooltip_text(""); + baselog->set_tooltip_text(""); + strlog->set_tooltip_text(""); + anglog->set_tooltip_text(""); + detail->set_tooltip_text(""); + Autogray->set_tooltip_text(""); + sensilog->set_tooltip_text(""); + fullimage->set_tooltip_text(""); + ciecam->set_tooltip_text(""); + contl->set_tooltip_text(""); + lightl->set_tooltip_text(""); + lightq->set_tooltip_text(""); + contq->set_tooltip_text(""); + colorfl->set_tooltip_text(""); + saturl->set_tooltip_text(""); + catad->set_tooltip_text(""); + expmaskL->set_tooltip_markup(""); + CCmaskshapeL->setTooltip(""); + LLmaskshapeL->setTooltip(""); + HHmaskshapeL->setTooltip(""); + blendmaskL->set_tooltip_text(""); + radmaskL->set_tooltip_text(""); + chromaskL->set_tooltip_text(""); + mask2CurveEditorL->set_tooltip_text(""); + LmaskshapeL->setTooltip(""); + + } +} + +void LocallabLog::disableListener() +{ + LocallabTool::disableListener(); + + autoconn.block(true); + fullimageConn.block(true); + ciecamconn.block(true); + enaLMaskConn.block(true); + surroundconn.block (true); + sursourconn.block (true); + AutograyConn.block(true); + showmaskLMethodConn.block(true); +} + +void LocallabLog::enableListener() +{ + LocallabTool::enableListener(); + + autoconn.block(false); + fullimageConn.block(false); + ciecamconn.block(false); + enaLMaskConn.block(false); + surroundconn.block (false); + sursourconn.block (false); + AutograyConn.block(false); + showmaskLMethodConn.block(false); +} + +bool LocallabLog::isMaskViewActive() +{ + return ((showmaskLMethod->get_active_row_number() != 0)); +} + +void LocallabLog::resetMaskView() +{ + showmaskLMethodConn.block(true); + + showmaskLMethod->set_active(0); + + showmaskLMethodConn.block(false); +} + +void LocallabLog::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, int &logMask, int &maskMask) +{ + logMask = showmaskLMethod->get_active_row_number(); +} + + +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); + complexity->set_active(spot.complexlog); + + autocompute->set_active(spot.autocompute); + blackEv->setValue(spot.blackEv); + repar->setValue(spot.repar); + + whiteEv->setValue(spot.whiteEv); +/* if(whiteEv->getValue() < 1.5){ + whiteEv->setValue(1.5); + } +*/ + if (spot.sursour == "Average") { + sursour->set_active (0); + } else if (spot.sursour == "Dim") { + sursour->set_active (1); + } + + + if (spot.surround == "Average") { + surround->set_active (0); + } else if (spot.surround == "Dim") { + surround->set_active (1); + } else if (spot.surround == "Dark") { + surround->set_active (2); + } else if (spot.surround == "ExtremelyDark") { + surround->set_active (3); + } + + ciecam->set_active(spot.ciecam); + fullimage->set_active(spot.fullimage); + Autogray->set_active(spot.Autogray); + sourceGray->setValue(spot.sourceGray); + sourceabs->setValue(spot.sourceabs); + catad->setValue(spot.catad); + saturl->setValue(spot.saturl); + lightl->setValue(spot.lightl); + lightq->setValue(spot.lightq); + contl->setValue(spot.contl); + contq->setValue(spot.contq); + colorfl->setValue(spot.colorfl); + LshapeL->setCurve(spot.LcurveL); + targabs->setValue(spot.targabs); + 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); + CCmaskshapeL->setCurve(spot.CCmaskcurveL); + LLmaskshapeL->setCurve(spot.LLmaskcurveL); + HHmaskshapeL->setCurve(spot.HHmaskcurveL); + enaLMask->set_active(spot.enaLMask); + blendmaskL->setValue(spot.blendmaskL); + radmaskL->setValue(spot.radmaskL); + chromaskL->setValue(spot.chromaskL); + LmaskshapeL->setCurve(spot.LmaskcurveL); + + + } + + // Enable all listeners + enableListener(); + + // Update GUI according to complexity mode + updateGUIToMode(static_cast(complexity->get_active_row_number())); + + // Update Log Encoding GUI according to autocompute button state + updateLogGUI(); + updateLogGUI2(); + + // 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.complexlog = complexity->get_active_row_number(); + + spot.autocompute = autocompute->get_active(); + spot.repar = repar->getValue(); + spot.blackEv = blackEv->getValue(); + spot.whiteEv = whiteEv->getValue(); + spot.fullimage = fullimage->get_active(); + spot.ciecam = ciecam->get_active(); + spot.Autogray = Autogray->get_active(); + spot.sourceGray = sourceGray->getValue(); + spot.sourceabs = sourceabs->getValue(); + spot.targabs = targabs->getValue(); + spot.targetGray = targetGray->getValue(); + spot.catad = catad->getValue(); + spot.saturl = saturl->getValue(); + spot.lightl = lightl->getValue(); + spot.lightq = lightq->getValue(); + spot.contl = contl->getValue(); + spot.contq = contq->getValue(); + spot.colorfl = colorfl->getValue(); + spot.LcurveL = LshapeL->getCurve(); + spot.detail = detail->getValue(); + spot.baselog = baselog->getValue(); + spot.sensilog = sensilog->getIntValue(); + spot.strlog = strlog->getValue(); + spot.anglog = anglog->getValue(); + spot.CCmaskcurveL = CCmaskshapeL->getCurve(); + spot.LLmaskcurveL = LLmaskshapeL->getCurve(); + spot.HHmaskcurveL = HHmaskshapeL->getCurve(); + spot.enaLMask = enaLMask->get_active(); + spot.blendmaskL = blendmaskL->getValue(); + spot.radmaskL = radmaskL->getValue(); + spot.chromaskL = chromaskL->getValue(); + spot.LmaskcurveL = LmaskshapeL->getCurve(); + + if (sursour->get_active_row_number() == 0) { + spot.sursour = "Average"; + } else if (sursour->get_active_row_number() == 1) { + spot.sursour = "Dim"; + } + + if (surround->get_active_row_number() == 0) { + spot.surround = "Average"; + } else if (surround->get_active_row_number() == 1) { + spot.surround = "Dim"; + } else if (surround->get_active_row_number() == 2) { + spot.surround = "Dark"; + } else if (surround->get_active_row_number() == 3) { + spot.surround = "ExtremelyDark"; + } + + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabLog::enaLMaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enaLMask->get_active()) { + listener->panelChanged(EvLocallabEnaLMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaLMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + + + +void LocallabLog::updateGUIToMode(const modeType new_type) +{ + + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + ciecam->hide(); + ciecam->set_active(false); + sourceabs->hide(); + targabs->hide(); + saturl->hide(); + contl->hide(); + lightl->hide(); + lightq->hide(); + contq->hide(); + colorfl->hide(); + catad->hide(); + surrHBox->hide(); + expL->hide(); + surHBox->hide(); + expmaskL->hide(); + gradlogFrame->hide(); + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + ciecam->hide(); + ciecam->set_active(true); + + sourceabs->show(); + targabs->show(); + catad->show(); + saturl->show(); + lightl->show(); + lightq->show(); + contl->show(); + contq->show(); + colorfl->show(); + surrHBox->show(); + expL->hide(); + surHBox->hide(); + expmaskL->hide(); + gradlogFrame->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + ciecam->hide(); + ciecam->set_active(true); + sourceabs->show(); + targabs->show(); + catad->show(); + saturl->show(); + lightl->show(); + lightq->show(); + contl->show(); + contq->show(); + colorfl->show(); + surrHBox->show(); + expL->show(); + expmaskL->show(); + gradlogFrame->show(); + surHBox->show(); + + } +} + + + + +void LocallabLog::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + ciecam->set_active(false); + contq->setValue(defSpot.contq); + colorfl->setValue(defSpot.colorfl); + lightl->setValue(defSpot.lightl); + lightq->setValue(defSpot.lightq); + sursour->set_active(0); + strlog->setValue(defSpot.strlog); + anglog->setValue(defSpot.anglog); + enaLMask->set_active(false); + // Enable all listeners + enableListener(); +} + + +void LocallabLog::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + ciecam->set_active(true); + contq->setValue(defSpot.contq); + colorfl->setValue(defSpot.colorfl); + lightl->setValue(defSpot.lightl); + lightq->setValue(defSpot.lightq); + sursour->set_active(0); + enaLMask->set_active(false); + // Enable all listeners + enableListener(); + +} + + + +void LocallabLog::showmaskLMethodChanged() +{ + + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabLog::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == HHmaskshapeL) { + if (listener) { + listener->panelChanged(EvlocallabHHmaskshapeL, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmaskshapeL) { + if (listener) { + listener->panelChanged(EvlocallabLLmaskshapeL, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == CCmaskshapeL) { + if (listener) { + listener->panelChanged(EvlocallabCCmaskshapeL, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LmaskshapeL) { + if (listener) { + listener->panelChanged(EvlocallabLmaskshapeL, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LshapeL) { + if (listener) { + listener->panelChanged(EvlocallabLshapeL, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + } +} + + +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 + repar->setDefault(defSpot.repar); + blackEv->setDefault(defSpot.blackEv); + whiteEv->setDefault(defSpot.whiteEv); + sourceGray->setDefault(defSpot.sourceGray); + sourceabs->setDefault(defSpot.sourceabs); + targabs->setDefault(defSpot.targabs); + targetGray->setDefault(defSpot.targetGray); + catad->setDefault(defSpot.catad); + saturl->setDefault(defSpot.saturl); + lightl->setDefault(defSpot.lightl); + lightq->setDefault(defSpot.lightq); + contl->setDefault(defSpot.contl); + contq->setDefault(defSpot.contq); + colorfl->setDefault(defSpot.colorfl); + detail->setDefault(defSpot.detail); + baselog->setDefault(defSpot.baselog); + sensilog->setDefault((double)defSpot.sensilog); + strlog->setDefault(defSpot.strlog); + anglog->setDefault(defSpot.anglog); + blendmaskL->setDefault(defSpot.blendmaskL); + radmaskL->setDefault(defSpot.radmaskL); + chromaskL->setDefault(defSpot.chromaskL); + + + } + + // 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 == repar) { + if (listener) { + listener->panelChanged(Evlocallabrepar, + repar->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + 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 == sourceabs) { + if (listener) { + listener->panelChanged(Evlocallabsourceabs, + sourceabs->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == targabs) { + if (listener) { + listener->panelChanged(Evlocallabtargabs, + targabs->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == targetGray) { + if (listener) { + listener->panelChanged(EvlocallabtargetGray, + targetGray->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == catad) { + if (listener) { + listener->panelChanged(Evlocallabcatad, + catad->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == saturl) { + if (listener) { + listener->panelChanged(Evlocallabsaturl, + saturl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lightl) { + if (listener) { + listener->panelChanged(Evlocallablightl, + lightl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lightq) { + if (listener) { + listener->panelChanged(Evlocallablightq, + lightq->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + + if (a == contl) { + if (listener) { + listener->panelChanged(Evlocallabcontl, + contl->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == contq) { + if (listener) { + listener->panelChanged(Evlocallabcontq, + contq->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == colorfl) { + if (listener) { + listener->panelChanged(Evlocallabcolorfl, + colorfl->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) + ")"); + } + } + + if (a == blendmaskL) { + if (listener) { + listener->panelChanged(EvLocallabblendmaskL, + blendmaskL->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmaskL) { + if (listener) { + listener->panelChanged(EvLocallabradmaskL, + radmaskL->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromaskL) { + if (listener) { + listener->panelChanged(EvLocallabchromaskL, + chromaskL->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + + } +} + +void LocallabLog::updateAutocompute(const float blackev, const float whiteev, const float sourceg, const float sourceab, const float targetg) +{ + idle_register.add( + [this, blackev, whiteev, sourceg, sourceab, 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); + sourceabs->setValue(sourceab); + 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::sursourChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(Evlocallabsursour, + sursour->get_active_text() + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + + +void LocallabLog::surroundChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + listener->panelChanged(Evlocallabsurround, + surround->get_active_text() + " (" + 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::ciecamChanged() +{ + /* + if(ciecam->get_active()){ + sourceabs->set_sensitive(true); + targabs->set_sensitive(true); + catad->set_sensitive(true); + surrHBox->set_sensitive(true); + + sourceabs->show(); + targabs->show(); + catad->show(); + saturl->show(); + lightl->show(); + contl->show(); + contq->show(); + surrHBox->show(); + } else { + sourceabs->hide(); + targabs->hide(); + saturl->hide(); + contl->hide(); + lightl->hide(); + contq->hide(); + catad->hide(); + surrHBox->hide(); + } +*/ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (ciecam->get_active()) { + listener->panelChanged(Evlocallabciecam, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(Evlocallabciecam, + 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::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 + CCmaskshapeL->updateLocallabBackground(normChromar); + LLmaskshapeL->updateLocallabBackground(normLumar); + HHmaskshapeL->updateLocallabBackground(normHuer); + LmaskshapeL->updateLocallabBackground(normLumar); + + return false; + } + ); +} + + + +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::updateLogGUI2() +{ + /* + if(ciecam->get_active()){ + sourceabs->show(); + targabs->show(); + catad->show(); + saturl->show(); + contl->show(); + lightl->show(); + contq->show(); + surrHBox->show(); + } else { + sourceabs->hide(); + targabs->hide(); + catad->hide(); + saturl->hide(); + lightl->hide(); + contl->hide(); + contq->hide(); + surrHBox->hide(); + } + */ +} + + +void LocallabLog::updateLogGUI() +{ + const int mode = complexity->get_active_row_number(); + + if (autocompute->get_active()) { + blackEv->set_sensitive(false); + whiteEv->set_sensitive(false); + sourceGray->set_sensitive(false); + if (mode == Expert || mode == Normal) { + sourceabs->set_sensitive(false); + } else { + sourceabs->hide(); + } + } else { + blackEv->set_sensitive(true); + whiteEv->set_sensitive(true); + sourceGray->set_sensitive(true); + if (mode == Expert || mode == Normal){ + sourceabs->set_sensitive(true); + } else { + sourceabs->hide(); + } + } +} + + +/* ==== LocallabMask ==== */ +LocallabMask::LocallabMask(): + LocallabTool(this, M("TP_LOCALLAB_MASKCOM_TOOLNAME"), M("TP_LOCALLAB_MASKCOM"), false), + + // Common mask specific widgets + sensimask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))), + blendmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKMASK"), -100., 100., 0.1, -10.))), + blendmaskab(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKMASKAB"), -100., 100., 0.1, -10.))), + softradiusmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 100.0, 0.5, 1.))), + showmask_Method(Gtk::manage(new MyComboBoxText())), + enamask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + mask_CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), + CCmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), + LLmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + HHmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + struFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABSTRUM")))), + strumaskmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUMASKCOL"), 0., 200., 0.1, 0.))), + toolmask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TOOLCOL")))), + blurFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABBLURM")))), + fftmask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FFTCOL_MASK")))), + contmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CONTCOL"), 0., 200., 0.5, 0.))), + blurmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURCOL"), 0.2, 100., 0.5, 0.2))), + toolmaskFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK")))), + radmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), + lapmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), + chromask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), + gammask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), + slopmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), + shadmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHAMASKCOL"), 0, 100, 1, 0))), + mask_HCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKH"))), + HHhmask_shape(static_cast(mask_HCurveEditorG->addCurve(CT_Flat, "H(H)", nullptr, false, true))), + mask2CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), + Lmask_shape(static_cast(mask2CurveEditorG->addCurve(CT_Diagonal, "L(L)"))), + mask2CurveEditorGwav(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVMASK"))), + LLmask_shapewav(static_cast(mask2CurveEditorGwav->addCurve(CT_Flat, "L(L)", nullptr, false, false))), + csThresholdmask(Gtk::manage(new ThresholdAdjuster(M("TP_LOCALLAB_CSTHRESHOLDBLUR"), 0, 9, 0, 0, 6, 5, 0, false))), + gradFramemask(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRADFRA")))), + str_mask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADSTR"), -2., 2., 0.05, 0.))), + ang_mask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GRADANG"), -180., 180., 0.1, 0.))) +{ + const LocallabParams::LocallabSpot defSpot; + + // Parameter Mask common specific widgets + sensimask->setAdjusterListener(this); + + blendmask->setLogScale(10, 0); + blendmask->setAdjusterListener(this); + + blendmaskab->setLogScale(10, 0); + blendmaskab->setAdjusterListener(this); + + softradiusmask->setAdjusterListener(this); + + showmask_Method->append(M("TP_LOCALLAB_SHOWMNONE")); + showmask_Method->append(M("TP_LOCALLAB_SHOWMODIFMASK")); + showmask_Method->append(M("TP_LOCALLAB_SHOWMASK")); + showmask_Method->append(M("TP_LOCALLAB_SHOWREF")); + showmask_Method->set_active(0); + showmask_Method->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKCOL_TOOLTIP")); + showmask_MethodConn = showmask_Method->signal_changed().connect(sigc::mem_fun(*this, &LocallabMask::showmask_MethodChanged)); + + enamaskConn = enamask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabMask::enamaskChanged)); + + mask_CurveEditorG->setCurveListener(this); + + CCmask_shape->setIdentityValue(0.); + CCmask_shape->setResetCurve(FlatCurveType(defSpot.CCmask_curve.at(0)), defSpot.CCmask_curve); + CCmask_shape->setBottomBarColorProvider(this, 1); + + LLmask_shape->setIdentityValue(0.); + LLmask_shape->setResetCurve(FlatCurveType(defSpot.LLmask_curve.at(0)), defSpot.LLmask_curve); + LLmask_shape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + HHmask_shape->setIdentityValue(0.); + HHmask_shape->setResetCurve(FlatCurveType(defSpot.HHmask_curve.at(0)), defSpot.HHmask_curve); + HHmask_shape->setCurveColorProvider(this, 2); + HHmask_shape->setBottomBarColorProvider(this, 2); + + mask_CurveEditorG->curveListComplete(); + + struFrame->set_label_align(0.025, 0.5); + + strumaskmask->setAdjusterListener(this); + + toolmaskConn = toolmask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabMask::toolmaskChanged)); + + blurFrame->set_label_align(0.025, 0.5); + + fftmaskConn = fftmask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabMask::fftmaskChanged)); + + contmask->setAdjusterListener(this); + + blurmask->setAdjusterListener(this); + + toolmaskFrame->set_label_align(0.025, 0.5); + + radmask->setAdjusterListener(this); + + lapmask->setAdjusterListener(this); + + chromask->setAdjusterListener(this); + + gammask->setAdjusterListener(this); + + slopmask->setAdjusterListener(this); + + shadmask->setAdjusterListener(this); + + mask_HCurveEditorG->setCurveListener(this); + + HHhmask_shape->setIdentityValue(0.); + HHhmask_shape->setResetCurve(FlatCurveType(defSpot.HHhmask_curve.at(0)), defSpot.HHhmask_curve); + HHhmask_shape->setCurveColorProvider(this, 2); + HHhmask_shape->setBottomBarColorProvider(this, 2); + + mask_HCurveEditorG->curveListComplete(); + + mask2CurveEditorG->setCurveListener(this); + + Lmask_shape->setResetCurve(DiagonalCurveType(defSpot.Lmask_curve.at(0)), defSpot.Lmask_curve); + Lmask_shape->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + Lmask_shape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2CurveEditorG->curveListComplete(); + + mask2CurveEditorGwav->setCurveListener(this); + + LLmask_shapewav->setIdentityValue(0.); + LLmask_shapewav->setResetCurve(FlatCurveType(defSpot.LLmask_curvewav.at(0)), defSpot.LLmask_curvewav); +// LLmask_shapewav->setBottomBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); + + mask2CurveEditorGwav->curveListComplete(); + + csThresholdmask->setAdjusterListener(this); + + gradFramemask->set_label_align(0.025, 0.5); + + str_mask->setAdjusterListener(this); + + ang_mask->setAdjusterListener(this); + ang_mask->set_tooltip_text(M("TP_LOCALLAB_GRADANG_TOOLTIP")); + + // Add Common mask specific widgets to GUI + pack_start(*sensimask); + pack_start(*blendmask); + pack_start(*blendmaskab); + pack_start(*softradiusmask); + pack_start(*showmask_Method); + pack_start(*enamask); + pack_start(*mask_CurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + ToolParamBlock* const strumBox = Gtk::manage(new ToolParamBlock()); + strumBox->pack_start(*strumaskmask); + strumBox->pack_start(*toolmask); + struFrame->add(*strumBox); + pack_start(*struFrame); + ToolParamBlock* const blurmBox = Gtk::manage(new ToolParamBlock()); + blurmBox->pack_start(*fftmask, Gtk::PACK_SHRINK, 0); + blurmBox->pack_start(*contmask); + blurmBox->pack_start(*blurmask); + blurFrame->add(*blurmBox); + pack_start(*blurFrame); + ToolParamBlock* const toolmaskBox = Gtk::manage(new ToolParamBlock()); + toolmaskBox->pack_start(*radmask, Gtk::PACK_SHRINK, 0); + toolmaskBox->pack_start(*lapmask, Gtk::PACK_SHRINK, 0); + toolmaskBox->pack_start(*chromask, Gtk::PACK_SHRINK, 0); + toolmaskBox->pack_start(*gammask, Gtk::PACK_SHRINK, 0); + toolmaskBox->pack_start(*slopmask, Gtk::PACK_SHRINK, 0); + toolmaskBox->pack_start(*shadmask, Gtk::PACK_SHRINK, 0); + toolmaskBox->pack_start(*mask_HCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolmaskBox->pack_start(*mask2CurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolmaskBox->pack_start(*mask2CurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolmaskBox->pack_start(*csThresholdmask, Gtk::PACK_SHRINK, 0); + ToolParamBlock* const gradmaskBox = Gtk::manage(new ToolParamBlock()); + gradmaskBox->pack_start(*str_mask); + gradmaskBox->pack_start(*ang_mask); + gradFramemask->add(*gradmaskBox); + toolmaskBox->pack_start(*gradFramemask, Gtk::PACK_SHRINK, 0); + toolmaskFrame->add(*toolmaskBox); + pack_start(*toolmaskFrame); +} + +LocallabMask::~LocallabMask() +{ + delete mask_CurveEditorG; + delete mask_HCurveEditorG; + delete mask2CurveEditorG; + delete mask2CurveEditorGwav; +} + +bool LocallabMask::isMaskViewActive() +{ + return ((showmask_Method->get_active_row_number() != 0)); +} + +void LocallabMask::resetMaskView() +{ + showmask_MethodConn.block(true); + showmask_Method->set_active(0); + showmask_MethodConn.block(false); +} + +void LocallabMask::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, int &logMask, int &maskMask) +{ + maskMask = showmask_Method->get_active_row_number(); +} + +void LocallabMask::updateAdviceTooltips(const bool showTooltips) +{ + if (showTooltips) { + exp->set_tooltip_text(M("TP_LOCALLAB_MASKCOM_TOOLTIP")); + sensimask->set_tooltip_text(M("TP_LOCALLAB_SENSIMASK_TOOLTIP")); + blendmask->set_tooltip_text(M("TP_LOCALLAB_BLENDMASKMASK_TOOLTIP")); + blendmaskab->set_tooltip_text(M("TP_LOCALLAB_BLENDMASKMASK_TOOLTIP")); + CCmask_shape->setTooltip(M("TP_LOCALLAB_CURVEEDITORM_CC_TOOLTIP")); + LLmask_shape->setTooltip(M("TP_LOCALLAB_CURVEEDITORM_CC_TOOLTIP")); + HHmask_shape->setTooltip(M("TP_LOCALLAB_CURVEEDITORM_CC_TOOLTIP")); + struFrame->set_tooltip_text(M("TP_LOCALLAB_STRUMASK_TOOLTIP")); + radmask->set_tooltip_text(M("TP_LOCALLAB_LAPRAD_TOOLTIP")); + mask_HCurveEditorG->set_tooltip_text(M("TP_LOCALLAB_HHMASK_TOOLTIP")); + mask2CurveEditorG->set_tooltip_text(M("TP_LOCALLAB_WAVMASK_TOOLTIP")); + Lmask_shape->setTooltip(M("TP_LOCALLAB_LMASK_LL_TOOLTIP")); + mask2CurveEditorGwav->set_tooltip_text(M("TP_LOCALLAB_WAVMASK_TOOLTIP")); + LLmask_shapewav->setTooltip(M("TP_LOCALLAB_LMASK_LEVEL_TOOLTIP")); + mask_CurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); + strumaskmask->set_tooltip_text(M("TP_LOCALLAB_STRUSTRMASK_TOOLTIP")); + blurFrame->set_tooltip_text(M("TP_LOCALLAB_BLURMASK_TOOLTIP")); + toolmask->set_tooltip_text(M("TP_LOCALLAB_TOOLMASK_TOOLTIP")); + toolmaskFrame->set_tooltip_text(M("TP_LOCALLAB_TOOLCOLFRMASK_TOOLTIP")); + fftmask->set_tooltip_text(M("TP_LOCALLAB_FFTMASK_TOOLTIP")); + gammask->set_tooltip_text(M("TP_LOCALLAB_GAMMASK_TOOLTIP")); + chromask->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); + slopmask->set_tooltip_text(M("TP_LOCALLAB_SLOMASK_TOOLTIP")); + shadmask->set_tooltip_text(M("TP_LOCALLAB_SHADMASK_TOOLTIP")); + contmask->set_tooltip_text(M("TP_LOCALLAB_CONTTHMASK_TOOLTIP")); + blurmask->set_tooltip_text(M("TP_LOCALLAB_BLURRMASK_TOOLTIP")); + lapmask->set_tooltip_text(M("TP_LOCALLAB_LAPRAD1_TOOLTIP")); + csThresholdmask->set_tooltip_text(M("TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP")); + } else { + exp->set_tooltip_text(""); + sensimask->set_tooltip_text(""); + blendmask->set_tooltip_text(""); + blendmaskab->set_tooltip_text(""); + CCmask_shape->setTooltip(""); + LLmask_shape->setTooltip(""); + HHmask_shape->setTooltip(""); + struFrame->set_tooltip_text(""); + radmask->set_tooltip_text(""); + mask_HCurveEditorG->set_tooltip_text(""); + mask2CurveEditorG->set_tooltip_text(""); + Lmask_shape->setTooltip(""); + mask2CurveEditorGwav->set_tooltip_text(""); + LLmask_shapewav->setTooltip(""); + mask_CurveEditorG->set_tooltip_markup(""); + strumaskmask->set_tooltip_text(""); + blurFrame->set_tooltip_text(""); + toolmask->set_tooltip_text(""); + toolmaskFrame->set_tooltip_text(""); + fftmask->set_tooltip_text(""); + gammask->set_tooltip_text(""); + chromask->set_tooltip_text(""); + slopmask->set_tooltip_text(""); + shadmask->set_tooltip_text(""); + contmask->set_tooltip_text(""); + blurmask->set_tooltip_text(""); + lapmask->set_tooltip_text(""); + csThresholdmask->set_tooltip_text(""); + } +} + +void LocallabMask::disableListener() +{ + LocallabTool::disableListener(); + + showmask_MethodConn.block(true); + enamaskConn.block(true); + toolmaskConn.block(true); + fftmaskConn.block(true); +} + +void LocallabMask::enableListener() +{ + LocallabTool::enableListener(); + + showmask_MethodConn.block(false); + enamaskConn.block(false); + toolmaskConn.block(false); + fftmaskConn.block(false); +} + +void LocallabMask::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.visimask); + exp->setEnabled(spot.expmask); + complexity->set_active(spot.complexmask); + + sensimask->setValue((double)spot.sensimask); + blendmask->setValue(spot.blendmask); + blendmaskab->setValue(spot.blendmaskab); + softradiusmask->setValue(spot.softradiusmask); + enamask->set_active(spot.enamask); + CCmask_shape->setCurve(spot.CCmask_curve); + LLmask_shape->setCurve(spot.LLmask_curve); + HHmask_shape->setCurve(spot.HHmask_curve); + strumaskmask->setValue(spot.strumaskmask); + toolmask->set_active(spot.toolmask); + fftmask->set_active(spot.fftmask); + contmask->setValue(spot.contmask); + // Update Common mask GUI according to fftmask button state + // Note: Contrary to the others, shall be called before setting blurmask value + updateMaskGUI(); + blurmask->setValue(spot.blurmask); + radmask->setValue(spot.radmask); + lapmask->setValue(spot.lapmask); + chromask->setValue(spot.chromask); + gammask->setValue(spot.gammask); + slopmask->setValue(spot.slopmask); + shadmask->setValue(spot.shadmask); + HHhmask_shape->setCurve(spot.HHhmask_curve); + Lmask_shape->setCurve(spot.Lmask_curve); + LLmask_shapewav->setCurve(spot.LLmask_curvewav); + csThresholdmask->setValue(spot.csthresholdmask); + str_mask->setValue((double)spot.str_mask); + ang_mask->setValue((double)spot.ang_mask); + } + + // 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 LocallabMask::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.expmask = exp->getEnabled(); + spot.visimask = exp->get_visible(); + spot.complexmask = complexity->get_active_row_number(); + + spot.sensimask = sensimask->getIntValue(); + spot.blendmask = blendmask->getValue(); + spot.blendmaskab = blendmaskab->getValue(); + spot.softradiusmask = softradiusmask->getValue(); + spot.enamask = enamask->get_active(); + spot.CCmask_curve = CCmask_shape->getCurve(); + spot.LLmask_curve = LLmask_shape->getCurve(); + spot.HHmask_curve = HHmask_shape->getCurve(); + spot.strumaskmask = strumaskmask->getValue(); + spot.toolmask = toolmask->get_active(); + spot.fftmask = fftmask->get_active(); + spot.contmask = contmask->getValue(); + spot.blurmask = blurmask->getValue(); + spot.radmask = radmask->getValue(); + spot.lapmask = lapmask->getValue(); + spot.chromask = chromask->getValue(); + spot.gammask = gammask->getValue(); + spot.slopmask = slopmask->getValue(); + spot.shadmask = shadmask->getValue(); + spot.HHhmask_curve = HHhmask_shape->getCurve(); + spot.Lmask_curve = Lmask_shape->getCurve(); + spot.LLmask_curvewav = LLmask_shapewav->getCurve(); + spot.csthresholdmask = csThresholdmask->getValue(); + spot.str_mask = str_mask->getIntValue(); + spot.ang_mask = ang_mask->getIntValue(); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabMask::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 + sensimask->setDefault((double)defSpot.sensimask); + blendmask->setDefault(defSpot.blendmask); + blendmaskab->setDefault(defSpot.blendmaskab); + softradiusmask->setDefault(defSpot.softradiusmask); + strumaskmask->setDefault(defSpot.strumaskmask); + contmask->setDefault(defSpot.contmask); + blurmask->setDefault(defSpot.blurmask); + radmask->setDefault(defSpot.radmask); + lapmask->setDefault(defSpot.lapmask); + chromask->setDefault(defSpot.chromask); + gammask->setDefault(defSpot.lapmask); + slopmask->setDefault(defSpot.slopmask); + shadmask->setDefault(defSpot.shadmask); + csThresholdmask->setDefault(defSpot.csthresholdmask); + str_mask->setDefault((double)defSpot.str_mask); + ang_mask->setDefault((double)defSpot.ang_mask); + } + + // Note: No need to manage pedited as batch mode is deactivated for Locallab +} + +void LocallabMask::adjusterChanged(Adjuster* a, double newval) +{ + if (isLocActivated && exp->getEnabled()) { + + if (a == sensimask) { + if (listener) { + listener->panelChanged(Evlocallabsensimask, + sensimask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmask) { + if (listener) { + listener->panelChanged(Evlocallabblendmask, + blendmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blendmaskab) { + if (listener) { + listener->panelChanged(Evlocallabblendmaskab, + blendmaskab->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == softradiusmask) { + if (listener) { + listener->panelChanged(Evlocallabsoftradiusmask, + softradiusmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == strumaskmask) { + if (listener) { + listener->panelChanged(Evlocallabstrumaskmask, + strumaskmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == contmask) { + if (listener) { + listener->panelChanged(Evlocallabcontmask, + contmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == blurmask) { + if (listener) { + listener->panelChanged(Evlocallabblurmask, + blurmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == radmask) { + if (listener) { + listener->panelChanged(Evlocallabradmask, + radmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == lapmask) { + if (listener) { + listener->panelChanged(Evlocallablapmask, + lapmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == chromask) { + if (listener) { + listener->panelChanged(Evlocallabchromask, + chromask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == gammask) { + if (listener) { + listener->panelChanged(Evlocallabgammask, + gammask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == slopmask) { + if (listener) { + listener->panelChanged(Evlocallabslopmask, + slopmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == shadmask) { + if (listener) { + listener->panelChanged(Evlocallabshadmask, + shadmask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == str_mask) { + if (listener) { + listener->panelChanged(Evlocallabstr_mask, + str_mask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (a == ang_mask) { + if (listener) { + listener->panelChanged(Evlocallabang_mask, + ang_mask->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + } +} + +void LocallabMask::adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) +{ + if (isLocActivated && exp->getEnabled()) { + if (a == csThresholdmask) { + if (listener) { + listener->panelChanged(EvlocallabcsThresholdmask, + csThresholdmask->getHistoryString() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabMask::curveChanged(CurveEditor* ce) +{ + if (isLocActivated && exp->getEnabled()) { + if (ce == CCmask_shape) { + if (listener) { + listener->panelChanged(EvlocallabCCmask_shape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmask_shape) { + if (listener) { + listener->panelChanged(EvlocallabLLmask_shape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHmask_shape) { + if (listener) { + listener->panelChanged(EvlocallabHHmask_shape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == HHhmask_shape) { + if (listener) { + listener->panelChanged(EvlocallabHHhmask_shape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == Lmask_shape) { + if (listener) { + listener->panelChanged(EvlocallabLmask_shape, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + if (ce == LLmask_shapewav) { + if (listener) { + listener->panelChanged(EvlocallabLLmask_shapewav, + M("HISTORY_CUSTOMCURVE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + + } +} + +void LocallabMask::complexityModeChanged() +{ + if (complexity->get_active_row_number() == Simple) { // New selected mode is Simple one + // Convert tool widget parameters + convertParamToNormal(); // From Expert mode to Normal mode + convertParamToSimple(); // From Normal mode to Simple mode + // Update GUI based on new mode + updateGUIToMode(Simple); + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_SIMPLE") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else 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); + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_NORMAL") + " (" + escapeHtmlChars(spotName) + ")"); + } + } else if (complexity->get_active_row_number() == Expert) { // New selected mode is Expert one + // Update GUI based on new mode + updateGUIToMode(Expert); + + if (listener && isLocActivated) { + listener->panelChanged(EvlocallabcomplexityWithRefresh, + M("TP_LOCALLAB_MODE_EXPERT") + " (" + escapeHtmlChars(spotName) + ")"); + } + } +} + +void LocallabMask::enabledChanged() +{ + if (isLocActivated) { + if (listener) { + if (exp->getEnabled()) { + listener->panelChanged(EvLocena_mask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocena_mask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabMask::convertParamToNormal() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden GUI widgets in Normal mode to default spot values + softradiusmask->setValue(defSpot.softradiusmask); + strumaskmask->setValue(defSpot.strumaskmask); + toolmask->set_active(defSpot.toolmask); + fftmask->set_active(defSpot.fftmask); + contmask->setValue(defSpot.contmask); + blurmask->setValue(defSpot.blurmask); + lapmask->setValue(defSpot.lapmask); + gammask->setValue(defSpot.gammask); + slopmask->setValue(defSpot.slopmask); + shadmask->setValue(defSpot.shadmask); + HHhmask_shape->setCurve(defSpot.HHhmask_curve); + LLmask_shapewav->setCurve(defSpot.LLmask_curvewav); + csThresholdmask->setValue(defSpot.csthresholdmask); + str_mask->setValue((double)defSpot.str_mask); + ang_mask->setValue((double)defSpot.ang_mask); + + // Enable all listeners + enableListener(); + + // Update GUI based on converted widget parameters: + // - Update Common mask GUI according to fftmask button state + updateMaskGUI(); +} + +void LocallabMask::convertParamToSimple() +{ + const LocallabParams::LocallabSpot defSpot; + + // Disable all listeners + disableListener(); + + // Set hidden specific GUI widgets in Simple mode to default spot values + gammask->setValue(defSpot.gammask); + slopmask->setValue(defSpot.slopmask); + //Lmask_shape->setCurve(defSpot.Lmask_curve); + + // Enable all listeners + enableListener(); +} + +void LocallabMask::updateGUIToMode(const modeType new_type) +{ + switch (new_type) { + case Simple: + // Expert and Normal mode widgets are hidden in Simple mode + softradiusmask->show(); + toolmaskFrame->show(); + struFrame->hide(); + blurFrame->hide(); + gammask->hide(); + slopmask->hide(); + shadmask->hide(); + lapmask->hide(); + mask_HCurveEditorG->hide(); + mask2CurveEditorGwav->hide(); + csThresholdmask->hide(); + gradFramemask->hide(); + + break; + + case Normal: + // Expert mode widgets are hidden in Normal mode + softradiusmask->show(); + struFrame->hide(); + blurFrame->hide(); + lapmask->hide(); + gammask->show(); + slopmask->show(); + shadmask->hide(); + mask_HCurveEditorG->hide(); + mask2CurveEditorGwav->hide(); + csThresholdmask->hide(); + gradFramemask->hide(); + // Specific Simple mode widgets are shown in Normal mode + toolmaskFrame->show(); + + break; + + case Expert: + // Show widgets hidden in Normal and Simple mode + softradiusmask->show(); + struFrame->show(); + blurFrame->show(); + toolmaskFrame->show(); + lapmask->show(); + gammask->show(); + slopmask->show(); + shadmask->show(); + mask_HCurveEditorG->show(); + mask2CurveEditorGwav->show(); + csThresholdmask->show(); + gradFramemask->show(); + } + +} + +void LocallabMask::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 + CCmask_shape->updateLocallabBackground(normChromar); + LLmask_shape->updateLocallabBackground(normLumar); + HHmask_shape->updateLocallabBackground(normHuer); + HHhmask_shape->updateLocallabBackground(normHuer); + Lmask_shape->updateLocallabBackground(normLumar); + + return false; + } + ); +} + +void LocallabMask::showmask_MethodChanged() +{ + // If mask preview is activated, deactivate all other tool mask preview + if (locToolListener) { + locToolListener->resetOtherMaskView(this); + } + + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } +} + +void LocallabMask::enamaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (enamask->get_active()) { + listener->panelChanged(EvLocallabEnaMask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabEnaMask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabMask::toolmaskChanged() +{ + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (toolmask->get_active()) { + listener->panelChanged(EvLocallabtoolmask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabtoolmask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabMask::fftmaskChanged() +{ + // Update Common mask GUI according to fftmask button state + updateMaskGUI(); + + if (isLocActivated && exp->getEnabled()) { + if (listener) { + if (fftmask->get_active()) { + listener->panelChanged(EvLocallabfftmask, + M("GENERAL_ENABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } else { + listener->panelChanged(EvLocallabfftmask, + M("GENERAL_DISABLED") + " (" + escapeHtmlChars(spotName) + ")"); + } + } + } +} + +void LocallabMask::updateMaskGUI() +{ + const double temp = blurmask->getValue(); + + if (fftmask->get_active()) { + blurmask->setLimits(0.2, 1000., 0.5, 0.2); + } else { + blurmask->setLimits(0.2, 100., 0.5, 0.2); + } + + blurmask->setValue(temp); +} diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index c60cba070..feef93564 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -832,7 +832,7 @@ int processLineParams ( int argc, char **argv ) } ii->decreaseRef(); - resultImage->free(); + delete resultImage; } if (imgParams) { diff --git a/rtgui/main.cc b/rtgui/main.cc index f669bcf4a..9f623a6df 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. @@ -458,7 +460,7 @@ int main (int argc, char **argv) SetConsoleCtrlHandler ( NULL, true ); // Set title of console char consoletitle[128]; - sprintf (consoletitle, "RawTherapee %s Console", RTVERSION); + snprintf(consoletitle, sizeof(consoletitle), "RawTherapee %s Console", RTVERSION); SetConsoleTitle (consoletitle); // increase size of screen buffer COORD c; @@ -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/mydiagonalcurve.cc b/rtgui/mydiagonalcurve.cc index ce6c6f3ec..4f9422c69 100644 --- a/rtgui/mydiagonalcurve.cc +++ b/rtgui/mydiagonalcurve.cc @@ -39,7 +39,9 @@ MyDiagonalCurve::MyDiagonalCurve () : ugpX(0.0), ugpY(0.0), activeParam(-1), - bghistvalid(false) + bghistvalid(false), + locallabRef(0.0) + { grab_point = -1; @@ -129,6 +131,36 @@ std::vector MyDiagonalCurve::get_vector (int veclen) return vector; } +void MyDiagonalCurve::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 MyDiagonalCurve::get_LUT (LUTf &lut) { @@ -260,6 +292,20 @@ void MyDiagonalCurve::draw (int handle) 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 diff --git a/rtgui/mydiagonalcurve.h b/rtgui/mydiagonalcurve.h index b2b83c02e..0eb173f70 100644 --- a/rtgui/mydiagonalcurve.h +++ b/rtgui/mydiagonalcurve.h @@ -62,6 +62,7 @@ protected: int activeParam; unsigned int* bghist; // histogram values bool bghistvalid; + double locallabRef; // Locallab reference value to display in the background void draw (int handle); void interpolate (); @@ -91,6 +92,7 @@ public: bool pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) override; void pipetteButton1Released(EditDataProvider *provider) override; void pipetteDrag(EditDataProvider *provider, int modifierKey) override; + void updateLocallabBackground(double ref); void setPos(double pos, int chanIdx) override; void stopNumericalAdjustment() override; 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/navigator.cc b/rtgui/navigator.cc index 619ea0cfd..9397cfc67 100644 --- a/rtgui/navigator.cc +++ b/rtgui/navigator.cc @@ -26,8 +26,50 @@ using namespace rtengine; -Navigator::Navigator () : currentRGBUnit(options.navRGBUnit), currentHSVUnit(options.navHSVUnit) +Navigator::Navigator() : + pointer_moved_delayed_call(50, 100), + currentRGBUnit(options.navRGBUnit), + currentHSVUnit(options.navHSVUnit) { + pointer_moved_delayed_call.setFunction( + [this](bool validPos, Glib::ustring profile, Glib::ustring profileW, int x, int y, int r, int g, int b, bool isRaw) + { + if (!validPos) { + setInvalid (x, y); + } else { + Glib::ustring s1, s2, s3; + + position->set_text (Glib::ustring::compose ("x: %1, y: %2", x, y)); + + getRGBText (r, g, b, s1, s2, s3, isRaw); + R->set_text (s1); + G->set_text (s2); + B->set_text (s3); + if (isRaw) { + H->set_text ("--"); + S->set_text ("--"); + V->set_text ("--"); + LAB_L->set_text ("--"); + LAB_A->set_text ("--"); + LAB_B->set_text ("--"); + } else { + float h, s, v; + float LAB_a, LAB_b, LAB_l; + Color::rgb2hsv01(r / 255.f, g / 255.f, b / 255.f, h, s, v); + getHSVText (h, s, v, s1, s2, s3); + H->set_text (s1); + S->set_text (s2); + V->set_text (s3); + + Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? + getLABText (LAB_l, LAB_a, LAB_b, s1, s2, s3); + LAB_L->set_text (s1); + LAB_A->set_text (s2); + LAB_B->set_text (s3); + } + } + } + ); set_label (M("MAIN_MSG_NAVIGATOR")); Gtk::VBox* mbox = Gtk::manage (new Gtk::VBox ()); @@ -202,6 +244,11 @@ Navigator::Navigator () : currentRGBUnit(options.navRGBUnit), currentHSVUnit(opt show_all (); } +Navigator::~Navigator() +{ + pointer_moved_delayed_call.cancel(); +} + void Navigator::setInvalid (int fullWidth, int fullHeight) { if (fullWidth > 0 && fullHeight > 0) { @@ -278,41 +325,7 @@ void Navigator::getLABText (float l, float a, float b, Glib::ustring &sL, Glib:: // if !validPos then x/y contain the full image size void Navigator::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) { - - if (!validPos) { - setInvalid (x, y); - } else { - Glib::ustring s1, s2, s3; - - position->set_text (Glib::ustring::compose ("x: %1, y: %2", x, y)); - - getRGBText (r, g, b, s1, s2, s3, isRaw); - R->set_text (s1); - G->set_text (s2); - B->set_text (s3); - if (isRaw) { - H->set_text ("--"); - S->set_text ("--"); - V->set_text ("--"); - LAB_L->set_text ("--"); - LAB_A->set_text ("--"); - LAB_B->set_text ("--"); - } else { - float h, s, v; - float LAB_a, LAB_b, LAB_l; - Color::rgb2hsv01(r / 255.f, g / 255.f, b / 255.f, h, s, v); - getHSVText (h, s, v, s1, s2, s3); - H->set_text (s1); - S->set_text (s2); - V->set_text (s3); - - Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? - getLABText (LAB_l, LAB_a, LAB_b, s1, s2, s3); - LAB_L->set_text (s1); - LAB_A->set_text (s2); - LAB_B->set_text (s3); - } - } + pointer_moved_delayed_call(validPos, profile, profileW, x, y, r, g, b, isRaw); } void Navigator::cycleUnitsRGB (GdkEventButton *event) { diff --git a/rtgui/navigator.h b/rtgui/navigator.h index e9d40e309..4c2a3fd32 100644 --- a/rtgui/navigator.h +++ b/rtgui/navigator.h @@ -20,6 +20,7 @@ #include +#include "delayed.h" #include "options.h" #include "pointermotionlistener.h" @@ -33,6 +34,8 @@ class Navigator final : typedef const double (*TMatrix)[3]; private: + DelayedCall pointer_moved_delayed_call; + Options::NavigatorUnit currentRGBUnit; Options::NavigatorUnit currentHSVUnit; void cycleUnitsRGB (GdkEventButton *event); @@ -53,7 +56,8 @@ protected: public: PreviewWindow* previewWindow; - Navigator (); + Navigator(); + ~Navigator() override; // pointermotionlistener interface // void pointerMoved (bool validPos, int x, int y, int r, int g, int b); diff --git a/rtgui/options.cc b/rtgui/options.cc index 7ae6c24aa..ce03db434 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; } @@ -396,6 +400,7 @@ void Options::setDefaults() overwriteOutputFile = false; // if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc. theme = "RawTherapee"; maxThumbnailHeight = 250; + maxThumbnailWidth = 800; maxCacheEntries = 20000; thumbInterp = 1; autoSuffix = true; @@ -442,12 +447,18 @@ void Options::setDefaults() histogramBlue = true; histogramLuma = false; histogramChroma = false; - histogramRAW = false; histogramBar = true; histogramHeight = 200; histogramDrawMode = 0; + histogramScopeType = ScopeType::HISTOGRAM; + histogramShowOptionButtons = false; + histogramTraceBrightness = 1; curvebboxpos = 1; + complexity = 2; + inspectorWindow = false; + zoomOnScroll = true; prevdemo = PD_Sidecar; + rgbDenoiseThreadLimit = 0; #if defined( _OPENMP ) && defined( __x86_64__ ) clutCacheSize = omp_get_num_procs(); @@ -473,6 +484,7 @@ void Options::setDefaults() menuGroupFileOperations = true; menuGroupProfileOperations = true; menuGroupExtProg = true; + showtooltip = true; ICCPC_primariesPreset = "sRGB", ICCPC_redPrimaryX = 0.6400; @@ -590,6 +602,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 +620,13 @@ 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 + +//wavelet + rtSettings.edghi = 3.0;//1.1 and 5. + rtSettings.edglo = 0.5;//0.1 and 0.95 + rtSettings.limrad = 20.;//1 and 60 + rtSettings.protectred = 60; rtSettings.protectredh = 0.3; @@ -638,6 +666,7 @@ void Options::setDefaults() lastRetinexDir = ""; lastDenoiseCurvesDir = ""; lastWaveletCurvesDir = ""; + lastlocalCurvesDir = ""; lastPFCurvesDir = ""; lastHsvCurvesDir = ""; lastToneCurvesDir = ""; @@ -757,6 +786,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 +847,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 +880,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")) { @@ -973,6 +1022,10 @@ void Options::readFromFile(Glib::ustring fname) maxThumbnailHeight = keyFile.get_integer("File Browser", "MaxPreviewHeight"); } + if (keyFile.has_key("File Browser", "MaxPreviewWidth")) { + maxThumbnailWidth = keyFile.get_integer("File Browser", "MaxPreviewWidth"); + } + if (keyFile.has_key("File Browser", "MaxCacheEntries")) { maxCacheEntries = keyFile.get_integer("File Browser", "MaxCacheEntries"); } @@ -1373,19 +1426,34 @@ void Options::readFromFile(Glib::ustring fname) } if (keyFile.has_key("GUI", "HistogramRAW")) { - histogramRAW = keyFile.get_boolean("GUI", "HistogramRAW"); + // Legacy option, replaced by HistogramScopeType. + if (keyFile.get_boolean("GUI", "HistogramRAW")) { + histogramScopeType = ScopeType::HISTOGRAM_RAW; + } } if (keyFile.has_key("GUI", "HistogramBar")) { 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", "HistogramScopeType")) { + histogramScopeType = static_cast(keyFile.get_integer("GUI", "HistogramScopeType")); + } + + if (keyFile.has_key("GUI", "HistogramShowOptionButtons")) { + histogramShowOptionButtons = keyFile.get_boolean("GUI", "HistogramShowOptionButtons"); + } + + if (keyFile.has_key("GUI", "HistogramTraceBrightness")) { + histogramTraceBrightness = keyFile.get_double("GUI", "HistogramTraceBrightness"); } if (keyFile.has_key("GUI", "NavigatorRGBUnit")) { @@ -1396,10 +1464,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 +1488,18 @@ 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_key("GUI", "InspectorWindow")) { + inspectorWindow = keyFile.get_boolean("GUI", "InspectorWindow"); + } + + if (keyFile.has_key("GUI", "ZoomOnScroll")) { + zoomOnScroll = keyFile.get_boolean("GUI", "ZoomOnScroll"); + } } if (keyFile.has_group("Crop Settings")) { @@ -1644,51 +1729,91 @@ 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("Wavelet")) { + if (keyFile.has_key("Wavelet", "Edghi")) { + rtSettings.edghi = keyFile.get_double("Wavelet", "Edghi"); + } + + if (keyFile.has_key("Wavelet", "Edglo")) { + rtSettings.edglo = keyFile.get_double("Wavelet", "Edglo"); + } + + if (keyFile.has_key("Wavelet", "Limrad")) { + rtSettings.limrad = keyFile.get_double("Wavelet", "Limrad"); + } + + } + + 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 +2006,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 +2105,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); @@ -1995,6 +2128,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("File Browser", "ThumbnailSizeQueue", thumbSizeQueue); keyFile.set_integer("File Browser", "SameThumbSize", sameThumbSize); keyFile.set_integer("File Browser", "MaxPreviewHeight", maxThumbnailHeight); + keyFile.set_integer("File Browser", "MaxPreviewWidth", maxThumbnailWidth); keyFile.set_integer("File Browser", "MaxCacheEntries", maxCacheEntries); Glib::ArrayHandle pext = parseExtensions; keyFile.set_string_list("File Browser", "ParseExtensions", pext); @@ -2048,6 +2182,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 +2272,34 @@ 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", "HistogramBar", histogramBar); + keyFile.set_integer("GUI", "HistogramHeight", histogramHeight); + keyFile.set_integer("GUI", "HistogramDrawMode", histogramDrawMode); + keyFile.set_integer("GUI", "HistogramScopeType", rtengine::toUnderlying(histogramScopeType)); + keyFile.set_boolean("GUI", "HistogramShowOptionButtons", histogramShowOptionButtons); + keyFile.set_double("GUI", "HistogramTraceBrightness", histogramTraceBrightness); + 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); + keyFile.set_boolean("GUI", "InspectorWindow", inspectorWindow); + keyFile.set_boolean("GUI", "ZoomOnScroll", zoomOnScroll); //Glib::ArrayHandle crvopen = crvOpen; //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); @@ -2216,6 +2357,13 @@ 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_double("Wavelet", "Edghi", rtSettings.edghi); + keyFile.set_double("Wavelet", "Edglo", rtSettings.edglo); + keyFile.set_double("Wavelet", "Limrad", rtSettings.limrad); + keyFile.set_string("ICC Profile Creator", "PimariesPreset", ICCPC_primariesPreset); keyFile.set_double("ICC Profile Creator", "RedPrimaryX", ICCPC_redPrimaryX); @@ -2286,6 +2434,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 +2474,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 +2495,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 +2521,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 +2538,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..03b551efe 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -168,13 +168,23 @@ private: const Glib::ustring& entryName, Glib::ustring& destination); public: - enum class NavigatorUnit { PERCENT, R0_255, R0_1, _COUNT }; + + enum class ScopeType { + NONE = -1, + HISTOGRAM, + HISTOGRAM_RAW, + PARADE, + VECTORSCOPE_HC, + VECTORSCOPE_HS, + WAVEFORM + }; + bool savesParamsAtExit; SaveFormat saveFormat, saveFormatBatch; Glib::ustring savePathTemplate; @@ -271,6 +281,7 @@ public: CPBKeyType CPBKeys; // Custom Profile Builder's key type int editorToSendTo; int maxThumbnailHeight; + int maxThumbnailWidth; std::size_t maxCacheEntries; int thumbInterp; // 0: nearest, 1: bilinear std::vector parseExtensions; // List containing all extensions type @@ -282,12 +293,15 @@ 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; + bool inspectorWindow; // open inspector in spearate window + bool zoomOnScroll; // translate scroll events to zoom std::vector thumbnailZoomRatios; bool overlayedFileNames; @@ -307,10 +321,13 @@ public: int histogramPosition; // 0=disabled, 1=left pane, 2=right pane bool histogramRed, histogramGreen, histogramBlue; - bool histogramLuma, histogramChroma, histogramRAW; + bool histogramLuma, histogramChroma; bool histogramBar; int histogramHeight; int histogramDrawMode; + ScopeType histogramScopeType; + bool histogramShowOptionButtons; + float histogramTraceBrightness; bool FileBrowserToolbarSingleRow; bool hideTPVScrollbar; int whiteBalanceSpotSize; @@ -409,6 +426,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 35164d2f5..90c25415d 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -60,6 +60,7 @@ void ParamsEdited::set(bool v) retinex.mapcurve = v; retinex.cdHcurve = v; retinex.lhcurve = v; + retinex.complexmethod = v; retinex.retinexMethod = v; retinex.mapMethod = v; retinex.viewMethod = v; @@ -243,6 +244,7 @@ void ParamsEdited::set(bool v) colorappearance.curveMode = v; colorappearance.curveMode2 = v; colorappearance.curveMode3 = v; + colorappearance.complexmethod = v; colorappearance.tempout = v; colorappearance.autotempout = v; colorappearance.greenout = v; @@ -338,14 +340,36 @@ void ParamsEdited::set(bool v) lensProf.lfCameraMake = v; lensProf.lfCameraModel = v; lensProf.lfLens = v; + perspective.method = v; perspective.horizontal = v; perspective.vertical = v; + perspective.camera_crop_factor = v; + perspective.camera_focal_length = v; + perspective.camera_pitch = v; + perspective.camera_roll = v; + perspective.camera_shift_horiz = v; + perspective.camera_shift_vert = v; + perspective.camera_yaw = v; + perspective.projection_pitch = v; + perspective.projection_rotate = v; + perspective.projection_shift_horiz = v; + perspective.projection_shift_vert = v; + perspective.projection_yaw = v; + perspective.control_lines = v; gradient.enabled = v; gradient.degree = v; gradient.feather = 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; @@ -497,6 +521,10 @@ void ParamsEdited::set(bool v) wavelet.bluelow = v; wavelet.lipst = v; wavelet.ballum = v; + wavelet.sigm = v; + wavelet.levden = v; + wavelet.thrden = v; + wavelet.limden = v; wavelet.balchrom = v; wavelet.chromfi = v; wavelet.chromco = v; @@ -504,6 +532,9 @@ void ParamsEdited::set(bool v) wavelet.mergeC = v; wavelet.softrad = v; wavelet.softradend = v; + wavelet.strend = v; + wavelet.detend = v; + wavelet.thrend = v; wavelet.Medgreinf = v; wavelet.ushamethod = v; wavelet.avoid = v; @@ -514,6 +545,11 @@ void ParamsEdited::set(bool v) wavelet.CLmethod = v; wavelet.Backmethod = v; wavelet.Tilesmethod = v; + wavelet.complexmethod = v; + wavelet.denmethod = v; + wavelet.mixmethod = v; + wavelet.slimethod = v; + wavelet.quamethod = v; wavelet.daubcoeffmethod = v; wavelet.CHmethod = v; wavelet.CHSLmethod = v; @@ -524,9 +560,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; @@ -567,14 +603,20 @@ void ParamsEdited::set(bool v) wavelet.level1noise = v; wavelet.level2noise = v; wavelet.level3noise = v; + wavelet.leveldenoise = v; + wavelet.levelsigm = v; wavelet.ccwcurve = v; wavelet.blcurve = v; wavelet.opacityCurveSH = v; wavelet.opacityCurveRG = v; wavelet.opacityCurveBY = v; + wavelet.wavdenoise = v; + wavelet.wavdenoiseh = v; wavelet.opacityCurveW = v; wavelet.opacityCurveWL = v; wavelet.hhcurve = v; + wavelet.wavguidcurve = v; + wavelet.wavhuecurve = v; wavelet.Chcurve = v; wavelet.wavclCurve = v; @@ -632,13 +674,15 @@ void ParamsEdited::set(bool v) dehaze.strength = v; dehaze.showDepthMap = v; dehaze.depth = v; - dehaze.luminance = v; + dehaze.saturation = v; metadata.mode = v; filmNegative.enabled = v; filmNegative.redRatio = v; filmNegative.greenExp = v; filmNegative.blueRatio = v; - filmNegative.baseValues = v; + filmNegative.refInput = v; + filmNegative.refOutput = v; + filmNegative.colorSpace = v; raw.preprocessWB.mode = v; exif = v; @@ -659,6 +703,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; @@ -686,6 +737,7 @@ void ParamsEdited::initFrom(const std::vector& retinex.lhcurve = retinex.lhcurve && p.retinex.lhcurve == other.retinex.lhcurve; retinex.transmissionCurve = retinex.transmissionCurve && p.retinex.transmissionCurve == other.retinex.transmissionCurve; retinex.gaintransmissionCurve = retinex.gaintransmissionCurve && p.retinex.gaintransmissionCurve == other.retinex.gaintransmissionCurve; + retinex.complexmethod = retinex.complexmethod && p.retinex.complexmethod == other.retinex.complexmethod; retinex.retinexMethod = retinex.retinexMethod && p.retinex.retinexMethod == other.retinex.retinexMethod; retinex.mapMethod = retinex.mapMethod && p.retinex.mapMethod == other.retinex.mapMethod; retinex.viewMethod = retinex.viewMethod && p.retinex.viewMethod == other.retinex.viewMethod; @@ -867,6 +919,7 @@ void ParamsEdited::initFrom(const std::vector& colorappearance.curveMode = colorappearance.curveMode && p.colorappearance.curveMode == other.colorappearance.curveMode; colorappearance.curveMode2 = colorappearance.curveMode2 && p.colorappearance.curveMode2 == other.colorappearance.curveMode2; colorappearance.curveMode3 = colorappearance.curveMode3 && p.colorappearance.curveMode3 == other.colorappearance.curveMode3; + colorappearance.complexmethod = colorappearance.complexmethod && p.colorappearance.complexmethod == other.colorappearance.complexmethod; colorappearance.tempout = colorappearance.tempout && p.colorappearance.tempout == other.colorappearance.tempout; colorappearance.autotempout = colorappearance.autotempout && p.colorappearance.autotempout == other.colorappearance.autotempout; colorappearance.greenout = colorappearance.greenout && p.colorappearance.greenout == other.colorappearance.greenout; @@ -967,14 +1020,561 @@ void ParamsEdited::initFrom(const std::vector& lensProf.lfCameraMake = lensProf.lfCameraMake && p.lensProf.lfCameraMake == other.lensProf.lfCameraMake; lensProf.lfCameraModel = lensProf.lfCameraModel && p.lensProf.lfCameraModel == other.lensProf.lfCameraModel; lensProf.lfLens = lensProf.lfLens && p.lensProf.lfLens == other.lensProf.lfLens; + perspective.method = perspective.method && p.perspective.method == other.perspective.method; perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal; perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical; + perspective.camera_crop_factor = perspective.camera_crop_factor && p.perspective.camera_crop_factor == other.perspective.camera_crop_factor; + perspective.camera_focal_length = perspective.camera_focal_length && p.perspective.camera_focal_length == other.perspective.camera_focal_length; + perspective.camera_pitch = perspective.camera_pitch && p.perspective.camera_pitch == other.perspective.camera_pitch; + perspective.camera_roll = perspective.camera_roll && p.perspective.camera_roll == other.perspective.camera_roll; + perspective.camera_shift_horiz = perspective.camera_shift_horiz && p.perspective.camera_shift_horiz == other.perspective.camera_shift_horiz; + perspective.camera_shift_vert = perspective.camera_shift_vert && p.perspective.camera_shift_vert == other.perspective.camera_shift_vert; + perspective.projection_pitch = perspective.projection_pitch && p.perspective.projection_pitch == other.perspective.projection_pitch; + perspective.camera_yaw = perspective.camera_yaw && p.perspective.camera_yaw == other.perspective.camera_yaw; + perspective.projection_rotate = perspective.projection_rotate && p.perspective.projection_rotate == other.perspective.projection_rotate; + perspective.projection_shift_horiz = perspective.projection_shift_horiz && p.perspective.projection_shift_horiz == other.perspective.projection_shift_horiz; + perspective.projection_shift_vert = perspective.projection_shift_vert && p.perspective.projection_shift_vert == other.perspective.projection_shift_vert; + perspective.projection_yaw = perspective.projection_yaw && p.perspective.projection_yaw == other.perspective.projection_yaw; + perspective.control_lines = perspective.control_lines && p.perspective.control_line_values == other.perspective.control_line_values && p.perspective.control_line_types == other.perspective.control_line_types; gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled; gradient.degree = gradient.degree && p.gradient.degree == other.gradient.degree; gradient.feather = gradient.feather && p.gradient.feather == other.gradient.feather; 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).prevMethod = locallab.spots.at(j).prevMethod && pSpot.prevMethod == otherSpot.prevMethod; + 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).hishow = locallab.spots.at(j).hishow && pSpot.hishow == otherSpot.hishow; + locallab.spots.at(j).activ = locallab.spots.at(j).activ && pSpot.activ == otherSpot.activ; + 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).CHcurve = locallab.spots.at(j).CHcurve && pSpot.CHcurve == otherSpot.CHcurve; + 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).quamethod = locallab.spots.at(j).quamethod && pSpot.quamethod == otherSpot.quamethod; + 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).invbl = locallab.spots.at(j).invbl && pSpot.invbl == otherSpot.invbl; + 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).dehazeSaturation = locallab.spots.at(j).dehazeSaturation && pSpot.dehazeSaturation == otherSpot.dehazeSaturation; + 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).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).complexlog = locallab.spots.at(j).complexlog && pSpot.complexlog == otherSpot.complexlog; + 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).sourceabs = locallab.spots.at(j).sourceabs && pSpot.sourceabs == otherSpot.sourceabs; + locallab.spots.at(j).targabs = locallab.spots.at(j).targabs && pSpot.targabs == otherSpot.targabs; + locallab.spots.at(j).targetGray = locallab.spots.at(j).targetGray && pSpot.targetGray == otherSpot.targetGray; + locallab.spots.at(j).catad = locallab.spots.at(j).catad && pSpot.catad == otherSpot.catad; + locallab.spots.at(j).saturl = locallab.spots.at(j).saturl && pSpot.saturl == otherSpot.saturl; + locallab.spots.at(j).lightl = locallab.spots.at(j).lightl && pSpot.lightl == otherSpot.lightl; + locallab.spots.at(j).lightq = locallab.spots.at(j).lightq && pSpot.lightq == otherSpot.lightq; + locallab.spots.at(j).contl = locallab.spots.at(j).contl && pSpot.contl == otherSpot.contl; + locallab.spots.at(j).contq = locallab.spots.at(j).contq && pSpot.contq == otherSpot.contq; + locallab.spots.at(j).colorfl = locallab.spots.at(j).colorfl && pSpot.colorfl == otherSpot.colorfl; + locallab.spots.at(j).LcurveL = locallab.spots.at(j).LcurveL && pSpot.LcurveL == otherSpot.LcurveL; + 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).ciecam = locallab.spots.at(j).ciecam && pSpot.ciecam == otherSpot.ciecam; + locallab.spots.at(j).enaLMask = locallab.spots.at(j).enaLMask && pSpot.enaLMask == otherSpot.enaLMask; + locallab.spots.at(j).repar = locallab.spots.at(j).repar && pSpot.repar == otherSpot.repar; + 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).sursour = locallab.spots.at(j).sursour && pSpot.sursour == otherSpot.sursour; + locallab.spots.at(j).surround = locallab.spots.at(j).surround && pSpot.surround == otherSpot.surround; + 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; + locallab.spots.at(j).CCmaskcurveL = locallab.spots.at(j).CCmaskcurveL && pSpot.CCmaskcurveL == otherSpot.CCmaskcurveL; + locallab.spots.at(j).LLmaskcurveL = locallab.spots.at(j).LLmaskcurveL && pSpot.LLmaskcurveL == otherSpot.LLmaskcurveL; + locallab.spots.at(j).HHmaskcurveL = locallab.spots.at(j).HHmaskcurveL && pSpot.HHmaskcurveL == otherSpot.HHmaskcurveL; + locallab.spots.at(j).blendmaskL = locallab.spots.at(j).blendmaskL && pSpot.blendmaskL == otherSpot.blendmaskL; + locallab.spots.at(j).radmaskL = locallab.spots.at(j).radmaskL && pSpot.radmaskL == otherSpot.radmaskL; + locallab.spots.at(j).chromaskL = locallab.spots.at(j).chromaskL && pSpot.chromaskL == otherSpot.chromaskL; + locallab.spots.at(j).LmaskcurveL = locallab.spots.at(j).LmaskcurveL && pSpot.LmaskcurveL == otherSpot.LmaskcurveL; + + + //mask + locallab.spots.at(j).visimask = locallab.spots.at(j).visimask && pSpot.visimask == otherSpot.visimask; + locallab.spots.at(j).complexmask = locallab.spots.at(j).complexmask && pSpot.complexmask == otherSpot.complexmask; + locallab.spots.at(j).expmask = locallab.spots.at(j).expmask && pSpot.expmask == otherSpot.expmask; + locallab.spots.at(j).sensimask = locallab.spots.at(j).sensimask && pSpot.sensimask == otherSpot.sensimask; + locallab.spots.at(j).blendmask = locallab.spots.at(j).blendmask && pSpot.blendmask == otherSpot.blendmask; + locallab.spots.at(j).blendmaskab = locallab.spots.at(j).blendmaskab && pSpot.blendmaskab == otherSpot.blendmaskab; + locallab.spots.at(j).softradiusmask = locallab.spots.at(j).softradiusmask && pSpot.softradiusmask == otherSpot.softradiusmask; + locallab.spots.at(j).enamask = locallab.spots.at(j).enamask && pSpot.enamask == otherSpot.enamask; + locallab.spots.at(j).fftmask = locallab.spots.at(j).fftmask && pSpot.fftmask == otherSpot.fftmask; + locallab.spots.at(j).blurmask = locallab.spots.at(j).blurmask && pSpot.blurmask == otherSpot.blurmask; + locallab.spots.at(j).contmask = locallab.spots.at(j).contmask && pSpot.contmask == otherSpot.contmask; + locallab.spots.at(j).CCmask_curve = locallab.spots.at(j).CCmask_curve && pSpot.CCmask_curve == otherSpot.CCmask_curve; + locallab.spots.at(j).LLmask_curve = locallab.spots.at(j).LLmask_curve && pSpot.LLmask_curve == otherSpot.LLmask_curve; + locallab.spots.at(j).HHmask_curve = locallab.spots.at(j).HHmask_curve && pSpot.HHmask_curve == otherSpot.HHmask_curve; + locallab.spots.at(j).strumaskmask = locallab.spots.at(j).strumaskmask && pSpot.strumaskmask == otherSpot.strumaskmask; + locallab.spots.at(j).toolmask = locallab.spots.at(j).toolmask && pSpot.toolmask == otherSpot.toolmask; + locallab.spots.at(j).radmask = locallab.spots.at(j).radmask && pSpot.radmask == otherSpot.radmask; + locallab.spots.at(j).lapmask = locallab.spots.at(j).lapmask && pSpot.lapmask == otherSpot.lapmask; + locallab.spots.at(j).chromask = locallab.spots.at(j).chromask && pSpot.chromask == otherSpot.chromask; + locallab.spots.at(j).gammask = locallab.spots.at(j).gammask && pSpot.gammask == otherSpot.gammask; + locallab.spots.at(j).slopmask = locallab.spots.at(j).slopmask && pSpot.slopmask == otherSpot.slopmask; + locallab.spots.at(j).shadmask = locallab.spots.at(j).shadmask && pSpot.shadmask == otherSpot.shadmask; + locallab.spots.at(j).str_mask = locallab.spots.at(j).str_mask && pSpot.str_mask == otherSpot.str_mask; + locallab.spots.at(j).ang_mask = locallab.spots.at(j).ang_mask && pSpot.ang_mask == otherSpot.ang_mask; + locallab.spots.at(j).HHhmask_curve = locallab.spots.at(j).HHhmask_curve && pSpot.HHhmask_curve == otherSpot.HHhmask_curve; + locallab.spots.at(j).Lmask_curve = locallab.spots.at(j).Lmask_curve && pSpot.Lmask_curve == otherSpot.Lmask_curve; + locallab.spots.at(j).LLmask_curvewav = locallab.spots.at(j).LLmask_curvewav && pSpot.LLmask_curvewav == otherSpot.LLmask_curvewav; + locallab.spots.at(j).csthresholdmask = locallab.spots.at(j).csthresholdmask && pSpot.csthresholdmask == otherSpot.csthresholdmask; + } + } + + 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; @@ -1123,6 +1723,10 @@ void ParamsEdited::initFrom(const std::vector& wavelet.lipst = wavelet.lipst && p.wavelet.lipst == other.wavelet.lipst; wavelet.bluehigh = wavelet.bluehigh && p.wavelet.bluehigh == other.wavelet.bluehigh; wavelet.ballum = wavelet.ballum && p.wavelet.ballum == other.wavelet.ballum; + wavelet.sigm = wavelet.sigm && p.wavelet.sigm == other.wavelet.sigm; + wavelet.levden = wavelet.levden && p.wavelet.levden == other.wavelet.levden; + wavelet.thrden = wavelet.thrden && p.wavelet.thrden == other.wavelet.thrden; + wavelet.limden = wavelet.limden && p.wavelet.limden == other.wavelet.limden; wavelet.balchrom = wavelet.balchrom && p.wavelet.balchrom == other.wavelet.balchrom; wavelet.chromfi = wavelet.chromfi && p.wavelet.chromfi == other.wavelet.chromfi; wavelet.chromco = wavelet.chromco && p.wavelet.chromco == other.wavelet.chromco; @@ -1130,6 +1734,9 @@ void ParamsEdited::initFrom(const std::vector& wavelet.mergeC = wavelet.mergeC && p.wavelet.mergeC == other.wavelet.mergeC; wavelet.softrad = wavelet.softrad && p.wavelet.softrad == other.wavelet.softrad; wavelet.softradend = wavelet.softradend && p.wavelet.softradend == other.wavelet.softradend; + wavelet.strend = wavelet.strend && p.wavelet.strend == other.wavelet.strend; + wavelet.detend = wavelet.detend && p.wavelet.detend == other.wavelet.detend; + wavelet.thrend = wavelet.thrend && p.wavelet.thrend == other.wavelet.thrend; wavelet.ushamethod = wavelet.ushamethod && p.wavelet.ushamethod == other.wavelet.ushamethod; wavelet.avoid = wavelet.avoid && p.wavelet.avoid == other.wavelet.avoid; wavelet.showmask = wavelet.showmask && p.wavelet.showmask == other.wavelet.showmask; @@ -1139,6 +1746,11 @@ void ParamsEdited::initFrom(const std::vector& wavelet.CLmethod = wavelet.CLmethod && p.wavelet.CLmethod == other.wavelet.CLmethod; wavelet.Backmethod = wavelet.Backmethod && p.wavelet.Backmethod == other.wavelet.Backmethod; wavelet.Tilesmethod = wavelet.Tilesmethod && p.wavelet.Tilesmethod == other.wavelet.Tilesmethod; + wavelet.complexmethod = wavelet.complexmethod && p.wavelet.complexmethod == other.wavelet.complexmethod; + wavelet.denmethod = wavelet.denmethod && p.wavelet.denmethod == other.wavelet.denmethod; + wavelet.mixmethod = wavelet.mixmethod && p.wavelet.mixmethod == other.wavelet.mixmethod; + wavelet.slimethod = wavelet.slimethod && p.wavelet.slimethod == other.wavelet.slimethod; + wavelet.quamethod = wavelet.quamethod && p.wavelet.quamethod == other.wavelet.quamethod; wavelet.daubcoeffmethod = wavelet.daubcoeffmethod && p.wavelet.daubcoeffmethod == other.wavelet.daubcoeffmethod; wavelet.CHmethod = wavelet.CHmethod && p.wavelet.CHmethod == other.wavelet.CHmethod; wavelet.CHSLmethod = wavelet.CHSLmethod && p.wavelet.CHSLmethod == other.wavelet.CHSLmethod; @@ -1191,6 +1803,8 @@ void ParamsEdited::initFrom(const std::vector& wavelet.level1noise = wavelet.level1noise && p.wavelet.level1noise == other.wavelet.level1noise; wavelet.level2noise = wavelet.level2noise && p.wavelet.level2noise == other.wavelet.level2noise; wavelet.level3noise = wavelet.level3noise && p.wavelet.level3noise == other.wavelet.level3noise; + wavelet.leveldenoise = wavelet.leveldenoise && p.wavelet.leveldenoise == other.wavelet.leveldenoise; + wavelet.levelsigm = wavelet.levelsigm && p.wavelet.levelsigm == other.wavelet.levelsigm; wavelet.pastlev = wavelet.pastlev && p.wavelet.pastlev == other.wavelet.pastlev; wavelet.satlev = wavelet.satlev && p.wavelet.satlev == other.wavelet.satlev; wavelet.ccwcurve = wavelet.ccwcurve && p.wavelet.ccwcurve == other.wavelet.ccwcurve; @@ -1198,10 +1812,14 @@ void ParamsEdited::initFrom(const std::vector& 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.wavdenoise = wavelet.wavdenoise && p.wavelet.wavdenoise == other.wavelet.wavdenoise; + wavelet.wavdenoiseh = wavelet.wavdenoiseh && p.wavelet.wavdenoiseh == other.wavelet.wavdenoiseh; wavelet.opacityCurveW = wavelet.opacityCurveW && p.wavelet.opacityCurveW == other.wavelet.opacityCurveW; wavelet.opacityCurveWL = wavelet.opacityCurveWL && p.wavelet.opacityCurveWL == other.wavelet.opacityCurveWL; wavelet.wavclCurve = wavelet.wavclCurve && p.wavelet.wavclCurve == other.wavelet.wavclCurve; wavelet.hhcurve = wavelet.hhcurve && p.wavelet.hhcurve == other.wavelet.hhcurve; + wavelet.wavguidcurve = wavelet.wavguidcurve && p.wavelet.wavguidcurve == other.wavelet.wavguidcurve; + wavelet.wavhuecurve = wavelet.wavhuecurve && p.wavelet.wavhuecurve == other.wavelet.wavhuecurve; wavelet.Chcurve = wavelet.Chcurve && p.wavelet.Chcurve == other.wavelet.Chcurve; wavelet.skinprotect = wavelet.skinprotect && p.wavelet.skinprotect == other.wavelet.skinprotect; // wavelet.enacont = wavelet.enacont && p.wavelet.enacont == other.wavelet.enacont; @@ -1249,15 +1867,15 @@ void ParamsEdited::initFrom(const std::vector& dehaze.strength = dehaze.strength && p.dehaze.strength == other.dehaze.strength; dehaze.showDepthMap = dehaze.showDepthMap && p.dehaze.showDepthMap == other.dehaze.showDepthMap; dehaze.depth = dehaze.depth && p.dehaze.depth == other.dehaze.depth; - dehaze.luminance = dehaze.luminance && p.dehaze.luminance == other.dehaze.luminance; + dehaze.saturation = dehaze.saturation && p.dehaze.saturation == other.dehaze.saturation; metadata.mode = metadata.mode && p.metadata.mode == other.metadata.mode; filmNegative.enabled = filmNegative.enabled && p.filmNegative.enabled == other.filmNegative.enabled; filmNegative.redRatio = filmNegative.redRatio && p.filmNegative.redRatio == other.filmNegative.redRatio; filmNegative.greenExp = filmNegative.greenExp && p.filmNegative.greenExp == other.filmNegative.greenExp; filmNegative.blueRatio = filmNegative.blueRatio && p.filmNegative.blueRatio == other.filmNegative.blueRatio; - filmNegative.baseValues = filmNegative.baseValues && p.filmNegative.redBase == other.filmNegative.redBase - && p.filmNegative.greenBase == other.filmNegative.greenBase - && p.filmNegative.blueBase == other.filmNegative.blueBase; + filmNegative.refInput = filmNegative.refInput && p.filmNegative.refInput == other.filmNegative.refInput; + filmNegative.refOutput = filmNegative.refOutput && p.filmNegative.refOutput == other.filmNegative.refOutput; + filmNegative.colorSpace = filmNegative.colorSpace && p.filmNegative.colorSpace == other.filmNegative.colorSpace; raw.preprocessWB.mode = raw.preprocessWB.mode && p.raw.preprocessWB.mode == other.raw.preprocessWB.mode; // How the hell can we handle that??? @@ -1375,6 +1993,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.retinex.gaintransmissionCurve = mods.retinex.gaintransmissionCurve; } + if (retinex.complexmethod) { + toEdit.retinex.complexmethod = mods.retinex.complexmethod; + } + if (retinex.retinexMethod) { toEdit.retinex.retinexMethod = mods.retinex.retinexMethod; } @@ -1713,7 +2335,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; } @@ -2018,6 +2640,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.colorappearance.curveMode3 = mods.colorappearance.curveMode3; } + if (colorappearance.complexmethod) { + toEdit.colorappearance.complexmethod = mods.colorappearance.complexmethod; + } + if (colorappearance.enabled) { toEdit.colorappearance.enabled = mods.colorappearance.enabled; } @@ -2417,6 +3043,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.lensProf.lfLens = mods.lensProf.lfLens; } + if (perspective.method) { + toEdit.perspective.method = mods.perspective.method; + } + if (perspective.horizontal) { toEdit.perspective.horizontal = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.horizontal + mods.perspective.horizontal : mods.perspective.horizontal; } @@ -2425,6 +3055,59 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical; } + if (perspective.camera_crop_factor) { + toEdit.perspective.camera_crop_factor = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_FOCAL_LENGTH] ? toEdit.perspective.camera_crop_factor + mods.perspective.camera_crop_factor : mods.perspective.camera_crop_factor; + } + + if (perspective.camera_focal_length) { + toEdit.perspective.camera_focal_length = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_FOCAL_LENGTH] ? toEdit.perspective.camera_focal_length + mods.perspective.camera_focal_length : mods.perspective.camera_focal_length; + } + + if (perspective.camera_pitch) { + toEdit.perspective.camera_pitch = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_ANGLE] ? toEdit.perspective.camera_pitch + mods.perspective.camera_pitch : mods.perspective.camera_pitch; + } + + if (perspective.camera_roll) { + toEdit.perspective.camera_roll = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_ANGLE] ? toEdit.perspective.camera_roll + mods.perspective.camera_roll : mods.perspective.camera_roll; + } + + if (perspective.camera_shift_horiz) { + toEdit.perspective.camera_shift_horiz = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_SHIFT] ? toEdit.perspective.camera_shift_horiz + mods.perspective.camera_shift_horiz : mods.perspective.camera_shift_horiz; + } + + if (perspective.camera_shift_vert) { + toEdit.perspective.camera_shift_vert = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_SHIFT] ? toEdit.perspective.camera_shift_vert + mods.perspective.camera_shift_vert : mods.perspective.camera_shift_vert; + } + + if (perspective.camera_yaw) { + toEdit.perspective.camera_yaw = dontforceSet && options.baBehav[ADDSET_PERSP_CAM_ANGLE] ? toEdit.perspective.camera_yaw + mods.perspective.camera_yaw : mods.perspective.camera_yaw; + } + + if (perspective.projection_pitch) { + toEdit.perspective.projection_pitch = dontforceSet && options.baBehav[ADDSET_PERSP_PROJ_ANGLE] ? toEdit.perspective.projection_pitch + mods.perspective.projection_pitch : mods.perspective.projection_pitch; + } + + if (perspective.projection_rotate) { + toEdit.perspective.projection_rotate = dontforceSet && options.baBehav[ADDSET_PERSP_PROJ_ROTATE] ? toEdit.perspective.projection_rotate + mods.perspective.projection_rotate : mods.perspective.projection_rotate; + } + + if (perspective.projection_shift_horiz) { + toEdit.perspective.projection_shift_horiz = dontforceSet && options.baBehav[ADDSET_PERSP_PROJ_SHIFT] ? toEdit.perspective.projection_shift_horiz + mods.perspective.projection_shift_horiz : mods.perspective.projection_shift_horiz; + } + + if (perspective.projection_shift_vert) { + toEdit.perspective.projection_shift_vert = dontforceSet && options.baBehav[ADDSET_PERSP_PROJ_SHIFT] ? toEdit.perspective.projection_shift_vert + mods.perspective.projection_shift_vert : mods.perspective.projection_shift_vert; + } + + if (perspective.projection_yaw) { + toEdit.perspective.projection_yaw = dontforceSet && options.baBehav[ADDSET_PERSP_PROJ_ANGLE] ? toEdit.perspective.projection_yaw + mods.perspective.projection_yaw : mods.perspective.projection_yaw; + } + + if (perspective.control_lines) { + toEdit.perspective.control_line_values = mods.perspective.control_line_values; + toEdit.perspective.control_line_types = mods.perspective.control_line_types; + } + if (gradient.enabled) { toEdit.gradient.enabled = mods.gradient.enabled; } @@ -2449,6 +3132,2013 @@ 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).prevMethod) { + toEdit.locallab.spots.at(i).prevMethod = mods.locallab.spots.at(i).prevMethod; + } + + 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).hishow) { + toEdit.locallab.spots.at(i).hishow = mods.locallab.spots.at(i).hishow; + } + + if (locallab.spots.at(i).activ) { + toEdit.locallab.spots.at(i).activ = mods.locallab.spots.at(i).activ; + } + + 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).CHcurve) { + toEdit.locallab.spots.at(i).CHcurve = mods.locallab.spots.at(i).CHcurve; + } + + 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).quamethod) { + toEdit.locallab.spots.at(i).quamethod = mods.locallab.spots.at(i).quamethod; + } + + 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).invbl) { + toEdit.locallab.spots.at(i).invbl = mods.locallab.spots.at(i).invbl; + } + + 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).dehazeSaturation) { + toEdit.locallab.spots.at(i).dehazeSaturation = mods.locallab.spots.at(i).dehazeSaturation; + } + + 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).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).complexlog) { + toEdit.locallab.spots.at(i).complexlog = mods.locallab.spots.at(i).complexlog; + } + + 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).sourceabs) { + toEdit.locallab.spots.at(i).sourceabs = mods.locallab.spots.at(i).sourceabs; + } + + if (locallab.spots.at(i).targabs) { + toEdit.locallab.spots.at(i).targabs = mods.locallab.spots.at(i).targabs; + } + + if (locallab.spots.at(i).targetGray) { + toEdit.locallab.spots.at(i).targetGray = mods.locallab.spots.at(i).targetGray; + } + + if (locallab.spots.at(i).catad) { + toEdit.locallab.spots.at(i).catad = mods.locallab.spots.at(i).catad; + } + + if (locallab.spots.at(i).saturl) { + toEdit.locallab.spots.at(i).saturl = mods.locallab.spots.at(i).saturl; + } + + if (locallab.spots.at(i).lightl) { + toEdit.locallab.spots.at(i).lightl = mods.locallab.spots.at(i).lightl; + } + + if (locallab.spots.at(i).lightq) { + toEdit.locallab.spots.at(i).lightq = mods.locallab.spots.at(i).lightq; + } + + if (locallab.spots.at(i).contl) { + toEdit.locallab.spots.at(i).contl = mods.locallab.spots.at(i).contl; + } + + if (locallab.spots.at(i).contq) { + toEdit.locallab.spots.at(i).contq = mods.locallab.spots.at(i).contq; + } + + if (locallab.spots.at(i).colorfl) { + toEdit.locallab.spots.at(i).colorfl = mods.locallab.spots.at(i).colorfl; + } + + if (locallab.spots.at(i).LcurveL) { + toEdit.locallab.spots.at(i).LcurveL = mods.locallab.spots.at(i).LcurveL; + } + + 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).ciecam) { + toEdit.locallab.spots.at(i).ciecam = mods.locallab.spots.at(i).ciecam; + } + + if (locallab.spots.at(i).enaLMask) { + toEdit.locallab.spots.at(i).enaLMask = mods.locallab.spots.at(i).enaLMask; + } + + if (locallab.spots.at(i).repar) { + toEdit.locallab.spots.at(i).repar = mods.locallab.spots.at(i).repar; + } + + 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).sursour) { + toEdit.locallab.spots.at(i).sursour = mods.locallab.spots.at(i).sursour; + } + + if (locallab.spots.at(i).surround) { + toEdit.locallab.spots.at(i).surround = mods.locallab.spots.at(i).surround; + } + + 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 (locallab.spots.at(i).CCmaskcurveL) { + toEdit.locallab.spots.at(i).CCmaskcurveL = mods.locallab.spots.at(i).CCmaskcurveL; + } + + if (locallab.spots.at(i).LLmaskcurveL) { + toEdit.locallab.spots.at(i).LLmaskcurveL = mods.locallab.spots.at(i).LLmaskcurveL; + } + + if (locallab.spots.at(i).HHmaskcurveL) { + toEdit.locallab.spots.at(i).HHmaskcurveL = mods.locallab.spots.at(i).HHmaskcurveL; + } + + if (locallab.spots.at(i).blendmaskL) { + toEdit.locallab.spots.at(i).blendmaskL = mods.locallab.spots.at(i).blendmaskL; + } + + if (locallab.spots.at(i).radmaskL) { + toEdit.locallab.spots.at(i).radmaskL = mods.locallab.spots.at(i).radmaskL; + } + + if (locallab.spots.at(i).chromaskL) { + toEdit.locallab.spots.at(i).chromaskL = mods.locallab.spots.at(i).chromaskL; + } + + if (locallab.spots.at(i).LmaskcurveL) { + toEdit.locallab.spots.at(i).LmaskcurveL = mods.locallab.spots.at(i).LmaskcurveL; + } + + // mask + if (locallab.spots.at(i).visimask) { + toEdit.locallab.spots.at(i).visimask = mods.locallab.spots.at(i).visimask; + } + + if (locallab.spots.at(i).complexmask) { + toEdit.locallab.spots.at(i).complexmask = mods.locallab.spots.at(i).complexmask; + } + + if (locallab.spots.at(i).expmask) { + toEdit.locallab.spots.at(i).expmask = mods.locallab.spots.at(i).expmask; + } + + if (locallab.spots.at(i).sensimask) { + toEdit.locallab.spots.at(i).sensimask = mods.locallab.spots.at(i).sensimask; + } + + if (locallab.spots.at(i).blendmask) { + toEdit.locallab.spots.at(i).blendmask = mods.locallab.spots.at(i).blendmask; + } + + if (locallab.spots.at(i).blendmaskab) { + toEdit.locallab.spots.at(i).blendmaskab = mods.locallab.spots.at(i).blendmaskab; + } + + if (locallab.spots.at(i).softradiusmask) { + toEdit.locallab.spots.at(i).softradiusmask = mods.locallab.spots.at(i).softradiusmask; + } + + if (locallab.spots.at(i).enamask) { + toEdit.locallab.spots.at(i).enamask = mods.locallab.spots.at(i).enamask; + } + + if (locallab.spots.at(i).fftmask) { + toEdit.locallab.spots.at(i).fftmask = mods.locallab.spots.at(i).fftmask; + } + + if (locallab.spots.at(i).blurmask) { + toEdit.locallab.spots.at(i).blurmask = mods.locallab.spots.at(i).blurmask; + } + + if (locallab.spots.at(i).contmask) { + toEdit.locallab.spots.at(i).contmask = mods.locallab.spots.at(i).contmask; + } + + if (locallab.spots.at(i).CCmask_curve) { + toEdit.locallab.spots.at(i).CCmask_curve = mods.locallab.spots.at(i).CCmask_curve; + } + + if (locallab.spots.at(i).LLmask_curve) { + toEdit.locallab.spots.at(i).LLmask_curve = mods.locallab.spots.at(i).LLmask_curve; + } + + if (locallab.spots.at(i).HHmask_curve) { + toEdit.locallab.spots.at(i).HHmask_curve = mods.locallab.spots.at(i).HHmask_curve; + } + + if (locallab.spots.at(i).strumaskmask) { + toEdit.locallab.spots.at(i).strumaskmask = mods.locallab.spots.at(i).strumaskmask; + } + + if (locallab.spots.at(i).toolmask) { + toEdit.locallab.spots.at(i).toolmask = mods.locallab.spots.at(i).toolmask; + } + + if (locallab.spots.at(i).radmask) { + toEdit.locallab.spots.at(i).radmask = mods.locallab.spots.at(i).radmask; + } + + if (locallab.spots.at(i).lapmask) { + toEdit.locallab.spots.at(i).lapmask = mods.locallab.spots.at(i).lapmask; + } + + if (locallab.spots.at(i).chromask) { + toEdit.locallab.spots.at(i).chromask = mods.locallab.spots.at(i).chromask; + } + + if (locallab.spots.at(i).gammask) { + toEdit.locallab.spots.at(i).gammask = mods.locallab.spots.at(i).gammask; + } + + if (locallab.spots.at(i).slopmask) { + toEdit.locallab.spots.at(i).slopmask = mods.locallab.spots.at(i).slopmask; + } + + if (locallab.spots.at(i).shadmask) { + toEdit.locallab.spots.at(i).shadmask = mods.locallab.spots.at(i).shadmask; + } + + if (locallab.spots.at(i).str_mask) { + toEdit.locallab.spots.at(i).str_mask = mods.locallab.spots.at(i).str_mask; + } + + if (locallab.spots.at(i).ang_mask) { + toEdit.locallab.spots.at(i).ang_mask = mods.locallab.spots.at(i).ang_mask; + } + + if (locallab.spots.at(i).HHhmask_curve) { + toEdit.locallab.spots.at(i).HHhmask_curve = mods.locallab.spots.at(i).HHhmask_curve; + } + + if (locallab.spots.at(i).Lmask_curve) { + toEdit.locallab.spots.at(i).Lmask_curve = mods.locallab.spots.at(i).Lmask_curve; + } + + if (locallab.spots.at(i).LLmask_curvewav) { + toEdit.locallab.spots.at(i).LLmask_curvewav = mods.locallab.spots.at(i).LLmask_curvewav; + } + + if (locallab.spots.at(i).csthresholdmask) { + toEdit.locallab.spots.at(i).csthresholdmask = mods.locallab.spots.at(i).csthresholdmask; + } + + } + + if (spot.enabled) { + toEdit.spot.enabled = mods.spot.enabled; + } + + if (spot.entries) { + toEdit.spot.entries = mods.spot.entries; + } + if (pcvignette.enabled) { toEdit.pcvignette.enabled = mods.pcvignette.enabled; } @@ -2631,14 +5321,6 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.resize.enabled = mods.resize.enabled; } - if (spot.enabled) { - toEdit.spot.enabled = mods.spot.enabled; - } - - if (spot.entries) { - toEdit.spot.entries = mods.spot.entries; - } - if (resize.allowUpscaling) { toEdit.resize.allowUpscaling = mods.resize.allowUpscaling; } @@ -3023,6 +5705,22 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.ballum = mods.wavelet.ballum; } + if (wavelet.sigm) { + toEdit.wavelet.sigm = mods.wavelet.sigm; + } + + if (wavelet.levden) { + toEdit.wavelet.levden = mods.wavelet.levden; + } + + if (wavelet.thrden) { + toEdit.wavelet.thrden = mods.wavelet.thrden; + } + + if (wavelet.limden) { + toEdit.wavelet.limden = mods.wavelet.limden; + } + if (wavelet.balchrom) { toEdit.wavelet.balchrom = mods.wavelet.balchrom; } @@ -3051,6 +5749,18 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.softradend = mods.wavelet.softradend; } + if (wavelet.strend) { + toEdit.wavelet.strend = mods.wavelet.strend; + } + + if (wavelet.detend) { + toEdit.wavelet.detend = mods.wavelet.detend; + } + + if (wavelet.thrend) { + toEdit.wavelet.thrend = mods.wavelet.thrend; + } + if (wavelet.lipst) { toEdit.wavelet.lipst = mods.wavelet.lipst; } @@ -3095,6 +5805,26 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.Tilesmethod = mods.wavelet.Tilesmethod; } + if (wavelet.complexmethod) { + toEdit.wavelet.complexmethod = mods.wavelet.complexmethod; + } + + if (wavelet.denmethod) { + toEdit.wavelet.denmethod = mods.wavelet.denmethod; + } + + if (wavelet.mixmethod) { + toEdit.wavelet.mixmethod = mods.wavelet.mixmethod; + } + + if (wavelet.slimethod) { + toEdit.wavelet.slimethod = mods.wavelet.slimethod; + } + + if (wavelet.quamethod) { + toEdit.wavelet.quamethod = mods.wavelet.quamethod; + } + if (wavelet.daubcoeffmethod) { toEdit.wavelet.daubcoeffmethod = mods.wavelet.daubcoeffmethod; } @@ -3191,6 +5921,14 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.level3noise = mods.wavelet.level3noise; } + if (wavelet.leveldenoise) { + toEdit.wavelet.leveldenoise = mods.wavelet.leveldenoise; + } + + if (wavelet.levelsigm) { + toEdit.wavelet.levelsigm = mods.wavelet.levelsigm; + } + if (wavelet.pastlev) { toEdit.wavelet.pastlev = mods.wavelet.pastlev; } @@ -3219,6 +5957,14 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.opacityCurveBY = mods.wavelet.opacityCurveBY; } + if (wavelet.wavdenoise) { + toEdit.wavelet.wavdenoise = mods.wavelet.wavdenoise; + } + + if (wavelet.wavdenoiseh) { + toEdit.wavelet.wavdenoiseh = mods.wavelet.wavdenoiseh; + } + if (wavelet.opacityCurveW) { toEdit.wavelet.opacityCurveW = mods.wavelet.opacityCurveW; } @@ -3231,6 +5977,14 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.hhcurve = mods.wavelet.hhcurve; } + if (wavelet.wavguidcurve) { + toEdit.wavelet.wavguidcurve = mods.wavelet.wavguidcurve; + } + + if (wavelet.wavhuecurve) { + toEdit.wavelet.wavhuecurve = mods.wavelet.wavhuecurve; + } + if (wavelet.Chcurve) { toEdit.wavelet.Chcurve = mods.wavelet.Chcurve; } @@ -3483,7 +6237,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; } @@ -3492,8 +6246,8 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.dehaze.showDepthMap = mods.dehaze.showDepthMap; } - if (dehaze.luminance) { - toEdit.dehaze.luminance = mods.dehaze.luminance; + if (dehaze.saturation) { + toEdit.dehaze.saturation = mods.dehaze.saturation; } if (metadata.mode) { @@ -3516,12 +6270,21 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.filmNegative.blueRatio = mods.filmNegative.blueRatio; } - if (filmNegative.baseValues) { - toEdit.filmNegative.redBase = mods.filmNegative.redBase; - toEdit.filmNegative.greenBase = mods.filmNegative.greenBase; - toEdit.filmNegative.blueBase = mods.filmNegative.blueBase; + if (filmNegative.refInput) { + toEdit.filmNegative.refInput = mods.filmNegative.refInput; } + if (filmNegative.refOutput) { + toEdit.filmNegative.refOutput = mods.filmNegative.refOutput; + } + + if (filmNegative.colorSpace) { + toEdit.filmNegative.colorSpace = mods.filmNegative.colorSpace; + } + + // BackCompat param cannot be managed via the GUI, and it's always copied + toEdit.filmNegative.backCompat = mods.filmNegative.backCompat; + if (raw.preprocessWB.mode) { toEdit.raw.preprocessWB.mode = mods.raw.preprocessWB.mode; } @@ -3572,7 +6335,1033 @@ bool RetinexParamsEdited::isUnchanged() const bool FilmNegativeParamsEdited::isUnchanged() const { - return enabled && redRatio && greenExp && blueRatio && baseValues; + return enabled && redRatio && greenExp && blueRatio && refInput && refOutput && colorSpace; +} + +LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : + // Control spot settings + name(v), + isvisible(v), + prevMethod(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), + hishow(v), + activ(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), + CHcurve(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), + quamethod(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), + invbl(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), + dehazeSaturation(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), + 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), + complexlog(v), + autocompute(v), + sourceGray(v), + sourceabs(v), + targabs(v), + targetGray(v), + catad(v), + saturl(v), + lightl(v), + lightq(v), + contl(v), + contq(v), + colorfl(v), + LcurveL(v), + Autogray(v), + fullimage(v), + repar(v), + ciecam(v), + blackEv(v), + whiteEv(v), + detail(v), + sursour(v), + surround(v), + sensilog(v), + baselog(v), + strlog(v), + anglog(v), + CCmaskcurveL(v), + LLmaskcurveL(v), + HHmaskcurveL(v), + enaLMask(v), + blendmaskL(v), + radmaskL(v), + chromaskL(v), + LmaskcurveL(v), + // mask + visimask(v), + complexmask(v), + expmask(v), + sensimask(v), + blendmask(v), + blendmaskab(v), + softradiusmask(v), + enamask(v), + fftmask(v), + blurmask(v), + contmask(v), + CCmask_curve(v), + LLmask_curve(v), + HHmask_curve(v), + strumaskmask(v), + toolmask(v), + radmask(v), + lapmask(v), + chromask(v), + gammask(v), + slopmask(v), + shadmask(v), + str_mask(v), + ang_mask(v), + HHhmask_curve(v), + Lmask_curve(v), + LLmask_curvewav(v), + csthresholdmask(v) + +{ +} + +void LocallabParamsEdited::LocallabSpotEdited::set(bool v) +{ + name = v; + isvisible = v; + prevMethod = 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; + hishow = v; + activ = 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; + CHcurve = 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; + quamethod = 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; + invbl = 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; + dehazeSaturation = 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; + blendmaskcb = v; + radmaskcb = v; + chromaskcb = v; + gammaskcb = v; + slomaskcb = v; + lapmaskcb = v; + Lmaskcbcurve = v; + // Log encoding + visilog = v; + explog = v; + complexlog = v; + autocompute = v; + sourceGray = v; + sourceabs = v; + targabs = v; + targetGray = v; + catad = v; + saturl = v; + lightl = v; + lightq = v; + contl = v; + contq = v; + colorfl = v; + LcurveL = v; + Autogray = v; + fullimage = v; + repar = v; + ciecam = v; + blackEv = v; + whiteEv = v; + detail = v; + sursour = v; + surround = v; + sensilog = v; + baselog = v; + strlog = v; + anglog = v; + CCmaskcurveL = v; + LLmaskcurveL = v; + HHmaskcurveL = v; + enaLMask = v; + blendmaskL = v; + radmaskL = v; + chromaskL = v; + LmaskcurveL = v; + // mask + visimask = v; + complexmask = v; + expmask = v; + sensimask = v; + blendmask = v; + blendmaskab = v; + softradiusmask = v; + enamask = v; + fftmask = v; + blurmask = v; + contmask = v; + CCmask_curve = v; + LLmask_curve = v; + HHmask_curve = v; + strumaskmask = v; + toolmask = v; + radmask = v; + lapmask = v; + chromask = v; + gammask = v; + slopmask = v; + shadmask = v; + str_mask = v; + ang_mask = v; + HHhmask_curve =(v); + Lmask_curve =(v); + LLmask_curvewav =(v); + csthresholdmask = v; } bool CaptureSharpeningParamsEdited::isUnchanged() const @@ -3583,4 +7372,4 @@ bool CaptureSharpeningParamsEdited::isUnchanged() const bool RAWParamsEdited::PreprocessWBParamsEdited::isUnchanged() const { return mode; -} \ No newline at end of file +} diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 02fa64408..143de90e0 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -73,6 +73,7 @@ struct RetinexParamsEdited { bool slope; bool neigh; bool offs; + bool complexmethod; bool retinexMethod; bool mapMethod; bool viewMethod; @@ -169,6 +170,10 @@ struct ColorToningEdited { bool labgridBLow; bool labgridAHigh; bool labgridBHigh; + bool labgridALowmerg; + bool labgridBLowmerg; + bool labgridAHighmerg; + bool labgridBHighmerg; bool labregions; bool labregionsShowMask; }; @@ -261,6 +266,7 @@ struct ColorAppearanceParamsEdited { bool curveMode; bool curveMode2; bool curveMode3; + bool complexmethod; bool enabled; bool degree; bool autodegree; @@ -379,6 +385,525 @@ struct RotateParamsEdited { struct DistortionParamsEdited { bool amount; }; +class LocallabParamsEdited +{ +public: + struct LocallabSpotEdited { + // Control spot settings + bool name; + bool isvisible; + bool prevMethod; + 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 hishow; + bool activ; + 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 CHcurve; + 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 quamethod; + 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 invbl; + 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 dehazeSaturation; + 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 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 complexlog; + bool autocompute; + bool sourceGray; + bool sourceabs; + bool targabs; + bool targetGray; + bool catad; + bool saturl; + bool lightl; + bool lightq; + bool contl; + bool contq; + bool colorfl; + bool LcurveL; + bool Autogray; + bool fullimage; + bool repar; + bool ciecam; + bool blackEv; + bool whiteEv; + bool detail; + bool sursour; + bool surround; + bool sensilog; + bool baselog; + bool strlog; + bool anglog; + bool CCmaskcurveL; + bool LLmaskcurveL; + bool HHmaskcurveL; + bool enaLMask; + bool blendmaskL; + bool radmaskL; + bool chromaskL; + bool LmaskcurveL; + //mask + bool visimask; + bool complexmask; + bool expmask; + bool sensimask; + bool blendmask; + bool blendmaskab; + bool softradiusmask; + bool enamask; + bool fftmask; + bool blurmask; + bool contmask; + bool CCmask_curve; + bool LLmask_curve; + bool HHmask_curve; + bool strumaskmask; + bool toolmask; + bool radmask; + bool lapmask; + bool chromask; + bool gammask; + bool slopmask; + bool shadmask; + bool str_mask; + bool ang_mask; + bool HHhmask_curve; + bool Lmask_curve; + bool LLmask_curvewav; + bool csthresholdmask; + + LocallabSpotEdited(bool v); + + void set(bool v); + }; + + bool enabled; + bool selspot; + std::vector spots; +}; struct LensProfParamsEdited { bool lcpFile; @@ -398,8 +923,22 @@ struct LensProfParamsEdited { }; struct PerspectiveParamsEdited { + bool method; bool horizontal; bool vertical; + bool camera_crop_factor; + bool camera_focal_length; + bool camera_pitch; + bool camera_roll; + bool camera_shift_horiz; + bool camera_shift_vert; + bool camera_yaw; + bool projection_pitch; + bool projection_rotate; + bool projection_shift_horiz; + bool projection_shift_vert; + bool projection_yaw; + bool control_lines; }; struct GradientParamsEdited { @@ -536,6 +1075,11 @@ struct WaveletParamsEdited { bool CLmethod; bool Backmethod; bool Tilesmethod; + bool complexmethod; + bool denmethod; + bool mixmethod; + bool slimethod; + bool quamethod; bool daubcoeffmethod; bool Dirmethod; bool sigma; @@ -582,14 +1126,20 @@ struct WaveletParamsEdited { bool level1noise; bool level2noise; bool level3noise; + bool leveldenoise; + bool levelsigm; bool ccwcurve; bool blcurve; bool opacityCurveSH; bool opacityCurveBY; + bool wavdenoise; + bool wavdenoiseh; bool opacityCurveRG; bool opacityCurveW; bool opacityCurveWL; bool hhcurve; + bool wavguidcurve; + bool wavhuecurve; bool Chcurve; bool pastlev; bool satlev; @@ -601,6 +1151,10 @@ struct WaveletParamsEdited { bool greenhigh; bool bluehigh; bool ballum; + bool sigm; + bool levden; + bool thrden; + bool limden; bool balchrom; bool chromfi; bool chromco; @@ -608,6 +1162,9 @@ struct WaveletParamsEdited { bool mergeC; bool softrad; bool softradend; + bool strend; + bool detend; + bool thrend; bool expcontrast; bool expchroma; bool expedge; @@ -621,7 +1178,6 @@ struct WaveletParamsEdited { bool labgridBLow; bool labgridAHigh; bool labgridBHigh; - }; struct DirPyrEqualizerParamsEdited { @@ -657,7 +1213,7 @@ struct DehazeParamsEdited { bool strength; bool showDepthMap; bool depth; - bool luminance; + bool saturation; }; struct RAWParamsEdited { @@ -754,7 +1310,9 @@ struct FilmNegativeParamsEdited { bool redRatio; bool greenExp; bool blueRatio; - bool baseValues; + bool refInput; + bool refOutput; + bool colorSpace; bool isUnchanged() const; }; @@ -789,6 +1347,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 f685d9b67..32f7e93d5 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"))); @@ -104,6 +270,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"))); @@ -135,17 +305,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 ()); @@ -187,6 +357,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[2]->pack_start (*blackwhite, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*hsveq, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*filmSimulation, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*filmNegative, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*softlight, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*rgbcurves, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*colortoning, Gtk::PACK_SHRINK, 2); @@ -217,50 +388,47 @@ 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 (*raw_preprocwb, 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 (*captureSharpening, Gtk::PACK_SHRINK, 2); Gtk::VBox* vbCol1 = Gtk::manage (new Gtk::VBox ()); Gtk::VBox* vbCol2 = Gtk::manage (new Gtk::VBox ()); @@ -270,11 +438,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); } @@ -319,6 +487,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)); @@ -434,6 +603,7 @@ void PartialPasteDlg::everythingToggled () ConnectionBlocker metaBlocker(metaConn); ConnectionBlocker rawBlocker(rawConn); ConnectionBlocker advancedBlocker(advancedConn); + ConnectionBlocker locallabBlocker(locallabConn); everything->set_inconsistent (false); @@ -446,6 +616,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 (); @@ -456,6 +627,7 @@ void PartialPasteDlg::everythingToggled () PartialPasteDlg::metaToggled (); PartialPasteDlg::rawToggled (); PartialPasteDlg::advancedToggled (); + PartialPasteDlg::locallabToggled(); } void PartialPasteDlg::rawToggled () @@ -486,7 +658,6 @@ void PartialPasteDlg::rawToggled () ConnectionBlocker raw_ca_autocorrectBlocker(raw_ca_autocorrectConn); ConnectionBlocker raw_caredblueBlocker(raw_caredblueConn); ConnectionBlocker raw_ca_avoid_colourshiftBlocker(raw_ca_avoid_colourshiftconn); - ConnectionBlocker filmNegativeBlocker(filmNegativeConn); ConnectionBlocker captureSharpeningBlocker(captureSharpeningConn); ConnectionBlocker raw_preprocwbBlocker(raw_preprocwbConn); @@ -517,7 +688,6 @@ void PartialPasteDlg::rawToggled () raw_ca_autocorrect->set_active (raw->get_active ()); raw_caredblue->set_active (raw->get_active ()); 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()); } @@ -597,6 +767,7 @@ void PartialPasteDlg::colorToggled () ConnectionBlocker chmixerbwBlocker(chmixerbwConn); ConnectionBlocker hsveqBlocker(hsveqConn); ConnectionBlocker filmSimulationBlocker(filmSimulationConn); + ConnectionBlocker filmNegativeBlocker(filmNegativeConn); ConnectionBlocker softlightBlocker(softlightConn); ConnectionBlocker rgbcurvesBlocker(rgbcurvesConn); ConnectionBlocker colortoningBlocker(colortoningConn); @@ -609,6 +780,7 @@ void PartialPasteDlg::colorToggled () blackwhite->set_active (color->get_active ()); hsveq->set_active (color->get_active ()); filmSimulation->set_active (color->get_active ()); + filmNegative->set_active (color->get_active()); softlight->set_active (color->get_active ()); rgbcurves->set_active (color->get_active ()); colortoning->set_active(color->get_active ()); @@ -666,6 +838,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) @@ -675,7 +858,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; @@ -1002,7 +1187,9 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.filmNegative.redRatio = falsePE.filmNegative.redRatio; filterPE.filmNegative.greenExp = falsePE.filmNegative.greenExp; filterPE.filmNegative.blueRatio = falsePE.filmNegative.blueRatio; - filterPE.filmNegative.baseValues = falsePE.filmNegative.baseValues; + filterPE.filmNegative.refInput = falsePE.filmNegative.refInput; + filterPE.filmNegative.refOutput = falsePE.filmNegative.refOutput; + filterPE.filmNegative.colorSpace = falsePE.filmNegative.colorSpace; } if (!captureSharpening->get_active ()) { @@ -1020,10 +1207,65 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.raw.preprocessWB.mode = falsePE.raw.preprocessWB.mode; } - if (dstPE) { - *dstPE = filterPE; - } + // Locallab shall be kept in last position + if (!locallab->get_active () && !locallab->get_inconsistent()) { + filterPE.locallab = falsePE.locallab; - // Apply the filter! - filterPE.combine(*dstPP, *srcPP, true); + 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 048928b34..8bf5104ae 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; @@ -112,6 +187,8 @@ public: Gtk::CheckButton* exifch; Gtk::CheckButton* iptc; + // options in locallab: + PartialSpotWidget* spots; // options in raw: Gtk::CheckButton* raw_expos; @@ -146,7 +223,7 @@ public: 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 spotConn, sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn; @@ -173,4 +250,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/pdsharpening.cc b/rtgui/pdsharpening.cc index 8bbf19620..1b98fd3ac 100644 --- a/rtgui/pdsharpening.cc +++ b/rtgui/pdsharpening.cc @@ -81,10 +81,10 @@ PdSharpening::PdSharpening() : dradiusOffset->setAdjusterListener(this); diter->setAdjusterListener(this); - contrast->delay = std::max(contrast->delay, options.adjusterMaxDelay); - dradius->delay = std::max(dradius->delay, options.adjusterMaxDelay); - dradiusOffset->delay = std::max(dradiusOffset->delay, options.adjusterMaxDelay); - diter->delay = std::max(diter->delay, options.adjusterMaxDelay); + contrast->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + dradius->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + dradiusOffset->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); + diter->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); } PdSharpening::~PdSharpening() diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index b86da6a52..55013ec4a 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -16,34 +16,290 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include "eventmapper.h" #include "perspective.h" #include "rtimage.h" +#include "rtsurface.h" #include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; +namespace +{ + +void controlLinesToValues(const std::vector& lines, + std::vector& values, std::vector& types) +{ + values.clear(); + types.clear(); + + for (auto&& line : lines) { + values.push_back(line.x1); + values.push_back(line.y1); + values.push_back(line.x2); + values.push_back(line.y2); + + int type = -1; + switch (line.type) { + case rtengine::ControlLine::VERTICAL: + type = 0; + break; + case rtengine::ControlLine::HORIZONTAL: + type = 1; + break; + } + types.push_back(type); + } +} + +std::vector valuesToControlLines( + const std::vector& values, const std::vector& types) +{ + int line_count = min(values.size() / 4, types.size()); + std::vector lines(line_count); + + auto values_iter = values.begin(); + auto types_iter = types.begin(); + for (auto&& line : lines) { + line.x1 = *(values_iter++); + line.y1 = *(values_iter++); + line.x2 = *(values_iter++); + line.y2 = *(values_iter++); + + switch (*(types_iter++)) { + case 0: + line.type = rtengine::ControlLine::VERTICAL; + break; + case 1: + line.type = rtengine::ControlLine::HORIZONTAL; + break; + } + } + + return lines; +} + +} + PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("TP_PERSPECTIVE_LABEL")) { + auto mapper = ProcEventMapper::getInstance(); + // Normal events. + EvPerspCamAngle = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_CAM_ANGLE"); + EvPerspCamFocalLength = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_CAM_FL"); + EvPerspCamShift = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_CAM_SHIFT"); + EvPerspMethod = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_METHOD"); + EvPerspProjAngle = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_PROJ_ANGLE"); + EvPerspProjRotate = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_PROJ_ROTATE"); + EvPerspProjShift = mapper->newEvent(TRANSFORM, "HISTORY_MSG_PERSP_PROJ_SHIFT"); + EvPerspRender = mapper->newEvent(TRANSFORM); + // Void events. + EvPerspCamAngleVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CAM_ANGLE"); + EvPerspCamFocalLengthVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CAM_FL"); + EvPerspCamShiftVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CAM_SHIFT"); + EvPerspProjAngleVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_PROJ_ANGLE"); + EvPerspProjRotateVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_PROJ_ROTATE"); + EvPerspProjShiftVoid = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_PROJ_SHIFT"); + setCamBasedEventsActive(); + EvPerspControlLines = mapper->newEvent(M_VOID, "HISTORY_MSG_PERSP_CTRL_LINE"); + + lens_geom_listener = nullptr; + panel_listener = nullptr; + metadata = nullptr; + + Gtk::Image* ipers_draw(new RTImage ("draw.png")); + Gtk::Image* ipers_trash = Gtk::manage (new RTImage ("trash-empty.png")); + Gtk::Image* ipers_apply = Gtk::manage (new RTImage ("tick.png")); + Gtk::Image* ipersHL = Gtk::manage (new RTImage ("perspective-horizontal-left-small.png")); Gtk::Image* ipersHR = Gtk::manage (new RTImage ("perspective-horizontal-right-small.png")); Gtk::Image* ipersVL = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png")); Gtk::Image* ipersVR = Gtk::manage (new RTImage ("perspective-vertical-top-small.png")); - horiz = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_HORIZONTAL"), -100, 100, 0.1, 0, ipersHL, ipersHR)); - horiz->setAdjusterListener (this); + Gtk::Image* ipers_auto_pitch = Gtk::manage (new RTImage ("perspective-vertical-bottom.png")); + Gtk::Image* ipers_auto_yaw = Gtk::manage (new RTImage ("perspective-horizontal-left.png")); + Gtk::Image* ipers_auto_pitch_yaw = Gtk::manage (new RTImage ("perspective-horizontal-vertical.png")); + + Gtk::Image* ipers_cam_yaw_left = Gtk::manage (new RTImage ("perspective-horizontal-left-small.png")); + Gtk::Image* ipers_cam_yaw_right = Gtk::manage (new RTImage ("perspective-horizontal-right-small.png")); + Gtk::Image* ipers_cam_pitch_left = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png")); + Gtk::Image* ipers_cam_pitch_right = Gtk::manage (new RTImage ("perspective-vertical-top-small.png")); + Gtk::Image* ipers_proj_yaw_left = Gtk::manage (new RTImage ("perspective-horizontal-left-small.png")); + Gtk::Image* ipers_proj_yaw_right = Gtk::manage (new RTImage ("perspective-horizontal-right-small.png")); + Gtk::Image* ipers_proj_pitch_left = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png")); + Gtk::Image* ipers_proj_pitch_right = Gtk::manage (new RTImage ("perspective-vertical-top-small.png")); + Gtk::Image* ipers_rotate_left = Gtk::manage(new RTImage("rotate-right-small.png")); + Gtk::Image* ipers_rotate_right = Gtk::manage(new RTImage("rotate-left-small.png")); + + Gtk::HBox* method_hbox = Gtk::manage (new Gtk::HBox()); + Gtk::Label* method_label = Gtk::manage (new Gtk::Label (M("TP_PERSPECTIVE_METHOD") + ": ")); + method = Gtk::manage (new MyComboBoxText ()); + method->append (M("TP_PERSPECTIVE_METHOD_SIMPLE")); + method->append (M("TP_PERSPECTIVE_METHOD_CAMERA_BASED")); + method_hbox->pack_start(*method_label, Gtk::PACK_SHRINK); + method_hbox->pack_start(*method); + pack_start(*method_hbox); + + simple = Gtk::manage( new Gtk::VBox() ); vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_VERTICAL"), -100, 100, 0.1, 0, ipersVL, ipersVR)); vert->setAdjusterListener (this); - pack_start (*horiz); - pack_start (*vert); + horiz = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_HORIZONTAL"), -100, 100, 0.1, 0, ipersHL, ipersHR)); + horiz->setAdjusterListener (this); + + camera_based = Gtk::manage( new Gtk::VBox() ); + + Gtk::Frame* camera_frame = Gtk::manage (new Gtk::Frame + (M("TP_PERSPECTIVE_CAMERA_FRAME"))); + camera_frame->set_label_align(0.025, 0.5); + + Gtk::VBox* camera_vbox = Gtk::manage (new Gtk::VBox()); + + camera_focal_length = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH"), 0.5, 2000, 0.01, 24)); + camera_focal_length->setAdjusterListener (this); + + camera_crop_factor = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_CROP_FACTOR"), 0.1, 30, 0.01, 1)); + camera_crop_factor->setAdjusterListener (this); + + camera_shift_horiz = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL"), -50, 50, 0.01, 0)); + camera_shift_horiz->setAdjusterListener (this); + + camera_shift_vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL"), -50, 50, 0.01, 0)); + camera_shift_vert->setAdjusterListener (this); + + camera_roll = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_ROLL"), -45, 45, 0.01, 0)); + camera_roll->setAdjusterListener (this); + + camera_pitch = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_PITCH"), + -60, 60, 0.1, 0, ipers_cam_pitch_left, ipers_cam_pitch_right)); + camera_pitch->setAdjusterListener (this); + + camera_yaw = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_CAMERA_YAW"), + -60, 60, 0.1, 0, ipers_cam_yaw_left, ipers_cam_yaw_right)); + camera_yaw->setAdjusterListener (this); + + // Begin control lines interface. + lines_button_apply = Gtk::manage (new Gtk::Button()); + lines_button_apply->set_image(*ipers_apply); + lines_button_apply->set_tooltip_text(M("GENERAL_APPLY")); + lines_button_apply->set_sensitive(false); + lines_button_apply->signal_pressed().connect(sigc::mem_fun( + *this, &::PerspCorrection::linesApplyButtonPressed)); + + lines_button_edit = Gtk::manage (new Gtk::ToggleButton()); + lines_button_edit->set_image(*ipers_draw); + lines_button_edit->set_tooltip_text(M("GENERAL_EDIT")); + lines_button_edit->signal_toggled().connect(sigc::mem_fun( + *this, &::PerspCorrection::linesEditButtonPressed)); + + lines_button_erase = Gtk::manage (new Gtk::Button()); + lines_button_erase->set_image(*ipers_trash); + lines_button_erase->set_tooltip_text(M("GENERAL_DELETE_ALL")); + lines_button_erase->set_sensitive(false); + lines_button_erase->signal_pressed().connect(sigc::mem_fun( + *this, &::PerspCorrection::linesEraseButtonPressed)); + + lines = std::unique_ptr(new ControlLineManager()); + lines->callbacks = std::make_shared(this); + + Gtk::HBox* control_lines_box = Gtk::manage (new Gtk::HBox()); + Gtk::Label* control_lines_label = Gtk::manage (new Gtk::Label (M("TP_PERSPECTIVE_CONTROL_LINES") + ": ")); + control_lines_label->set_tooltip_markup( M("TP_PERSPECTIVE_CONTROL_LINES_TOOLTIP") ); + control_lines_box->pack_start(*control_lines_label, Gtk::PACK_SHRINK); + control_lines_box->pack_start(*lines_button_edit); + control_lines_box->pack_start(*lines_button_apply); + control_lines_box->pack_start(*lines_button_erase); + // End control lines interface. + + auto_pitch = Gtk::manage (new Gtk::Button ()); + auto_pitch->set_image(*ipers_auto_pitch); + auto_pitch->signal_pressed().connect( sigc::bind(sigc::mem_fun(*this, &PerspCorrection::autoCorrectionPressed), auto_pitch) ); + + auto_yaw = Gtk::manage (new Gtk::Button ()); + auto_yaw->set_image(*ipers_auto_yaw); + auto_yaw->signal_pressed().connect( sigc::bind(sigc::mem_fun(*this, &PerspCorrection::autoCorrectionPressed), auto_yaw) ); + + auto_pitch_yaw = Gtk::manage (new Gtk::Button ()); + auto_pitch_yaw->set_image(*ipers_auto_pitch_yaw); + auto_pitch_yaw->signal_pressed().connect( sigc::bind(sigc::mem_fun(*this, &PerspCorrection::autoCorrectionPressed), auto_pitch_yaw) ); + + Gtk::HBox* auto_hbox = Gtk::manage (new Gtk::HBox()); + Gtk::Label* auto_label = Gtk::manage (new Gtk::Label (M("GENERAL_AUTO") + ": ")); + auto_hbox->pack_start(*auto_label, Gtk::PACK_SHRINK); + + Gtk::Frame* pca_frame = Gtk::manage (new Gtk::Frame + (M("TP_PERSPECTIVE_POST_CORRECTION_ADJUSTMENT_FRAME"))); + pca_frame->set_label_align(0.025, 0.5); + + Gtk::VBox* pca_vbox = Gtk::manage (new Gtk::VBox()); + + projection_shift_horiz = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL"), -100, 100, 0.01, 0)); + projection_shift_horiz->setAdjusterListener (this); + + projection_shift_vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL"), -100, 100, 0.01, 0)); + projection_shift_vert->setAdjusterListener (this); + + projection_rotate = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_PROJECTION_ROTATE"), -45, 45, 0.01, 0, ipers_rotate_left, ipers_rotate_right)); + projection_rotate->setAdjusterListener (this); + + Gtk::Frame* recovery_frame = Gtk::manage (new Gtk::Frame + (M("TP_PERSPECTIVE_RECOVERY_FRAME"))); + recovery_frame->set_label_align(0.025, 0.5); + + Gtk::VBox* recovery_vbox = Gtk::manage (new Gtk::VBox()); + + projection_pitch = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_PROJECTION_PITCH"), -60, 60, 0.1, 0, ipers_proj_pitch_left, ipers_proj_pitch_right)); + projection_pitch->setAdjusterListener (this); + + projection_yaw = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_PROJECTION_YAW"), -60, 60, 0.1, 0, ipers_proj_yaw_left, ipers_proj_yaw_right)); + projection_yaw->setAdjusterListener (this); + + simple->pack_start (*horiz); + simple->pack_start (*vert); + + auto_hbox->pack_start (*auto_pitch); + auto_hbox->pack_start (*auto_yaw); + auto_hbox->pack_start (*auto_pitch_yaw); + + camera_vbox->pack_start (*camera_focal_length); + camera_vbox->pack_start (*camera_crop_factor); + camera_vbox->pack_start (*camera_shift_horiz); + camera_vbox->pack_start (*camera_shift_vert); + camera_vbox->pack_start (*camera_roll); + camera_vbox->pack_start (*camera_pitch); + camera_vbox->pack_start (*camera_yaw); + camera_vbox->pack_start (*Gtk::manage (new Gtk::HSeparator())); + camera_vbox->pack_start (*control_lines_box); + camera_vbox->pack_start (*Gtk::manage (new Gtk::HSeparator())); + camera_vbox->pack_start (*auto_hbox); + camera_frame->add(*camera_vbox); + camera_based->pack_start(*camera_frame); + + pca_vbox->pack_start (*projection_shift_horiz); + pca_vbox->pack_start (*projection_shift_vert); + pca_vbox->pack_start (*projection_rotate); + pca_frame->add(*pca_vbox); + camera_based->pack_start(*pca_frame); + + recovery_vbox->pack_start (*projection_yaw); + recovery_vbox->pack_start (*projection_pitch); + recovery_frame->add(*recovery_vbox); + camera_based->pack_start(*recovery_frame); + + pack_start(*simple); + pack_start(*camera_based); horiz->setLogScale(2, 0); vert->setLogScale(2, 0); + camera_focal_length->setLogScale(4000, 0.5); + camera_crop_factor->setLogScale(300, 0.1); + + method->signal_changed().connect(sigc::mem_fun(*this, &PerspCorrection::methodChanged)); show_all(); } @@ -56,10 +312,44 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited) if (pedited) { horiz->setEditedState (pedited->perspective.horizontal ? Edited : UnEdited); vert->setEditedState (pedited->perspective.vertical ? Edited : UnEdited); + camera_crop_factor->setEditedState (pedited->perspective.camera_crop_factor ? Edited : UnEdited); + camera_focal_length->setEditedState (pedited->perspective.camera_focal_length ? Edited : UnEdited); + camera_pitch->setEditedState (pedited->perspective.camera_pitch ? Edited : UnEdited); + camera_roll->setEditedState (pedited->perspective.camera_roll ? Edited : UnEdited); + camera_shift_horiz->setEditedState (pedited->perspective.camera_shift_horiz ? Edited : UnEdited); + camera_shift_vert->setEditedState (pedited->perspective.camera_shift_vert ? Edited : UnEdited); + camera_yaw->setEditedState (pedited->perspective.camera_yaw ? Edited : UnEdited); + projection_pitch->setEditedState (pedited->perspective.projection_pitch ? Edited : UnEdited); + projection_rotate->setEditedState (pedited->perspective.projection_rotate ? Edited : UnEdited); + projection_shift_horiz->setEditedState (pedited->perspective.projection_shift_horiz ? Edited : UnEdited); + projection_shift_vert->setEditedState (pedited->perspective.projection_shift_vert ? Edited : UnEdited); + projection_yaw->setEditedState (pedited->perspective.projection_yaw ? Edited : UnEdited); + lines->setEdited (pedited->perspective.control_lines); } horiz->setValue (pp->perspective.horizontal); vert->setValue (pp->perspective.vertical); + setFocalLengthValue (pp, metadata); + camera_pitch->setValue (pp->perspective.camera_pitch); + camera_roll->setValue (pp->perspective.camera_roll); + camera_shift_horiz->setValue (pp->perspective.camera_shift_horiz); + camera_shift_vert->setValue (pp->perspective.camera_shift_vert); + camera_yaw->setValue (pp->perspective.camera_yaw); + projection_pitch->setValue (pp->perspective.projection_pitch); + projection_rotate->setValue (pp->perspective.projection_rotate); + projection_shift_horiz->setValue (pp->perspective.projection_shift_horiz); + projection_shift_vert->setValue (pp->perspective.projection_shift_vert); + projection_yaw->setValue (pp->perspective.projection_yaw); + lines->setLines(valuesToControlLines(pp->perspective.control_line_values, + pp->perspective.control_line_types)); + + if (pedited && !pedited->perspective.method) { + method->set_active (2); + } else if (pp->perspective.method == "simple") { + method->set_active (0); + } else if (pp->perspective.method == "camera_based") { + method->set_active (1); + } enableListener (); } @@ -67,12 +357,51 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited) void PerspCorrection::write (ProcParams* pp, ParamsEdited* pedited) { + pp->perspective.render = render; + pp->perspective.horizontal = horiz->getValue (); pp->perspective.vertical = vert->getValue (); + pp->perspective.camera_crop_factor= camera_crop_factor->getValue (); + pp->perspective.camera_focal_length = camera_focal_length->getValue (); + pp->perspective.camera_pitch = camera_pitch->getValue (); + pp->perspective.camera_roll = camera_roll->getValue (); + pp->perspective.camera_shift_horiz = camera_shift_horiz->getValue (); + pp->perspective.camera_shift_vert = camera_shift_vert->getValue (); + pp->perspective.camera_yaw = camera_yaw->getValue (); + pp->perspective.projection_pitch = projection_pitch->getValue (); + pp->perspective.projection_rotate = projection_rotate->getValue (); + pp->perspective.projection_shift_horiz = projection_shift_horiz->getValue (); + pp->perspective.projection_shift_vert = projection_shift_vert->getValue (); + pp->perspective.projection_yaw = projection_yaw->getValue (); + + std::vector control_lines; + lines->toControlLines(control_lines); + controlLinesToValues(control_lines, pp->perspective.control_line_values, + pp->perspective.control_line_types); + + if (method->get_active_row_number() == 0) { + pp->perspective.method = "simple"; + } else if (method->get_active_row_number() == 1) { + pp->perspective.method = "camera_based"; + } if (pedited) { + pedited->perspective.method = method->get_active_row_number() != 2; pedited->perspective.horizontal = horiz->getEditedState (); pedited->perspective.vertical = vert->getEditedState (); + pedited->perspective.camera_crop_factor= camera_crop_factor->getEditedState (); + pedited->perspective.camera_focal_length = camera_focal_length->getEditedState (); + pedited->perspective.camera_pitch = camera_pitch->getEditedState(); + pedited->perspective.camera_roll = camera_roll->getEditedState(); + pedited->perspective.camera_shift_horiz = camera_shift_horiz->getEditedState(); + pedited->perspective.camera_shift_vert = camera_shift_vert->getEditedState(); + pedited->perspective.camera_yaw = camera_yaw->getEditedState(); + pedited->perspective.projection_pitch = projection_pitch->getEditedState(); + pedited->perspective.projection_rotate = projection_rotate->getEditedState(); + pedited->perspective.projection_shift_horiz = projection_shift_horiz->getEditedState(); + pedited->perspective.projection_shift_vert = projection_shift_vert->getEditedState(); + pedited->perspective.projection_yaw = projection_yaw->getEditedState(); + pedited->perspective.control_lines = lines->getEdited(); } } @@ -81,28 +410,224 @@ void PerspCorrection::setDefaults (const ProcParams* defParams, const ParamsEdit horiz->setDefault (defParams->perspective.horizontal); vert->setDefault (defParams->perspective.vertical); + camera_crop_factor->setDefault (defParams->perspective.camera_crop_factor); + camera_focal_length->setDefault (defParams->perspective.camera_focal_length); + camera_pitch->setDefault (defParams->perspective.camera_pitch); + camera_roll->setDefault (defParams->perspective.camera_roll); + camera_shift_horiz->setDefault (defParams->perspective.camera_shift_horiz); + camera_shift_vert->setDefault (defParams->perspective.camera_shift_vert); + camera_yaw->setDefault (defParams->perspective.camera_yaw); + projection_pitch->setDefault (defParams->perspective.projection_pitch); + projection_rotate->setDefault (defParams->perspective.projection_rotate); + projection_shift_horiz->setDefault (defParams->perspective.projection_shift_horiz); + projection_shift_vert->setDefault (defParams->perspective.projection_shift_vert); + projection_yaw->setDefault (defParams->perspective.projection_yaw); if (pedited) { horiz->setDefaultEditedState (pedited->perspective.horizontal ? Edited : UnEdited); vert->setDefaultEditedState (pedited->perspective.vertical ? Edited : UnEdited); + camera_crop_factor->setDefaultEditedState (pedited->perspective.camera_crop_factor ? Edited : UnEdited); + camera_focal_length->setDefaultEditedState (pedited->perspective.camera_focal_length ? Edited : UnEdited); + camera_pitch->setDefaultEditedState (pedited->perspective.camera_pitch ? Edited : UnEdited); + camera_roll->setDefaultEditedState (pedited->perspective.camera_roll ? Edited : UnEdited); + camera_shift_horiz->setDefaultEditedState (pedited->perspective.camera_shift_horiz ? Edited : UnEdited); + camera_shift_vert->setDefaultEditedState (pedited->perspective.camera_shift_vert ? Edited : UnEdited); + camera_yaw->setDefaultEditedState (pedited->perspective.camera_yaw ? Edited : UnEdited); + projection_pitch->setDefaultEditedState (pedited->perspective.projection_pitch ? Edited : UnEdited); + projection_rotate->setDefaultEditedState (pedited->perspective.projection_rotate ? Edited : UnEdited); + projection_shift_horiz->setDefaultEditedState (pedited->perspective.projection_shift_horiz ? Edited : UnEdited); + projection_shift_vert->setDefaultEditedState (pedited->perspective.projection_shift_vert ? Edited : UnEdited); + projection_yaw->setDefaultEditedState (pedited->perspective.projection_yaw ? Edited : UnEdited); } else { horiz->setDefaultEditedState (Irrelevant); vert->setDefaultEditedState (Irrelevant); + camera_crop_factor->setDefaultEditedState (Irrelevant); + camera_focal_length->setDefaultEditedState (Irrelevant); + camera_pitch->setDefaultEditedState (Irrelevant); + camera_roll->setDefaultEditedState (Irrelevant); + camera_shift_horiz->setDefaultEditedState (Irrelevant); + camera_shift_vert->setDefaultEditedState (Irrelevant); + camera_yaw->setDefaultEditedState (Irrelevant); + projection_pitch->setDefaultEditedState (Irrelevant); + projection_rotate->setDefaultEditedState (Irrelevant); + projection_shift_horiz->setDefaultEditedState (Irrelevant); + projection_shift_vert->setDefaultEditedState (Irrelevant); + projection_yaw->setDefaultEditedState (Irrelevant); } } void PerspCorrection::adjusterChanged(Adjuster* a, double newval) { if (listener) { - listener->panelChanged (EvPerspCorr, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_PERSPECTIVE_HORIZONTAL"), M("TP_PERSPECTIVE_VERTICAL"), horiz->getValue(), vert->getValue())); + if (a == horiz || a == vert) { + listener->panelChanged (EvPerspCorr, + Glib::ustring::compose("%1=%2\n%3=%4", + M("TP_PERSPECTIVE_HORIZONTAL"), + horiz->getValue(), + M("TP_PERSPECTIVE_VERTICAL"), + vert->getValue())); + } else if (a == camera_focal_length || a == camera_crop_factor) { + listener->panelChanged (*event_persp_cam_focal_length, + Glib::ustring::compose("%1=%2\n%3=%4", + M("TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH"), + camera_focal_length->getValue(), + M("TP_PERSPECTIVE_CAMERA_CROP_FACTOR"), + camera_crop_factor->getValue())); + } else if (a == camera_shift_horiz || a == camera_shift_vert) { + listener->panelChanged (*event_persp_cam_shift, + Glib::ustring::compose("%1=%2\n%3=%4", + M("TP_PERSPECTIVE_CAMERA_SHIFT_HORIZONTAL"), + camera_shift_horiz->getValue(), + M("TP_PERSPECTIVE_CAMERA_SHIFT_VERTICAL"), + camera_shift_vert->getValue())); + } else if (a == camera_pitch || a == camera_roll|| a == camera_yaw) { + listener->panelChanged (*event_persp_cam_angle, + Glib::ustring::compose("%1=%2\n%3=%4\n%5=%6", + M("TP_PERSPECTIVE_CAMERA_ROLL"), + camera_roll->getValue(), + M("TP_PERSPECTIVE_CAMERA_YAW"), + camera_yaw->getValue(), + M("TP_PERSPECTIVE_CAMERA_PITCH"), + camera_pitch->getValue())); + } else if (a == projection_shift_horiz || a == projection_shift_vert) { + listener->panelChanged (*event_persp_proj_shift, + Glib::ustring::compose("%1=%2\n%3=%4", + M("TP_PERSPECTIVE_PROJECTION_SHIFT_HORIZONTAL"), + projection_shift_horiz->getValue(), + M("TP_PERSPECTIVE_PROJECTION_SHIFT_VERTICAL"), + projection_shift_vert->getValue())); + } else if (a == projection_rotate) { + listener->panelChanged (*event_persp_proj_rotate, + Glib::ustring::format(projection_rotate->getValue())); + } else if (a == projection_pitch || a == projection_yaw) { + listener->panelChanged (*event_persp_proj_angle, + Glib::ustring::compose("%1=%2\n%3=%4", + M("TP_PERSPECTIVE_PROJECTION_PITCH"), + projection_pitch->getValue(), + M("TP_PERSPECTIVE_PROJECTION_YAW"), + projection_yaw->getValue())); + } } } -void PerspCorrection::setAdjusterBehavior (bool badd) +void PerspCorrection::applyControlLines(void) +{ + if (!lens_geom_listener) { + return; + } + + std::vector control_lines; + int h_count = 0, v_count = 0; + double rot = camera_roll->getValue(); + double pitch = camera_pitch->getValue(); + double yaw = camera_yaw->getValue(); + + lines->toControlLines(control_lines); + + for (unsigned int i = 0; i < lines->size(); i++) { + if (control_lines[i].type == rtengine::ControlLine::HORIZONTAL) { + h_count++; + } else if (control_lines[i].type == rtengine::ControlLine::VERTICAL) { + v_count++; + } + } + lens_geom_listener->autoPerspRequested(v_count > 1, h_count > 1, rot, pitch, + yaw, &control_lines); + + disableListener(); + camera_pitch->setValue(pitch); + camera_roll->setValue(rot); + camera_yaw->setValue(yaw); + enableListener(); + + adjusterChanged(camera_pitch, pitch); +} + +void PerspCorrection::autoCorrectionPressed(Gtk::Button* b) +{ + if (!lens_geom_listener) { + return; + } + + double rot = 0; + double pitch = 0; + double yaw = 0; + + if (b == auto_pitch) { + lens_geom_listener->autoPerspRequested(true, false, rot, pitch, yaw); + } else if (b == auto_yaw) { + lens_geom_listener->autoPerspRequested(false, true, rot, pitch, yaw); + } else if (b == auto_pitch_yaw) { + lens_geom_listener->autoPerspRequested(true, true, rot, pitch, yaw); + } + + disableListener(); + camera_pitch->setValue(pitch); + camera_roll->setValue(rot); + camera_yaw->setValue(yaw); + enableListener(); + + adjusterChanged(camera_pitch, pitch); +} + +void PerspCorrection::methodChanged (void) +{ + + if (!batchMode) { + removeIfThere (this, simple, false); + removeIfThere (this, camera_based, false); + + if (method->get_active_row_number() == 0) { + pack_start (*simple); + } else if (method->get_active_row_number() == 1) { + pack_start (*camera_based); + } + + // If no longer in camera-based mode and control lines are being edited. + if (method->get_active_row_number() != 1 && lines_button_edit->get_active()) { + lines_button_edit->set_active(false); + } + } + + if (listener) { + listener->panelChanged (EvPerspMethod, method->get_active_text ()); + } + +} + +void PerspCorrection::setAdjusterBehavior (bool badd, bool camera_focal_length_add, bool camera_shift_add, bool camera_angle_add, bool projection_angle_add, bool projection_shift_add, bool projection_rotate_add) { horiz->setAddMode(badd); vert->setAddMode(badd); + camera_crop_factor->setAddMode(camera_focal_length_add); + camera_focal_length->setAddMode(camera_focal_length_add); + camera_pitch->setAddMode(camera_angle_add); + camera_roll->setAddMode(camera_angle_add); + camera_shift_horiz->setAddMode(camera_shift_add); + camera_shift_vert->setAddMode(camera_shift_add); + camera_yaw->setAddMode(camera_angle_add); + projection_pitch->setAddMode(projection_angle_add); + projection_rotate->setAddMode(projection_rotate_add); + projection_shift_horiz->setAddMode(projection_shift_add); + projection_shift_vert->setAddMode(projection_shift_add); + projection_yaw->setAddMode(projection_angle_add); +} + +void PerspCorrection::setControlLineEditMode(bool active) +{ + // Only camera-based mode supports control lines, so the mode must be + // switched if not in camera-based mode. + if (method->get_active_row_number() != 1) { + method->set_active(1); + } + + lines_button_edit->set_active(active); +} + +void PerspCorrection::setMetadata (const rtengine::FramesMetaData* metadata) +{ + this->metadata = metadata; } void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp) @@ -110,6 +635,18 @@ void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp) horiz->trimValue(pp->perspective.horizontal); vert->trimValue(pp->perspective.vertical); + camera_crop_factor->trimValue(pp->perspective.camera_crop_factor); + camera_focal_length->trimValue(pp->perspective.camera_focal_length); + camera_pitch->trimValue(pp->perspective.camera_pitch); + camera_roll->trimValue(pp->perspective.camera_roll); + camera_shift_horiz->trimValue(pp->perspective.camera_shift_horiz); + camera_shift_vert->trimValue(pp->perspective.camera_shift_vert); + camera_yaw->trimValue(pp->perspective.camera_yaw); + projection_pitch->trimValue(pp->perspective.projection_pitch); + projection_rotate->trimValue(pp->perspective.projection_rotate); + projection_shift_horiz->trimValue(pp->perspective.projection_shift_horiz); + projection_shift_vert->trimValue(pp->perspective.projection_shift_vert); + projection_yaw->trimValue(pp->perspective.projection_yaw); } void PerspCorrection::setBatchMode (bool batchMode) @@ -118,4 +655,176 @@ void PerspCorrection::setBatchMode (bool batchMode) ToolPanel::setBatchMode (batchMode); horiz->showEditedCB (); vert->showEditedCB (); + camera_crop_factor->showEditedCB (); + camera_focal_length->showEditedCB (); + camera_pitch->showEditedCB (); + camera_roll->showEditedCB (); + camera_shift_horiz->showEditedCB (); + camera_shift_vert->showEditedCB (); + camera_yaw->showEditedCB (); + projection_pitch->showEditedCB (); + projection_rotate->showEditedCB (); + projection_shift_horiz->showEditedCB (); + projection_shift_vert->showEditedCB (); + projection_yaw->showEditedCB (); + + lines_button_edit->set_sensitive(false); + auto_pitch->set_sensitive(false); + auto_yaw->set_sensitive(false); + auto_pitch_yaw->set_sensitive(false); + + method->append (M("GENERAL_UNCHANGED")); +} + +void PerspCorrection::setFocalLengthValue (const ProcParams* pparams, const FramesMetaData* metadata) +{ + const double pp_crop_factor = pparams->perspective.camera_crop_factor; + const double pp_focal_length = pparams->perspective.camera_focal_length; + double default_crop_factor = 1.0; + double default_focal_length = 24.0; + + // Defaults from metadata. + if (metadata && (pp_crop_factor <= 0 || pp_focal_length <= 0)) { + const double fl = metadata->getFocalLen(); + const double fl35 = metadata->getFocalLen35mm(); + + if (fl <= 0) { + if (fl35 <= 0) { + // No focal length data. + } else { + // 35mm focal length available. + default_focal_length = fl35; + } + } else { + if (fl35 <= 0) { + // Focal length available. + default_focal_length = fl; + } else { + // Focal length and 35mm equivalent available. + default_focal_length = fl; + default_crop_factor = fl35 / fl; + } + } + } + + // Change value if those from the ProcParams are invalid. + if (pp_crop_factor > 0) { + camera_crop_factor->setValue(pparams->perspective.camera_crop_factor); + } else { + camera_crop_factor->setDefault(default_crop_factor); + camera_crop_factor->setValue(default_crop_factor); + } + if (pp_focal_length > 0) { + camera_focal_length->setValue(pparams->perspective.camera_focal_length); + } else { + camera_focal_length->setDefault(default_focal_length); + camera_focal_length->setValue(default_focal_length); + } +} + +void PerspCorrection::switchOffEditMode(void) +{ + lines_button_edit->set_active(false); +} + +void PerspCorrection::setEditProvider(EditDataProvider* provider) +{ + lines->setEditProvider(provider); +} + +void PerspCorrection::lineChanged(void) +{ + if (listener) { + listener->panelChanged(EvPerspControlLines, M("HISTORY_CHANGED")); + } +} + +void PerspCorrection::linesApplyButtonPressed(void) +{ + if (method->get_active_row_number() == 1) { + // Calculate perspective distortion if in camera-based mode. + applyControlLines(); + } + lines_button_edit->set_active(false); +} + +void PerspCorrection::linesEditButtonPressed(void) +{ + if (lines_button_edit->get_active()) { // Enter edit mode. + lines->setActive(true); + lines->setDrawMode(true); + render = false; + if (lens_geom_listener) { + lens_geom_listener->updateTransformPreviewRequested(EvPerspRender, false); + } + lines_button_apply->set_sensitive(true); + lines_button_erase->set_sensitive(true); + setCamBasedEventsActive(false); + if (panel_listener) { + panel_listener->controlLineEditModeChanged(true); + } + } else { // Leave edit mode. + setCamBasedEventsActive(true); + lines_button_apply->set_sensitive(false); + lines_button_erase->set_sensitive(false); + render = true; + if (lens_geom_listener) { + lens_geom_listener->updateTransformPreviewRequested(EvPerspRender, true); + } + lines->setDrawMode(false); + lines->setActive(false); + if (panel_listener) { + panel_listener->controlLineEditModeChanged(false); + } + } +} + +void PerspCorrection::linesEraseButtonPressed(void) +{ + lines->removeAll(); +} + +void PerspCorrection::requestApplyControlLines(void) +{ + if (lines_button_apply->is_sensitive()) { + linesApplyButtonPressed(); + } +} + +void PerspCorrection::setCamBasedEventsActive(bool active) +{ + if (active) { + event_persp_cam_focal_length = &EvPerspCamFocalLength; + event_persp_cam_shift = &EvPerspCamShift; + event_persp_cam_angle = &EvPerspCamAngle; + event_persp_proj_shift = &EvPerspProjShift; + event_persp_proj_rotate = &EvPerspProjRotate; + event_persp_proj_angle = &EvPerspProjAngle; + } else { + event_persp_cam_focal_length = &EvPerspCamFocalLengthVoid; + event_persp_cam_shift = &EvPerspCamShiftVoid; + event_persp_cam_angle = &EvPerspCamAngleVoid; + event_persp_proj_shift = &EvPerspProjShiftVoid; + event_persp_proj_rotate = &EvPerspProjRotateVoid; + event_persp_proj_angle = &EvPerspProjAngleVoid; + } +} + +LinesCallbacks::LinesCallbacks(PerspCorrection* tool): + tool(tool) +{ +} + +void LinesCallbacks::lineChanged(void) +{ + if (tool) { + tool->lineChanged(); + } +} + +void LinesCallbacks::switchOffEditMode(void) +{ + if (tool) { + tool->switchOffEditMode(); + } } diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 0564479de..6ba169b60 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -21,8 +21,18 @@ #include #include "adjuster.h" +#include "controllines.h" +#include "lensgeomlistener.h" #include "toolpanel.h" +class PerspCorrectionPanelListener +{ +public: + virtual ~PerspCorrectionPanelListener() = default; + + virtual void controlLineEditModeChanged(bool active) = 0; +}; + class PerspCorrection final : public ToolParamBlock, public AdjusterListener, @@ -30,8 +40,59 @@ class PerspCorrection final : { protected: + bool render = true; + MyComboBoxText* method; + Gtk::VBox* simple; Adjuster* horiz; Adjuster* vert; + Gtk::Button* auto_pitch; + Gtk::Button* auto_yaw; + Gtk::Button* auto_pitch_yaw; + Gtk::VBox* camera_based; + Adjuster* camera_crop_factor; + Adjuster* camera_focal_length; + Adjuster* camera_pitch; + Adjuster* camera_roll; + Adjuster* camera_shift_horiz; + Adjuster* camera_shift_vert; + Adjuster* camera_yaw; + std::unique_ptr lines; + Gtk::Button* lines_button_apply; + Gtk::ToggleButton* lines_button_edit; + Gtk::Button* lines_button_erase; + Adjuster* projection_pitch; + Adjuster* projection_rotate; + Adjuster* projection_shift_horiz; + Adjuster* projection_shift_vert; + Adjuster* projection_yaw; + rtengine::ProcEvent EvPerspCamFocalLength; + rtengine::ProcEvent EvPerspCamShift; + rtengine::ProcEvent EvPerspCamAngle; + rtengine::ProcEvent EvPerspControlLines; + rtengine::ProcEvent EvPerspMethod; + rtengine::ProcEvent EvPerspProjShift; + rtengine::ProcEvent EvPerspProjRotate; + rtengine::ProcEvent EvPerspProjAngle; + rtengine::ProcEvent EvPerspRender; + rtengine::ProcEvent EvPerspCamFocalLengthVoid; + rtengine::ProcEvent EvPerspCamShiftVoid; + rtengine::ProcEvent EvPerspCamAngleVoid; + rtengine::ProcEvent EvPerspProjShiftVoid; + rtengine::ProcEvent EvPerspProjRotateVoid; + rtengine::ProcEvent EvPerspProjAngleVoid; + rtengine::ProcEvent* event_persp_cam_focal_length; + rtengine::ProcEvent* event_persp_cam_shift; + rtengine::ProcEvent* event_persp_cam_angle; + rtengine::ProcEvent* event_persp_proj_shift; + rtengine::ProcEvent* event_persp_proj_rotate; + rtengine::ProcEvent* event_persp_proj_angle; + LensGeomListener* lens_geom_listener; + PerspCorrectionPanelListener* panel_listener; + const rtengine::FramesMetaData* metadata; + + void applyControlLines (void); + void setCamBasedEventsActive (bool active = true); + void setFocalLengthValue (const rtengine::procparams::ProcParams* pparams, const rtengine::FramesMetaData* metadata); public: @@ -43,6 +104,36 @@ public: void setBatchMode (bool batchMode) override; void adjusterChanged (Adjuster* a, double newval) override; - void setAdjusterBehavior (bool badd); + void autoCorrectionPressed (Gtk::Button* b); + void lineChanged (void); + void linesApplyButtonPressed (void); + void linesEditButtonPressed (void); + void linesEraseButtonPressed (void); + void methodChanged (void); + void requestApplyControlLines(void); + void setAdjusterBehavior (bool badd, bool camera_focal_length_add, bool camera_shift_add, bool camera_angle_add, bool projection_angle_add, bool projection_shift_add, bool projection_rotate_add); + void setControlLineEditMode(bool active); + void setEditProvider (EditDataProvider* provider) override; + void setLensGeomListener (LensGeomListener* listener) + { + lens_geom_listener = listener; + } + void setPerspCorrectionPanelListener(PerspCorrectionPanelListener* listener) + { + panel_listener = listener; + } + void setMetadata (const rtengine::FramesMetaData* metadata); + void switchOffEditMode (void); void trimValues (rtengine::procparams::ProcParams* pp) override; }; + +class LinesCallbacks: public ControlLineManager::Callbacks +{ +protected: + PerspCorrection* tool; + +public: + explicit LinesCallbacks(PerspCorrection* tool); + void lineChanged (void) override; + void switchOffEditMode (void) override; +}; diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 6a670733b..162e63f9e 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,11 +1,15 @@ #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 349 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /* Log of version changes + 349 2020-10-29 + replaced Haze removal Luminance checkbox with an adjuster to blend between luminance and normal mode + 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 5268948cc..b18e9e66c 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -10,8 +10,8 @@ * * 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . @@ -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,136 +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_HORIZONTAL") + ", " + M ("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, 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")); @@ -436,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); } @@ -492,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; @@ -506,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); @@ -588,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); @@ -602,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); @@ -639,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); @@ -647,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 @@ -719,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); @@ -737,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) { @@ -790,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); @@ -889,114 +898,140 @@ 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->append(M("PREFERENCES_COMPLEXITY_SIMP")); + complexitylocal->set_active(2); + 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); + zoomOnScrollCB = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_ZOOMONSCROLL"))); + setExpandAlignProperties(zoomOnScrollCB, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*zoomOnScrollCB, *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); + inspectorWindowCB = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_INSPECTORWINDOW"))); + setExpandAlignProperties(inspectorWindowCB, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*inspectorWindowCB, *complexitylocal, Gtk::POS_BOTTOM, 1, 1); + Gtk::Label* inspectorNextStartL = Gtk::manage(new Gtk::Label(Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); + setExpandAlignProperties(inspectorNextStartL, false, false, Gtk::ALIGN_START, Gtk::ALIGN_BASELINE); + workflowGrid->attach_next_to(*inspectorNextStartL, *inspectorWindowCB, Gtk::POS_RIGHT, 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, *zoomOnScrollCB, 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, *inspectorWindowCB, 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 --------------------------------------------- @@ -1057,6 +1092,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); @@ -1077,129 +1113,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) ); @@ -1208,103 +1243,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)); @@ -1318,54 +1353,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"); @@ -1423,23 +1458,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)); @@ -1457,44 +1492,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); @@ -1504,7 +1539,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()) { @@ -1515,26 +1550,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()) { @@ -1545,24 +1580,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; @@ -1570,7 +1605,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; @@ -1578,19 +1613,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, @@ -1611,18 +1646,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(); @@ -1636,9 +1671,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; @@ -1654,42 +1689,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; @@ -1704,17 +1739,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; @@ -1729,59 +1764,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(); @@ -1790,11 +1825,15 @@ void Preferences::storePreferences () moptions.mainNBVertical = editorMode == 1; moptions.curvebboxpos = curveBBoxPosC->get_active_row_number(); + moptions.complexity = complexitylocal->get_active_row_number(); + moptions.inspectorWindow = inspectorWindowCB->get_active(); + moptions.zoomOnScroll = zoomOnScrollCB->get_active(); 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(); @@ -1811,97 +1850,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)); @@ -1919,63 +1957,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()); @@ -1983,32 +2021,36 @@ 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); + inspectorWindowCB->set_active(moptions.inspectorWindow); + zoomOnScrollCB->set_active(moptions.zoomOnScroll); - 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); @@ -2021,50 +2063,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 } @@ -2083,9 +2125,9 @@ void Preferences::savePressed () { } */ -void Preferences::autoMonProfileToggled () +void Preferences::autoMonProfileToggled() { - monProfile->set_sensitive (!cbAutoMonProfile->get_active()); + monProfile->set_sensitive(!cbAutoMonProfile->get_active()); } /* @@ -2094,43 +2136,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 @@ -2138,59 +2180,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; @@ -2203,17 +2245,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; @@ -2226,29 +2268,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 @@ -2256,24 +2298,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() @@ -2288,26 +2330,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(); @@ -2316,48 +2358,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 { @@ -2369,47 +2410,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 @@ -2418,56 +2464,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; @@ -2476,44 +2522,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(); //} } @@ -2521,29 +2568,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); @@ -2552,12 +2600,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..60ca00ea2 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -146,6 +146,11 @@ class Preferences final : Gtk::CheckButton* ctiffserialize; Gtk::ComboBoxText* curveBBoxPosC; + Gtk::ComboBoxText* complexitylocal; + + Gtk::CheckButton* inspectorWindowCB; + Gtk::CheckButton* zoomOnScrollCB; + Gtk::ComboBoxText* themeCBT; Gtk::FontButton* mainFontFB; Gtk::FontButton* colorPickerFontFB; @@ -208,6 +213,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/preprocess.cc b/rtgui/preprocess.cc index 4a663ad07..f33a87a28 100644 --- a/rtgui/preprocess.cc +++ b/rtgui/preprocess.cc @@ -46,9 +46,7 @@ PreProcess::PreProcess () : FoldableToolPanel(this, "preprocess", M("TP_PREPROCE hdThreshold->set_tooltip_markup (M("TP_RAW_HD_TOOLTIP")); hdThreshold->setAdjusterListener (this); - if (hdThreshold->delay < options.adjusterMaxDelay) { - hdThreshold->delay = options.adjusterMaxDelay; - } + hdThreshold->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); hdThreshold->show(); pack_start( *hdThreshold, Gtk::PACK_SHRINK, 4); diff --git a/rtgui/previewhandler.cc b/rtgui/previewhandler.cc index 1dad0676e..76def26b4 100644 --- a/rtgui/previewhandler.cc +++ b/rtgui/previewhandler.cc @@ -110,7 +110,7 @@ void PreviewHandler::delImage(IImage8* i) oldImg->getMutex().unlock(); } - i->free(); + delete i; pih->phandler->previewImgMutex.lock(); pih->phandler->previewImg.clear(); pih->phandler->previewImgMutex.unlock(); 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/rawcacorrection.cc b/rtgui/rawcacorrection.cc index 9e5c592ef..58c7995f9 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -47,24 +47,18 @@ RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_RAWCA caAutoiterations->setAdjusterListener (this); caAutoiterations->set_tooltip_markup(M("TP_RAWCACORR_AUTOIT_TOOLTIP")); - if (caAutoiterations->delay < options.adjusterMaxDelay) { - caAutoiterations->delay = options.adjusterMaxDelay; - } + caAutoiterations->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); caRed = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CARED"), -4.0, 4.0, 0.1, 0, icaredL, icaredR)); caRed->setAdjusterListener (this); - if (caRed->delay < options.adjusterMaxDelay) { - caRed->delay = options.adjusterMaxDelay; - } + caRed->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); caRed->show(); caBlue = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CABLUE"), -8.0, 8.0, 0.1, 0, icablueL, icablueR)); caBlue->setAdjusterListener (this); - if (caBlue->delay < options.adjusterMaxDelay) { - caBlue->delay = options.adjusterMaxDelay; - } + caBlue->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); caBlue->show(); diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index 7548bf4be..7b5ecabc9 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -33,9 +33,7 @@ RAWExposure::RAWExposure () : FoldableToolPanel(this, "rawexposure", M("TP_EXPOS PexPos = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_LINEAR"), 0.1, 16.0, 0.01, 1)); PexPos->setAdjusterListener (this); - if (PexPos->delay < options.adjusterMaxDelay) { - PexPos->delay = options.adjusterMaxDelay; - } + PexPos->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexPos->show(); pack_start( *PexPos, Gtk::PACK_SHRINK, 4);//exposi diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 2fdd8f319..ec250d69b 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -9,6 +9,7 @@ #include "rtimage.h" #include "options.h" #include "../rtengine/color.h" +#include "eventmapper.h" using namespace rtengine; using namespace rtengine::procparams; @@ -25,13 +26,26 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL") nextsigma = 0.; nextminT = 0.; nextmaxT = 0.; + auto m = ProcEventMapper::getInstance(); + EvReticomplex = m->newEvent(DEMOSAIC, "HISTORY_MSG_COMPLEXRETI"); + const RetinexParams default_params; // MAIN Expander ================================================================== + complexmethod = Gtk::manage (new MyComboBoxText ()); + complexmethod->append(M("TP_WAVELET_COMPNORMAL")); + complexmethod->append(M("TP_WAVELET_COMPEXPERT")); + complexmethodconn = complexmethod->signal_changed().connect(sigc::mem_fun(*this, &Retinex::complexmethodChanged)); + complexmethod->set_tooltip_text(M("TP_WAVELET_COMPLEX_TOOLTIP")); + Gtk::HBox* const complexHBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const complexLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_COMPLEXLAB") + ":")); + complexHBox->pack_start(*complexLabel, Gtk::PACK_SHRINK, 4); + complexHBox->pack_start(*complexmethod); + pack_start(*complexHBox); Gtk::Grid *retinexGrid = Gtk::manage ( new Gtk::Grid()); @@ -116,7 +130,8 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL") // MAP (MASK) Frame --------------------------------------------------------------- - Gtk::Frame *maskFrame = Gtk::manage (new Gtk::Frame (M ("TP_RETINEX_LABEL_MASK")) ); + // Gtk::Frame *maskFrame = Gtk::manage (new Gtk::Frame (M ("TP_RETINEX_LABEL_MASK")) ); + maskFrame = Gtk::manage (new Gtk::Frame (M ("TP_RETINEX_LABEL_MASK")) ); setExpandAlignProperties (maskFrame, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); Gtk::Grid *maskGrid = Gtk::manage ( new Gtk::Grid()); @@ -384,7 +399,6 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL") Gtk::Grid *tranGrid = Gtk::manage (new Gtk::Grid()); setExpandAlignProperties (tranGrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); - const RetinexParams default_params; // Transmission map curve transmissionCurveEditorG = new CurveEditorGroup (options.lastRetinexDir, M ("TP_RETINEX_TRANSMISSION")); @@ -488,112 +502,58 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL") str->setAdjusterListener (this); - - if (str->delay < 200) { - str->delay = 200; - } + str->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); scal->setAdjusterListener (this); - - if (scal->delay < 200) { - scal->delay = 200; - } + scal->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); iter->setAdjusterListener (this); - - if (iter->delay < 200) { - iter->delay = 200; - } + iter->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); grad->setAdjusterListener (this); - - if (grad->delay < 200) { - grad->delay = 200; - } + grad->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); grads->setAdjusterListener (this); - - if (grads->delay < 200) { - grads->delay = 200; - } + grads->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); gam->setAdjusterListener (this); - - if (gam->delay < 500) { - gam->delay = 500; - } + gam->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay) * 2.5f); slope->setAdjusterListener (this); - - if (slope->delay < 500) { - slope->delay = 500; - } + slope->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay) * 2.5f); neigh->setAdjusterListener (this); - - if (neigh->delay < 200) { - neigh->delay = 200; - } + neigh->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); offs->setAdjusterListener (this); - - if (offs->delay < 200) { - offs->delay = 200; - } + offs->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); vart->setAdjusterListener (this); - - if (vart->delay < 200) { - vart->delay = 200; - } + offs->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); limd->setAdjusterListener (this); - - if (limd->delay < 200) { - limd->delay = 200; - } + limd->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); highl->setAdjusterListener (this); - - if (highl->delay < 200) { - highl->delay = 200; - } + highl->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); radius->setAdjusterListener (this); - - if (radius->delay < 200) { - radius->delay = 200; - } + radius->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); highlights->setAdjusterListener (this); - - if (highlights->delay < 200) { - highlights->delay = 200; - } + highlights->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); h_tonalwidth->setAdjusterListener (this); - - if (h_tonalwidth->delay < 200) { - h_tonalwidth->delay = 200; - } + h_tonalwidth->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); shadows->setAdjusterListener (this); - - if (shadows->delay < 200) { - shadows->delay = 200; - } + shadows->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); s_tonalwidth->setAdjusterListener (this); - - if (s_tonalwidth->delay < 200) { - s_tonalwidth->delay = 200; - } + s_tonalwidth->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); skal->setAdjusterListener (this); - - if (skal->delay < 200) { - skal->delay = 200; - } + skal->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); disableListener(); retinexColorSpaceChanged(); @@ -628,12 +588,14 @@ void Retinex::neutral_pressed () limd->resetValue (false); highl->resetValue (false); gam->resetValue (false); + skal->resetValue (false); slope->resetValue (false); highlights->resetValue (false); h_tonalwidth->resetValue (false); shadows->resetValue (false); s_tonalwidth->resetValue (false); radius->resetValue (false); + medianmap->set_active (false); mapMethod->set_active (0); viewMethod->set_active (0); retinexMethod->set_active (2); @@ -742,7 +704,53 @@ void Retinex::updateTrans () } } +void Retinex::convertParamToNormal() +{ + const RetinexParams def_params; + disableListener(); + iter->setValue(def_params.iter); + viewMethod->set_active(0); + mapMethod->set_active(0); + cdshape->reset(); + cdshapeH->reset(); + lhshape->reset(); + transmissionShape->reset(); + medianmap->set_active(def_params.medianmap); + enableListener(); +} +void Retinex::updateGUIToMode(int mode) +{ + + if(mode ==0) { + iterFrame->hide(); + maskFrame->hide(); + equalFrame->hide(); + viewMethod->hide(); + mapMethod->hide(); + transmissionCurveEditorG->hide(); + medianmap->hide(); + } else { + iterFrame->show(); + maskFrame->show(); + equalFrame->show(); + viewMethod->show(); + transmissionCurveEditorG->show(); + medianmap->show(); + mapMethod->show(); + if (iter->getIntValue() > 1) { + grad->set_sensitive (true); + scal->set_sensitive (true); + grads->set_sensitive (true); + } else { + grad->set_sensitive (false); + scal->set_sensitive (false); + grads->set_sensitive (false); + } + + } + +} void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) { @@ -752,6 +760,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) gammaretinexConn.block (true); mapMethodConn.block (true); viewMethodConn.block (true); + complexmethodconn.block (true); if (pedited) { @@ -775,6 +784,9 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) shadows->setEditedState (pedited->retinex.shadows ? Edited : UnEdited); s_tonalwidth->setEditedState (pedited->retinex.stonalwidth ? Edited : UnEdited); + if (!pedited->retinex.complexmethod) { + complexmethod->set_active_text (M ("GENERAL_UNCHANGED")); + } if (!pedited->retinex.retinexMethod) { retinexMethod->set_active_text (M ("GENERAL_UNCHANGED")); @@ -844,6 +856,13 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) medianmapConn.block (false); lastmedianmap = pp->retinex.medianmap; + if (pp->retinex.complexmethod == "normal") { + complexmethod->set_active(0); + } else if (pp->retinex.complexmethod == "expert") { + complexmethod->set_active(1); + } + + if (pp->retinex.retinexMethod == "low") { retinexMethod->set_active (0); } else if (pp->retinex.retinexMethod == "uni") { @@ -906,6 +925,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) mapMethodChanged (); viewMethodChanged (); + medianmapConn.block (true); medianmapChanged (); medianmapConn.block (false); @@ -914,7 +934,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) cdshapeH->setCurve (pp->retinex.cdHcurve); lhshape->setCurve (pp->retinex.lhcurve); mapshape->setCurve (pp->retinex.mapcurve); - + retinexMethodConn.block (false); retinexColorSpaceConn.block (false); gammaretinexConn.block (false); @@ -923,8 +943,18 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) transmissionShape->setCurve (pp->retinex.transmissionCurve); gaintransmissionShape->setCurve (pp->retinex.gaintransmissionCurve); + complexmethodconn.block (false); enableListener (); + + if (complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + // convertParamToNormal(); + + } else { + updateGUIToMode(1); + } + } @@ -961,6 +991,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.stonalwidth = (int)s_tonalwidth->getValue (); if (pedited) { + pedited->retinex.complexmethod = complexmethod->get_active_text() != M ("GENERAL_UNCHANGED"); pedited->retinex.retinexMethod = retinexMethod->get_active_text() != M ("GENERAL_UNCHANGED"); pedited->retinex.retinexcolorspace = retinexcolorspace->get_active_text() != M ("GENERAL_UNCHANGED"); pedited->retinex.gammaretinex = gammaretinex->get_active_text() != M ("GENERAL_UNCHANGED"); @@ -998,6 +1029,12 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) } + if (complexmethod->get_active_row_number() == 0) { + pp->retinex.complexmethod = "normal"; + } else if (complexmethod->get_active_row_number() == 1) { + pp->retinex.complexmethod = "expert"; + } + if (retinexMethod->get_active_row_number() == 0) { pp->retinex.retinexMethod = "low"; } else if (retinexMethod->get_active_row_number() == 1) { @@ -1056,6 +1093,27 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) } +void Retinex::complexmethodChanged() +{ + + if (!batchMode) { + if (complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + convertParamToNormal(); + + } else { + updateGUIToMode(1); + } + } + + if (listener) { + listener->panelChanged(EvReticomplex, complexmethod->get_active_text()); + } + +} + + + void Retinex::retinexMethodChanged() { @@ -1138,8 +1196,11 @@ void Retinex::viewMethodChanged() limd->show(); transmissionCurveEditorG->show(); medianmap->show(); - - iterFrame->show(); + if (complexmethod->get_active_row_number() == 0) { + iterFrame->hide(); + } else { + iterFrame->show(); + } /* iter->show(); scal->show(); @@ -1522,6 +1583,7 @@ void Retinex::setBatchMode (bool batchMode) h_tonalwidth->showEditedCB (); shadows->showEditedCB (); s_tonalwidth->showEditedCB (); + // complexmethod->append(M("GENERAL_UNCHANGED")); skal->showEditedCB (); curveEditorGD->setBatchMode (batchMode); diff --git a/rtgui/retinex.h b/rtgui/retinex.h index dea65daab..bf480c9cc 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -28,6 +28,7 @@ class Retinex final : { private: IdleRegister idle_register; + rtengine::ProcEvent EvReticomplex; protected: CurveEditorGroup* curveEditorGD; @@ -72,6 +73,9 @@ protected: MyComboBoxText* mapMethod; MyComboBoxText* viewMethod; Gtk::CheckButton* medianmap; + MyComboBoxText* complexmethod; + sigc::connection complexmethodconn; + double nextmin; double nextmax; double nextminiT; @@ -87,6 +91,7 @@ protected: Gtk::Frame *gainFrame; Gtk::Frame *tranFrame; Gtk::Frame *iterFrame; + Gtk::Frame *maskFrame; Gtk::Frame *equalFrame; DiagonalCurveEditor* cdshape; @@ -148,4 +153,7 @@ public: private: void foldAllButMe(GdkEventButton* event, MyExpander *expander); + void convertParamToNormal(); + void updateGUIToMode(int mode); + void complexmethodChanged(); }; 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/sharpenedge.cc b/rtgui/sharpenedge.cc index 939de7979..e00d919c3 100644 --- a/rtgui/sharpenedge.cc +++ b/rtgui/sharpenedge.cc @@ -35,16 +35,12 @@ SharpenEdge::SharpenEdge () : FoldableToolPanel(this, "sharpenedge", M("TP_SHARP passes = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_PASSES"), 1, 4, 1, 2)); passes->setAdjusterListener (this); - if (passes->delay < options.adjusterMaxDelay) { - passes->delay = options.adjusterMaxDelay; - } + passes->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); amount = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_AMOUNT"), 0, 100, 1, 50)); amount->setAdjusterListener (this); - if (amount->delay < options.adjusterMaxDelay) { - amount->delay = options.adjusterMaxDelay; - } + amount->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); threechannels = Gtk::manage(new Gtk::CheckButton((M("TP_SHARPENEDGE_THREE"))));// L + a + b threechannels->set_active (false); diff --git a/rtgui/soundman.cc b/rtgui/soundman.cc index a4cf5337b..d038ffd72 100644 --- a/rtgui/soundman.cc +++ b/rtgui/soundman.cc @@ -26,7 +26,7 @@ #include #endif -#ifdef __linux__ +#if defined(__linux__) && defined(USE_CANBERRA) #include #endif @@ -67,7 +67,7 @@ void SoundManager::playSoundAsync(const Glib::ustring &sound) wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (sound.c_str(), -1, NULL, NULL, NULL); PlaySoundW(wfilename, NULL, sndParam); g_free( wfilename ); -#elif defined(__linux__) +#elif defined(__linux__) && defined(USE_CANBERRA) ca_context_play(ca_gtk_context_get(), 0, CA_PROP_EVENT_ID, sound.c_str(), CA_PROP_MEDIA_FILENAME, sound.c_str(), NULL); #endif } diff --git a/rtgui/thumbbrowserentrybase.cc b/rtgui/thumbbrowserentrybase.cc index 3840c8bf9..0c71cea2c 100644 --- a/rtgui/thumbbrowserentrybase.cc +++ b/rtgui/thumbbrowserentrybase.cc @@ -135,7 +135,6 @@ ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : textGap(6), sideMargin(8), lowerMargin(8), - preview(nullptr), dispname(Glib::path_get_basename(fname)), buttonSet(nullptr), width(0), @@ -171,7 +170,6 @@ ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : ThumbBrowserEntryBase::~ThumbBrowserEntryBase () { - delete[] preview; delete buttonSet; } @@ -207,7 +205,7 @@ void ThumbBrowserEntryBase::updateBackBuffer () bbSelected = selected; bbFramed = framed; - bbPreview = preview; + bbPreview = preview.data(); Cairo::RefPtr cc = Cairo::Context::create(surface); @@ -237,16 +235,20 @@ void ThumbBrowserEntryBase::updateBackBuffer () if (buttonSet) { int tmp; - buttonSet->getAllocatedDimensions (tmp, bsHeight); + buttonSet->getAllocatedDimensions(tmp, bsHeight); } + int infow, infoh; + getTextSizes(infow, infoh); + // draw preview frame //backBuffer->draw_rectangle (cc, false, (exp_width-prew)/2, upperMargin+bsHeight, prew+1, preh+1); // draw thumbnail image - if (preview) { + if (!preview.empty()) { prex = borderWidth + (exp_width - prew) / 2; - prey = upperMargin + bsHeight + borderWidth; - backBuffer->copyRGBCharData(preview, 0, 0, prew, preh, prew * 3, prex, prey); + const int hh = exp_height - (upperMargin + bsHeight + borderWidth + infoh + lowerMargin); + prey = upperMargin + bsHeight + borderWidth + std::max((hh - preh) / 2, 0); + backBuffer->copyRGBCharData(preview.data(), 0, 0, prew, preh, prew * 3, prex, prey); } customBackBufferUpdate (cc); @@ -255,9 +257,6 @@ void ThumbBrowserEntryBase::updateBackBuffer () bbIcons = getIconsOnImageArea (); bbSpecificityIcons = getSpecificityIconsOnImageArea (); - int infow, infoh; - getTextSizes (infow, infoh); - int iofs_x = 4, iofs_y = 4; int istartx = prex; int istarty = prey; @@ -356,7 +355,7 @@ void ThumbBrowserEntryBase::updateBackBuffer () textposx_dt = 0; } - textposy = upperMargin + bsHeight + 2 * borderWidth + preh + borderWidth + textGap; + textposy = exp_height - lowerMargin - infoh; textw = exp_width - 2 * textGap; if (selected) { @@ -556,10 +555,7 @@ void ThumbBrowserEntryBase::resize (int h) } if (preh != old_preh || prew != old_prew) { // if new thumbnail height or new orientation - if (preview) { - delete [] preview; - preview = nullptr; - } + preview.clear(); refreshThumbnailImage (); } else if (backBuffer) { backBuffer->setDirty(true); // This will force a backBuffer update on queue_draw @@ -620,7 +616,7 @@ void ThumbBrowserEntryBase::draw (Cairo::RefPtr cc) bbHeight = backBuffer->getHeight(); } - if (!backBuffer || selected != bbSelected || framed != bbFramed || preview != bbPreview + if (!backBuffer || selected != bbSelected || framed != bbFramed || preview.data() != bbPreview || exp_width != bbWidth || exp_height != bbHeight || getIconsOnImageArea () != bbIcons || getSpecificityIconsOnImageArea() != bbSpecificityIcons || backBuffer->isDirty()) { @@ -680,7 +676,7 @@ rtengine::Coord2D ThumbBrowserEntryBase::getPosInImgSpace (int x, int y) const { rtengine::Coord2D coord(-1., -1.); - if (preview) { + if (!preview.empty()) { x -= ofsX + startx; y -= ofsY + starty; diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index dbc6cf73e..764f806fd 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -59,7 +59,7 @@ protected: MyRWMutex lockRW; // Locks access to all image thumb changing actions - guint8* preview; // holds the preview image. used in updateBackBuffer. TODO Olli: Make a cache to reduce mem significantly + std::vector preview; // holds the preview image. used in updateBackBuffer. Glib::ustring dispname; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 7452c9d72..324a0c0c1 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" @@ -120,7 +121,7 @@ void Thumbnail::_generateThumbnailImage () tpp = nullptr; delete [] lastImg; lastImg = nullptr; - tw = -1; + tw = options.maxThumbnailWidth; th = options.maxThumbnailHeight; imgRatio = -1.; @@ -137,20 +138,20 @@ void Thumbnail::_generateThumbnailImage () if (ext == "jpg" || ext == "jpeg") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); if (tpp) { cfs.format = FT_Jpeg; } } else if (ext == "png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); if (tpp) { cfs.format = FT_Png; } } else if (ext == "tif" || ext == "tiff") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); if (tpp) { cfs.format = FT_Tiff; @@ -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 @@ -587,10 +589,13 @@ void Thumbnail::decreaseRef () cachemgr->closeThumbnail (this); } -int Thumbnail::getThumbnailWidth (const int h, const rtengine::procparams::ProcParams *pparams) const +void Thumbnail::getThumbnailSize(int &w, int &h, const rtengine::procparams::ProcParams *pparams) { + MyMutex::MyLock lock(mutex); + int tw_ = tw; int th_ = th; + float imgRatio_ = imgRatio; if (pparams) { @@ -615,10 +620,16 @@ int Thumbnail::getThumbnailWidth (const int h, const rtengine::procparams::ProcP } } - if (imgRatio_ > 0.f) { - return imgRatio_ * h; + if (imgRatio_ > 0.) { + w = imgRatio_ * static_cast(h); } else { - return tw_ * h / th_; + w = tw_ * h / th_; + } + + if (w > options.maxThumbnailWidth) { + const float s = static_cast(options.maxThumbnailWidth) / w; + w = options.maxThumbnailWidth; + h = std::max(h * s, 1); } } @@ -873,7 +884,7 @@ void Thumbnail::_loadThumbnail(bool firstTrial) if (!succ && firstTrial) { _generateThumbnailImage (); - if (cfs.supported && firstTrial) { + if (cfs.supported) { _loadThumbnail (false); } @@ -993,7 +1004,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/thumbnail.h b/rtgui/thumbnail.h index c22c80cea..aee5ee0a6 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -119,7 +119,7 @@ public: // unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w rtengine::IImage8* processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); - int getThumbnailWidth (int h, const rtengine::procparams::ProcParams *pparams = nullptr) const; + void getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams = nullptr); void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); void getOriginalSize (int& w, int& h); diff --git a/rtgui/toolbar.cc b/rtgui/toolbar.cc index 99c4196c6..5cdfc2787 100644 --- a/rtgui/toolbar.cc +++ b/rtgui/toolbar.cc @@ -77,6 +77,12 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n pack_start (*straTool); + perspTool = Gtk::manage(new Gtk::ToggleButton()); + Gtk::Image* perspimg = Gtk::manage(new RTImage("perspective-vertical-bottom.png")); + perspTool->set_image(*perspimg); + perspTool->set_relief(Gtk::RELIEF_NONE); + pack_start(*perspTool); + handTool->set_active (true); current = TMHand; @@ -87,12 +93,14 @@ ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(n cpConn = colPickerTool->signal_button_press_event().connect_notify( sigc::mem_fun(*this, &ToolBar::colPicker_pressed)); cropConn = cropTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::crop_pressed)); straConn = straTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::stra_pressed)); + perspConn = perspTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::persp_pressed)); handTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_HAND")); wbTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_WB")); colPickerTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_COLORPICKER")); cropTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_CROP")); straTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_STRAIGHTEN")); + perspTool->set_tooltip_markup(M("TOOLBAR_TOOLTIP_PERSPECTIVE")); } // @@ -107,9 +115,10 @@ void ToolBar::setTool (ToolMode tool) ConnectionBlocker handBlocker(handConn); ConnectionBlocker straBlocker(straConn); ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); - stopEdit = tool == TMHand && handTool->get_active() && editingMode; + stopEdit = tool == TMHand && (handTool->get_active() || (perspTool && perspTool->get_active())) && editingMode && !blockEdit; handTool->set_active (false); @@ -122,6 +131,9 @@ void ToolBar::setTool (ToolMode tool) if (colPickerTool) { colPickerTool->set_active (false); } + if (perspTool) { + perspTool->set_active(false); + } if (tool == TMHand) { handTool->set_active (true); @@ -138,6 +150,12 @@ void ToolBar::setTool (ToolMode tool) if (colPickerTool) { colPickerTool->set_active (true); } + } else if (tool == TMPerspective) { + if (perspTool) { + perspTool->set_active(true); + // Perspective is a hand tool, but has its own button. + handTool->set_image(*handimg); + } } current = tool; @@ -160,6 +178,7 @@ void ToolBar::startEditMode() ConnectionBlocker handBlocker(handConn); ConnectionBlocker straBlocker(straConn); ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); if (current != TMHand) { @@ -172,6 +191,9 @@ void ToolBar::startEditMode() cropTool->set_active (false); straTool->set_active (false); + if (perspTool) { + perspTool->set_active(false); + } current = TMHand; } handTool->set_active (true); @@ -204,9 +226,10 @@ void ToolBar::hand_pressed () ConnectionBlocker handBlocker(handConn); ConnectionBlocker straBlocker(straConn); ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); - if (editingMode) { + if (editingMode && !blockEdit) { stopEditMode(); if (listener) { listener->editModeSwitchedOff (); @@ -222,6 +245,9 @@ void ToolBar::hand_pressed () cropTool->set_active (false); straTool->set_active (false); + if (perspTool) { + perspTool->set_active(false); + } handTool->set_active (true); if (current != TMHand) { @@ -244,6 +270,7 @@ void ToolBar::wb_pressed () ConnectionBlocker handBlocker(handConn); ConnectionBlocker straBlocker(straConn); ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); if (current != TMSpotWB) { @@ -256,6 +283,9 @@ void ToolBar::wb_pressed () handTool->set_active (false); cropTool->set_active (false); straTool->set_active (false); + if (perspTool) { + perspTool->set_active(false); + } if (colPickerTool) { colPickerTool->set_active(false); } @@ -288,10 +318,13 @@ void ToolBar::colPicker_pressed (GdkEventButton* event) wbTool->set_active (false); } straTool->set_active (false); + if (perspTool) { + perspTool->set_active(false); + } 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 (); @@ -359,6 +392,7 @@ void ToolBar::crop_pressed () ConnectionBlocker handBlocker(handConn); ConnectionBlocker straBlocker(straConn); ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); if (editingMode) { @@ -376,6 +410,9 @@ void ToolBar::crop_pressed () } straTool->set_active (false); + if (perspTool) { + perspTool->set_active(false); + } cropTool->set_active (true); if (current != TMCropSelect) { @@ -399,6 +436,7 @@ void ToolBar::stra_pressed () ConnectionBlocker handBlocker(handConn); ConnectionBlocker straBlocker(straConn); ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); if (editingMode) { @@ -416,6 +454,9 @@ void ToolBar::stra_pressed () } cropTool->set_active (false); + if (perspTool) { + perspTool->set_active(false); + } straTool->set_active (true); if (current != TMStraighten) { @@ -432,6 +473,35 @@ void ToolBar::stra_pressed () } } +void ToolBar::persp_pressed () +{ + if (listener && !perspTool->get_active()) { + listener->toolDeselected(TMPerspective); + return; + } + + // Unlike other modes, mode switching is handled by the perspective panel. + { + ConnectionBlocker handBlocker(handConn); + ConnectionBlocker straBlocker(straConn); + ConnectionBlocker cropBlocker(cropConn); + ConnectionBlocker perspBlocker(perspConn); + ConnectionBlocker wbWasBlocked(wbTool, wbConn), cpWasBlocked(colPickerTool, cpConn); + + if (editingMode) { + stopEditMode(); + if (listener) { + listener->editModeSwitchedOff(); + } + } + + } + + if (listener) { + listener->toolSelected(TMPerspective); + } +} + bool ToolBar::handleShortcutKey (GdkEventKey* event) { @@ -485,6 +555,11 @@ void ToolBar::setBatchMode() removeIfThere(this, colPickerTool, false); colPickerTool = nullptr; } + if (perspTool) { + perspConn.disconnect(); + removeIfThere(this, perspTool, false); + perspTool = nullptr; + } allowNoTool = true; switch (current) { diff --git a/rtgui/toolbar.h b/rtgui/toolbar.h index 8ec6bb615..85a0c3345 100644 --- a/rtgui/toolbar.h +++ b/rtgui/toolbar.h @@ -30,6 +30,8 @@ class ToolBarListener public: virtual ~ToolBarListener() = default; + /// Callback when a tool is deselected. WARNING: Not yet called for most tools. + virtual void toolDeselected(ToolMode tool) = 0; /// Callback when a tool is selected virtual void toolSelected(ToolMode tool) = 0; @@ -51,6 +53,7 @@ private: void colPicker_pressed (GdkEventButton* event); void crop_pressed (); void stra_pressed (); + void persp_pressed (); bool showColorPickers(bool showCP); void switchColorPickersVisibility(); @@ -60,16 +63,19 @@ protected: Gtk::ToggleButton* colPickerTool; Gtk::ToggleButton* cropTool; Gtk::ToggleButton* straTool; + Gtk::ToggleButton* perspTool; ToolBarListener* listener; LockablePickerToolListener* pickerListener; 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; sigc::connection cropConn; sigc::connection straConn; + sigc::connection perspConn; public: ToolBar (); @@ -99,4 +105,9 @@ public: bool handleShortcutKey (GdkEventKey* event); void setBatchMode(); + + void blockEditDeactivation(bool cond = true) + { + blockEdit = cond; + } }; diff --git a/rtgui/toolenum.h b/rtgui/toolenum.h index c3bc873f1..424afca87 100644 --- a/rtgui/toolenum.h +++ b/rtgui/toolenum.h @@ -18,4 +18,4 @@ */ #pragma once -enum ToolMode {TMNone = -1, TMHand = 0, TMSpotWB = 1, TMCropSelect = 2, TMStraighten = 3, TMColorPicker = 4}; +enum ToolMode {TMNone = -1, TMHand = 0, TMSpotWB = 1, TMCropSelect = 2, TMStraighten = 3, TMColorPicker = 4, TMPerspective = 5}; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 3e7a533c9..71fa14519 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -26,12 +26,13 @@ #include "../rtengine/dfmanager.h" #include "../rtengine/ffmanager.h" #include "../rtengine/improcfun.h" +#include "../rtengine/perspectivecorrection.h" #include "../rtengine/procevents.h" #include "../rtengine/refreshmap.h" 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 ()); @@ -41,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,52 +54,53 @@ 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 ()); + 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 ()); + 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, // and a separate Demosaic and Black Level tool will be created in an "X-Trans sensor" tool @@ -122,6 +125,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (detailsPanel, sharpenMicro); addfavoritePanel (colorPanel, hsvequalizer); addfavoritePanel (colorPanel, filmSimulation); + addfavoritePanel (colorPanel, filmNegative); addfavoritePanel (colorPanel, softlight); addfavoritePanel (colorPanel, rgbcurves); addfavoritePanel (colorPanel, colortoning); @@ -138,6 +142,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); @@ -162,7 +168,6 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (rawPanel, preprocess); addfavoritePanel (rawPanel, darkframe); addfavoritePanel (rawPanel, flatfield); - addfavoritePanel (rawPanel, filmNegative); addfavoritePanel (rawPanel, pdSharpening); int favoriteCount = 0; @@ -176,25 +181,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); @@ -219,6 +223,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); @@ -232,10 +240,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); } @@ -243,45 +252,79 @@ 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); - distortion->setLensGeomListener (this); - crop->setCropPanelListener (this); - icm->setICMPanelListener (this); - filmNegative->setFilmNegProvider (this); + for (auto toolPanel : toolPanels) { + toolPanel->setListener(this); + } - toolBar = new ToolBar (); - toolBar->setToolBarListener (this); + whitebalance->setWBProvider(this); + whitebalance->setSpotWBListener(this); + darkframe->setDFProvider(this); + flatfield->setFFProvider(this); + lensgeom->setLensGeomListener(this); + rotate->setLensGeomListener(this); + perspective->setLensGeomListener(this); + perspective->setPerspCorrectionPanelListener(this); + distortion->setLensGeomListener(this); + crop->setCropPanelListener(this); + icm->setICMPanelListener(this); + filmNegative->setFilmNegProvider(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(); @@ -298,13 +341,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) { @@ -319,16 +366,15 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt bayerprocess->FoldableToolPanel::show(); bayerpreprocess->FoldableToolPanel::show(); rawcacorrection->FoldableToolPanel::show(); + preprocessWB->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); - filmNegative->FoldableToolPanel::show(); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; } ); - } - else if (isXtrans) { + } else if (isXtrans) { idle_register.add( [this]() -> bool { @@ -340,16 +386,15 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt bayerprocess->FoldableToolPanel::hide(); bayerpreprocess->FoldableToolPanel::hide(); rawcacorrection->FoldableToolPanel::hide(); + preprocessWB->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); - filmNegative->FoldableToolPanel::show(); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; } ); - } - else if (isMono) { + } else if (isMono) { idle_register.add( [this]() -> bool { @@ -364,7 +409,6 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::show(); - filmNegative->FoldableToolPanel::hide(); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -385,7 +429,6 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::hide(); - filmNegative->FoldableToolPanel::hide(); pdSharpening->FoldableToolPanel::hide(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -407,7 +450,6 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::hide(); - filmNegative->FoldableToolPanel::hide(); pdSharpening->FoldableToolPanel::hide(); retinex->FoldableToolPanel::setGrayedOut(true); return false; @@ -453,18 +495,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); } } @@ -482,34 +524,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, maskStruc.logMask, maskStruc.maskMask); + } 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, 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( @@ -526,7 +612,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 @@ -539,19 +625,19 @@ 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(); + filterRawRefresh = pe.raw.isUnchanged() && pe.lensProf.isUnchanged() && pe.retinex.isUnchanged() && pe.pdsharpening.isUnchanged(); } *params = *mergedParams; @@ -568,35 +654,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, 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) @@ -608,59 +720,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->setFilmNegListener (filmNegative); - flatfield->setShortcutPath (Glib::path_get_dirname (ipc->getInitialImage()->getFileName())); + 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())); - icm->setRawMeta (raw, (const rtengine::FramesData*)pMetaData); - lensProf->setRawMeta (raw, 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; } } @@ -716,33 +830,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); } @@ -753,15 +874,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); } } @@ -770,7 +891,8 @@ void ToolPanelCoordinator::sharpMaskSelected(bool sharpMask) if (!ipc) { return; } - ipc->beginUpdateParams (); + + ipc->beginUpdateParams(); ipc->endUpdateParams (ipc->setSharpMask(sharpMask)); } @@ -811,7 +933,7 @@ CropGUIListener* ToolPanelCoordinator::startCropEditing(Thumbnail* thm) return crop; } -void ToolPanelCoordinator::autoCropRequested () +void ToolPanelCoordinator::autoCropRequested() { if (!ipc) { @@ -819,12 +941,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() @@ -838,11 +960,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; @@ -861,12 +983,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; @@ -881,49 +1003,90 @@ Glib::ustring ToolPanelCoordinator::GetCurrentImageFilePath() return ipc->getInitialImage()->getFileName(); } -void ToolPanelCoordinator::straightenRequested () +void ToolPanelCoordinator::straightenRequested() { if (!ipc) { return; } - toolBar->setTool (TMStraighten); + toolBar->setTool(TMStraighten); } -double ToolPanelCoordinator::autoDistorRequested () +void ToolPanelCoordinator::autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector *lines) +{ + if (!(ipc && (corr_pitch || corr_yaw))) { + return; + } + + rtengine::ImageSource *src = dynamic_cast(ipc->getInitialImage()); + if (!src) { + return; + } + + rtengine::procparams::ProcParams params; + ipc->getParams(¶ms); + + auto res = rtengine::PerspectiveCorrection::autocompute(src, corr_pitch, corr_yaw, ¶ms, src->getMetaData(), lines); + rot = res.angle; + pitch = res.pitch; + yaw = res.yaw; +} + +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::spotWBRequested (int size) +void ToolPanelCoordinator::updateTransformPreviewRequested(rtengine::ProcEvent event, bool render_perspective) +{ + if (!ipc) { + return; + } + + ipc->beginUpdateParams()->perspective.render = render_perspective; + ipc->endUpdateParams(event); +} + +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::controlLineEditModeChanged(bool active) +{ + if (!ipc) { + return; + } + + if (active) { + toolBar->setTool(TMPerspective); + } } void ToolPanelCoordinator::saveInputICCReference(const Glib::ustring& fname, bool apply_wb) { if (ipc) { - ipc->saveInputICCReference (fname, apply_wb); + ipc->saveInputICCReference(fname, apply_wb); } } @@ -947,7 +1110,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) { @@ -957,10 +1120,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); } } } @@ -968,7 +1131,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 @@ -984,31 +1147,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; } } @@ -1016,7 +1183,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; @@ -1029,20 +1196,31 @@ 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::toolDeselected(ToolMode tool) +{ + if (tool == TMPerspective) { + perspective->requestApplyControlLines(); + } +} + +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) { @@ -1055,18 +1233,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) { @@ -1074,42 +1257,54 @@ 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; + } + + case TMPerspective: { + toolBar->blockEditDeactivation(false); // To allow deactivating Locallab when switching to another tool using toolbar + perspective->setControlLineEditMode(true); + perspective->setExpanded(true); + bool isFavorite = checkFavorite(perspective); + if (!isFavorite) { + isFavorite = checkFavorite(lensgeom); + 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); } } -bool ToolPanelCoordinator::getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, std::array& newExps) +bool ToolPanelCoordinator::getFilmNegativeSpot(rtengine::Coord spot, int spotSize, RGB &refInput, RGB &refOutput) { - return ipc && ipc->getFilmNegativeExponents(spotA.x, spotA.y, spotB.x, spotB.y, newExps); + return ipc && ipc->getFilmNegativeSpot(spot.x, spot.y, spotSize, refInput, refOutput); } - -bool ToolPanelCoordinator::getRawSpotValues(rtengine::Coord spot, int spotSize, std::array& rawValues) -{ - return ipc && ipc->getRawSpotValues(spot.x, spot.y, spotSize, rawValues); -} \ No newline at end of file diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index e938de47b..7adf45b08 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -54,6 +54,7 @@ #include "lensgeomlistener.h" #include "lensprofile.h" #include "localcontrast.h" +#include "locallab.h" #include "pcvignette.h" #include "pdsharpening.h" #include "perspective.h" @@ -102,6 +103,7 @@ class ToolPanelCoordinator : public LensGeomListener, public SpotWBListener, public CropPanelListener, + public PerspCorrectionPanelListener, public ICMPanelListener, public ImageAreaToolListener, public rtengine::ImageTypeListener, @@ -112,6 +114,7 @@ protected: WhiteBalance* whitebalance; Vignetting* vignetting; Gradient* gradient; + Locallab* locallab; Retinex* retinex; PCVignette* pcvignette; LensGeometry* lensgeom; @@ -178,6 +181,7 @@ protected: ToolVBox* transformPanel; ToolVBox* rawPanel; ToolVBox* advancedPanel; + ToolVBox* locallabPanel; ToolBar* toolBar; TextOrIcon* toiF; @@ -188,9 +192,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; @@ -199,27 +204,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; } @@ -235,12 +245,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 @@ -263,36 +273,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); } } @@ -304,13 +314,14 @@ public: Glib::ustring GetCurrentImageFilePath() override; // FilmNegProvider interface - bool getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, std::array& newExps) override; - bool getRawSpotValues(rtengine::Coord spot, int spotSize, std::array& rawValues) override; + bool getFilmNegativeSpot(rtengine::Coord spot, int spotSize, RGB &refInput, RGB &refOutput) override; // rotatelistener interface void straightenRequested () override; void autoCropRequested () override; + void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector *lines = nullptr) override; double autoDistorRequested () override; + void updateTransformPreviewRequested (rtengine::ProcEvent event, bool render_perspective) override; // spotwblistener interface void spotWBRequested (int size) override; @@ -318,6 +329,9 @@ public: // croppanellistener interface void cropSelectRequested () override; + // PerspCorrectionPanelListener interface + void controlLineEditModeChanged(bool active) override; + // icmpanellistener interface void saveInputICCReference(const Glib::ustring& fname, bool apply_wb) override; @@ -330,14 +344,15 @@ 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 toolDeselected(ToolMode tool) override; 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 2dc4aa05c..2057847df 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . * - * 2014 - 2019Jacques Desmis + * 2014 - 2020 Jacques Desmis */ #include "wavelet.h" @@ -29,6 +29,7 @@ #include "eventmapper.h" #include "labgrid.h" #include "../rtengine/color.h" +#include using namespace rtengine; using namespace rtengine::procparams; @@ -72,6 +73,10 @@ Wavelet::Wavelet() : separatoredge(Gtk::manage(new Gtk::HSeparator())), opaCurveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_COLORT"))), opacityCurveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_OPACITY"))), + CurveEditorwavnoise(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_DENOISE"))), + CurveEditorwavnoiseh(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_DENOISEH"))), + CurveEditorwavguid(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_DENOISEGUID"))), + CurveEditorwavhue(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_DENOISEHUE"))), opacityCurveEditorW(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_OPACITYW"))), opacityCurveEditorWL(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_OPACITYWL"))), median(Gtk::manage(new Gtk::CheckButton(M("TP_WAVELET_MEDI")))), @@ -88,7 +93,7 @@ Wavelet::Wavelet() : offset(Gtk::manage(new Adjuster(M("TP_WAVELET_WAVOFFSET"), 0.33, 1.66, 0.01, 1., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), lowthr(Gtk::manage(new Adjuster(M("TP_WAVELET_WAVLOWTHR"), 20., 100., 0.5, 40.))), rescon(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCON"), -100, 100, 1, 0))), - resconH(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCONH"), -100, 100, 1, 0))), + resconH(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCONH"), 0, 100, 1, 0))), reschro(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCHRO"), -100, 100, 1, 0))), resblur(Gtk::manage(new Adjuster(M("TP_WAVELET_RESBLUR"), 0, 100, 1, 0))), resblurc(Gtk::manage(new Adjuster(M("TP_WAVELET_RESBLURC"), 0, 100, 1, 0))), @@ -99,7 +104,7 @@ Wavelet::Wavelet() : gamma(Gtk::manage(new Adjuster(M("TP_WAVELET_COMPGAMMA"), 0.4, 2.0, 0.01, 1.0))), sup(Gtk::manage(new Adjuster(M("TP_WAVELET_SUPE"), -100, 350, 1, 0))), sky(Gtk::manage(new Adjuster(M("TP_WAVELET_SKY"), -100., 100.0, 1., 0.))), - thres(Gtk::manage(new Adjuster(M("TP_WAVELET_LEVELS"), 4, 9, 1, 7))),//3 + thres(Gtk::manage(new Adjuster(M("TP_WAVELET_LEVELS"), 5, 9, 1, 7))),//3 chroma(Gtk::manage(new Adjuster(M("TP_WAVELET_CHRO"), 1, 9, 1, 5))), chro(Gtk::manage(new Adjuster(M("TP_WAVELET_CHR"), 0., 100., 1., 0.))), contrast(Gtk::manage(new Adjuster(M("TP_WAVELET_CONTRA"), -100, 100, 1, 0))), @@ -131,22 +136,31 @@ 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))), + leveldenoise(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_LEVFOUR"), 0., 100., 0., M("TP_WAVELET_DEN5THR"), 1, 0., 100., 0., M("TP_WAVELET_NOIS"), 1., nullptr, false))), + levelsigm(Gtk::manage(new ThresholdAdjuster(M("TP_WAVELET_LEVELSIGM"), 0.05, 3., 1., M("TP_WAVELET_LEVELHIGH"), 1, 0.05, 3., 1., M("TP_WAVELET_LEVELLOW"), 1., nullptr, false))), + sigm(Gtk::manage(new Adjuster(M("TP_WAVELET_SIGM"), 0.05, 3.5, 0.01, 1.))), + levden(Gtk::manage(new Adjuster(M("TP_WAVELET_LEVDEN"), 0., 100., 0.5, 0.))), + thrden(Gtk::manage(new Adjuster(M("TP_WAVELET_DENLH"), 0., 100., 0.5, 0.))), + limden(Gtk::manage(new Adjuster(M("TP_WAVELET_LIMDEN"), 0., 1., 0.01, 0.))), + 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"), 1, 9, 1, 5))), + 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.))), + softradend(Gtk::manage(new Adjuster(M("TP_WAVELET_SOFTRAD"), 0.0, 1000., 1., 0.))), + strend(Gtk::manage(new Adjuster(M("TP_WAVELET_STREND"), 0.0, 100., 1.0, 50.))), + detend(Gtk::manage(new Adjuster(M("TP_WAVELET_DETEND"), -10, 10, 1, 0))), + thrend(Gtk::manage(new Adjuster(M("TP_WAVELET_THREND"), 0.0, 100., 0.5, 0.))), chrwav(Gtk::manage(new Adjuster(M("TP_WAVELET_CHRWAV"), 0., 100., 0.5, 0.))), Lmethod(Gtk::manage(new MyComboBoxText())), CHmethod(Gtk::manage(new MyComboBoxText())), @@ -158,11 +172,16 @@ Wavelet::Wavelet() : HSmethod(Gtk::manage(new MyComboBoxText())), CLmethod(Gtk::manage(new MyComboBoxText())), Backmethod(Gtk::manage(new MyComboBoxText())), + complexmethod(Gtk::manage(new MyComboBoxText())), Tilesmethod(Gtk::manage(new MyComboBoxText())), daubcoeffmethod(Gtk::manage(new MyComboBoxText())), Dirmethod(Gtk::manage(new MyComboBoxText())), Medgreinf(Gtk::manage(new MyComboBoxText())), ushamethod(Gtk::manage(new MyComboBoxText())), + denmethod(Gtk::manage(new MyComboBoxText())), + mixmethod(Gtk::manage(new MyComboBoxText())), + quamethod(Gtk::manage(new MyComboBoxText())), + slimethod(Gtk::manage(new MyComboBoxText())), chanMixerHLFrame(Gtk::manage(new Gtk::Frame(M("TP_COLORTONING_HIGHLIGHT")))), chanMixerMidFrame(Gtk::manage(new Gtk::Frame(M("TP_COLORTONING_MIDTONES")))), chanMixerShadowsFrame(Gtk::manage(new Gtk::Frame(M("TP_COLORTONING_SHADOWS")))), @@ -174,6 +193,7 @@ Wavelet::Wavelet() : 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")))), + guidFrame(Gtk::manage(new Gtk::Frame(M("TP_WAVELET_GUIDFRAME")))), 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") + ":"))), @@ -190,7 +210,14 @@ Wavelet::Wavelet() : expclari(Gtk::manage(new MyExpander(true, M("TP_WAVELET_CLARI")))), expbl(Gtk::manage(new MyExpander(true, M("TP_WAVELET_BL")))), neutrHBox(Gtk::manage(new Gtk::HBox())), - usharpHBox(Gtk::manage(new Gtk::HBox())) + usharpHBox(Gtk::manage(new Gtk::HBox())), + ctboxch(Gtk::manage(new Gtk::HBox())), + quaHBox(Gtk::manage(new Gtk::HBox())), + sliHBox(Gtk::manage(new Gtk::HBox())), + denHBox(Gtk::manage(new Gtk::HBox())), + mixHBox(Gtk::manage(new Gtk::HBox())), + ctboxBA(Gtk::manage(new Gtk::VBox())) + { CurveListener::setMulti(true); auto m = ProcEventMapper::getInstance(); @@ -227,6 +254,25 @@ Wavelet::Wavelet() : EvWavrangeab = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_RANGEAB"); EvWavprotab = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_PROTAB"); EvWavlevelshc = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_LEVELSHC"); + EvWavcomplexmet = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_COMPLEX"); + EvWavsigm = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVSIGM"); + EvWavdenoise = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVDENOISE"); + EvWavdenmethod = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVDENMET"); + EvWavmixmethod = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVMIXMET"); + EvWavquamethod = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVQUAMET"); + EvWavlevden = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVLEVDEN"); + EvWavdenoiseh = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVDENOISEH"); + EvWavstrend = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVSTREND"); + EvWavdetend = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVDETEND"); + EvWavlevdenois = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVDENLH"); + EvWavslimethod = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVSLIMET"); + EvWavthrend = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVTHREND"); + EvWavguid = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVGUIDH"); + EvWavhue = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVHUE"); + EvWavthrden = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVTHRDEN"); + EvWavlevelsigm = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVLEVELSIGM"); + EvWavlimden = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVLIMDEN"); + labgrid = Gtk::manage(new LabGrid(EvWavLabGridValue, M("TP_WAVELET_LABGRID_VALUES"))); @@ -269,6 +315,16 @@ Wavelet::Wavelet() : thres->set_tooltip_text(M("TP_WAVELET_LEVELS_TOOLTIP")); thres->setAdjusterListener(this); + complexmethod->append(M("TP_WAVELET_COMPNORMAL")); + complexmethod->append(M("TP_WAVELET_COMPEXPERT")); + complexmethodconn = complexmethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::complexmethodChanged)); + complexmethod->set_tooltip_text(M("TP_WAVELET_COMPLEX_TOOLTIP")); + Gtk::HBox* const complexHBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const complexLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_COMPLEXLAB") + ":")); + complexHBox->pack_start(*complexLabel, Gtk::PACK_SHRINK, 4); + complexHBox->pack_start(*complexmethod); + + Tilesmethod->append(M("TP_WAVELET_TILESFULL")); Tilesmethod->append(M("TP_WAVELET_TILESBIG")); // Tilesmethod->append(M("TP_WAVELET_TILESLIT")); @@ -335,6 +391,7 @@ Wavelet::Wavelet() : levdirSubHBox->pack_start(*Lmethod); levdirSubHBox->pack_start(*Dirmethod, Gtk::PACK_EXPAND_WIDGET, 2); // same, but 2 not 4? + settingsBox->pack_start(*complexHBox); settingsBox->pack_start(*strength); settingsBox->pack_start(*thres); settingsBox->pack_start(*tilesizeHBox); @@ -431,7 +488,7 @@ Wavelet::Wavelet() : curveEditorC->set_tooltip_text(M("TP_WAVELET_FINCOAR_TOOLTIP")); - opacityShapeSH = static_cast(curveEditorC->addCurve(CT_Flat, "", nullptr, false, false)); + opacityShapeSH = static_cast(curveEditorC->addCurve(CT_Flat, "", nullptr, false, false)); opacityShapeSH->setIdentityValue(0.); opacityShapeSH->setResetCurve(FlatCurveType(default_params.opacityCurveSH.at(0)), default_params.opacityCurveSH); @@ -440,10 +497,10 @@ Wavelet::Wavelet() : contrastSHVBox->pack_start(*HSmethod); contrastSHVBox->pack_start(*hllev); - // contrastSHVBox->pack_start(*threshold); + contrastSHVBox->pack_start(*threshold); contrastSHVBox->pack_start(*bllev); -// contrastSHVBox->pack_start(*threshold2); - contrastSHVBox->pack_start(*curveEditorC); + 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); @@ -452,7 +509,7 @@ Wavelet::Wavelet() : ToolParamBlock* const chBox = Gtk::manage(new ToolParamBlock()); Gtk::Label* const labmch = Gtk::manage(new Gtk::Label(M("TP_WAVELET_CHTYPE") + ":")); - Gtk::HBox* const ctboxch = Gtk::manage(new Gtk::HBox()); +// Gtk::HBox* const ctboxch = Gtk::manage(new Gtk::HBox()); ctboxch->pack_start(*labmch, Gtk::PACK_SHRINK, 1); CHmethod->append(M("TP_WAVELET_CH1")); @@ -574,7 +631,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); @@ -589,13 +646,121 @@ Wavelet::Wavelet() : level3noise->setAdjusterListener(this); level3noise->setUpdatePolicy(RTUP_DYNAMIC); + + leveldenoise->setAdjusterListener(this); + leveldenoise->setUpdatePolicy(RTUP_DYNAMIC); + + levelsigm->setAdjusterListener(this); + levelsigm->setUpdatePolicy(RTUP_DYNAMIC); + ballum->setAdjusterListener(this); + sigm->setAdjusterListener(this); + levden->setAdjusterListener(this); + thrden->setAdjusterListener(this); + limden->setAdjusterListener(this); + CurveEditorwavnoise->setCurveListener(this); + CurveEditorwavnoiseh->setCurveListener(this); + CurveEditorwavguid->setCurveListener(this); + CurveEditorwavhue->setCurveListener(this); + + quamethod->append(M("TP_WAVELET_QUACONSER")); + quamethod->append(M("TP_WAVELET_QUAAGRES")); + quamethodconn = quamethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::quamethodChanged)); +// quamethod->set_tooltip_text(M("TP_WAVELET_DENQUA_TOOLTIP")); + Gtk::Label* const quaLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DENQUA") + ":")); + quaHBox->pack_start(*quaLabel, Gtk::PACK_SHRINK, 4); + quaHBox->pack_start(*quamethod); + + slimethod->append(M("TP_WAVELET_DENSLI")); + slimethod->append(M("TP_WAVELET_DENCURV")); + slimethodconn = slimethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::slimethodChanged)); +// slimethod->set_tooltip_text(M("TP_WAVELET_DENSLI_TOOLTIP")); + Gtk::Label* const sliLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DENSLILAB") + ":")); + sliHBox->pack_start(*sliLabel, Gtk::PACK_SHRINK, 4); + sliHBox->pack_start(*slimethod); + + + denmethod->append(M("TP_WAVELET_DENEQUAL")); + denmethod->append(M("TP_WAVELET_DEN14PLUS")); + denmethod->append(M("TP_WAVELET_DEN14LOW")); + denmethod->append(M("TP_WAVELET_DEN12PLUS")); + denmethod->append(M("TP_WAVELET_DEN12LOW")); + denmethodconn = denmethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::denmethodChanged)); + denmethod->set_tooltip_text(M("TP_WAVELET_DENEQUAL_TOOLTIP")); +// Gtk::HBox* const denHBox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* const denLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DENCONTRAST") + ":")); + denHBox->pack_start(*denLabel, Gtk::PACK_SHRINK, 4); + denHBox->pack_start(*denmethod); + + mixmethod->append(M("TP_WAVELET_MIXNOISE")); + mixmethod->append(M("TP_WAVELET_MIXMIX")); + mixmethod->append(M("TP_WAVELET_MIXMIX70")); + mixmethod->append(M("TP_WAVELET_MIXDENOISE")); + mixmethodconn = mixmethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::mixmethodChanged)); + mixmethod->set_tooltip_text(M("TP_WAVELET_DENMIX_TOOLTIP")); + Gtk::Label* const mixLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_MIXCONTRAST") + ":")); + mixHBox->pack_start(*mixLabel, Gtk::PACK_SHRINK, 4); + mixHBox->pack_start(*mixmethod); + + wavdenoise = static_cast(CurveEditorwavnoise->addCurve(CT_Flat, "", nullptr, false, false)); + wavdenoise->setIdentityValue(0.); + wavdenoise->setResetCurve(FlatCurveType(default_params.wavdenoise.at(0)), default_params.wavdenoise); + CurveEditorwavnoise->set_tooltip_text(M("TP_WAVELET_DENLOCAL_TOOLTIP")); + + CurveEditorwavnoise->curveListComplete(); + CurveEditorwavnoise->show(); + const std::vector milestones4 = makeWholeHueRange(); + + wavdenoiseh = static_cast(CurveEditorwavnoiseh->addCurve(CT_Flat, "", nullptr, false, false)); + wavdenoiseh->setIdentityValue(0.); + wavdenoiseh->setResetCurve(FlatCurveType(default_params.wavdenoiseh.at(0)), default_params.wavdenoiseh); + CurveEditorwavnoiseh->set_tooltip_text(M("TP_WAVELET_DENLOCAL_TOOLTIP")); + CurveEditorwavnoiseh->curveListComplete(); + CurveEditorwavnoiseh->show(); + + wavhue = static_cast(CurveEditorwavhue->addCurve(CT_Flat, M("TP_WAVELET_CURVEEDITOR_HH"))); +// wavhue->setTooltip(M("TP_WAVELET_WAVHUE_HH_TOOLTIP")); + wavhue->setCurveColorProvider(this, 5); + CurveEditorwavhue->set_tooltip_text(M("TP_WAVELET_DENWAVHUE_TOOLTIP")); + CurveEditorwavhue->curveListComplete(); + wavhue->setBottomBarBgGradient(milestones4); + + + + + wavguidf = static_cast(CurveEditorwavguid->addCurve(CT_Flat, M("TP_WAVELET_CURVEEDITOR_HH"))); +// wavguidf->setTooltip(M("TP_WAVELET_WAVGUID_HH_TOOLTIP")); + wavguidf->setCurveColorProvider(this, 5); + CurveEditorwavguid->set_tooltip_text(M("TP_WAVELET_DENWAVGUID_TOOLTIP")); + CurveEditorwavguid->curveListComplete(); + wavguidf->setBottomBarBgGradient(milestones4); + + + + levelsigm->set_tooltip_text(M("TP_WAVELET_DENSIGMA_TOOLTIP")); +// levden->set_tooltip_text(M("TP_WAVELET_DENLEV_TOOLTIP")); + thrden->set_tooltip_text(M("TP_WAVELET_THRDEN_TOOLTIP")); +// limden->set_tooltip_text(M("TP_WAVELET_LIMDEN_TOOLTIP")); noiseBox->pack_start(*ballum); + noiseBox->pack_start(*CurveEditorwavhue); noiseBox->pack_start(*level0noise, Gtk::PACK_SHRINK, 0); noiseBox->pack_start(*level1noise, Gtk::PACK_SHRINK, 0); noiseBox->pack_start(*level2noise, Gtk::PACK_SHRINK, 0); noiseBox->pack_start(*level3noise, Gtk::PACK_SHRINK, 0); + // noiseBox->pack_start(*levden); + noiseBox->pack_start(*leveldenoise, Gtk::PACK_SHRINK, 0); + noiseBox->pack_start(*thrden); + noiseBox->pack_start(*quaHBox); + noiseBox->pack_start(*sliHBox); + noiseBox->pack_start(*denHBox); + noiseBox->pack_start(*mixHBox); + noiseBox->pack_start(*levelsigm, Gtk::PACK_SHRINK, 0); + noiseBox->pack_start(*limden); + noiseBox->pack_start(*sigm); + noiseBox->pack_start(*CurveEditorwavnoise); +// noiseBox->pack_start(*CurveEditorwavnoiseh); + balchrom->setAdjusterListener(this); chromfi->setAdjusterListener(this); @@ -608,7 +773,7 @@ Wavelet::Wavelet() : chroBox->pack_start(*chromco); chroFrame->add(*chroBox); noiseBox->pack_start(*chroFrame); - noiseBox->set_tooltip_text(M("TP_WAVELET_NOISE_TOOLTIP")); +// noiseBox->set_tooltip_text(M("TP_WAVELET_NOISE_TOOLTIP")); //Clarity @@ -674,7 +839,7 @@ Wavelet::Wavelet() : EDmethod->append(M("TP_WAVELET_EDCU")); EDmethodconn = EDmethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::EDmethodChanged)); ctboxED->pack_start(*EDmethod); - edgBox->pack_start(*ctboxED); + // edgBox->pack_start(*ctboxED); edgcont->setAdjusterListener(this); edgcont->setBgGradient(milestones2); @@ -838,7 +1003,7 @@ Wavelet::Wavelet() : thrH->setAdjusterListener(this); radius->setAdjusterListener(this); - radius->hide(); +// radius->hide(); shFrame->set_label_align(0.025, 0.5); ToolParamBlock* const shBox = Gtk::manage(new ToolParamBlock()); @@ -1007,7 +1172,7 @@ Wavelet::Wavelet() : resBox->pack_start(*neutrHBox); // Final Touchup - Gtk::VBox* const ctboxBA = Gtk::manage(new Gtk::VBox()); + // Gtk::VBox* const ctboxBA = Gtk::manage(new Gtk::VBox()); ctboxBA->set_spacing(2); @@ -1027,6 +1192,9 @@ Wavelet::Wavelet() : balance->setAdjusterListener(this); balance->set_tooltip_text(M("TP_WAVELET_BALANCE_TOOLTIP")); softradend->setAdjusterListener(this); + strend->setAdjusterListener(this); + detend->setAdjusterListener(this); + thrend->setAdjusterListener(this); opacityCurveEditorW->setCurveListener(this); @@ -1092,7 +1260,18 @@ Wavelet::Wavelet() : finalBox->pack_start(*fincFrame); finalBox->pack_start(*curveEditorG, Gtk::PACK_SHRINK, 4); - finalBox->pack_start(*softradend); + thrend->set_tooltip_text(M("TP_WAVELET_FINTHR_TOOLTIP")); + + guidFrame->set_label_align(0.025, 0.5); + ToolParamBlock* const guidBox = Gtk::manage(new ToolParamBlock()); + guidBox->pack_start(*softradend); + guidBox->pack_start(*strend); + guidBox->pack_start(*detend); + guidBox->pack_start(*thrend); + guidBox->pack_start(*CurveEditorwavguid); + guidFrame->add(*guidBox); + finalBox->pack_start(*guidFrame); + //----------------------------- @@ -1151,6 +1330,10 @@ Wavelet::~Wavelet() delete opaCurveEditorG; delete curveEditorC; delete opacityCurveEditorG; + delete CurveEditorwavnoise; + delete CurveEditorwavnoiseh; + delete CurveEditorwavguid; + delete CurveEditorwavhue; delete curveEditorbl; delete CCWcurveEditorG; delete curveEditorRES; @@ -1161,6 +1344,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) { @@ -1218,6 +1419,11 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) CLmethodconn.block(true); Backmethodconn.block(true); Tilesmethodconn.block(true); + complexmethodconn.block(true); + denmethodconn.block(true); + mixmethodconn.block(true); + slimethodconn.block(true); + quamethodconn.block(true); daubcoeffmethodconn.block(true); Dirmethodconn.block(true); CHmethodconn.block(true); @@ -1339,6 +1545,45 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) } else if (pp->wavelet.CLmethod == "all") { CLmethod->set_active(3); } + if (pp->wavelet.complexmethod == "normal") { + complexmethod->set_active(0); + } else if (pp->wavelet.complexmethod == "expert") { + complexmethod->set_active(1); + } + + if (pp->wavelet.denmethod == "equ") { + denmethod->set_active(0); + } else if (pp->wavelet.denmethod == "high") { + denmethod->set_active(1); + } else if (pp->wavelet.denmethod == "low") { + denmethod->set_active(2); + } else if (pp->wavelet.denmethod == "12high") { + denmethod->set_active(3); + } else if (pp->wavelet.denmethod == "12low") { + denmethod->set_active(4); + } + + if (pp->wavelet.mixmethod == "nois") { + mixmethod->set_active(0); + } else if (pp->wavelet.mixmethod == "mix") { + mixmethod->set_active(1); + } else if (pp->wavelet.mixmethod == "mix7") { + mixmethod->set_active(2); + } else if (pp->wavelet.mixmethod == "den") { + mixmethod->set_active(3); + } + + if (pp->wavelet.slimethod == "sli") { + slimethod->set_active(0); + } else if (pp->wavelet.slimethod == "cur") { + slimethod->set_active(1); + } + + if (pp->wavelet.quamethod == "cons") { + quamethod->set_active(0); + } else if (pp->wavelet.quamethod == "agre") { + quamethod->set_active(1); + } //Tilesmethod->set_active (2); if (pp->wavelet.Tilesmethod == "full") { @@ -1379,11 +1624,15 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) ccshape->setCurve(pp->wavelet.ccwcurve); blshape->setCurve(pp->wavelet.blcurve); opacityShapeRG->setCurve(pp->wavelet.opacityCurveRG); + wavdenoise->setCurve(pp->wavelet.wavdenoise); + wavdenoiseh->setCurve(pp->wavelet.wavdenoiseh); opacityShapeSH->setCurve(pp->wavelet.opacityCurveSH); opacityShapeBY->setCurve(pp->wavelet.opacityCurveBY); opacityShape->setCurve(pp->wavelet.opacityCurveW); opacityShapeWL->setCurve(pp->wavelet.opacityCurveWL); hhshape->setCurve(pp->wavelet.hhcurve); + wavguidf->setCurve(pp->wavelet.wavguidcurve); + wavhue->setCurve(pp->wavelet.wavhuecurve); Chshape->setCurve(pp->wavelet.Chcurve); clshape->setCurve(pp->wavelet.wavclCurve); expcontrast->setEnabled(pp->wavelet.expcontrast); @@ -1466,7 +1715,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); @@ -1491,8 +1742,15 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) mergeC->setValue(pp->wavelet.mergeC); softrad->setValue(pp->wavelet.softrad); softradend->setValue(pp->wavelet.softradend); + strend->setValue(pp->wavelet.strend); + detend->setValue(pp->wavelet.detend); + thrend->setValue(pp->wavelet.thrend); 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); + sigm->setValue(pp->wavelet.sigm); + levden->setValue(pp->wavelet.levden); + thrden->setValue(pp->wavelet.thrden); + limden->setValue(pp->wavelet.limden); ballum->setValue(pp->wavelet.ballum); balchrom->setValue(pp->wavelet.balchrom); chromfi->setValue(pp->wavelet.chromfi); @@ -1501,6 +1759,8 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) level1noise->setValue(pp->wavelet.level1noise); level2noise->setValue(pp->wavelet.level2noise); level3noise->setValue(pp->wavelet.level3noise); + leveldenoise->setValue(pp->wavelet.leveldenoise); + levelsigm->setValue(pp->wavelet.levelsigm); strength->setValue(pp->wavelet.strength); balance->setValue(pp->wavelet.balance); iter->setValue(pp->wavelet.iter); @@ -1538,6 +1798,26 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) Backmethod->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->wavelet.complexmethod) { + complexmethod->set_active_text(M("GENERAL_UNCHANGED")); + } + + if (!pedited->wavelet.denmethod) { + denmethod->set_active_text(M("GENERAL_UNCHANGED")); + } + + if (!pedited->wavelet.mixmethod) { + mixmethod->set_active_text(M("GENERAL_UNCHANGED")); + } + + if (!pedited->wavelet.slimethod) { + slimethod->set_active_text(M("GENERAL_UNCHANGED")); + } + + if (!pedited->wavelet.quamethod) { + quamethod->set_active_text(M("GENERAL_UNCHANGED")); + } + if (!pedited->wavelet.Tilesmethod) { Tilesmethod->set_active_text(M("GENERAL_UNCHANGED")); } @@ -1602,9 +1882,13 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) opacityShapeRG->setCurve(pp->wavelet.opacityCurveRG); opacityShapeSH->setCurve(pp->wavelet.opacityCurveSH); opacityShapeBY->setCurve(pp->wavelet.opacityCurveBY); + wavdenoise->setCurve(pp->wavelet.wavdenoise); + wavdenoiseh->setCurve(pp->wavelet.wavdenoiseh); opacityShape->setCurve(pp->wavelet.opacityCurveW); opacityShapeWL->setCurve(pp->wavelet.opacityCurveWL); hhshape->setUnChanged(!pedited->wavelet.hhcurve); + wavguidf->setUnChanged(!pedited->wavelet.wavguidcurve); + wavhue->setUnChanged(!pedited->wavelet.wavhuecurve); Chshape->setUnChanged(!pedited->wavelet.Chcurve); clshape->setUnChanged(!pedited->wavelet.wavclCurve); avoid->set_inconsistent(!pedited->wavelet.avoid); @@ -1655,7 +1939,14 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) mergeC->setEditedState(pedited->wavelet.mergeC ? Edited : UnEdited); softrad->setEditedState(pedited->wavelet.softrad ? Edited : UnEdited); softradend->setEditedState(pedited->wavelet.softradend ? Edited : UnEdited); + strend->setEditedState(pedited->wavelet.strend ? Edited : UnEdited); + detend->setEditedState(pedited->wavelet.detend ? Edited : UnEdited); + thrend->setEditedState(pedited->wavelet.thrend ? Edited : UnEdited); + sigm->setEditedState(pedited->wavelet.sigm ? Edited : UnEdited); + levden->setEditedState(pedited->wavelet.levden ? Edited : UnEdited); + thrden->setEditedState(pedited->wavelet.thrden ? Edited : UnEdited); + limden->setEditedState(pedited->wavelet.limden ? Edited : UnEdited); ballum->setEditedState(pedited->wavelet.ballum ? Edited : UnEdited); balchrom->setEditedState(pedited->wavelet.balchrom ? Edited : UnEdited); chromfi->setEditedState(pedited->wavelet.chromfi ? Edited : UnEdited); @@ -1689,6 +1980,8 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) level1noise->setEditedState(pedited->wavelet.level1noise ? Edited : UnEdited); level2noise->setEditedState(pedited->wavelet.level2noise ? Edited : UnEdited); level3noise->setEditedState(pedited->wavelet.level3noise ? Edited : UnEdited); + leveldenoise->setEditedState(pedited->wavelet.leveldenoise ? Edited : UnEdited); + levelsigm->setEditedState(pedited->wavelet.levelsigm ? Edited : UnEdited); for (int i = 0; i < 9; i++) { correction[i]->setEditedState(pedited->wavelet.c[i] ? Edited : UnEdited); @@ -1754,6 +2047,15 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) } else { sup->hide(); } + + if (complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + convertParamToNormal(); + + } else { + updateGUIToMode(1); + } + } /***************************************************************************************************** @@ -1766,6 +2068,11 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) CLmethodconn.block(false); Backmethodconn.block(false); Tilesmethodconn.block(false); + complexmethodconn.block(false); + denmethodconn.block(false); + mixmethodconn.block(false); + slimethodconn.block(false); + quamethodconn.block(false); daubcoeffmethodconn.block(false); CHmethodconn.block(false); CHSLmethodconn.block(false); @@ -1795,9 +2102,13 @@ void Wavelet::setEditProvider(EditDataProvider *provider) opacityShapeRG->setEditProvider(provider); opacityShapeSH->setEditProvider(provider); opacityShapeBY->setEditProvider(provider); + wavdenoise->setEditProvider(provider); + wavdenoiseh->setEditProvider(provider); opacityShape->setEditProvider(provider); opacityShapeWL->setEditProvider(provider); hhshape->setEditProvider(provider); + wavguidf->setEditProvider(provider); + wavhue->setEditProvider(provider); Chshape->setEditProvider(provider); clshape->setEditProvider(provider); } @@ -1868,20 +2179,30 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.level1noise = level1noise->getValue (); pp->wavelet.level2noise = level2noise->getValue (); pp->wavelet.level3noise = level3noise->getValue (); + pp->wavelet.leveldenoise = leveldenoise->getValue (); + pp->wavelet.levelsigm = levelsigm->getValue (); 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.wavdenoise = wavdenoise->getCurve(); + pp->wavelet.wavdenoiseh = wavdenoiseh->getCurve(); pp->wavelet.opacityCurveW = opacityShape->getCurve(); pp->wavelet.opacityCurveWL = opacityShapeWL->getCurve(); pp->wavelet.hhcurve = hhshape->getCurve(); + pp->wavelet.wavguidcurve = wavguidf->getCurve(); + pp->wavelet.wavhuecurve = wavhue->getCurve(); pp->wavelet.Chcurve = Chshape->getCurve(); pp->wavelet.pastlev = pastlev->getValue (); pp->wavelet.satlev = satlev->getValue (); pp->wavelet.strength = (int) strength->getValue(); pp->wavelet.balance = (int) balance->getValue(); pp->wavelet.balchrom = balchrom->getValue(); + pp->wavelet.sigm = sigm->getValue(); + pp->wavelet.levden = levden->getValue(); + pp->wavelet.thrden = thrden->getValue(); + pp->wavelet.limden = limden->getValue(); pp->wavelet.ballum = ballum->getValue(); pp->wavelet.chromfi = chromfi->getValue(); pp->wavelet.chromco = chromco->getValue(); @@ -1901,6 +2222,9 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.mergeC = mergeC->getValue(); pp->wavelet.softrad = softrad->getValue(); pp->wavelet.softradend = softradend->getValue(); + pp->wavelet.strend = strend->getValue(); + pp->wavelet.detend = detend->getIntValue(); + pp->wavelet.thrend = thrend->getValue(); pp->wavelet.expcontrast = expcontrast->getEnabled(); pp->wavelet.expchroma = expchroma->getEnabled(); pp->wavelet.expedge = expedge->getEnabled(); @@ -1945,6 +2269,11 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.CLmethod = CLmethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->wavelet.Backmethod = Backmethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->wavelet.Tilesmethod = Tilesmethod->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->wavelet.complexmethod = complexmethod->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->wavelet.denmethod = denmethod->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->wavelet.mixmethod = mixmethod->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->wavelet.slimethod = slimethod->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->wavelet.quamethod = quamethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->wavelet.daubcoeffmethod = daubcoeffmethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->wavelet.CHmethod = CHmethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->wavelet.CHSLmethod = CHSLmethod->get_active_text() != M("GENERAL_UNCHANGED"); @@ -1999,12 +2328,18 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.level1noise = level1noise->getEditedState(); pedited->wavelet.level2noise = level2noise->getEditedState(); pedited->wavelet.level3noise = level3noise->getEditedState(); + pedited->wavelet.leveldenoise = leveldenoise->getEditedState(); + pedited->wavelet.levelsigm = levelsigm->getEditedState(); pedited->wavelet.opacityCurveRG = !opacityShapeRG->isUnChanged(); pedited->wavelet.opacityCurveSH = !opacityShapeSH->isUnChanged(); pedited->wavelet.opacityCurveBY = !opacityShapeBY->isUnChanged(); + pedited->wavelet.wavdenoise = !wavdenoise->isUnChanged(); + pedited->wavelet.wavdenoiseh = !wavdenoiseh->isUnChanged(); pedited->wavelet.opacityCurveW = !opacityShape->isUnChanged(); pedited->wavelet.opacityCurveWL = !opacityShapeWL->isUnChanged(); pedited->wavelet.hhcurve = !hhshape->isUnChanged(); + pedited->wavelet.wavguidcurve = !wavguidf->isUnChanged(); + pedited->wavelet.wavhuecurve = !wavhue->isUnChanged(); pedited->wavelet.Chcurve = !Chshape->isUnChanged(); pedited->wavelet.bllev = bllev->getEditedState(); pedited->wavelet.pastlev = pastlev->getEditedState(); @@ -2016,6 +2351,10 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.bluemed = bluemed->getEditedState(); pedited->wavelet.greenhigh = greenhigh->getEditedState(); pedited->wavelet.bluehigh = bluehigh->getEditedState(); + pedited->wavelet.sigm = sigm->getEditedState(); + pedited->wavelet.levden = levden->getEditedState(); + pedited->wavelet.thrden = thrden->getEditedState(); + pedited->wavelet.limden = limden->getEditedState(); pedited->wavelet.ballum = ballum->getEditedState(); pedited->wavelet.balchrom = balchrom->getEditedState(); pedited->wavelet.chromfi = chromfi->getEditedState(); @@ -2024,6 +2363,9 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.mergeC = mergeC->getEditedState(); pedited->wavelet.softrad = softrad->getEditedState(); pedited->wavelet.softradend = softradend->getEditedState(); + pedited->wavelet.strend = strend->getEditedState(); + pedited->wavelet.detend = detend->getEditedState(); + pedited->wavelet.thrend = thrend->getEditedState(); pedited->wavelet.balance = balance->getEditedState(); pedited->wavelet.iter = iter->getEditedState(); pedited->wavelet.sigmafin = sigmafin->getEditedState(); @@ -2148,6 +2490,46 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) // pp->wavelet.Tilesmethod = "lit"; } + if (complexmethod->get_active_row_number() == 0) { + pp->wavelet.complexmethod = "normal"; + } else if (complexmethod->get_active_row_number() == 1) { + pp->wavelet.complexmethod = "expert"; + } + + if (denmethod->get_active_row_number() == 0) { + pp->wavelet.denmethod = "equ"; + } else if (denmethod->get_active_row_number() == 1) { + pp->wavelet.denmethod = "high"; + } else if (denmethod->get_active_row_number() == 2) { + pp->wavelet.denmethod = "low"; + } else if (denmethod->get_active_row_number() == 3) { + pp->wavelet.denmethod = "12high"; + } else if (denmethod->get_active_row_number() == 4) { + pp->wavelet.denmethod = "12low"; + } + + if (mixmethod->get_active_row_number() == 0) { + pp->wavelet.mixmethod = "nois"; + } else if (mixmethod->get_active_row_number() == 1) { + pp->wavelet.mixmethod = "mix"; + } else if (mixmethod->get_active_row_number() == 2) { + pp->wavelet.mixmethod = "mix7"; + } else if (mixmethod->get_active_row_number() == 3) { + pp->wavelet.mixmethod = "den"; + } + + if (slimethod->get_active_row_number() == 0) { + pp->wavelet.slimethod = "sli"; + } else if (slimethod->get_active_row_number() == 1) { + pp->wavelet.slimethod = "cur"; + } + + if (quamethod->get_active_row_number() == 0) { + pp->wavelet.quamethod = "cons"; + } else if (quamethod->get_active_row_number() == 1) { + pp->wavelet.quamethod = "agre"; + } + if (daubcoeffmethod->get_active_row_number() == 0) { pp->wavelet.daubcoeffmethod = "2_"; } else if (daubcoeffmethod->get_active_row_number() == 1) { @@ -2187,12 +2569,20 @@ void Wavelet::curveChanged(CurveEditor* ce) listener->panelChanged(EvWavlevelshc, M("HISTORY_CUSTOMCURVE")); } else if (ce == opacityShapeBY) { listener->panelChanged(EvWavOpac, M("HISTORY_CUSTOMCURVE")); + } else if (ce == wavdenoise) { + listener->panelChanged(EvWavdenoise, M("HISTORY_CUSTOMCURVE")); + } else if (ce == wavdenoiseh) { + listener->panelChanged(EvWavdenoiseh, M("HISTORY_CUSTOMCURVE")); } else if (ce == opacityShape) { listener->panelChanged(EvWavopacity, M("HISTORY_CUSTOMCURVE")); } else if (ce == opacityShapeWL) { listener->panelChanged(EvWavopacityWL, M("HISTORY_CUSTOMCURVE")); } else if (ce == hhshape) { listener->panelChanged(EvWavHHCurve, M("HISTORY_CUSTOMCURVE")); + } else if (ce == wavguidf) { + listener->panelChanged(EvWavguid, M("HISTORY_CUSTOMCURVE")); + } else if (ce == wavhue) { + listener->panelChanged(EvWavhue, M("HISTORY_CUSTOMCURVE")); } else if (ce == Chshape) { listener->panelChanged(EvWavCHCurve, M("HISTORY_CUSTOMCURVE")); } else if (ce == clshape) { @@ -2266,6 +2656,12 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit level1noise->setDefault (defParams->wavelet.level1noise); level2noise->setDefault (defParams->wavelet.level2noise); level3noise->setDefault (defParams->wavelet.level3noise); + leveldenoise->setDefault (defParams->wavelet.leveldenoise); + levelsigm->setDefault (defParams->wavelet.levelsigm); + sigm->setDefault(defParams->wavelet.sigm); + levden->setDefault(defParams->wavelet.levden); + thrden->setDefault(defParams->wavelet.thrden); + limden->setDefault(defParams->wavelet.limden); ballum->setDefault(defParams->wavelet.ballum); balchrom->setDefault(defParams->wavelet.balchrom); chromfi->setDefault(defParams->wavelet.chromfi); @@ -2282,6 +2678,9 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit mergeC->setDefault(defParams->wavelet.mergeC); softrad->setDefault(defParams->wavelet.softrad); softradend->setDefault(defParams->wavelet.softradend); + strend->setDefault(defParams->wavelet.strend); + detend->setDefault(defParams->wavelet.detend); + thrend->setDefault(defParams->wavelet.thrend); if (pedited) { greenlow->setDefaultEditedState(pedited->wavelet.greenlow ? Edited : UnEdited); @@ -2294,6 +2693,13 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit mergeC->setDefaultEditedState(pedited->wavelet.mergeC ? Edited : UnEdited); softrad->setDefaultEditedState(pedited->wavelet.softrad ? Edited : UnEdited); softradend->setDefaultEditedState(pedited->wavelet.softradend ? Edited : UnEdited); + strend->setDefaultEditedState(pedited->wavelet.strend ? Edited : UnEdited); + detend->setDefaultEditedState(pedited->wavelet.detend ? Edited : UnEdited); + thrend->setDefaultEditedState(pedited->wavelet.thrend ? Edited : UnEdited); + sigm->setDefaultEditedState(pedited->wavelet.sigm ? Edited : UnEdited); + levden->setDefaultEditedState(pedited->wavelet.levden ? Edited : UnEdited); + thrden->setDefaultEditedState(pedited->wavelet.thrden ? Edited : UnEdited); + limden->setDefaultEditedState(pedited->wavelet.limden ? Edited : UnEdited); ballum->setDefaultEditedState(pedited->wavelet.ballum ? Edited : UnEdited); balchrom->setDefaultEditedState(pedited->wavelet.balchrom ? Edited : UnEdited); chromfi->setDefaultEditedState(pedited->wavelet.chromfi ? Edited : UnEdited); @@ -2355,6 +2761,8 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit level1noise->setDefaultEditedState(pedited->wavelet.level1noise ? Edited : UnEdited); level2noise->setDefaultEditedState(pedited->wavelet.level2noise ? Edited : UnEdited); level3noise->setDefaultEditedState(pedited->wavelet.level3noise ? Edited : UnEdited); + leveldenoise->setDefaultEditedState(pedited->wavelet.leveldenoise ? Edited : UnEdited); + levelsigm->setDefaultEditedState(pedited->wavelet.levelsigm ? Edited : UnEdited); for (int i = 0; i < 9; i++) { correction[i]->setDefaultEditedState(pedited->wavelet.c[i] ? Edited : UnEdited); @@ -2408,6 +2816,8 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit level1noise->setDefaultEditedState(Irrelevant); level2noise->setDefaultEditedState(Irrelevant); level3noise->setDefaultEditedState(Irrelevant); + leveldenoise->setDefaultEditedState(Irrelevant); + levelsigm->setDefaultEditedState(Irrelevant); pastlev->setDefaultEditedState(Irrelevant); satlev->setDefaultEditedState(Irrelevant); strength->setDefaultEditedState(Irrelevant); @@ -2446,6 +2856,13 @@ void Wavelet::adjusterChanged(ThresholdAdjuster* a, double newBottom, double new } else if (a == level3noise) { listener->panelChanged(EvWavlev3nois, Glib::ustring::compose(Glib::ustring(M("TP_WAVELET_NOIS") + ": %1" + "\n" + M("TP_WAVELET_STREN") + ": %2"), int(newTop), int(newBottom))); + } else if (a == leveldenoise) { + listener->panelChanged(EvWavlevdenois, + Glib::ustring::compose(Glib::ustring(M("TP_WAVELET_NOIS") + ": %1" + "\n" + M("TP_WAVELET_DEN5THR") + ": %2"), int(newTop), int(newBottom))); + } else if (a == levelsigm) { + usleep(150); + listener->panelChanged(EvWavlevelsigm, + Glib::ustring::compose(Glib::ustring(M("TP_WAVELET_LEVELLOW") + ": %1" + "\n" + M("TP_WAVELET_LEVELHIGH") + ": %2"), (newTop), (newBottom))); } } @@ -2815,6 +3232,199 @@ void Wavelet::ushamethodChanged() } + +void Wavelet::convertParamToNormal() +{ + const WaveletParams def_params; + disableListener(); + //contrast + offset->setValue(def_params.offset); + sigma->setValue(def_params.sigma); + lowthr->setValue(def_params.lowthr); + //chroma + expchroma->setEnabled(def_params.expchroma); + sigmacol->setValue(def_params.sigmacol); + CHmethod->set_active(2); + //denoise + chromfi->setValue(def_params.chromfi); + chromco->setValue(def_params.chromco); + denmethod->set_active(4); + mixmethod->set_active(2); + slimethod->set_active(0); + levelsigm->setValue(def_params.levelsigm); + leveldenoise->setValue(def_params.leveldenoise); + limden->setValue(def_params.limden); + thrden->setValue(def_params.thrden); +// quamethod->set_active(0); + sigm->setValue(def_params.sigm); + //toning + exptoning->setEnabled(def_params.exptoning); + //gamut + median->set_active(def_params.median); + avoid->set_active(def_params.avoid); + hueskin->setValue(def_params.hueskin); + skinprotect->setValue(def_params.skinprotect); + //blur + expbl->setEnabled(def_params.expbl); + //edge sharpness + lipst->set_active(def_params.lipst); + lipstUpdateUI(); + edgesensi->setValue(def_params.edgesensi); + edgeampli->setValue(def_params.edgeampli); + NPmethod->set_active(0); + //resid + // oldsh->set_active(true); + radius->setValue(def_params.radius); + resblur->setValue(def_params.resblur); + resblurc->setValue(def_params.resblurc); + cbenab->set_active(false); + + //final touchup + BAmethod->set_active(0); + sigmafin->setValue(def_params.sigmafin); + enableListener(); + + // Update GUI based on converted widget parameters: +} + +void Wavelet::updateGUIToMode(int mode) +{ + if(mode ==0) { + offset->hide(); + sigma->hide(); + lowthr->hide(); + ctboxch->hide(); + sigmacol->hide(); + expgamut->hide(); + exptoning->hide(); + chroFrame->hide(); + expbl->hide(); + lipst->hide(); + dirFrame->hide(); + oldsh->hide(); + radius->hide(); + blurFrame->hide(); + cbenab->hide(); + sigmafin->hide(); + denHBox->hide(); + mixHBox->hide(); + sliHBox->hide(); + sigm->hide(); + levelsigm->hide(); + CurveEditorwavnoiseh->hide(); + CurveEditorwavnoise->hide(); + // levden->hide(); + thrden->hide(); + leveldenoise->hide(); + limden->hide(); + } else { + offset->show(); + sigma->show(); + lowthr->show(); + ctboxch->show(); + sigmacol->show(); + expgamut->show(); + exptoning->show(); + chroFrame->show(); + expbl->show(); + lipst->show(); + dirFrame->show(); + oldsh->hide(); + radius->show(); + blurFrame->show(); + cbenab->show(); + sigmafin->show(); + denHBox->hide(); + mixHBox->show(); + sigm->hide(); + levelsigm->show(); + limden->show(); + levden->show(); + sliHBox->show(); + if (slimethod->get_active_row_number() == 0){ + leveldenoise->show(); + thrden->show(); + CurveEditorwavnoiseh->hide(); + CurveEditorwavnoise->hide(); + } else { + thrden->hide(); + leveldenoise->show(); + CurveEditorwavnoiseh->show(); + CurveEditorwavnoise->show(); + } + disableListener(); + denmethod->set_active(4); + enableListener(); + + } + +} + + +void Wavelet::complexmethodChanged() +{ + if (complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + convertParamToNormal(); + + } else { + updateGUIToMode(1); + } + + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(EvWavcomplexmet, complexmethod->get_active_text()); + } +} + +void Wavelet::denmethodChanged() +{ + + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(EvWavdenmethod, denmethod->get_active_text()); + } +} + +void Wavelet::mixmethodChanged() +{ + + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(EvWavmixmethod, mixmethod->get_active_text()); + } +} + +void Wavelet::slimethodChanged() +{ + + if (slimethod->get_active_row_number() == 0 && complexmethod->get_active_row_number() == 0) { + updateGUIToMode(0); + convertParamToNormal(); + leveldenoise->show(); + } else if (slimethod->get_active_row_number() == 0 && complexmethod->get_active_row_number() == 1){ + updateGUIToMode(1); + leveldenoise->show(); + CurveEditorwavnoiseh->hide(); + CurveEditorwavnoise->hide(); + } else if (slimethod->get_active_row_number() == 1 && complexmethod->get_active_row_number() == 1){ + updateGUIToMode(1); + leveldenoise->show(); + CurveEditorwavnoiseh->show(); + CurveEditorwavnoise->show(); + } + + + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(EvWavslimethod, slimethod->get_active_text()); + } +} + +void Wavelet::quamethodChanged() +{ + + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(EvWavquamethod, quamethod->get_active_text()); + } +} + void Wavelet::TilesmethodChanged() { //TilesmethodUpdateUI(); @@ -2896,6 +3506,11 @@ void Wavelet::setBatchMode(bool batchMode) CLmethod->append(M("GENERAL_UNCHANGED")); Backmethod->append(M("GENERAL_UNCHANGED")); Tilesmethod->append(M("GENERAL_UNCHANGED")); + complexmethod->append(M("GENERAL_UNCHANGED")); + denmethod->append(M("GENERAL_UNCHANGED")); + mixmethod->append(M("GENERAL_UNCHANGED")); + slimethod->append(M("GENERAL_UNCHANGED")); + quamethod->append(M("GENERAL_UNCHANGED")); daubcoeffmethod->append(M("GENERAL_UNCHANGED")); CHmethod->append(M("GENERAL_UNCHANGED")); Medgreinf->append(M("GENERAL_UNCHANGED")); @@ -2911,6 +3526,10 @@ void Wavelet::setBatchMode(bool batchMode) opaCurveEditorG->setBatchMode(batchMode); curveEditorC->setBatchMode(batchMode); opacityCurveEditorG->setBatchMode(batchMode); + CurveEditorwavnoise->setBatchMode(batchMode); + CurveEditorwavnoiseh->setBatchMode(batchMode); + CurveEditorwavguid->setBatchMode(batchMode); + CurveEditorwavhue->setBatchMode(batchMode); opacityCurveEditorW->setBatchMode(batchMode); opacityCurveEditorWL->setBatchMode(batchMode); curveEditorbl->setBatchMode(batchMode); @@ -2971,6 +3590,8 @@ void Wavelet::setBatchMode(bool batchMode) level1noise->showEditedCB(); level2noise->showEditedCB(); level3noise->showEditedCB(); + leveldenoise->showEditedCB(); + levelsigm->showEditedCB(); ToolPanel::setBatchMode(batchMode); @@ -3063,6 +3684,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) { @@ -3106,8 +3730,17 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) } else { sup->hide(); } + if(z >= 8 ) { + expnoise->setEnabled(false); + expnoise->set_sensitive(false); + } else { + // expnoise->setEnabled(pp->wavelet.expnoise); + expnoise->set_sensitive(true); + } listener->panelChanged(EvWavthres, thres->getTextValue()); + updateGUImaxlev(); + updateGUI(); } else if (a == skinprotect) { listener->panelChanged(EvWavSkin, skinprotect->getTextValue()); } else if (a == strength) { @@ -3134,6 +3767,14 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvWavbluehigh, bluehigh->getTextValue()); } else if (a == ballum) { listener->panelChanged(EvWavballum, ballum->getTextValue()); + } else if (a == sigm) { + listener->panelChanged(EvWavsigm, sigm->getTextValue()); + } else if (a == levden) { + listener->panelChanged(EvWavlevden, levden->getTextValue()); + } else if (a == thrden) { + listener->panelChanged(EvWavthrden, thrden->getTextValue()); + } else if (a == limden) { + listener->panelChanged(EvWavlimden, limden->getTextValue()); } else if (a == balchrom) { listener->panelChanged(EvWavbalchrom, balchrom->getTextValue()); } else if (a == chromfi) { @@ -3148,6 +3789,12 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvWavsoftrad, softrad->getTextValue()); } else if (a == softradend) { listener->panelChanged(EvWavsoftradend, softradend->getTextValue()); + } else if (a == strend) { + listener->panelChanged(EvWavstrend, strend->getTextValue()); + } else if (a == detend) { + listener->panelChanged(EvWavdetend, detend->getTextValue()); + } else if (a == thrend) { + listener->panelChanged(EvWavthrend, thrend->getTextValue()); } else if (a == greenmed) { listener->panelChanged(EvWavgreenmed, greenmed->getTextValue()); } else if (a == bluemed) { @@ -3212,6 +3859,13 @@ void Wavelet::enabledUpdateUI() sup->hide(); } + if(z >= 8) { + expnoise->setEnabled(false); + expnoise->set_sensitive(false); + } else { + expnoise->set_sensitive(true); + } + // adjusterUpdateUI(tmrs); } } @@ -3671,6 +4325,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 c6a0a6b85..c7e002a64 100644 --- a/rtgui/wavelet.h +++ b/rtgui/wavelet.h @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . * - * 2014 Jacques Desmis + * 2014 2020 Jacques Desmis */ #pragma once @@ -47,7 +47,6 @@ class Wavelet final : public: Wavelet(); ~Wavelet() override; - bool wavComputed_(); void adjusterChanged(Adjuster* a, double newval) override; void autoOpenCurve() override; @@ -102,6 +101,24 @@ private: rtengine::ProcEvent EvWavrangeab; rtengine::ProcEvent EvWavprotab; rtengine::ProcEvent EvWavlevelshc; + rtengine::ProcEvent EvWavcomplexmet; + rtengine::ProcEvent EvWavsigm; + rtengine::ProcEvent EvWavdenoise; + rtengine::ProcEvent EvWavdenmethod; + rtengine::ProcEvent EvWavmixmethod; + rtengine::ProcEvent EvWavquamethod; + rtengine::ProcEvent EvWavlevden; + rtengine::ProcEvent EvWavdenoiseh; + rtengine::ProcEvent EvWavstrend; + rtengine::ProcEvent EvWavdetend; + rtengine::ProcEvent EvWavlevdenois; + rtengine::ProcEvent EvWavslimethod; + rtengine::ProcEvent EvWavthrend; + rtengine::ProcEvent EvWavguid; + rtengine::ProcEvent EvWavhue; + rtengine::ProcEvent EvWavthrden; + rtengine::ProcEvent EvWavlevelsigm; + rtengine::ProcEvent EvWavlimden; LabGrid *labgrid; @@ -121,6 +138,11 @@ private: void LmethodChanged(); void MedgreinfChanged(); void TMmethodChanged(); + void complexmethodChanged(); + void denmethodChanged(); + void mixmethodChanged(); + void quamethodChanged(); + void slimethodChanged(); void TilesmethodChanged(); void avoidToggled(); void showmaskToggled (); @@ -141,7 +163,10 @@ private: void updatewavLabel (); void wavChanged(double nlevel) override; void ushamethodChanged(); - + void updateGUI(); + void updateGUImaxlev(); + void convertParamToNormal(); + void updateGUIToMode(int mode); void HSmethodUpdateUI(); void CHmethodUpdateUI(); // void CHSLmethodChangedUI(); @@ -179,6 +204,14 @@ private: FlatCurveEditor* opacityShapeRG; CurveEditorGroup* const opacityCurveEditorG; FlatCurveEditor* opacityShapeBY; + CurveEditorGroup* const CurveEditorwavnoise; + FlatCurveEditor* wavdenoise; + CurveEditorGroup* const CurveEditorwavnoiseh; + FlatCurveEditor* wavdenoiseh; + CurveEditorGroup* const CurveEditorwavguid; + FlatCurveEditor* wavguidf; + CurveEditorGroup* const CurveEditorwavhue; + FlatCurveEditor* wavhue; CurveEditorGroup* const opacityCurveEditorW; CurveEditorGroup* const opacityCurveEditorWL; FlatCurveEditor* opacityShape; @@ -257,7 +290,13 @@ private: ThresholdAdjuster* const level1noise; ThresholdAdjuster* const level2noise; ThresholdAdjuster* const level3noise; + ThresholdAdjuster* const leveldenoise; + ThresholdAdjuster* const levelsigm; + Adjuster* const sigm; + Adjuster* const levden; + Adjuster* const thrden; + Adjuster* const limden; Adjuster* const threshold; Adjuster* const threshold2; Adjuster* const edgedetect; @@ -273,6 +312,9 @@ private: Adjuster* const mergeC; Adjuster* const softrad; Adjuster* const softradend; + Adjuster* const strend; + Adjuster* const detend; + Adjuster* const thrend; Adjuster* const chrwav; MyComboBoxText* const Lmethod; @@ -295,6 +337,8 @@ private: sigc::connection CLmethodconn; MyComboBoxText* const Backmethod; sigc::connection Backmethodconn; + MyComboBoxText* const complexmethod; + sigc::connection complexmethodconn; MyComboBoxText* const Tilesmethod; sigc::connection Tilesmethodconn; MyComboBoxText* const daubcoeffmethod; @@ -305,6 +349,14 @@ private: sigc::connection MedgreinfConn; MyComboBoxText* const ushamethod; sigc::connection ushamethodconn; + MyComboBoxText* const denmethod; + sigc::connection denmethodconn; + MyComboBoxText* const mixmethod; + sigc::connection mixmethodconn; + MyComboBoxText* const quamethod; + sigc::connection quamethodconn; + MyComboBoxText* const slimethod; + sigc::connection slimethodconn; Gtk::Frame* const chanMixerHLFrame; Gtk::Frame* const chanMixerMidFrame; @@ -317,6 +369,7 @@ private: Gtk::Frame* const fincFrame; Gtk::Frame* const dirFrame; Gtk::Frame* const tonFrame; + Gtk::Frame* const guidFrame; Gtk::Label* const wavLabels; Gtk::Label* const labmC; @@ -336,6 +389,12 @@ private: Gtk::HBox* const neutrHBox; Gtk::HBox* const usharpHBox; + Gtk::HBox* const ctboxch; + Gtk::HBox* const quaHBox; + Gtk::HBox* const sliHBox; + Gtk::HBox* const denHBox; + Gtk::HBox* const mixHBox; + Gtk::VBox* const ctboxBA;// = Gtk::manage(new Gtk::VBox()); sigc::connection enableChromaConn, enableContrastConn, enableEdgeConn, enabletmConn, enableFinalConn, enableclariConn; sigc::connection enableNoiseConn, enableResidConn, enableToningConn; diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index a371bad88..db63c68be 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -79,9 +79,7 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP dualDemosaicContrast->addAutoButton(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP")); dualDemosaicContrast->setAutoValue(true); - if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { - dualDemosaicContrast->delay = options.adjusterMaxDelay; - } + dualDemosaicContrast->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); dualDemosaicContrast->show(); dualDemosaicOptions->pack_start(*dualDemosaicContrast); @@ -91,9 +89,7 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP border = Gtk::manage(new Adjuster(M("TP_RAW_BORDER"), 0, 16, 1, 7)); border->setAdjusterListener (this); - if (border->delay < options.adjusterMaxDelay) { - border->delay = options.adjusterMaxDelay; - } + border->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); border->show(); borderbox->pack_start(*border); @@ -103,9 +99,7 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); ccSteps->setAdjusterListener (this); - if (ccSteps->delay < options.adjusterMaxDelay) { - ccSteps->delay = options.adjusterMaxDelay; - } + ccSteps->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); ccSteps->show(); pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); diff --git a/rtgui/xtransrawexposure.cc b/rtgui/xtransrawexposure.cc index 8d854ca80..e1b56b9f0 100644 --- a/rtgui/xtransrawexposure.cc +++ b/rtgui/xtransrawexposure.cc @@ -32,25 +32,19 @@ XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, "xtransrawexpo PexBlackRed = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_RED"), -2048, 2048, 1.0, 0)); //black level PexBlackRed->setAdjusterListener (this); - if (PexBlackRed->delay < options.adjusterMaxDelay) { - PexBlackRed->delay = options.adjusterMaxDelay; - } + PexBlackRed->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlackRed->show(); PexBlackGreen = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_GREEN"), -2048, 2048, 1.0, 0)); //black level PexBlackGreen->setAdjusterListener (this); - if (PexBlackGreen->delay < options.adjusterMaxDelay) { - PexBlackGreen->delay = options.adjusterMaxDelay; - } + PexBlackGreen->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlackGreen->show(); PexBlackBlue = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_BLUE"), -2048, 2048, 1.0, 0)); //black level PexBlackBlue->setAdjusterListener (this); - if (PexBlackBlue->delay < options.adjusterMaxDelay) { - PexBlackBlue->delay = options.adjusterMaxDelay; - } + PexBlackBlue->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); PexBlackBlue->show(); diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index bc1a2dc3b..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